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