change hanja mode label
[platform/upstream/ibus-hangul.git] / src / engine.c
index 1658967..cdc19ce 100644 (file)
@@ -1,9 +1,16 @@
 /* vim:set et sts=4: */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 #include <ibus.h>
 #include <hangul.h>
 #include <string.h>
+
+#include "i18n.h"
 #include "engine.h"
+#include "ustring.h"
+
 
 typedef struct _IBusHangulEngine IBusHangulEngine;
 typedef struct _IBusHangulEngineClass IBusHangulEngineClass;
@@ -13,10 +20,15 @@ struct _IBusHangulEngine {
 
     /* members */
     HangulInputContext *context;
+    UString* preedit;
     gboolean hangul_mode;
+    gboolean hanja_mode;
+    HanjaList* hanja_list;
 
     IBusLookupTable *table;
+
     IBusProperty    *hangul_mode_prop;
+    IBusProperty    *prop_hanja_mode;
     IBusPropList    *prop_list;
 };
 
@@ -35,8 +47,9 @@ static void   ibus_hangul_engine_destroy              (IBusHangulEngine               *hangul);
 static gboolean
                        ibus_hangul_engine_process_key_event
                                             (IBusEngine             *engine,
-                                             guint                      keyval,
-                                             guint                      modifiers);
+                                             guint                   keyval,
+                                             guint                   keycode,
+                                             guint                   modifiers);
 static void ibus_hangul_engine_focus_in     (IBusEngine             *engine);
 static void ibus_hangul_engine_focus_out    (IBusEngine             *engine);
 static void ibus_hangul_engine_reset        (IBusEngine             *engine);
@@ -56,12 +69,11 @@ static void ibus_hangul_engine_page_up      (IBusEngine             *engine);
 static void ibus_hangul_engine_page_down    (IBusEngine             *engine);
 static void ibus_hangul_engine_cursor_up    (IBusEngine             *engine);
 static void ibus_hangul_engine_cursor_down  (IBusEngine             *engine);
-static void ibus_hangul_engine_toggle_hangul_mode
-                                            (IBusHangulEngine       *hangul);
-#if 0
-static void ibus_hangul_property_activate   (IBusEngine             *engine,
+static void ibus_hangul_engine_property_activate
+                                            (IBusEngine             *engine,
                                              const gchar            *prop_name,
-                                             gint                    prop_state);
+                                             guint                   prop_state);
+#if 0
 static void ibus_hangul_engine_property_show
                                                                                        (IBusEngine             *engine,
                                              const gchar            *prop_name);
@@ -74,7 +86,23 @@ static void ibus_hangul_engine_flush        (IBusHangulEngine       *hangul);
 static void ibus_hangul_engine_update_preedit_text
                                             (IBusHangulEngine       *hangul);
 
+static void ibus_hangul_engine_update_lookup_table
+                                           (IBusHangulEngine       *hangul);
+static void ibus_config_value_changed       (IBusConfig             *config,
+                                             const gchar            *section,
+                                             const gchar            *name,
+                                             GValue                 *value,
+                                             gpointer                user_data);
+
+static void    lookup_table_set_visible    (IBusLookupTable *table,
+                                            gboolean flag);
+static gboolean        lookup_table_is_visible     (IBusLookupTable *table);
+
 static IBusEngineClass *parent_class = NULL;
+static HanjaTable *hanja_table = NULL;
+static HanjaTable *symbol_table = NULL;
+static IBusConfig *config = NULL;
+static GString    *hangul_keyboard;
 
 GType
 ibus_hangul_engine_get_type (void)
@@ -103,6 +131,43 @@ ibus_hangul_engine_get_type (void)
        return type;
 }
 
