150c9ee
From 18ad10e6dd89a0327fa29535f03fa51b953e7635 Mon Sep 17 00:00:00 2001
63b857f
From: fujiwarat <takao.fujiwara1@gmail.com>
150c9ee
Date: Mon, 28 Nov 2011 12:23:06 +0900
63b857f
Subject: [PATCH] Add a bridge hotkey which use prev-next engines instead
63b857f
 of on-off.
63b857f
63b857f
---
095f9c1
 bus/Makefile.am                 |   20 +-
be89530
 bus/ibusimpl.c                  |  598 +++++++++++++++++++++++++++++++++++----
5f53fe6
 bus/inputcontext.c              |   81 ++++++
095f9c1
 bus/inputcontext.h              |   22 ++
be89530
 bus/registry.c                  |   61 ++++
0318d1b
 bus/registry.h                  |   10 +
be89530
 configure.ac                    |   31 ++
095f9c1
 data/Makefile.am                |    6 +-
150c9ee
 data/ibus.schemas.in            |  298 -------------------
150c9ee
 data/ibus.schemas.in.in         |  311 ++++++++++++++++++++
095f9c1
 ibus/_config.py.in              |    6 +
be89530
 ibus/inputcontext.py            |   17 +-
5f53fe6
 ibus/interface/iinputcontext.py |    7 +-
095f9c1
 ibus/xkbxml.py.in               |    4 +
095f9c1
 setup/enginecombobox.py         |    3 +
0318d1b
 setup/enginetreeview.py         |    8 +-
150c9ee
 setup/main.py                   |   45 +++
150c9ee
 setup/setup.ui                  |   64 ++++-
095f9c1
 src/Makefile.am                 |   18 +-
095f9c1
 src/ibushotkey.c                |   11 +
095f9c1
 src/ibushotkey.h                |   11 +
be89530
 src/ibusinputcontext.c          |   27 ++
5f53fe6
 src/ibusinputcontext.h          |   12 +
095f9c1
 src/ibusutil.c                  |   12 +
0318d1b
 src/ibusutil.h                  |   14 +
3ef409f
 ui/gtk/panel.py                 |  335 ++++++++++++++++++++--
095f9c1
 xkb/Makefile.am                 |    2 +
be89530
 xkb/ibus-engine-xkb-main.c      |   16 +
095f9c1
 xkb/xkbxml.c                    |   10 +-
150c9ee
 29 files changed, 1653 insertions(+), 407 deletions(-)
63b857f
 delete mode 100644 data/ibus.schemas.in
63b857f
 create mode 100644 data/ibus.schemas.in.in
63b857f
63b857f
diff --git a/bus/Makefile.am b/bus/Makefile.am
095f9c1
index 074b456..0efaa1b 100644
63b857f
--- a/bus/Makefile.am
63b857f
+++ b/bus/Makefile.am
63b857f
@@ -29,15 +29,17 @@ INCLUDES =                \
63b857f
 	-I$(top_builddir)/src \
63b857f
 	$(NULL)
63b857f
 
63b857f
-AM_CFLAGS =                        \
63b857f
-	@GLIB2_CFLAGS@                 \
63b857f
-	@GIO2_CFLAGS@                  \
63b857f
-	@GTHREAD2_CFLAGS@              \
63b857f
-	-DG_LOG_DOMAIN=\"IBUS\"        \
63b857f
-	-DPKGDATADIR=\"$(pkgdatadir)\" \
63b857f
-	-DLIBEXECDIR=\"$(libexecdir)\" \
63b857f
-	-DBINDIR=\"@bindir@\"          \
63b857f
-	$(INCLUDES)                    \
63b857f
+AM_CFLAGS =                                                            \
63b857f
+	@GLIB2_CFLAGS@                                                 \
63b857f
+	@GIO2_CFLAGS@                                                  \
63b857f
+	@GTHREAD2_CFLAGS@                                              \
63b857f
+	-DG_LOG_DOMAIN=\"IBUS\"                                        \
63b857f
+	-DPKGDATADIR=\"$(pkgdatadir)\"                                 \
63b857f
+	-DLIBEXECDIR=\"$(libexecdir)\"                                 \
63b857f
+	-DBINDIR=\"@bindir@\"                                          \
63b857f
+	-DUSE_BRIDGE_HOTKEY=$(USE_BRIDGE_HOTKEY)                       \
63b857f
+	-DDEFAULT_BRIDGE_ENGINE_NAME=\"$(DEFAULT_BRIDGE_ENGINE_NAME)\" \
63b857f
+	$(INCLUDES)                                                    \
63b857f
 	$(NULL)
63b857f
 AM_LDADD =                  \
63b857f
 	@GOBJECT2_LIBS@         \
63b857f
diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c
150c9ee
index 059d660..67761fb 100644
63b857f
--- a/bus/ibusimpl.c
63b857f
+++ b/bus/ibusimpl.c
095f9c1
@@ -20,12 +20,17 @@
63b857f
  * Boston, MA 02111-1307, USA.
63b857f
  */
63b857f
 
63b857f
+#ifdef HAVE_CONFIG_H
63b857f
+#include <config.h>
63b857f
+#endif
63b857f
+
63b857f
 #include <unistd.h>
63b857f
 #include <sys/types.h>
63b857f
 #include <sys/wait.h>
095f9c1
 #include <signal.h>
095f9c1
 #include <locale.h>
095f9c1
 #include <strings.h>
095f9c1
+#include <string.h>
095f9c1
 #include "types.h"
095f9c1
 #include "ibusimpl.h"
095f9c1
 #include "dbusimpl.h"
5f53fe6
@@ -79,6 +84,11 @@ struct _BusIBusImpl {
63b857f
     /* engine-specific hotkeys */
63b857f
     IBusHotkeyProfile *engines_hotkey_profile;
63b857f
     GHashTable      *hotkey_to_engines_map;
63b857f
+
47affbc
+#if USE_BRIDGE_HOTKEY
63b857f
+    IBusEngineDesc *prev_hotkey_engine;
5f53fe6
+    guint           xkb_group_length;
47affbc
+#endif
63b857f
 };
63b857f
 
63b857f
 struct _BusIBusImplClass {
5f53fe6
@@ -99,6 +109,8 @@ enum {
b4e3b48
 static guint            _signals[LAST_SIGNAL] = { 0 };
b4e3b48
 */
b4e3b48
 
b4e3b48
+static gchar           *_bridge_trigger_keys = NULL;
b4e3b48
+
b4e3b48
 /* functions prototype */
b4e3b48
 static void      bus_ibus_impl_destroy           (BusIBusImpl        *ibus);
b4e3b48
 static void      bus_ibus_impl_service_method_call
5f53fe6
@@ -285,6 +297,112 @@ _panel_destroy_cb (BusPanelProxy *panel,
63b857f
     g_object_unref (panel);
63b857f
 }
63b857f
 
0318d1b
+/**
0318d1b
+ * _foreach_remove_engine_hotkey:
0318d1b
+ *
0318d1b
+ * Remove the engine-specific hot key of the engine, and update ibus->engines_hotkey_profile.
0318d1b
+ */
0318d1b
+gboolean
0318d1b
+_foreach_remove_engine_hotkey (gpointer        key,
0318d1b
+                               gpointer        value,
0318d1b
+                               gpointer        data)
63b857f
+{
0318d1b
+    GQuark event = GPOINTER_TO_UINT (value);
0318d1b
+    struct _impl_and_desc {
0318d1b
+        BusIBusImpl    *ibus;
0318d1b
+        IBusEngineDesc *desc;
0318d1b
+    } *id = (struct _impl_and_desc *) data;
0318d1b
+    BusIBusImpl *ibus = id->ibus;
0318d1b
+    IBusEngineDesc *desc = id->desc;
0318d1b
+    GList *engine_list;
63b857f
+
0318d1b
+    g_assert (ibus != NULL);
0318d1b
+    g_assert (desc != NULL);
0318d1b
+
0318d1b
+    if (event == 0) {
0318d1b
+        return FALSE;
63b857f
+    }
63b857f
+
0318d1b
+    engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map,
0318d1b
+                                       GUINT_TO_POINTER (event));
0318d1b
+
0318d1b
+    /* As we will rebuild the engines hotkey map whenever an engine was
0318d1b
+     * added or removed, we don't need to hold a reference of the engine
0318d1b
+     * here. */
0318d1b
+    if (engine_list && g_list_find (engine_list, desc) != NULL) {
0318d1b
+        engine_list = g_list_remove (engine_list, desc);
63b857f
+    }
63b857f
+
0318d1b
+    /* We need to steal the value before adding it back, otherwise it will
0318d1b
+     * be destroyed. */
0318d1b
+    g_hash_table_steal (ibus->hotkey_to_engines_map, GUINT_TO_POINTER (event));
0318d1b
+
0318d1b
+    if (engine_list != NULL) {
0318d1b
+        g_hash_table_insert (ibus->hotkey_to_engines_map,
0318d1b
+                             GUINT_TO_POINTER (event), engine_list);
0318d1b
+    }
0318d1b
+
0318d1b
+    return FALSE;
0318d1b
+}
0318d1b
+
0318d1b
+/**
0318d1b
+ * _add_engine_hotkey_with_hotkeys:
0318d1b
+ *
0318d1b
+ * Check the engine-specific hot key of the engine, and update ibus->engines_hotkey_profile.
0318d1b
+ */
0318d1b
+static void
0318d1b
+_add_engine_hotkey_with_hotkeys (IBusEngineDesc *engine,
0318d1b
+                                 BusIBusImpl    *ibus,
0318d1b
+                                 const gchar    *hotkeys)
0318d1b
+{
0318d1b
+    gchar **hotkey_list;
0318d1b
+    gchar **p;
0318d1b
+    gchar *hotkey;
0318d1b
+    GList *engine_list;
0318d1b
+
0318d1b
+    GQuark event;
0318d1b
+    guint keyval;
0318d1b
+    guint modifiers;
0318d1b
+
0318d1b
+    g_assert (engine != NULL);
0318d1b
+    g_assert (hotkeys && *hotkeys);
0318d1b
+
0318d1b
+    hotkey_list = g_strsplit_set (hotkeys, ";,", 0);
0318d1b
+
0318d1b
+    for (p = hotkey_list; p && *p; ++p) {
0318d1b
+        hotkey = g_strstrip (*p);
0318d1b
+        if (!*hotkey || !ibus_key_event_from_string (hotkey, &keyval, &modifiers)) {
0318d1b
+            continue;
0318d1b
+        }
0318d1b
+
0318d1b
+        /* If the hotkey already exists, we won't need to add it again. */
0318d1b
+        event = ibus_hotkey_profile_lookup_hotkey (ibus->engines_hotkey_profile,
0318d1b
+                                                   keyval, modifiers);
0318d1b
+        if (event == 0) {
0318d1b
+            event = g_quark_from_string (hotkey);
0318d1b
+            ibus_hotkey_profile_add_hotkey (ibus->engines_hotkey_profile,
0318d1b
+                                            keyval, modifiers, event);
0318d1b
+        }
0318d1b
+
0318d1b
+        engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map,
0318d1b
+                                           GUINT_TO_POINTER (event));
0318d1b
+
0318d1b
+        /* As we will rebuild the engines hotkey map whenever an engine was
0318d1b
+         * added or removed, we don't need to hold a reference of the engine
0318d1b
+         * here. */
0318d1b
+        engine_list = g_list_append (engine_list, engine);
0318d1b
+
0318d1b
+        /* We need to steal the value before adding it back, otherwise it will
0318d1b
+         * be destroyed. */
0318d1b
+        g_hash_table_steal (ibus->hotkey_to_engines_map, GUINT_TO_POINTER (event));
0318d1b
+
0318d1b
+        g_hash_table_insert (ibus->hotkey_to_engines_map,
0318d1b
+                             GUINT_TO_POINTER (event), engine_list);
0318d1b
+    }
0318d1b
+
0318d1b
+    g_strfreev (hotkey_list);
63b857f
+}
63b857f
+
63b857f
 static void
