1 /* Copyright (C) 2011 Edward Der-Hua Liu, Hsin-Chu, Taiwan
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation version 2.1
6 * of the License.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18 #include <sys/stat.h>
19
20 #include "hime.h"
21
22 #include "gtab-buf.h"
23 #include "gtab.h"
24 #include "pho.h"
25 #include "win-sym.h"
26
27 static GtkWidget *gwin_sym = NULL;
28 static int cur_in_method;
29 gboolean win_sym_enabled = 0;
30
31 typedef struct {
32 char **sym;
33 int symN;
34 } SYM_ROW;
35
36 static SYM_ROW *syms;
37 static int symsN;
38
39 typedef struct {
40 SYM_ROW *syms;
41 int symsN;
42 } PAGE;
43
44 static PAGE *pages;
45 static int pagesN;
46 static int idx;
47
48 extern char *TableDir;
49
watch_fopen(char * filename,time_t * pfile_modify_time)50 FILE *watch_fopen (char *filename, time_t *pfile_modify_time) {
51 FILE *fp;
52 char fname[256];
53
54 get_hime_user_or_sys_fname (filename, fname);
55
56 if ((fp = fopen (fname, "rb")) == NULL) {
57 strcat (strcat (strcpy (fname, TableDir), "/"), filename);
58
59 if ((fp = fopen (fname, "rb")) == NULL)
60 return NULL;
61 }
62
63 struct stat st;
64 fstat (fileno (fp), &st);
65
66 if (st.st_mtime == *pfile_modify_time) {
67 fclose (fp);
68 return NULL;
69 }
70
71 *pfile_modify_time = st.st_mtime;
72 return fp;
73 }
74
save_page()75 static void save_page () {
76 if (!symsN)
77 return;
78
79 pages = trealloc (pages, PAGE, pagesN + 1);
80 pages[pagesN].syms = syms;
81 pages[pagesN].symsN = symsN;
82 pagesN++;
83 syms = NULL;
84 symsN = 0;
85 }
86
read_syms()87 static gboolean read_syms () {
88 FILE *fp;
89 static char symbol_table[] = "symbol-table";
90 static time_t file_modify_time;
91
92 if ((fp = watch_fopen (symbol_table, &file_modify_time)) == NULL)
93 return FALSE;
94
95 skip_utf8_sigature (fp);
96
97 int pg;
98 for (pg = 0; pg < pagesN; pg++) {
99 syms = pages[pg].syms;
100 symsN = pages[pg].symsN;
101
102 int i;
103 for (i = 0; i < symsN; i++) {
104 int j;
105 for (j = 0; j < syms[i].symN; j++)
106 if (syms[i].sym[j])
107 free (syms[i].sym[j]);
108 }
109 free (syms);
110 }
111 pagesN = 0;
112 pages = NULL;
113 syms = NULL;
114 symsN = 0;
115
116 while (!feof (fp)) {
117 char tt[1024];
118
119 memset (tt, 0, sizeof (tt));
120 myfgets (tt, sizeof (tt), fp);
121 // dbg("%d] %s\n",strlen(tt), tt);
122
123 #if 0
124 int len=strlen(tt);
125 if (!len)
126 continue;
127
128 if (tt[len-1]=='\n') {
129 tt[len-1]=0;
130 }
131 #endif
132
133 if (tt[0] == 0)
134 save_page ();
135
136 if (tt[0] == '#')
137 continue;
138
139 char *p = tt;
140
141 syms = trealloc (syms, SYM_ROW, symsN + 1);
142 SYM_ROW *psym = &syms[symsN++];
143 memset (psym, 0, sizeof (SYM_ROW));
144
145 while (*p) {
146 char *n = p;
147
148 while (*n && *n != '\t')
149 n++;
150
151 *n = 0;
152
153 psym->sym = trealloc (psym->sym, char *, psym->symN + 1);
154 psym->sym[psym->symN++] = strdup (p);
155
156 p = n + 1;
157 }
158
159 if (!psym->symN) {
160 free (syms);
161 syms = NULL;
162 symsN = 0;
163 }
164 }
165
166 if (symsN)
167 save_page ();
168
169 fclose (fp);
170
171 idx = 0;
172 syms = pages[idx].syms;
173 symsN = pages[idx].symsN;
174
175 return TRUE;
176 }
177
178 gboolean add_to_tsin_buf (char *str, phokey_t *pho, int len);
179 void send_text_call_back (char *text);
180 void tsin_reset_in_pho (), reset_gtab_all (), clr_in_area_pho ();
181 void force_preedit_shift ();
182 gboolean output_gbuf ();
183 void output_buffer_call_back ();
184 gboolean gtab_cursor_end (), gtab_phrase_on ();
185 void flush_tsin_buffer ();
186 gboolean tsin_cursor_end ();
187 void add_to_tsin_buf_str (char *str);
188
189 extern int c_len;
190 extern short gbufN;
cb_button_sym(GtkButton * button,GtkWidget * label)191 static void cb_button_sym (GtkButton *button, GtkWidget *label) {
192 // dbg("cb_button_sym\n");
193 char *str = (char *) gtk_label_get_text (GTK_LABEL (label));
194
195 #if USE_TSIN
196 if (current_method_type () == method_type_TSIN && current_CS->im_state == HIME_STATE_CHINESE) {
197 add_to_tsin_buf_str (str);
198 if (hime_punc_auto_send && tsin_cursor_end ()) {
199 flush_tsin_buffer ();
200 output_buffer_call_back ();
201 } else {
202 force_preedit_shift ();
203 }
204 } else
205 #endif
206 if (gtab_phrase_on ()) {
207 insert_gbuf_nokey (str);
208 if (hime_punc_auto_send && gtab_cursor_end ()) {
209 output_gbuf ();
210 output_buffer_call_back ();
211 } else
212 force_preedit_shift ();
213 } else {
214 send_text_call_back (str);
215 }
216
217 switch (current_method_type ()) {
218 case method_type_PHO:
219 clr_in_area_pho ();
220 break;
221 #if USE_TSIN
222 case method_type_TSIN:
223 tsin_reset_in_pho ();
224 break;
225 #endif
226 case method_type_MODULE:
227 break;
228 default:
229 reset_gtab_all ();
230 break;
231 }
232
233 if (hime_win_sym_click_close) {
234 win_sym_enabled = 0;
235 hide_win_sym ();
236 }
237 }
238
239 void update_active_in_win_geom ();
240 extern int win_status_y;
241
move_win_sym()242 void move_win_sym () {
243 #if 0
244 dbg("move_win_sym %d\n", current_CS->in_method);
245 #endif
246 if (!gwin_sym)
247 return;
248
249 int wx, wy;
250 #if 0
251 if (hime_pop_up_win) {
252 wx = dpy_xl;
253 } else
254 #endif
255 {
256 // dbg("win_y: %d %d\n", win_y, win_yl);
257 update_active_in_win_geom ();
258
259 wx = win_x;
260 wy = win_y + win_yl;
261 }
262
263 int winsym_xl, winsym_yl;
264 get_win_size (gwin_sym, &winsym_xl, &winsym_yl);
265
266 if (wx + winsym_xl > dpy_xl)
267 wx = dpy_xl - winsym_xl;
268 if (wx < 0)
269 wx = 0;
270
271 #if 0
272 if (hime_pop_up_win) {
273 wy = win_status_y - winsym_yl;
274 } else
275 #endif
276 {
277 if (wy + winsym_yl > dpy_yl)
278 wy = win_y - winsym_yl;
279 if (wy < 0)
280 wy = 0;
281 }
282
283 gtk_window_move (GTK_WINDOW (gwin_sym), wx, wy);
284 }
285
hide_win_sym()286 void hide_win_sym () {
287 if (!gwin_sym)
288 return;
289 gtk_widget_hide (gwin_sym);
290 }
291
show_win_sym()292 void show_win_sym () {
293 if (!current_CS)
294 return;
295
296 if (!gwin_sym || !win_sym_enabled || current_CS->im_state == HIME_STATE_DISABLED)
297 return;
298 #if 0
299 dbg("show_win_sym\n");
300 #endif
301 gtk_widget_show_all (gwin_sym);
302 move_win_sym ();
303 }
304
305 void lookup_gtab_out (char *ch, char *out);
306 void str_to_all_phokey_chars (char *b5_str, char *out);
307
sym_lookup_key(char * instr,char * outstr)308 static void sym_lookup_key (char *instr, char *outstr) {
309 if (current_method_type () == method_type_PHO || current_method_type () == method_type_TSIN) {
310 str_to_all_phokey_chars (instr, outstr);
311 } else {
312 outstr[0] = 0;
313
314 while (*instr) {
315 char tt[512];
316 tt[0] = 0;
317 lookup_gtab_out (instr, tt);
318 strcat (outstr, tt);
319
320 instr += utf8_sz (instr);
321
322 if (*instr)
323 strcat (outstr, " | ");
324 }
325 }
326 }
327
destory_win()328 static void destory_win () {
329 if (gwin_sym)
330 gtk_widget_destroy (gwin_sym);
331 gwin_sym = NULL;
332 }
333
disp_win_sym()334 static void disp_win_sym () {
335 syms = pages[idx].syms;
336 symsN = pages[idx].symsN;
337 destory_win ();
338 // win_sym_enabled = 0;
339 create_win_sym ();
340 }
341
win_sym_page_up()342 gboolean win_sym_page_up () {
343 if (!win_sym_enabled)
344 return FALSE;
345 idx--;
346 if (idx < 0)
347 idx = pagesN - 1;
348 disp_win_sym ();
349 return TRUE;
350 }
351
win_sym_page_down()352 gboolean win_sym_page_down () {
353 // dbg("win_sym_page_down\n");
354 if (!win_sym_enabled)
355 return FALSE;
356 idx = (idx + 1) % pagesN;
357 disp_win_sym ();
358 return TRUE;
359 }
360
button_scroll_event(GtkWidget * widget,GdkEventScroll * event,gpointer user_data)361 static gboolean button_scroll_event (GtkWidget *widget, GdkEventScroll *event, gpointer user_data) {
362 if (pagesN < 2)
363 return TRUE;
364
365 switch (event->direction) {
366 case GDK_SCROLL_UP:
367 win_sym_page_up ();
368 break;
369 case GDK_SCROLL_DOWN:
370 win_sym_page_down ();
371 break;
372 default:
373 break;
374 }
375
376 return TRUE;
377 }
378
mouse_button_callback_up_down(GtkWidget * widget,GdkEventButton * event,gpointer data)379 static void mouse_button_callback_up_down (GtkWidget *widget, GdkEventButton *event, gpointer data) {
380 GdkEventScroll sc;
381 sc.direction = data ? GDK_SCROLL_UP : GDK_SCROLL_DOWN;
382 button_scroll_event (NULL, &sc, NULL);
383 }
384
create_win_sym()385 void create_win_sym () {
386 if (!current_CS) {
387 dbg ("create_win_sym, null CS\n");
388 return;
389 }
390
391 if (current_CS->in_method < 0) {
392 p_err ("bad current_CS %d\n", current_CS->in_method);
393 }
394
395 if (current_method_type () != method_type_PHO && current_method_type () != method_type_TSIN && current_method_type () != method_type_MODULE && !cur_inmd)
396 return;
397
398 if (read_syms () || cur_in_method != current_CS->in_method) {
399 destory_win ();
400 } else {
401 if (!syms)
402 return;
403 }
404
405 if (gwin_sym) {
406 if (win_sym_enabled)
407 show_win_sym ();
408 else
409 hide_win_sym ();
410
411 return;
412 }
413
414 gwin_sym = gtk_window_new (GTK_WINDOW_TOPLEVEL);
415 gtk_window_set_has_resize_grip (GTK_WINDOW (gwin_sym), FALSE);
416
417 cur_in_method = current_CS->in_method;
418
419 GtkWidget *hbox_top = gtk_hbox_new (FALSE, 0);
420 gtk_container_add (GTK_CONTAINER (gwin_sym), hbox_top);
421
422 GtkWidget *vbox_top = gtk_vbox_new (FALSE, 0);
423 gtk_orientable_set_orientation (GTK_ORIENTABLE (vbox_top), GTK_ORIENTATION_VERTICAL);
424 gtk_box_pack_start (GTK_BOX (hbox_top), vbox_top, TRUE, TRUE, 0);
425
426 gtk_container_set_border_width (GTK_CONTAINER (vbox_top), 0);
427
428 int i;
429 for (i = 0; i < symsN; i++) {
430 SYM_ROW *psym = &syms[i];
431 GtkWidget *hbox_row = gtk_hbox_new (FALSE, 0);
432 gtk_box_pack_start (GTK_BOX (vbox_top), hbox_row, FALSE, FALSE, 0);
433 gtk_container_set_border_width (GTK_CONTAINER (hbox_row), 0);
434
435 int j;
436 for (j = 0; j < psym->symN; j++) {
437 char *str = psym->sym[j];
438
439 if (!str[0])
440 continue;
441
442 GtkWidget *button = gtk_button_new ();
443 GtkWidget *label = gtk_label_new (str);
444
445 gtk_container_add (GTK_CONTAINER (button), label);
446 set_label_font_size (label, hime_font_size_symbol);
447
448 gtk_container_set_border_width (GTK_CONTAINER (button), 0);
449 gtk_box_pack_start (GTK_BOX (hbox_row), button, FALSE, FALSE, 0);
450
451 if (utf8_str_N (str) > 0) {
452 char phos[512];
453
454 sym_lookup_key (str, phos);
455
456 int phos_len = strlen (phos);
457
458 if (phos_len) {
459 #if GTK_CHECK_VERSION(2, 12, 0)
460 gtk_widget_set_tooltip_text (button, phos);
461 #else
462 GtkTooltips *button_pho_tips = gtk_tooltips_new ();
463 gtk_tooltips_set_tip (GTK_TOOLTIPS (button_pho_tips), button, phos, NULL);
464 #endif
465 }
466 }
467
468 g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (cb_button_sym), label);
469 }
470 }
471
472 gtk_box_pack_start (GTK_BOX (hbox_top), gtk_vseparator_new (), FALSE, FALSE, 0);
473
474 GtkWidget *vbox_arrow = gtk_vbox_new (TRUE, 0);
475 gtk_orientable_set_orientation (GTK_ORIENTABLE (vbox_arrow), GTK_ORIENTATION_VERTICAL);
476 gtk_box_pack_start (GTK_BOX (hbox_top), vbox_arrow, TRUE, TRUE, 0);
477 GtkWidget *eve_up = gtk_event_box_new (), *eve_down = gtk_event_box_new ();
478 gtk_event_box_set_visible_window (GTK_EVENT_BOX (eve_up), FALSE);
479 gtk_event_box_set_visible_window (GTK_EVENT_BOX (eve_down), FALSE);
480 gtk_box_pack_start (GTK_BOX (vbox_arrow), eve_up, TRUE, TRUE, 0);
481 gtk_container_add (GTK_CONTAINER (eve_up), gtk_arrow_new (GTK_ARROW_UP, GTK_SHADOW_IN));
482 gtk_box_pack_start (GTK_BOX (vbox_arrow), eve_down, TRUE, TRUE, 0);
483 gtk_container_add (GTK_CONTAINER (eve_down), gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_IN));
484
485 g_signal_connect (G_OBJECT (eve_up), "button-press-event", G_CALLBACK (mouse_button_callback_up_down), (gpointer) 1);
486 g_signal_connect (G_OBJECT (eve_down), "button-press-event", G_CALLBACK (mouse_button_callback_up_down), NULL);
487
488 gtk_widget_realize (gwin_sym);
489 set_no_focus (gwin_sym);
490
491 if (win_sym_enabled)
492 gtk_widget_show_all (gwin_sym);
493
494 g_signal_connect (G_OBJECT (gwin_sym), "scroll-event", G_CALLBACK (button_scroll_event), NULL);
495
496 move_win_sym ();
497 #if 0
498 dbg("in_method:%d\n", current_CS->in_method);
499 #endif
500 return;
501 }
502
toggle_win_sym()503 void toggle_win_sym () {
504 win_sym_enabled ^= 1;
505 create_win_sym ();
506 }
507
change_win_sym_font_size()508 void change_win_sym_font_size () {
509 }
510