+void
+ibus_hangul_init (IBusBus *bus)
+{
+    gboolean res;
+    GValue value = { 0, };
+
+    hanja_table = hanja_table_load (NULL);
+
+    symbol_table = hanja_table_load (IBUSHANGUL_DATADIR "/data/symbol.txt");
+
+    config = ibus_bus_get_config (bus);
+
+    hangul_keyboard = g_string_new_len ("2", 8);
+    res = ibus_config_get_value (config, "engine/Hangul",
+                                         "HangulKeyboard", &value);
+    if (res) {
+        const gchar* str = g_value_get_string (&value);
+        g_string_assign (hangul_keyboard, str);
+    }
+}
+
+void
+ibus_hangul_exit (void)
+{
+    hanja_table_delete (hanja_table);
+    hanja_table = NULL;
+
+    hanja_table_delete (symbol_table);
+    symbol_table = NULL;
+
+    g_object_unref (config);
+    config = NULL;
+
+    g_string_free (hangul_keyboard, TRUE);
+    hangul_keyboard = NULL;
+}
+
 static void
 ibus_hangul_engine_class_init (IBusHangulEngineClass *klass)
 {
@@ -129,27 +194,54 @@ ibus_hangul_engine_class_init (IBusHangulEngineClass *klass)
 
     engine_class->cursor_up = ibus_hangul_engine_cursor_up;
     engine_class->cursor_down = ibus_hangul_engine_cursor_down;
+
+    engine_class->property_activate = ibus_hangul_engine_property_activate;
 }
 
 static void
 ibus_hangul_engine_init (IBusHangulEngine *hangul)
 {
-    hangul->context = hangul_ic_new ("2");
+    IBusProperty* prop;
+    IBusText* label;
+    IBusText* tooltip;
+
+    hangul->context = hangul_ic_new (hangul_keyboard->str);
+    hangul->preedit = ustring_new();
+    hangul->hanja_list = NULL;
     hangul->hangul_mode = TRUE;
-    hangul->hangul_mode_prop = ibus_property_new ("hangul_mode_prop",
-                                           PROP_TYPE_NORMAL,
-                                           NULL,
-                                           NULL,
-                                           NULL,
-                                           TRUE,
-                                           FALSE,
-                                           0,
-                                           NULL);
+    hangul->hanja_mode = FALSE;
 
     hangul->prop_list = ibus_prop_list_new ();
-    ibus_prop_list_append (hangul->prop_list,  hangul->hangul_mode_prop);
 
-    hangul->table = ibus_lookup_table_new (9, 0, TRUE, TRUE);
+    label = ibus_text_new_from_string (_("Hanja lock"));
+    tooltip = ibus_text_new_from_string (_("Enable/Disable Hanja mode"));
+    prop = ibus_property_new ("hanja_mode",
+                              PROP_TYPE_TOGGLE,
+                              label,
+                             NULL,
+                              tooltip,
+                              TRUE, TRUE, PROP_STATE_UNCHECKED, NULL);
+    g_object_unref (label);
+    g_object_unref (tooltip);
+    ibus_prop_list_append (hangul->prop_list, prop);
+    hangul->prop_hanja_mode = prop;
+
+    label = ibus_text_new_from_string (_("Setup"));
+    tooltip = ibus_text_new_from_string (_("Configure hangul engine"));
+    prop = ibus_property_new ("setup",
+                              PROP_TYPE_NORMAL,
+                              label,
+                             "gtk-preferences",
+                              tooltip,
+                              TRUE, TRUE, PROP_STATE_UNCHECKED, NULL);
+    g_object_unref (label);
+    g_object_unref (tooltip);
+    ibus_prop_list_append (hangul->prop_list, prop);
+
+    hangul->table = ibus_lookup_table_new (9, 0, TRUE, FALSE);
+
+    g_signal_connect (config, "value-changed",
+                     G_CALLBACK(ibus_config_value_changed), hangul);
 }
 
 static GObject*