63b857f
 _config_set_value_done (GObject      *object,
63b857f
                         GAsyncResult *res,
5f53fe6
@@ -572,6 +690,67 @@ bus_ibus_impl_set_hotkey (BusIBusImpl *i
b4e3b48
 
b4e3b48
 }
b4e3b48
 
b4e3b48
+#if USE_BRIDGE_HOTKEY
095f9c1
+static gboolean
095f9c1
+use_bridge_hotkey (BusIBusImpl *ibus)
095f9c1
+{
095f9c1
+    GVariant *variant = NULL;
095f9c1
+    gboolean _use_bridge_hotkey = TRUE;
095f9c1
+
095f9c1
+    g_assert (ibus != NULL);
095f9c1
+
095f9c1
+    if (!ibus->config) {
095f9c1
+        return TRUE;
095f9c1
+    }
095f9c1
+
095f9c1
+    variant = ibus_config_get_value (ibus->config,
095f9c1
+                                     "general/hotkey",
095f9c1
+                                     "use_bridge_hotkey");
095f9c1
+
095f9c1
+    if (variant != NULL) {
095f9c1
+        g_variant_get (variant, "b", &_use_bridge_hotkey);
095f9c1
+        g_variant_unref (variant);
095f9c1
+    }
095f9c1
+
095f9c1
+    return _use_bridge_hotkey;
095f9c1
+}
095f9c1
+
b4e3b48
+static void
b4e3b48
+bus_ibus_impl_set_bridge_trigger_keys (BusIBusImpl *ibus,
b4e3b48
+                                       GQuark       hotkey,
b4e3b48
+                                       GVariant    *value)
b4e3b48
+{
b4e3b48
+    g_assert (BUS_IS_IBUS_IMPL (ibus));
b4e3b48
+
b4e3b48
+    ibus_hotkey_profile_remove_hotkey_by_event (ibus->hotkey_profile, hotkey);
b4e3b48
+
b4e3b48
+    if (value == NULL) {
b4e3b48
+        return;
b4e3b48
+    }
b4e3b48
+
b4e3b48
+    GVariantIter iter;
b4e3b48
+    g_variant_iter_init (&iter, value);
b4e3b48
+    const gchar *str = NULL;
b4e3b48
+
b4e3b48
+    g_free (_bridge_trigger_keys);
b4e3b48
+    _bridge_trigger_keys = NULL;
b4e3b48
+
b4e3b48
+    while (g_variant_iter_loop (&iter,"&s", &str)) {
b4e3b48
+       if (str != NULL) {
b4e3b48
+           gchar *tmp =NULL;
b4e3b48
+
b4e3b48
+           if (_bridge_trigger_keys) {
b4e3b48
+               tmp = g_strdup_printf ("%s,%s", _bridge_trigger_keys, str);
b4e3b48
+           } else {
b4e3b48
+               tmp = g_strdup (str);
b4e3b48
+           }
b4e3b48
+           g_free (_bridge_trigger_keys);
b4e3b48
+           _bridge_trigger_keys = tmp;
b4e3b48
+       }
b4e3b48
+    }
b4e3b48
+}
b4e3b48
+#endif
b4e3b48
+
b4e3b48
 /**
b4e3b48
  * bus_ibus_impl_set_trigger:
b4e3b48
  *
5f53fe6
@@ -583,7 +762,15 @@ bus_ibus_impl_set_trigger (BusIBusImpl *
577a981
 {
577a981
     GQuark hotkey = g_quark_from_static_string ("trigger");
577a981
     if (value != NULL) {
b4e3b48
+#if USE_BRIDGE_HOTKEY
095f9c1
+        if (use_bridge_hotkey (ibus)) {
095f9c1
+            bus_ibus_impl_set_bridge_trigger_keys (ibus, hotkey, value);
095f9c1
+        } else {
095f9c1
+            bus_ibus_impl_set_hotkey (ibus, hotkey, value);
095f9c1
+        }
b4e3b48
+#else
577a981
         bus_ibus_impl_set_hotkey (ibus, hotkey, value);
577a981
+#endif
577a981
     }
577a981
 #ifndef OS_CHROMEOS
577a981
     else {
5f53fe6
@@ -649,6 +836,72 @@ bus_ibus_impl_set_previous_engine (BusIB
0318d1b
     bus_ibus_impl_set_hotkey (ibus, hotkey, value);
63b857f
 }
63b857f
 
0318d1b
+#if USE_BRIDGE_HOTKEY
0318d1b
+static gint
0318d1b
+_engine_desc_name_cmp (IBusEngineDesc *desc1,
0318d1b
+                       IBusEngineDesc *desc2)
63b857f
+{
0318d1b
+    return g_strcmp0 (ibus_engine_desc_get_name (desc1),
0318d1b
+                      ibus_engine_desc_get_name (desc2));
63b857f
+}
63b857f
+
63b857f
+static void
0318d1b
+_set_register_engines (BusIBusImpl *ibus,
0318d1b
+                       GVariant    *value)
63b857f
+{
0318d1b
+    GList *engine_list = NULL;
63b857f
+
0318d1b
+    g_assert (BUS_IS_IBUS_IMPL (ibus));
63b857f
+
0318d1b
+    engine_list = ibus->register_engine_list;
0318d1b
+    if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_ARRAY) {
0318d1b
+        GVariantIter iter;
0318d1b
+        g_variant_iter_init (&iter, value);
0318d1b
+        const gchar *engine_name = NULL;
0318d1b
+        while (g_variant_iter_loop (&iter, "&s", &engine_name)) {
0318d1b
+            IBusEngineDesc *engine = bus_registry_find_engine_by_name (ibus->registry, engine_name);
0318d1b
+            if (engine == NULL || g_list_find (engine_list, engine) != NULL)
0318d1b
+                continue;
0318d1b
+            engine_list = g_list_append (engine_list, g_object_ref (engine));
63b857f
+        }
0318d1b
+    } else if (value != NULL) {
0318d1b
+        g_variant_unref (value);
0318d1b
+    }
63b857f
+
0318d1b
+    ibus->register_engine_list = engine_list;
0318d1b
+
0318d1b
+    if (engine_list) {
0318d1b
+        BusComponent *component = bus_component_from_engine_desc ((IBusEngineDesc *) engine_list->data);
0318d1b
+        if (component && !bus_component_is_running (component)) {
0318d1b
+            bus_component_start (component, g_verbose);
63b857f
+        }
0318d1b
+    }
0318d1b
+}
63b857f
+
0318d1b
+static void
0318d1b
+_set_default_keyboard_layout_engines (BusIBusImpl *ibus)
0318d1b
+{
0318d1b
+    GList *engines = NULL;
0318d1b
+    GList *list;
0318d1b
+    GVariantBuilder builder;
63b857f
+
0318d1b
+    g_assert (BUS_IS_IBUS_IMPL (ibus));
63b857f
+
0318d1b
+    engines = bus_registry_get_engines_by_name_prefix (ibus->registry,
0318d1b
+                                                       DEFAULT_BRIDGE_ENGINE_NAME);
0318d1b
+    /* sort engines by rank */
0318d1b
+    engines = g_list_sort (engines, (GCompareFunc) _engine_desc_name_cmp);
63b857f
+
0318d1b
+    g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
0318d1b
+    for (list = engines; list != NULL; list = list->next) {
0318d1b
+        IBusEngineDesc *desc = (IBusEngineDesc *)list->data;
0318d1b
+        g_variant_builder_add (&builder, "s", ibus_engine_desc_get_name (desc));
63b857f
+    }
0318d1b
+    _set_register_engines (ibus, g_variant_builder_end (&builder));
0318d1b
+    g_list_free (engines);
0318d1b
+}
0318d1b
+#endif
63b857f
+
63b857f
 /**
0318d1b
  * bus_ibus_impl_set_preload_engines:
0318d1b
  *
5f53fe6
@@ -668,6 +921,9 @@ bus_ibus_impl_set_preload_engines (BusIB
0318d1b
             _set_preload_engines (ibus, value);
0318d1b
         }
0318d1b
     }
0318d1b
+#if USE_BRIDGE_HOTKEY
0318d1b
+    _set_default_keyboard_layout_engines (ibus);
0318d1b
+#endif
0318d1b
 #else
0318d1b
     _set_preload_engines (ibus, value);
0318d1b
 #endif
be89530
@@ -1216,6 +1472,53 @@ _find_engine_desc_by_name (BusIBusImpl *
be89530
     return NULL;
be89530
 }
be89530
 
be89530
+#if USE_BRIDGE_HOTKEY
be89530
+const gchar *
be89530
+_get_engine_desc_hotkeys_with_system (IBusEngineDesc *desc)
be89530
+{
be89530
+    const gchar *hotkeys = NULL;
be89530
+
be89530
+    /* If the user customized the trigger key, the trigger key is used for
be89530
+     * any IBus engines. */
be89530
+    if (_bridge_trigger_keys != NULL &&
be89530
+        *_bridge_trigger_keys != '\0' &&
be89530
+        g_strcmp0 (_bridge_trigger_keys, "Control+space") != 0) {
be89530
+
be89530
+        hotkeys = (const gchar *) _bridge_trigger_keys;
be89530
+    } else if (desc) {
be89530
+        hotkeys = ibus_engine_desc_get_hotkeys (desc);
be89530
+    }
be89530
+
be89530
+    /* If engine hotkeys are not defined in the compose xml file,
be89530
+     * IBus trigger keys are used. */
be89530
+    if (!hotkeys || !*hotkeys) {
be89530
+            hotkeys = (const gchar *) _bridge_trigger_keys;
be89530
+    }
be89530
+
be89530
+    return hotkeys;
be89530
+}
be89530
+
be89530
+void
be89530
+_update_hotkeys_by_prev_engine_desc (BusIBusImpl    *ibus,
be89530
+                                     IBusEngineDesc *next_desc,
be89530
+                                     IBusEngineDesc *prev_desc)
be89530
+{
be89530
+    struct _impl_and_desc {
be89530
+        BusIBusImpl    *ibus;
be89530
+        IBusEngineDesc *desc;
be89530
+    } id = {ibus, next_desc};
be89530
+    const gchar *hotkeys = NULL;
be89530
+
be89530
+    hotkeys = _get_engine_desc_hotkeys_with_system (prev_desc);
be89530
+    if (hotkeys && *hotkeys) {
be89530
+        ibus_hotkey_profile_foreach_hotkey (ibus->engines_hotkey_profile,
be89530
+                                            _foreach_remove_engine_hotkey,
be89530
+                                            &id;;
be89530
+        _add_engine_hotkey_with_hotkeys (next_desc, ibus, hotkeys);
be89530
+    }
be89530
+}
be89530
+#endif
be89530
+
be89530
 /**
be89530
  * _context_request_engine_cb:
be89530
  *
be89530
@@ -1226,7 +1529,53 @@ _context_request_engine_cb (BusInputCont
63b857f
                             const gchar     *engine_name,
63b857f
                             BusIBusImpl     *ibus)
63b857f
 {
63b857f
-    return bus_ibus_impl_get_engine_desc (ibus, engine_name);
63b857f
+    IBusEngineDesc *desc = bus_ibus_impl_get_engine_desc (ibus, engine_name);
63b857f
+
63b857f
+#if USE_BRIDGE_HOTKEY
63b857f
+    IBusEngineDesc *current_desc = NULL;
b4e3b48
+
095f9c1
+    if (!use_bridge_hotkey (ibus)) {
095f9c1
+        return desc;
095f9c1
+    }
095f9c1
+
63b857f
+    if (context) {
63b857f
+        BusEngineProxy *engine = bus_input_context_get_engine (context);
63b857f
+        if (engine != NULL) {
63b857f
+            current_desc = bus_engine_proxy_get_desc (engine);
63b857f
+        }
63b857f
+    }
b4e3b48
+
095f9c1
+    if (((current_desc == NULL && desc != NULL) ||
095f9c1
+         (current_desc != NULL && desc != NULL &&
095f9c1
+          g_strcmp0 (ibus_engine_desc_get_name (current_desc),
095f9c1
+                     ibus_engine_desc_get_name (desc)) != 0)) &&
095f9c1
+        g_ascii_strncasecmp (ibus_engine_desc_get_name (desc),
095f9c1
+                             DEFAULT_BRIDGE_ENGINE_NAME,
095f9c1
+                             strlen (DEFAULT_BRIDGE_ENGINE_NAME)) == 0) {
be89530
+        _update_hotkeys_by_prev_engine_desc (ibus, desc, current_desc);
be89530
+    }
b4e3b48
+
be89530
+    if (current_desc && desc &&
be89530
+        g_strcmp0 (ibus_engine_desc_get_name (current_desc),
be89530
+                   ibus_engine_desc_get_name (desc)) != 0) {
be89530
+        if (context) {
be89530
+            bus_input_context_set_prev_hotkey_engine (context, current_desc);
be89530
+        } else {
be89530
+            ibus->prev_hotkey_engine = current_desc;
b4e3b48
+        }
b4e3b48
+
be89530
+        /* If the previous engine is not included in engine_list and
be89530
+         * the current engine is the defualt bridge engine,
be89530
+         * the current engine is also not included in engine_list.
be89530
+         * So the engine is added here. */
be89530
+        if (g_ascii_strncasecmp (ibus_engine_desc_get_name (current_desc),
be89530
+                                 DEFAULT_BRIDGE_ENGINE_NAME,
be89530
+                                 strlen (DEFAULT_BRIDGE_ENGINE_NAME)) == 0) {
be89530
+            _update_hotkeys_by_prev_engine_desc (ibus, current_desc, desc);
63b857f
+        }
63b857f
+    }
63b857f
+#endif
63b857f
+    return desc;
63b857f
 }
63b857f
 
