63b857f
From 7f81445b3e6613d14f64253506a309095a37c8d7 Mon Sep 17 00:00:00 2001
8a795bf
From: fujiwarat <takao.fujiwara1@gmail.com>
63b857f
Date: Mon, 20 Jun 2011 19:04:42 +0900
8a795bf
Subject: [PATCH] Reload preload engines until users customize the list.
8a795bf
8a795bf
The idea is, if users don't customize the preload_engines with ibus-setup,
8a795bf
users would prefer to load the system default engines again by login.
8a795bf
The gconf value 'preload_engine_mode' is
63b857f
IBUS_PRELOAD_ENGINE_MODE_USER by default but set
63b857f
IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE for the initial login.
8a795bf
If preload_engine_mode is IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE,
8a795bf
ibus-daemon loads the system preload engines by langs.
8a795bf
If preload_engine_mode is IBUS_PRELOAD_ENGINE_MODE_USER,
8a795bf
ibus-daemon do not update the gconf value preload_engines.
8a795bf
On the other hand, if users enable the customized engine checkbutton
8a795bf
on ibus-setup, ibus-setup sets 'preload_engine_mode' as
8a795bf
IBUS_PRELOAD_ENGINE_MODE_USER and users can customize the value
8a795bf
'preload_engines'.
8a795bf
---
63b857f
 bus/ibusimpl.c       |  402 +++++++++++++++++++++++++++++++++++++++-----------
63b857f
 data/ibus.schemas.in |   13 ++
9d6bb4f
 ibus/common.py       |    6 +
63b857f
 setup/main.py        |   70 ++++++++-
9d6bb4f
 setup/setup.ui       |   21 +++-
3b5789d
 src/ibustypes.h      |   10 ++
63b857f
 6 files changed, 427 insertions(+), 95 deletions(-)
8a795bf
8a795bf
diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c
63b857f
index a7ae52b..bb4b8ae 100644
8a795bf
--- a/bus/ibusimpl.c
8a795bf
+++ b/bus/ibusimpl.c
63b857f
@@ -144,6 +144,9 @@ static void     bus_ibus_impl_set_previous_engine
8a795bf
 static void     bus_ibus_impl_set_preload_engines
8a795bf
                                                 (BusIBusImpl        *ibus,
8a795bf
                                                  GVariant           *value);
8a795bf
+static void     bus_ibus_impl_set_preload_engine_mode
8a795bf
+                                                (BusIBusImpl        *ibus,
8a795bf
+                                                 GVariant           *value);
8a795bf
 static void     bus_ibus_impl_set_use_sys_layout
8a795bf
                                                 (BusIBusImpl        *ibus,
8a795bf
                                                  GVariant           *value);
63b857f
@@ -285,6 +288,259 @@ _panel_destroy_cb (BusPanelProxy *panel,
8a795bf
 }
8a795bf
 
63b857f
 static void