@@ -196,44 +288,314 @@ ibus_hangul_engine_destroy (IBusHangulEngine *hangul)
 static void
 ibus_hangul_engine_update_preedit_text (IBusHangulEngine *hangul)
 {
-    const gunichar *str;
+    const ucschar *hic_preedit;
     IBusText *text;
-
-    str = hangul_ic_get_preedit_string (hangul->context);
-
-    if (str != NULL && str[0] != 0) {
-        text = ibus_text_new_from_ucs4 (str);
-        ibus_text_append_attribute (text, IBUS_ATTR_TYPE_FOREGROUND, 0x00ffffff, 0, -1);
-        ibus_text_append_attribute (text, IBUS_ATTR_TYPE_BACKGROUND, 0x00000000, 0, -1);
+    UString *preedit;
+    gint preedit_len;
+
+    // ibus-hangul's preedit string is made up of ibus context's
+    // internal preedit string and libhangul's preedit string.
+    // libhangul only supports one syllable preedit string.
+    // In order to make longer preedit string, ibus-hangul maintains
+    // internal preedit string.
+    hic_preedit = hangul_ic_get_preedit_string (hangul->context);
+
+    preedit = ustring_dup (hangul->preedit);
+    preedit_len = ustring_length(preedit);
+    ustring_append_ucs4 (preedit, hic_preedit, -1);
+
+    if (ustring_length(preedit) > 0) {
+        text = ibus_text_new_from_ucs4 ((gunichar*)preedit->data);
+       // ibus-hangul's internal preedit string
+        ibus_text_append_attribute (text, IBUS_ATTR_TYPE_UNDERLINE,
+               IBUS_ATTR_UNDERLINE_SINGLE, 0, preedit_len);
+       // Preedit string from libhangul context.
+       // This is currently composing syllable.
+        ibus_text_append_attribute (text, IBUS_ATTR_TYPE_FOREGROUND,
+               0x00ffffff, preedit_len, -1);
+       ibus_text_append_attribute (text, IBUS_ATTR_TYPE_BACKGROUND,
+               0x00000000, preedit_len, -1);
         ibus_engine_update_preedit_text ((IBusEngine *)hangul,
                                          text,
                                          ibus_text_get_length (text),
                                          TRUE);
         g_object_unref (text);
-    }
-    else {
+    } else {
         text = ibus_text_new_from_static_string ("");
         ibus_engine_update_preedit_text ((IBusEngine *)hangul, text, 0, FALSE);
         g_object_unref (text);
     }
+
+    ustring_delete(preedit);
+}
+
+static void
+ibus_hangul_engine_update_lookup_table_ui (IBusHangulEngine *hangul)
+{
+    guint cursor_pos;
+    const char* comment;
+    IBusText* text;
+
+    // update aux text
+    cursor_pos = ibus_lookup_table_get_cursor_pos (hangul->table);
+    comment = hanja_list_get_nth_comment (hangul->hanja_list, cursor_pos);
+
+    text = ibus_text_new_from_string (comment);
+    ibus_engine_update_auxiliary_text ((IBusEngine *)hangul, text, TRUE);
+    g_object_unref (text);
+
+    // update lookup table
+    ibus_engine_update_lookup_table ((IBusEngine *)hangul, hangul->table, TRUE);
+}
+
+static void
+ibus_hangul_engine_commit_current_candidate (IBusHangulEngine *hangul)
+{
+    guint cursor_pos;
+    const char* key;
+    const char* value;
+    int key_len;
+    int preedit_len;
+    int len;
+
+    IBusText* text;
+
+    cursor_pos = ibus_lookup_table_get_cursor_pos (hangul->table);
+    key = hanja_list_get_nth_key (hangul->hanja_list, cursor_pos);
+    value = hanja_list_get_nth_value (hangul->hanja_list, cursor_pos);
+
+    key_len = g_utf8_strlen(key, -1);
+    preedit_len = ustring_length(hangul->preedit);
+
+    len = MIN(key_len, preedit_len);
+    ustring_erase (hangul->preedit, 0, len);
+    if (key_len > preedit_len)
+       hangul_ic_reset (hangul->context);
+
+    ibus_hangul_engine_update_preedit_text (hangul);
+
+    text = ibus_text_new_from_string (value);
+    ibus_engine_commit_text ((IBusEngine *)hangul, text);
+    g_object_unref (text);
+}
+
+static void
+ibus_hangul_engine_update_hanja_list (IBusHangulEngine *hangul)
+{
+    char* utf8;
+    const ucschar* hic_preedit;
+    UString* preedit;
+
+    if (hangul->hanja_list != NULL) {
+       hanja_list_delete (hangul->hanja_list);
+       hangul->hanja_list = NULL;
+    }
+
+    hic_preedit = hangul_ic_get_preedit_string (hangul->context);
+
+    preedit = ustring_dup (hangul->preedit);
+    ustring_append_ucs4 (preedit, hic_preedit, -1);
+    if (ustring_length(preedit) > 0) {
+       utf8 = ustring_to_utf8 (preedit, -1);
+       if (utf8 != NULL) {
+           if (symbol_table != NULL)
+               hangul->hanja_list = hanja_table_match_prefix (symbol_table, utf8);
+           if (hangul->hanja_list == NULL)
+               hangul->hanja_list = hanja_table_match_prefix (hanja_table, utf8);
+           g_free (utf8);
+       }
+    }
+
+    ustring_delete (preedit);
+}
+
+
+static void
+ibus_hangul_engine_apply_hanja_list (IBusHangulEngine *hangul)
+{
+    HanjaList* list = hangul->hanja_list;
+    if (list != NULL) {
+       int i, n;
+       n = hanja_list_get_size (list);
+
+       ibus_lookup_table_clear (hangul->table);
+       for (i = 0; i < n; i++) {
+           const char* value = hanja_list_get_nth_value (list, i);
+           IBusText* text = ibus_text_new_from_string (value);
+           ibus_lookup_table_append_candidate (hangul->table, text);
+           g_object_unref (text);
+       }
+
+       ibus_lookup_table_set_cursor_pos (hangul->table, 0);
+       ibus_hangul_engine_update_lookup_table_ui (hangul);
+       lookup_table_set_visible (hangul->table, TRUE);
+    }
+}
+
+static void
+ibus_hangul_engine_hide_lookup_table (IBusHangulEngine *hangul)
+{
+    gboolean is_visible;
+    is_visible = lookup_table_is_visible (hangul->table);
+
+    // Sending hide lookup table message when the lookup table
+    // is not visible results wrong behavior. So I have to check
+    // whether the table is visible or not before to hide.
+    if (is_visible) {
+       ibus_engine_hide_lookup_table ((IBusEngine *)hangul);
+       ibus_engine_hide_auxiliary_text ((IBusEngine *)hangul);
+       lookup_table_set_visible (hangul->table, FALSE);
+    }
+
+    if (hangul->hanja_list != NULL) {
+       hanja_list_delete (hangul->hanja_list);
+       hangul->hanja_list = NULL;
+    }
+}
+
+static void
+ibus_hangul_engine_update_lookup_table (IBusHangulEngine *hangul)
+{
+    ibus_hangul_engine_update_hanja_list (hangul);
+
+    if (hangul->hanja_list != NULL) {
+        ibus_hangul_engine_apply_hanja_list (hangul);
+    } else {
+        ibus_hangul_engine_hide_lookup_table (hangul);
+    }
+}
+
+static gboolean
+ibus_hangul_engine_process_candidate_key_event (IBusHangulEngine    *hangul,
+                                                guint                keyval,
+                                                guint                modifiers)
+{
+    if (keyval == IBUS_Escape) {
+        ibus_hangul_engine_hide_lookup_table (hangul);
+       return TRUE;
+    } else if (keyval == IBUS_Return) {
+       ibus_hangul_engine_commit_current_candidate (hangul);
+
+       if (hangul->hanja_mode) {
+           ibus_hangul_engine_update_lookup_table (hangul);
+       } else {
+           ibus_hangul_engine_hide_lookup_table (hangul);
+       }
+       return TRUE;
+    } else if (keyval >= IBUS_1 && keyval <= IBUS_9) {
+       guint page_no;
+       guint page_size;
+       guint cursor_pos;
+
+       page_size = ibus_lookup_table_get_page_size (hangul->table);
+       cursor_pos = ibus_lookup_table_get_cursor_pos (hangul->table);
+       page_no = cursor_pos / page_size;
+
+       cursor_pos = page_no * page_size + (keyval - IBUS_1);
+       ibus_lookup_table_set_cursor_pos (hangul->table, cursor_pos);
+
+       ibus_hangul_engine_commit_current_candidate (hangul);
+
+       if (hangul->hanja_mode) {
+           ibus_hangul_engine_update_lookup_table (hangul);
+       } else {
+           ibus_hangul_engine_hide_lookup_table (hangul);
+       }
+       return TRUE;
+    } else if (keyval == IBUS_Left) {
+        ibus_lookup_table_cursor_up (hangul->table);
+        ibus_hangul_engine_update_lookup_table_ui (hangul);
+       return TRUE;
+    } else if (keyval == IBUS_Right) {
+        ibus_lookup_table_cursor_down (hangul->table);
+        ibus_hangul_engine_update_lookup_table_ui (hangul);
+       return TRUE;
+    } else if (keyval == IBUS_Up) {
+        ibus_lookup_table_page_up (hangul->table);
+        ibus_hangul_engine_update_lookup_table_ui (hangul);
+       return TRUE;
+    } else if (keyval == IBUS_Down) {
+        ibus_lookup_table_page_down (hangul->table);
+        ibus_hangul_engine_update_lookup_table_ui (hangul);
+       return TRUE;
+    } else if (keyval == IBUS_Page_Up) {
+        ibus_lookup_table_page_up (hangul->table);
+        ibus_hangul_engine_update_lookup_table_ui (hangul);
+       return TRUE;
+    } else if (keyval == IBUS_Page_Down) {
+        ibus_lookup_table_page_down (hangul->table);
+        ibus_hangul_engine_update_lookup_table_ui (hangul);
+       return TRUE;
+    }
+
+    if (!hangul->hanja_mode) {
+       if (keyval == IBUS_h) {
+           ibus_lookup_table_cursor_up (hangul->table);
+           ibus_hangul_engine_update_lookup_table_ui (hangul);
+           return TRUE;
+       } else if (keyval == IBUS_l) {
+           ibus_lookup_table_cursor_down (hangul->table);
+           ibus_hangul_engine_update_lookup_table_ui (hangul);
+           return TRUE;
+       } else if (keyval == IBUS_k) {
+           ibus_lookup_table_page_up (hangul->table);
+           ibus_hangul_engine_update_lookup_table_ui (hangul);
+           return TRUE;
+       } else if (keyval == IBUS_j) {
+           ibus_lookup_table_page_down (hangul->table);
+           ibus_hangul_engine_update_lookup_table_ui (hangul);
+           return TRUE;
+       }
+    }
+
+    return FALSE;
 }
 
 static gboolean
 ibus_hangul_engine_process_key_event (IBusEngine     *engine,
                                       guint           keyval,
+                                      guint           keycode,
                                       guint           modifiers)
 {
     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
 
     gboolean retval;
-    const gunichar *str;
+    const ucschar *str;
 
     if (modifiers & IBUS_RELEASE_MASK)
         return FALSE;
 
+    // if we don't ignore shift keys, shift key will make flush the preedit 
+    // string. So you cannot input shift+key.
+    // Let's think about these examples:
+    //   dlTek (2 set)
+    //   qhRdmaqkq (2 set)
+    if (keyval == IBUS_Shift_L || keyval == IBUS_Shift_R)
+        return FALSE;
+
+    if (keyval == IBUS_F9 || keyval == IBUS_Hangul_Hanja) {
+       if (hangul->hanja_list == NULL) {
+           ibus_hangul_engine_update_lookup_table (hangul);
+       } else {
+           ibus_hangul_engine_hide_lookup_table (hangul);
+       }
+       return TRUE;
+    }
+
     if (modifiers & (IBUS_CONTROL_MASK | IBUS_MOD1_MASK))
         return FALSE;
 
+    if (hangul->hanja_list != NULL) {
+       retval = ibus_hangul_engine_process_candidate_key_event (hangul,
+                    keyval, modifiers);
+       if (hangul->hanja_mode) {
+           if (retval)
+               return TRUE;
+       } else {
+           return TRUE;
+       }
+    }
+
     if (keyval == IBUS_BackSpace) {
         retval = hangul_ic_backspace (hangul->context);
     } else {
@@ -241,14 +603,39 @@ ibus_hangul_engine_process_key_event (IBusEngine     *engine,
     }
 
     str = hangul_ic_get_commit_string (hangul->context);
-    if (str != NULL && str[0] != 0) {
-        IBusText *text = ibus_text_new_from_ucs4 (str);
-        ibus_engine_commit_text ((IBusEngine *)hangul, text);
-        g_object_unref (text);
+    if (hangul->hanja_mode) {
+       const ucschar* hic_preedit;
+
+       hic_preedit = hangul_ic_get_preedit_string (hangul->context);
+       if (hic_preedit != NULL && hic_preedit[0] != 0) {
+           ustring_append_ucs4 (hangul->preedit, str, -1);
+       } else {
+           IBusText *text;
+           const ucschar* preedit;
+
+           ustring_append_ucs4 (hangul->preedit, str, -1);
+           if (ustring_length (hangul->preedit) > 0) {
+               preedit = ustring_begin (hangul->preedit);
+               text = ibus_text_new_from_ucs4 ((gunichar*)preedit);
+               ibus_engine_commit_text (engine, text);
+               g_object_unref (text);
+           }
+           ustring_clear (hangul->preedit);
+       }
+    } else {
+       if (str != NULL && str[0] != 0) {
+           IBusText *text = ibus_text_new_from_ucs4 (str);
+           ibus_engine_commit_text (engine, text);
+           g_object_unref (text);
+       }
     }
 
     ibus_hangul_engine_update_preedit_text (hangul);
 
+    if (hangul->hanja_mode) {
+       ibus_hangul_engine_update_lookup_table (hangul);
+    }
+
     if (!retval)
         ibus_hangul_engine_flush (hangul);
 
@@ -275,32 +662,22 @@ ibus_hangul_engine_flush (IBusHangulEngine *hangul)
 }
 
 static void
-ibus_hangul_engine_toggle_hangul_mode (IBusHangulEngine *hangul)
-{
-    IBusText *text;
-    hangul->hangul_mode = ! hangul->hangul_mode;
-
-    ibus_hangul_engine_flush (hangul);
-
-    if (hangul->hangul_mode) {
-        text = ibus_text_new_from_static_string ("한");
-    }
-    else {
-        text = ibus_text_new_from_static_string ("A");
-    }
-
-    ibus_property_set_label (hangul->hangul_mode_prop, text);
-    ibus_engine_update_property ((IBusEngine *)hangul, hangul->hangul_mode_prop);
-    g_object_unref (text);
-}
-
-static void
 ibus_hangul_engine_focus_in (IBusEngine *engine)
 {
     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
 
+    if (hangul->hanja_mode) {
+       hangul->prop_hanja_mode->state = PROP_STATE_CHECKED;
+    } else {
+       hangul->prop_hanja_mode->state = PROP_STATE_UNCHECKED;
+    }
+
     ibus_engine_register_properties (engine, hangul->prop_list);
 
+    if (hangul->hanja_list != NULL) {
+        ibus_hangul_engine_update_lookup_table_ui (hangul);
+    }
+
     parent_class->focus_in (engine);
 }
 
@@ -309,7 +686,12 @@ ibus_hangul_engine_focus_out (IBusEngine *engine)
 {
     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
 
-    ibus_hangul_engine_flush (hangul);
+    if (hangul->hanja_list == NULL) {
+       ibus_hangul_engine_flush (hangul);
+    } else {
+       ibus_engine_hide_lookup_table (engine);
+       ibus_engine_hide_auxiliary_text (engine);
+    }
 
     parent_class->focus_out ((IBusEngine *) hangul);
 }
@@ -320,6 +702,9 @@ ibus_hangul_engine_reset (IBusEngine *engine)
     IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
 
     ibus_hangul_engine_flush (hangul);
+    if (hangul->hanja_list != NULL) {
+        ibus_hangul_engine_hide_lookup_table (hangul);
+    }
     parent_class->reset (engine);
 }
 
@@ -351,12 +736,91 @@ ibus_hangul_engine_page_down (IBusEngine *engine)
 static void
 ibus_hangul_engine_cursor_up (IBusEngine *engine)
 {
+    IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
+
+    if (hangul->hanja_list != NULL) {
+       ibus_lookup_table_cursor_up (hangul->table);
+       ibus_hangul_engine_update_lookup_table_ui (hangul);
+    }
+
     parent_class->cursor_up (engine);
 }
 
 static void
 ibus_hangul_engine_cursor_down (IBusEngine *engine)
 {
+    IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
+
+    if (hangul->hanja_list != NULL) {
+       ibus_lookup_table_cursor_down (hangul->table);
+       ibus_hangul_engine_update_lookup_table_ui (hangul);
+    }
+
     parent_class->cursor_down (engine);
 }
 
+static void
+ibus_hangul_engine_property_activate (IBusEngine    *engine,
+                                      const gchar   *prop_name,
+                                      guint          prop_state)
+{
+    if (strcmp(prop_name, "setup") == 0) {
+        GError *error = NULL;
+        gchar *argv[2] = { NULL, };
+       gchar *path;
+       const char* libexecdir;
+
+       libexecdir = g_getenv("LIBEXECDIR");
+       if (libexecdir == NULL)
+           libexecdir = LIBEXECDIR;
+
+       path = g_build_filename(libexecdir, "ibus-setup-hangul", NULL);
+       argv[0] = path;
+       argv[1] = NULL;
+        g_spawn_async (NULL, argv, NULL, 0, NULL, NULL, NULL, &error);
+
+       g_free(path);
+    } else if (strcmp(prop_name, "hanja_mode") == 0) {
+       IBusHangulEngine *hangul = (IBusHangulEngine *) engine;
+
+       hangul->hanja_mode = !hangul->hanja_mode;
+       if (hangul->hanja_mode) {
+           hangul->prop_hanja_mode->state = PROP_STATE_CHECKED;
+       } else {
+           hangul->prop_hanja_mode->state = PROP_STATE_UNCHECKED;
+       }
+
+       ibus_engine_update_property (engine, hangul->prop_hanja_mode);
+    }
+}
+
+static void
+ibus_config_value_changed (IBusConfig   *config,
+                           const gchar  *section,
+                           const gchar  *name,
+                           GValue       *value,
+                           gpointer      user_data)
+{
+    IBusHangulEngine *hangul = (IBusHangulEngine *) user_data;
+
+    if (strcmp(section, "engine/Hangul") == 0) {
+        if (strcmp(name, "HangulKeyboard") == 0) {
+            const gchar *str = g_value_get_string (value);
+            g_string_assign (hangul_keyboard, str);
+            hangul_ic_select_keyboard (hangul->context, hangul_keyboard->str);
+        }
+    }
+}
+
+static void
+lookup_table_set_visible (IBusLookupTable *table, gboolean flag)
+{
+    g_object_set_data (G_OBJECT(table), "visible", GUINT_TO_POINTER(flag));
+}
+
+static gboolean
+lookup_table_is_visible (IBusLookupTable *table)
+{
+    gpointer res = g_object_get_data (G_OBJECT(table), "visible");
+    return GPOINTER_TO_UINT(res);
+}