63b857f
 /**
be89530
@@ -1265,8 +1614,13 @@ bus_ibus_impl_get_engine_desc (BusIBusIm
0318d1b
         if (!desc) {
0318d1b
             if (ibus->register_engine_list) {
0318d1b
                 desc = (IBusEngineDesc *) ibus->register_engine_list->data;
0318d1b
+#if USE_BRIDGE_HOTKEY
0318d1b
+                if (engine_name == NULL) {
0318d1b
+                    desc = NULL;
0318d1b
+                }
0318d1b
+#endif
0318d1b
             }
0318d1b
-            else if (ibus->engine_list) {
0318d1b
+            if (!desc && ibus->engine_list) {
0318d1b
                 desc = (IBusEngineDesc *) ibus->engine_list->data;
0318d1b
             }
0318d1b
         }
be89530
@@ -1311,9 +1665,20 @@ bus_ibus_impl_context_request_rotate_eng
5f53fe6
     desc = bus_engine_proxy_get_desc (engine);
5f53fe6
 
5f53fe6
     p = g_list_find (ibus->register_engine_list, desc);
5f53fe6
+#if USE_BRIDGE_HOTKEY
5f53fe6
+    if (!use_bridge_hotkey (ibus)) {
5f53fe6
+        p = NULL;
5f53fe6
+    }
5f53fe6
+#endif
5f53fe6
     if (p != NULL) {
5f53fe6
         if (is_next) {
5f53fe6
             p = p->next;
5f53fe6
+#if USE_BRIDGE_HOTKEY
5f53fe6
+            if (p && g_list_length (ibus->register_engine_list) -
5f53fe6
+                    g_list_length (p) >= ibus->xkb_group_length) {
5f53fe6
+                p = NULL;
5f53fe6
+            }
5f53fe6
+#endif
5f53fe6
         } else {
5f53fe6
             p = p->prev;
5f53fe6
         }
be89530
@@ -1343,11 +1708,25 @@ bus_ibus_impl_context_request_rotate_eng
be89530
     if (p == NULL && g_list_find (ibus->engine_list, desc) != NULL) {
be89530
         if (is_next) {
be89530
             p = ibus->register_engine_list;
5f53fe6
+#if USE_BRIDGE_HOTKEY
be89530
+            if (!use_bridge_hotkey (ibus)) {
be89530
+                p = NULL;
be89530
+            }
5f53fe6
+#endif
be89530
             if (p == NULL) {
be89530
                 p = ibus->engine_list;
be89530
             }
be89530
         } else {
be89530
             p = g_list_last (ibus->register_engine_list);
5f53fe6
+#if USE_BRIDGE_HOTKEY
be89530
+            if (!use_bridge_hotkey (ibus)) {
be89530
+                p = NULL;
be89530
+            }
be89530
+            else if (ibus->xkb_group_length > 0) {
be89530
+                p = g_list_nth (ibus->register_engine_list,
be89530
+                                ibus->xkb_group_length - 1);
be89530
+            }
5f53fe6
+#endif
be89530
             if (p == NULL) {
be89530
                 p = g_list_last (ibus->engine_list);
be89530
             }
be89530
@@ -1358,14 +1737,31 @@ bus_ibus_impl_context_request_rotate_eng
5f53fe6
         next_desc = (IBusEngineDesc*) p->data;
5f53fe6
     }
5f53fe6
     else {
5f53fe6
+#if USE_BRIDGE_HOTKEY
5f53fe6
+        if (use_bridge_hotkey (ibus) && ibus->register_engine_list) {
5f53fe6
+            next_desc = (IBusEngineDesc *) ibus->register_engine_list->data;
5f53fe6
+        }
5f53fe6
+#else
5f53fe6
         if (ibus->register_engine_list) {
5f53fe6
             next_desc = (IBusEngineDesc *) ibus->register_engine_list->data;
5f53fe6
         }
5f53fe6
+#endif
5f53fe6
         else if (ibus->engine_list) {
5f53fe6
             next_desc = (IBusEngineDesc *) ibus->engine_list->data;
5f53fe6
         }
5f53fe6
     }
5f53fe6
 
5f53fe6
+#if USE_BRIDGE_HOTKEY
be89530
+    if (use_bridge_hotkey (ibus) && desc != next_desc) {
5f53fe6
+        bus_input_context_set_prev_hotkey_engine (context, desc);
be89530
+        if (desc != NULL &&
be89530
+            g_ascii_strncasecmp (ibus_engine_desc_get_name (desc),
be89530
+                                 DEFAULT_BRIDGE_ENGINE_NAME,
be89530
+                                 strlen (DEFAULT_BRIDGE_ENGINE_NAME)) == 0) {
be89530
+            _update_hotkeys_by_prev_engine_desc (ibus, desc, next_desc);
be89530
+        }
5f53fe6
+    }
5f53fe6
+#endif
5f53fe6
     bus_ibus_impl_set_context_engine_from_desc (ibus, context, next_desc);
5f53fe6
 }
5f53fe6
 
be89530
@@ -1387,7 +1783,9 @@ bus_ibus_impl_context_request_previous_e
5f53fe6
         if (!ibus->global_previous_engine_name) {
5f53fe6
             ibus->global_previous_engine_name = bus_ibus_impl_load_global_previous_engine_name_from_config (ibus);
5f53fe6
         }
5f53fe6
+#if 0
5f53fe6
         engine_name = ibus->global_previous_engine_name;
5f53fe6
+#endif
5f53fe6
         if (engine_name != NULL) {
5f53fe6
             /* If the previous engine is removed from the engine list or the
5f53fe6
                current engine and the previous engine are the same one, force
be89530
@@ -1448,6 +1846,9 @@ bus_ibus_impl_set_focused_context (BusIB
ed173d8
 
ed173d8
     BusEngineProxy *engine = NULL;
ed173d8
     gboolean is_enabled = FALSE;
ed173d8
+#if USE_BRIDGE_HOTKEY
ed173d8
+    IBusEngineDesc *desc = NULL;
ed173d8
+#endif
ed173d8
 
ed173d8
     if (ibus->focused_context) {
ed173d8
         if (ibus->use_global_engine) {
be89530
@@ -1455,6 +1856,9 @@ bus_ibus_impl_set_focused_context (BusIB
ed173d8
             engine = bus_input_context_get_engine (ibus->focused_context);
ed173d8
             if (engine) {
ed173d8
                 is_enabled = bus_input_context_is_enabled (ibus->focused_context);
ed173d8
+#if USE_BRIDGE_HOTKEY
ed173d8
+                desc = bus_input_context_get_prev_hotkey_engine (ibus->focused_context);
ed173d8
+#endif
ed173d8
                 g_object_ref (engine);
ed173d8
                 bus_input_context_set_engine (ibus->focused_context, NULL);
ed173d8
             }
be89530
@@ -1479,6 +1883,9 @@ bus_ibus_impl_set_focused_context (BusIB
ed173d8
             if (is_enabled) {
ed173d8
                 bus_input_context_enable (context);
ed173d8
             }
ed173d8
+#if USE_BRIDGE_HOTKEY
ed173d8
+            bus_input_context_set_prev_hotkey_engine (ibus->focused_context, desc);
ed173d8
+#endif
ed173d8
             g_object_unref (engine);
ed173d8
         }
ed173d8
 
be89530
@@ -1708,6 +2115,25 @@ _context_disabled_cb (BusInputContext   
5f53fe6
 }
5f53fe6
 
5f53fe6
 /**
5f53fe6
+ * _context_set_xkb_engines_cb:
5f53fe6
+ *
5f53fe6
+ * A callback function to be called when the "set-xkb-engines" signal is sent to the context.
5f53fe6
+ */
5f53fe6
+static void
5f53fe6
+_context_set_xkb_engines_cb (BusInputContext    *context,
5f53fe6
+                             GList              *list,
5f53fe6
+                             BusIBusImpl        *ibus)
5f53fe6
+{
5f53fe6
+    if (list == NULL) {
5f53fe6
+        return;
5f53fe6
+    }
5f53fe6
+
5f53fe6
+#if USE_BRIDGE_HOTKEY
5f53fe6
+    ibus->xkb_group_length = g_list_length (list);
5f53fe6
+#endif
5f53fe6
+}
5f53fe6
+
5f53fe6
+/**
5f53fe6
  * bus_ibus_impl_create_input_context:
5f53fe6
  * @client: A name of a client. e.g. "gtk-im"
5f53fe6
  * @returns: A BusInputContext object.
be89530
@@ -1735,6 +2161,7 @@ bus_ibus_impl_create_input_context (BusI
5f53fe6
         { "destroy",        G_CALLBACK (_context_destroy_cb) },
5f53fe6
         { "enabled",        G_CALLBACK (_context_enabled_cb) },
5f53fe6
         { "disabled",       G_CALLBACK (_context_disabled_cb) },
5f53fe6
+        { "set-xkb-engines", G_CALLBACK (_context_set_xkb_engines_cb) },
5f53fe6
     };
5f53fe6
 
5f53fe6
     gint i;
be89530
@@ -2312,6 +2739,9 @@ bus_ibus_impl_filter_keyboard_shortcuts 
095f9c1
 
095f9c1
     GQuark event;
095f9c1
     GList *engine_list;
095f9c1
+#if USE_BRIDGE_HOTKEY
095f9c1
+    IBusEngineDesc *prev_hotkey_engine = NULL;
095f9c1
+#endif
095f9c1
 
095f9c1
     if (trigger == 0) {
095f9c1
         trigger = g_quark_from_static_string ("trigger");
be89530
@@ -2377,6 +2807,12 @@ bus_ibus_impl_filter_keyboard_shortcuts 
095f9c1
         return FALSE;
095f9c1
     }
095f9c1
 
095f9c1
+#if USE_BRIDGE_HOTKEY
095f9c1
+    if (!use_bridge_hotkey (ibus)) {
095f9c1
+        return FALSE;
095f9c1
+    }
095f9c1
+#endif
095f9c1
+
095f9c1
     /* Then try engines hotkeys. */
