1 /*
2  * Copyright (C) 2020 The HIME team, Taiwan
3  * Copyright (C) 2011-2012 cwlin <https://github.com/cwlin>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18  */
19 
20 #include "chewing.h"
21 
22 // hime-chewing funcs
23 static gboolean select_idx (int c);
24 static void prev_page (void);
25 static void next_page (void);
26 static gboolean chewing_initialize (void);
27 static gboolean is_empty (void);
28 static gboolean hime_label_show (char *pszPho, int nPos);
29 static gboolean hime_label_clear (int nCount);
30 static gboolean hime_label_cand_show (char *pszWord, int nCount);
31 static gboolean gtk_pango_font_pixel_size_get (int *pnFontWidth, int *pnFontHeight);
32 
33 static gboolean hime_key_filter (int *pnKeyVal);
34 static gboolean hime_zuin_label_show (void);
35 static gboolean hime_buffer_label_show (void);
36 static gboolean hime_buffer_commit (void);
37 
38 static void hime_chewing_cb_register (void);
39 static void hime_chewing_handler_default (ChewingContext *pCtx);
40 
41 static int hime_chewing_wrapper_bs (ChewingContext *pCtx);
42 static int hime_chewing_wrapper_enter (ChewingContext *pCtx);
43 static int hime_chewing_wrapper_home (ChewingContext *pCtx);
44 static int hime_chewing_wrapper_left (ChewingContext *pCtx);
45 static int hime_chewing_wrapper_up (ChewingContext *pCtx);
46 static int hime_chewing_wrapper_right (ChewingContext *pCtx);
47 static int hime_chewing_wrapper_down (ChewingContext *pCtx);
48 static int hime_chewing_wrapper_pageup (ChewingContext *pCtx);
49 static int hime_chewing_wrapper_pagedown (ChewingContext *pCtx);
50 static int hime_chewing_wrapper_end (ChewingContext *pCtx);
51 static int hime_chewing_wrapper_del (ChewingContext *pCtx);
52 
53 static HIME_module_main_functions g_himeModMainFuncs;
54 static GtkWidget *g_pWinChewing = NULL;
55 static ChewingContext *g_pChewingCtx = NULL;
56 static GtkWidget *g_pEvBoxChewing = NULL;
57 static GtkWidget *g_pHBoxChewing = NULL;
58 static SEG *g_pSeg = NULL;
59 static int g_nCurrentCursorPos = 0;
60 
61 static intptr_t (*g_pKeyHandler[HIME_CHEWING_KEY_MAX]) (ChewingContext *pCtx);
62 
63 // FIXME: impl
64 static gboolean
select_idx(int c)65 select_idx (int c) {
66     return TRUE;
67 }
68 
69 // FIXME: impl
70 static void
prev_page(void)71 prev_page (void) {
72 }
73 
74 // FIXME: impl
75 static void
next_page(void)76 next_page (void) {
77 }
78 
79 static gboolean
hime_label_show(char * pszPho,int nPos)80 hime_label_show (char *pszPho, int nPos) {
81     char szTmp[128];
82 
83     if (!pszPho)
84         return FALSE;
85 
86     memset (szTmp, 0x00, 128);
87 
88     if (*g_himeModMainFuncs.mf_hime_win_color_use)
89         snprintf (szTmp, sizeof (szTmp), "<span background=\"%s\" foreground=\"white\">%s</span>",
90                   *g_himeModMainFuncs.mf_tsin_cursor_color,
91                   pszPho);
92     else
93         snprintf (szTmp, sizeof (szTmp), "<span background=\"" TSIN_CURSOR_COLOR_DEFAULT "\">%s</span>",
94                   pszPho);
95 
96     gtk_label_set_markup (GTK_LABEL (g_pSeg[nPos].label),
97                           nPos != g_nCurrentCursorPos ? pszPho : szTmp);
98 
99     return TRUE;
100 }
101 
102 static gboolean
hime_label_clear(int nCount)103 hime_label_clear (int nCount) {
104     while (nCount--)
105         gtk_label_set_text (GTK_LABEL (g_pSeg[nCount].label), NULL);
106 
107     return TRUE;
108 }
109 
110 static gboolean
gtk_pango_font_pixel_size_get(int * pnFontWidth,int * pnFontHeight)111 gtk_pango_font_pixel_size_get (int *pnFontWidth, int *pnFontHeight) {
112     PangoLayout *pPangoLayout;
113     PangoContext *pPangoContext;
114     PangoFontDescription *pPangoFontDesc;
115 
116     pPangoLayout = gtk_widget_create_pango_layout (g_pWinChewing, "中");
117     //pPangoLayout = gtk_widget_create_pango_layout (
118     //                   g_pWinChewing,
119     //                   (char *)gtk_label_get_text (GTK_LABEL (g_pSeg[g_nCurrentCursorPos].label)));
120     pPangoContext = gtk_widget_get_pango_context (g_pWinChewing);
121     pPangoFontDesc = pango_context_get_font_description (pPangoContext);
122 
123     pango_layout_set_font_description (pPangoLayout, pPangoFontDesc);
124     pango_layout_get_pixel_size (pPangoLayout, pnFontWidth, pnFontHeight);
125 
126     g_object_unref (pPangoLayout);
127     return TRUE;
128 }
129 
130 // FIXME: the pos of g_pSeg[].label is not correct
131 static gboolean
hime_label_cand_show(char * pszWord,int nIdx)132 hime_label_cand_show (char *pszWord, int nIdx) {
133     int nX, nY;
134     int nFontWidth, nFontHeight;
135 
136     g_himeModMainFuncs.mf_set_sele_text (chewing_cand_TotalChoice (g_pChewingCtx),
137                                          nIdx,
138                                          pszWord,
139                                          -1);
140 
141     // find the position of the cand win
142     g_himeModMainFuncs.mf_get_widget_xy (g_pWinChewing,
143                                          g_pSeg[g_nCurrentCursorPos].label,
144                                          &nX, &nY);
145 
146     gtk_pango_font_pixel_size_get (&nFontWidth, &nFontHeight);
147     nX += g_nCurrentCursorPos * nFontWidth;
148 
149     nY = g_himeModMainFuncs.mf_hime_edit_display_ap_only () ? *g_himeModMainFuncs.mf_win_y : *g_himeModMainFuncs.mf_win_y + *g_himeModMainFuncs.mf_win_yl;
150 
151     g_himeModMainFuncs.mf_disp_selections (nX, nY);
152 
153     return TRUE;
154 }
155 
156 static gboolean
chewing_initialize(void)157 chewing_initialize (void) {
158     char *pszChewingHashDir;
159     char *pszHome;
160     gboolean bWriteMode = FALSE;
161     ChewingConfigData dummyConfig;
162 
163     pszHome = getenv ("HOME");
164     if (!pszHome)
165         pszHome = "";
166 
167     pszChewingHashDir = malloc (strlen (pszHome) + strlen ("/.chewing/") + 1);
168     memset (pszChewingHashDir, 0x00, strlen (pszHome) + strlen ("/.chewing/") + 1);
169     sprintf (pszChewingHashDir, "%s/.chewing", pszHome);
170 
171     free (pszChewingHashDir);
172     pszHome = NULL;
173 
174     g_pChewingCtx = chewing_new ();
175     if (!g_pChewingCtx)
176         return FALSE;
177 
178     memset (&dummyConfig, 0x00, sizeof (ChewingConfigData));
179 
180     chewing_config_open (bWriteMode);
181 
182     chewing_config_load (&dummyConfig);
183 
184     chewing_config_set (g_pChewingCtx);
185 
186     chewing_config_close ();
187 
188     hime_chewing_cb_register ();
189 
190     return TRUE;
191 }
192 
193 static gboolean
is_empty(void)194 is_empty (void) {
195     if (!g_pChewingCtx)
196         return FALSE;
197     return !chewing_buffer_Check (g_pChewingCtx) && !chewing_bopomofo_Check (g_pChewingCtx);
198 }
199 
200 static gboolean
hime_key_filter(int * pnKeyVal)201 hime_key_filter (int *pnKeyVal) {
202     if ((*pnKeyVal) > HIME_CHEWING_DEFAULT_KEY_MIN &&
203         (*pnKeyVal) < HIME_CHEWING_DEFAULT_KEY_MAX)
204         chewing_handle_Default (g_pChewingCtx, (*pnKeyVal));
205     else if ((*pnKeyVal) >= XK_KP_0 && (*pnKeyVal) <= XK_KP_9)
206         chewing_handle_Numlock (g_pChewingCtx, (*pnKeyVal) - XK_KP_0 + '0');
207     else if ((*pnKeyVal) < HIME_CHEWING_KEY_MAX &&
208              (*pnKeyVal) >= HIME_CHEWING_KEY_MIN)
209         if ((int) (g_pKeyHandler[(*pnKeyVal)](g_pChewingCtx)) == -1)
210             return FALSE;
211 
212     g_nCurrentCursorPos = chewing_cursor_Current (g_pChewingCtx);
213 
214     if (g_nCurrentCursorPos < 0 || g_nCurrentCursorPos > MAX_SEG_NUM)
215         return FALSE;
216 
217     return TRUE;
218 }
219 
220 static gboolean
hime_zuin_label_show(void)221 hime_zuin_label_show (void) {
222     const char *pszTmp = NULL;
223     char *pszWord = NULL;
224     int nZuinLen = 0, nIdx = 0, nPhoIdx = 0;
225 
226     pszTmp = chewing_bopomofo_String_static (g_pChewingCtx);
227     nZuinLen = strlen (pszTmp) / 3;
228     pszWord = (char *) realloc (pszWord, 4);
229 
230     if (!pszWord)
231         return FALSE;
232 
233     memset (pszWord, 0x00, 4);
234 
235     if (pszTmp) {
236         for (nIdx = 0; nIdx < nZuinLen; nIdx++) {
237             memcpy (pszWord, pszTmp + nIdx * 3, 3);
238             for (nPhoIdx = 0; nPhoIdx < 3; nPhoIdx++)
239                 if (strstr (g_himeModMainFuncs.mf_pho_chars[nPhoIdx], pszWord) != NULL)
240                     hime_label_show (pszWord, nPhoIdx + chewing_buffer_Len (g_pChewingCtx) + 1);
241         }
242     }
243 
244     free (pszWord);
245 
246     return TRUE;
247 }
248 
249 static gboolean
hime_buffer_label_show(void)250 hime_buffer_label_show (void) {
251     char *pszTmp = NULL;
252     char *pszWord = NULL;
253     char *pszChewingCand = NULL;
254     char *pHead = NULL;
255     int nIdx = 0;
256     int nPos = 0;
257     int nWordSize = 0;
258 
259     pszWord = (char *) realloc (pszWord, 8);
260 
261     if (!pszWord)
262         return FALSE;
263 
264     memset (pszWord, 0x00, 8);
265 
266     // check if the composing is valid or not
267     if (chewing_buffer_Check (g_pChewingCtx)) {
268         g_himeModMainFuncs.mf_hide_selections_win ();
269         pszTmp = chewing_buffer_String (g_pChewingCtx);
270 
271         // init cand_no
272         chewing_cand_Enumerate (g_pChewingCtx);
273 
274         g_himeModMainFuncs.mf_clear_sele ();
275 
276         if (chewing_cand_TotalChoice (g_pChewingCtx)) {
277             while (chewing_cand_hasNext (g_pChewingCtx)) {
278                 pszChewingCand = chewing_cand_String (g_pChewingCtx);
279 
280                 if (nIdx > chewing_get_candPerPage (g_pChewingCtx) - 1)
281                     break;
282                 hime_label_cand_show (pszChewingCand, nIdx++);
283                 free (pszChewingCand);
284             }
285         }
286 
287         for (nPos = 0, pHead = pszTmp, nIdx = 0; nPos < strlen (pszTmp); nPos += nWordSize, pHead += nWordSize) {
288             if (!((*pHead) & 0x80))  // 1 byte utf-8 data
289                 nWordSize = 1;
290             else if (((*pHead) & 0xf0) == 0xc0)  // 2 bytes utf-8 data
291                 nWordSize = 2;
292             else if (((*pHead) & 0xf0) == 0xe0)  // 3 bytes utf-8 data
293                 nWordSize = 3;
294             else if (((*pHead) & 0xf0) == 0xf0)  // 4 bytes utf-8 data
295                 nWordSize = 4;
296 
297             memset (pszWord, 0x00, 8);
298             memcpy (pszWord, pHead, nWordSize);
299             hime_label_show (pszWord, nIdx++);
300         }
301 
302         // if chewing_buffer_Check is not zero,
303         // it means that the chewing_buffer_String must have val,
304         // so we could free the ptr here
305         free (pszTmp);
306     }
307 
308     free (pszWord);
309 
310     return TRUE;
311 }
312 
313 static gboolean
hime_buffer_commit(void)314 hime_buffer_commit (void) {
315     char *pszTmp = NULL;
316 
317     if (chewing_commit_Check (g_pChewingCtx)) {
318         pszTmp = chewing_commit_String (g_pChewingCtx);
319         g_himeModMainFuncs.mf_send_text (pszTmp);
320 
321         // FIXME: workaround for repeated commit
322         chewing_handle_Esc (g_pChewingCtx);
323 
324         // if chewing_commit_Check is not zero,
325         // it means that the chewing_commit_String must have val,
326         // so we could free the ptr here
327         free (pszTmp);
328     }
329 
330     if (*g_himeModMainFuncs.mf_hime_pop_up_win && is_empty ())
331         module_hide_win ();
332 
333     return TRUE;
334 }
335 
336 static void
hime_chewing_handler_default(ChewingContext * pCtx)337 hime_chewing_handler_default (ChewingContext *pCtx) {
338     return ((void) NULL);
339 }
340 
341 static int
hime_chewing_wrapper_bs(ChewingContext * pCtx)342 hime_chewing_wrapper_bs (ChewingContext *pCtx) {
343     //  If zuin is present, force libchewing handles Backspace for removing last zuin
344     const char *pszWord = chewing_bopomofo_String_static (pCtx);
345     if (pszWord[0] != '\0')
346         return chewing_handle_Backspace (g_pChewingCtx);
347     HIME_CHEWING_WRAPPER_FUNC (chewing_handle_Backspace);
348 }
349 
350 static int
hime_chewing_wrapper_enter(ChewingContext * pCtx)351 hime_chewing_wrapper_enter (ChewingContext *pCtx) {
352     HIME_CHEWING_WRAPPER_FUNC (chewing_handle_Enter);
353 }
354 
355 static int
hime_chewing_wrapper_home(ChewingContext * pCtx)356 hime_chewing_wrapper_home (ChewingContext *pCtx) {
357     HIME_CHEWING_WRAPPER_FUNC (chewing_handle_Home);
358 }
359 
360 static int
hime_chewing_wrapper_left(ChewingContext * pCtx)361 hime_chewing_wrapper_left (ChewingContext *pCtx) {
362     HIME_CHEWING_WRAPPER_FUNC (chewing_handle_Left);
363 }
364 
365 static int
hime_chewing_wrapper_up(ChewingContext * pCtx)366 hime_chewing_wrapper_up (ChewingContext *pCtx) {
367     HIME_CHEWING_WRAPPER_FUNC (chewing_handle_Up);
368 }
369 
370 static int
hime_chewing_wrapper_right(ChewingContext * pCtx)371 hime_chewing_wrapper_right (ChewingContext *pCtx) {
372     HIME_CHEWING_WRAPPER_FUNC (chewing_handle_Right);
373 }
374 
375 static int
hime_chewing_wrapper_down(ChewingContext * pCtx)376 hime_chewing_wrapper_down (ChewingContext *pCtx) {
377     HIME_CHEWING_WRAPPER_FUNC (chewing_handle_Down);
378 }
379 
380 static int
hime_chewing_wrapper_pageup(ChewingContext * pCtx)381 hime_chewing_wrapper_pageup (ChewingContext *pCtx) {
382     HIME_CHEWING_WRAPPER_FUNC (chewing_handle_PageUp);
383 }
384 
hime_chewing_wrapper_pagedown(ChewingContext * pCtx)385 static int hime_chewing_wrapper_pagedown (ChewingContext *pCtx) {
386     HIME_CHEWING_WRAPPER_FUNC (chewing_handle_PageDown);
387 }
388 
389 static int
hime_chewing_wrapper_end(ChewingContext * pCtx)390 hime_chewing_wrapper_end (ChewingContext *pCtx) {
391     HIME_CHEWING_WRAPPER_FUNC (chewing_handle_End);
392 }
393 
394 static int
hime_chewing_wrapper_del(ChewingContext * pCtx)395 hime_chewing_wrapper_del (ChewingContext *pCtx) {
396     HIME_CHEWING_WRAPPER_FUNC (chewing_handle_Del);
397 }
398 
399 static void
hime_chewing_cb_register(void)400 hime_chewing_cb_register (void) {
401     int nIdx = HIME_CHEWING_KEY_MIN;
402 
403     for (; nIdx < HIME_CHEWING_KEY_MAX; nIdx++)
404         g_pKeyHandler[nIdx] = (void *) hime_chewing_handler_default;
405 
406     g_pKeyHandler[XK_space] = (void *) chewing_handle_Space;
407     g_pKeyHandler[XK_BackSpace] = (void *) hime_chewing_wrapper_bs;
408     g_pKeyHandler[XK_Tab] = (void *) chewing_handle_Tab;
409     g_pKeyHandler[XK_Return] = (void *) hime_chewing_wrapper_enter;
410     g_pKeyHandler[XK_Escape] = (void *) chewing_handle_Esc;
411     g_pKeyHandler[XK_Home] = (void *) hime_chewing_wrapper_home;
412     g_pKeyHandler[XK_Left] = (void *) hime_chewing_wrapper_left;
413     g_pKeyHandler[XK_Up] = (void *) hime_chewing_wrapper_up;
414     g_pKeyHandler[XK_Right] = (void *) hime_chewing_wrapper_right;
415     g_pKeyHandler[XK_Down] = (void *) hime_chewing_wrapper_down;
416     g_pKeyHandler[XK_Page_Up] = (void *) hime_chewing_wrapper_pageup;
417     g_pKeyHandler[XK_Page_Down] = (void *) hime_chewing_wrapper_pagedown;
418     g_pKeyHandler[XK_End] = (void *) hime_chewing_wrapper_end;
419     g_pKeyHandler[XK_KP_Enter] = (void *) hime_chewing_wrapper_enter;
420     g_pKeyHandler[XK_KP_Left] = (void *) hime_chewing_wrapper_left;
421     g_pKeyHandler[XK_KP_Up] = (void *) hime_chewing_wrapper_up;
422     g_pKeyHandler[XK_KP_Right] = (void *) hime_chewing_wrapper_right;
423     g_pKeyHandler[XK_KP_Down] = (void *) hime_chewing_wrapper_down;
424     g_pKeyHandler[XK_KP_Delete] = (void *) hime_chewing_wrapper_del;
425 #if 0
426     g_pKeyHandler[XK_Shift_L]   = (void *)chewing_handle_ShiftLeft;
427     g_pKeyHandler[XK_Shift_R]   = (void *)chewing_handle_ShiftRight;
428 #endif
429     g_pKeyHandler[XK_Delete] = (void *) hime_chewing_wrapper_del;
430 }
431 
module_init_win(HIME_module_main_functions * pFuncs)432 int module_init_win (HIME_module_main_functions *pFuncs) {
433     GtkWidget *pErrDialog = NULL;
434     int nIdx;
435     int nSegSize = 0;
436 
437     if (!pFuncs)
438         return FALSE;
439 
440     g_himeModMainFuncs = *pFuncs;
441 
442     g_himeModMainFuncs.mf_set_tsin_pho_mode ();
443     g_himeModMainFuncs.mf_set_win1_cb ((cb_selec_by_idx_t) select_idx,
444                                        prev_page,
445                                        next_page);
446 
447     if (g_pWinChewing)
448         return TRUE;
449 
450     if (!chewing_initialize ()) {
451         pErrDialog = gtk_message_dialog_new (NULL,
452                                              GTK_DIALOG_MODAL,
453                                              GTK_MESSAGE_ERROR,
454                                              GTK_BUTTONS_CLOSE,
455                                              "chewing init failed");
456         gtk_dialog_run (GTK_DIALOG (pErrDialog));
457         gtk_widget_destroy (pErrDialog);
458         return FALSE;
459     }
460 
461     g_pWinChewing = gtk_window_new (GTK_WINDOW_TOPLEVEL);
462     gtk_window_set_has_resize_grip (GTK_WINDOW (g_pWinChewing), FALSE);
463 
464     gtk_widget_realize (g_pWinChewing);
465     g_himeModMainFuncs.mf_set_no_focus (g_pWinChewing);
466 
467     g_pEvBoxChewing = gtk_event_box_new ();
468     gtk_event_box_set_visible_window (GTK_EVENT_BOX (g_pEvBoxChewing), FALSE);
469 
470     if (!g_pEvBoxChewing)
471         return FALSE;
472     gtk_container_add (GTK_CONTAINER (g_pWinChewing), g_pEvBoxChewing);
473 
474     g_pHBoxChewing = gtk_hbox_new (FALSE, 0);
475     if (!g_pHBoxChewing)
476         return FALSE;
477     gtk_container_add (GTK_CONTAINER (g_pEvBoxChewing), g_pHBoxChewing);
478 
479     // TODO: not sure if we need the mouse CB or not...
480     //        if we add the CB here, then it seems that we have to use gdk
481     //        it seems not so important...? do it later
482     //g_signal_connect (G_OBJECT (g_pEvBoxChewing), "button-press-event",
483     //                  G_CALLBACK (mouse_button_callback), NULL);
484 
485     if (!g_pSeg) {
486         nSegSize = sizeof (SEG) * MAX_SEG_NUM;
487         g_pSeg = malloc (nSegSize);
488         memset (g_pSeg, 0, nSegSize);
489     }
490 
491     for (nIdx = 0; nIdx < MAX_SEG_NUM; nIdx++) {
492         g_pSeg[nIdx].label = gtk_label_new (NULL);
493         gtk_widget_show (g_pSeg[nIdx].label);
494         gtk_box_pack_start (GTK_BOX (g_pHBoxChewing),
495                             g_pSeg[nIdx].label,
496                             FALSE,
497                             FALSE,
498                             0);
499     }
500 
501     if (!g_himeModMainFuncs.mf_phkbm->selkeyN)
502         g_himeModMainFuncs.mf_load_tab_pho_file ();
503 
504     gtk_widget_show_all (g_pWinChewing);
505 
506     g_himeModMainFuncs.mf_init_tsin_selection_win ();
507 
508     module_change_font_size ();
509 
510     module_hide_win ();
511 
512     return TRUE;
513 }
514 
515 // FIXME: impl
module_get_win_geom(void)516 void module_get_win_geom (void) {
517     return;
518 }
519 
520 // FIXME: chk
module_reset(void)521 int module_reset (void) {
522     if (!g_pWinChewing)
523         return 0;
524     return 1;
525 }
526 
527 // FIXME: refine and chk
module_get_preedit(char * pszStr,HIME_PREEDIT_ATTR himePreeditAttr[],int * pnCursor,int * pCompFlag)528 int module_get_preedit (char *pszStr, HIME_PREEDIT_ATTR himePreeditAttr[], int *pnCursor, int *pCompFlag) {
529     char *pszTmpStr = NULL;
530     const char *pszZuinStr = NULL;
531     int nIdx;
532     int nLength;
533     int nTotalLen = 0;
534     int nAttr = 0;
535     int nZuinLen = 0;
536 
537     pszStr[0] = 0;
538     *pnCursor = 0;
539     himePreeditAttr[0].flag = HIME_PREEDIT_ATTR_FLAG_UNDERLINE;
540     himePreeditAttr[0].ofs0 = 0;
541 
542     if (chewing_buffer_Len (g_pChewingCtx))
543         nAttr = 1;
544 
545     for (nIdx = 0; nIdx < chewing_buffer_Len (g_pChewingCtx); nIdx++) {
546         pszTmpStr = (char *) gtk_label_get_text (GTK_LABEL (g_pSeg[nIdx].label));
547         nLength = g_himeModMainFuncs.mf_utf8_str_N (pszTmpStr);
548         nTotalLen += nLength;
549 
550         if (nIdx < chewing_cursor_Current (g_pChewingCtx))
551             *pnCursor += nLength;
552 
553 #if 0
554         if (nIdx == chewing_cursor_Current (g_pChewingCtx))
555         {
556             himePreeditAttr[1].ofs0 = *pnCursor;
557             himePreeditAttr[1].ofs1 = *pnCursor + nLength;
558             himePreeditAttr[1].flag = HIME_PREEDIT_ATTR_FLAG_REVERSE;
559             nAttr++;
560         }
561 #endif
562 
563         strcat (pszStr, pszTmpStr);
564     }
565 
566     if (g_himeModMainFuncs.mf_hime_display_on_the_spot_key ()) {
567         pszZuinStr = chewing_bopomofo_String_static (g_pChewingCtx);
568         strcat (pszStr, pszZuinStr);
569         nTotalLen += nZuinLen;
570     }
571 
572     himePreeditAttr[0].ofs1 = nTotalLen;
573 
574     pCompFlag = 0;
575 
576     return nAttr;
577 }
578 
579 gboolean
module_feedkey(int nKeyVal,int nKeyState)580 module_feedkey (int nKeyVal, int nKeyState) {
581     if (!g_pChewingCtx)
582         return FALSE;
583 
584     if (!g_himeModMainFuncs.mf_tsin_pho_mode ())
585         return FALSE;
586 
587     hime_label_clear (MAX_SEG_NUM);
588 
589     chewing_set_ShapeMode (g_pChewingCtx, g_himeModMainFuncs.mf_current_shape_mode ());
590 
591     if (nKeyState & (Mod1Mask | Mod4Mask | Mod5Mask | ControlMask))
592         return FALSE;
593 
594     if (!hime_key_filter (&nKeyVal))
595         return FALSE;
596 
597     if (!hime_buffer_commit ())
598         return FALSE;
599 
600     if (!hime_buffer_label_show ())
601         return FALSE;
602 
603     if (!hime_zuin_label_show ())
604         return FALSE;
605 
606     module_show_win ();
607 
608     return TRUE;
609 }
610 
611 // FIXME: impl
module_feedkey_release(KeySym xkey,int nKbState)612 int module_feedkey_release (KeySym xkey, int nKbState) {
613     return 0;
614 }
615 
module_move_win(int nX,int nY)616 void module_move_win (int nX, int nY) {
617     gtk_window_get_size (GTK_WINDOW (g_pWinChewing),
618                          g_himeModMainFuncs.mf_win_xl,
619                          g_himeModMainFuncs.mf_win_yl);
620 
621     if (nX + *g_himeModMainFuncs.mf_win_xl > *g_himeModMainFuncs.mf_dpy_xl)
622         nX = *g_himeModMainFuncs.mf_dpy_xl - *g_himeModMainFuncs.mf_win_xl;
623     if (nX < 0)
624         nX = 0;
625 
626     if (nY + *g_himeModMainFuncs.mf_win_yl > *g_himeModMainFuncs.mf_dpy_yl)
627         nY = *g_himeModMainFuncs.mf_dpy_yl - *g_himeModMainFuncs.mf_win_yl;
628     if (nY < 0)
629         nY = 0;
630 
631     gtk_window_move (GTK_WINDOW (g_pWinChewing), nX, nY);
632 
633     *g_himeModMainFuncs.mf_win_x = nX;
634     *g_himeModMainFuncs.mf_win_y = nY;
635 
636     g_himeModMainFuncs.mf_move_win_sym ();
637 }
638 
module_change_font_size(void)639 void module_change_font_size (void) {
640     GdkColor colorFG;
641 
642     gdk_color_parse (*g_himeModMainFuncs.mf_hime_win_color_fg, &colorFG);
643 
644 #if GTK_CHECK_VERSION(3, 0, 0)
645     GdkRGBA rgbfg;
646     gdk_rgba_parse (&rgbfg, gdk_color_to_string (&colorFG));
647 #endif
648 
649     g_himeModMainFuncs.mf_change_win_bg (g_pWinChewing);
650     g_himeModMainFuncs.mf_change_win_bg (g_pEvBoxChewing);
651 
652     for (int i = 0; i < MAX_SEG_NUM; i++) {
653         GtkWidget *pLabel = g_pSeg[i].label;
654         g_himeModMainFuncs.mf_set_label_font_size (
655             pLabel,
656             *g_himeModMainFuncs.mf_hime_font_size);
657 
658         if (*g_himeModMainFuncs.mf_hime_win_color_use) {
659 #if !GTK_CHECK_VERSION(3, 0, 0)
660             gtk_widget_modify_fg (pLabel, GTK_STATE_NORMAL, &colorFG);
661 #else
662             gtk_widget_override_color (pLabel, GTK_STATE_FLAG_NORMAL, &rgbfg);
663 #endif
664         }
665     }
666 }
667 
module_show_win(void)668 void module_show_win (void) {
669     if (g_himeModMainFuncs.mf_hime_edit_display_ap_only ())
670         return;
671 
672     if (*g_himeModMainFuncs.mf_hime_pop_up_win && is_empty ())
673         return;
674 
675     gtk_window_resize (GTK_WINDOW (g_pWinChewing),
676                        32 * (chewing_buffer_Check (g_pChewingCtx) + 1),
677                        12);
678     gtk_widget_show (g_pWinChewing);
679 
680     g_himeModMainFuncs.mf_show_win_sym ();
681 }
682 
module_hide_win(void)683 void module_hide_win (void) {
684     gtk_widget_hide (g_pWinChewing);
685     g_himeModMainFuncs.mf_hide_selections_win ();
686     g_himeModMainFuncs.mf_hide_win_sym ();
687 }
688 
689 // FIXME: chk
module_win_visible(void)690 int module_win_visible (void) {
691     return gtk_widget_get_visible (g_pWinChewing);
692 }
693 
module_win_geom(void)694 void module_win_geom (void) {
695     if (!g_pWinChewing)
696         return;
697 
698     gtk_window_get_position (GTK_WINDOW (g_pWinChewing),
699                              g_himeModMainFuncs.mf_win_x,
700                              g_himeModMainFuncs.mf_win_y);
701 
702     g_himeModMainFuncs.mf_get_win_size (g_pWinChewing,
703                                         g_himeModMainFuncs.mf_win_xl,
704                                         g_himeModMainFuncs.mf_win_yl);
705 }
706 
module_flush_input(void)707 int module_flush_input (void) {
708     char *pszTmp;
709 
710     if (chewing_buffer_Check (g_pChewingCtx)) {
711         pszTmp = chewing_buffer_String (g_pChewingCtx);
712         g_himeModMainFuncs.mf_send_text (pszTmp);
713         free (pszTmp);
714     }
715 
716     chewing_Reset (g_pChewingCtx);
717 
718     // FIXME: dirty workaround to reset the libchewing internal data
719     //        it may impact the bEscCleanAllBuf setting
720     chewing_handle_Esc (g_pChewingCtx);
721 
722     hime_label_clear (MAX_SEG_NUM);
723 
724     if (*g_himeModMainFuncs.mf_hime_pop_up_win && is_empty ())
725         module_hide_win ();
726 
727     return 0;
728 }
729