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 <stdlib.h>
37 #include <string.h>
38 #include <assert.h>
39 #if !UIM_USE_NOTIFY_PLUGINS
40 #include <stdarg.h>
41 #endif
42 
43 #include "uim.h"
44 #include "uim-internal.h"
45 #include "uim-util.h"
46 #include "uim-iconv.h"
47 #include "uim-posix.h"
48 #include "uim-im-switcher.h"
49 #include "uim-scm.h"
50 #include "uim-scm-abbrev.h"
51 #if UIM_USE_NOTIFY_PLUGINS
52 #include "uim-notify.h"
53 #else
54 #include "gettext.h"
55 #endif
56 
57 
58 enum uim_result {
59   FAILED = -1,
60   OK = 0
61 };
62 
63 static void fatal_error_hook(void);
64 
65 static void *uim_init_internal(void *dummy);
66 struct uim_get_candidate_args {
67   uim_context uc;
68   int index;
69   int enum_hint;
70 };
71 static void *uim_get_candidate_internal(struct uim_get_candidate_args *args);
72 struct uim_delay_activating_args {
73   uim_context uc;
74   int nr;
75   int display_limit;
76   int selected_index;
77 };
78 static void *uim_delay_activating_internal(struct uim_delay_activating_args *);
79 static uim_lisp get_nth_im(uim_context uc, int nth);
80 #ifdef ENABLE_ANTHY_STATIC
81 void uim_anthy_plugin_instance_init(void);
82 void uim_anthy_plugin_instance_quit(void);
83 #endif
84 #ifdef ENABLE_ANTHY_UTF8_STATIC
85 void uim_anthy_utf8_plugin_instance_init(void);
86 void uim_anthy_utf8_plugin_instance_quit(void);
87 #endif
88 
89 static uim_bool uim_initialized;
90 static uim_lisp protected0, protected1;
91 
92 unsigned int uim_init_count;
93 
94 /****************************************************************
95  * Core APIs                                                    *
96  ****************************************************************/
97 static void
fatal_error_hook(void)98 fatal_error_hook(void)
99 {
100   /* actual error message is already printed by the Scheme interpreter */
101   uim_fatal_error("an unhandled error raised from Scheme interpreter");
102 }
103 
104 int
uim_init(void)105 uim_init(void)
106 {
107   int ret;
108   char *sys_load_path;
109 
110   if (uim_initialized)
111     return OK;
112 
113   uim_init_error();
114 
115   if (UIM_CATCH_ERROR_BEGIN())
116     return FAILED;
117 
118   sys_load_path = (uim_issetugid()) ? NULL : getenv("LIBUIM_SYSTEM_SCM_FILES");
119   uim_scm_init(sys_load_path);
120   uim_scm_set_fatal_error_hook(fatal_error_hook);
121 
122   ret = (int)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)uim_init_internal, NULL);
123 
124   UIM_CATCH_ERROR_END();
125 
126   return ret;
127 }
128 
129 static void *
uim_init_internal(void * dummy)130 uim_init_internal(void *dummy)
131 {
132   char *scm_files;
133 
134   protected0 = uim_scm_f();
135   protected1 = uim_scm_f();
136   uim_scm_gc_protect(&protected0);
137   uim_scm_gc_protect(&protected1);
138 
139   /* To allow (cond-expand (uim ...)) in early initialization stages,
140    * provision of the "uim" should be performed as early as possible. */
141   uim_scm_callf("provide", "s", "uim");
142 
143   uim_init_im_subrs();
144   uim_init_intl_subrs();
145   uim_init_iconv_subrs();
146   uim_init_posix_subrs();
147   uim_init_util_subrs();
148 #if UIM_USE_NOTIFY_PLUGINS
149   uim_notify_init();  /* init uim-notify facility */
150 #endif
151   uim_init_notify_subrs();  /* init Scheme interface of uim-notify */
152   uim_init_key_subrs();
153   uim_init_rk_subrs();
154   uim_init_dynlib();
155 #ifdef ENABLE_ANTHY_STATIC
156   uim_anthy_plugin_instance_init();
157 #endif
158 #ifdef ENABLE_ANTHY_UTF8_STATIC
159   uim_anthy_utf8_plugin_instance_init();
160 #endif
161 
162   if (uim_issetugid()) {
163     scm_files = SCM_FILES;
164   } else {
165     scm_files = getenv("LIBUIM_SCM_FILES");
166     scm_files = (scm_files) ? scm_files : SCM_FILES;
167   }
168   uim_scm_set_lib_path(scm_files);
169 
170   uim_scm_require_file("init.scm");
171 
172   uim_initialized = UIM_TRUE;
173 
174   return (void *)OK;
175 }
176 
177 void
uim_quit(void)178 uim_quit(void)
179 {
180   if (!uim_initialized)
181     return;
182 
183   if (UIM_CATCH_ERROR_BEGIN()) {
184     /* Leave uim_initialized uncleared to keep libuim disabled. */
185     return;
186   }
187 
188 #ifdef ENABLE_ANTHY_STATIC
189   uim_anthy_plugin_instance_quit();
190 #endif
191 #ifdef ENABLE_ANTHY_UTF8_STATIC
192   uim_anthy_utf8_plugin_instance_quit();
193 #endif
194 #if UIM_USE_NOTIFY_PLUGINS
195   uim_notify_quit();
196 #endif
197   uim_scm_callf("annotation-unload", "");
198   uim_scm_callf("dynlib-unload-all", "");
199   uim_quit_dynlib();
200   uim_scm_quit();
201   uim_initialized = UIM_FALSE;
202 }
203 
204 uim_context
uim_create_context(void * ptr,const char * enc,const char * lang,const char * engine,struct uim_code_converter * conv,void (* commit_cb)(void * ptr,const char * str))205 uim_create_context(void *ptr,
206 		   const char *enc,
207 		   const char *lang,
208 		   const char *engine,
209 		   struct uim_code_converter *conv,
210 		   void (*commit_cb)(void *ptr, const char *str))
211 {
212   uim_context uc;
213   uim_lisp lang_, engine_;
214 
215   if (UIM_CATCH_ERROR_BEGIN())
216     return NULL;
217 
218   assert(uim_scm_gc_any_contextp());
219 
220   uc = uim_malloc(sizeof(*uc));
221   memset(uc, 0, sizeof(*uc));
222 
223   /* helper system */
224   uc->uim_fd = -1;
225 
226   /* encoding handlings */
227   if (!enc)
228     enc = "UTF-8";
229   uc->client_encoding = uim_strdup(enc);
230   uc->conv_if = (conv) ? conv : uim_iconv;
231 
232   /* variables */
233   uc->is_enabled = UIM_TRUE;
234 
235   /* core callbacks */
236   uc->commit_cb = commit_cb;
237 
238   /* foreign context objects */
239   uc->ptr = ptr;
240 
241   protected0 = lang_ = (lang) ? MAKE_SYM(lang) : uim_scm_f();
242   protected1 = engine_ = (engine) ? MAKE_SYM(engine) : uim_scm_f();
243   uc->sc = uim_scm_f(); /* failsafe */
244   uc->sc = uim_scm_callf("create-context", "poo", uc, lang_, engine_);
245   uim_scm_gc_protect(&uc->sc);
246   uim_scm_callf("setup-context", "o", uc->sc);
247 
248   UIM_CATCH_ERROR_END();
249 
250   return uc;
251 }
252 
253 void
uim_release_context(uim_context uc)254 uim_release_context(uim_context uc)
255 {
256   int i;
257 
258   if (UIM_CATCH_ERROR_BEGIN())
259     return;
260 
261   assert(uim_scm_gc_any_contextp());
262   assert(uc);
263 
264   uim_scm_callf("release-context", "p", uc);
265   uim_scm_gc_unprotect(&uc->sc);
266   if (uc->outbound_conv)
267     uc->conv_if->release(uc->outbound_conv);
268   if (uc->inbound_conv)
269     uc->conv_if->release(uc->inbound_conv);
270   for (i = 0; i < uc->nr_modes; i++) {
271     free(uc->modes[i]);
272     uc->modes[i] = NULL;
273   }
274   free(uc->propstr);
275   free(uc->modes);
276   free(uc->client_encoding);
277 #ifdef DEBUG
278   /* prevents operating on invalidated uim_context */
279   memset(uc, 0, sizeof(*uc));
280 #endif
281   free(uc);
282 
283   UIM_CATCH_ERROR_END();
284 }
285 
286 void
uim_reset_context(uim_context uc)287 uim_reset_context(uim_context uc)
288 {
289   if (UIM_CATCH_ERROR_BEGIN())
290     return;
291 
292   assert(uim_scm_gc_any_contextp());
293   assert(uc);
294 
295   uim_scm_callf("reset-handler", "p", uc);
296 
297   UIM_CATCH_ERROR_END();
298 }
299 
300 void
uim_focus_in_context(uim_context uc)301 uim_focus_in_context(uim_context uc)
302 {
303   if (UIM_CATCH_ERROR_BEGIN())
304     return;
305 
306   assert(uim_scm_gc_any_contextp());
307   assert(uc);
308 
309   uim_scm_callf("focus-in-handler", "p", uc);
310 
311   UIM_CATCH_ERROR_END();
312 }
313 
314 void
uim_focus_out_context(uim_context uc)315 uim_focus_out_context(uim_context uc)
316 {
317   if (UIM_CATCH_ERROR_BEGIN())
318     return;
319 
320   assert(uim_scm_gc_any_contextp());
321   assert(uc);
322 
323   uim_scm_callf("focus-out-handler", "p", uc);
324 
325   UIM_CATCH_ERROR_END();
326 }
327 
328 void
uim_place_context(uim_context uc)329 uim_place_context(uim_context uc)
330 {
331   if (UIM_CATCH_ERROR_BEGIN())
332     return;
333 
334   assert(uim_scm_gc_any_contextp());
335   assert(uc);
336 
337   uim_scm_callf("place-handler", "p", uc);
338 
339   UIM_CATCH_ERROR_END();
340 }
341 
342 void
uim_displace_context(uim_context uc)343 uim_displace_context(uim_context uc)
344 {
345   if (UIM_CATCH_ERROR_BEGIN())
346     return;
347 
348   assert(uim_scm_gc_any_contextp());
349   assert(uc);
350 
351   uim_scm_callf("displace-handler", "p", uc);
352 
353   UIM_CATCH_ERROR_END();
354 }
355 
356 void
uim_set_preedit_cb(uim_context uc,void (* clear_cb)(void * ptr),void (* pushback_cb)(void * ptr,int attr,const char * str),void (* update_cb)(void * ptr))357 uim_set_preedit_cb(uim_context uc,
358 		   void (*clear_cb)(void *ptr),
359 		   void (*pushback_cb)(void *ptr, int attr, const char *str),
360 		   void (*update_cb)(void *ptr))
361 {
362   if (UIM_CATCH_ERROR_BEGIN())
363     return;
364 
365   assert(uim_scm_gc_any_contextp());
366   assert(uc);
367 
368   uc->preedit_clear_cb = clear_cb;
369   uc->preedit_pushback_cb = pushback_cb;
370   uc->preedit_update_cb = update_cb;
371 
372   UIM_CATCH_ERROR_END();
373 }
374 
375 void
uim_set_candidate_selector_cb(uim_context uc,void (* activate_cb)(void * ptr,int nr,int display_limit),void (* select_cb)(void * ptr,int index),void (* shift_page_cb)(void * ptr,int direction),void (* deactivate_cb)(void * ptr))376 uim_set_candidate_selector_cb(uim_context uc,
377                               void (*activate_cb)(void *ptr,
378                                                   int nr, int display_limit),
379                               void (*select_cb)(void *ptr, int index),
380                               void (*shift_page_cb)(void *ptr, int direction),
381                               void (*deactivate_cb)(void *ptr))
382 {
383   if (UIM_CATCH_ERROR_BEGIN())
384     return;
385 
386   assert(uim_scm_gc_any_contextp());
387   assert(uc);
388 
389   uc->candidate_selector_activate_cb   = activate_cb;
390   uc->candidate_selector_select_cb     = select_cb;
391   uc->candidate_selector_deactivate_cb = deactivate_cb;
392   uc->candidate_selector_shift_page_cb = shift_page_cb;
393 
394   UIM_CATCH_ERROR_END();
395 }
396 
397 uim_candidate
uim_get_candidate(uim_context uc,int index,int accel_enumeration_hint)398 uim_get_candidate(uim_context uc, int index, int accel_enumeration_hint)
399 {
400   struct uim_get_candidate_args args;
401   uim_candidate cand;
402 
403   if (UIM_CATCH_ERROR_BEGIN())
404     return NULL;
405 
406   assert(uim_scm_gc_any_contextp());
407   assert(uc);
408   assert(index >= 0);
409   assert(accel_enumeration_hint >= 0);
410 
411   args.uc = uc;
412   args.index = index;
413   args.enum_hint = accel_enumeration_hint;
414 
415   cand = (uim_candidate)uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)uim_get_candidate_internal, &args);
416 
417   UIM_CATCH_ERROR_END();
418 
419   return cand;
420 }
421 
422 static void *
uim_get_candidate_internal(struct uim_get_candidate_args * args)423 uim_get_candidate_internal(struct uim_get_candidate_args *args)
424 {
425   uim_context uc;
426   uim_candidate cand;
427   uim_lisp triple;
428   const char *str, *head, *ann;
429 
430   uc = args->uc;
431   triple = uim_scm_callf("get-candidate", "pii",
432 			 uc, args->index, args->enum_hint);
433   ENSURE((uim_scm_length(triple) == 3), "invalid candidate triple");
434 
435   cand = uim_malloc(sizeof(*cand));
436   memset(cand, 0, sizeof(*cand));
437 
438   str  = REFER_C_STR(CAR(triple));
439   head = REFER_C_STR(CAR(CDR(triple)));
440   ann  = REFER_C_STR(CAR(CDR(CDR((triple)))));
441   cand->str           = uc->conv_if->convert(uc->outbound_conv, str);
442   cand->heading_label = uc->conv_if->convert(uc->outbound_conv, head);
443   cand->annotation    = uc->conv_if->convert(uc->outbound_conv, ann);
444 
445   return (void *)cand;
446 }
447 
448 /* Accepts NULL candidates that produced by an error on uim_get_candidate(). */
449 const char *
uim_candidate_get_cand_str(uim_candidate cand)450 uim_candidate_get_cand_str(uim_candidate cand)
451 {
452   if (UIM_CATCH_ERROR_BEGIN())
453     return "";
454 
455   assert(uim_scm_gc_any_contextp());
456   if (!cand)
457     uim_fatal_error("null candidate");
458 
459   UIM_CATCH_ERROR_END();
460 
461   return cand->str;
462 }
463 
464 const char *
uim_candidate_get_heading_label(uim_candidate cand)465 uim_candidate_get_heading_label(uim_candidate cand)
466 {
467   if (UIM_CATCH_ERROR_BEGIN())
468     return "";
469 
470   assert(uim_scm_gc_any_contextp());
471   if (!cand)
472     uim_fatal_error("null candidate");
473 
474   UIM_CATCH_ERROR_END();
475 
476   return cand->heading_label;
477 }
478 
479 const char *
uim_candidate_get_annotation_str(uim_candidate cand)480 uim_candidate_get_annotation_str(uim_candidate cand)
481 {
482   if (UIM_CATCH_ERROR_BEGIN())
483     return "";
484 
485   assert(uim_scm_gc_any_contextp());
486   if (!cand)
487     uim_fatal_error("null candidate");
488 
489   UIM_CATCH_ERROR_END();
490 
491   return cand->annotation;
492 }
493 
494 void
uim_candidate_free(uim_candidate cand)495 uim_candidate_free(uim_candidate cand)
496 {
497   if (UIM_CATCH_ERROR_BEGIN())
498     return;
499 
500   assert(uim_scm_gc_any_contextp());
501   if (!cand)
502     uim_fatal_error("null candidate");
503 
504   free(cand->str);
505   free(cand->heading_label);
506   free(cand->annotation);
507   free(cand);
508 
509   UIM_CATCH_ERROR_END();
510 }
511 
512 int
uim_get_candidate_index(uim_context uc)513 uim_get_candidate_index(uim_context uc)
514 {
515   if (UIM_CATCH_ERROR_BEGIN())
516     return 0;
517 
518   assert(uim_scm_gc_any_contextp());
519   assert(uc);
520 
521   UIM_CATCH_ERROR_END();
522 
523   return 0;
524 }
525 
526 void
uim_set_candidate_index(uim_context uc,int nth)527 uim_set_candidate_index(uim_context uc, int nth)
528 {
529   if (UIM_CATCH_ERROR_BEGIN())
530     return;
531 
532   assert(uim_scm_gc_any_contextp());
533   assert(uc);
534   assert(nth >= 0);
535 
536   uim_scm_callf("set-candidate-index", "pi", uc, nth);
537 
538   UIM_CATCH_ERROR_END();
539 }
540 
541 void
uim_set_text_acquisition_cb(uim_context uc,int (* acquire_cb)(void * ptr,enum UTextArea text_id,enum UTextOrigin origin,int former_len,int latter_len,char ** former,char ** latter),int (* delete_cb)(void * ptr,enum UTextArea text_id,enum UTextOrigin origin,int former_len,int latter_len))542 uim_set_text_acquisition_cb(uim_context uc,
543 			    int (*acquire_cb)(void *ptr,
544 					      enum UTextArea text_id,
545 					      enum UTextOrigin origin,
546 					      int former_len, int latter_len,
547 					      char **former, char **latter),
548 			    int (*delete_cb)(void *ptr, enum UTextArea text_id,
549 				    	     enum UTextOrigin origin,
550 					     int former_len, int latter_len))
551 {
552   if (UIM_CATCH_ERROR_BEGIN())
553     return;
554 
555   assert(uim_scm_gc_any_contextp());
556   assert(uc);
557 
558   uc->acquire_text_cb = acquire_cb;
559   uc->delete_text_cb = delete_cb;
560 
561   UIM_CATCH_ERROR_END();
562 }
563 
564 uim_bool
uim_input_string(uim_context uc,const char * str)565 uim_input_string(uim_context uc, const char *str)
566 {
567   uim_bool ret;
568   uim_lisp consumed;
569   char *conv;
570 
571   if (UIM_CATCH_ERROR_BEGIN())
572     return UIM_FALSE;
573 
574   assert(uim_scm_gc_any_contextp());
575   assert(uc);
576   assert(str);
577 
578   conv = uc->conv_if->convert(uc->inbound_conv, str);
579   if (conv) {
580     protected0 =
581       consumed = uim_scm_callf("input-string-handler", "ps", uc, conv);
582     free(conv);
583 
584     ret = C_BOOL(consumed);
585   } else {
586     ret = UIM_FALSE;
587   }
588 
589   UIM_CATCH_ERROR_END();
590 
591   return ret;
592 }
593 
594 /****************************************************************
595  * Optional APIs                                                *
596  ****************************************************************/
597 void
uim_set_client_encoding(uim_context uc,const char * encoding)598 uim_set_client_encoding(uim_context uc, const char *encoding)
599 {
600   uim_lisp im_enc;
601 
602   if (UIM_CATCH_ERROR_BEGIN())
603     return;
604 
605   assert(uim_scm_gc_any_contextp());
606   assert(uc);
607   assert(encoding);
608 
609   free(uc->client_encoding);
610   uc->client_encoding = uim_strdup(encoding);
611 
612   protected0 = im_enc = uim_scm_callf("uim-context-encoding", "p", uc);
613   uim_set_encoding(uc, REFER_C_STR(im_enc));
614 
615   UIM_CATCH_ERROR_END();
616 }
617 
618 void
uim_set_configuration_changed_cb(uim_context uc,void (* changed_cb)(void * ptr))619 uim_set_configuration_changed_cb(uim_context uc,
620 				 void (*changed_cb)(void *ptr))
621 {
622   if (UIM_CATCH_ERROR_BEGIN())
623     return;
624 
625   assert(uim_scm_gc_any_contextp());
626   assert(uc);
627 
628   uc->configuration_changed_cb = changed_cb;
629 
630   UIM_CATCH_ERROR_END();
631 }
632 
633 void
uim_set_im_switch_request_cb(uim_context uc,void (* sw_app_im_cb)(void * ptr,const char * name),void (* sw_system_im_cb)(void * ptr,const char * name))634 uim_set_im_switch_request_cb(uim_context uc,
635 			     void (*sw_app_im_cb)(void *ptr, const char *name),
636 			     void (*sw_system_im_cb)(void *ptr,
637                                                      const char *name))
638 {
639   if (UIM_CATCH_ERROR_BEGIN())
640     return;
641 
642   assert(uim_scm_gc_any_contextp());
643   assert(uc);
644 
645   uc->switch_app_global_im_cb = sw_app_im_cb;
646   uc->switch_system_global_im_cb = sw_system_im_cb;
647 
648   UIM_CATCH_ERROR_END();
649 }
650 
651 void
uim_switch_im(uim_context uc,const char * engine)652 uim_switch_im(uim_context uc, const char *engine)
653 {
654   if (UIM_CATCH_ERROR_BEGIN())
655     return;
656 
657   /* related to the commit log of r1400:
658 
659      We should not add the API uim_destroy_context(). We should move
660      IM-switching feature into Scheme instead. It removes the context
661      management code related to IM-switching duplicated in several IM
662      bridges. Refer the implementation of GtkIMMulticontext as example
663      of proxy-like IM-switcher. It does IM-switching without extending
664      immodule API. We should follow its design to make our API simple.
665      -- 2004-10-05 YamaKen
666   */
667   assert(uim_scm_gc_any_contextp());
668   assert(uc);
669   assert(engine);
670 
671   uim_scm_callf("uim-switch-im", "py", uc, engine);
672 
673   UIM_CATCH_ERROR_END();
674 }
675 
676 const char *
uim_get_current_im_name(uim_context uc)677 uim_get_current_im_name(uim_context uc)
678 {
679   uim_lisp im, ret;
680   const char *name;
681 
682   if (UIM_CATCH_ERROR_BEGIN())
683     return "direct";
684 
685   assert(uim_scm_gc_any_contextp());
686   assert(uc);
687 
688   protected0 = im = uim_scm_callf("uim-context-im", "p", uc);
689   protected1 = ret = uim_scm_callf("im-name", "o", im);
690   name = REFER_C_STR(ret);
691 
692   UIM_CATCH_ERROR_END();
693 
694   return name;
695 }
696 
697 const char *
uim_get_default_im_name(const char * localename)698 uim_get_default_im_name(const char *localename)
699 {
700   uim_lisp ret;
701   const char *name;
702 
703   if (UIM_CATCH_ERROR_BEGIN())
704     return "direct";
705 
706   assert(uim_scm_gc_any_contextp());
707   assert(localename);
708 
709   protected0 = ret = uim_scm_callf("uim-get-default-im-name", "s", localename);
710   name = REFER_C_STR(ret);
711 
712   UIM_CATCH_ERROR_END();
713 
714   return name;
715 }
716 
717 const char *
uim_get_im_name_for_locale(const char * localename)718 uim_get_im_name_for_locale(const char *localename)
719 {
720   uim_lisp ret;
721   const char *name;
722 
723   if (UIM_CATCH_ERROR_BEGIN())
724     return "direct";
725 
726   assert(uim_scm_gc_any_contextp());
727   assert(localename);
728 
729   protected0 =
730     ret = uim_scm_callf("uim-get-im-name-for-locale", "s", localename);
731   name = REFER_C_STR(ret);
732 
733   UIM_CATCH_ERROR_END();
734 
735   return name;
736 }
737 
738 #if !UIM_USE_NOTIFY_PLUGINS
739 uim_bool
uim_notify_info(const char * msg_fmt,...)740 uim_notify_info(const char *msg_fmt, ...)
741 {
742   va_list args;
743   int ret;
744 
745   va_start(args, msg_fmt);
746   fputs("libuim: [info] ", stderr);
747   ret = vfprintf(stderr, msg_fmt, args);
748   fputs("\n", stderr);
749   va_end(args);
750 
751   return (ret >= 0);
752 }
753 
754 uim_bool
uim_notify_fatal(const char * msg_fmt,...)755 uim_notify_fatal(const char *msg_fmt, ...)
756 {
757   va_list args;
758   int ret;
759 
760   va_start(args, msg_fmt);
761   fputs("libuim: [fatal] ", stderr);
762   ret = vfprintf(stderr, msg_fmt, args);
763   fputs("\n", stderr);
764   va_end(args);
765 
766   return (ret >= 0);
767 }
768 
769 static uim_lisp
notify_get_plugins(void)770 notify_get_plugins(void)
771 {
772    return CONS(LIST3(MAKE_SYM("builtin"), MAKE_STR(N_("builtin")), MAKE_STR(N_("libuim builtin"))), uim_scm_null());
773 }
774 
775 static uim_lisp
notify_info(uim_lisp msg_)776 notify_info(uim_lisp msg_)
777 {
778   const char *msg = REFER_C_STR(msg_);
779 
780   return MAKE_BOOL(uim_notify_info("%s", dgettext(GETTEXT_PACKAGE, msg)));
781 }
782 
783 static uim_lisp
notify_fatal(uim_lisp msg_)784 notify_fatal(uim_lisp msg_)
785 {
786   const char *msg = REFER_C_STR(msg_);
787 
788   return MAKE_BOOL(uim_notify_fatal("%s", dgettext(GETTEXT_PACKAGE, msg)));
789 }
790 
791 void
uim_init_notify_subrs(void)792 uim_init_notify_subrs(void)
793 {
794   uim_scm_init_proc0("uim-notify-get-plugins", notify_get_plugins);
795   uim_scm_init_proc1("uim-notify-info", notify_info);
796   uim_scm_init_proc1("uim-notify-fatal", notify_fatal);
797 }
798 #endif  /* !UIM_USE_NOTIFY_PLUGINS */
799 
800 void
uim_set_delay_candidate_selector_cb(uim_context uc,void (* delay_activate_cb)(void * ptr,int delay))801 uim_set_delay_candidate_selector_cb(uim_context uc,
802                                     void (*delay_activate_cb)(void *ptr,
803                                                               int delay))
804 {
805   if (UIM_CATCH_ERROR_BEGIN())
806     return;
807 
808   assert(uim_scm_gc_any_contextp());
809   assert(uc);
810 
811   uc->candidate_selector_delay_activate_cb = delay_activate_cb;
812 
813   UIM_CATCH_ERROR_END();
814 }
815 
816 void
uim_delay_activating(uim_context uc,int * nr,int * display_limit,int * selected_index)817 uim_delay_activating(uim_context uc, int *nr, int *display_limit, int *selected_index)
818 {
819   struct uim_delay_activating_args args;
820 
821   if (UIM_CATCH_ERROR_BEGIN())
822     return;
823 
824   assert(uim_scm_gc_any_contextp());
825   assert(uc);
826 
827   args.uc = uc;
828   args.nr = *nr;
829   args.display_limit = *display_limit;
830   args.selected_index = *selected_index;
831 
832   uim_scm_call_with_gc_ready_stack((uim_gc_gate_func_ptr)uim_delay_activating_internal, &args);
833   *nr = args.nr;
834   *display_limit = args.display_limit;
835   *selected_index = args.selected_index;
836 
837   UIM_CATCH_ERROR_END();
838 }
839 
840 static void *
uim_delay_activating_internal(struct uim_delay_activating_args * args)841 uim_delay_activating_internal(struct uim_delay_activating_args *args)
842 {
843   uim_context uc;
844   uim_lisp triple;
845 
846   uc = args->uc;
847   triple = uim_scm_callf("delay-activating-handler", "p", uc);
848   if (LISTP(triple) && uim_scm_length(triple) == 3) {
849     args->nr = C_INT(CAR(triple));
850     args->display_limit = C_INT(CAR(CDR(triple)));
851     args->selected_index = C_INT(CAR(CDR(CDR(triple))));
852   }
853   return NULL;
854 }
855 
856 /****************************************************************
857  * Legacy 'mode' API                                            *
858  ****************************************************************/
859 int
uim_get_nr_modes(uim_context uc)860 uim_get_nr_modes(uim_context uc)
861 {
862   if (UIM_CATCH_ERROR_BEGIN())
863     return 0;
864 
865   assert(uim_scm_gc_any_contextp());
866   assert(uc);
867 
868   UIM_CATCH_ERROR_END();
869 
870   return uc->nr_modes;
871 }
872 
873 const char *
uim_get_mode_name(uim_context uc,int nth)874 uim_get_mode_name(uim_context uc, int nth)
875 {
876   if (UIM_CATCH_ERROR_BEGIN())
877     return NULL;
878 
879   assert(uim_scm_gc_any_contextp());
880   assert(uc);
881   assert(nth >= 0);
882   assert(nth < uc->nr_modes);
883 
884   UIM_CATCH_ERROR_END();
885 
886   return uc->modes[nth];
887 }
888 
889 int
uim_get_current_mode(uim_context uc)890 uim_get_current_mode(uim_context uc)
891 {
892   if (UIM_CATCH_ERROR_BEGIN())
893     return 0;
894 
895   assert(uim_scm_gc_any_contextp());
896   assert(uc);
897 
898   UIM_CATCH_ERROR_END();
899 
900   return uc->mode;
901 }
902 
903 void
uim_set_mode(uim_context uc,int mode)904 uim_set_mode(uim_context uc, int mode)
905 {
906   if (UIM_CATCH_ERROR_BEGIN())
907     return;
908 
909   assert(uim_scm_gc_any_contextp());
910   assert(uc);
911   assert(mode >= 0);
912 
913   uc->mode = mode;
914   uim_scm_callf("mode-handler", "pi", uc, mode);
915 
916   UIM_CATCH_ERROR_END();
917 }
918 
919 void
uim_set_mode_cb(uim_context uc,void (* update_cb)(void * ptr,int mode))920 uim_set_mode_cb(uim_context uc, void (*update_cb)(void *ptr, int mode))
921 {
922   if (UIM_CATCH_ERROR_BEGIN())
923     return;
924 
925   assert(uim_scm_gc_any_contextp());
926   assert(uc);
927 
928   UIM_CATCH_ERROR_END();
929 
930   uc->mode_update_cb = update_cb;
931 }
932 
933 void
uim_set_mode_list_update_cb(uim_context uc,void (* update_cb)(void * ptr))934 uim_set_mode_list_update_cb(uim_context uc, void (*update_cb)(void *ptr))
935 {
936   if (UIM_CATCH_ERROR_BEGIN())
937     return;
938 
939   assert(uim_scm_gc_any_contextp());
940   assert(uc);
941 
942   UIM_CATCH_ERROR_END();
943 
944   uc->mode_list_update_cb = update_cb;
945 }
946 
947 /****************************************************************
948  * Legacy 'property list' API                                   *
949  ****************************************************************/
950 void
uim_set_prop_list_update_cb(uim_context uc,void (* update_cb)(void * ptr,const char * str))951 uim_set_prop_list_update_cb(uim_context uc,
952 			    void (*update_cb)(void *ptr, const char *str))
953 {
954   if (UIM_CATCH_ERROR_BEGIN())
955     return;
956 
957   assert(uim_scm_gc_any_contextp());
958   assert(uc);
959 
960   uc->prop_list_update_cb = update_cb;
961 
962   UIM_CATCH_ERROR_END();
963 }
964 
965 /* Obsolete */
966 void
uim_set_prop_label_update_cb(uim_context uc,void (* update_cb)(void * ptr,const char * str))967 uim_set_prop_label_update_cb(uim_context uc,
968 			     void (*update_cb)(void *ptr, const char *str))
969 {
970   if (UIM_CATCH_ERROR_BEGIN())
971     return;
972 
973   assert(uim_scm_gc_any_contextp());
974   assert(uc);
975 
976   UIM_CATCH_ERROR_END();
977 }
978 
979 void
uim_prop_list_update(uim_context uc)980 uim_prop_list_update(uim_context uc)
981 {
982   if (UIM_CATCH_ERROR_BEGIN())
983     return;
984 
985   assert(uim_scm_gc_any_contextp());
986   assert(uc);
987 
988   if (uc->propstr && uc->prop_list_update_cb)
989     uc->prop_list_update_cb(uc->ptr, uc->propstr);
990 
991   UIM_CATCH_ERROR_END();
992 }
993 
994 /* Obsolete */
995 void
uim_prop_label_update(uim_context uc)996 uim_prop_label_update(uim_context uc)
997 {
998   if (UIM_CATCH_ERROR_BEGIN())
999     return;
1000 
1001   assert(uim_scm_gc_any_contextp());
1002   assert(uc);
1003 
1004   UIM_CATCH_ERROR_END();
1005 }
1006 
1007 void
uim_prop_activate(uim_context uc,const char * str)1008 uim_prop_activate(uim_context uc, const char *str)
1009 {
1010   if (UIM_CATCH_ERROR_BEGIN())
1011     return;
1012 
1013   assert(uim_scm_gc_any_contextp());
1014   assert(uc);
1015   assert(str);
1016 
1017   uim_scm_callf("prop-activate-handler", "ps", uc, str);
1018 
1019   UIM_CATCH_ERROR_END();
1020 }
1021 
1022 /****************************************************************
1023  * Legacy 'custom' API                                          *
1024  ****************************************************************/
1025 /* Tentative name. I followed above uim_prop_update_custom, but prop
1026 would not be proper to this function. */
1027 /*
1028  * As I described in doc/HELPER-PROTOCOL, it had wrongly named by my
1029  * misunderstanding about what is the 'property' of uim. It should be
1030  * renamed along with corresponding procol names when an appropriate
1031  * time has come.  -- YamaKen 2005-09-12
1032  */
1033 /** Update custom value from property message.
1034  * Update custom value from property message. The implementation
1035  * avoids arbitrary sexp evaluation for both custom symbol \a custom
1036  * and custom value \a val.
1037  */
1038 void
uim_prop_update_custom(uim_context uc,const char * custom,const char * val)1039 uim_prop_update_custom(uim_context uc, const char *custom, const char *val)
1040 {
1041   if (UIM_CATCH_ERROR_BEGIN())
1042     return;
1043 
1044   assert(uim_scm_gc_any_contextp());
1045   assert(uc);
1046   assert(custom);
1047   assert(val);
1048 
1049   uim_scm_callf("custom-set-handler", "pys", uc, custom, val);
1050 
1051   UIM_CATCH_ERROR_END();
1052 }
1053 
1054 uim_bool
uim_prop_reload_configs(void)1055 uim_prop_reload_configs(void)
1056 {
1057   if (UIM_CATCH_ERROR_BEGIN())
1058     return UIM_FALSE;
1059 
1060   assert(uim_scm_gc_any_contextp());
1061 
1062   /* FIXME: handle return value properly. */
1063   uim_scm_callf("custom-reload-user-configs", "");
1064 
1065   UIM_CATCH_ERROR_END();
1066 
1067   return UIM_TRUE;
1068 }
1069 
1070 /****************************************************************
1071  * Legacy nth-index based IM management APIs                    *
1072  ****************************************************************/
1073 int
uim_get_nr_im(uim_context uc)1074 uim_get_nr_im(uim_context uc)
1075 {
1076   uim_lisp n_;
1077   int n;
1078 
1079   if (UIM_CATCH_ERROR_BEGIN())
1080     return 0;
1081 
1082   assert(uim_scm_gc_any_contextp());
1083   assert(uc);
1084 
1085   protected0 = n_ = uim_scm_callf("uim-n-convertible-ims", "p", uc);
1086   n = C_INT(n_);
1087 
1088   UIM_CATCH_ERROR_END();
1089 
1090   return n;
1091 }
1092 
1093 static uim_lisp
get_nth_im(uim_context uc,int nth)1094 get_nth_im(uim_context uc, int nth)
1095 {
1096   assert(uim_scm_gc_any_contextp());
1097   assert(uc);
1098   assert(nth >= 0);
1099 
1100   return uim_scm_callf("uim-nth-convertible-im", "pi", uc, nth);
1101 }
1102 
1103 const char *
uim_get_im_name(uim_context uc,int nth)1104 uim_get_im_name(uim_context uc, int nth)
1105 {
1106   uim_lisp im, str_;
1107   const char *str;
1108 
1109   if (UIM_CATCH_ERROR_BEGIN())
1110     return NULL;
1111 
1112   protected0 = im = get_nth_im(uc, nth);
1113   protected1 = str_ = uim_scm_callf("im-name", "o", im);
1114   str = REFER_C_STR(str_);
1115 
1116   UIM_CATCH_ERROR_END();
1117 
1118   return str;
1119 }
1120 
1121 const char *
uim_get_im_language(uim_context uc,int nth)1122 uim_get_im_language(uim_context uc, int nth)
1123 {
1124   uim_lisp im, str_;
1125   const char *str;
1126 
1127   if (UIM_CATCH_ERROR_BEGIN())
1128     return NULL;
1129 
1130   protected0 = im = get_nth_im(uc, nth);
1131   protected1 = str_ = uim_scm_callf("im-lang", "o", im);
1132   str = REFER_C_STR(str_);
1133 
1134   UIM_CATCH_ERROR_END();
1135 
1136   return str;
1137 }
1138 
1139 const char *
uim_get_im_encoding(uim_context uc,int nth)1140 uim_get_im_encoding(uim_context uc, int nth)
1141 {
1142   uim_lisp im, str_;
1143   const char *str;
1144 
1145   if (UIM_CATCH_ERROR_BEGIN())
1146     return NULL;
1147 
1148   protected0 = im = get_nth_im(uc, nth);
1149   protected1 = str_ = uim_scm_callf("im-encoding", "o", im);
1150   str = REFER_C_STR(str_);
1151 
1152   UIM_CATCH_ERROR_END();
1153 
1154   return str;
1155 }
1156 
1157 const char *
uim_get_im_short_desc(uim_context uc,int nth)1158 uim_get_im_short_desc(uim_context uc, int nth)
1159 {
1160   uim_lisp im, short_desc;
1161   const char *str;
1162 
1163   if (UIM_CATCH_ERROR_BEGIN())
1164     return NULL;
1165 
1166   protected0 = im = get_nth_im(uc, nth);
1167   protected1 = short_desc = uim_scm_callf("im-short-desc", "o", im);
1168   str = (FALSEP(short_desc)) ? "-" : REFER_C_STR(short_desc);
1169 
1170   UIM_CATCH_ERROR_END();
1171 
1172   return str;
1173 }
1174