095f9c1
     event = ibus_hotkey_profile_filter_key_event (ibus->engines_hotkey_profile,
095f9c1
                                                   keyval,
be89530
@@ -2398,6 +2834,24 @@ bus_ibus_impl_filter_keyboard_shortcuts 
b4e3b48
 
b4e3b48
         g_assert (new_engine_desc);
b4e3b48
 
63b857f
+#if USE_BRIDGE_HOTKEY
095f9c1
+        if (context) {
095f9c1
+            prev_hotkey_engine = bus_input_context_get_prev_hotkey_engine (context);
095f9c1
+            if (prev_hotkey_engine == NULL && ibus->prev_hotkey_engine) {
095f9c1
+                prev_hotkey_engine = ibus->prev_hotkey_engine;
095f9c1
+                bus_input_context_set_prev_hotkey_engine (context,
095f9c1
+                                                          prev_hotkey_engine);
095f9c1
+            }
095f9c1
+        }
095f9c1
+
b4e3b48
+        /* If the previous engine is not included in engine_list,
b4e3b48
+         * this enables a new engine instead of toggling the engines
b4e3b48
+         * so should not enable the previous engine. */
095f9c1
+        if (prev_hotkey_engine &&
095f9c1
+            g_list_find (engine_list, prev_hotkey_engine) != NULL) {
095f9c1
+            new_engine_desc = prev_hotkey_engine;
63b857f
+        }
63b857f
+#else
b4e3b48
         /* Find out what engine we should switch to. If the current engine has
b4e3b48
          * the same hotkey, then we should switch to the next engine with the
b4e3b48
          * same hotkey in the list. Otherwise, we just switch to the first
be89530
@@ -2409,8 +2863,43 @@ bus_ibus_impl_filter_keyboard_shortcuts 
63b857f
                 break;
63b857f
             }
63b857f
         }
63b857f
+#endif
095f9c1
+
47affbc
+#if USE_BRIDGE_HOTKEY
095f9c1
+        if (context == NULL) {
095f9c1
+            return FALSE;
095f9c1
+        }
5f53fe6
+
095f9c1
+        /* This means RequestEngine signal might be done but SetEngine signal
095f9c1
+         * has not been done yet by ibus status icon. */
095f9c1
+        if (current_engine_desc == NULL &&
095f9c1
+            !bus_input_context_inited_engine (context)) {
095f9c1
+            return FALSE;
095f9c1
+        }
be89530
 
be89530
         if (current_engine_desc != new_engine_desc) {
095f9c1
+            if (current_engine_desc) {
095f9c1
+                if (context) {
095f9c1
+                    bus_input_context_set_prev_hotkey_engine (context,
095f9c1
+                                                              current_engine_desc);
095f9c1
+                }
095f9c1
+            }
be89530
+
be89530
+            /* If the current engine is the defualt bridge engine,
be89530
+             * the current engine is not included in engine_list.
be89530
+             * E.g. prev is Ctrl+space and Zenaku and current is Ctrl+space.
b4e3b48
+             * So the engine is added here. */
6cab06d
+            if (current_engine_desc != NULL &&
095f9c1
+                g_ascii_strncasecmp (ibus_engine_desc_get_name (current_engine_desc),
095f9c1
+                                     DEFAULT_BRIDGE_ENGINE_NAME,
095f9c1
+                                     strlen (DEFAULT_BRIDGE_ENGINE_NAME)) == 0) {
be89530
+                _update_hotkeys_by_prev_engine_desc (ibus,
be89530
+                                                     current_engine_desc,
be89530
+                                                     new_engine_desc);
b4e3b48
+            }
47affbc
+#else
be89530
+        if (current_engine_desc != new_engine_desc) {
47affbc
+#endif
63b857f
             bus_ibus_impl_set_context_engine_from_desc (ibus, context, new_engine_desc);
63b857f
         }
63b857f
 
be89530
@@ -2514,59 +3003,54 @@ static void
63b857f
 _add_engine_hotkey (IBusEngineDesc *engine, BusIBusImpl *ibus)
63b857f
 {
63b857f
     const gchar *hotkeys;
63b857f
-    gchar **hotkey_list;
63b857f
-    gchar **p;
63b857f
-    gchar *hotkey;
63b857f
-    GList *engine_list;
63b857f
-
63b857f
-    GQuark event;
63b857f
-    guint keyval;
63b857f
-    guint modifiers;
63b857f
 
63b857f
     if (!engine) {
63b857f
         return;
63b857f
     }
63b857f
 
095f9c1
-    hotkeys = ibus_engine_desc_get_hotkeys (engine);
095f9c1
-
095f9c1
-    if (!hotkeys || !*hotkeys) {
b4e3b48
+#if USE_BRIDGE_HOTKEY
095f9c1
+    if (!use_bridge_hotkey (ibus)) {
095f9c1
         return;
b4e3b48
     }
b4e3b48
 
63b857f
-    hotkey_list = g_strsplit_set (hotkeys, ";,", 0);
63b857f
-
63b857f
-    for (p = hotkey_list; p && *p; ++p) {
63b857f
-        hotkey = g_strstrip (*p);
63b857f
-        if (!*hotkey || !ibus_key_event_from_string (hotkey, &keyval, &modifiers)) {
63b857f
-            continue;
63b857f
-        }
63b857f
-
63b857f
-        /* If the hotkey already exists, we won't need to add it again. */
63b857f
-        event = ibus_hotkey_profile_lookup_hotkey (ibus->engines_hotkey_profile,
63b857f
-                                                   keyval, modifiers);
63b857f
-        if (event == 0) {
63b857f
-            event = g_quark_from_string (hotkey);
63b857f
-            ibus_hotkey_profile_add_hotkey (ibus->engines_hotkey_profile,
63b857f
-                                            keyval, modifiers, event);
63b857f
-        }
095f9c1
+    /* Do not register hotkeys for the default keymap engines
095f9c1
+     * but register hotkeys for only input-method engines
095f9c1
+     * in 'RegisterComponent' dbus method.
095f9c1
+     * The hotkeys for an activated keymap engine will be registered
095f9c1
+     * in 'SetEngine' dbus method. */
095f9c1
+    if (g_ascii_strncasecmp (ibus_engine_desc_get_name (engine),
095f9c1
+                             DEFAULT_BRIDGE_ENGINE_NAME,
095f9c1
+                             strlen (DEFAULT_BRIDGE_ENGINE_NAME)) == 0) {
095f9c1
+        return;
095f9c1
+    }
095f9c1
 
63b857f
-        engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map,
63b857f
-                                           GUINT_TO_POINTER (event));
095f9c1
+    /* If the user customized the trigger key, the trigger key is used for
095f9c1
+     * any IBus engines. */
095f9c1
+    if (_bridge_trigger_keys != NULL &&
095f9c1
+        *_bridge_trigger_keys != '\0' &&
095f9c1
+        g_strcmp0 (_bridge_trigger_keys, "Control+space") != 0) {
095f9c1
 
63b857f
-        /* As we will rebuild the engines hotkey map whenever an engine was
63b857f
-         * added or removed, we don't need to hold a reference of the engine
63b857f
-         * here. */
63b857f
-        engine_list = g_list_append (engine_list, engine);
095f9c1
+        hotkeys = (const gchar *) _bridge_trigger_keys;
095f9c1
+    } else {
095f9c1
+        hotkeys = ibus_engine_desc_get_hotkeys (engine);
095f9c1
+    }
095f9c1
+#else
095f9c1
+    hotkeys = ibus_engine_desc_get_hotkeys (engine);
095f9c1
+#endif
095f9c1
 
63b857f
-        /* We need to steal the value before adding it back, otherwise it will
63b857f
-         * be destroyed. */
63b857f
-        g_hash_table_steal (ibus->hotkey_to_engines_map, GUINT_TO_POINTER (event));
095f9c1
+#if USE_BRIDGE_HOTKEY
095f9c1
+    /* If engine hotkeys are not defined in the compose xml file, IBus trigger
095f9c1
+     * keys are used. */
095f9c1
+    if (!hotkeys || !*hotkeys) {
095f9c1
+        hotkeys = (const gchar *) _bridge_trigger_keys;
095f9c1
+    }
095f9c1
+#endif
095f9c1
 
63b857f
-        g_hash_table_insert (ibus->hotkey_to_engines_map,
63b857f
-                             GUINT_TO_POINTER (event), engine_list);
b4e3b48
+    if (!hotkeys || !*hotkeys) {
b4e3b48
+        return;
b4e3b48
     }
b4e3b48
 
63b857f
-    g_strfreev (hotkey_list);
63b857f
+    _add_engine_hotkey_with_hotkeys (engine, ibus, hotkeys);
63b857f
 }
63b857f
 
63b857f
 /**
095f9c1
diff --git a/bus/inputcontext.c b/bus/inputcontext.c
5f53fe6
index 3c81688..58ab8f4 100644
095f9c1
--- a/bus/inputcontext.c
095f9c1
+++ b/bus/inputcontext.c
095f9c1
@@ -90,6 +90,12 @@ struct _BusInputContext {
095f9c1
 
095f9c1
     /* incompleted set engine by desc request */
095f9c1
     SetEngineByDescData *data;
095f9c1
+
095f9c1
+    /* if init engine */
095f9c1
+    gboolean inited_engine;
095f9c1
+
095f9c1
+    /* previous hotkey engine for bridge hotkey mode */
095f9c1
+    IBusEngineDesc *prev_hotkey_engine;
095f9c1
 };
095f9c1
 
095f9c1
 struct _BusInputContextClass {
5f53fe6
@@ -122,6 +128,7 @@ enum {
5f53fe6
     DISABLED,
5f53fe6
     ENGINE_CHANGED,
5f53fe6
     REQUEST_ENGINE,
5f53fe6
+    SET_XKB_ENGINES,
5f53fe6
     LAST_SIGNAL,
5f53fe6
 };
5f53fe6
 
5f53fe6
@@ -265,6 +272,9 @@ static const gchar introspection_xml[] =
5f53fe6
     "    <method name='GetEngine'>"
5f53fe6
     "      <arg direction='out' type='v' name='desc' />"
5f53fe6
     "    </method>"
5f53fe6
+    "    <method name='SetXKBEngines'>"
5f53fe6
+    "      <arg direction='in' type='av' name='engines' />"
5f53fe6
+    "    </method>"
5f53fe6
     "    <method name='SetSurroundingText'>"
5f53fe6
     "      <arg direction='in' type='v' name='text' />"
5f53fe6
     "      <arg direction='in' type='u' name='cursor_pos' />"
5f53fe6
@@ -586,6 +596,17 @@ bus_input_context_class_init (BusInputContextClass *class)
5f53fe6
             1,
5f53fe6
             G_TYPE_STRING);
5f53fe6
 
5f53fe6
+    context_signals[SET_XKB_ENGINES] =
5f53fe6
+        g_signal_new (I_("set-xkb-engines"),
5f53fe6
+            G_TYPE_FROM_CLASS (class),
5f53fe6
+            G_SIGNAL_RUN_LAST,
5f53fe6
+            0,
5f53fe6
+            NULL, NULL,
5f53fe6
+            bus_marshal_VOID__OBJECT,
5f53fe6
+            G_TYPE_NONE,
5f53fe6
+            1,
5f53fe6
+            G_TYPE_POINTER);
5f53fe6
+
5f53fe6
     text_empty = ibus_text_new_from_string ("");
5f53fe6
     g_object_ref_sink (text_empty);
5f53fe6
     lookup_table_empty = ibus_lookup_table_new (9 /* page size */, 0, FALSE, FALSE);
5f53fe6
@@ -648,6 +669,11 @@ bus_input_context_destroy (BusInputContext *context)
095f9c1
         context->client = NULL;
095f9c1
     }
095f9c1
 
095f9c1
+    if (context->prev_hotkey_engine) {
095f9c1
+        g_object_unref (context->prev_hotkey_engine);
095f9c1
+        context->prev_hotkey_engine = NULL;
095f9c1
+    }
095f9c1
+
095f9c1
     IBUS_OBJECT_CLASS (bus_input_context_parent_class)->destroy (IBUS_OBJECT (context));
095f9c1
 }
095f9c1
 
5f53fe6
@@ -1048,6 +1074,32 @@ _ic_get_engine (BusInputContext       *context,
5f53fe6
 }
5f53fe6
 
5f53fe6
 /**
5f53fe6
+ * _ic_set_xkb_engines:
5f53fe6
+ *
5f53fe6
+ * Implement the "SetXKBEngines" method call of the org.freedesktop.IBus.InputContext interface.
5f53fe6
+ */
5f53fe6
+static void
5f53fe6
+_ic_set_xkb_engines (BusInputContext       *context,
5f53fe6
+                     GVariant              *parameters,
5f53fe6
+                     GDBusMethodInvocation *invocation)
5f53fe6
+{
5f53fe6
+    GVariantIter *iter = NULL;
5f53fe6
+    GVariant *var;
5f53fe6
+    GList *list = NULL;
5f53fe6
+
5f53fe6
+    g_variant_get_child (parameters, 0, "av", &iter);
5f53fe6
+    while (g_variant_iter_loop (iter, "v", &var)) {
5f53fe6
+        list = g_list_append (list, ibus_serializable_deserialize (var));
5f53fe6
+    }
5f53fe6
+    g_variant_iter_free (iter);
5f53fe6
+
5f53fe6
+    g_signal_emit (context,
5f53fe6
+                   context_signals[SET_XKB_ENGINES], 0,
5f53fe6
+                   list);
5f53fe6
+    return;
5f53fe6
+}
5f53fe6
+
5f53fe6
+/**
5f53fe6
  * bus_input_context_service_method_call:
5f53fe6
  *
5f53fe6
  * Handle a D-Bus method call whose destination and interface name are both "org.freedesktop.IBus.InputContext"
5f53fe6
@@ -1126,6 +1178,7 @@ bus_input_context_service_method_call (IBusService            *service,
5f53fe6
         { "IsEnabled",         _ic_is_enabled },
5f53fe6
         { "SetEngine",         _ic_set_engine },
5f53fe6
         { "GetEngine",         _ic_get_engine },
5f53fe6
+        { "SetXKBEngines",     _ic_set_xkb_engines },
5f53fe6
         { "SetSurroundingText", _ic_set_surrounding_text},
5f53fe6
     };
5f53fe6
 
5f53fe6
@@ -2218,6 +2271,7 @@ bus_input_context_set_engine (BusInputContext *context,
095f9c1
     }
095f9c1
     else {
095f9c1
         gint i;
095f9c1
+        context->inited_engine = TRUE;
095f9c1
         context->engine = engine;
095f9c1
         g_object_ref (context->engine);
095f9c1
 
5f53fe6
@@ -2542,3 +2596,30 @@ bus_input_context_get_client (BusInputContext *context)
095f9c1
     g_assert (BUS_IS_INPUT_CONTEXT (context));
095f9c1
     return context->client;
095f9c1
 }
095f9c1
+
095f9c1
+gboolean
095f9c1
+bus_input_context_inited_engine (BusInputContext *context)
095f9c1
+{
095f9c1
+    g_assert (BUS_IS_INPUT_CONTEXT (context));
095f9c1
+    return context->inited_engine;
095f9c1
+}
095f9c1
+
095f9c1
+IBusEngineDesc *
095f9c1
+bus_input_context_get_prev_hotkey_engine (BusInputContext *context)
095f9c1
+{
095f9c1
+    g_assert (BUS_IS_INPUT_CONTEXT (context));
095f9c1
+    return context->prev_hotkey_engine;
095f9c1
+}
095f9c1
+
095f9c1
+void
095f9c1
+bus_input_context_set_prev_hotkey_engine (BusInputContext *context,
095f9c1
+                                          IBusEngineDesc  *desc)
095f9c1
+{
095f9c1
+    g_assert (BUS_IS_INPUT_CONTEXT (context));
095f9c1
+    g_assert (desc == NULL || IBUS_IS_ENGINE_DESC (desc));
095f9c1
+
095f9c1
+    if (context->prev_hotkey_engine) {
095f9c1
+        g_object_unref (context->prev_hotkey_engine);
095f9c1
+    }
095f9c1
+    context->prev_hotkey_engine = desc ? g_object_ref (desc) : NULL;
095f9c1
+}
095f9c1
diff --git a/bus/inputcontext.h b/bus/inputcontext.h
095f9c1
index bc4e096..c79e033 100644
095f9c1
--- a/bus/inputcontext.h
095f9c1
+++ b/bus/inputcontext.h
095f9c1
@@ -213,5 +213,27 @@ void                 bus_input_context_set_capabilities (BusInputContext    *con
095f9c1
  */
095f9c1
 const gchar         *bus_input_context_get_client       (BusInputContext    *context);
095f9c1
 
095f9c1
+/**
095f9c1
+ * bus_input_context_inited_engine:
095f9c1
+ * @returns: context->inited_engine.
095f9c1
+ */
095f9c1
+gboolean             bus_input_context_inited_engine
095f9c1
+                                                        (BusInputContext *context);
095f9c1
+
095f9c1
+/**
095f9c1
+ * bus_input_context_get_prev_hotkey_engine:
095f9c1
+ * @returns: context->prev_hotkey_engine.
095f9c1
+ */
095f9c1
+IBusEngineDesc      *bus_input_context_get_prev_hotkey_engine
095f9c1
+                                                        (BusInputContext *context);
095f9c1
+
095f9c1
+/**
095f9c1
+ * bus_input_context_set_prev_hotkey_engine:
095f9c1
+ * @desc: Assign the desc to context->prev_hotkey_engine.
095f9c1
+ */
095f9c1
+void                 bus_input_context_set_prev_hotkey_engine
095f9c1
+                                                        (BusInputContext *context,
095f9c1
+                                                         IBusEngineDesc  *desc);
095f9c1
+
095f9c1
 G_END_DECLS
095f9c1
 #endif
63b857f
diff --git a/bus/registry.c b/bus/registry.c
0318d1b
index 7b74781..28e2abf 100644
63b857f
--- a/bus/registry.c
63b857f
+++ b/bus/registry.c
63b857f
@@ -19,6 +19,11 @@
63b857f
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
63b857f
  * Boston, MA 02111-1307, USA.
