Refactoring hanja mode code
[platform/upstream/ibus-hangul.git] / src / engine.c
1 /* vim:set et sts=4: */
2
3 #include <ibus.h>
4 #include <hangul.h>
5 #include <string.h>
6
7 #include "engine.h"
8 #include "ustring.h"
9
10 typedef struct _IBusHangulEngine IBusHangulEngine;
11 typedef struct _IBusHangulEngineClass IBusHangulEngineClass;
12
13 struct _IBusHangulEngine {
14         IBusEngine parent;
15
16     /* members */
17     HangulInputContext *context;
18     UString* preedit;
19     gboolean hangul_mode;
20     gboolean hanja_mode;
21     HanjaList* hanja_list;
22
23     IBusLookupTable *table;
24
25     IBusProperty    *hangul_mode_prop;
26     IBusProperty    *prop_hanja_mode;
27     IBusPropList    *prop_list;
28 };
29
30 struct _IBusHangulEngineClass {
31         IBusEngineClass parent;
32 };
33
34 /* functions prototype */
35 static void     ibus_hangul_engine_class_init   (IBusHangulEngineClass  *klass);
36 static void     ibus_hangul_engine_init             (IBusHangulEngine           *hangul);
37 static GObject*
38             ibus_hangul_engine_constructor  (GType                   type,
39                                              guint                   n_construct_params,
40                                              GObjectConstructParam  *construct_params);
41 static void     ibus_hangul_engine_destroy              (IBusHangulEngine               *hangul);
42 static gboolean
43                         ibus_hangul_engine_process_key_event
44                                             (IBusEngine             *engine,
45                                              guint                   keyval,
46                                              guint                   keycode,
47                                              guint                   modifiers);
48 static void ibus_hangul_engine_focus_in     (IBusEngine             *engine);
49 static void ibus_hangul_engine_focus_out    (IBusEngine             *engine);
50 static void ibus_hangul_engine_reset        (IBusEngine             *engine);
51 static void ibus_hangul_engine_enable       (IBusEngine             *engine);
52 static void ibus_hangul_engine_disable      (IBusEngine             *engine);
53 #if 0
54 static void ibus_engine_set_cursor_location (IBusEngine             *engine,
55                                              gint                    x,
56                                              gint                    y,
57                                              gint                    w,
58                                              gint                    h);
59 static void ibus_hangul_engine_set_capabilities
60                                             (IBusEngine             *engine,
61                                              guint                   caps);
62 #endif
63 static void ibus_hangul_engine_page_up      (IBusEngine             *engine);
64 static void ibus_hangul_engine_page_down    (IBusEngine             *engine);
65 static void ibus_hangul_engine_cursor_up    (IBusEngine             *engine);
66 static void ibus_hangul_engine_cursor_down  (IBusEngine             *engine);
67 static void ibus_hangul_engine_property_activate
68                                             (IBusEngine             *engine,
69                                              const gchar            *prop_name,
70                                              guint                   prop_state);
71 #if 0
72 static void ibus_hangul_engine_property_show
73                                                                                         (IBusEngine             *engine,
74                                              const gchar            *prop_name);
75 static void ibus_hangul_engine_property_hide
76                                                                                         (IBusEngine             *engine,
77                                              const gchar            *prop_name);
78 #endif
79
80 static void ibus_hangul_engine_flush        (IBusHangulEngine       *hangul);
81 static void ibus_hangul_engine_update_preedit_text
82                                             (IBusHangulEngine       *hangul);
83
84 static void ibus_hangul_engine_update_lookup_table
85                                             (IBusHangulEngine       *hangul);
86 static void ibus_config_value_changed       (IBusConfig             *config,
87                                              const gchar            *section,
88                                              const gchar            *name,
89                                              GValue                 *value,
90                                              gpointer                user_data);
91
92 static void     lookup_table_set_visible    (IBusLookupTable *table,
93                                              gboolean flag);
94 static gboolean lookup_table_is_visible     (IBusLookupTable *table);
95
96 static IBusEngineClass *parent_class = NULL;
97 static HanjaTable *hanja_table = NULL;
98 static IBusConfig *config = NULL;
99 static GString    *hangul_keyboard;
100
101 GType
102 ibus_hangul_engine_get_type (void)
103 {
104         static GType type = 0;
105
106         static const GTypeInfo type_info = {
107                 sizeof (IBusHangulEngineClass),
108                 (GBaseInitFunc)         NULL,
109                 (GBaseFinalizeFunc) NULL,
110                 (GClassInitFunc)        ibus_hangul_engine_class_init,
111                 NULL,
112                 NULL,
113                 sizeof (IBusHangulEngine),
114                 0,
115                 (GInstanceInitFunc)     ibus_hangul_engine_init,
116         };
117
118         if (type == 0) {
119                 type = g_type_register_static (IBUS_TYPE_ENGINE,
120                                                                            "IBusHangulEngine",
121                                                                            &type_info,
122                                                                            (GTypeFlags) 0);
123         }
124
125         return type;
126 }
127
128 void
129 ibus_hangul_init (IBusBus *bus)
130 {
131     gboolean res;
132     GValue value = { 0, };
133
134     hanja_table = hanja_table_load (NULL);
135
136     config = ibus_bus_get_config (bus);
137
138     hangul_keyboard = g_string_new_len ("2", 8);
139     res = ibus_config_get_value (config, "engine/Hangul",
140                                          "HangulKeyboard", &value);
141     if (res) {
142         const gchar* str = g_value_get_string (&value);
143         g_string_assign (hangul_keyboard, str);
144     }
145 }
146
147 void
148 ibus_hangul_exit (void)
149 {
150     hanja_table_delete (hanja_table);
151     hanja_table = NULL;
152
153     g_object_unref (config);
154     config = NULL;
155
156     g_string_free (hangul_keyboard, TRUE);
157     hangul_keyboard = NULL;
158 }
159
160 static void
161 ibus_hangul_engine_class_init (IBusHangulEngineClass *klass)
162 {
163     GObjectClass *object_class = G_OBJECT_CLASS (klass);
164         IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
165         IBusEngineClass *engine_class = IBUS_ENGINE_CLASS (klass);
166
167         parent_class = (IBusEngineClass *) g_type_class_peek_parent (klass);
168
169     object_class->constructor = ibus_hangul_engine_constructor;
170         ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_hangul_engine_destroy;
171
172     engine_class->process_key_event = ibus_hangul_engine_process_key_event;
173
174     engine_class->reset = ibus_hangul_engine_reset;
175     engine_class->enable = ibus_hangul_engine_enable;
176     engine_class->disable = ibus_hangul_engine_disable;
177
178     engine_class->focus_in = ibus_hangul_engine_focus_in;
179     engine_class->focus_out = ibus_hangul_engine_focus_out;
180
181     engine_class->page_up = ibus_hangul_engine_page_up;
182     engine_class->page_down = ibus_hangul_engine_page_down;
183
184     engine_class->cursor_up = ibus_hangul_engine_cursor_up;
185     engine_class->cursor_down = ibus_hangul_engine_cursor_down;
186
187     engine_class->property_activate = ibus_hangul_engine_property_activate;
188 }
189
190 static void
191 ibus_hangul_engine_init (IBusHangulEngine *hangul)
192 {
193     IBusProperty* prop;
194     IBusText* label;
195     IBusText* tooltip;
196
197     hangul->context = hangul_ic_new (hangul_keyboard->str);
198     hangul->preedit = ustring_new();
199     hangul->hanja_list = NULL;
200     hangul->hangul_mode = TRUE;
201     hangul->hanja_mode = FALSE;
202
203     hangul->prop_list = ibus_prop_list_new ();
204
205     label = ibus_text_new_from_static_string ("韓");
206     tooltip = ibus_text_new_from_static_string ("Enable/Disable Hanja mode");
207     prop = ibus_property_new ("hanja_mode",
208                               PROP_TYPE_NORMAL,
209                               label,
210                               NULL,
211                               tooltip,
212                               TRUE, TRUE, PROP_STATE_UNCHECKED, NULL);
213     g_object_unref (label);
214     g_object_unref (tooltip);
215     ibus_prop_list_append (hangul->prop_list, prop);
216     hangul->prop_hanja_mode = prop;
217
218     label = ibus_text_new_from_static_string ("Setup");
219     tooltip = ibus_text_new_from_static_string ("Configure hangul engine");
220     prop = ibus_property_new ("setup",
221                               PROP_TYPE_NORMAL,
222                               label,
223                               "gtk-preferences",
224                               tooltip,
225                               TRUE, TRUE, PROP_STATE_UNCHECKED, NULL);
226     g_object_unref (label);
227     g_object_unref (tooltip);
228     ibus_prop_list_append (hangul->prop_list, prop);
229
230     hangul->table = ibus_lookup_table_new (9, 0, TRUE, FALSE);
231
232     g_signal_connect (config, "value-changed",
233                       G_CALLBACK(ibus_config_value_changed), hangul);
234 }
235
236 static GObject*
237 ibus_hangul_engine_constructor (GType                   type,
238                                 guint                   n_construct_params,
239                                 GObjectConstructParam  *construct_params)
240 {
241     IBusHangulEngine *hangul;
242
243     hangul = (IBusHangulEngine *) G_OBJECT_CLASS (parent_class)->constructor (type,
244                                                        n_construct_params,
245                                                        construct_params);
246
247     return (GObject *)hangul;
248 }
249
250
251 static void
252 ibus_hangul_engine_destroy (IBusHangulEngine *hangul)
253 {
254     if (hangul->prop_list) {
255         g_object_unref (hangul->prop_list);
256         hangul->prop_list = NULL;
257     }
258
259     if (hangul->hangul_mode_prop) {
260         g_object_unref (hangul->hangul_mode_prop);
261         hangul->hangul_mode_prop = NULL;
262     }
263
264     if (hangul->table) {
265         g_object_unref (hangul->table);
266         hangul->table = NULL;
267     }
268
269     if (hangul->context) {
270         hangul_ic_delete (hangul->context);
271         hangul->context = NULL;
272     }
273
274         IBUS_OBJECT_CLASS (parent_class)->destroy ((IBusObject *)hangul);
275 }
276
277 static void
278 ibus_hangul_engine_update_preedit_text (IBusHangulEngine *hangul)
279 {
280     const ucschar *hic_preedit;
281     IBusText *text;
282     UString *preedit;
283     gint preedit_len;
284
285     // ibus-hangul's preedit string is made up of ibus context's
286     // internal preedit string and libhangul's preedit string.
287     // libhangul only supports one syllable preedit string.
288     // In order to make longer preedit string, ibus-hangul maintains
289     // internal preedit string.
290     hic_preedit = hangul_ic_get_preedit_string (hangul->context);
291
292     preedit = ustring_dup (hangul->preedit);
293     preedit_len = ustring_length(preedit);
294     ustring_append_ucs4 (preedit, hic_preedit, -1);
295
296     if (ustring_length(preedit) > 0) {
297         text = ibus_text_new_from_ucs4 ((gunichar*)preedit->data);
298         // ibus-hangul's internal preedit string
299         ibus_text_append_attribute (text, IBUS_ATTR_TYPE_UNDERLINE,
300                 IBUS_ATTR_UNDERLINE_SINGLE, 0, preedit_len);
301         // Preedit string from libhangul context.
302         // This is currently composing syllable.
303         ibus_text_append_attribute (text, IBUS_ATTR_TYPE_FOREGROUND,
304                 0x00ffffff, preedit_len, -1);
305         ibus_text_append_attribute (text, IBUS_ATTR_TYPE_BACKGROUND,
306                 0x00000000, preedit_len, -1);
307         ibus_engine_update_preedit_text ((IBusEngine *)hangul,
308                                          text,
309                                          ibus_text_get_length (text),
310                                          TRUE);
311         g_object_unref (text);
312     } else {
313         text = ibus_text_new_from_static_string ("");
314         ibus_engine_update_preedit_text ((IBusEngine *)hangul, text, 0, FALSE);
315         g_object_unref (text);
316     }
317
318     ustring_delete(preedit);
319 }
320
321 static void
322 ibus_hangul_engine_update_lookup_table_ui (IBusHangulEngine *hangul)
323 {
324     guint cursor_pos;
325     const char* comment;
326     IBusText* text;
327
328     // update aux text
329     cursor_pos = ibus_lookup_table_get_cursor_pos (hangul->table);
330     comment = hanja_list_get_nth_comment (hangul->hanja_list, cursor_pos);
331
332     text = ibus_text_new_from_string (comment);
333     ibus_engine_update_auxiliary_text ((IBusEngine *)hangul, text, TRUE);
334     g_object_unref (text);
335
336     // update lookup table
337     ibus_engine_update_lookup_table ((IBusEngine *)hangul, hangul->table, TRUE);
338 }
339
340 static void
341 ibus_hangul_engine_commit_current_candidate (IBusHangulEngine *hangul)
342 {
343     guint cursor_pos;
344     const char* key;
345     const char* value;
346     int key_len;
347     int preedit_len;
348     int len;
349
350     IBusText* text;
351
352     cursor_pos = ibus_lookup_table_get_cursor_pos (hangul->table);
353     key = hanja_list_get_nth_key (hangul->hanja_list, cursor_pos);
354     value = hanja_list_get_nth_value (hangul->hanja_list, cursor_pos);
355
356     key_len = g_utf8_strlen(key, -1);
357     preedit_len = ustring_length(hangul->preedit);
358
359     len = MIN(key_len, preedit_len);
360     ustring_erase (hangul->preedit, 0, len);
361     if (key_len > preedit_len)
362         hangul_ic_reset (hangul->context);
363
364     ibus_hangul_engine_update_preedit_text (hangul);
365
366     text = ibus_text_new_from_string (value);
367     ibus_engine_commit_text ((IBusEngine *)hangul, text);
368     g_object_unref (text);
369 }
370
371 static void
372 ibus_hangul_engine_update_hanja_list (IBusHangulEngine *hangul)
373 {
374     char* utf8;
375     const ucschar* hic_preedit;
376     UString* preedit;
377
378     if (hangul->hanja_list != NULL) {
379         hanja_list_delete (hangul->hanja_list);
380         hangul->hanja_list = NULL;
381     }
382
383     hic_preedit = hangul_ic_get_preedit_string (hangul->context);
384
385     preedit = ustring_dup (hangul->preedit);
386     ustring_append_ucs4 (preedit, hic_preedit, -1);
387     if (ustring_length(preedit) > 0) {
388         utf8 = ustring_to_utf8 (preedit, -1);
389         if (utf8 != NULL) {
390             hangul->hanja_list = hanja_table_match_prefix (hanja_table, utf8);
391             g_free (utf8);
392         }
393     }
394
395     ustring_delete (preedit);
396 }
397
398
399 static void
400 ibus_hangul_engine_apply_hanja_list (IBusHangulEngine *hangul)
401 {
402     HanjaList* list = hangul->hanja_list;
403     if (list != NULL) {
404         int i, n;
405         n = hanja_list_get_size (list);
406
407         ibus_lookup_table_clear (hangul->table);
408         for (i = 0; i < n; i++) {
409             const char* value = hanja_list_get_nth_value (list, i);
410             IBusText* text = ibus_text_new_from_string (value);
411             ibus_lookup_table_append_candidate (hangul->table, text);
412             g_object_unref (text);
413         }
414
415         ibus_lookup_table_set_cursor_pos (hangul->table, 0);
416         ibus_hangul_engine_update_lookup_table_ui (hangul);
417         lookup_table_set_visible (hangul->table, TRUE);
418     }
419 }
420
421 static void
422 ibus_hangul_engine_hide_lookup_table (IBusHangulEngine *hangul)
423 {
424     gboolean is_visible;
425     is_visible = lookup_table_is_visible (hangul->table);
426
427     // Sending hide lookup table message when the lookup table
428     // is not visible results wrong behavior. So I have to check
429     // whether the table is visible or not before to hide.
430     if (is_visible) {
431         ibus_engine_hide_lookup_table ((IBusEngine *)hangul);
432         ibus_engine_hide_auxiliary_text ((IBusEngine *)hangul);
433         lookup_table_set_visible (hangul->table, FALSE);
434     }
435
436     if (hangul->hanja_list != NULL) {
437         hanja_list_delete (hangul->hanja_list);
438         hangul->hanja_list = NULL;
439     }
440 }
441
442 static void
443 ibus_hangul_engine_update_lookup_table (IBusHangulEngine *hangul)
444 {
445     ibus_hangul_engine_update_hanja_list (hangul);
446
447     if (hangul->hanja_list != NULL) {
448         ibus_hangul_engine_apply_hanja_list (hangul);
449     } else {
450         ibus_hangul_engine_hide_lookup_table (hangul);
451     }
452 }
453
454 static gboolean
455 ibus_hangul_engine_process_candidate_key_event (IBusHangulEngine    *hangul,
456                                                 guint                keyval,
457                                                 guint                modifiers)
458 {
459     if (keyval == IBUS_Escape) {
460         ibus_hangul_engine_hide_lookup_table (hangul);
461         return TRUE;
462     } else if (keyval == IBUS_Return) {
463         ibus_hangul_engine_commit_current_candidate (hangul);
464
465         if (hangul->hanja_mode) {
466             ibus_hangul_engine_update_lookup_table (hangul);
467         } else {
468             ibus_hangul_engine_hide_lookup_table (hangul);
469         }
470         return TRUE;
471     } else if (keyval >= IBUS_1 && keyval <= IBUS_9) {
472         guint page_no;
473         guint page_size;
474         guint cursor_pos;
475
476         page_size = ibus_lookup_table_get_page_size (hangul->table);
477         cursor_pos = ibus_lookup_table_get_cursor_pos (hangul->table);
478         page_no = cursor_pos / page_size;
479
480         cursor_pos = page_no * page_size + (keyval - IBUS_1);
481         ibus_lookup_table_set_cursor_pos (hangul->table, cursor_pos);
482
483         ibus_hangul_engine_commit_current_candidate (hangul);
484
485         if (hangul->hanja_mode) {
486             ibus_hangul_engine_update_lookup_table (hangul);
487         } else {
488             ibus_hangul_engine_hide_lookup_table (hangul);
489         }
490         return TRUE;
491     } else if (keyval == IBUS_Left) {
492         ibus_lookup_table_cursor_up (hangul->table);
493         ibus_hangul_engine_update_lookup_table_ui (hangul);
494         return TRUE;
495     } else if (keyval == IBUS_Right) {
496         ibus_lookup_table_cursor_down (hangul->table);
497         ibus_hangul_engine_update_lookup_table_ui (hangul);
498         return TRUE;
499     } else if (keyval == IBUS_Up) {
500         ibus_lookup_table_page_up (hangul->table);
501         ibus_hangul_engine_update_lookup_table_ui (hangul);
502         return TRUE;
503     } else if (keyval == IBUS_Down) {
504         ibus_lookup_table_page_down (hangul->table);
505         ibus_hangul_engine_update_lookup_table_ui (hangul);
506         return TRUE;
507     } else if (keyval == IBUS_Page_Up) {
508         ibus_lookup_table_page_up (hangul->table);
509         ibus_hangul_engine_update_lookup_table_ui (hangul);
510         return TRUE;
511     } else if (keyval == IBUS_Page_Down) {
512         ibus_lookup_table_page_down (hangul->table);
513         ibus_hangul_engine_update_lookup_table_ui (hangul);
514         return TRUE;
515     }
516
517     if (!hangul->hanja_mode) {
518         if (keyval == IBUS_h) {
519             ibus_lookup_table_cursor_up (hangul->table);
520             ibus_hangul_engine_update_lookup_table_ui (hangul);
521             return TRUE;
522         } else if (keyval == IBUS_l) {
523             ibus_lookup_table_cursor_down (hangul->table);
524             ibus_hangul_engine_update_lookup_table_ui (hangul);
525             return TRUE;
526         } else if (keyval == IBUS_k) {
527             ibus_lookup_table_page_up (hangul->table);
528             ibus_hangul_engine_update_lookup_table_ui (hangul);
529             return TRUE;
530         } else if (keyval == IBUS_j) {
531             ibus_lookup_table_page_down (hangul->table);
532             ibus_hangul_engine_update_lookup_table_ui (hangul);
533             return TRUE;
534         }
535     }
536
537     return FALSE;
538 }
539
540 static gboolean
541 ibus_hangul_engine_process_key_event (IBusEngine     *engine,
542                                       guint           keyval,
543                                       guint           keycode,
544                                       guint           modifiers)
545 {
546     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
547
548     gboolean retval;
549     const ucschar *str;
550
551     if (modifiers & IBUS_RELEASE_MASK)
552         return FALSE;
553
554     // if we don't ignore shift keys, shift key will make flush the preedit 
555     // string. So you cannot input shift+key.
556     // Let's think about these examples:
557     //   dlTek (2 set)
558     //   qhRdmaqkq (2 set)
559     if (keyval == IBUS_Shift_L || keyval == IBUS_Shift_R)
560         return FALSE;
561
562     if (keyval == IBUS_F9 || keyval == IBUS_Hangul_Hanja) {
563         if (hangul->hanja_list == NULL) {
564             ibus_hangul_engine_update_lookup_table (hangul);
565         } else {
566             ibus_hangul_engine_hide_lookup_table (hangul);
567         }
568         return TRUE;
569     }
570
571     if (modifiers & (IBUS_CONTROL_MASK | IBUS_MOD1_MASK))
572         return FALSE;
573
574     if (hangul->hanja_list != NULL) {
575         retval = ibus_hangul_engine_process_candidate_key_event (hangul,
576                      keyval, modifiers);
577         if (hangul->hanja_mode) {
578             if (retval)
579                 return TRUE;
580         } else {
581             return TRUE;
582         }
583     }
584
585     if (keyval == IBUS_BackSpace) {
586         retval = hangul_ic_backspace (hangul->context);
587     } else {
588         retval = hangul_ic_process (hangul->context, keyval);
589     }
590
591     str = hangul_ic_get_commit_string (hangul->context);
592     if (hangul->hanja_mode) {
593         const ucschar* hic_preedit;
594
595         hic_preedit = hangul_ic_get_preedit_string (hangul->context);
596         if (hic_preedit != NULL && hic_preedit[0] != 0) {
597             ustring_append_ucs4 (hangul->preedit, str, -1);
598         } else {
599             IBusText *text;
600             const ucschar* preedit;
601
602             ustring_append_ucs4 (hangul->preedit, str, -1);
603             if (ustring_length (hangul->preedit) > 0) {
604                 preedit = ustring_begin (hangul->preedit);
605                 text = ibus_text_new_from_ucs4 ((gunichar*)preedit);
606                 ibus_engine_commit_text (engine, text);
607                 g_object_unref (text);
608             }
609             ustring_clear (hangul->preedit);
610         }
611     } else {
612         if (str != NULL && str[0] != 0) {
613             IBusText *text = ibus_text_new_from_ucs4 (str);
614             ibus_engine_commit_text (engine, text);
615             g_object_unref (text);
616         }
617     }
618
619     ibus_hangul_engine_update_preedit_text (hangul);
620
621     if (hangul->hanja_mode) {
622         ibus_hangul_engine_update_lookup_table (hangul);
623     }
624
625     if (!retval)
626         ibus_hangul_engine_flush (hangul);
627
628     return retval;
629 }
630
631 static void
632 ibus_hangul_engine_flush (IBusHangulEngine *hangul)
633 {
634     const gunichar *str;
635     IBusText *text;
636
637     str = hangul_ic_flush (hangul->context);
638
639     if (str == NULL || str[0] == 0)
640         return;
641
642     text = ibus_text_new_from_ucs4 (str);
643
644     ibus_engine_hide_preedit_text ((IBusEngine *) hangul);
645     ibus_engine_commit_text ((IBusEngine *) hangul, text);
646
647     g_object_unref (text);
648 }
649
650 static void
651 ibus_hangul_engine_focus_in (IBusEngine *engine)
652 {
653     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
654
655     IBusText* label = NULL;
656     if (hangul->hanja_mode) {
657         label = ibus_text_new_from_static_string("漢");
658     } else {
659         label = ibus_text_new_from_static_string("韓");
660     }
661     ibus_property_set_label (hangul->prop_hanja_mode, label);
662     g_object_unref (label);
663
664     ibus_engine_register_properties (engine, hangul->prop_list);
665
666     if (hangul->hanja_list != NULL) {
667         ibus_hangul_engine_update_lookup_table_ui (hangul);
668     }
669
670     parent_class->focus_in (engine);
671 }
672
673 static void
674 ibus_hangul_engine_focus_out (IBusEngine *engine)
675 {
676     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
677
678     if (hangul->hanja_list == NULL) {
679         ibus_hangul_engine_flush (hangul);
680     } else {
681         ibus_engine_hide_lookup_table (engine);
682         ibus_engine_hide_auxiliary_text (engine);
683     }
684
685     parent_class->focus_out ((IBusEngine *) hangul);
686 }
687
688 static void
689 ibus_hangul_engine_reset (IBusEngine *engine)
690 {
691     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
692
693     ibus_hangul_engine_flush (hangul);
694     if (hangul->hanja_list != NULL) {
695         ibus_hangul_engine_hide_lookup_table (hangul);
696     }
697     parent_class->reset (engine);
698 }
699
700 static void
701 ibus_hangul_engine_enable (IBusEngine *engine)
702 {
703     parent_class->enable (engine);
704 }
705
706 static void
707 ibus_hangul_engine_disable (IBusEngine *engine)
708 {
709     ibus_hangul_engine_focus_out (engine);
710     parent_class->disable (engine);
711 }
712
713 static void
714 ibus_hangul_engine_page_up (IBusEngine *engine)
715 {
716     parent_class->page_up (engine);
717 }
718
719 static void
720 ibus_hangul_engine_page_down (IBusEngine *engine)
721 {
722     parent_class->page_down (engine);
723 }
724
725 static void
726 ibus_hangul_engine_cursor_up (IBusEngine *engine)
727 {
728     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
729
730     if (hangul->hanja_list != NULL) {
731         ibus_lookup_table_cursor_up (hangul->table);
732         ibus_hangul_engine_update_lookup_table_ui (hangul);
733     }
734
735     parent_class->cursor_up (engine);
736 }
737
738 static void
739 ibus_hangul_engine_cursor_down (IBusEngine *engine)
740 {
741     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
742
743     if (hangul->hanja_list != NULL) {
744         ibus_lookup_table_cursor_down (hangul->table);
745         ibus_hangul_engine_update_lookup_table_ui (hangul);
746     }
747
748     parent_class->cursor_down (engine);
749 }
750
751 static void
752 ibus_hangul_engine_property_activate (IBusEngine    *engine,
753                                       const gchar   *prop_name,
754                                       guint          prop_state)
755 {
756     if (strcmp(prop_name, "setup") == 0) {
757         GError *error = NULL;
758         gchar *argv[2] = { NULL, };
759         gchar *path;
760         const char* libexecdir;
761
762         libexecdir = g_getenv("LIBEXECDIR");
763         if (libexecdir == NULL)
764             libexecdir = LIBEXECDIR;
765
766         path = g_build_filename(libexecdir, "ibus-setup-hangul", NULL);
767         argv[0] = path;
768         argv[1] = NULL;
769         g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error);
770
771         g_free(path);
772     } else if (strcmp(prop_name, "hanja_mode") == 0) {
773         IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
774         IBusText *label;
775
776         hangul->hanja_mode = !hangul->hanja_mode;
777
778         if (hangul->hanja_mode) {
779             label = ibus_text_new_from_static_string("漢");
780             hangul->prop_hanja_mode->state = PROP_STATE_CHECKED;
781         } else {
782             label = ibus_text_new_from_static_string("韓");
783             hangul->prop_hanja_mode->state = PROP_STATE_UNCHECKED;
784         }
785
786         ibus_property_set_label (hangul->prop_hanja_mode, label);
787         ibus_engine_update_property (engine, hangul->prop_hanja_mode);
788         g_object_unref(label);
789     }
790 }
791
792 static void
793 ibus_config_value_changed (IBusConfig   *config,
794                            const gchar  *section,
795                            const gchar  *name,
796                            GValue       *value,
797                            gpointer      user_data)
798 {
799     IBusHangulEngine *hangul = (IBusHangulEngine *) user_data;
800
801     if (strcmp(section, "engine/Hangul") == 0) {
802         if (strcmp(name, "HangulKeyboard") == 0) {
803             const gchar *str = g_value_get_string (value);
804             g_string_assign (hangul_keyboard, str);
805             hangul_ic_select_keyboard (hangul->context, hangul_keyboard->str);
806         }
807     }
808 }
809
810 static void
811 lookup_table_set_visible (IBusLookupTable *table, gboolean flag)
812 {
813     g_object_set_data (G_OBJECT(table), "visible", GUINT_TO_POINTER(flag));
814 }
815
816 static gboolean
817 lookup_table_is_visible (IBusLookupTable *table)
818 {
819     gpointer res = g_object_get_data (G_OBJECT(table), "visible");
820     return GPOINTER_TO_UINT(res);
821 }