1 #include "gcin.h"
2 #include "config.h"
3 #include "gcin-version.h"
4 #include "gtab.h"
5 #if UNIX
6 #include <signal.h>
7 #include <pwd.h>
8 #endif
9 #if GCIN_i18n_message
10 #include <libintl.h>
11 #endif
12 
13 #if UNIX
14 Window root;
15 #endif
16 Display *dpy;
17 
18 int win_xl, win_yl;
19 int win_x, win_y;   // actual win x/y
20 int dpy_xl, dpy_yl;
21 #if WIN32
22 int dpy_x_ofs, dpy_y_ofs;
23 #endif
24 DUAL_XIM_ENTRY xim_arr[1];
25 
26 extern char *fullchar[];
27 gboolean win_kbm_inited;
28 
half_char_to_full_char(KeySym xkey)29 char *half_char_to_full_char(KeySym xkey)
30 {
31   if (xkey < ' ' || xkey > 127)
32     return NULL;
33   return fullchar[xkey-' '];
34 }
35 
36 
37 #if UNIX
start_inmd_window()38 static void start_inmd_window()
39 {
40   GtkWidget *win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
41   gtk_widget_realize (win);
42   GdkWindow *gdkwin0 = gtk_widget_get_window(win);
43   xim_arr[0].xim_xwin = GDK_WINDOW_XWINDOW(gdkwin0);
44   dbg("xim_xwin %x\n", xim_arr[0].xim_xwin);
45 }
46 #endif
47 
48 
49 #if USE_XIM
50 char *lc;
51 
52 static XIMStyle Styles[] = {
53 #if 1
54         XIMPreeditCallbacks|XIMStatusCallbacks,         //OnTheSpot
55         XIMPreeditCallbacks|XIMStatusArea,              //OnTheSpot
56         XIMPreeditCallbacks|XIMStatusNothing,           //OnTheSpot
57 #endif
58         XIMPreeditPosition|XIMStatusArea,               //OverTheSpot
59         XIMPreeditPosition|XIMStatusNothing,            //OverTheSpot
60         XIMPreeditPosition|XIMStatusNone,               //OverTheSpot
61 #if 1
62         XIMPreeditArea|XIMStatusArea,                   //OffTheSpot
63         XIMPreeditArea|XIMStatusNothing,                //OffTheSpot
64         XIMPreeditArea|XIMStatusNone,                   //OffTheSpot
65 #endif
66         XIMPreeditNothing|XIMStatusNothing,             //Root
67         XIMPreeditNothing|XIMStatusNone,                //Root
68 };
69 static XIMStyles im_styles;
70 
71 #if 1
72 static XIMTriggerKey trigger_keys[] = {
73         {XK_space, ControlMask, ControlMask},
74         {XK_space, ShiftMask, ShiftMask},
75         {XK_space, Mod1Mask, Mod1Mask},   // Alt
76         {XK_space, Mod4Mask, Mod4Mask},   // Windows
77 };
78 #endif
79 
80 /* Supported Encodings */
81 static XIMEncoding chEncodings[] = {
82         "COMPOUND_TEXT",
83         0
84 };
85 static XIMEncodings encodings;
86 
87 int xim_ForwardEventHandler(IMForwardEventStruct *call_data);
88 
89 XIMS current_ims;
90 extern void toggle_im_enabled();
91 
92 
MyTriggerNotifyHandler(IMTriggerNotifyStruct * call_data)93 int MyTriggerNotifyHandler(IMTriggerNotifyStruct *call_data)
94 {
95 //    dbg("MyTriggerNotifyHandler %d %x\n", call_data->key_index, call_data->event_mask);
96 
97     if (call_data->flag == 0) { /* on key */
98 //        db(g("trigger %d\n", call_data->key_index);
99         if ((call_data->key_index == 0 && gcin_im_toggle_keys==Control_Space) ||
100             (call_data->key_index == 3 && gcin_im_toggle_keys==Shift_Space) ||
101             (call_data->key_index == 6 && gcin_im_toggle_keys==Alt_Space) ||
102             (call_data->key_index == 9 && gcin_im_toggle_keys==Windows_Space)
103             ) {
104             toggle_im_enabled();
105         }
106         return True;
107     } else {
108         /* never happens */
109         return False;
110     }
111 }
112 
113 #if 0
114 void switch_IC_index(int index);
115 #endif
116 void CreateIC(IMChangeICStruct *call_data);
117 void DeleteIC(CARD16 icid);
118 void SetIC(IMChangeICStruct * call_data);
119 void GetIC(IMChangeICStruct *call_data);
120 int xim_gcin_FocusIn(IMChangeFocusStruct *call_data);
121 int xim_gcin_FocusOut(IMChangeFocusStruct *call_data);
122 
gcin_ProtoHandler(XIMS ims,IMProtocol * call_data)123 int gcin_ProtoHandler(XIMS ims, IMProtocol *call_data)
124 {
125 //  dbg("gcin_ProtoHandler %x ims\n", ims);
126 
127   current_ims = ims;
128 
129   switch (call_data->major_code) {
130   case XIM_OPEN:
131 #define MAX_CONNECT 20000
132     {
133       IMOpenStruct *pimopen=(IMOpenStruct *)call_data;
134 
135       if(pimopen->connect_id > MAX_CONNECT - 1)
136         return True;
137 
138 #if DEBUG && 0
139     dbg("open lang %s  connectid:%d\n", pimopen->lang.name, pimopen->connect_id);
140 #endif
141       return True;
142     }
143   case XIM_CLOSE:
144 #if DEBUG && 0
145     dbg("XIM_CLOSE\n");
146 #endif
147     return True;
148   case XIM_CREATE_IC:
149 #if DEBUG && 0
150      dbg("CREATE_IC\n");
151 #endif
152      CreateIC((IMChangeICStruct *)call_data);
153      return True;
154   case XIM_DESTROY_IC:
155      {
156        IMChangeICStruct *pimcha=(IMChangeICStruct *)call_data;
157 #if DEBUG && 0
158        dbg("DESTROY_IC %d\n", pimcha->icid);
159 #endif
160        DeleteIC(pimcha->icid);
161      }
162      return True;
163   case XIM_SET_IC_VALUES:
164 #if DEBUG && 0
165      dbg("SET_IC\n");
166 #endif
167      SetIC((IMChangeICStruct *)call_data);
168      return True;
169   case XIM_GET_IC_VALUES:
170 #if DEBUG && 0
171      dbg("GET_IC\n");
172 #endif
173      GetIC((IMChangeICStruct *)call_data);
174      return True;
175   case XIM_FORWARD_EVENT:
176 #if DEBUG && 0
177      dbg("XIM_FORWARD_EVENT\n");
178 #endif
179      return xim_ForwardEventHandler((IMForwardEventStruct *)call_data);
180   case XIM_SET_IC_FOCUS:
181 #if DEBUG && 0
182      dbg("XIM_SET_IC_FOCUS\n");
183 #endif
184      return xim_gcin_FocusIn((IMChangeFocusStruct *)call_data);
185   case XIM_UNSET_IC_FOCUS:
186 #if DEBUG && 0
187      dbg("XIM_UNSET_IC_FOCUS\n");
188 #endif
189      return xim_gcin_FocusOut((IMChangeFocusStruct *)call_data);
190   case XIM_RESET_IC:
191 #if DEBUG && 0
192      dbg("XIM_UNSET_IC_FOCUS\n");
193 #endif
194      return True;
195   case XIM_TRIGGER_NOTIFY:
196 #if DEBUG && 0
197      dbg("XIM_TRIGGER_NOTIFY\n");
198 #endif
199      MyTriggerNotifyHandler((IMTriggerNotifyStruct *)call_data);
200      return True;
201   case XIM_PREEDIT_START_REPLY:
202 #if DEBUG && 1
203      dbg("XIM_PREEDIT_START_REPLY\n");
204 #endif
205      return True;
206   case XIM_PREEDIT_CARET_REPLY:
207 #if DEBUG && 1
208      dbg("XIM_PREEDIT_CARET_REPLY\n");
209 #endif
210      return True;
211   case XIM_STR_CONVERSION_REPLY:
212 #if DEBUG && 1
213      dbg("XIM_STR_CONVERSION_REPLY\n");
214 #endif
215      return True;
216   default:
217      printf("Unknown major code.\n");
218      break;
219   }
220 
221   return True;
222 }
223 
224 
open_xim()225 void open_xim()
226 {
227   XIMTriggerKeys triggerKeys;
228 
229   im_styles.supported_styles = Styles;
230   im_styles.count_styles = sizeof(Styles)/sizeof(Styles[0]);
231 
232   triggerKeys.count_keys = sizeof(trigger_keys)/sizeof(trigger_keys[0]);
233   triggerKeys.keylist = trigger_keys;
234 
235   encodings.count_encodings = sizeof(chEncodings)/sizeof(XIMEncoding) - 1;
236   encodings.supported_encodings = chEncodings;
237 
238   if ((xim_arr[0].xims = IMOpenIM(dpy,
239           IMServerWindow,         xim_arr[0].xim_xwin,        //input window
240           IMModifiers,            "Xi18n",        //X11R6 protocol
241           IMServerName,           xim_arr[0].xim_server_name, //XIM server name
242           IMLocale,               lc,
243           IMServerTransport,      "X/",      //Comm. protocol
244           IMInputStyles,          &im_styles,   //faked styles
245           IMEncodingList,         &encodings,
246           IMProtocolHandler,      gcin_ProtoHandler,
247           IMFilterEventMask,      KeyPressMask|KeyReleaseMask,
248           IMOnKeysList, &triggerKeys,
249           NULL)) == NULL) {
250           p_err_no_alert("IMOpenIM '%s' failed. Maybe another XIM server is running.\n",
251           xim_arr[0].xim_server_name);
252   }
253 }
254 
255 #endif // if USE_XIM
256 
257 void load_tsin_db();
258 void load_tsin_conf(), load_setttings(), load_tab_pho_file();
259 
260 void disp_hide_tsin_status_row(), gcb_main(), update_win_kbm_inited();
261 void change_tsin_line_color(), change_win0_style(), change_tsin_color();
262 void change_win_gtab_style();
263 void update_item_active_all();
264 void destroy_inmd_menu();
265 void load_gtab_list(gboolean);
266 void change_win1_font();
267 void set_wselkey();
268 void toggle_im_enabled();
269 
reload_data()270 static void reload_data()
271 {
272   dbg("reload_data\n");
273   load_setttings();
274   if (current_method_type()==method_type_TSIN)
275     set_wselkey();
276 
277 //  load_tsin_db();
278   change_win0_style();
279   change_win1_font();
280   change_win_gtab_style();
281 //  change_win_pho_style();
282   load_tab_pho_file();
283   change_tsin_color();
284   update_win_kbm_inited();
285 
286   destroy_inmd_menu();
287   load_gtab_list(TRUE);
288   // after inmd is reloaded, toogle twice to reload *.gtab if necessary
289   toggle_im_enabled();
290   toggle_im_enabled();
291 
292   update_item_active_all();
293 #if USE_GCB
294   gcb_main();
295 #endif
296 }
297 
298 void change_tsin_font_size();
299 void change_gtab_font_size();
300 void change_pho_font_size();
301 void change_win_sym_font_size();
302 void change_win_gtab_style();
303 extern int win_kbm_on;
304 
change_font_size()305 static void change_font_size()
306 {
307   load_setttings();
308   change_tsin_font_size();
309   change_gtab_font_size();
310   change_pho_font_size();
311   change_win_sym_font_size();
312   change_win0_style();
313   change_win_gtab_style();
314   update_win_kbm_inited();
315   change_win1_font();
316 //  change_win_pho_style();
317 }
318 
319 #if UNIX
xerror_handler(Display * d,XErrorEvent * eve)320 static int xerror_handler(Display *d, XErrorEvent *eve)
321 {
322   return 0;
323 }
324 #endif
325 
326 #if UNIX
327 Atom gcin_atom;
328 #endif
329 void disp_tray_icon(), toggle_gb_output();
330 
cb_trad_sim_toggle()331 void cb_trad_sim_toggle()
332 {
333   toggle_gb_output();
334   disp_tray_icon();
335 }
336 
337 void execute_message(char *message), show_win_kbm(), hide_win_kbm();
338 int b_show_win_kbm=0;
339 void disp_win_kbm_capslock_init();
340 
kbm_open_close(gboolean b_show)341 void kbm_open_close(gboolean b_show)
342 {
343   b_show_win_kbm=b_show;
344   if (b_show) {
345     show_win_kbm();
346     disp_win_kbm_capslock_init();
347   } else
348     hide_win_kbm();
349 }
350 
kbm_toggle()351 void kbm_toggle()
352 {
353   win_kbm_inited = 1;
354   kbm_open_close(!b_show_win_kbm);
355 }
356 
357 
358 void reload_tsin_db();
359 void reload_en_db();
360 void do_exit();
361 
message_cb(char * message)362 void message_cb(char *message)
363 {
364 //   dbg("message '%s'\n", message);
365 
366    if (!strcmp(message, CHANGE_FONT_SIZE)) {
367      change_font_size();
368    } else
369    if (!strcmp(message, GB_OUTPUT_TOGGLE)) {
370      cb_trad_sim_toggle();
371      update_item_active_all();
372    } else
373    if (!strcmp(message, KBM_TOGGLE)) {
374      kbm_toggle();
375    } else
376 #if UNIX
377    if (strstr(message, "#gcin_message")) {
378      execute_message(message);
379    } else
380 #endif
381    if (!strcmp(message, RELOAD_TSIN_DB)) {
382      reload_tsin_db();
383      reload_en_db();
384    } else
385    if (!strcmp(message, GCIN_EXIT_MESSAGE)) {
386      do_exit();
387    } else
388      reload_data();
389 }
390 
391 #if UNIX
my_gdk_filter(GdkXEvent * xevent,GdkEvent * event,gpointer data)392 static GdkFilterReturn my_gdk_filter(GdkXEvent *xevent,
393                                      GdkEvent *event,
394                                      gpointer data)
395 {
396    XEvent *xeve = (XEvent *)xevent;
397 #if 0
398    dbg("a zzz %d\n", xeve->type);
399 #endif
400 
401    // only very old WM will enter this
402    if (xeve->type == FocusIn || xeve->type == FocusOut) {
403 #if 0
404      dbg("focus %s\n", xeve->type == FocusIn ? "in":"out");
405 #endif
406      return GDK_FILTER_REMOVE;
407    }
408 
409 #if USE_XIM
410    if (XFilterEvent(xeve, None) == True)
411      return GDK_FILTER_REMOVE;
412 #endif
413 
414    return GDK_FILTER_CONTINUE;
415 }
416 
init_atom_property()417 void init_atom_property()
418 {
419   gcin_atom = get_gcin_atom(dpy);
420   XSetSelectionOwner(dpy, gcin_atom, xim_arr[0].xim_xwin, CurrentTime);
421 }
422 #endif
423 
424 
425 void hide_win0();
426 void destroy_win0();
427 void destroy_win1();
428 void destroy_win_gtab();
429 void free_pho_mem(),free_tsin(), free_en(), free_all_IC(), free_gtab(), free_phrase(), destroy_tray_win32(), free_gcb();
430 void close_pho_fw();
431 void close_gtab_use_count();
432 
do_exit()433 void do_exit()
434 {
435   dbg("----------------- do_ exit ----------------\n");
436   close_pho_fw();
437   free_pho_mem();
438   free_tsin();
439   free_en();
440   close_gtab_use_count();
441 #if USE_XIM
442   free_all_IC();
443 #endif
444   free_gtab();
445   free_phrase();
446 #if UNIX
447   free_gcb();
448 #endif
449 #if 1
450   destroy_win0();
451   destroy_win1();
452   destroy_win_gtab();
453 #endif
454 
455 #if 1
456   destroy_tray_win32();
457 #endif
458   gtk_main_quit();
459 }
460 
sig_do_exit(int sig)461 void sig_do_exit(int sig)
462 {
463   do_exit();
464 }
465 
466 char *get_gcin_xim_name();
467 void load_phrase(), init_TableDir();
468 void init_tray(), exec_setup_scripts();
469 #if UNIX
470 void init_gcin_im_serv(Window win);
471 #else
472 void init_gcin_im_serv();
473 #endif
474 void gcb_main(), init_tray_win32();
475 
476 #if WIN32
477 void init_gcin_program_files();
478  #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
479 #endif
480 int win32_tray_disabled = 1;
481 
482 
delayed_start_cb(gpointer data)483 gboolean delayed_start_cb(gpointer data)
484 {
485 #if WIN32
486   Sleep(200);
487 #endif
488 
489   win32_tray_disabled = 0;
490 
491 #if TRAY_ENABLED
492   if (gcin_status_tray) {
493 #if UNIX
494     if (gcin_win32_icon==GCIN_TRAY_WIN32)
495       init_tray_win32();
496     else
497     if (gcin_win32_icon==GCIN_TRAY_UNIX)
498       init_tray();
499 #if USE_INDICATOR
500     else
501       init_tray_indicator();
502 #endif
503 #endif
504   }
505 #endif
506 
507   dbg("after init_tray\n");
508 
509 #if USE_GCB
510   if (gcb_position)
511     gcb_main();
512 
513   dbg("after gcb_main\n");
514 #endif
515 
516   return FALSE;
517 }
518 
get_dpy_xyl()519 void get_dpy_xyl()
520 {
521 	dpy_xl = gdk_screen_width(), dpy_yl = gdk_screen_height();
522 #if WIN32
523 	dpy_x_ofs = GetSystemMetrics(SM_XVIRTUALSCREEN);
524 	dpy_y_ofs = GetSystemMetrics(SM_YVIRTUALSCREEN);
525 #endif
526 }
527 
screen_size_changed(GdkScreen * screen,gpointer user_data)528 void screen_size_changed(GdkScreen *screen, gpointer user_data)
529 {
530 	get_dpy_xyl();
531 }
532 
533 #include "lang.h"
534 
535 extern int destroy_window;
536 
main(int argc,char ** argv)537 int main(int argc, char **argv)
538 {
539 #if WIN32
540    putenv("PANGO_WIN32_NO_UNISCRIBE=1");
541 #else
542    // restarting gcin may invoke gcin at USB disk, cannot umount
543    struct passwd *pw = getpwuid(getuid());
544    char *homedir = pw->pw_dir;
545    chdir(homedir);
546 #endif
547 
548   char *destroy = getenv("GCIN_DESTROY_WINDOW");
549   if (destroy)
550     destroy_window = atoi(destroy);
551 //  printf("GCIN_DESTROY_WINDOW=%d\n",destroy_window);
552 
553   gtk_init (&argc, &argv);
554 
555 #if GTK_CHECK_VERSION(2,91,6)
556 #if 1
557   static char css[]=
558 "button {\n"
559 "border-width: 0 0 0 0;\n"
560 "margin: 0 0 0 0;\n"
561 "padding: 0 0 0 0;\n"
562 "border-radius: 0;\n"
563 "}";
564   GtkCssProvider *provider = gtk_css_provider_new();
565   gtk_css_provider_load_from_data(provider, css, -1, NULL);
566   gtk_style_context_add_provider_for_screen(gdk_display_get_default_screen(gdk_display_get_default()), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
567   g_object_unref(provider);
568 #endif
569 #else
570 static char button_rc[]="style \"button\"\n"
571 "{\n"
572 "   GtkButton::inner-border = {0,0,0,0}\n"
573 "\n"
574 "xthickness = 1\n"
575 "ythickness = 0\n"
576 "}\n"
577 "class \"GtkButton\" style \"button\"";
578   gtk_rc_parse_string(button_rc);
579 #endif
580 
581 #if UNIX
582   signal(SIGCHLD, SIG_IGN);
583   signal(SIGPIPE, SIG_IGN);
584   if (getenv("GCIN_DAEMON")) {
585     daemon(1,1);
586 #if FREEBSD
587     setpgid(0, getpid());
588 #else
589     setpgrp();
590 #endif
591   }
592 #endif
593 
594 //putenv("GDK_NATIVE_WINDOWS=1");
595 #if WIN32
596   typedef BOOL (WINAPI* pImmDisableIME)(DWORD);
597   pImmDisableIME pd;
598   HMODULE imm32=LoadLibraryA("imm32");
599   if (imm32 && (pd=(pImmDisableIME)GetProcAddress(imm32, "ImmDisableIME"))) {
600      (*pd)(0);
601   }
602   init_gcin_program_files();
603   init_gcin_im_serv();
604 #endif
605 
606   set_is_chs();
607 
608 #if UNIX
609   char *lc_ctype = getenv("LC_CTYPE");
610   char *lc_all = getenv("LC_ALL");
611   char *lang = getenv("LANG");
612   if (!lc_ctype && lang)
613     lc_ctype = lang;
614 
615   if (lc_all)
616     lc_ctype = lc_all;
617 
618   if (!lc_ctype)
619     lc_ctype = "zh_TW.Big5";
620   dbg("gcin get env LC_CTYPE=%s  LC_ALL=%s  LANG=%s\n", lc_ctype, lc_all, lang);
621 #endif
622 
623 #if USE_XIM
624   char *t = strchr(lc_ctype, '.');
625   if (t) {
626     int len = t - lc_ctype;
627 #if MAC_OS || FREEBSD
628     lc = strdup(lc_ctype);
629     lc[len] = 0;
630 #else
631     lc = g_strndup(lc_ctype, len);
632 #endif
633   }
634   else
635     lc = lc_ctype;
636 
637   char *xim_server_name = get_gcin_xim_name();
638 
639   strcpy(xim_arr[0].xim_server_name, xim_server_name);
640 
641   dbg("gcin XIM will use %s as the default encoding\n", lc_ctype);
642 #endif
643 
644   if (argc == 2 && (!strcmp(argv[1], "-v") || !strcmp(argv[1], "--version") || !strcmp(argv[1], "-h")) ) {
645     p_err(" version %s\n", GCIN_VERSION);
646   }
647 
648   init_TableDir();
649   load_setttings();
650   load_gtab_list(TRUE);
651 
652 
653 #if GCIN_i18n_message
654   bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
655   textdomain(GETTEXT_PACKAGE);
656 #endif
657 
658   dbg("after gtk_init\n");
659 
660 #if UNIX
661   dpy = GDK_DISPLAY();
662   root=DefaultRootWindow(dpy);
663 #endif
664   get_dpy_xyl();
665   g_signal_connect(gdk_screen_get_default(),"size-changed", G_CALLBACK(screen_size_changed), NULL);
666 
667   dbg("display width:%d height:%d\n", dpy_xl, dpy_yl);
668 
669 #if UNIX
670   start_inmd_window();
671 #endif
672 
673 #if USE_XIM
674   open_xim();
675 #endif
676 
677 #if UNIX
678   gdk_window_add_filter(NULL, my_gdk_filter, NULL);
679 
680   init_atom_property();
681   signal(SIGINT, sig_do_exit);
682   signal(SIGHUP, sig_do_exit);
683   // disable the io handler abort
684   // void *olderr =
685     XSetErrorHandler((XErrorHandler)xerror_handler);
686 #endif
687 
688 #if UNIX
689   init_gcin_im_serv(xim_arr[0].xim_xwin);
690 #endif
691 
692   exec_setup_scripts();
693 
694 #if UNIX
695   g_timeout_add(5000, delayed_start_cb, NULL);
696 #else
697   delayed_start_cb(NULL);
698 #endif
699 
700   dbg("before gtk_main\n");
701 
702   disp_win_kbm_capslock_init();
703 
704   gtk_main();
705 
706   return 0;
707 }
708