63b857f
  */
63b857f
+
63b857f
+#ifdef HAVE_CONFIG_H
63b857f
+#include <config.h>
63b857f
+#endif
63b857f
+
63b857f
 #include "registry.h"
63b857f
 #include <glib/gstdio.h>
63b857f
 #include <gio/gio.h>
63b857f
@@ -101,6 +106,9 @@ bus_registry_init (BusRegistry *registry)
63b857f
     registry->observed_paths = NULL;
63b857f
     registry->components = NULL;
63b857f
     registry->engine_table = g_hash_table_new (g_str_hash, g_str_equal);
63b857f
+#if USE_BRIDGE_HOTKEY
63b857f
+    gboolean has_default_engine = FALSE;
63b857f
+#endif
63b857f
 
63b857f
 #ifdef G_THREADS_ENABLED
63b857f
     /* If glib supports thread, we'll create a thread to monitor changes in IME
095f9c1
@@ -145,12 +153,40 @@ bus_registry_init (BusRegistry *registry)
63b857f
         GList *p1;
63b857f
         for (p1 = engines; p1 != NULL; p1 = p1->next) {
63b857f
             IBusEngineDesc *desc = (IBusEngineDesc *) p1->data;
63b857f
+#if USE_BRIDGE_HOTKEY
095f9c1
+            if (g_ascii_strncasecmp (ibus_engine_desc_get_name (desc),
095f9c1
+                                     DEFAULT_BRIDGE_ENGINE_NAME,
095f9c1
+                                     strlen (DEFAULT_BRIDGE_ENGINE_NAME)) == 0) {
63b857f
+                has_default_engine = TRUE;
63b857f
+            }
63b857f
+#endif
63b857f
             g_hash_table_insert (registry->engine_table,
63b857f
                                  (gpointer) ibus_engine_desc_get_name (desc),
63b857f
                                  desc);
63b857f
         }
63b857f
         g_list_free (engines);
63b857f
     }
63b857f
+
63b857f
+#if USE_BRIDGE_HOTKEY
63b857f
+    if (has_default_engine == FALSE) {
63b857f
+        bus_registry_remove_all (registry);
63b857f
+        bus_registry_load (registry);
63b857f
+        bus_registry_save_cache (registry);
63b857f
+
63b857f
+        for (p = registry->components; p != NULL; p = p->next) {
63b857f
+            BusComponent *comp = (BusComponent *) p->data;
63b857f
+            GList *engines = bus_component_get_engines (comp);
63b857f
+            GList *p1;
63b857f
+            for (p1 = engines; p1 != NULL; p1 = p1->next) {
63b857f
+                IBusEngineDesc *desc = (IBusEngineDesc *) p1->data;
63b857f
+                g_hash_table_insert (registry->engine_table,
63b857f
+                                     (gpointer) ibus_engine_desc_get_name (desc),
63b857f
+                                     desc);
63b857f
+            }
63b857f
+            g_list_free (engines);
63b857f
+        }
63b857f
+    }
63b857f
+#endif
63b857f
 }
63b857f
 
63b857f
 static void
0318d1b
@@ -516,6 +552,31 @@ bus_registry_get_engines_by_language (BusRegistry *registry,
0318d1b
     return engines;
0318d1b
 }
0318d1b
 
0318d1b
+GList *
0318d1b
+bus_registry_get_engines_by_name_prefix (BusRegistry *registry,
0318d1b
+                                         const gchar *name_prefix)
0318d1b
+{
0318d1b
+    GList *p1, *p2;
0318d1b
+    GList *engines = NULL;
0318d1b
+
0318d1b
+    g_assert (BUS_IS_REGISTRY (registry));
0318d1b
+    g_assert (name_prefix);
0318d1b
+
0318d1b
+    p1 = bus_registry_get_engines (registry);
0318d1b
+
0318d1b
+    for (p2 = p1; p2 != NULL; p2 = p2->next) {
0318d1b
+        IBusEngineDesc *desc = (IBusEngineDesc *) p2->data;
0318d1b
+        if (g_ascii_strncasecmp (ibus_engine_desc_get_name (desc),
0318d1b
+                                 name_prefix,
0318d1b
+                                 strlen (name_prefix)) == 0) {
0318d1b
+            engines = g_list_append (engines, desc);
0318d1b
+        }
0318d1b
+    }
0318d1b
+
0318d1b
+    g_list_free (p1);
0318d1b
+    return engines;
0318d1b
+}
0318d1b
+
0318d1b
 IBusEngineDesc *
0318d1b
 bus_registry_find_engine_by_name (BusRegistry *registry,
0318d1b
                                   const gchar *name)
0318d1b
diff --git a/bus/registry.h b/bus/registry.h
0318d1b
index cdabec0..721187c 100644
0318d1b
--- a/bus/registry.h
0318d1b
+++ b/bus/registry.h
0318d1b
@@ -73,6 +73,16 @@ GList           *bus_registry_get_engines_by_language
0318d1b
                                                  const gchar    *language);
0318d1b
 
0318d1b
 /**
0318d1b
+ * bus_registry_get_engines_by_name_prefix:
0318d1b
+ * @name_prefix: a prefix in the name of IBusEngineDesc. 
0318d1b
+ * @returns: a list of IBusEngineDesc objects which has the name prefix.
0318d1b
+ *           The caller has to call g_list_free for the returned list.
0318d1b
+ */
0318d1b
+GList           *bus_registry_get_engines_by_name_prefix
0318d1b
+                                                (BusRegistry    *registry,
0318d1b
+                                                 const gchar    *name_prefix);
0318d1b
+
0318d1b
+/**
0318d1b
  * bus_registry_stop_all_components:
0318d1b
  *
0318d1b
  * Terminate all component processes.
63b857f
diff --git a/configure.ac b/configure.ac
e4605fa
index 227e28e..788fbef 100644
63b857f
--- a/configure.ac
63b857f
+++ b/configure.ac
e4605fa
@@ -483,6 +483,34 @@ else
63b857f
     enable_surrounding_text="no (disabled, use --enable-surrounding-text to enable)"
63b857f
 fi
63b857f
 
e4605fa
+# Option for bridge hotkey
63b857f
+AC_ARG_ENABLE(bridge-hotkey,
63b857f
+    AS_HELP_STRING([--enable-bridge-hotkey],
63b857f
+        [Enable bridge hotkey instead of ON/OFF hotkey]),
63b857f
+    [enable_bridge_hotkey=$enableval],
63b857f
+    [enable_bridge_hotkey=no]
63b857f
+)
63b857f
+
63b857f
+if test x"$enable_bridge_hotkey" = x"yes"; then
63b857f
+    USE_BRIDGE_HOTKEY=1
b4e3b48
+    TRIGGER_HOTKEYS="Control+space"
63b857f
+else
63b857f
+    USE_BRIDGE_HOTKEY=0
63b857f
+    TRIGGER_HOTKEYS="Control+space,Zenkaku_Hankaku,Alt+Kanji,Alt+grave,Hangul,Alt+Release+Alt_R"
63b857f
+    enable_bridge_hotkey="no (disabled, use --enable-bridge-hotkey to enable)"
63b857f
+fi
63b857f
+AC_SUBST(USE_BRIDGE_HOTKEY)
63b857f
+AC_SUBST(TRIGGER_HOTKEYS)
63b857f
+
e4605fa
+# Define default bridge engine name
63b857f
+AC_ARG_WITH(bridge-engine,
63b857f
+    AS_HELP_STRING([--with-bridge-engine[=bridge_engine_name]],
095f9c1
+        [Set bridge engine name in IM bridge hotkey. (default: xkb:layout:default:)]),
63b857f
+    [DEFAULT_BRIDGE_ENGINE_NAME=$with_bridge_engine],
095f9c1
+    [DEFAULT_BRIDGE_ENGINE_NAME="xkb:layout:default:"]
63b857f
+)
63b857f
+AC_SUBST(DEFAULT_BRIDGE_ENGINE_NAME)
63b857f
+
e4605fa
 # Check iso-codes.
63b857f
 PKG_CHECK_MODULES(ISOCODES, [
63b857f
     iso-codes
e4605fa
@@ -509,6 +537,7 @@ bus/Makefile
63b857f
 util/Makefile
63b857f
 util/IMdkit/Makefile
63b857f
 data/Makefile
63b857f
+data/ibus.schemas.in
63b857f
 data/icons/Makefile
63b857f
 data/keymaps/Makefile
e0a5e11
 data/dconf/Makefile
e4605fa
@@ -561,5 +590,7 @@ Build options:
63b857f
   No snooper regexes        "$NO_SNOOPER_APPS"
63b857f
   Panel icon                "$IBUS_ICON_KEYBOARD"
63b857f
   Enable surrounding-text   $enable_surrounding_text
63b857f
+  Enable bridge hotkey      $enable_bridge_hotkey
63b857f
+  Default bridge engine     $DEFAULT_BRIDGE_ENGINE_NAME
63b857f
 ])
63b857f
 
63b857f
diff --git a/data/Makefile.am b/data/Makefile.am
095f9c1
index 99be41c..824da76 100644
63b857f
--- a/data/Makefile.am
63b857f
+++ b/data/Makefile.am
e0a5e11
@@ -30,7 +30,8 @@ SUBDIRS += dconf
e0a5e11
 endif
63b857f
 
63b857f
 schemasdir = $(GCONF_SCHEMA_FILE_DIR)
63b857f
-schemas_in_files = ibus.schemas.in
63b857f
+schemas_in_in_files = ibus.schemas.in.in
63b857f
+schemas_in_files = $(schemas_in_in_files:.schemas.in.in=.schemas.in)
63b857f
 schemas_DATA = $(schemas_in_files:.schemas.in=.schemas)
63b857f
 @INTLTOOL_SCHEMAS_RULE@
63b857f
 
e0a5e11
@@ -45,11 +46,12 @@ if GCONF_SCHEMAS_INSTALL
63b857f
 endif
63b857f
 
63b857f
 EXTRA_DIST = \
63b857f
-	$(schemas_in_files) \
63b857f
+	$(schemas_in_in_files) \
63b857f
 	$(NULL)
63b857f
 
63b857f
 DISTCLEANFILES = \
63b857f
 	$(schemas_DATA) \
63b857f
+	$(schemas_in_files) \
63b857f
 	$(NULL)
63b857f
 
63b857f
 -include $(top_srcdir)/git.mk
63b857f
diff --git a/data/ibus.schemas.in b/data/ibus.schemas.in.in
0318d1b
index 8979515..2a2b459
63b857f
--- a/data/ibus.schemas.in
63b857f
+++ b/data/ibus.schemas.in.in
63b857f
@@ -31,7 +31,7 @@
63b857f
       <owner>ibus</owner>
63b857f
       <type>list</type>
63b857f
       <list_type>string</list_type>
63b857f
-      <default>[Control+space,Zenkaku_Hankaku,Alt+Kanji,Alt+grave,Hangul,Alt+Release+Alt_R]</default>
63b857f
+      <default>[@TRIGGER_HOTKEYS@]</default>
63b857f
       <locale name="C">
63b857f
         <short>Trigger shortcut keys</short>
63b857f
 	    <long>The shortcut keys for turning input method on or off</long>
e68340e
@@ -103,6 +103,19 @@
e68340e
       </locale>
e68340e
     </schema>
e68340e
     <schema>
e68340e
+      <key>/schemas/desktop/ibus/general/hotkey/use_bridge_hotkey</key>
e68340e
+      <applyto>/desktop/ibus/general/hotkey/use_bridge_hotkey</applyto>
e68340e
+      <owner>ibus</owner>
e68340e
+      <type>bool</type>
e68340e
+      <default>true</default>
e68340e
+      <locale name="C">
e68340e
+        <short>Use bridge hotkey</short>
e68340e
+	    <long>Use trigger keys to toggle the prev and next IM engines
e68340e
+                  if true. Use trigger keys to toggle an enable and 
e68340e
+                  disabled IM engine if false.</long>
e68340e
+      </locale>
e68340e
+    </schema>
e68340e
+    <schema>
e68340e
       <key>/schemas/desktop/ibus/panel/show</key>
e68340e
       <applyto>/desktop/ibus/panel/show</applyto>
e68340e
       <owner>ibus</owner>
63b857f
diff --git a/ibus/_config.py.in b/ibus/_config.py.in
63b857f
index a830136..4c3c980 100644
63b857f
--- a/ibus/_config.py.in
63b857f
+++ b/ibus/_config.py.in
63b857f
@@ -25,6 +25,8 @@ __all__ = (
63b857f
     "get_copyright",
63b857f
     "get_license",
63b857f
     "get_ICON_KEYBOARD",
63b857f
+    "use_bridge_hotkey",
63b857f
+    "DEFAULT_BRIDGE_ENGINE_NAME",
63b857f
     "ISOCODES_PREFIX",
63b857f
     "_"
63b857f
 )
150c9ee
@@ -55,4 +57,8 @@ def get_ICON_KEYBOARD():
150c9ee
         return fallback_icon
63b857f
     return icon
63b857f
 
63b857f
+def use_bridge_hotkey():
63b857f
+    return True if @USE_BRIDGE_HOTKEY@ == 1 else False
63b857f
+
63b857f
+DEFAULT_BRIDGE_ENGINE_NAME='@DEFAULT_BRIDGE_ENGINE_NAME@'
63b857f
 ISOCODES_PREFIX='@ISOCODES_PREFIX@'
63b857f
diff --git a/ibus/inputcontext.py b/ibus/inputcontext.py
5f53fe6
index 64a6ba2..b471e20 100644
63b857f
--- a/ibus/inputcontext.py
63b857f
+++ b/ibus/inputcontext.py
63b857f
@@ -28,6 +28,7 @@ import sys
63b857f
 import gobject
63b857f
 import dbus
63b857f
 import dbus.lowlevel
63b857f
+import _config
63b857f
 import object
63b857f
 import common
63b857f
 import serializable
5f53fe6
@@ -283,8 +284,22 @@ class InputContext(object.Object):
095f9c1
         except:
095f9c1
             return None
63b857f
 
095f9c1
+    def __handle_ic_reply(self):
095f9c1
+        pass
095f9c1
+
095f9c1
+    def __handle_ic_error(self, e):
095f9c1
+        print self.__gtype_name__, str(e)
095f9c1
+
095f9c1
     def set_engine(self, engine):
095f9c1
-        return self.__context.SetEngine(engine.name)
095f9c1
+        return self.__context.SetEngine(engine.name,
095f9c1
+                                        reply_handler=self.__handle_ic_reply,
095f9c1
+                                        error_handler=self.__handle_ic_error)
095f9c1
+
5f53fe6
+    def set_xkb_engines(self, engines):
5f53fe6
+        engines = map(lambda e: serializable.serialize_object(e), engines)
5f53fe6
+        return self.__context.SetXKBEngines(engines,
5f53fe6
+                                            reply_handler=self.__handle_ic_reply,
5f53fe6
+                                            error_handler=self.__handle_ic_error)
095f9c1
 
63b857f
     def introspect(self):
63b857f
         return self.__context.Introspect()
095f9c1
diff --git a/ibus/interface/iinputcontext.py b/ibus/interface/iinputcontext.py
5f53fe6
index 06ce519..3b655dc 100644
095f9c1
--- a/ibus/interface/iinputcontext.py
095f9c1
+++ b/ibus/interface/iinputcontext.py
5f53fe6
@@ -76,8 +76,11 @@ class IInputContext(dbus.service.Object):
095f9c1
     @method(out_signature="v")
095f9c1
     def GetEngine(self): pass
095f9c1
 
095f9c1
-    @method(in_signature="s")
095f9c1
-    def SetEngine(self, engine_name): pass
095f9c1
+    @async_method(in_signature="s")
095f9c1
+    def SetEngine(self, engine_name, reply_cb, error_cb): pass
5f53fe6
+
5f53fe6
+    @async_method(in_signature="av")
5f53fe6
+    def SetXKBEngines(self, engines, reply_cb, error_cb): pass
63b857f
 
095f9c1
     @method()
095f9c1
     def Destroy(self): pass
095f9c1
diff --git a/ibus/xkbxml.py.in b/ibus/xkbxml.py.in
0318d1b
index 9407c13..bf61810 100644
095f9c1
--- a/ibus/xkbxml.py.in
095f9c1
+++ b/ibus/xkbxml.py.in
095f9c1
@@ -33,6 +33,8 @@ import enginedesc
095f9c1
 from xml.sax.saxutils import XMLFilterBase, XMLGenerator
095f9c1
 from xml.sax._exceptions import SAXParseException
095f9c1
 from cStringIO import StringIO
095f9c1
+from _config import DEFAULT_BRIDGE_ENGINE_NAME
095f9c1
+from _config import get_ICON_KEYBOARD
095f9c1
 
095f9c1
 try:
095f9c1
     from glib import get_user_config_dir
0318d1b
@@ -315,6 +317,8 @@ class XKBConfigRegistry():
095f9c1
             engine_layout = layout
095f9c1
 
095f9c1
         icon = 'ibus-engine'
0318d1b
+        if name.startswith(DEFAULT_BRIDGE_ENGINE_NAME):
095f9c1
+            icon = get_ICON_KEYBOARD()
095f9c1
 
095f9c1
         engine = enginedesc.EngineDesc(name, longname, desc, lang,
095f9c1
                                        'LGPL2.1',
47affbc
diff --git a/setup/enginecombobox.py b/setup/enginecombobox.py
095f9c1
index 7383177..d35757d 100644
47affbc
--- a/setup/enginecombobox.py
47affbc
+++ b/setup/enginecombobox.py
47affbc
@@ -64,6 +64,9 @@ class EngineComboBox(gtk.ComboBox):
47affbc
         self.__model.set(iter1, 0, 0)
47affbc
         lang = {}
47affbc
         for e in engines:
47affbc
+            if ibus.use_bridge_hotkey() and \
095f9c1
+               e.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
47affbc
+                continue
47affbc
             l = ibus.get_language_name(e.language)
47affbc
             if l not in lang:
47affbc
                 lang[l] = []
577a981
diff --git a/setup/enginetreeview.py b/setup/enginetreeview.py
0318d1b
index f620361..664dc99 100644
577a981
--- a/setup/enginetreeview.py
577a981
+++ b/setup/enginetreeview.py
0318d1b
@@ -172,8 +172,12 @@ class EngineTreeView(gtk.TreeView):
47affbc
         for e in engines:
47affbc
             if e in self.__engines:
47affbc
                 continue
47affbc
-            iter = self.__model.append(None)
47affbc
-            self.__model.set(iter, 0, e)
47affbc
+            if ibus.use_bridge_hotkey() and \
095f9c1
+               e.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
47affbc
+                pass
47affbc
+            else:
47affbc
+                iter = self.__model.append(None)
47affbc
+                self.__model.set(iter, 0, e)
47affbc
             self.__engines.add(e)
47affbc
         self.__emit_changed()
47affbc
 
095f9c1
diff --git a/setup/main.py b/setup/main.py
150c9ee
index 7f4a040..a773944 100644
095f9c1
--- a/setup/main.py
095f9c1
+++ b/setup/main.py
150c9ee
@@ -213,6 +213,22 @@ class Setup(object):
095f9c1
             self.__config.get_value("general", "use_global_engine", False))
095f9c1
         self.__checkbutton_use_global_engine.connect("toggled", self.__checkbutton_use_global_engine_toggled_cb)
095f9c1
 
095f9c1
+        # hotkey settings
095f9c1
+        if ibus.use_bridge_hotkey():
150c9ee
+            self.__set_bridge_hotkey_labels()
095f9c1
+            self.__checkbutton_use_on_off_hotkey = \
095f9c1
+                self.__builder.get_object("checkbutton_use_on_off_hotkey")
095f9c1
+            self.__checkbutton_use_on_off_hotkey.set_active(
095f9c1
+                not self.__config.get_value("general/hotkey",
095f9c1
+                                            "use_bridge_hotkey",
095f9c1
+                                            True))
095f9c1
+            self.__checkbutton_use_on_off_hotkey.connect("toggled",
095f9c1
+                self.__checkbutton_use_on_off_hotkey_cb)
095f9c1
+        else:
095f9c1
+            checkbutton = self.__builder.get_object("checkbutton_use_on_off_hotkey")
095f9c1
+            checkbutton.hide()
095f9c1
+            checkbutton.set_no_show_all(True)
095f9c1
+
095f9c1
         # init engine page
095f9c1
         preload_engine_mode = self.__config.get_value("general",
095f9c1
                                                       "preload_engine_mode",
150c9ee
@@ -519,6 +535,35 @@ class Setup(object):
095f9c1
         value = self.__checkbutton_use_global_engine.get_active()
095f9c1
         self.__config.set_value("general", "use_global_engine", value)
095f9c1
 
095f9c1
+    def __checkbutton_use_on_off_hotkey_cb(self, button):
095f9c1
+        value = self.__checkbutton_use_on_off_hotkey.get_active()
095f9c1
+        self.__config.set_value("general/hotkey", "use_bridge_hotkey",
095f9c1
+                                not value)
150c9ee
+        self.__set_bridge_hotkey_labels()
150c9ee
+
150c9ee
+    def __set_bridge_hotkey_labels(self):
150c9ee
+        label = self.__builder.get_object("label_trigger_hotkey")
150c9ee
+        label_enable = self.__builder.get_object("label_enable")
150c9ee
+        hbox_enable = self.__builder.get_object("hbox_enable")
150c9ee
+        label_disable = self.__builder.get_object("label_disable")
150c9ee
+        hbox_disable = self.__builder.get_object("hbox_disable")
150c9ee
+        if self.__config.get_value("general/hotkey", "use_bridge_hotkey", True):
150c9ee
+            label.set_label(_("Toggle input methods:"))
150c9ee
+            label.set_tooltip_text(_("The shortcut keys to toggle "
150c9ee
+                                     "the previous and next input methods"))
150c9ee
+            label_enable.hide()
150c9ee
+            hbox_enable.hide()
150c9ee
+            label_disable.hide()
150c9ee
+            hbox_disable.hide()
150c9ee
+        else:
150c9ee
+            label.set_label(_("Enable or disable:"))
150c9ee
+            label.set_tooltip_text(_("The shortcut keys for turning "
150c9ee
+                                     "input method on or off"))
150c9ee
+            label_enable.show()
150c9ee
+            hbox_enable.show()
150c9ee
+            label_disable.show()
150c9ee
+            hbox_disable.show()
095f9c1
+
095f9c1
     def __config_value_changed_cb(self, bus, section, name, value):
095f9c1
         if section == 'general' and name == 'preload_engines':
095f9c1
             engines = self.__get_engine_descs_from_names(value)
095f9c1
diff --git a/setup/setup.ui b/setup/setup.ui
150c9ee
index f1e6d0b..671b84c 100644
095f9c1
--- a/setup/setup.ui
095f9c1
+++ b/setup/setup.ui
150c9ee
@@ -100,6 +100,7 @@
150c9ee
                                 <property name="n_columns">2</property>
150c9ee
                                 <property name="column_spacing">12</property>
150c9ee
                                 <property name="row_spacing">6</property>
150c9ee
+                                <property name="no_show_all">True</property>
150c9ee
                                 <child>
150c9ee
                                   <object class="GtkLabel" id="label8">
150c9ee
                                     <property name="visible">True</property>
150c9ee
@@ -232,7 +233,7 @@
095f9c1
                                   </packing>
095f9c1
                                 </child>
095f9c1
                                 <child>
095f9c1
-                                  <object class="GtkLabel" id="label7">
095f9c1
+                                  <object class="GtkLabel" id="label_trigger_hotkey">
095f9c1
                                     <property name="visible">True</property>
095f9c1
                                     <property name="tooltip_text" translatable="yes">The shortcut keys for turning input method on or off</property>
095f9c1
                                     <property name="xalign">0</property>
150c9ee
@@ -244,7 +245,7 @@
150c9ee
                                   </packing>
150c9ee
                                 </child>
150c9ee
                                 <child>
150c9ee
-                                  <object class="GtkLabel" id="label18">
150c9ee
+                                  <object class="GtkLabel" id="label_enable">
150c9ee
                                     <property name="visible">True</property>
150c9ee
                                     <property name="xalign">0</property>
150c9ee
                                     <property name="label" translatable="yes">Enable:</property>
150c9ee
@@ -257,7 +258,7 @@
150c9ee
                                   </packing>
150c9ee
                                 </child>
150c9ee
                                 <child>
150c9ee
-                                  <object class="GtkHBox" id="hbox2">
150c9ee
+                                  <object class="GtkHBox" id="hbox_enable">
150c9ee
                                     <property name="visible">True</property>
150c9ee
                                     <property name="spacing">6</property>
150c9ee
                                     <child>
150c9ee
@@ -292,7 +293,7 @@
150c9ee
                                   </packing>
150c9ee
                                 </child>
150c9ee
                                 <child>
150c9ee
-                                  <object class="GtkLabel" id="label19">
150c9ee
+                                  <object class="GtkLabel" id="label_disable">
150c9ee
                                     <property name="visible">True</property>
150c9ee
                                     <property name="xalign">0</property>
150c9ee
                                     <property name="label" translatable="yes">Disable:</property>
150c9ee
@@ -305,7 +306,7 @@
150c9ee
                                   </packing>
150c9ee
                                 </child>
150c9ee
                                 <child>
150c9ee
-                                  <object class="GtkHBox" id="hbox3">
150c9ee
+                                  <object class="GtkHBox" id="hbox_disable">
150c9ee
                                     <property name="visible">True</property>
150c9ee
                                     <property name="spacing">6</property>
150c9ee
                                     <child>
150c9ee
@@ -962,6 +963,59 @@ You may use up/down buttons to change it.</i></small></property>
095f9c1
                         <property name="position">1</property>
095f9c1
                       </packing>
095f9c1
                     </child>
095f9c1
+                    <child>
095f9c1
+                      <object class="GtkFrame" id="frame6">
095f9c1
+                        <property name="visible">True</property>
095f9c1
+                        <property name="label_xalign">0</property>
095f9c1
+                        <property name="shadow_type">none</property>
095f9c1
+                        <child>
095f9c1
+                          <object class="GtkAlignment" id="alignment14">
095f9c1
+                            <property name="visible">True</property>
095f9c1
+                            <property name="left_padding">12</property>
095f9c1
+                            <child>
095f9c1
+                              <object class="GtkAlignment" id="alignment15">
095f9c1
+                                <property name="visible">True</property>
095f9c1
+                                <property name="top_padding">6</property>
095f9c1
+                                <property name="left_padding">12</property>
095f9c1
+                                <child>
095f9c1
+                                  <object class="GtkVBox" id="vbox10">
095f9c1
+                                    <property name="visible">True</property>
095f9c1
+                                    <property name="orientation">vertical</property>
095f9c1
+                                    <property name="spacing">6</property>
095f9c1
+                                    <child>
095f9c1
+                                      <object class="GtkCheckButton" id="checkbutton_use_on_off_hotkey">
150c9ee
+                                        <property name="label" translatable="yes">Use toggle shortcut keys to enable or disable an input method</property>
095f9c1
+                                        <property name="visible">True</property>
095f9c1
+                                        <property name="can_focus">True</property>
095f9c1
+                                        <property name="receives_default">False</property>
095f9c1
+                                        <property name="draw_indicator">True</property>
095f9c1
+                                      </object>
095f9c1
+                                      <packing>
095f9c1
+                                        <property name="expand">False</property>
095f9c1
+                                        <property name="fill">False</property>
095f9c1
+                                        <property name="position">0</property>
095f9c1
+                                      </packing>
095f9c1
+                                    </child>
095f9c1
+                                  </object>
095f9c1
+                                </child>
095f9c1
+                              </object>
095f9c1
+                            </child>
095f9c1
+                          </object>
095f9c1
+                        </child>
095f9c1
+                        <child type="label">
095f9c1
+                          <object class="GtkLabel" id="label50">
095f9c1
+                            <property name="visible">True</property>
095f9c1
+                            <property name="label" translatable="yes"><b>Hot keys setting</b></property>
095f9c1
+                            <property name="use_markup">True</property>
095f9c1
+                          </object>
095f9c1
+                        </child>
095f9c1
+                      </object>
095f9c1
+                      <packing>
095f9c1
+                        <property name="expand">False</property>
095f9c1
+                        <property name="fill">False</property>
095f9c1
+                        <property name="position">2</property>
095f9c1
+                      </packing>
095f9c1
+                    </child>
095f9c1
                   </object>
095f9c1
                 </child>
095f9c1
               </object>
63b857f
diff --git a/src/Makefile.am b/src/Makefile.am
47affbc
index 6454522..319df3c 100644
63b857f
--- a/src/Makefile.am
63b857f
+++ b/src/Makefile.am
47affbc
@@ -38,14 +38,16 @@ INTROSPECTION_GIRS =
47affbc
 CLEANFILES =
47affbc
 
47affbc
 # C preprocessor flags
47affbc
-AM_CPPFLAGS =                                   \
47affbc
-    -DG_LOG_DOMAIN=\"IBUS\"                     \
47affbc
-    @GLIB2_CFLAGS@                              \
47affbc
-    @GOBJECT2_CFLAGS@                           \
47affbc
-    @GIO2_CFLAGS@                               \
47affbc
-    -DIBUS_DATA_DIR=\"$(pkgdatadir)\"           \
47affbc
-    -DIBUS_COMPILATION                          \
47affbc
-    -DISOCODES_PREFIX=\"$(ISOCODES_PREFIX)\"    \
47affbc
+AM_CPPFLAGS =                                                           \
47affbc
+    -DG_LOG_DOMAIN=\"IBUS\"                                             \
47affbc
+    @GLIB2_CFLAGS@                                                      \
47affbc
+    @GOBJECT2_CFLAGS@                                                   \
47affbc
+    @GIO2_CFLAGS@                                                       \
47affbc
+    -DIBUS_DATA_DIR=\"$(pkgdatadir)\"                                   \
47affbc
+    -DIBUS_COMPILATION                                                  \
47affbc
+    -DISOCODES_PREFIX=\"$(ISOCODES_PREFIX)\"                            \
47affbc
+    -DUSE_BRIDGE_HOTKEY=$(USE_BRIDGE_HOTKEY)                            \
47affbc
+    -DDEFAULT_BRIDGE_ENGINE_NAME=\"$(DEFAULT_BRIDGE_ENGINE_NAME)\"      \
63b857f
     $(NULL)
63b857f
 
63b857f
 # ibus library
63b857f
diff --git a/src/ibushotkey.c b/src/ibushotkey.c
63b857f
index 32f8338..bef7dfc 100644
63b857f
--- a/src/ibushotkey.c
63b857f
+++ b/src/ibushotkey.c
63b857f
@@ -562,3 +562,14 @@ ibus_hotkey_profile_lookup_hotkey (IBusHotkeyProfile *profile,
63b857f
 
63b857f
     return (GQuark) GPOINTER_TO_UINT (g_tree_lookup (priv->hotkeys, &hotkey));
63b857f
 }
63b857f
+
63b857f
+void
63b857f
+ibus_hotkey_profile_foreach_hotkey (IBusHotkeyProfile *profile,
63b857f
+                                    GTraverseFunc      func,
63b857f
+                                    gpointer           user_data)
63b857f
+{
63b857f
+    IBusHotkeyProfilePrivate *priv;
63b857f
+    priv = IBUS_HOTKEY_PROFILE_GET_PRIVATE (profile);
63b857f
+
63b857f
+    g_tree_foreach (priv->hotkeys, func, user_data);
63b857f
+}
63b857f
diff --git a/src/ibushotkey.h b/src/ibushotkey.h
63b857f
index 9a341f6..92ec6af 100644
63b857f
--- a/src/ibushotkey.h
63b857f
+++ b/src/ibushotkey.h
63b857f
@@ -179,5 +179,16 @@ GQuark           ibus_hotkey_profile_lookup_hotkey
63b857f
                                                  guint               keyval,
63b857f
                                                  guint               modifiers);
63b857f
 
63b857f
+/**
63b857f
+ * ibus_hotkey_profile_foreach_hotkey:
63b857f
+ * @profile: An IBusHotkeyProfile.
63b857f
+ * @func: (scope call): A GTraverseFunc for g_tree_traverse.
63b857f
+ * @user_data: A gpointer for g_tree_traverse.
63b857f
+ */
63b857f
+void             ibus_hotkey_profile_foreach_hotkey
63b857f
+                                                (IBusHotkeyProfile  *profile,
63b857f
+                                                 GTraverseFunc       func,
63b857f
+                                                 gpointer            user_data);
63b857f
+
63b857f
 G_END_DECLS
