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