1 #include "chewing.h"
2 
3 // gcin-chewing funcs
4 static gboolean select_idx (int c);
5 static void prev_page (void);
6 static void next_page (void);
7 static gboolean chewing_initialize (void);
8 static gboolean is_empty (void);
9 static gboolean gcin_label_show (char *pszPho, int nPos);
10 static gboolean gcin_label_clear (int nCount);
11 static gboolean gcin_label_cand_show (char *pszWord, int nCount);
12 static gboolean gtk_pango_font_pixel_size_get (int *pnFontWidth, int *pnFontHeight);
13 
14 static GCIN_module_main_functions g_gcinModMainFuncs;
15 static GtkWidget *g_pWinChewing      = NULL;
16 static ChewingContext *g_pChewingCtx = NULL;
17 static GtkWidget *g_pEvBoxChewing    = NULL;
18 static GtkWidget *g_pHBoxChewing     = NULL;
19 static SEG *g_pSeg = NULL;
20 static int g_nCurrentCursorPos = 0;
21 
22 // FIXME: impl
23 static gboolean
select_idx(int c)24 select_idx (int c)
25 {
26     return TRUE;
27 }
28 
29 // FIXME: impl
30 static void
prev_page(void)31 prev_page (void)
32 {
33 }
34 
35 // FIXME: impl
36 static void
next_page(void)37 next_page (void)
38 {
39 }
40 
41 static gboolean
gcin_label_show(char * pszPho,int nPos)42 gcin_label_show (char *pszPho, int nPos)
43 {
44     char szTmp[128];
45 
46     if (!pszPho)
47         return FALSE;
48 
49     memset (szTmp, 0x00, 128);
50 
51     sprintf (szTmp, "<span background=\"%s\" foreground=\"%s\">%s</span>",
52              *g_gcinModMainFuncs.mf_tsin_cursor_color,
53              *g_gcinModMainFuncs.mf_gcin_win_color_fg,
54              pszPho);
55 
56     gtk_label_set_markup (GTK_LABEL (g_pSeg[nPos].label),
57                           nPos != g_nCurrentCursorPos ? pszPho : szTmp);
58 
59     return TRUE;
60 }
61 
62 static gboolean
gcin_label_clear(int nCount)63 gcin_label_clear (int nCount)
64 {
65     while (nCount--)
66         gtk_label_set_text (GTK_LABEL (g_pSeg[nCount].label), NULL);
67 
68     return TRUE;
69 }
70 
71 static gboolean
gtk_pango_font_pixel_size_get(int * pnFontWidth,int * pnFontHeight)72 gtk_pango_font_pixel_size_get (int *pnFontWidth, int *pnFontHeight)
73 {
74     PangoLayout *pPangoLayout;
75     PangoContext *pPangoContext;
76     PangoFontDescription *pPangoFontDesc;
77 
78     pPangoLayout = gtk_widget_create_pango_layout (g_pWinChewing, "中");
79     //pPangoLayout = gtk_widget_create_pango_layout (
80     //                   g_pWinChewing,
81     //                   (char *)gtk_label_get_text (GTK_LABEL (g_pSeg[g_nCurrentCursorPos].label)));
82     pPangoContext = gtk_widget_get_pango_context (g_pWinChewing);
83     pPangoFontDesc = pango_context_get_font_description (pPangoContext);
84 
85     pango_layout_set_font_description (pPangoLayout, pPangoFontDesc);
86     pango_layout_get_pixel_size (pPangoLayout, pnFontWidth, pnFontHeight);
87 
88     g_object_unref (pPangoLayout);
89     return TRUE;
90 }
91 
92 // FIXME: the pos of g_pSeg[].label is not correct
93 static gboolean
gcin_label_cand_show(char * pszWord,int nIdx)94 gcin_label_cand_show (char *pszWord, int nIdx)
95 {
96     int nX, nY;
97     int nFontWidth, nFontHeight;
98 
99     g_gcinModMainFuncs.mf_set_sele_text (nIdx,
100                                          pszWord,
101                                          -1);
102 
103     // find the position of the cand win
104     g_gcinModMainFuncs.mf_get_widget_xy (g_pWinChewing,
105                                          g_pSeg[g_nCurrentCursorPos].label,
106                                          &nX, &nY);
107 
108     gtk_pango_font_pixel_size_get (&nFontWidth, &nFontHeight);
109     nX += g_nCurrentCursorPos * nFontWidth;
110 
111     nY = g_gcinModMainFuncs.mf_gcin_edit_display_ap_only () ?
112          *g_gcinModMainFuncs.mf_win_y :
113          *g_gcinModMainFuncs.mf_win_y + *g_gcinModMainFuncs.mf_win_yl;
114 
115     g_gcinModMainFuncs.mf_disp_selections (nX, nY);
116 
117     return TRUE;
118 }
119 
120 static gboolean
chewing_initialize(void)121 chewing_initialize (void)
122 {
123     char *pszChewingHashDir;
124     char *pszHome;
125     gboolean bWriteMode = FALSE;
126     ChewingConfigData dummyConfig;
127 
128     pszHome = getenv ("HOME");
129     if (!pszHome)
130         pszHome = "";
131 
132     pszChewingHashDir = malloc (strlen (pszHome) + strlen ("/.chewing/") + 1);
133     memset (pszChewingHashDir, 0x00, strlen (pszHome) + strlen ("/.chewing/") + 1);
134     sprintf (pszChewingHashDir, "%s/.chewing", pszHome);
135 
136     if (chewing_Init (CHEWING_DATADIR, pszChewingHashDir) != 0)
137     {
138         free (pszChewingHashDir);
139         return FALSE;
140     }
141     free (pszChewingHashDir);
142     pszHome = NULL;
143 
144     g_pChewingCtx = chewing_new ();
145     if (!g_pChewingCtx)
146         return FALSE;
147 
148     memset (&dummyConfig, 0x00, sizeof (ChewingConfigData));
149 
150     chewing_config_open (bWriteMode);
151 
152     chewing_config_load (&dummyConfig);
153 
154     chewing_config_set (g_pChewingCtx);
155 
156     chewing_config_close ();
157 
158     return TRUE;
159 }
160 
161 static gboolean
is_empty(void)162 is_empty (void)
163 {
164     if (!g_pChewingCtx)
165         return FALSE;
166     return chewing_zuin_Check (g_pChewingCtx) ? FALSE : TRUE;
167 }
168 
169 int
module_init_win(GCIN_module_main_functions * pFuncs)170 module_init_win (GCIN_module_main_functions *pFuncs)
171 {
172     GtkWidget *pErrDialog = NULL;
173     int nIdx;
174     int nSegSize = 0;
175 
176     if (!pFuncs)
177         return FALSE;
178 
179     g_gcinModMainFuncs = *pFuncs;
180 
181     g_gcinModMainFuncs.mf_set_tsin_pho_mode ();
182     g_gcinModMainFuncs.mf_set_win1_cb ((cb_selec_by_idx_t)select_idx,
183                                         prev_page,
184                                         next_page);
185 
186     if (g_pWinChewing)
187         return TRUE;
188 
189     if (!chewing_initialize ())
190     {
191         pErrDialog = gtk_message_dialog_new (NULL,
192                          GTK_DIALOG_MODAL,
193                          GTK_MESSAGE_ERROR,
194                          GTK_BUTTONS_CLOSE,
195                          "chewing init failed");
196         gtk_dialog_run (GTK_DIALOG (pErrDialog));
197         gtk_widget_destroy (pErrDialog);
198         return FALSE;
199     }
200 
201     g_pWinChewing = gtk_window_new (GTK_WINDOW_TOPLEVEL);
202     gtk_window_set_has_resize_grip (GTK_WINDOW (g_pWinChewing), FALSE);
203     gtk_window_set_resizable(GTK_WINDOW(g_pWinChewing), FALSE);
204 
205     gtk_window_set_default_size (GTK_WINDOW (g_pWinChewing), 32, 12);
206 
207     gtk_widget_realize (g_pWinChewing);
208     g_gcinModMainFuncs.mf_set_no_focus (g_pWinChewing);
209 
210     g_pEvBoxChewing = gtk_event_box_new ();
211     gtk_event_box_set_visible_window (GTK_EVENT_BOX(g_pEvBoxChewing), FALSE);
212 
213     if (!g_pEvBoxChewing)
214         return FALSE;
215     gtk_container_add (GTK_CONTAINER (g_pWinChewing), g_pEvBoxChewing);
216 
217     g_pHBoxChewing = gtk_hbox_new (FALSE, 0);
218     if (!g_pHBoxChewing)
219         return FALSE;
220     gtk_container_add (GTK_CONTAINER (g_pEvBoxChewing), g_pHBoxChewing);
221 
222     // TODO: not sure if we need the mouse CB or not...
223     //        if we add the CB here, then it seems that we have to use gdk
224     //        it seems not so important...? do it later
225     //g_signal_connect (G_OBJECT (g_pEvBoxChewing), "button-press-event",
226     //                  G_CALLBACK (mouse_button_callback), NULL);
227 
228     if (!g_pSeg)
229     {
230         nSegSize = sizeof (SEG) * MAX_SEG_NUM;
231         g_pSeg = malloc (nSegSize);
232         memset (g_pSeg, 0, nSegSize);
233     }
234 
235     for (nIdx = 0; nIdx < MAX_SEG_NUM; nIdx++)
236     {
237         g_pSeg[nIdx].label = gtk_label_new (NULL);
238         gtk_widget_show (g_pSeg[nIdx].label);
239         gtk_box_pack_start (GTK_BOX (g_pHBoxChewing),
240                             g_pSeg[nIdx].label,
241                             FALSE,
242                             FALSE,
243                             0);
244     }
245 
246     if (!g_gcinModMainFuncs.mf_phkbm->selkeyN)
247         g_gcinModMainFuncs.mf_load_tab_pho_file();
248 
249     gtk_widget_show_all (g_pWinChewing);
250 
251     g_gcinModMainFuncs.mf_init_tsin_selection_win ();
252 
253     module_change_font_size ();
254 
255     module_hide_win ();
256 
257     return TRUE;
258 }
259 
260 // FIXME: impl
261 void
module_get_win_geom(void)262 module_get_win_geom (void)
263 {
264     return;
265 }
266 
267 // FIXME: chk
268 int
module_reset(void)269 module_reset (void)
270 {
271     if (!g_pWinChewing)
272         return 0;
273     return 1;
274 }
275 
276 // FIXME: refine and chk
277 int
module_get_preedit(char * pszStr,GCIN_PREEDIT_ATTR gcinPreeditAttr[],int * pnCursor,int * pCompFlag)278 module_get_preedit (char *pszStr, GCIN_PREEDIT_ATTR gcinPreeditAttr[],
279                     int *pnCursor, int *pCompFlag)
280 {
281     char *pszTmpStr = NULL;
282     int nIdx;
283     int nLength;
284     int nTotalLen = 0;
285     int nAttr = 0;
286 
287     pszStr[0] = 0;
288     *pnCursor = 0;
289     gcinPreeditAttr[0].flag = GCIN_PREEDIT_ATTR_FLAG_UNDERLINE;
290     gcinPreeditAttr[0].ofs0 = 0;
291 
292     if (chewing_buffer_Len (g_pChewingCtx))
293         nAttr = 1;
294 
295     for (nIdx = 0; nIdx < chewing_buffer_Len (g_pChewingCtx); nIdx++)
296     {
297         pszTmpStr = (char *)gtk_label_get_text (GTK_LABEL (g_pSeg[nIdx].label));
298         nLength = g_gcinModMainFuncs.mf_utf8_str_N (pszTmpStr);
299         nTotalLen += nLength;
300 
301         if (nIdx < chewing_cursor_Current (g_pChewingCtx))
302             *pnCursor += nLength;
303 
304 #if 0
305         if (nIdx == chewing_cursor_Current (g_pChewingCtx))
306         {
307             gcinPreeditAttr[1].ofs0 = *pnCursor;
308             gcinPreeditAttr[1].ofs1 = *pnCursor + nLength;
309             gcinPreeditAttr[1].flag = GCIN_PREEDIT_ATTR_FLAG_REVERSE;
310             nAttr++;
311         }
312 #endif
313 
314         strcat (pszStr, pszTmpStr);
315     }
316 
317     gcinPreeditAttr[0].ofs1 = nTotalLen;
318 
319     pCompFlag = 0;
320 
321     return nAttr;
322 }
323 
324 gboolean
module_feedkey(int nKeyVal,int nKeyState)325 module_feedkey (int nKeyVal, int nKeyState)
326 {
327     char *pszTmp         = NULL;
328     char *pszChewingCand = NULL;
329     int nZuinLen         = 0;
330     char szWord[4];
331     int nPhoIdx, nBufIdx;
332     int nIdx;
333 
334     if (!g_pChewingCtx)
335         return FALSE;
336 
337     memset (szWord, 0x00, 4);
338 
339     if (!g_gcinModMainFuncs.mf_tsin_pho_mode ())
340         return FALSE;
341 
342     switch (nKeyVal)
343     {
344         case XK_space:
345             chewing_handle_Space (g_pChewingCtx);
346             break;
347 
348         case XK_Escape:
349             chewing_handle_Esc (g_pChewingCtx);
350             break;
351 
352         case XK_Return:
353         case XK_KP_Enter:
354             chewing_handle_Enter (g_pChewingCtx);
355             break;
356 
357         case XK_Delete:
358         case XK_KP_Delete:
359             chewing_handle_Del (g_pChewingCtx);
360             break;
361 
362         case XK_BackSpace:
363             chewing_handle_Backspace (g_pChewingCtx);
364             break;
365 
366         case XK_Up:
367         case XK_KP_Up:
368             chewing_handle_Up (g_pChewingCtx);
369             break;
370 
371         case XK_Down:
372         case XK_KP_Down:
373             chewing_handle_Down (g_pChewingCtx);
374             break;
375 
376         case XK_Left:
377         case XK_KP_Left:
378             chewing_handle_Left (g_pChewingCtx);
379             break;
380 
381         case XK_Right:
382         case XK_KP_Right:
383             chewing_handle_Right (g_pChewingCtx);
384             break;
385 
386 #if 0
387         case XK_Shift_L:
388             chewing_handle_ShiftLeft (g_pChewingCtx);
389             break;
390 
391         case XK_Shift_R:
392             chewing_handle_ShiftRight (g_pChewingCtx);
393             break;
394 #endif
395 
396         case XK_Tab:
397             chewing_handle_Tab (g_pChewingCtx);
398             break;
399 
400         default:
401             if (nKeyVal > 32 && nKeyVal < 127)
402                 chewing_handle_Default (g_pChewingCtx, nKeyVal);
403             break;
404     }
405 
406     gcin_label_clear (MAX_SEG_NUM);
407     g_nCurrentCursorPos = chewing_cursor_Current (g_pChewingCtx);
408 
409     if (g_nCurrentCursorPos < 0 || g_nCurrentCursorPos > MAX_SEG_NUM)
410         return FALSE;
411 
412     // zuin symbols
413     pszTmp = chewing_zuin_String (g_pChewingCtx, &nZuinLen);
414     if (pszTmp)
415     {
416         for (nBufIdx = 0; nBufIdx < nZuinLen; nBufIdx++)
417         {
418             memcpy (szWord, pszTmp + nBufIdx * 3, 3);
419             for (nPhoIdx = 0; nPhoIdx < 3; nPhoIdx++)
420                 if (strstr (g_gcinModMainFuncs.mf_pho_chars[nPhoIdx], szWord) != NULL)
421                     gcin_label_show (szWord, nPhoIdx + chewing_buffer_Len (g_pChewingCtx) + 1);
422         }
423         free (pszTmp);
424     }
425 
426     // check if the composing is valid or not
427     if (chewing_buffer_Check (g_pChewingCtx))
428     {
429         g_gcinModMainFuncs.mf_hide_selections_win ();
430         pszTmp = chewing_buffer_String (g_pChewingCtx);
431 
432         // init cand_no
433         chewing_cand_Enumerate (g_pChewingCtx);
434 
435         g_gcinModMainFuncs.mf_clear_sele ();
436 
437         if (chewing_cand_TotalChoice (g_pChewingCtx))
438         {
439             nIdx = 0;
440             while (chewing_cand_hasNext (g_pChewingCtx))
441             {
442                 pszChewingCand = chewing_cand_String (g_pChewingCtx);
443 
444                 if (nIdx > chewing_get_candPerPage (g_pChewingCtx) - 1)
445                     break;
446                 gcin_label_cand_show (pszChewingCand, nIdx++);
447                 free (pszChewingCand);
448             }
449         }
450 
451         for (nIdx = 0; nIdx < chewing_buffer_Len (g_pChewingCtx); nIdx++)
452         {
453             memcpy (szWord, pszTmp + (nIdx * 3), 3);
454             gcin_label_show (szWord, nIdx);
455         }
456 
457         free (pszTmp);
458     }
459 
460     if (chewing_commit_Check (g_pChewingCtx))
461     {
462         pszTmp = chewing_commit_String (g_pChewingCtx);
463         g_gcinModMainFuncs.mf_send_text (pszTmp);
464 
465         // FIXME: workaround for repeated commit
466         //        it impacts the bEscCleanAllBuf setting!
467         chewing_handle_Esc (g_pChewingCtx);
468         free (pszTmp);
469     }
470 
471     module_show_win ();
472 
473     return TRUE;
474 }
475 
476 // FIXME: impl
477 int
module_feedkey_release(KeySym xkey,int nKbState)478 module_feedkey_release (KeySym xkey, int nKbState)
479 {
480     return 0;
481 }
482 
483 void
module_move_win(int nX,int nY)484 module_move_win (int nX, int nY)
485 {
486     gtk_window_get_size (GTK_WINDOW (g_pWinChewing),
487                          g_gcinModMainFuncs.mf_win_xl,
488                          g_gcinModMainFuncs.mf_win_yl);
489 
490     if (nX + *g_gcinModMainFuncs.mf_win_xl > *g_gcinModMainFuncs.mf_dpy_xl)
491         nX = *g_gcinModMainFuncs.mf_dpy_xl - *g_gcinModMainFuncs.mf_win_xl;
492     if (nX < 0)
493         nX = 0;
494 
495     if (nY + *g_gcinModMainFuncs.mf_win_yl > *g_gcinModMainFuncs.mf_dpy_yl)
496         nY = *g_gcinModMainFuncs.mf_dpy_yl - *g_gcinModMainFuncs.mf_win_yl;
497     if (nY < 0)
498         nY = 0;
499 
500     gtk_window_move (GTK_WINDOW(g_pWinChewing), nX, nY);
501 
502     *g_gcinModMainFuncs.mf_win_x = nX;
503     *g_gcinModMainFuncs.mf_win_y = nY;
504 
505     g_gcinModMainFuncs.mf_move_win_sym ();
506 }
507 
508 void
module_change_font_size(void)509 module_change_font_size (void)
510 {
511     GdkColor colorFG;
512     GtkWidget *pLabel;
513     int n;
514 
515     gdk_color_parse (*g_gcinModMainFuncs.mf_gcin_win_color_fg, &colorFG);
516     g_gcinModMainFuncs.mf_change_win_bg (g_pWinChewing);
517     g_gcinModMainFuncs.mf_change_win_bg (g_pEvBoxChewing);
518 
519     for (n = 0; n < MAX_SEG_NUM; n++)
520     {
521         pLabel = g_pSeg[n].label;
522         g_gcinModMainFuncs.mf_set_label_font_size (pLabel,
523             *g_gcinModMainFuncs.mf_gcin_font_size);
524 
525         if (*g_gcinModMainFuncs.mf_gcin_win_color_use) {
526 #if !GTK_CHECK_VERSION(2,91,6)
527             gtk_widget_modify_fg (pLabel, GTK_STATE_NORMAL, &colorFG);
528 #else
529             GdkRGBA rgbfg;
530             gdk_rgba_parse(&rgbfg, gdk_color_to_string(&colorFG));
531             gtk_widget_override_color(pLabel, GTK_STATE_FLAG_NORMAL, &rgbfg);
532 #endif
533         }
534     }
535 }
536 
537 void
module_show_win(void)538 module_show_win (void)
539 {
540     if (g_gcinModMainFuncs.mf_gcin_edit_display_ap_only ())
541         return;
542 
543     if (is_empty ())
544         return;
545 
546     gtk_window_resize (GTK_WINDOW (g_pWinChewing),
547                        32 * (chewing_buffer_Check (g_pChewingCtx) + 1),
548                        12);
549     gtk_widget_show (g_pWinChewing);
550 
551     g_gcinModMainFuncs.mf_show_win_sym ();
552 }
553 
554 void
module_hide_win(void)555 module_hide_win (void)
556 {
557     gtk_widget_hide (g_pWinChewing);
558     g_gcinModMainFuncs.mf_hide_selections_win ();
559     g_gcinModMainFuncs.mf_hide_win_sym ();
560 }
561 
562 // FIXME: chk
563 int
module_win_visible(void)564 module_win_visible (void)
565 {
566     return GTK_WIDGET_VISIBLE (g_pWinChewing);
567 }
568 
569 void
module_win_geom(void)570 module_win_geom (void)
571 {
572     if (!g_pWinChewing)
573         return;
574 
575     gtk_window_get_position(GTK_WINDOW(g_pWinChewing),
576                             g_gcinModMainFuncs.mf_win_x,
577                             g_gcinModMainFuncs.mf_win_y);
578 
579     g_gcinModMainFuncs.mf_get_win_size(g_pWinChewing,
580                                        g_gcinModMainFuncs.mf_win_xl,
581                                        g_gcinModMainFuncs.mf_win_yl);
582 }
583 
584 int
module_flush_input(void)585 module_flush_input (void)
586 {
587     char *pszTmp;
588 
589     if (chewing_commit_Check (g_pChewingCtx))
590     {
591         pszTmp = chewing_commit_String (g_pChewingCtx);
592         g_gcinModMainFuncs.mf_send_text (pszTmp);
593         free (pszTmp);
594     }
595 
596     chewing_Reset (g_pChewingCtx);
597     return 0;
598 }
599 
600