63b857f
 #endif
5f53fe6
diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c
5f53fe6
index 54e30ae..c37a71d 100644
5f53fe6
--- a/src/ibusinputcontext.c
5f53fe6
+++ b/src/ibusinputcontext.c
5f53fe6
@@ -1219,6 +1219,33 @@ ibus_input_context_set_engine (IBusInputContext *context,
5f53fe6
                        );
5f53fe6
 }
5f53fe6
 
5f53fe6
+void
5f53fe6
+ibus_input_context_set_xkb_engines (IBusInputContext *context,
5f53fe6
+                                    GList            *list)
5f53fe6
+{
5f53fe6
+    GVariantBuilder builder;
5f53fe6
+    GList *p;
5f53fe6
+
5f53fe6
+    g_assert (IBUS_IS_INPUT_CONTEXT (context));
5f53fe6
+    g_assert (list);
5f53fe6
+
5f53fe6
+    g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
5f53fe6
+    for (p = list; p; p = p->next) {
5f53fe6
+        g_variant_builder_add (&builder, "v",
5f53fe6
+                               ibus_serializable_serialize ((IBusSerializable *) p->data));
5f53fe6
+    }
5f53fe6
+
5f53fe6
+    g_dbus_proxy_call ((GDBusProxy *) context,
5f53fe6
+                       "SetXKBEngines",                     /* method_name */
5f53fe6
+                       g_variant_new ("(av)", &builder),    /* parameters */
5f53fe6
+                       G_DBUS_CALL_FLAGS_NONE,              /* flags */
5f53fe6
+                       -1,                                  /* timeout */
5f53fe6
+                       NULL,                                /* cancellable */
5f53fe6
+                       NULL,                                /* callback */
5f53fe6
+                       NULL                                 /* user_data */
5f53fe6
+                       );
5f53fe6
+}
5f53fe6
+
5f53fe6
 #define DEFINE_FUNC(name, Name)                                         \
