1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2 
3 #include "mc_im.h"
4 
5 #include <pobl/bl_mem.h> /* free */
6 #include <pobl/bl_debug.h>
7 #include <pobl/bl_file.h>
8 #include <pobl/bl_conf_io.h>
9 #include <pobl/bl_dlfcn.h>
10 #include <pobl/bl_map.h>
11 #include <pobl/bl_str.h> /* strdup */
12 #include <pobl/bl_def.h> /* USE_WIN32API */
13 #include <glib.h>
14 #include <c_intl.h>
15 #include <dirent.h>
16 #include <im_info.h>
17 
18 #include "mc_combo.h"
19 #include "mc_io.h"
20 
21 #if 0
22 #define __DEBUG
23 #endif
24 
25 #if defined(USE_WIN32API)
26 #define CONFIG_PATH "."
27 #elif defined(SYSCONFDIR)
28 #define CONFIG_PATH SYSCONFDIR
29 #else
30 #define CONFIG_PATH "/etc"
31 #endif
32 
33 #ifndef LIBDIR
34 #define IM_DIR "/usr/local/lib/mlterm/"
35 #else
36 #define IM_DIR LIBDIR "/mlterm/"
37 #endif
38 
39 #define STR_LEN 256
40 
41 BL_MAP_TYPEDEF(xim_locale, char *, char *);
42 
43 #define IM_MAX 20
44 
45 typedef enum im_type {
46   IM_NONE = 0,
47   IM_XIM = 1,
48   IM_OTHER = 2,
49 
50   IM_TYPE_MAX = IM_MAX
51 
52 } im_type_t;
53 
54 typedef im_info_t *(*im_get_info_func_t)(char *, char *);
55 
56 /* --- static variables --- */
57 
58 static char *cur_locale;
59 
60 static im_type_t im_type;
61 static im_type_t cur_im_type;
62 
63 static char **xims;
64 static char **locales;
65 static u_int num_xims;
66 
67 static int is_changed = 0;
68 
69 static char xim_auto_str[STR_LEN] = "";
70 static char current_locale_str[STR_LEN] = "";
71 static char selected_xim_name[STR_LEN] = "";
72 static char selected_xim_locale[STR_LEN] = "";
73 
74 static im_info_t *im_info_table[IM_MAX];
75 static u_int num_info = 0;
76 static im_info_t *selected_im = NULL;
77 static int selected_im_arg = -1;
78 
79 static GtkWidget **im_opt_widget;
80 
81 static GtkWidget *skk_dict_entry;
82 static GtkWidget *skk_sskey_entry;
83 static GtkWidget *wnn_serv_entry;
84 
85 /* --- static functions --- */
86 
is_im_plugin(char * file_name)87 static int is_im_plugin(char *file_name) {
88   if (bl_dl_is_module(file_name) && strstr(file_name, "im-")) {
89     return 1;
90   }
91 
92   return 0;
93 }
94 
95 #ifdef USE_WIN32API
get_kbd_info(char * locale,char * encoding)96 static im_info_t *get_kbd_info(char *locale, char *encoding) {
97   im_info_t *result;
98 
99   if (!(result = malloc(sizeof(im_info_t)))) {
100     return NULL;
101   }
102 
103   result->num_args = 13;
104 
105   if (!(result->args = malloc(sizeof(char *) * result->num_args))) {
106     free(result);
107     return NULL;
108   }
109 
110   if (!(result->readable_args = malloc(sizeof(char *) * result->num_args))) {
111     free(result->args);
112     free(result);
113     return NULL;
114   }
115 
116   result->readable_args[0] = strdup("Unknown");
117   result->readable_args[1] = strdup("Arabic");
118   result->readable_args[2] = strdup("Hebrew");
119   result->readable_args[3] = strdup("Indic (ASSAMESE)");
120   result->readable_args[4] = strdup("Indic (BENGALI)");
121   result->readable_args[5] = strdup("Indic (GUJARATI)");
122   result->readable_args[6] = strdup("Indic (HINDI)");
123   result->readable_args[7] = strdup("Indic (KANNADA)");
124   result->readable_args[8] = strdup("Indic (MALAYALAM)");
125   result->readable_args[9] = strdup("Indic (ORIYA)");
126   result->readable_args[10] = strdup("Indic (PUNJABI)");
127   result->readable_args[11] = strdup("Indic (TAMIL)");
128   result->readable_args[12] = strdup("Indic (TELUGU)");
129 
130   result->args[0] = strdup("");
131   result->args[1] = strdup("arabic");
132   result->args[2] = strdup("hebrew");
133   result->args[3] = strdup("isciiassamese");
134   result->args[4] = strdup("isciibengali");
135   result->args[5] = strdup("isciigujarati");
136   result->args[6] = strdup("isciihindi");
137   result->args[7] = strdup("isciikannada");
138   result->args[8] = strdup("isciimalayalam");
139   result->args[9] = strdup("isciioriya");
140   result->args[10] = strdup("isciipunjabi");
141   result->args[11] = strdup("isciitamil");
142   result->args[12] = strdup("isciitelugu");
143 
144   result->id = strdup("kbd");
145   result->name = strdup("keyboard");
146 
147   return result;
148 }
149 #endif
150 
get_im_info(char * locale,char * encoding)151 static int get_im_info(char *locale, char *encoding) {
152   char *im_dir_path;
153   DIR *dir;
154   struct dirent *d;
155   const char *gui;
156 
157   if ((dir = opendir(IM_DIR))) {
158     im_dir_path = IM_DIR;
159 #if 0
160   } else if ((dir = opendir("."))) {
161     im_dir_path = "";
162 #endif
163   } else {
164 #ifdef USE_WIN32API
165     if ((im_info_table[num_info] = get_kbd_info(locale, encoding))) {
166       num_info++;
167       return 1;
168     }
169 #endif
170     return 0;
171   }
172 
173   gui = mc_get_gui();
174 
175   while ((d = readdir(dir))) {
176     im_info_t *info;
177     char symname[100];
178     char *p;
179     char *end;
180     bl_dl_handle_t handle;
181 
182     if (d->d_name[0] == '.' || !is_im_plugin(d->d_name)) continue;
183 
184     /* libim-foo.so -> libim-foo */
185     if (!(p = strchr(d->d_name, '.'))) continue;
186     *p = '\0';
187 
188     /* libim-foo -> im-foo */
189     if (!(p = strstr(d->d_name, "im-"))) continue;
190 
191     end = p + strlen(p);
192     if (strcmp(gui, "sdl2") == 0) {
193       end -= 5;
194       if (strcmp(end, "-sdl2") != 0) {
195         continue;
196       }
197     } else if (strcmp(gui, "fb") == 0 || strcmp(gui, "console") == 0 ||
198                strcmp(gui, "wayland") == 0) {
199       end -= 3;
200       if (strcmp(end, *gui == 'w' ? "-wl" : "-fb") != 0) {
201         continue;
202       }
203     }
204 
205     if ((handle = bl_dl_open(im_dir_path, p))) {
206       im_get_info_func_t func;
207 
208       *end = '\0';
209       snprintf(symname, 100, "im_%s_get_info", &p[3]);
210 
211       if ((func = (im_get_info_func_t)bl_dl_func_symbol(handle, symname))) {
212         if ((info = (*func)(locale, encoding))) {
213           im_info_table[num_info] = info;
214           num_info++;
215         }
216       }
217 
218       bl_dl_close(handle);
219     }
220   }
221 
222   return 0;
223 }
224 
225 /*
226  * XIM
227  */
228 
get_xim_locale(char * xim)229 static char *get_xim_locale(char *xim) {
230   int count;
231 
232   for (count = 0; count < num_xims; count++) {
233     if (strcmp(xims[count], xim) == 0) {
234       return locales[count];
235     }
236   }
237 
238   return NULL;
239 }
240 
xim_selected(GtkWidget * widget,gpointer data)241 static gint xim_selected(GtkWidget *widget, gpointer data) {
242   char *locale;
243 
244   snprintf(selected_xim_name, STR_LEN, "%s", gtk_entry_get_text(GTK_ENTRY(widget)));
245 
246   if ((locale = get_xim_locale(selected_xim_name))) {
247     gtk_entry_set_text(GTK_ENTRY(data), locale);
248   } else {
249     gtk_entry_set_text(GTK_ENTRY(data), current_locale_str);
250   }
251 
252   snprintf(selected_xim_locale, STR_LEN, "%s", gtk_entry_get_text(GTK_ENTRY(data)));
253 
254   is_changed = 1;
255 
256   return 1;
257 }
258 
read_xim_conf(BL_MAP (xim_locale)xim_locale_table,char * filename)259 static int read_xim_conf(BL_MAP(xim_locale) xim_locale_table, char *filename) {
260   bl_file_t *from;
261   char *key;
262   char *value;
263   BL_PAIR(xim_locale) pair;
264   int result;
265 
266   if (!(from = bl_file_open(filename, "r"))) {
267 #ifdef DEBUG
268     bl_warn_printf(BL_DEBUG_TAG " %s couldn't be opened.\n", filename);
269 #endif
270 
271     return 0;
272   }
273 
274   while (bl_conf_io_read(from, &key, &value)) {
275     bl_map_get(xim_locale_table, key, pair);
276 
277     if (pair) {
278       free(pair->value);
279       pair->value = strdup(value);
280     } else {
281       key = strdup(key);
282       value = strdup(value);
283 
284       bl_map_set(result, xim_locale_table, key, value);
285     }
286   }
287 
288   bl_file_close(from);
289 
290   return 1;
291 }
292 
xim_widget_new(const char * xim_name,const char * xim_locale,const char * cur_locale)293 static GtkWidget *xim_widget_new(const char *xim_name, const char *xim_locale,
294                                  const char *cur_locale) {
295   BL_MAP(xim_locale) xim_locale_table;
296   BL_PAIR(xim_locale) * array;
297   u_int size;
298   char *rcpath;
299   char *default_xim_name;
300   GtkWidget *vbox;
301   GtkWidget *hbox;
302   GtkWidget *label;
303   GtkWidget *entry;
304   GtkWidget *combo;
305   GtkWidget *combo_entry;
306   int count;
307 
308   default_xim_name = mc_get_str_value("default_xim_name");
309   snprintf(xim_auto_str, STR_LEN, _("auto (currently %s)"), default_xim_name);
310   free(default_xim_name);
311 
312   /*
313    * create known xim list from <prefix>/etc/mlterm/xim and/or
314    * ~/.mlterm/xim.
315    */
316 
317   bl_map_new_with_size(char *, char *, xim_locale_table, bl_map_hash_str, bl_map_compare_str, 16);
318 
319   bl_set_sys_conf_dir(CONFIG_PATH);
320 
321   if ((rcpath = bl_get_sys_rc_path("mlterm/xim"))) {
322     read_xim_conf(xim_locale_table, rcpath);
323     free(rcpath);
324   }
325 
326   if ((rcpath = bl_get_user_rc_path("mlterm/xim"))) {
327     read_xim_conf(xim_locale_table, rcpath);
328     free(rcpath);
329   }
330 
331   bl_map_get_pairs_array(xim_locale_table, array, size);
332 
333   if ((xims = malloc(sizeof(char *) * (size + 1))) == NULL ||
334       (locales = malloc(sizeof(char *) * (size + 1))) == NULL) {
335     free(xims);
336     bl_map_destroy(xim_locale_table);
337 
338     return NULL;
339   }
340 
341   for (count = 0; count < size; count++) {
342     xims[count] = array[count]->key;
343     locales[count] = array[count]->value;
344   }
345 
346   xims[count] = xim_auto_str;
347   locales[count] = NULL;
348 
349   num_xims = size + 1;
350 
351   bl_map_destroy(xim_locale_table);
352 
353   /*
354    * create widgets
355    */
356 
357   vbox = gtk_vbox_new(FALSE, 5);
358 
359   snprintf(current_locale_str, STR_LEN, _("auto (currently %s)"), cur_locale);
360   entry = gtk_entry_new();
361   snprintf(selected_xim_locale, STR_LEN, "%s", xim_locale ? xim_locale : current_locale_str);
362   gtk_entry_set_text(GTK_ENTRY(entry), selected_xim_locale);
363 
364   snprintf(selected_xim_name, STR_LEN, "%s", xim_name ? xim_name : xim_auto_str);
365   combo = mc_combo_new(_("XIM Server"), xims, num_xims, selected_xim_name, 0, &combo_entry);
366   g_signal_connect(combo_entry, "changed", G_CALLBACK(xim_selected), entry);
367 
368   label = gtk_label_new(_("XIM locale"));
369 
370   hbox = gtk_hbox_new(FALSE, 5);
371 
372   gtk_box_pack_start(GTK_BOX(vbox), combo, TRUE, TRUE, 0);
373   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
374   gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
375   gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
376 
377   gtk_widget_show(combo);
378   gtk_widget_show(entry);
379   gtk_widget_show(label);
380   gtk_widget_show(hbox);
381 
382   return vbox;
383 }
384 
385 /*
386  * pluggable ims
387  */
388 
im_selected(GtkWidget * widget,gpointer data)389 static gint im_selected(GtkWidget *widget, gpointer data) {
390   const char *str;
391   int i;
392 
393   if (selected_im == NULL) return 1;
394 
395   str = (const char *)gtk_entry_get_text(GTK_ENTRY(widget));
396 
397   for (i = 0; i < selected_im->num_args; i++)
398     if (strcmp(selected_im->readable_args[i], str) == 0) selected_im_arg = i;
399 
400   is_changed = 1;
401 
402   return 1;
403 }
404 
im_widget_new(int nth_im,const char * value,char * locale)405 static GtkWidget *im_widget_new(int nth_im, const char *value, char *locale) {
406   GtkWidget *combo;
407   GtkWidget *entry;
408   im_info_t *info;
409   int i;
410   int selected = 0;
411   size_t len;
412 
413   info = im_info_table[nth_im];
414 
415   if (value) {
416     for (i = 1; i < info->num_args; i++) {
417       if (strcmp(info->args[i], value) == 0) {
418         selected = i;
419       }
420     }
421   }
422 
423   if (!info->num_args) return NULL;
424 
425   if (!value || (value && selected)) {
426     char *auto_str;
427 
428     /*
429      * replace gettextized string
430      */
431     len = strlen(_("auto (currently %s)")) + strlen(info->readable_args[0]) + 1;
432 
433     if ((auto_str = malloc(len))) {
434       snprintf(auto_str, len, _("auto (currently %s)"), info->readable_args[0]);
435       free(info->readable_args[0]);
436       info->readable_args[0] = auto_str;
437     }
438   } else {
439     free(info->readable_args[0]);
440     info->readable_args[0] = strdup(value);
441   }
442 
443   combo = mc_combo_new(_("Option"), info->readable_args, info->num_args,
444                        info->readable_args[selected], 1, &entry);
445   g_signal_connect(entry, "changed", G_CALLBACK(im_selected), NULL);
446 
447   return combo;
448 }
449 
entry_selected(GtkWidget * widget,gpointer data)450 static gint entry_selected(GtkWidget *widget, gpointer data) {
451   is_changed = 1;
452 
453   return 1;
454 }
455 
entry_with_label_new(GtkWidget * parent,const char * text,const char * value)456 static GtkWidget *entry_with_label_new(GtkWidget *parent, const char *text, const char *value) {
457   GtkWidget *hbox;
458   GtkWidget *label;
459   GtkWidget *entry;
460 
461   hbox = gtk_hbox_new(FALSE, 5);
462   gtk_box_pack_start(GTK_BOX(parent), hbox, TRUE, TRUE, 0);
463   gtk_widget_show(hbox);
464 
465   label = gtk_label_new(text);
466   gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
467   gtk_widget_show(label);
468 
469   entry = gtk_entry_new();
470   gtk_entry_set_text(GTK_ENTRY(entry), value);
471   g_signal_connect(entry, "changed", G_CALLBACK(entry_selected), entry);
472   gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
473   gtk_widget_show(entry);
474 
475   return entry;
476 }
477 
combo_with_label_new(GtkWidget * parent,const char * label_name,char ** item_names,u_int item_num,const char * value)478 static GtkWidget *combo_with_label_new(GtkWidget *parent, const char *label_name,
479                                        char **item_names, u_int item_num, const char *value) {
480   GtkWidget *hbox;
481   GtkWidget *combo;
482   GtkWidget *entry;
483 
484   hbox = gtk_hbox_new(FALSE, 5);
485   gtk_box_pack_start(GTK_BOX(parent), hbox, TRUE, TRUE, 0);
486   gtk_widget_show(hbox);
487 
488   combo = mc_combo_new(label_name, item_names, item_num, value, 0, &entry);
489   gtk_box_pack_start(GTK_BOX(hbox), combo, TRUE, TRUE, 0);
490   gtk_widget_show(combo);
491   g_signal_connect(entry, "changed", G_CALLBACK(entry_selected), entry);
492 
493   return entry;
494 }
495 
skk_widget_new(char * value)496 static GtkWidget *skk_widget_new(char *value) {
497   GtkWidget *vbox;
498   char *dict = NULL;
499   char *sskey = NULL;
500   char buf[2];
501   char *cands[] = { ";", ":", "Muhenkan", "Henkan", };
502 
503   /* Same processing as im_skk_new() in im_skk.c */
504   if (value) {
505 #if 1
506     /* XXX Compat with 3.8.3 or before. */
507     if (!strchr(value, '=')) {
508       dict = value;
509     } else
510 #endif
511     {
512       char *next;
513 
514       do {
515         if ((next = strchr(value, ','))) {
516           *(next++) = '\0';
517         }
518 
519         if (strncmp(value, "sskey=", 6) == 0) {
520           int digit;
521           sskey = value + 6;
522           if (sscanf(sskey, "\\x%x", &digit) == 1) {
523             buf[0] = digit;
524             buf[1] = '\0';
525             sskey = buf;
526           }
527         } else if (strncmp(value, "dict=", 5) == 0) {
528           dict = value + 5;
529         }
530       } while ((value = next));
531     }
532   }
533 
534   vbox = gtk_vbox_new(FALSE, 5);
535   skk_dict_entry = entry_with_label_new(vbox, _("Dictionary"), dict ? dict : "");
536   skk_sskey_entry = combo_with_label_new(vbox, _("Sticky shift key"), cands,
537                                          sizeof(cands) / sizeof(cands[0]),
538                                          sskey ? sskey : "");
539 
540   return vbox;
541 }
542 
skk_current_value(void)543 static char *skk_current_value(void) {
544   const char *dict;
545   const char *sskey;
546   size_t len = 4;
547   char *value;
548   char *p;
549 
550   dict = gtk_entry_get_text(GTK_ENTRY(skk_dict_entry));
551   if (*dict) {
552     len += (strlen(dict) + 5 + 1);
553   }
554   sskey = gtk_entry_get_text(GTK_ENTRY(skk_sskey_entry));
555   if (*sskey) {
556     len += (strlen(sskey) + 6 + 1);
557   }
558 
559   value = p = malloc(len);
560 
561   strcpy(p, "skk");
562   p += 3;
563 
564   if (*dict) {
565     sprintf(p, ":dict=%s", dict);
566     p += strlen(p);
567   }
568   if (*sskey) {
569     char sep = *dict ? ',' : ':';
570 
571     if (strlen(sskey) == 1) {
572       sprintf(p, "%csskey=\\x%.2x", sep, *sskey);
573     } else {
574       sprintf(p, "%csskey=%s", sep, sskey);
575     }
576   }
577 
578   return value;
579 }
580 
wnn_widget_new(char * value)581 static GtkWidget *wnn_widget_new(char *value) {
582   GtkWidget *vbox;
583 
584   vbox = gtk_vbox_new(FALSE, 5);
585   wnn_serv_entry = entry_with_label_new(vbox, _("Server"), value);
586 
587   return vbox;
588 }
589 
wnn_current_value(void)590 static char *wnn_current_value(void) {
591   const char *serv;
592   size_t len = 4;
593   char *value;
594 
595   serv = gtk_entry_get_text(GTK_ENTRY(wnn_serv_entry));
596   if (*serv) {
597     len += (strlen(serv) + 1);
598   }
599 
600   value = malloc(len);
601 
602   if (*serv) {
603     sprintf(value, "wnn:%s", serv);
604   } else {
605     strcpy(value, "wnn");
606   }
607 
608   return value;
609 }
610 
611 /*
612  * callbacks for radio buttons of im type.
613  */
button_xim_checked(GtkWidget * widget,gpointer data)614 static gint button_xim_checked(GtkWidget *widget, gpointer data) {
615   if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
616     if (data) gtk_widget_show(GTK_WIDGET(data));
617     im_type = IM_XIM;
618   } else {
619     if (data) gtk_widget_hide(GTK_WIDGET(data));
620   }
621 
622   is_changed = 1;
623 
624   return 1;
625 }
626 
button_im_checked(GtkWidget * widget,gpointer data)627 static gint button_im_checked(GtkWidget *widget, gpointer data) {
628   int i;
629   int idx = 0;
630 
631   if (data == NULL || num_info == 0) {
632     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
633       im_type = IM_NONE;
634     }
635   } else {
636     for (i = 0; i < num_info; i++)
637       if (im_info_table[i] == data) idx = i;
638 
639     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
640       im_type = IM_OTHER + idx;
641       selected_im = data;
642       if (im_opt_widget[idx]) gtk_widget_show(GTK_WIDGET(im_opt_widget[idx]));
643     } else {
644       if (im_opt_widget[idx]) gtk_widget_hide(GTK_WIDGET(im_opt_widget[idx]));
645     }
646   }
647 
648   is_changed = 1;
649 
650   return 1;
651 }
652 
653 /* --- global functions --- */
654 
mc_im_init(void)655 void mc_im_init(void) {
656   char *encoding = mc_get_str_value("encoding");
657 
658   cur_locale = mc_get_str_value("locale"); /* XXX leaked */
659 
660   get_im_info(cur_locale, encoding);
661 
662   free(encoding);
663 }
664 
mc_im_config_widget_new(void)665 GtkWidget *mc_im_config_widget_new(void) {
666   char *xim_name = NULL;
667   char *xim_locale = NULL;
668   char *value;
669   char *im_name;
670   int i;
671   int index = -1;
672   GtkWidget *xim;
673   GtkWidget *frame;
674   GtkWidget *vbox;
675   GtkWidget *hbox;
676   GtkWidget *radio;
677   GSList *group;
678 
679   value = mc_get_str_value("input_method");
680 
681   im_name = bl_str_sep(&value, ":");
682 
683   im_type = IM_NONE;
684   if (strncmp(im_name, "xim", 3) == 0) {
685     im_type = IM_XIM;
686     xim_name = bl_str_sep(&value, ":");
687     xim_locale = bl_str_sep(&value, ":");
688   } else if (strncmp(im_name, "none", 4) == 0) {
689     /* do nothing */
690   } else {
691     for (i = 0; i < num_info; i++) {
692       if (strcmp(im_name, im_info_table[i]->id) == 0) {
693         index = i;
694         im_type = IM_OTHER + i;
695         break;
696       }
697     }
698   }
699   cur_im_type = im_type;
700 
701   if (strcmp(mc_get_gui(), "xlib") != 0) {
702     xim = NULL;
703   } else {
704     xim = xim_widget_new(xim_name, xim_locale, cur_locale);
705   }
706 
707   im_opt_widget = malloc(sizeof(GtkWidget*) * num_info);
708 
709   for (i = 0; i < num_info; i++) {
710     if (strcmp(im_info_table[i]->id, "skk") == 0)
711       im_opt_widget[i] = skk_widget_new(index == i ? value : "");
712     else if (strcmp(im_info_table[i]->id, "wnn") == 0)
713       im_opt_widget[i] = wnn_widget_new(index == i ? value : "");
714     else
715       im_opt_widget[i] = im_widget_new(i, index == i ? value : NULL, cur_locale);
716   }
717 
718   free(im_name);
719 
720   frame = gtk_frame_new(_("Input Method"));
721 
722   vbox = gtk_vbox_new(FALSE, 5);
723   gtk_widget_show(vbox);
724 
725   hbox = gtk_hbox_new(FALSE, 5);
726   radio = gtk_radio_button_new_with_label(NULL, xim ? "XIM" : "Default");
727   g_signal_connect(radio, "toggled", G_CALLBACK(button_xim_checked), xim);
728   gtk_widget_show(GTK_WIDGET(radio));
729   gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0);
730   if (im_type == IM_XIM) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
731 
732   for (i = 0; i < num_info; i++) {
733     group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio));
734     radio = gtk_radio_button_new_with_label(group, im_info_table[i]->name);
735     g_signal_connect(radio, "toggled", G_CALLBACK(button_im_checked), im_info_table[i]);
736     gtk_widget_show(GTK_WIDGET(radio));
737     gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0);
738     if (index == i)
739       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
740   }
741 
742   if (strcmp(mc_get_gui(), "xlib") == 0) {
743     group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio));
744     radio = gtk_radio_button_new_with_label(group, _("None"));
745     g_signal_connect(radio, "toggled", G_CALLBACK(button_im_checked), NULL);
746     gtk_widget_show(GTK_WIDGET(radio));
747     gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0);
748     if (im_type == IM_NONE) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
749   }
750 
751   gtk_widget_show(GTK_WIDGET(hbox));
752   gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
753 
754   switch (im_type) {
755     case IM_XIM:
756       if (xim) gtk_widget_show(xim);
757       for (i = 0; i < num_info; i++)
758         if (im_opt_widget[i]) gtk_widget_hide(im_opt_widget[i]);
759       break;
760     case IM_NONE:
761       if (xim) gtk_widget_hide(xim);
762       for (i = 0; i < num_info; i++)
763         if (im_opt_widget[i]) gtk_widget_hide(im_opt_widget[i]);
764       break;
765     default: /* OTHER */
766       if (xim) gtk_widget_hide(xim);
767       for (i = 0; i < num_info; i++) {
768         if (!im_opt_widget[i]) continue;
769 
770         if (i == index)
771           gtk_widget_show(im_opt_widget[i]);
772         else
773           gtk_widget_hide(im_opt_widget[i]);
774       }
775       break;
776   }
777 
778   if (xim) gtk_box_pack_start(GTK_BOX(vbox), xim, TRUE, TRUE, 0);
779   for (i = 0; i < num_info; i++)
780     if (im_opt_widget[i]) gtk_box_pack_start(GTK_BOX(vbox), im_opt_widget[i], TRUE, TRUE, 0);
781 
782   gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
783   gtk_container_add(GTK_CONTAINER(frame), vbox);
784 
785   is_changed = 0;
786 
787   return frame;
788 }
789 
mc_update_im(void)790 void mc_update_im(void) {
791   char *p;
792   size_t len;
793 
794   if (!is_changed) return;
795 
796   if (strcmp(selected_im->id, "skk") == 0) {
797     p = skk_current_value();
798     goto end;
799   } else if (strcmp(selected_im->id, "wnn") == 0) {
800     p = wnn_current_value();
801     goto end;
802   }
803 
804   if (im_type == cur_im_type && selected_im_arg == -1) {
805     is_changed = 0;
806     return;
807   }
808 
809   if (selected_im_arg == -1) {
810     is_changed = 0;
811     selected_im_arg = 0;
812   }
813 
814   switch (im_type) {
815     case IM_XIM:
816       if (strcmp(selected_xim_name, xim_auto_str) == 0) {
817         p = strdup("xim");
818       } else if (strcmp(selected_xim_locale, current_locale_str) == 0) {
819         len = 3 + 1 + strlen(selected_xim_name) + 1;
820         if (!(p = malloc(sizeof(char) * len))) return;
821         sprintf(p, "xim:%s", selected_xim_name);
822       } else {
823         len = 3 + 1 + strlen(selected_xim_name) + 1 + strlen(selected_xim_locale) + 1;
824         if (!(p = malloc(sizeof(char) * len))) return;
825         sprintf(p, "xim:%s:%s", selected_xim_name, selected_xim_locale);
826       }
827       break;
828     case IM_NONE:
829       p = strdup("none");
830       break;
831     /* case IM_OTHER: */
832     default:
833       if (selected_im == NULL) return;
834       if (selected_im_arg == 0) { /* auto */
835         p = strdup(selected_im->id);
836       } else {
837         len = strlen(selected_im->id) + strlen(selected_im->args[selected_im_arg]) + 2;
838         if (!(p = malloc(len))) return;
839         sprintf(p, "%s:%s", selected_im->id, selected_im->args[selected_im_arg]);
840       }
841       break;
842   }
843 
844 end:
845   mc_set_str_value("input_method", p);
846 
847   selected_im_arg = -1;
848   cur_im_type = im_type;
849   is_changed = 0;
850 
851   free(p);
852 }
853