63b857f
+_config_set_value_done (GObject      *object,
63b857f
+                        GAsyncResult *res,
63b857f
+                        gpointer      user_data)
63b857f
+{
63b857f
+    IBusConfig *config = (IBusConfig *) object;
63b857f
+    GVariant *value = (GVariant *) user_data;
63b857f
+    GError *error = NULL;
63b857f
+
63b857f
+    g_assert (IBUS_IS_CONFIG (config));
63b857f
+
63b857f
+    if (!ibus_config_set_value_async_finish (config, res, &error)) {
63b857f
+        if (error) {
63b857f
+            g_error_free (error);
63b857f
+        }
63b857f
+    }
63b857f
+    g_variant_unref (value);
63b857f
+}
63b857f
+
9d6bb4f
+#ifndef OS_CHROMEOS
3b5789d
+static gint
3b5789d
+_engine_desc_cmp (IBusEngineDesc *desc1,
3b5789d
+                  IBusEngineDesc *desc2)
8a795bf
+{
3b5789d
+    return - ((gint) ibus_engine_desc_get_rank (desc1)) +
3b5789d
+              ((gint) ibus_engine_desc_get_rank (desc2));
3b5789d
+}
9d6bb4f
+#endif
8a795bf
+
9d6bb4f
+#ifndef OS_CHROMEOS
3b5789d
+static gint
3b5789d
+_get_config_preload_engine_mode (BusIBusImpl *ibus)
3b5789d
+{
3b5789d
+    GVariant *variant = NULL;
63b857f
+    gint preload_engine_mode = IBUS_PRELOAD_ENGINE_MODE_USER;
3b5789d
+
3b5789d
+    g_assert (BUS_IS_IBUS_IMPL (ibus));
3b5789d
+
3b5789d
+    if (ibus->config == NULL) {
3b5789d
+        return preload_engine_mode;
8a795bf
+    }
8a795bf
+
3b5789d
+    variant = ibus_config_get_value (ibus->config, "general",
63b857f
+                                     "preload_engines");
63b857f
+    if (variant == NULL) {
63b857f
+        /* Set LANG_RELATIVE mode for the initial login */
63b857f
+        preload_engine_mode = IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE;
63b857f
+        variant = g_variant_ref_sink (g_variant_new ("i", preload_engine_mode));
63b857f
+        ibus_config_set_value_async (ibus->config, "general",
63b857f
+                                     "preload_engine_mode", variant,
63b857f
+                                     -1,
63b857f
+                                     NULL,
63b857f
+                                     _config_set_value_done,
63b857f
+                                     variant);
63b857f
+        return preload_engine_mode;
63b857f
+    } else {
63b857f
+        g_variant_unref (variant);
63b857f
+    }
63b857f
+
63b857f
+    variant = ibus_config_get_value (ibus->config, "general",
3b5789d
+                                     "preload_engine_mode");
3b5789d
+    if (variant != NULL) {
3b5789d
+        if (g_variant_classify (variant) == G_VARIANT_CLASS_INT32) {
3b5789d
+            preload_engine_mode = g_variant_get_int32 (variant);
3b5789d
+        }
3b5789d
+        g_variant_unref (variant);
8a795bf
+    }
8a795bf
+
3b5789d
+    return preload_engine_mode;
8a795bf
+}
9d6bb4f
+#endif
8a795bf
+
63b857f
+static int
63b857f
+_compare_engine_list_value (GVariant *value_a, GVariant *value_b)
63b857f
+{
63b857f
+    GVariant *value;
63b857f
+    GVariantIter iter;
63b857f
+    const gchar *engine_name = NULL;
63b857f
+    gchar *concat_engine_names;
63b857f
+    gchar *concat_engine_names_a = NULL;
63b857f
+    gchar *concat_engine_names_b = NULL;
63b857f
+    int retval = 0;
63b857f
+
63b857f
+    value = value_a;
63b857f
+    concat_engine_names = NULL;
63b857f
+    if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_ARRAY) {
63b857f
+        g_variant_iter_init (&iter, value);
63b857f
+        while (g_variant_iter_loop (&iter, "&s", &engine_name)) {
63b857f
+            gchar *tmp = g_strdup_printf ("%s::%s",
63b857f
+                                          concat_engine_names ? concat_engine_names : "",
63b857f
+                                          engine_name ? engine_name : "");
63b857f
+            g_free (concat_engine_names);
63b857f
+            concat_engine_names = tmp;
63b857f
+        }
63b857f
+    }
63b857f
+    concat_engine_names_a = concat_engine_names;
63b857f
+
63b857f
+    value = value_b;
63b857f
+    concat_engine_names = NULL;
63b857f
+    if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_ARRAY) {
63b857f
+        g_variant_iter_init (&iter, value);
63b857f
+        while (g_variant_iter_loop (&iter, "&s", &engine_name)) {
63b857f
+            gchar *tmp = g_strdup_printf ("%s::%s",
63b857f
+                                          concat_engine_names ? concat_engine_names : "",
63b857f
+                                          engine_name ? engine_name : "");
63b857f
+            g_free (concat_engine_names);
63b857f
+            concat_engine_names = tmp;
63b857f
+        }
63b857f
+    }
63b857f
+    concat_engine_names_b = concat_engine_names;
63b857f
+
63b857f
+    retval = g_strcmp0 (concat_engine_names_a, concat_engine_names_b);
63b857f
+    g_free (concat_engine_names_a);
63b857f
+    g_free (concat_engine_names_b);
63b857f
+    return retval;
63b857f
+}
63b857f
+
63b857f
+static void
63b857f
+_preload_engines_config_get_value_done (GObject      *object,
63b857f
+                                        GAsyncResult *res,
63b857f
+                                        gpointer      user_data)
63b857f
+{
63b857f
+    IBusConfig *config = (IBusConfig *) object;
63b857f
+    GVariant *new_value = (GVariant *) user_data;
63b857f
+    GVariant *value = NULL;
63b857f
+    GError *error = NULL;
63b857f
+
63b857f
+    g_assert (IBUS_IS_CONFIG (config));
63b857f
+
63b857f
+    value = ibus_config_get_value_async_finish (config, res, &error);
63b857f
+    if (error) {
63b857f
+        g_error_free (error);
63b857f
+    }
63b857f
+    if (_compare_engine_list_value (value, new_value) != 0) {
63b857f
+        ibus_config_set_value_async (config, "general",
63b857f
+                                     "preload_engines", new_value,
63b857f
+                                     -1,
63b857f
+                                     NULL,
63b857f
+                                     _config_set_value_done,
63b857f
+                                     new_value);
63b857f
+    } else if (new_value) {
63b857f
+        g_variant_unref (new_value);
63b857f
+    }
63b857f
+    if (value) {
63b857f
+        g_variant_unref (value);
63b857f
+    }
63b857f
+}
63b857f
+
8a795bf
+static void
3b5789d
+_set_preload_engines (BusIBusImpl *ibus,
3b5789d
+                      GVariant    *value)
3b5789d
+{
3b5789d
+    GList *engine_list = NULL;
3b5789d
+
3b5789d
+    g_assert (BUS_IS_IBUS_IMPL (ibus));
3b5789d
+
3b5789d
+    g_list_foreach (ibus->engine_list, (GFunc) g_object_unref, NULL);
3b5789d
+    g_list_free (ibus->engine_list);
3b5789d
+
3b5789d
+    if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_ARRAY) {
3b5789d
+        GVariantIter iter;
3b5789d
+        g_variant_iter_init (&iter, value);
3b5789d
+        const gchar *engine_name = NULL;
3b5789d
+        while (g_variant_iter_loop (&iter, "&s", &engine_name)) {
3b5789d
+            IBusEngineDesc *engine = bus_registry_find_engine_by_name (ibus->registry, engine_name);
3b5789d
+            if (engine == NULL || g_list_find (engine_list, engine) != NULL)
3b5789d
+                continue;
3b5789d
+            engine_list = g_list_append (engine_list, engine);
3b5789d
+        }
3b5789d
+
3b5789d
+        if (engine_list != NULL &&
63b857f
+            ibus->config != NULL) {
63b857f
+            /* sync function will effects the startup performance.
63b857f
+             * We'd always like to save the value so that ibus-setup
63b857f
+             * get the updated engine list. */
63b857f
+            ibus_config_get_value_async (ibus->config, "general",
63b857f
+                                         "preload_engines",
63b857f
+                                         -1,
63b857f
+                                         NULL,
63b857f
+                                         _preload_engines_config_get_value_done,
63b857f
+                                         g_variant_ref_sink (value));
9d6bb4f
+        } else {
9d6bb4f
+            /* We don't update preload_engines with an empty string for safety.
9d6bb4f
+             * Just unref the floating value. */
9d6bb4f
+            g_variant_unref (value);
3b5789d
+        }
9d6bb4f
+    } else if (value != NULL) {
9d6bb4f
+        g_variant_unref (value);
3b5789d
+    }
3b5789d
+
3b5789d
+    g_list_foreach (engine_list, (GFunc) g_object_ref, NULL);
3b5789d
+    ibus->engine_list = engine_list;
3b5789d
+
3b5789d
+    if (ibus->engine_list) {
3b5789d
+        BusComponent *component = bus_component_from_engine_desc ((IBusEngineDesc *) ibus->engine_list->data);
3b5789d
+        if (component && !bus_component_is_running (component)) {
3b5789d
+            bus_component_start (component, g_verbose);
3b5789d
+        }
3b5789d
+    }
3b5789d
+
48fb145
+    bus_ibus_impl_check_global_engine (ibus);
3b5789d
+    bus_ibus_impl_update_engines_hotkey_profile (ibus);
3b5789d
+}
3b5789d
+
9d6bb4f
+#ifndef OS_CHROMEOS
3b5789d
+static void
3b5789d
+_set_language_relative_preload_engines (BusIBusImpl *ibus)
3b5789d
+{
3b5789d
+    gchar *lang = NULL;
3b5789d
+    gchar *p = NULL;
3b5789d
+    GList *engines = NULL;
3b5789d
+    GList *list;
3b5789d
+    GVariantBuilder builder;
3b5789d
+
3b5789d
+    g_assert (BUS_IS_IBUS_IMPL (ibus));
3b5789d
+
9d6bb4f
+    /* The setlocale call first checks LC_ALL. If it's not available, checks
9d6bb4f
+     * LC_CTYPE. If it's also not available, checks LANG. */
38194cc
+    lang = g_strdup (setlocale (LC_CTYPE, NULL));
38194cc
+    if (lang == NULL) {
38194cc
+        return;
38194cc
+    }
9d6bb4f
+
3b5789d
+    p = index (lang, '.');
3b5789d
+    if (p) {
3b5789d
+        *p = '\0';
3b5789d
+    }
3b5789d
+
3b5789d
+    engines = bus_registry_get_engines_by_language (ibus->registry, lang);
3b5789d
+    if (engines == NULL) {
3b5789d
+        p = index (lang, '_');
3b5789d
+        if (p) {
3b5789d
+            *p = '\0';
3b5789d
+            engines = bus_registry_get_engines_by_language (ibus->registry, lang);
3b5789d
+        }
3b5789d
+    }
3b5789d
+    g_free (lang);
3b5789d
+
3b5789d
+    /* sort engines by rank */
3b5789d
+    engines = g_list_sort (engines, (GCompareFunc) _engine_desc_cmp);
3b5789d
+
3b5789d
+    g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
3b5789d
+    for (list = engines; list != NULL; list = list->next) {
3b5789d
+        IBusEngineDesc *desc = (IBusEngineDesc *)list->data;
3b5789d
+        /* ignore engines with rank <== 0 */
3b5789d
+        if (ibus_engine_desc_get_rank (desc) > 0)
3b5789d
+            g_variant_builder_add (&builder, "s", ibus_engine_desc_get_name (desc));
3b5789d
+    }
3b5789d
+    _set_preload_engines (ibus, g_variant_builder_end (&builder));
3b5789d
+    g_list_free (engines);
3b5789d
+}
9d6bb4f
+#endif
3b5789d
+
63b857f
+static void
3b5789d
 bus_ibus_impl_set_hotkey (BusIBusImpl *ibus,
3b5789d
                           GQuark       hotkey,
63b857f
                           GVariant    *value)