5f53fe6
     void                                                                \
5f53fe6
     ibus_input_context_##name (IBusInputContext *context)               \
5f53fe6
diff --git a/src/ibusinputcontext.h b/src/ibusinputcontext.h
5f53fe6
index be3c502..40b902e 100644
5f53fe6
--- a/src/ibusinputcontext.h
5f53fe6
+++ b/src/ibusinputcontext.h
5f53fe6
@@ -495,6 +495,18 @@ void         ibus_input_context_set_engine  (IBusInputContext   *context,
5f53fe6
                                              const gchar        *name);
5f53fe6
 
5f53fe6
 /**
5f53fe6
+ * ibus_input_context_set_xkb_engines:
5f53fe6
+ * @context: An IBusInputContext.
5f53fe6
+ * @list: (transfer container) (element-type IBusEngineDesc):
5f53fe6
+ *     A list of the engines.
5f53fe6
+ *
5f53fe6
+ * Set XKB group layouts from the desktop session.
5f53fe6
+ */
5f53fe6
+void         ibus_input_context_set_xkb_engines
5f53fe6
+                                            (IBusInputContext *context,
5f53fe6
+                                             GList            *list);
5f53fe6
+
5f53fe6
+/**
5f53fe6
  * ibus_input_context_set_surrounding_text:
5f53fe6
  * @context: An #IBusInputContext.
5f53fe6
  * @text: An #IBusText surrounding the current cursor on the application.
095f9c1
diff --git a/src/ibusutil.c b/src/ibusutil.c
095f9c1
index ddb6b9e..46dab1a 100644
095f9c1
--- a/src/ibusutil.c
095f9c1
+++ b/src/ibusutil.c
095f9c1
@@ -145,3 +145,15 @@ ibus_get_language_name(const gchar *_locale) {
095f9c1
     }
095f9c1
     return retval;
095f9c1
 }
095f9c1
+
095f9c1
+gboolean
095f9c1
+ibus_use_bridge_hotkey (void)
095f9c1
+{
095f9c1
+    return (USE_BRIDGE_HOTKEY == 1) ? TRUE : FALSE;
095f9c1
+}
095f9c1
+
095f9c1
+const gchar *
095f9c1
+ibus_get_default_bridge_engine_name (void)
095f9c1
+{
095f9c1
+    return DEFAULT_BRIDGE_ENGINE_NAME;
095f9c1
+}
095f9c1
diff --git a/src/ibusutil.h b/src/ibusutil.h
095f9c1
index 7cf1995..a19d16e 100644
095f9c1
--- a/src/ibusutil.h
095f9c1
+++ b/src/ibusutil.h
095f9c1
@@ -43,4 +43,18 @@
095f9c1
  */
095f9c1
 const gchar *    ibus_get_language_name         (const gchar    *_locale);
095f9c1
 
095f9c1
+/**
095f9c1
+ * ibus_bus_use_bridge_hotkey:
095f9c1
+ * @bus: An #IBusBus.
095f9c1
+ * @returns: %TRUE if @bus use bridge hotkey, %FALSE otherwise.
095f9c1
+ */
095f9c1
+gboolean         ibus_use_bridge_hotkey (void);
095f9c1
+
095f9c1
+/**
095f9c1
+ * ibus_bus_get_default_bridge_engine_name:
095f9c1
+ * @bus: An #IBusBus.
095f9c1
+ * @returns: A default bridge engine name.
095f9c1
+ */
095f9c1
+const gchar *    ibus_get_default_bridge_engine_name (void);
095f9c1
+
095f9c1
 #endif
63b857f
diff --git a/ui/gtk/panel.py b/ui/gtk/panel.py
3ef409f
index 8804634..549393a 100644
63b857f
--- a/ui/gtk/panel.py
63b857f
+++ b/ui/gtk/panel.py
0318d1b
@@ -67,6 +67,7 @@ class Panel(ibus.PanelBase):
0318d1b
         self.__data_dir = path.join(self.__prefix, "share", "ibus")
0318d1b
         # self.__icons_dir = path.join(self.__data_dir, "icons")
0318d1b
         self.__setup_cmd = path.join(self.__prefix, "bin", "ibus-setup")
0318d1b
+        self.__show = 0
0318d1b
 
0318d1b
         # connect bus signal
0318d1b
         self.__config.connect("value-changed", self.__config_value_changed_cb)
0318d1b
@@ -133,6 +134,14 @@ class Panel(ibus.PanelBase):
63b857f
         # self.__bus.request_name(ibus.panel.IBUS_SERVICE_PANEL, 0)
63b857f
 
63b857f
         # init xkb
63b857f
+        self.__default_layout = 'default'
63b857f
+        self.__default_model = 'default'
63b857f
+        self.__default_option = 'default'
a4b3ac5
+        self.__disabled_engines = []
47affbc
+        self.__disabled_engines_id = -1
47affbc
+        self.__disabled_engines_prev_id = -1
47affbc
+        self.__disabled_engines_swapped = 0
63b857f
+
63b857f
         self.__xkblayout = ibus.XKBLayout(self.__config)
63b857f
         use_xkb = self.__config.get_value("general", "use_system_keyboard_layout", False)
63b857f
         if not use_xkb:
b4e3b48
@@ -142,11 +151,18 @@ class Panel(ibus.PanelBase):
63b857f
             value = 'default'
63b857f
         if value != 'default':
63b857f
             self.__xkblayout.set_default_layout(value)
