1 /*
2 
3   Copyright (c) 2003-2013 uim Project https://github.com/uim/uim
4 
5   All rights reserved.
6 
7   Redistribution and use in source and binary forms, with or without
8   modification, are permitted provided that the following conditions
9   are met:
10 
11   1. Redistributions of source code must retain the above copyright
12      notice, this list of conditions and the following disclaimer.
13   2. Redistributions in binary form must reproduce the above copyright
14      notice, this list of conditions and the following disclaimer in the
15      documentation and/or other materials provided with the distribution.
16   3. Neither the name of authors nor the names of its contributors
17      may be used to endorse or promote products derived from this software
18      without specific prior written permission.
19 
20   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
21   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE
24   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30   SUCH DAMAGE.
31 
32 */
33 
34 #include <config.h>
35 
36 #include <ctype.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <assert.h>
40 
41 #include "uim-internal.h"
42 #include "uim-scm.h"
43 #include "uim-scm-abbrev.h"
44 #include "uim-im-switcher.h"
45 
46 
47 #define TEXT_EMPTYP(txt) (!(txt) || !(txt)[0])
48 
49 
50 /* this is not a uim API, so did not name as uim_retrieve_context() */
51 static uim_context
retrieve_uim_context(uim_lisp c)52 retrieve_uim_context(uim_lisp c)
53 {
54   uim_context uc;
55 
56   if (CONSP(c))  /* passed as Scheme-side input context */
57     c = CAR(c);
58 
59   uc = C_PTR(c);
60   assert(uc);
61 
62   return uc;
63 }
64 
65 /* extract Scheme IM context from Scheme-object-wrapped uim_context */
66 static uim_lisp
im_retrieve_context(uim_lisp uc_)67 im_retrieve_context(uim_lisp uc_)
68 {
69   uim_context uc;
70 
71   uc = C_PTR(uc_);
72   assert(uc);
73 
74   return uc->sc;
75 }
76 
77 static uim_lisp
im_convertiblep(uim_lisp uc_,uim_lisp im_encoding_)78 im_convertiblep(uim_lisp uc_, uim_lisp im_encoding_)
79 {
80   uim_context uc;
81   const char *im_encoding;
82   uim_bool convertiblep;
83 
84   uc = retrieve_uim_context(uc_);
85   im_encoding = REFER_C_STR(im_encoding_);
86   convertiblep = uc->conv_if->is_convertible(uc->client_encoding, im_encoding);
87 
88   return MAKE_BOOL(convertiblep);
89 }
90 
91 static uim_lisp
im_clear_preedit(uim_lisp uc_)92 im_clear_preedit(uim_lisp uc_)
93 {
94   uim_context uc;
95 
96   uc = retrieve_uim_context(uc_);
97   if (uc->preedit_clear_cb)
98     uc->preedit_clear_cb(uc->ptr);
99 
100   return uim_scm_f();
101 }
102 
103 static uim_lisp
im_pushback_preedit(uim_lisp uc_,uim_lisp attr_,uim_lisp str_)104 im_pushback_preedit(uim_lisp uc_, uim_lisp attr_, uim_lisp str_)
105 {
106   uim_context uc;
107   const char *str;
108   char *converted_str;
109   int attr;
110 
111   uc = retrieve_uim_context(uc_);
112   attr = C_INT(attr_);
113   str = REFER_C_STR(str_);
114 
115   converted_str = uc->conv_if->convert(uc->outbound_conv, str);
116   if (uc->preedit_pushback_cb)
117     uc->preedit_pushback_cb(uc->ptr, attr, converted_str);
118   free(converted_str);
119 
120   return uim_scm_f();
121 }
122 
123 static uim_lisp
im_update_preedit(uim_lisp uc_)124 im_update_preedit(uim_lisp uc_)
125 {
126   uim_context uc;
127 
128   uc = retrieve_uim_context(uc_);
129   if (uc->preedit_update_cb)
130     uc->preedit_update_cb(uc->ptr);
131 
132   return uim_scm_f();
133 }
134 
135 static uim_lisp
im_commit(uim_lisp uc_,uim_lisp str_)136 im_commit(uim_lisp uc_, uim_lisp str_)
137 {
138   uim_context uc;
139   const char *str;
140   char *converted_str;
141 
142   uc = retrieve_uim_context(uc_);
143   str = REFER_C_STR(str_);
144 
145   converted_str = uc->conv_if->convert(uc->outbound_conv, str);
146   if (uc->commit_cb)
147     uc->commit_cb(uc->ptr, converted_str);
148   free(converted_str);
149 
150   return uim_scm_f();
151 }
152 
153 static uim_lisp
im_set_encoding(uim_lisp uc_,uim_lisp enc_)154 im_set_encoding(uim_lisp uc_, uim_lisp enc_)
155 {
156   uim_context uc;
157   const char *enc;
158 
159   uc = retrieve_uim_context(uc_);
160   enc = REFER_C_STR(enc_);
161 
162   uim_set_encoding(uc, enc);
163 
164   return uim_scm_f();
165 }
166 
167 void
uim_set_encoding(uim_context uc,const char * enc)168 uim_set_encoding(uim_context uc, const char *enc)
169 {
170   assert(uc);
171   assert(enc);
172 
173   if (uc->outbound_conv)
174     uc->conv_if->release(uc->outbound_conv);
175   if (uc->inbound_conv)
176     uc->conv_if->release(uc->inbound_conv);
177 
178   if (!strcmp(uc->client_encoding, enc)) {
179     uc->outbound_conv = NULL;
180     uc->inbound_conv  = NULL;
181   } else {
182     uc->outbound_conv = uc->conv_if->create(uc->client_encoding, enc);
183     uc->inbound_conv  = uc->conv_if->create(enc, uc->client_encoding);
184   }
185 }
186 
187 static uim_lisp
im_clear_mode_list(uim_lisp uc_)188 im_clear_mode_list(uim_lisp uc_)
189 {
190   uim_context uc;
191   int i;
192 
193   uc = retrieve_uim_context(uc_);
194 
195   for (i = 0; i < uc->nr_modes; i++) {
196     if (uc->modes[i]) {
197       free(uc->modes[i]);
198       uc->modes[i] = NULL;
199     }
200   }
201   if (uc->modes) {
202     free(uc->modes);
203     uc->modes = NULL;
204   }
205   uc->nr_modes = 0;
206 
207   return uim_scm_f();
208 }
209 
210 static uim_lisp
im_pushback_mode_list(uim_lisp uc_,uim_lisp str_)211 im_pushback_mode_list(uim_lisp uc_, uim_lisp str_)
212 {
213   uim_context uc;
214   const char *str;
215 
216   uc = retrieve_uim_context(uc_);
217   str = REFER_C_STR(str_);
218 
219   uc->modes = uim_realloc(uc->modes, sizeof(char *) * (uc->nr_modes + 1));
220   uc->modes[uc->nr_modes] = uc->conv_if->convert(uc->outbound_conv, str);
221   uc->nr_modes++;
222 
223   return uim_scm_f();
224 }
225 
226 static uim_lisp
im_update_mode_list(uim_lisp uc_)227 im_update_mode_list(uim_lisp uc_)
228 {
229   uim_context uc;
230 
231   uc = retrieve_uim_context(uc_);
232 
233   if (uc->mode_list_update_cb)
234     uc->mode_list_update_cb(uc->ptr);
235 
236   return uim_scm_f();
237 }
238 
239 static uim_lisp
im_update_prop_list(uim_lisp uc_,uim_lisp prop_)240 im_update_prop_list(uim_lisp uc_, uim_lisp prop_)
241 {
242   uim_context uc;
243   const char *prop;
244 
245   uc = retrieve_uim_context(uc_);
246   prop = REFER_C_STR(prop_);
247 
248   free(uc->propstr);
249   uc->propstr = uc->conv_if->convert(uc->outbound_conv, prop);
250 
251   if (uc->prop_list_update_cb)
252     uc->prop_list_update_cb(uc->ptr, uc->propstr);
253 
254   return uim_scm_f();
255 }
256 
257 static uim_lisp
im_update_mode(uim_lisp uc_,uim_lisp mode_)258 im_update_mode(uim_lisp uc_, uim_lisp mode_)
259 {
260   uim_context uc;
261   int mode;
262 
263   uc = retrieve_uim_context(uc_);
264   mode = C_INT(mode_);
265 
266   uc->mode = mode;
267   if (uc->mode_update_cb)
268     uc->mode_update_cb(uc->ptr, mode);
269 
270   return uim_scm_f();
271 }
272 
273 static uim_lisp
im_activate_candidate_selector(uim_lisp uc_,uim_lisp nr_,uim_lisp display_limit_)274 im_activate_candidate_selector(uim_lisp uc_,
275                                uim_lisp nr_, uim_lisp display_limit_)
276 {
277   uim_context uc;
278   int nr, display_limit;
279 
280   uc = retrieve_uim_context(uc_);
281   nr = C_INT(nr_);
282   display_limit = C_INT(display_limit_);
283 
284   if (uc->candidate_selector_activate_cb)
285     uc->candidate_selector_activate_cb(uc->ptr, nr, display_limit);
286 
287   return uim_scm_f();
288 }
289 
290 static uim_lisp
im_delay_activate_candidate_selector(uim_lisp uc_,uim_lisp delay_)291 im_delay_activate_candidate_selector(uim_lisp uc_, uim_lisp delay_)
292 {
293   uim_context uc;
294   int delay;
295 
296   uc = retrieve_uim_context(uc_);
297   delay = C_INT(delay_);
298 
299   if (uc->candidate_selector_delay_activate_cb)
300     uc->candidate_selector_delay_activate_cb(uc->ptr, delay);
301 
302   return uim_scm_f();
303 }
304 
305 static uim_lisp
im_select_candidate(uim_lisp uc_,uim_lisp idx_)306 im_select_candidate(uim_lisp uc_, uim_lisp idx_)
307 {
308   uim_context uc;
309   int idx;
310 
311   uc = retrieve_uim_context(uc_);
312   idx = C_INT(idx_);
313 
314   if (uc->candidate_selector_select_cb)
315     uc->candidate_selector_select_cb(uc->ptr, idx);
316 
317   return uim_scm_f();
318 }
319 
320 
321 /* My naming sense seems bad... */
322 static uim_lisp
im_shift_page_candidate(uim_lisp uc_,uim_lisp dir_)323 im_shift_page_candidate(uim_lisp uc_, uim_lisp dir_)
324 {
325   uim_context uc;
326   int dir;
327 
328   uc = retrieve_uim_context(uc_);
329   dir = (C_BOOL(dir_)) ? 1 : 0;
330 
331   if (uc->candidate_selector_shift_page_cb)
332     uc->candidate_selector_shift_page_cb(uc->ptr, dir);
333 
334   return uim_scm_f();
335 }
336 
337 static uim_lisp
im_deactivate_candidate_selector(uim_lisp uc_)338 im_deactivate_candidate_selector(uim_lisp uc_)
339 {
340   uim_context uc;
341 
342   uc = retrieve_uim_context(uc_);
343 
344   if (uc->candidate_selector_deactivate_cb)
345     uc->candidate_selector_deactivate_cb(uc->ptr);
346 
347   return uim_scm_f();
348 }
349 
350 static uim_lisp
im_delay_activate_candidate_selector_supportedp(uim_lisp uc_)351 im_delay_activate_candidate_selector_supportedp(uim_lisp uc_)
352 {
353   uim_context uc;
354 
355   uc = retrieve_uim_context(uc_);
356 
357   if (uc->candidate_selector_delay_activate_cb)
358     return uim_scm_t();
359   return uim_scm_f();
360 }
361 
362 static uim_lisp
im_acquire_text(uim_lisp uc_,uim_lisp text_id_,uim_lisp origin_,uim_lisp former_len_,uim_lisp latter_len_)363 im_acquire_text(uim_lisp uc_, uim_lisp text_id_, uim_lisp origin_,
364 		uim_lisp former_len_, uim_lisp latter_len_)
365 {
366   uim_context uc;
367   int err, former_len, latter_len;
368   enum UTextArea text_id;
369   enum UTextOrigin origin;
370   char *former, *latter, *cv_former, *cv_latter;
371   uim_lisp former_, latter_;
372 
373   uc = retrieve_uim_context(uc_);
374 
375   if (!uc->acquire_text_cb)
376     return uim_scm_f();
377 
378   text_id = C_INT(text_id_);
379   origin = C_INT(origin_);
380   former_len = C_INT(former_len_);
381   latter_len = C_INT(latter_len_);
382 
383   err = uc->acquire_text_cb(uc->ptr, text_id, origin,
384                             former_len, latter_len, &former, &latter);
385   if (err)
386     return uim_scm_f();
387 
388   /* FIXME: string->list is not applied here for each text part. This
389    * interface should be revised when SigScheme has been introduced to
390    * uim. Until then, perform character separation by each input methods if
391    * needed.  -- YamaKen 2006-10-07 */
392   cv_former = uc->conv_if->convert(uc->inbound_conv, former);
393   cv_latter = uc->conv_if->convert(uc->inbound_conv, latter);
394   free(former);
395   free(latter);
396   former_
397     = (TEXT_EMPTYP(cv_former)) ? uim_scm_null() : LIST1(MAKE_STR_DIRECTLY(cv_former));
398   latter_
399     = (TEXT_EMPTYP(cv_latter)) ? uim_scm_null() : LIST1(MAKE_STR_DIRECTLY(cv_latter));
400 
401   return uim_scm_callf("ustr-new", "oo", former_, latter_);
402 }
403 
404 static uim_lisp
im_delete_text(uim_lisp uc_,uim_lisp text_id_,uim_lisp origin_,uim_lisp former_len_,uim_lisp latter_len_)405 im_delete_text(uim_lisp uc_, uim_lisp text_id_, uim_lisp origin_,
406 	       uim_lisp former_len_, uim_lisp latter_len_)
407 {
408   uim_context uc;
409   int err, former_len, latter_len;
410   enum UTextArea text_id;
411   enum UTextOrigin origin;
412 
413   uc = retrieve_uim_context(uc_);
414 
415   if (!uc->delete_text_cb)
416     return uim_scm_f();
417 
418   text_id = C_INT(text_id_);
419   origin = C_INT(origin_);
420   former_len = C_INT(former_len_);
421   latter_len = C_INT(latter_len_);
422 
423   err = uc->delete_text_cb(uc->ptr, text_id, origin, former_len, latter_len);
424 
425   return MAKE_BOOL(!err);
426 }
427 
428 static uim_lisp
raise_configuration_change(uim_lisp uc_)429 raise_configuration_change(uim_lisp uc_)
430 {
431   uim_context uc;
432 
433   uc = retrieve_uim_context(uc_);
434 
435   if (uc->configuration_changed_cb)
436     uc->configuration_changed_cb(uc->ptr);
437 
438   return uim_scm_t();
439 }
440 
441 static uim_lisp
switch_app_global_im(uim_lisp uc_,uim_lisp name_)442 switch_app_global_im(uim_lisp uc_, uim_lisp name_)
443 {
444   uim_context uc;
445   const char *name;
446 
447   uc = retrieve_uim_context(uc_);
448   name = REFER_C_STR(name_);
449 
450   if (uc->switch_app_global_im_cb)
451     uc->switch_app_global_im_cb(uc->ptr, name);
452 
453   return uim_scm_t();
454 }
455 
456 static uim_lisp
switch_system_global_im(uim_lisp uc_,uim_lisp name_)457 switch_system_global_im(uim_lisp uc_, uim_lisp name_)
458 {
459   uim_context uc;
460   const char *name;
461 
462   uc = retrieve_uim_context(uc_);
463   name = REFER_C_STR(name_);
464 
465   if (uc->switch_system_global_im_cb)
466     uc->switch_system_global_im_cb(uc->ptr, name);
467 
468   return uim_scm_t();
469 }
470 
471 void
uim_init_im_subrs(void)472 uim_init_im_subrs(void)
473 {
474   uim_scm_init_proc1("im-retrieve-context", im_retrieve_context);
475   uim_scm_init_proc2("im-set-encoding",     im_set_encoding);
476   uim_scm_init_proc2("im-convertible?",     im_convertiblep);
477 
478   uim_scm_init_proc2("im-commit",           im_commit);
479   uim_scm_init_proc1("im-clear-preedit",    im_clear_preedit);
480   uim_scm_init_proc3("im-pushback-preedit", im_pushback_preedit);
481   uim_scm_init_proc1("im-update-preedit",   im_update_preedit);
482 
483   uim_scm_init_proc3("im-activate-candidate-selector",
484 		     im_activate_candidate_selector);
485   uim_scm_init_proc2("im-select-candidate", im_select_candidate);
486   uim_scm_init_proc2("im-shift-page-candidate", im_shift_page_candidate);
487   uim_scm_init_proc1("im-deactivate-candidate-selector",
488 		     im_deactivate_candidate_selector);
489 
490   uim_scm_init_proc2("im-delay-activate-candidate-selector",
491 		     im_delay_activate_candidate_selector);
492   uim_scm_init_proc1("im-delay-activate-candidate-selector-supported?",
493 		     im_delay_activate_candidate_selector_supportedp);
494 
495   uim_scm_init_proc5("im-acquire-text-internal", im_acquire_text);
496   uim_scm_init_proc5("im-delete-text-internal", im_delete_text);
497 
498   uim_scm_init_proc1("im-clear-mode-list",    im_clear_mode_list);
499   uim_scm_init_proc2("im-pushback-mode-list", im_pushback_mode_list);
500   uim_scm_init_proc1("im-update-mode-list",   im_update_mode_list);
501   uim_scm_init_proc2("im-update-mode",        im_update_mode);
502 
503   uim_scm_init_proc2("im-update-prop-list", im_update_prop_list);
504 
505   uim_scm_init_proc1("im-raise-configuration-change",
506 		     raise_configuration_change);
507   uim_scm_init_proc2("im-switch-app-global-im", switch_app_global_im);
508   uim_scm_init_proc2("im-switch-system-global-im", switch_system_global_im);
509 }
510