63b857f
@@ -394,35 +650,50 @@ static void
3b5789d
 bus_ibus_impl_set_preload_engines (BusIBusImpl *ibus,
3b5789d
                                    GVariant    *value)
8a795bf
 {
3b5789d
-    GList *engine_list = NULL;
9d6bb4f
-
069aa90
-    g_list_foreach (ibus->engine_list, (GFunc) g_object_unref, NULL);
069aa90
-    g_list_free (ibus->engine_list);
9d6bb4f
+#ifndef OS_CHROMEOS
9d6bb4f
+    gint preload_engine_mode = _get_config_preload_engine_mode (ibus);
9d6bb4f
 
3b5789d
-    if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_ARRAY) {
3b5789d
-        GVariantIter iter;
3b5789d
-        g_variant_iter_init (&iter, value);
3b5789d
-        const gchar *engine_name = NULL;
3b5789d
-        while (g_variant_iter_loop (&iter, "&s", &engine_name)) {
3b5789d
-            IBusEngineDesc *engine = bus_registry_find_engine_by_name (ibus->registry, engine_name);
3b5789d
-            if (engine == NULL || g_list_find (engine_list, engine) != NULL)
3b5789d
-                continue;
3b5789d
-            engine_list = g_list_append (engine_list, engine);
3b5789d
+    if (preload_engine_mode == IBUS_PRELOAD_ENGINE_MODE_USER) {
3b5789d
+        if (value == NULL) {
3b5789d
+            _set_language_relative_preload_engines (ibus);
3b5789d
+        } else {
3b5789d
+            _set_preload_engines (ibus, value);
3b5789d
         }
3b5789d
     }
9d6bb4f
+#else
9d6bb4f
+    _set_preload_engines (ibus, value);
9d6bb4f
+#endif
3b5789d
+}
3b5789d
 
3b5789d
-    g_list_foreach (engine_list, (GFunc) g_object_ref, NULL);
3b5789d
-    ibus->engine_list = engine_list;
9d6bb4f
+/**
9d6bb4f
+ * bus_ibus_impl_set_preload_engine_mode:
9d6bb4f
+ *
63b857f
+ * A function to be called when "preload_engine_mode" config is updated.
9d6bb4f
+ */
3b5789d
+static void
3b5789d
+bus_ibus_impl_set_preload_engine_mode (BusIBusImpl *ibus,
3b5789d
+                                       GVariant    *value)
3b5789d
+{
9d6bb4f
+#ifndef OS_CHROMEOS
63b857f
+    gint preload_engine_mode = IBUS_PRELOAD_ENGINE_MODE_USER;
3b5789d
 
3b5789d
-    if (ibus->engine_list) {
3b5789d
-        BusComponent *component = bus_component_from_engine_desc ((IBusEngineDesc *) ibus->engine_list->data);
3b5789d
-        if (component && !bus_component_is_running (component)) {
3b5789d
-            bus_component_start (component, g_verbose);
3b5789d
-        }
1935274
+    /* bus_ibus_impl_reload_config() sets value = NULL.
1935274
+     * bus_ibus_impl_reload_config() is always called when
1935274
+     * RequestName signal is sent so it is good to get the gconf value
1935274
+     * again when value == NULL.
1935274
+     */
3b5789d
+    if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_INT32) {
3b5789d
+        preload_engine_mode = g_variant_get_int32 (value);
1935274
+    } else {
1935274
+        preload_engine_mode = _get_config_preload_engine_mode (ibus);
3b5789d
     }
3b5789d
 
48fb145
-    bus_ibus_impl_check_global_engine (ibus);
3b5789d
-    bus_ibus_impl_update_engines_hotkey_profile (ibus);
3b5789d
+    if (preload_engine_mode == IBUS_PRELOAD_ENGINE_MODE_USER) {
3b5789d
+        return;
3b5789d
+    }
3b5789d
+
3b5789d
+    _set_language_relative_preload_engines (ibus);
9d6bb4f
+#endif
8a795bf
 }
8a795bf
 
3b5789d
 /**
63b857f
@@ -503,89 +774,47 @@ bus_ibus_impl_set_use_global_engine (BusIBusImpl *ibus,
3b5789d
     }
3b5789d
 }
3b5789d
 
0610dd6
-#ifndef OS_CHROMEOS
3b5789d
-static gint
3b5789d
-_engine_desc_cmp (IBusEngineDesc *desc1,
3b5789d
-                  IBusEngineDesc *desc2)
3b5789d
-{
3b5789d
-    return - ((gint) ibus_engine_desc_get_rank (desc1)) +
3b5789d
-              ((gint) ibus_engine_desc_get_rank (desc2));
3b5789d
-}
0610dd6
-#endif
3b5789d
-
3b5789d
 /**
3b5789d
  * bus_ibus_impl_set_default_preload_engines:
3b5789d
  *
9d6bb4f
- * If the "preload_engines" config variable is not set yet, set the default value which is determined based on a current locale.
3b5789d
+ * bus_ibus_impl_set_default_preload_engines handles the gconf value
8a795bf
+ * /desktop/ibus/general/preload_engines and preload_engine_mode.
8a795bf
+ * The idea is, if users don't customize the preload_engines with ibus-setup,
8a795bf
+ * users would prefer to load the system default engines again by login.
8a795bf
+ * The gconf value 'preload_engine_mode' is
63b857f
+ * IBUS_PRELOAD_ENGINE_MODE_USER by default but set
63b857f
+ * IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE for the initial login.
8a795bf
+ * If preload_engine_mode is IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE,
8a795bf
+ * ibus-daemon loads the system preload engines by langs.
8a795bf
+ * If preload_engine_mode is IBUS_PRELOAD_ENGINE_MODE_USER,
8a795bf
+ * ibus-daemon do not update the gconf value preload_engines.
8a795bf
+ * On the other hand, if users enable the customized engine checkbutton
8a795bf
+ * on ibus-setup, ibus-setup sets 'preload_engine_mode' as
8a795bf
+ * IBUS_PRELOAD_ENGINE_MODE_USER and users can customize the value
8a795bf
+ * 'preload_engines'.
3b5789d
  */
8a795bf
 static void
3b5789d
 bus_ibus_impl_set_default_preload_engines (BusIBusImpl *ibus)
8a795bf
 {
0610dd6
 #ifndef OS_CHROMEOS
3b5789d
-    g_assert (BUS_IS_IBUS_IMPL (ibus));
3b5789d
-
8a795bf
     static gboolean done = FALSE;
63b857f
+    gint preload_engine_mode = IBUS_PRELOAD_ENGINE_MODE_USER;
3b5789d
+
3b5789d
+    g_assert (BUS_IS_IBUS_IMPL (ibus));
8a795bf
 
3b5789d
     if (done || ibus->config == NULL) {
3b5789d
         return;
3b5789d
     }
8a795bf
 
8a795bf
-    GVariant *variant = ibus_config_get_value (ibus->config, "general", "preload_engines");
8a795bf
-    if (variant != NULL) {
3b5789d
+    preload_engine_mode = _get_config_preload_engine_mode (ibus);
8a795bf
+
3b5789d
+    if (preload_engine_mode == IBUS_PRELOAD_ENGINE_MODE_USER) {
3b5789d
         done = TRUE;
3b5789d
-        g_variant_unref (variant);
3b5789d
         return;
8a795bf
     }
8a795bf
 
8a795bf
     done = TRUE;
9d6bb4f
-
9d6bb4f
-    /* The setlocale call first checks LC_ALL. If it's not available, checks
9d6bb4f
-     * LC_CTYPE. If it's also not available, checks LANG. */
9d6bb4f
-    gchar *lang = g_strdup (setlocale (LC_CTYPE, NULL));
9d6bb4f
-    if (lang == NULL) {
9d6bb4f
-        return;
9d6bb4f
-    }
9d6bb4f
-
3b5789d
-    gchar *p = index (lang, '.');
3b5789d
-    if (p) {
3b5789d
-        *p = '\0';
3b5789d
-    }
3b5789d
-
3b5789d
-    GList *engines = bus_registry_get_engines_by_language (ibus->registry, lang);
3b5789d
-    if (engines == NULL) {
3b5789d
-        p = index (lang, '_');
3b5789d
-        if (p) {
3b5789d
-            *p = '\0';
3b5789d
-            engines = bus_registry_get_engines_by_language (ibus->registry, lang);
3b5789d
-        }
3b5789d
-    }
3b5789d
-    g_free (lang);
3b5789d
-
3b5789d
-    /* sort engines by rank */
3b5789d
-    engines = g_list_sort (engines, (GCompareFunc) _engine_desc_cmp);
3b5789d
-
3b5789d
-    GVariantBuilder builder;
3b5789d
-    g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
3b5789d
-    GList *list;
3b5789d
-    for (list = engines; list != NULL; list = list->next) {
3b5789d
-        IBusEngineDesc *desc = (IBusEngineDesc *) list->data;
3b5789d
-        /* ignore engines with rank <= 0 */
3b5789d
-        if (ibus_engine_desc_get_rank (desc) > 0)
3b5789d
-            g_variant_builder_add (&builder, "s", ibus_engine_desc_get_name (desc));
3b5789d
-    }
069aa90
-
069aa90
-    GVariant *value = g_variant_builder_end (&builder);
069aa90
-    if (value != NULL) {
069aa90
-        if (g_variant_n_children (value) > 0) {
069aa90
-            ibus_config_set_value (ibus->config,
069aa90
-                                   "general", "preload_engines", value);
069aa90
-        } else {
069aa90
-            /* We don't update preload_engines with an empty string for safety.
069aa90
-             * Just unref the floating value. */
069aa90
-            g_variant_unref (value);
069aa90
-        }
069aa90
-    }
3b5789d
-    g_list_free (engines);
3b5789d
+    _set_language_relative_preload_engines (ibus);
0610dd6
 #endif
3b5789d
 }
3b5789d
 
63b857f
@@ -601,6 +830,7 @@ const static struct {
9d6bb4f
     { "general/hotkey", "next_engine_in_menu",   bus_ibus_impl_set_next_engine_in_menu },
9d6bb4f
     { "general/hotkey", "previous_engine",       bus_ibus_impl_set_previous_engine },
9d6bb4f
     { "general", "preload_engines",              bus_ibus_impl_set_preload_engines },
63b857f
+    { "general", "preload_engine_mode",          bus_ibus_impl_set_preload_engine_mode },
9d6bb4f
     { "general", "use_system_keyboard_layout",   bus_ibus_impl_set_use_sys_layout },
9d6bb4f
     { "general", "use_global_engine",            bus_ibus_impl_set_use_global_engine },
9d6bb4f
     { "general", "embed_preedit_text",           bus_ibus_impl_set_embed_preedit_text },
8a795bf
diff --git a/data/ibus.schemas.in b/data/ibus.schemas.in
63b857f
index 7ca4899..d4334e1 100644
8a795bf
--- a/data/ibus.schemas.in
8a795bf
+++ b/data/ibus.schemas.in
8a795bf
@@ -13,6 +13,19 @@
8a795bf
       </locale>
8a795bf
     </schema>
8a795bf
     <schema>
8a795bf
+      <key>/schemas/desktop/ibus/general/preload_engine_mode</key>
8a795bf
+      <applyto>/desktop/ibus/general/preload_engine_mode</applyto>
8a795bf
+      <owner>ibus</owner>
8a795bf
+      <type>int</type>
63b857f
+      <default>0</default>
8a795bf
+      <locale name="C">
8a795bf
+        <short>Preload engine mode</short>
8a795bf
+           <long>Preload engines are loaded with this mode.
3b5789d
+                 0 = user customized engines.
3b5789d
+                 1 = language related engines.</long>
8a795bf
+      </locale>
8a795bf
+    </schema>
8a795bf
+    <schema>
8a795bf
       <key>/schemas/desktop/ibus/general/hotkey/trigger</key>
8a795bf
       <applyto>/desktop/ibus/general/hotkey/trigger</applyto>
8a795bf
       <owner>ibus</owner>
8a795bf
diff --git a/ibus/common.py b/ibus/common.py
63b857f
index 6483aae..127ed93 100644
8a795bf
--- a/ibus/common.py
8a795bf
+++ b/ibus/common.py
48fb145
@@ -40,6 +40,8 @@ __all__ = (
48fb145
         "BUS_REQUEST_NAME_REPLY_IN_QUEUE",
48fb145
         "BUS_REQUEST_NAME_REPLY_EXISTS",
48fb145
         "BUS_REQUEST_NAME_REPLY_ALREADY_OWNER",
3b5789d
+        "PRELOAD_ENGINE_MODE_USER",
3b5789d
+        "PRELOAD_ENGINE_MODE_LANG_RELATIVE",
3b5789d
         "default_reply_handler",
3b5789d
         "default_error_handler",
3b5789d
         "DEFAULT_ASYNC_HANDLERS",
48fb145
@@ -150,6 +152,10 @@ BUS_REQUEST_NAME_REPLY_IN_QUEUE      = 2
48fb145
 BUS_REQUEST_NAME_REPLY_EXISTS        = 3
48fb145
 BUS_REQUEST_NAME_REPLY_ALREADY_OWNER = 4
8a795bf
 
8a795bf
+# define preload engine mode
3b5789d
+PRELOAD_ENGINE_MODE_USER          = 0
3b5789d
+PRELOAD_ENGINE_MODE_LANG_RELATIVE = 1
8a795bf
+
8a795bf
 def default_reply_handler( *args):
8a795bf
     pass
8a795bf
 
8a795bf
diff --git a/setup/main.py b/setup/main.py
63b857f
index 7f4a040..192fb88 100644
8a795bf
--- a/setup/main.py
8a795bf
+++ b/setup/main.py
63b857f
@@ -92,6 +92,7 @@ class Setup(object):
63b857f
         # keyboard shortcut
63b857f
         # trigger
63b857f
         self.__config = self.__bus.get_config()
63b857f
+        self.__config.connect("value-changed", self.__config_value_changed_cb)
63b857f
         shortcuts = self.__config.get_value(
63b857f
                         "general/hotkey", "trigger",
63b857f
                         ibus.CONFIG_GENERAL_SHORTCUT_TRIGGER_DEFAULT)
63b857f
@@ -213,15 +214,22 @@ class Setup(object):
8a795bf
         self.__checkbutton_use_global_engine.connect("toggled", self.__checkbutton_use_global_engine_toggled_cb)
8a795bf
 
8a795bf
         # init engine page
8a795bf
+        preload_engine_mode = self.__config.get_value("general",
8a795bf
+                                                      "preload_engine_mode",
3b5789d
+                                                      ibus.common.PRELOAD_ENGINE_MODE_USER)
8a795bf
+        button = self.__builder.get_object("checkbutton_preload_engine_mode")
8a795bf
+        if preload_engine_mode == ibus.common.PRELOAD_ENGINE_MODE_USER:
8a795bf
+            button.set_active(True)
8a795bf
+            self.__builder.get_object("hbox_customize_active_input_methods").set_sensitive(True)
8a795bf
+        else:
8a795bf
+            button.set_active(False)
8a795bf
+            self.__builder.get_object("hbox_customize_active_input_methods").set_sensitive(False)
8a795bf
+        button.connect("toggled", self.__checkbutton_preload_engine_mode_toggled_cb)
8a795bf
         self.__engines = self.__bus.list_engines()
8a795bf
         self.__combobox = self.__builder.get_object("combobox_engines")
8a795bf
         self.__combobox.set_engines(self.__engines)
8a795bf
 
8a795bf
-        tmp_dict = {}
8a795bf
-        for e in self.__engines:
8a795bf
-            tmp_dict[e.name] = e
3b5789d
-        engine_names = self.__config.get_value("general", "preload_engines", [])
8a795bf
-        engines = [tmp_dict[name] for name in engine_names if name in tmp_dict]
3b5789d
+        engines = self.__bus.list_active_engines()
8a795bf
 
8a795bf
         self.__treeview = self.__builder.get_object("treeview_engines")
8a795bf
         self.__treeview.set_engines(engines)
63b857f
@@ -265,6 +273,26 @@ class Setup(object):
8a795bf
             engine_names = map(lambda e: e.name, engines)
8a795bf
             self.__config.set_list("general", "preload_engines", engine_names, "s")
8a795bf
 
8a795bf
+    def __get_engine_descs_from_names(self, engine_names):
8a795bf
+        tmp_dict = {}
8a795bf
+        for e in self.__engines:
8a795bf
+            tmp_dict[e.name] = e
8a795bf
+        engines = [tmp_dict[name] for name in engine_names if name in tmp_dict]
8a795bf
+        return engines
8a795bf
+
63b857f
+    def __compare_descs(self, engines_a, engines_b):
63b857f
+        engines = engines_a
63b857f
+        concat_engine_names = ""
63b857f
+        for engine in engines:
63b857f
+            concat_engine_names = "%s::%s" % (concat_engine_names, engine.name)
63b857f
+        concat_engine_names_a = concat_engine_names
63b857f
+        engines = engines_b
63b857f
+        concat_engine_names = ""
63b857f
+        for engine in engines:
63b857f
+            concat_engine_names = "%s::%s" % (concat_engine_names, engine.name)
63b857f
+        concat_engine_names_b = concat_engine_names
63b857f
+        return concat_engine_names_a == concat_engine_names_b
63b857f
+
8a795bf
     def __button_engine_add_cb(self, button):
8a795bf
         engine = self.__combobox.get_active_engine()
8a795bf
         self.__treeview.append_engine(engine)
63b857f
@@ -276,6 +304,32 @@ class Setup(object):
8a795bf
             about.run()
8a795bf
             about.destroy()
8a795bf
 
8a795bf
+    def __checkbutton_preload_engine_mode_toggled_cb(self, button):
8a795bf
+        if button.get_active():
8a795bf
+            self.__config.set_value("general",
8a795bf
+                                    "preload_engine_mode",
8a795bf
+                                    ibus.common.PRELOAD_ENGINE_MODE_USER)
8a795bf
+            self.__builder.get_object("hbox_customize_active_input_methods").set_sensitive(True)
3b5789d
+            self.__treeview.notify("engines")
8a795bf
+        else:
63b857f
+            message = _("The list of your saved input methods will be " \
63b857f
+                        "cleared immediately and the list will be " \
63b857f
+                        "configured by the login language every time. " \
63b857f
+                        "Do you agree with this?")
63b857f
+            dlg = gtk.MessageDialog(type = gtk.MESSAGE_QUESTION,
63b857f
+                    buttons = gtk.BUTTONS_YES_NO,
63b857f
+                    message_format = message)
63b857f
+            id = dlg.run()
63b857f
+            dlg.destroy()
63b857f
+            self.__flush_gtk_events()
63b857f
+            if id != gtk.RESPONSE_YES:
63b857f
+                button.set_active(True)
63b857f
+                return
8a795bf
+            self.__config.set_value("general",
8a795bf
+                                    "preload_engine_mode",
8a795bf
+                                    ibus.common.PRELOAD_ENGINE_MODE_LANG_RELATIVE)
8a795bf
+            self.__builder.get_object("hbox_customize_active_input_methods").set_sensitive(False)
8a795bf
+
8a795bf
     def __init_bus(self):
8a795bf
         try:
8a795bf
             self.__bus = ibus.Bus()
63b857f
@@ -466,7 +520,11 @@ class Setup(object):
63b857f
         self.__config.set_value("general", "use_global_engine", value)
63b857f
 
63b857f
     def __config_value_changed_cb(self, bus, section, name, value):
63b857f
-        pass
63b857f
+        if section == 'general' and name == 'preload_engines':
63b857f
+            engines = self.__get_engine_descs_from_names(value)
63b857f
+            current_engines = self.__treeview.get_engines()
63b857f
+            if self.__compare_descs(engines, current_engines) == False:
63b857f
+                self.__treeview.set_engines(engines)
63b857f
 
63b857f
     def __config_reloaded_cb(self, bus):
63b857f
         pass
8a795bf
diff --git a/setup/setup.ui b/setup/setup.ui
1935274
index f1e6d0b..562c091 100644
8a795bf
--- a/setup/setup.ui
8a795bf
+++ b/setup/setup.ui
9d6bb4f
@@ -582,7 +582,22 @@
8a795bf
                     <property name="visible">True</property>
8a795bf
                     <property name="orientation">vertical</property>
8a795bf
                     <child>
8a795bf
-                      <object class="GtkHBox" id="hbox1">
8a795bf
+                      <object class="GtkCheckButton" id="checkbutton_preload_engine_mode">
8a795bf
+                        <property name="visible">True</property>
8a795bf
+                        <property name="label" translatable="yes">Customize active input _methods</property>
8a795bf
+                        <property name="use_underline">True</property>
8a795bf
+                        <property name="can_focus">True</property>
8a795bf
+                        <property name="receives_default">False</property>
8a795bf
+                        <property name="tooltip_text" translatable="yes">Customize active input methods</property>
8a795bf
+                        <property name="draw_indicator">True</property>
8a795bf
+                      </object>
8a795bf
+                      <packing>
8a795bf
+                        <property name="expand">False</property>
8a795bf
+                        <property name="position">0</property>
8a795bf
+                      </packing>
8a795bf
+                    </child>
8a795bf
+                    <child>
8a795bf
+                      <object class="GtkHBox" id="hbox_customize_active_input_methods">
8a795bf
                         <property name="visible">True</property>
8a795bf
                         <child>
8a795bf
                           <object class="GtkAlignment" id="alignment6">
9d6bb4f
@@ -733,7 +748,7 @@
8a795bf
                         </child>
8a795bf
                       </object>
8a795bf
                       <packing>
8a795bf
-                        <property name="position">0</property>
8a795bf
+                        <property name="position">1</property>
8a795bf
                       </packing>
8a795bf
                     </child>
8a795bf
                     <child>
9d6bb4f
@@ -772,7 +787,7 @@ You may use up/down buttons to change it.</i></small></property>
8a795bf
                       </object>
8a795bf
                       <packing>
8a795bf
                         <property name="expand">False</property>
8a795bf
-                        <property name="position">1</property>
8a795bf
+                        <property name="position">2</property>
8a795bf
                       </packing>
8a795bf
                     </child>
8a795bf
                   </object>
8a795bf
diff --git a/src/ibustypes.h b/src/ibustypes.h
63b857f
index 6a31847..14b44fc 100644
8a795bf
--- a/src/ibustypes.h
8a795bf
+++ b/src/ibustypes.h
63b857f
@@ -186,6 +186,16 @@ typedef enum {
63b857f
 } IBusError;
8a795bf
 
8a795bf
 /**
8a795bf
+ * IBusPreloadEngineMode:
8a795bf
+ * @IBUS_PRELOAD_ENGINE_MODE_USER: user custimized engines
3b5789d
+ * @IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE: language related engines.
8a795bf
+ */
8a795bf
+typedef enum {
3b5789d
+    IBUS_PRELOAD_ENGINE_MODE_USER          = 0,
3b5789d
+    IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE = 1,
8a795bf
+} IBusPreloadEngineMode;
8a795bf
+
8a795bf
+/**
8a795bf
  * IBusRectangle:
8a795bf
  * @x: x coordinate.
8a795bf
  * @y: y coordinate.
8a795bf
-- 
63b857f
1.7.4.4
8a795bf