63b857f
+            if value.find('(') >= 0:
63b857f
+                self.__default_layout = value.split('(')[0]
63b857f
+                self.__default_model = value.split('(')[1].split(')')[0]
63b857f
+            else:
63b857f
+                self.__default_layout = value
63b857f
+                self.__default_model = None
63b857f
         value = str(self.__config.get_value("general", "system_keyboard_option", ''))
63b857f
         if value == '':
63b857f
             value = 'default'
63b857f
         if value != 'default':
63b857f
             self.__xkblayout.set_default_option(value)
63b857f
+            self.__default_option = value
63b857f
 
63b857f
     def set_cursor_location(self, x, y, w, h):
63b857f
         self.__candidate_panel.set_cursor_location(x, y, w, h)
3ef409f
@@ -233,12 +249,119 @@ class Panel(ibus.PanelBase):
63b857f
     def __set_im_name(self, name):
63b857f
         self.__language_bar.set_im_name(name)
63b857f
 
095f9c1
+    def __use_bridge_hotkey(self):
095f9c1
+        if not ibus.use_bridge_hotkey():
095f9c1
+            return False
095f9c1
+        if self.__config == None:
095f9c1
+            return True
095f9c1
+        return self.__config.get_value("general/hotkey", "use_bridge_hotkey",
095f9c1
+                                       True)
095f9c1
+
3ef409f
+    def __registry_get_lang_from_layout(self, layout, model=None):
3ef409f
+        langs = None
3ef409f
+        lang = 'en'
3ef409f
+        registry = ibus.XKBConfigRegistry()
3ef409f
+        get_layout_lang = registry.get_layout_lang()
3ef409f
+        if model == '':
3ef409f
+            model = None
3ef409f
+        if model != None:
3ef409f
+            label = "%s(%s)" % (layout, model)
3ef409f
+            if label in get_layout_lang:
3ef409f
+                langs = get_layout_lang[label]
3ef409f
+        if langs == None:
3ef409f
+            label = layout
3ef409f
+            if label in get_layout_lang:
3ef409f
+                langs = get_layout_lang[label]
3ef409f
+        if langs != None:
3ef409f
+            lang = str(langs[0])
3ef409f
+        return lang
3ef409f
+
095f9c1
+    def __set_default_layout_engine(self, use_bridge_hotkey):
63b857f
+        default_layout = self.__default_layout
63b857f
+        default_model = self.__default_model
63b857f
+        if default_layout == 'default':
63b857f
+            default_layout = self.__xkblayout.get_default_layout()[0]
47affbc
+            default_model = self.__xkblayout.get_default_layout()[1]
63b857f
+        if default_model == 'default':
63b857f
+            default_model = self.__xkblayout.get_default_layout()[1]
63b857f
+        layouts = default_layout.split(',')
47affbc
+        models = None
63b857f
+        if default_model != None and default_model != '':
63b857f
+            models = default_model.split(',')
a4b3ac5
+        if len(self.__disabled_engines) == 0:
47affbc
+            for i, layout in enumerate(layouts):
47affbc
+                registry = ibus.XKBConfigRegistry()
3ef409f
+                model = None
3ef409f
+                if models != None and i < len(models):
3ef409f
+                    model = models[i]
3ef409f
+                lang = self.__registry_get_lang_from_layout(layout, model)
47affbc
+                model = None
47affbc
+                if i == 0:
47affbc
+                    layout = default_layout
47affbc
+                    model = default_model
a4b3ac5
+                elif models != None and i < len(models):
47affbc
+                    model = models[i]
47affbc
+                if model == '':
47affbc
+                    model = None
47affbc
+                model_desc = _("Default Layout")
e4605fa
+                if i == 0:
e4605fa
+                    l = 0
3ef409f
+                    # layout 'in' and model 'eng' is English layout.
3ef409f
+                    if models != None and model != 'eng':
a4b3ac5
+                        for j in range(0, len(models)):
a4b3ac5
+                            l = l + len(models[j])
e4605fa
+                    if l != 0:
e4605fa
+                        model_desc = model_desc + " (" + model + ")"
e4605fa
+                elif model != None:
47affbc
+                    model_desc = model_desc + " (" + model + ")"
0318d1b
+                name = ibus.DEFAULT_BRIDGE_ENGINE_NAME + "#" + str(i)
47affbc
+                engine = registry.engine_desc_new(lang,
47affbc
+                                                  layout,
47affbc
+                                                  _("Default Layout"),
47affbc
+                                                  model,
095f9c1
+                                                  model_desc,
0318d1b
+                                                  name)
47affbc
+                self.__disabled_engines.append(engine)
47affbc
+            self.__disabled_engines_id = self.__xkblayout.get_group()
5f53fe6
+            if use_bridge_hotkey and len(self.__disabled_engines) > 0:
5f53fe6
+                self.__focus_ic.set_xkb_engines(self.__disabled_engines)
095f9c1
+        if not use_bridge_hotkey:
47affbc
+            return
a4b3ac5
+        if len(self.__disabled_engines) > 0:
095f9c1
+            if self.__focus_ic == None:
095f9c1
+                return
095f9c1
+            engine = self.__focus_ic.get_engine()
095f9c1
+            if engine == None:
095f9c1
+                if self.__disabled_engines_id < 0:
095f9c1
+                    self.__disabled_engines_id = 0
095f9c1
+                self.__focus_ic.focus_in()
095f9c1
+                self.__focus_ic.set_engine(self.__disabled_engines[self.__disabled_engines_id])
095f9c1
+            elif engine != None and \
095f9c1
+                 not self.__focus_ic.is_enabled():
095f9c1
+                self.__focus_ic.focus_in()
095f9c1
+                self.__focus_ic.enable()
63b857f
+
63b857f
     def focus_in(self, ic):
63b857f
         self.reset()
63b857f
         self.__focus_ic = ibus.InputContext(self.__bus, ic)
47affbc
         enabled = self.__focus_ic.is_enabled()
b4e3b48
-        self.__language_bar.set_enabled(enabled)
63b857f
 
095f9c1
+        use_bridge_hotkey = self.__use_bridge_hotkey()
095f9c1
+        self.__set_default_layout_engine(use_bridge_hotkey)
095f9c1
+        if use_bridge_hotkey:
b4e3b48
+            if self.__show != 1:
b4e3b48
+                self.__language_bar.set_enabled(enabled)
b4e3b48
+            elif enabled:
b4e3b48
+                engine = self.__focus_ic.get_engine()
b4e3b48
+                if engine != None and \
095f9c1
+                   not engine.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
b4e3b48
+                    self.__language_bar.set_enabled(enabled)
b4e3b48
+                else:
b4e3b48
+                    self.__language_bar.set_enabled(False)
b4e3b48
+            else:
b4e3b48
+                self.__language_bar.set_enabled(False)
b4e3b48
+        else:
b4e3b48
+            self.__language_bar.set_enabled(enabled)
63b857f
         if not enabled:
63b857f
             self.__set_im_icon(ICON_KEYBOARD)
63b857f
             self.__set_im_name(None)
3ef409f
@@ -247,10 +370,13 @@ class Panel(ibus.PanelBase):
be89530
         else:
be89530
             engine = self.__focus_ic.get_engine()
be89530
             if engine:
be89530
-                self.__set_im_icon(engine.icon)
be89530
+                if engine.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
be89530
+                    self.__set_im_icon(ICON_KEYBOARD)
be89530
+                else:
be89530
+                    self.__set_im_icon(engine.icon)
47affbc
                 self.__set_im_name(engine.longname)
47affbc
                 if self.__bus.get_use_sys_layout():
47affbc
-                    self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine))
47affbc
+                    self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine, False))
47affbc
             else:
47affbc
                 self.__set_im_icon(ICON_KEYBOARD)
47affbc
                 self.__set_im_name(None)
3ef409f
@@ -273,7 +399,21 @@ class Panel(ibus.PanelBase):
b4e3b48
             return
b4e3b48
 
b4e3b48
         enabled = self.__focus_ic.is_enabled()
b4e3b48
-        self.__language_bar.set_enabled(enabled)
b4e3b48
+
095f9c1
+        if self.__use_bridge_hotkey():
b4e3b48
+            if self.__show != 1:
b4e3b48
+                self.__language_bar.set_enabled(enabled)
b4e3b48
+            elif enabled:
b4e3b48
+                engine = self.__focus_ic.get_engine()
b4e3b48
+                if engine != None and \
095f9c1
+                   not engine.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
b4e3b48
+                    self.__language_bar.set_enabled(enabled)
b4e3b48
+                else:
b4e3b48
+                    self.__language_bar.set_enabled(False)
b4e3b48
+            else:
b4e3b48
+                self.__language_bar.set_enabled(False)
b4e3b48
+        else:
b4e3b48
+            self.__language_bar.set_enabled(enabled)
b4e3b48
 
b4e3b48
         if enabled == False:
b4e3b48
             self.reset()
3ef409f
@@ -284,10 +424,13 @@ class Panel(ibus.PanelBase):
be89530
         else:
be89530
             engine = self.__focus_ic.get_engine()
be89530
             if engine:
be89530
-                self.__set_im_icon(engine.icon)
be89530
+                if engine.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
be89530
+                    self.__set_im_icon(ICON_KEYBOARD)
be89530
+                else:
be89530
+                    self.__set_im_icon(engine.icon)
47affbc
                 self.__set_im_name(engine.longname)
47affbc
                 if self.__bus.get_use_sys_layout():
47affbc
-                    self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine))
47affbc
+                    self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine, True))
47affbc
             else:
47affbc
                 self.__set_im_icon(ICON_KEYBOARD)
47affbc
                 self.__set_im_name(None)
3ef409f
@@ -315,6 +458,7 @@ class Panel(ibus.PanelBase):
b4e3b48
 
b4e3b48
     def __config_load_show(self):
b4e3b48
         show = self.__config.get_value("panel", "show", 0)
b4e3b48
+        self.__show = show
b4e3b48
         self.__language_bar.set_show(show)
b4e3b48
 
b4e3b48
     def __config_load_position(self):
3ef409f
@@ -443,6 +587,21 @@ class Panel(ibus.PanelBase):
47affbc
     #     menu.set_take_focus(False)
47affbc
     #     return menu
47affbc
 
47affbc
+    def __add_engine_in_menu(self, menu, engine, is_bold, size):
47affbc
+        language = engine.language
47affbc
+        lang = ibus.get_language_name(language)
47affbc
+        item = gtk.ImageMenuItem("%s - %s" % (lang, engine.longname))
47affbc
+        if is_bold:
47affbc
+            for widget in item.get_children():
47affbc
+                if isinstance(widget, gtk.Label):
47affbc
+                    widget.set_markup("%s" % widget.get_text())
47affbc
+        if engine.icon:
47affbc
+            item.set_image(_icon.IconWidget(engine.icon, size[0]))
47affbc
+        else:
47affbc
+            item.set_image(_icon.IconWidget(ICON_ENGINE, size[0]))
47affbc
+        item.connect("activate", self.__im_menu_item_activate_cb, engine)
47affbc
+        menu.add(item)
47affbc
+
47affbc
     def __create_im_menu(self):
47affbc
         engines = self.__bus.list_active_engines()
47affbc
         current_engine = \
3ef409f
@@ -453,25 +612,39 @@ class Panel(ibus.PanelBase):
63b857f
         size = gtk.icon_size_lookup(gtk.ICON_SIZE_MENU)
63b857f
         menu = gtk.Menu()
63b857f
         for i, engine in enumerate(engines):
63b857f
-            lang = ibus.get_language_name(engine.language)
47affbc
-            item = gtk.ImageMenuItem("%s - %s" % (lang, engine.longname))
47affbc
-            if current_engine and current_engine.name == engine.name:
47affbc
-                for widget in item.get_children():
47affbc
-                    if isinstance(widget, gtk.Label):
47affbc
-                        widget.set_markup("%s" % widget.get_text())
47affbc
-            if engine.icon:
47affbc
-                item.set_image(_icon.IconWidget(engine.icon, size[0]))
47affbc
-            else:
47affbc
-                item.set_image(_icon.IconWidget(ICON_ENGINE, size[0]))
47affbc
-            item.connect("activate", self.__im_menu_item_activate_cb, engine)
47affbc
-            menu.add(item)
0318d1b
+            if engine.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
0318d1b
+                if not self.__use_bridge_hotkey():
0318d1b
+                    continue
a4b3ac5
+                if len(self.__disabled_engines) == 0:
0318d1b
+                    continue
0318d1b
+                engine.disabled_engines_id = -1
47affbc
+                for j, kb_engine in enumerate(self.__disabled_engines):
095f9c1
+                    if engine.name == kb_engine.name:
095f9c1
+                        engine.disabled_engines_id = j
095f9c1
+                        break
0318d1b
+                if engine.disabled_engines_id == -1:
0318d1b
+                    continue
0318d1b
+                kb_engine = self.__disabled_engines[engine.disabled_engines_id]
0318d1b
+                kb_engine.is_bridge = True
0318d1b
+                kb_engine.disabled_engines_id = engine.disabled_engines_id
095f9c1
+                is_bold = True if (current_engine != None and \
0318d1b
+                        current_engine.name == kb_engine.name) else False
0318d1b
+                self.__add_engine_in_menu(menu, kb_engine,
095f9c1
+                                          is_bold,
095f9c1
+                                          size)
47affbc
+                continue
47affbc
+            engine.is_bridge = False
47affbc
+            is_bold = True if (current_engine != None and \
47affbc
+                    current_engine.name == engine.name) else False
47affbc
+            self.__add_engine_in_menu(menu, engine, is_bold, size)
</