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