[ibus/f15] Added ibus-xx-icon-symbol.patch
Takao Fujiwara
fujiwara at fedoraproject.org
Tue Jun 21 08:50:15 UTC 2011
commit 63b857f037c74b6c91a009b59274099909dc21f1
Author: Takao Fujiwara <tfujiwar at redhat.com>
Date: Tue Jun 21 17:49:07 2011 +0900
Added ibus-xx-icon-symbol.patch
- Added ibus-xx-bridge-hotkey.patch
.gitignore | 2 +
ibus-435880-surrounding-text.patch | 375 --------
ibus-530711-preload-sys.patch | 244 ++++-
ibus-541492-xkb.patch | 1790 ++++++++++++++++++++----------------
ibus-HEAD.patch | 741 +++++++++++++++
ibus-xx-bridge-hotkey.patch | 874 ++++++++++++++++++
ibus-xx-icon-symbol.patch | 331 +++++++
ibus-xx-setup-frequent-lang.patch | 16 +-
ibus.spec | 73 +-
sources | 3 +-
10 files changed, 3228 insertions(+), 1221 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 58ef980..f33ca6e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,5 @@ ibus-1.3.6.tar.gz
/ibus_master_da.po
/ibus-1.3.99.20110419.tar.gz
/gnome-shell-ibus-plugins-20110601.tar.bz2
+/gnome-shell-ibus-plugins-20110621.tar.bz2
+/ibus-indicator.tar.bz2
diff --git a/ibus-530711-preload-sys.patch b/ibus-530711-preload-sys.patch
index b071d6e..7dec5ba 100644
--- a/ibus-530711-preload-sys.patch
+++ b/ibus-530711-preload-sys.patch
@@ -1,12 +1,13 @@
-From 047452beffd7cb429bf4dfeb2371f120cc8041a6 Mon Sep 17 00:00:00 2001
+From 7f81445b3e6613d14f64253506a309095a37c8d7 Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1 at gmail.com>
-Date: Fri, 11 Mar 2011 16:07:09 +0900
+Date: Mon, 20 Jun 2011 19:04:42 +0900
Subject: [PATCH] Reload preload engines until users customize the list.
The idea is, if users don't customize the preload_engines with ibus-setup,
users would prefer to load the system default engines again by login.
The gconf value 'preload_engine_mode' is
-IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE by default.
+IBUS_PRELOAD_ENGINE_MODE_USER by default but set
+IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE for the initial login.
If preload_engine_mode is IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE,
ibus-daemon loads the system preload engines by langs.
If preload_engine_mode is IBUS_PRELOAD_ENGINE_MODE_USER,
@@ -15,22 +16,20 @@ On the other hand, if users enable the customized engine checkbutton
on ibus-setup, ibus-setup sets 'preload_engine_mode' as
IBUS_PRELOAD_ENGINE_MODE_USER and users can customize the value
'preload_engines'.
-Loading system default may spend the startup time. If you mind it,
-your dist may like to put TRUE in 'use_local_preload_engines' value.
---
- bus/ibusimpl.c | 286 +++++++++++++++++++++++++++++++++++---------------
- data/ibus.schemas.in | 13 +++
+ bus/ibusimpl.c | 402 +++++++++++++++++++++++++++++++++++++++-----------
+ data/ibus.schemas.in | 13 ++
ibus/common.py | 6 +
- setup/main.py | 37 ++++++-
+ setup/main.py | 70 ++++++++-
setup/setup.ui | 21 +++-
src/ibustypes.h | 10 ++
- 6 files changed, 279 insertions(+), 94 deletions(-)
+ 6 files changed, 427 insertions(+), 95 deletions(-)
diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c
-index 8d4ec36..0caa8c7 100644
+index a7ae52b..bb4b8ae 100644
--- a/bus/ibusimpl.c
+++ b/bus/ibusimpl.c
-@@ -144,6 +144,9 @@ static void bus_ibus_impl_set_previo
+@@ -144,6 +144,9 @@ static void bus_ibus_impl_set_previous_engine
static void bus_ibus_impl_set_preload_engines
(BusIBusImpl *ibus,
GVariant *value);
@@ -40,10 +39,28 @@ index 8d4ec36..0caa8c7 100644
static void bus_ibus_impl_set_use_sys_layout
(BusIBusImpl *ibus,
GVariant *value);
-@@ -284,6 +287,142 @@ _panel_destroy_cb (BusPanelProxy *panel,
- g_object_unref (panel);
+@@ -285,6 +288,259 @@ _panel_destroy_cb (BusPanelProxy *panel,
}
+ static void
++_config_set_value_done (GObject *object,
++ GAsyncResult *res,
++ gpointer user_data)
++{
++ IBusConfig *config = (IBusConfig *) object;
++ GVariant *value = (GVariant *) user_data;
++ GError *error = NULL;
++
++ g_assert (IBUS_IS_CONFIG (config));
++
++ if (!ibus_config_set_value_async_finish (config, res, &error)) {
++ if (error) {
++ g_error_free (error);
++ }
++ }
++ g_variant_unref (value);
++}
++
+#ifndef OS_CHROMEOS
+static gint
+_engine_desc_cmp (IBusEngineDesc *desc1,
@@ -59,7 +76,7 @@ index 8d4ec36..0caa8c7 100644
+_get_config_preload_engine_mode (BusIBusImpl *ibus)
+{
+ GVariant *variant = NULL;
-+ gint preload_engine_mode = IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE;
++ gint preload_engine_mode = IBUS_PRELOAD_ENGINE_MODE_USER;
+
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+
@@ -68,6 +85,23 @@ index 8d4ec36..0caa8c7 100644
+ }
+
+ variant = ibus_config_get_value (ibus->config, "general",
++ "preload_engines");
++ if (variant == NULL) {
++ /* Set LANG_RELATIVE mode for the initial login */
++ preload_engine_mode = IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE;
++ variant = g_variant_ref_sink (g_variant_new ("i", preload_engine_mode));
++ ibus_config_set_value_async (ibus->config, "general",
++ "preload_engine_mode", variant,
++ -1,
++ NULL,
++ _config_set_value_done,
++ variant);
++ return preload_engine_mode;
++ } else {
++ g_variant_unref (variant);
++ }
++
++ variant = ibus_config_get_value (ibus->config, "general",
+ "preload_engine_mode");
+ if (variant != NULL) {
+ if (g_variant_classify (variant) == G_VARIANT_CLASS_INT32) {
@@ -80,6 +114,82 @@ index 8d4ec36..0caa8c7 100644
+}
+#endif
+
++static int
++_compare_engine_list_value (GVariant *value_a, GVariant *value_b)
++{
++ GVariant *value;
++ GVariantIter iter;
++ const gchar *engine_name = NULL;
++ gchar *concat_engine_names;
++ gchar *concat_engine_names_a = NULL;
++ gchar *concat_engine_names_b = NULL;
++ int retval = 0;
++
++ value = value_a;
++ concat_engine_names = NULL;
++ if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_ARRAY) {
++ g_variant_iter_init (&iter, value);
++ while (g_variant_iter_loop (&iter, "&s", &engine_name)) {
++ gchar *tmp = g_strdup_printf ("%s::%s",
++ concat_engine_names ? concat_engine_names : "",
++ engine_name ? engine_name : "");
++ g_free (concat_engine_names);
++ concat_engine_names = tmp;
++ }
++ }
++ concat_engine_names_a = concat_engine_names;
++
++ value = value_b;
++ concat_engine_names = NULL;
++ if (value != NULL && g_variant_classify (value) == G_VARIANT_CLASS_ARRAY) {
++ g_variant_iter_init (&iter, value);
++ while (g_variant_iter_loop (&iter, "&s", &engine_name)) {
++ gchar *tmp = g_strdup_printf ("%s::%s",
++ concat_engine_names ? concat_engine_names : "",
++ engine_name ? engine_name : "");
++ g_free (concat_engine_names);
++ concat_engine_names = tmp;
++ }
++ }
++ concat_engine_names_b = concat_engine_names;
++
++ retval = g_strcmp0 (concat_engine_names_a, concat_engine_names_b);
++ g_free (concat_engine_names_a);
++ g_free (concat_engine_names_b);
++ return retval;
++}
++
++static void
++_preload_engines_config_get_value_done (GObject *object,
++ GAsyncResult *res,
++ gpointer user_data)
++{
++ IBusConfig *config = (IBusConfig *) object;
++ GVariant *new_value = (GVariant *) user_data;
++ GVariant *value = NULL;
++ GError *error = NULL;
++
++ g_assert (IBUS_IS_CONFIG (config));
++
++ value = ibus_config_get_value_async_finish (config, res, &error);
++ if (error) {
++ g_error_free (error);
++ }
++ if (_compare_engine_list_value (value, new_value) != 0) {
++ ibus_config_set_value_async (config, "general",
++ "preload_engines", new_value,
++ -1,
++ NULL,
++ _config_set_value_done,
++ new_value);
++ } else if (new_value) {
++ g_variant_unref (new_value);
++ }
++ if (value) {
++ g_variant_unref (value);
++ }
++}
++
+static void
+_set_preload_engines (BusIBusImpl *ibus,
+ GVariant *value)
@@ -103,11 +213,16 @@ index 8d4ec36..0caa8c7 100644
+ }
+
+ if (engine_list != NULL &&
-+ ibus->config != NULL &&
-+ ibus_config_get_value (ibus->config, "general",
-+ "preload_engines") == NULL) {
-+ ibus_config_set_value (ibus->config, "general",
-+ "preload_engines", value);
++ ibus->config != NULL) {
++ /* sync function will effects the startup performance.
++ * We'd always like to save the value so that ibus-setup
++ * get the updated engine list. */
++ ibus_config_get_value_async (ibus->config, "general",
++ "preload_engines",
++ -1,
++ NULL,
++ _preload_engines_config_get_value_done,
++ g_variant_ref_sink (value));
+ } else {
+ /* We don't update preload_engines with an empty string for safety.
+ * Just unref the floating value. */
@@ -180,10 +295,11 @@ index 8d4ec36..0caa8c7 100644
+}
+#endif
+
- static void
++static void
bus_ibus_impl_set_hotkey (BusIBusImpl *ibus,
GQuark hotkey,
-@@ -394,35 +533,50 @@ static void
+ GVariant *value)
+@@ -394,35 +650,50 @@ static void
bus_ibus_impl_set_preload_engines (BusIBusImpl *ibus,
GVariant *value)
{
@@ -220,14 +336,14 @@ index 8d4ec36..0caa8c7 100644
+/**
+ * bus_ibus_impl_set_preload_engine_mode:
+ *
-+ * A function to be called when "preload_engines_mode" config is updated.
++ * A function to be called when "preload_engine_mode" config is updated.
+ */
+static void
+bus_ibus_impl_set_preload_engine_mode (BusIBusImpl *ibus,
+ GVariant *value)
+{
+#ifndef OS_CHROMEOS
-+ gint preload_engine_mode = IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE;
++ gint preload_engine_mode = IBUS_PRELOAD_ENGINE_MODE_USER;
- if (ibus->engine_list) {
- BusComponent *component = bus_component_from_engine_desc ((IBusEngineDesc *) ibus->engine_list->data);
@@ -256,7 +372,7 @@ index 8d4ec36..0caa8c7 100644
}
/**
-@@ -503,89 +657,48 @@ bus_ibus_impl_set_use_global_engine (Bus
+@@ -503,89 +774,47 @@ bus_ibus_impl_set_use_global_engine (BusIBusImpl *ibus,
}
}
@@ -279,7 +395,8 @@ index 8d4ec36..0caa8c7 100644
+ * The idea is, if users don't customize the preload_engines with ibus-setup,
+ * users would prefer to load the system default engines again by login.
+ * The gconf value 'preload_engine_mode' is
-+ * IBUS_PRELOAD_ENGINE_MODE_USER by default.
++ * IBUS_PRELOAD_ENGINE_MODE_USER by default but set
++ * IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE for the initial login.
+ * If preload_engine_mode is IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE,
+ * ibus-daemon loads the system preload engines by langs.
+ * If preload_engine_mode is IBUS_PRELOAD_ENGINE_MODE_USER,
@@ -288,8 +405,6 @@ index 8d4ec36..0caa8c7 100644
+ * on ibus-setup, ibus-setup sets 'preload_engine_mode' as
+ * IBUS_PRELOAD_ENGINE_MODE_USER and users can customize the value
+ * 'preload_engines'.
-+ * Loading system default may spend the startup time. If you mind it,
-+ * your dist may like to put TRUE in 'use_local_preload_engines' value.
*/
static void
bus_ibus_impl_set_default_preload_engines (BusIBusImpl *ibus)
@@ -298,7 +413,7 @@ index 8d4ec36..0caa8c7 100644
- g_assert (BUS_IS_IBUS_IMPL (ibus));
-
static gboolean done = FALSE;
-+ gint preload_engine_mode = IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE;
++ gint preload_engine_mode = IBUS_PRELOAD_ENGINE_MODE_USER;
+
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
@@ -369,16 +484,16 @@ index 8d4ec36..0caa8c7 100644
#endif
}
-@@ -601,6 +714,7 @@ const static struct {
+@@ -601,6 +830,7 @@ const static struct {
{ "general/hotkey", "next_engine_in_menu", bus_ibus_impl_set_next_engine_in_menu },
{ "general/hotkey", "previous_engine", bus_ibus_impl_set_previous_engine },
{ "general", "preload_engines", bus_ibus_impl_set_preload_engines },
-+ { "general", "preload_engines_mode", bus_ibus_impl_set_preload_engine_mode },
++ { "general", "preload_engine_mode", bus_ibus_impl_set_preload_engine_mode },
{ "general", "use_system_keyboard_layout", bus_ibus_impl_set_use_sys_layout },
{ "general", "use_global_engine", bus_ibus_impl_set_use_global_engine },
{ "general", "embed_preedit_text", bus_ibus_impl_set_embed_preedit_text },
diff --git a/data/ibus.schemas.in b/data/ibus.schemas.in
-index 7ca4899..39922a0 100644
+index 7ca4899..d4334e1 100644
--- a/data/ibus.schemas.in
+++ b/data/ibus.schemas.in
@@ -13,6 +13,19 @@
@@ -389,7 +504,7 @@ index 7ca4899..39922a0 100644
+ <applyto>/desktop/ibus/general/preload_engine_mode</applyto>
+ <owner>ibus</owner>
+ <type>int</type>
-+ <default>1</default>
++ <default>0</default>
+ <locale name="C">
+ <short>Preload engine mode</short>
+ <long>Preload engines are loaded with this mode.
@@ -402,7 +517,7 @@ index 7ca4899..39922a0 100644
<applyto>/desktop/ibus/general/hotkey/trigger</applyto>
<owner>ibus</owner>
diff --git a/ibus/common.py b/ibus/common.py
-index e105f18..20c0710 100644
+index 6483aae..127ed93 100644
--- a/ibus/common.py
+++ b/ibus/common.py
@@ -40,6 +40,8 @@ __all__ = (
@@ -426,10 +541,18 @@ index e105f18..20c0710 100644
pass
diff --git a/setup/main.py b/setup/main.py
-index 7f4a040..9cdce02 100644
+index 7f4a040..192fb88 100644
--- a/setup/main.py
+++ b/setup/main.py
-@@ -213,15 +213,22 @@ class Setup(object):
+@@ -92,6 +92,7 @@ class Setup(object):
+ # keyboard shortcut
+ # trigger
+ self.__config = self.__bus.get_config()
++ self.__config.connect("value-changed", self.__config_value_changed_cb)
+ shortcuts = self.__config.get_value(
+ "general/hotkey", "trigger",
+ ibus.CONFIG_GENERAL_SHORTCUT_TRIGGER_DEFAULT)
+@@ -213,15 +214,22 @@ class Setup(object):
self.__checkbutton_use_global_engine.connect("toggled", self.__checkbutton_use_global_engine_toggled_cb)
# init engine page
@@ -457,7 +580,7 @@ index 7f4a040..9cdce02 100644
self.__treeview = self.__builder.get_object("treeview_engines")
self.__treeview.set_engines(engines)
-@@ -265,6 +272,13 @@ class Setup(object):
+@@ -265,6 +273,26 @@ class Setup(object):
engine_names = map(lambda e: e.name, engines)
self.__config.set_list("general", "preload_engines", engine_names, "s")
@@ -468,10 +591,23 @@ index 7f4a040..9cdce02 100644
+ engines = [tmp_dict[name] for name in engine_names if name in tmp_dict]
+ return engines
+
++ def __compare_descs(self, engines_a, engines_b):
++ engines = engines_a
++ concat_engine_names = ""
++ for engine in engines:
++ concat_engine_names = "%s::%s" % (concat_engine_names, engine.name)
++ concat_engine_names_a = concat_engine_names
++ engines = engines_b
++ concat_engine_names = ""
++ for engine in engines:
++ concat_engine_names = "%s::%s" % (concat_engine_names, engine.name)
++ concat_engine_names_b = concat_engine_names
++ return concat_engine_names_a == concat_engine_names_b
++
def __button_engine_add_cb(self, button):
engine = self.__combobox.get_active_engine()
self.__treeview.append_engine(engine)
-@@ -276,6 +290,19 @@ class Setup(object):
+@@ -276,6 +304,32 @@ class Setup(object):
about.run()
about.destroy()
@@ -483,6 +619,19 @@ index 7f4a040..9cdce02 100644
+ self.__builder.get_object("hbox_customize_active_input_methods").set_sensitive(True)
+ self.__treeview.notify("engines")
+ else:
++ message = _("The list of your saved input methods will be " \
++ "cleared immediately and the list will be " \
++ "configured by the login language every time. " \
++ "Do you agree with this?")
++ dlg = gtk.MessageDialog(type = gtk.MESSAGE_QUESTION,
++ buttons = gtk.BUTTONS_YES_NO,
++ message_format = message)
++ id = dlg.run()
++ dlg.destroy()
++ self.__flush_gtk_events()
++ if id != gtk.RESPONSE_YES:
++ button.set_active(True)
++ return
+ self.__config.set_value("general",
+ "preload_engine_mode",
+ ibus.common.PRELOAD_ENGINE_MODE_LANG_RELATIVE)
@@ -491,6 +640,19 @@ index 7f4a040..9cdce02 100644
def __init_bus(self):
try:
self.__bus = ibus.Bus()
+@@ -466,7 +520,11 @@ class Setup(object):
+ self.__config.set_value("general", "use_global_engine", value)
+
+ def __config_value_changed_cb(self, bus, section, name, value):
+- pass
++ if section == 'general' and name == 'preload_engines':
++ engines = self.__get_engine_descs_from_names(value)
++ current_engines = self.__treeview.get_engines()
++ if self.__compare_descs(engines, current_engines) == False:
++ self.__treeview.set_engines(engines)
+
+ def __config_reloaded_cb(self, bus):
+ pass
diff --git a/setup/setup.ui b/setup/setup.ui
index f1e6d0b..562c091 100644
--- a/setup/setup.ui
@@ -538,11 +700,11 @@ index f1e6d0b..562c091 100644
</child>
</object>
diff --git a/src/ibustypes.h b/src/ibustypes.h
-index 035d124..0a9d7b2 100644
+index 6a31847..14b44fc 100644
--- a/src/ibustypes.h
+++ b/src/ibustypes.h
-@@ -177,6 +177,16 @@ typedef enum {
- } IBusBusRequestNameReply;
+@@ -186,6 +186,16 @@ typedef enum {
+ } IBusError;
/**
+ * IBusPreloadEngineMode:
@@ -559,5 +721,5 @@ index 035d124..0a9d7b2 100644
* @x: x coordinate.
* @y: y coordinate.
--
-1.7.4.1
+1.7.4.4
diff --git a/ibus-541492-xkb.patch b/ibus-541492-xkb.patch
index 9100d48..21f0694 100644
--- a/ibus-541492-xkb.patch
+++ b/ibus-541492-xkb.patch
@@ -1,6 +1,6 @@
-From b6b83e9484abad910271b15222d3f76f206a1ff6 Mon Sep 17 00:00:00 2001
+From 7fab90a9962d3b4f8eff40cf08939873575d153e Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1 at gmail.com>
-Date: Wed, 1 Jun 2011 18:24:10 +0900
+Date: Tue, 21 Jun 2011 11:34:52 +0900
Subject: [PATCH] Add XKB layouts
---
@@ -12,30 +12,36 @@ Subject: [PATCH] Add XKB layouts
ibus/__init__.py | 2 +
ibus/bus.py | 3 +
ibus/interface/iibus.py | 3 +
- ibus/xkblayout.py.in | 225 ++++++++++++++
- ibus/xkbxml.py.in | 413 ++++++++++++++++++++++++++
+ ibus/xkblayout.py.in | 225 ++++++++++++++++
+ ibus/xkbxml.py.in | 413 ++++++++++++++++++++++++++++++
setup/Makefile.am | 1 +
setup/enginecombobox.py | 7 +-
setup/main.py | 3 +
- setup/setup.ui | 609 ++++++++++++++++++++++++++++++++++++++-
- setup/xkbsetup.py | 454 +++++++++++++++++++++++++++++
+ setup/setup.ui | 609 +++++++++++++++++++++++++++++++++++++++++++-
+ setup/xkbsetup.py | 454 +++++++++++++++++++++++++++++++++
+ src/Makefile.am | 5 +
+ src/ibus.h | 1 +
src/ibusfactory.c | 21 ++-
src/ibusfactory.h | 5 +-
+ src/ibusxkbxml.c | 440 ++++++++++++++++++++++++++++++++
+ src/ibusxkbxml.h | 172 +++++++++++++
ui/gtk/panel.py | 39 +++
- xkb/Makefile.am | 104 +++++++
- xkb/ibus-engine-xkb-main.c | 397 +++++++++++++++++++++++++
- xkb/ibus-engine-xkb-main.h | 46 +++
- xkb/ibus-xkb-main.c | 105 +++++++
- xkb/xkblayout.xml.in | 16 +
+ xkb/Makefile.am | 104 ++++++++
+ xkb/ibus-engine-xkb-main.c | 397 +++++++++++++++++++++++++++++
+ xkb/ibus-engine-xkb-main.h | 46 ++++
+ xkb/ibus-xkb-main.c | 112 ++++++++
+ xkb/xkblayout.xml.in | 16 ++
xkb/xkblayoutconfig.xml.in | 6 +
- xkb/xkblib.c | 303 +++++++++++++++++++
- xkb/xkblib.h | 40 +++
- xkb/xkbxml.c | 696 ++++++++++++++++++++++++++++++++++++++++++++
- xkb/xkbxml.h | 189 ++++++++++++
- 28 files changed, 3808 insertions(+), 6 deletions(-)
+ xkb/xkblib.c | 327 ++++++++++++++++++++++++
+ xkb/xkblib.h | 41 +++
+ xkb/xkbxml.c | 335 ++++++++++++++++++++++++
+ xkb/xkbxml.h | 110 ++++++++
+ 32 files changed, 4018 insertions(+), 6 deletions(-)
create mode 100644 ibus/xkblayout.py.in
create mode 100644 ibus/xkbxml.py.in
create mode 100644 setup/xkbsetup.py
+ create mode 100644 src/ibusxkbxml.c
+ create mode 100644 src/ibusxkbxml.h
create mode 100644 xkb/Makefile.am
create mode 100644 xkb/ibus-engine-xkb-main.c
create mode 100644 xkb/ibus-engine-xkb-main.h
@@ -48,7 +54,7 @@ Subject: [PATCH] Add XKB layouts
create mode 100644 xkb/xkbxml.h
diff --git a/Makefile.am b/Makefile.am
-index 29c57e1..dbe0b6b 100644
+index 7be558b..59fbabb 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -42,6 +42,12 @@ DAEMON_DIRS = \
@@ -73,7 +79,7 @@ index 29c57e1..dbe0b6b 100644
$(NULL)
diff --git a/configure.ac b/configure.ac
-index 8da8c6e..ce1526c 100644
+index 5544dfa..85e5e30 100644
--- a/configure.ac
+++ b/configure.ac
@@ -185,6 +185,60 @@ else
@@ -297,7 +303,7 @@ index 678d517..7de56fc 100644
diff --git a/ibus/xkblayout.py.in b/ibus/xkblayout.py.in
new file mode 100644
-index 0000000..6097ed1
+index 0000000..637f6c1
--- /dev/null
+++ b/ibus/xkblayout.py.in
@@ -0,0 +1,225 @@
@@ -305,9 +311,9 @@ index 0000000..6097ed1
+#
+# ibus - The Input Bus
+#
-+# Copyright (c) 2010 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang at gmail.com>
-+# Copyright (c) 2007-2010 Red Hat, Inc.
++# Copyright (c) 2011 Takao Fujiwara <takao.fujiwara1 at gmail.com>
++# Copyright (c) 2011 Peng Huang <shawn.p.huang at gmail.com>
++# Copyright (c) 2011 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
@@ -371,6 +377,16 @@ index 0000000..6097ed1
+ option = ','.join(option_array)
+ return (layout, option)
+
++ def __get_output_from_cmdline(self, arg, string):
++ exec_command = "%s %s" % (self.__command, arg)
++ retval = None
++ for line in os.popen(exec_command).readlines():
++ line = line.strip()
++ if line.startswith(string):
++ retval = line[len(string):]
++ break
++ return retval
++
+ def use_xkb(self, enable):
+ if self.__command == None:
+ return
@@ -379,38 +395,22 @@ index 0000000..6097ed1
+ def get_layout(self):
+ if not self.__use_xkb:
+ return None
-+ exec_command = "%s %s" % (self.__command, "--get")
-+ retval = None
-+ for line in os.popen(exec_command).readlines():
-+ line = line.strip()
-+ if line.startswith("layout: "):
-+ retval = line[len("layout: "):]
-+ break
-+ return retval
++ return self.__get_output_from_cmdline("--get", "layout: ")
+
+ def get_model(self):
+ if not self.__use_xkb:
+ return None
-+ exec_command = "%s %s" % (self.__command, "--get")
-+ retval = None
-+ for line in os.popen(exec_command).readlines():
-+ line = line.strip()
-+ if line.startswith("model: "):
-+ retval = line[len("model: "):]
-+ break
-+ return retval
++ return self.__get_output_from_cmdline("--get", "model: ")
+
+ def get_option(self):
+ if not self.__use_xkb:
+ return None
-+ exec_command = "%s %s" % (self.__command, "--get")
-+ retval = None
-+ for line in os.popen(exec_command).readlines():
-+ line = line.strip()
-+ if line.startswith("option: "):
-+ retval = line[len("option: "):]
-+ break
-+ return retval
++ return self.__get_output_from_cmdline("--get", "option: ")
++
++ def get_group(self):
++ if not self.__use_xkb:
++ return 0
++ return int(self.__get_output_from_cmdline("--get-group", "group: "))
+
+ def set_layout(self, layout="default", model="default", option="default"):
+ if not self.__use_xkb:
@@ -520,6 +520,12 @@ index 0000000..6097ed1
+ self.__default_option = option
+ self.__time_lag_session_xkb_option = False
+
++ def get_default_layout(self):
++ return [self.__default_layout, self.__default_model];
++
++ def get_default_option(self):
++ return self.__default_option
++
+ def reload_default_layout(self):
+ if not self.__use_xkb:
+ return
@@ -528,7 +534,7 @@ index 0000000..6097ed1
+ self.__default_option = self.get_option()
diff --git a/ibus/xkbxml.py.in b/ibus/xkbxml.py.in
new file mode 100644
-index 0000000..57f54da
+index 0000000..7e5a44e
--- /dev/null
+++ b/ibus/xkbxml.py.in
@@ -0,0 +1,413 @@
@@ -536,9 +542,9 @@ index 0000000..57f54da
+#
+# ibus - The Input Bus
+#
-+# Copyright (c) 2010 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang at gmail.com>
-+# Copyright (c) 2007-2010 Red Hat, Inc.
++# Copyright (c) 2011 Takao Fujiwara <takao.fujiwara1 at gmail.com>
++# Copyright (c) 2011 Peng Huang <shawn.p.huang at gmail.com>
++# Copyright (c) 2011 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
@@ -1664,7 +1670,7 @@ index 0a69df8..f1e6d0b 100644
</interface>
diff --git a/setup/xkbsetup.py b/setup/xkbsetup.py
new file mode 100644
-index 0000000..74d5212
+index 0000000..1685bff
--- /dev/null
+++ b/setup/xkbsetup.py
@@ -0,0 +1,454 @@
@@ -1672,9 +1678,9 @@ index 0000000..74d5212
+#
+# ibus - The Input Bus
+#
-+# Copyright (c) 2010 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang at gmail.com>
-+# Copyright (c) 2007-2010 Red Hat, Inc.
++# Copyright (c) 2011 Takao Fujiwara <takao.fujiwara1 at gmail.com>
++# Copyright (c) 2011 Peng Huang <shawn.p.huang at gmail.com>
++# Copyright (c) 2011 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
@@ -2122,6 +2128,34 @@ index 0000000..74d5212
+ label.set_text(label.get_text())
+ expander.set_data("checked", checked)
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index a53bd23..6454522 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -184,6 +184,11 @@ typelibs_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+ CLEANFILES += $(dist_gir_DATA) $(typelibs_DATA)
+ endif
+
++if ENABLE_XKB
++ibus_sources += ibusxkbxml.c
++ibus_headers += ibusxkbxml.h
++endif
++
+ # gen enum types
+ ibusenumtypes.h: $(ibus_headers) ibusenumtypes.h.template
+ $(AM_V_GEN) ( top_builddir=`cd $(top_builddir) && pwd`; \
+diff --git a/src/ibus.h b/src/ibus.h
+index c408f3d..6bb9ff5 100644
+--- a/src/ibus.h
++++ b/src/ibus.h
+@@ -44,6 +44,7 @@
+ #include <ibuskeymap.h>
+ #include <ibusenumtypes.h>
+ #include <ibushotkey.h>
++#include <ibusxkbxml.h>
+ #include <ibusxml.h>
+ #include <ibusenginedesc.h>
+ #include <ibusobservedpath.h>
diff --git a/src/ibusfactory.c b/src/ibusfactory.c
index 11d9a6d..7770216 100644
--- a/src/ibusfactory.c
@@ -2202,219 +2236,18 @@ index 47c06e0..102081c 100644
};
/**
-diff --git a/ui/gtk/panel.py b/ui/gtk/panel.py
-index 90be1d5..de64920 100644
---- a/ui/gtk/panel.py
-+++ b/ui/gtk/panel.py
-@@ -132,6 +132,22 @@ class Panel(ibus.PanelBase):
- self.__config_load_show_im_name()
- # self.__bus.request_name(ibus.panel.IBUS_SERVICE_PANEL, 0)
-
-+ # init xkb
-+ self.__xkblayout = ibus.XKBLayout(self.__config)
-+ use_xkb = self.__config.get_value("general", "use_system_keyboard_layout", False)
-+ if not use_xkb:
-+ self.__xkblayout.use_xkb(use_xkb)
-+ value = str(self.__config.get_value("general", "system_keyboard_layout", ''))
-+ if value == '':
-+ value = 'default'
-+ if value != 'default':
-+ self.__xkblayout.set_default_layout(value)
-+ value = str(self.__config.get_value("general", "system_keyboard_option", ''))
-+ if value == '':
-+ value = 'default'
-+ if value != 'default':
-+ self.__xkblayout.set_default_option(value)
-+
- def set_cursor_location(self, x, y, w, h):
- self.__candidate_panel.set_cursor_location(x, y, w, h)
-
-@@ -226,14 +242,20 @@ class Panel(ibus.PanelBase):
- if not enabled:
- self.__set_im_icon(ICON_KEYBOARD)
- self.__set_im_name(None)
-+ if self.__bus.get_use_sys_layout():
-+ self.__xkblayout.set_layout()
- else:
- engine = self.__focus_ic.get_engine()
- if engine:
- self.__set_im_icon(engine.icon)
- self.__set_im_name(engine.longname)
-+ if self.__bus.get_use_sys_layout():
-+ self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine))
- else:
- self.__set_im_icon(ICON_KEYBOARD)
- self.__set_im_name(None)
-+ if self.__bus.get_use_sys_layout():
-+ self.__xkblayout.set_layout()
- self.__language_bar.focus_in()
-
- def focus_out(self, ic):
-@@ -243,6 +265,8 @@ class Panel(ibus.PanelBase):
- self.__language_bar.focus_out()
- self.__set_im_icon(ICON_KEYBOARD)
- self.__set_im_name(None)
-+ if self.__bus.get_use_sys_layout():
-+ self.__xkblayout.set_layout()
-
- def state_changed(self):
- if not self.__focus_ic:
-@@ -255,14 +279,20 @@ class Panel(ibus.PanelBase):
- self.reset()
- self.__set_im_icon(ICON_KEYBOARD)
- self.__set_im_name(None)
-+ if self.__bus.get_use_sys_layout():
-+ self.__xkblayout.set_layout()
- else:
- engine = self.__focus_ic.get_engine()
- if engine:
- self.__set_im_icon(engine.icon)
- self.__set_im_name(engine.longname)
-+ if self.__bus.get_use_sys_layout():
-+ self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine))
- else:
- self.__set_im_icon(ICON_KEYBOARD)
- self.__set_im_name(None)
-+ if self.__bus.get_use_sys_layout():
-+ self.__xkblayout.set_layout()
-
-
- def reset(self):
-@@ -542,3 +572,12 @@ class Panel(ibus.PanelBase):
- flags=glib.SPAWN_DO_NOT_REAP_CHILD)[0]
- self.__setup_pid = pid
- glib.child_watch_add(self.__setup_pid, self.__child_watch_cb)
-+
-+ def __engine_get_layout_wrapper(self, engine):
-+ # This code is for the back compatibility.
-+ # Should we remove the codes after all IM engines are changed
-+ # to "default" layout?
-+ if engine.name != None and engine.name.startswith("xkb:layout:"):
-+ return engine.layout
-+ else:
-+ return "default"
-diff --git a/xkb/Makefile.am b/xkb/Makefile.am
-new file mode 100644
-index 0000000..64b1fc8
---- /dev/null
-+++ b/xkb/Makefile.am
-@@ -0,0 +1,104 @@
-+# vim:set noet ts=4:
-+#
-+# ibus - The Input Bus
-+#
-+# Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang at gmail.com>
-+# Copyright (c) 2007-2010 Red Hat, Inc.
-+#
-+# This library is free software; you can redistribute it and/or
-+# modify it under the terms of the GNU Lesser General Public
-+# License as published by the Free Software Foundation; either
-+# version 2 of the License, or (at your option) any later version.
-+#
-+# This library is distributed in the hope that it will be useful,
-+# but WITHOUT ANY WARRANTY; without even the implied warranty of
-+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+# GNU Lesser General Public License for more details.
-+#
-+# You should have received a copy of the GNU Lesser General Public
-+# License along with this program; if not, write to the
-+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
-+# Boston, MA 02111-1307 USA
-+
-+libibus = $(top_builddir)/src/libibus- at IBUS_API_VERSION@.la
-+
-+INCLUDES = \
-+ -I$(top_srcdir) \
-+ -I$(top_srcdir)/src \
-+ -DIBUS_LOCALEDIR=\"$(datadir)/locale\" \
-+ -DLIBEXECDIR=\""$(libexecdir)"\" \
-+ $(NULL)
-+
-+noinst_PROGRAMS = $(TESTS)
-+libexec_PROGRAMS =
-+EXTRA_DIST =
-+DISTCLEANFILES =
-+
-+if ENABLE_XKB
-+libexec_PROGRAMS += ibus-xkb
-+ibus_xkb_SOURCES = \
-+ ibus-xkb-main.c \
-+ xkblib.h \
-+ xkblib.c \
-+ $(NULL)
-+ibus_xkb_CFLAGS = \
-+ @XKB_CFLAGS@ \
-+ @X11_CFLAGS@ \
-+ @GLIB2_CFLAGS@ \
-+ $(NULL)
-+ibus_xkb_LDADD = \
-+ @XKB_LIBS@ \
-+ @X11_LIBS@ \
-+ @GLIB2_LIBS@ \
-+ $(libibus) \
-+ $(NULL)
-+
-+libexec_PROGRAMS += ibus-engine-xkb
-+ibus_engine_xkb_SOURCES = \
-+ ibus-engine-xkb-main.c \
-+ ibus-engine-xkb-main.h \
-+ xkbxml.c \
-+ xkbxml.h \
-+ $(NULL)
-+ibus_engine_xkb_CFLAGS = \
-+ @GLIB2_CFLAGS@ \
-+ @GOBJECT2_CFLAGS@ \
-+ @GCONF_CFLAGS@ \
-+ $(NULL)
-+ibus_engine_xkb_LDADD = \
-+ @GLIB2_LIBS@ \
-+ @GOBJECT2_LIBS@ \
-+ @GCONF_LIBS@ \
-+ $(libibus) \
-+ $(NULL)
-+
-+xkblayoutdir = $(datadir)/ibus/component
-+xkblayout_in_files = xkblayout.xml.in
-+xkblayout_DATA = $(xkblayout_in_files:.xml.in=.xml)
-+
-+xkblayoutconfigdir = $(datadir)/ibus/xkb
-+xkblayoutconfig_in_files = xkblayoutconfig.xml.in
-+xkblayoutconfig_DATA = $(xkblayoutconfig_in_files:.xml.in=.xml)
-+
-+%.xml : %.xml.in
-+ @sed -e "s|\@libexecdir\@|$(libexecdir)|g" \
-+ -e "s|\@datadir\@|$(datadir)|g" \
-+ -e "s|\@XKB_PRELOAD_LAYOUTS\@|$(XKB_PRELOAD_LAYOUTS)|g" \
-+ $< > $@
-+
-+INCLUDES += \
-+ -DXKBLAYOUTCONFIG_FILE=\""$(xkblayoutconfigdir)/$(xkblayoutconfig_DATA)"\" \
-+ $(NULL)
-+
-+EXTRA_DIST += \
-+ $(xkblayout_in_files) \
-+ $(xkblayoutconfig_in_files) \
-+ $(NULL)
-+
-+DISTCLEANFILES += \
-+ $(xkblayout_DATA) \
-+ $(xkblayoutconfig_DATA) \
-+ $(NULL)
-+
-+endif
-diff --git a/xkb/ibus-engine-xkb-main.c b/xkb/ibus-engine-xkb-main.c
+diff --git a/src/ibusxkbxml.c b/src/ibusxkbxml.c
new file mode 100644
-index 0000000..e1861e8
+index 0000000..c630eb9
--- /dev/null
-+++ b/xkb/ibus-engine-xkb-main.c
-@@ -0,0 +1,397 @@
++++ b/src/ibusxkbxml.c
+@@ -0,0 +1,440 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* vim:set et sts=4: */
+/* bus - The Input Bus
-+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright (C) 2008-2010 Red Hat, Inc.
++ * Copyright (C) 2011 Takao Fujiwara <takao.fujiwara1 at gmail.com>
++ * Copyright (C) 2011 Peng Huang <shawn.p.huang at gmail.com>
++ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
@@ -2435,29 +2268,854 @@ index 0000000..e1861e8
+#include <config.h>
+#endif
+
-+#include <gconf/gconf-client.h>
-+#include <ibus.h>
-+#include <stdlib.h>
++#include <glib.h>
+
-+#ifdef ENABLE_NLS
-+#include <locale.h>
-+#endif
++#include "ibus.h"
+
-+#include "ibus-engine-xkb-main.h"
-+#include "xkbxml.h"
++#ifndef XKB_RULES_XML_FILE
++#define XKB_RULES_XML_FILE "/usr/share/X11/xkb/rules/evdev.xml"
++#endif
+
-+#define IBUS_TYPE_XKB_ENGINE (ibus_xkb_engine_get_type ())
++#define IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE(o) \
++ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryPrivate))
+
-+static IBusBus *bus = NULL;
-+static IBusFactory *factory = NULL;
-+static IBusEngineClass *parent_class = NULL;
-+static gboolean ibus = FALSE;
-+static gboolean xml = FALSE;
++typedef struct _IBusXKBConfigRegistryPrivate IBusXKBConfigRegistryPrivate;
+
-+static const GOptionEntry entries[] =
-+{
-+ { "ibus", 'i', 0, G_OPTION_ARG_NONE, &ibus, "component is executed by ibus", NULL },
-+ { "xml", 'x', 0, G_OPTION_ARG_NONE, &xml, "print component xml", NULL },
++struct _IBusXKBConfigRegistryPrivate {
++ GHashTable *layout_list;
++ GHashTable *layout_lang;
++ GHashTable *layout_desc;
++ GHashTable *variant_desc;
++};
++
++
++/* functions prototype */
++static void ibus_xkb_config_registry_destroy
++ (IBusXKBConfigRegistry *xkb_config);
++
++G_DEFINE_TYPE (IBusXKBConfigRegistry, ibus_xkb_config_registry, IBUS_TYPE_OBJECT)
++
++static void
++parse_xkb_xml_languagelist_node (IBusXKBConfigRegistryPrivate *priv,
++ XMLNode *parent_node,
++ const gchar *layout_name)
++{
++ XMLNode *node = parent_node;
++ XMLNode *sub_node;
++ GList *p;
++ GList *lang_list = NULL;
++
++ g_assert (node != NULL);
++ g_assert (layout_name != NULL);
++ for (p = node->sub_nodes; p; p = p->next) {
++ sub_node = (XMLNode *) p->data;
++ if (g_strcmp0 (sub_node->name, "iso639Id") == 0) {
++ lang_list = g_list_append (lang_list,
++ (gpointer) g_strdup (sub_node->text));
++ continue;
++ }
++ }
++ if (lang_list == NULL) {
++ /* some nodes have no lang */
++ return;
++ }
++ if (g_hash_table_lookup (priv->layout_lang, layout_name) != NULL) {
++ g_warning ("duplicated name %s exists", layout_name);
++ return;
++ }
++ g_hash_table_insert (priv->layout_lang,
++ (gpointer) g_strdup (layout_name),
++ (gpointer) lang_list);
++}
++
++static const gchar *
++parse_xkb_xml_configitem_node (IBusXKBConfigRegistryPrivate *priv,
++ XMLNode *parent_node)
++{
++ XMLNode *node = parent_node;
++ XMLNode *sub_node;
++ GList *p;
++ gchar *name = NULL;
++ gchar *description = NULL;
++
++ g_assert (node != NULL);
++ for (p = node->sub_nodes; p; p = p->next) {
++ sub_node = (XMLNode *) p->data;
++ if (g_strcmp0 (sub_node->name, "name") == 0) {
++ name = sub_node->text;
++ continue;
++ }
++ if (g_strcmp0 (sub_node->name, "description") == 0) {
++ description = sub_node->text;
++ continue;
++ }
++ if (g_strcmp0 (sub_node->name, "languageList") == 0) {
++ if (name == NULL) {
++ g_warning ("layout name is NULL in node %s", node->name);
++ continue;
++ }
++ parse_xkb_xml_languagelist_node (priv, sub_node, name);
++ continue;
++ }
++ }
++ if (name == NULL) {
++ g_warning ("No name in layout node");
++ return NULL;
++ }
++ if (g_hash_table_lookup (priv->layout_desc, name) != NULL) {
++ g_warning ("duplicated name %s exists", name);
++ return name;
++ }
++ g_hash_table_insert (priv->layout_desc,
++ (gpointer) g_strdup (name),
++ (gpointer) g_strdup (description));
++
++ return name;
++}
++
++static const gchar *
++parse_xkb_xml_variant_configitem_node (IBusXKBConfigRegistryPrivate *priv,
++ XMLNode *parent_node,
++ const gchar *layout_name)
++{
++ XMLNode *node = parent_node;
++ XMLNode *sub_node;
++ GList *p;
++ gchar *name = NULL;
++ gchar *description = NULL;
++ gchar *variant_lang_name = NULL;
++
++ g_assert (node != NULL);
++ g_assert (layout_name != NULL);
++ for (p = node->sub_nodes; p; p = p->next) {
++ sub_node = (XMLNode *) p->data;
++ if (g_strcmp0 (sub_node->name, "name") == 0) {
++ name = sub_node->text;
++ continue;
++ }
++ if (g_strcmp0 (sub_node->name, "description") == 0) {
++ description = sub_node->text;
++ continue;
++ }
++ if (g_strcmp0 (sub_node->name, "languageList") == 0) {
++ if (name == NULL) {
++ g_warning ("layout name is NULL in node %s", node->name);
++ continue;
++ }
++ variant_lang_name = g_strdup_printf ("%s(%s)", layout_name, name);
++ parse_xkb_xml_languagelist_node (priv, sub_node, variant_lang_name);
++ g_free (variant_lang_name);
++ continue;
++ }
++ }
++ if (name == NULL) {
++ g_warning ("No name in layout node");
++ return NULL;
++ }
++ if (g_hash_table_lookup (priv->variant_desc, name) != NULL) {
++ /* This is an expected case. */
++ return name;
++ }
++ g_hash_table_insert (priv->variant_desc,
++ (gpointer) g_strdup (name),
++ (gpointer) g_strdup (description));
++ return name;
++}
++
++static const gchar *
++parse_xkb_xml_variant_node (IBusXKBConfigRegistryPrivate *priv,
++ XMLNode *parent_node,
++ const gchar *layout_name)
++{
++ XMLNode *node = parent_node;
++ XMLNode *sub_node;
++ GList *p;
++ const gchar *variant_name = NULL;
++
++ g_assert (node != NULL);
++ g_assert (layout_name != NULL);
++ for (p = node->sub_nodes; p; p = p->next) {
++ sub_node = (XMLNode *) p->data;
++ if (g_strcmp0 (sub_node->name, "configItem") == 0) {
++ variant_name = parse_xkb_xml_variant_configitem_node (priv, sub_node, layout_name);
++ continue;
++ }
++ }
++ return variant_name;
++}
++
++static GList *
++parse_xkb_xml_variantlist_node (IBusXKBConfigRegistryPrivate *priv,
++ XMLNode *parent_node,
++ const gchar *layout_name,
++ GList *variant_list)
++{
++ XMLNode *node = parent_node;
++ XMLNode *sub_node;
++ GList *p;
++ const gchar *variant_name = NULL;
++
++ g_assert (node != NULL);
++ g_assert (layout_name != NULL);
++ for (p = node->sub_nodes; p; p = p->next) {
++ sub_node = (XMLNode *) p->data;
++ if (g_strcmp0 (sub_node->name, "variant") == 0) {
++ variant_name = parse_xkb_xml_variant_node (priv, sub_node, layout_name);
++ if (variant_name != NULL) {
++ variant_list = g_list_append (variant_list,
++ (gpointer) g_strdup (variant_name));
++ }
++ continue;
++ }
++ }
++ return variant_list;
++}
++
++static void
++parse_xkb_xml_layout_node (IBusXKBConfigRegistryPrivate *priv,
++ XMLNode *parent_node)
++{
++ XMLNode *node = parent_node;
++ XMLNode *sub_node;
++ GList *p;
++ const gchar *name = NULL;
++ GList *variant_list = NULL;
++
++ g_assert (node != NULL);
++ for (p = node->sub_nodes; p; p = p->next) {
++ sub_node = (XMLNode *) p->data;
++ if (g_strcmp0 (sub_node->name, "configItem") == 0) {
++ name = parse_xkb_xml_configitem_node (priv, sub_node);
++ continue;
++ }
++ if (g_strcmp0 (sub_node->name, "variantList") == 0) {
++ if (name == NULL) {
++ g_warning ("layout name is NULL in node %s", node->name);
++ continue;
++ }
++ variant_list = parse_xkb_xml_variantlist_node (priv, sub_node,
++ name,
++ variant_list);
++ continue;
++ }
++ }
++ if (g_hash_table_lookup (priv->layout_list, name) != NULL) {
++ g_warning ("duplicated name %s exists", name);
++ return;
++ }
++ g_hash_table_insert (priv->layout_list,
++ (gpointer) g_strdup (name),
++ (gpointer) variant_list);
++}
++
++static void
++parse_xkb_xml_top_node (IBusXKBConfigRegistryPrivate *priv,
++ XMLNode *parent_node)
++{
++ XMLNode *node = parent_node;
++ XMLNode *sub_node;
++ GList *p;
++
++ g_assert (priv != NULL);
++ g_assert (node != NULL);
++
++ if (g_strcmp0 (node->name, "xkbConfigRegistry") != 0) {
++ g_warning ("node has no xkbConfigRegistry name");
++ return;
++ }
++ for (p = node->sub_nodes; p; p = p->next) {
++ sub_node = (XMLNode *) p->data;
++ if (g_strcmp0 (sub_node->name, "layoutList") == 0) {
++ break;
++ }
++ }
++ if (p == NULL) {
++ g_warning ("xkbConfigRegistry node has no layoutList node");
++ return;
++ }
++ node = sub_node;
++ for (p = node->sub_nodes; p; p = p->next) {
++ sub_node = (XMLNode *) p->data;
++ if (g_strcmp0 (sub_node->name, "layout") == 0) {
++ parse_xkb_xml_layout_node (priv, sub_node);
++ continue;
++ }
++ }
++}
++
++static void
++free_lang_list (GList *list)
++{
++ GList *l = list;
++ while (l) {
++ g_free (l->data);
++ l->data = NULL;
++ l = l->next;
++ }
++ g_list_free (list);
++}
++
++static void
++parse_xkb_config_registry_file (IBusXKBConfigRegistryPrivate *priv,
++ const gchar *file)
++{
++ XMLNode *node;
++
++ g_assert (file != NULL);
++
++ priv->layout_list = g_hash_table_new_full (g_str_hash,
++ (GEqualFunc) g_str_equal,
++ (GDestroyNotify) g_free,
++ (GDestroyNotify) free_lang_list);
++ priv->layout_desc = g_hash_table_new_full (g_str_hash,
++ (GEqualFunc) g_str_equal,
++ (GDestroyNotify) g_free,
++ (GDestroyNotify) g_free);
++ priv->layout_lang = g_hash_table_new_full (g_str_hash,
++ (GEqualFunc) g_str_equal,
++ (GDestroyNotify) g_free,
++ (GDestroyNotify) free_lang_list);
++ priv->variant_desc = g_hash_table_new_full (g_str_hash,
++ (GEqualFunc) g_str_equal,
++ (GDestroyNotify) g_free,
++ (GDestroyNotify) g_free);
++ node = ibus_xml_parse_file (file);
++ parse_xkb_xml_top_node (priv, node);
++ ibus_xml_free (node);
++}
++
++static void
++ibus_xkb_config_registry_init (IBusXKBConfigRegistry *xkb_config)
++{
++ IBusXKBConfigRegistryPrivate *priv;
++ const gchar *file = XKB_RULES_XML_FILE;
++
++ priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config);
++ parse_xkb_config_registry_file (priv, file);
++}
++
++static void
++ibus_xkb_config_registry_destroy (IBusXKBConfigRegistry *xkb_config)
++{
++ IBusXKBConfigRegistryPrivate *priv;
++
++ g_return_if_fail (xkb_config != NULL);
++
++ priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config);
++
++ g_hash_table_destroy (priv->layout_list);
++ priv->layout_list = NULL;
++ g_hash_table_destroy (priv->layout_lang);
++ priv->layout_lang= NULL;
++ g_hash_table_destroy (priv->layout_desc);
++ priv->layout_desc= NULL;
++ g_hash_table_destroy (priv->variant_desc);
++ priv->variant_desc = NULL;
++
++ IBUS_OBJECT_CLASS(ibus_xkb_config_registry_parent_class)->destroy (IBUS_OBJECT (xkb_config));
++}
++
++static void
++ibus_xkb_config_registry_class_init (IBusXKBConfigRegistryClass *klass)
++{
++ IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
++
++ g_type_class_add_private (klass, sizeof (IBusXKBConfigRegistryPrivate));
++
++ ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_xkb_config_registry_destroy;
++}
++
++IBusXKBConfigRegistry *
++ibus_xkb_config_registry_new (void)
++{
++ IBusXKBConfigRegistry *xkb_config;
++
++ xkb_config = IBUS_XKB_CONFIG_REGISTRY (g_object_new (IBUS_TYPE_XKB_CONFIG_REGISTRY, NULL));
++ return xkb_config;
++}
++
++#define TABLE_FUNC(field_name) const GHashTable * \
++ibus_xkb_config_registry_get_##field_name (IBusXKBConfigRegistry *xkb_config) \
++{ \
++ IBusXKBConfigRegistryPrivate *priv; \
++ \
++ g_return_val_if_fail (xkb_config != NULL, NULL); \
++ priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config); \
++ return priv->field_name; \
++}
++
++TABLE_FUNC (layout_list)
++TABLE_FUNC (layout_lang)
++TABLE_FUNC (layout_desc)
++TABLE_FUNC (variant_desc)
++
++#undef TABLE_FUNC
++
++#define TABLE_LOOKUP_LIST_FUNC(field_name, value) GList * \
++ibus_xkb_config_registry_##field_name##_get_##value (IBusXKBConfigRegistry *xkb_config, const gchar *key) \
++{ \
++ GHashTable *table; \
++ GList *list = NULL; \
++ \
++ table = (GHashTable *) \
++ ibus_xkb_config_registry_get_##field_name (xkb_config); \
++ list = (GList *) g_hash_table_lookup (table, key); \
++ return g_list_copy (list); \
++}
++
++#define TABLE_LOOKUP_STRING_FUNC(field_name, value) gchar * \
++ibus_xkb_config_registry_##field_name##_get_##value (IBusXKBConfigRegistry *xkb_config, const gchar *key) \
++{ \
++ GHashTable *table; \
++ const gchar *desc = NULL; \
++ \
++ table = (GHashTable *) \
++ ibus_xkb_config_registry_get_##field_name (xkb_config); \
++ desc = (const gchar *) g_hash_table_lookup (table, key); \
++ return g_strdup (desc); \
++}
++
++TABLE_LOOKUP_LIST_FUNC (layout_list, variants)
++TABLE_LOOKUP_LIST_FUNC (layout_lang, langs)
++TABLE_LOOKUP_STRING_FUNC (layout_desc, desc)
++TABLE_LOOKUP_STRING_FUNC (variant_desc, desc)
++
++#undef TABLE_LOOKUP_LIST_FUNC
++#undef TABLE_LOOKUP_STRING_FUNC
+diff --git a/src/ibusxkbxml.h b/src/ibusxkbxml.h
+new file mode 100644
+index 0000000..6986b5c
+--- /dev/null
++++ b/src/ibusxkbxml.h
+@@ -0,0 +1,172 @@
++/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
++/* vim:set et sts=4: */
++/* bus - The Input Bus
++ * Copyright (C) 2011 Takao Fujiwara <takao.fujiwara1 at gmail.com>
++ * Copyright (C) 2011 Peng Huang <shawn.p.huang at gmail.com>
++ * Copyright (C) 2011 Red Hat, Inc.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++#ifndef __IBUS_XKBXML_H_
++#define __IBUS_XKBXML_H_
++
++#include "ibus.h"
++
++/*
++ * Type macros.
++ */
++/* define IBusXKBConfigRegistry macros */
++#define IBUS_TYPE_XKB_CONFIG_REGISTRY \
++ (ibus_xkb_config_registry_get_type ())
++#define IBUS_XKB_CONFIG_REGISTRY(obj) \
++ (G_TYPE_CHECK_INSTANCE_CAST ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistry))
++#define IBUS_XKB_CONFIG_REGISTRY_CLASS(klass) \
++ (G_TYPE_CHECK_CLASS_CAST ((klass), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryClass))
++#define IBUS_IS_XKB_CONFIG_REGISTRY(obj) \
++ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY))
++#define IBUS_IS_XKB_CONFIG_REGISTRY_CLASS(klass) \
++ (G_TYPE_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_XKB_CONFIG_REGISTRY))
++#define IBUS_XKB_CONFIG_REGISTRY_GET_CLASS(obj) \
++ (G_TYPE_INSTANCE_GET_CLASS ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryClass))
++
++G_BEGIN_DECLS
++
++typedef struct _IBusXKBConfigRegistry IBusXKBConfigRegistry;
++typedef struct _IBusXKBConfigRegistryClass IBusXKBConfigRegistryClass;
++
++struct _IBusXKBConfigRegistry {
++ IBusObject parent;
++};
++
++struct _IBusXKBConfigRegistryClass {
++ IBusObjectClass parent;
++ /* signals */
++ /*< private >*/
++ /* padding */
++ gpointer pdummy[8];
++};
++
++
++GType ibus_xkb_config_registry_get_type
++ (void);
++
++/**
++ * ibus_xkb_config_registry_new:
++ * @returns: A newly allocated IBusXKBConfigRegistry
++ *
++ * New an IBusXKBConfigRegistry.
++ */
++IBusXKBConfigRegistry *
++ ibus_xkb_config_registry_new
++ (void);
++
++/**
++ * ibus_xkb_config_registry_get_layout_list: (skip)
++ * @xkb_config: An IBusXKBConfigRegistry.
++ * @returns: A const GHashTable
++ *
++ * a const GHashTable
++ */
++const GHashTable *
++ ibus_xkb_config_registry_get_layout_list
++ (IBusXKBConfigRegistry *xkb_config);
++
++/**
++ * ibus_xkb_config_registry_get_layout_lang: (skip)
++ * @xkb_config: An IBusXKBConfigRegistry.
++ * @returns: A const GHashTable
++ *
++ * a const GHashTable
++ */
++const GHashTable *
++ ibus_xkb_config_registry_get_layout_lang
++ (IBusXKBConfigRegistry *xkb_config);
++
++/**
++ * ibus_xkb_config_registry_get_layout_desc: (skip)
++ * @xkb_config: An IBusXKBConfigRegistry.
++ * @returns: A const GHashTable
++ *
++ * a const GHashTable
++ */
++const GHashTable *
++ ibus_xkb_config_registry_get_layout_desc
++ (IBusXKBConfigRegistry *xkb_config);
++
++/**
++ * ibus_xkb_config_registry_get_variant_desc: (skip)
++ * @xkb_config: An IBusXKBConfigRegistry.
++ * @returns: A const GHashTable
++ *
++ * a const GHashTable
++ */
++const GHashTable *
++ ibus_xkb_config_registry_get_variant_desc
++ (IBusXKBConfigRegistry *xkb_config);
++
++/**
++ * ibus_xkb_config_registry_layout_list_get_variants:
++ * @xkb_config: An IBusXKBConfigRegistry.
++ * @layout: A layout.
++ * @returns: (transfer container) (element-type utf8): A GList
++ *
++ * a GList
++ */
++GList *
++ ibus_xkb_config_registry_layout_list_get_variants
++ (IBusXKBConfigRegistry *xkb_config,
++ const gchar *layout);
++
++/**
++ * ibus_xkb_config_registry_layout_lang_get_langs:
++ * @xkb_config: An IBusXKBConfigRegistry.
++ * @layout: A layout.
++ * @returns: (transfer container) (element-type utf8): A GList
++ *
++ * a GList
++ */
++GList *
++ ibus_xkb_config_registry_layout_lang_get_langs
++ (IBusXKBConfigRegistry *xkb_config,
++ const gchar *layout);
++
++/**
++ * ibus_xkb_config_registry_layout_desc_get_desc:
++ * @xkb_config: An IBusXKBConfigRegistry.
++ * @layout: A layout.
++ * @returns: A layout description
++ *
++ * a layout description
++ */
++gchar *
++ ibus_xkb_config_registry_layout_desc_get_desc
++ (IBusXKBConfigRegistry *xkb_config,
++ const gchar *layout);
++
++/**
++ * ibus_xkb_config_registry_variant_desc_get_desc:
++ * @xkb_config: An IBusXKBConfigRegistry.
++ * @variant: A variant.
++ * @returns: A variant description
++ *
++ * a variant description
++ */
++gchar *
++ ibus_xkb_config_registry_variant_desc_get_desc
++ (IBusXKBConfigRegistry *xkb_config,
++ const gchar *variant);
++G_END_DECLS
++#endif
+diff --git a/ui/gtk/panel.py b/ui/gtk/panel.py
+index 90be1d5..de64920 100644
+--- a/ui/gtk/panel.py
++++ b/ui/gtk/panel.py
+@@ -132,6 +132,22 @@ class Panel(ibus.PanelBase):
+ self.__config_load_show_im_name()
+ # self.__bus.request_name(ibus.panel.IBUS_SERVICE_PANEL, 0)
+
++ # init xkb
++ self.__xkblayout = ibus.XKBLayout(self.__config)
++ use_xkb = self.__config.get_value("general", "use_system_keyboard_layout", False)
++ if not use_xkb:
++ self.__xkblayout.use_xkb(use_xkb)
++ value = str(self.__config.get_value("general", "system_keyboard_layout", ''))
++ if value == '':
++ value = 'default'
++ if value != 'default':
++ self.__xkblayout.set_default_layout(value)
++ value = str(self.__config.get_value("general", "system_keyboard_option", ''))
++ if value == '':
++ value = 'default'
++ if value != 'default':
++ self.__xkblayout.set_default_option(value)
++
+ def set_cursor_location(self, x, y, w, h):
+ self.__candidate_panel.set_cursor_location(x, y, w, h)
+
+@@ -226,14 +242,20 @@ class Panel(ibus.PanelBase):
+ if not enabled:
+ self.__set_im_icon(ICON_KEYBOARD)
+ self.__set_im_name(None)
++ if self.__bus.get_use_sys_layout():
++ self.__xkblayout.set_layout()
+ else:
+ engine = self.__focus_ic.get_engine()
+ if engine:
+ self.__set_im_icon(engine.icon)
+ self.__set_im_name(engine.longname)
++ if self.__bus.get_use_sys_layout():
++ self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine))
+ else:
+ self.__set_im_icon(ICON_KEYBOARD)
+ self.__set_im_name(None)
++ if self.__bus.get_use_sys_layout():
++ self.__xkblayout.set_layout()
+ self.__language_bar.focus_in()
+
+ def focus_out(self, ic):
+@@ -243,6 +265,8 @@ class Panel(ibus.PanelBase):
+ self.__language_bar.focus_out()
+ self.__set_im_icon(ICON_KEYBOARD)
+ self.__set_im_name(None)
++ if self.__bus.get_use_sys_layout():
++ self.__xkblayout.set_layout()
+
+ def state_changed(self):
+ if not self.__focus_ic:
+@@ -255,14 +279,20 @@ class Panel(ibus.PanelBase):
+ self.reset()
+ self.__set_im_icon(ICON_KEYBOARD)
+ self.__set_im_name(None)
++ if self.__bus.get_use_sys_layout():
++ self.__xkblayout.set_layout()
+ else:
+ engine = self.__focus_ic.get_engine()
+ if engine:
+ self.__set_im_icon(engine.icon)
+ self.__set_im_name(engine.longname)
++ if self.__bus.get_use_sys_layout():
++ self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine))
+ else:
+ self.__set_im_icon(ICON_KEYBOARD)
+ self.__set_im_name(None)
++ if self.__bus.get_use_sys_layout():
++ self.__xkblayout.set_layout()
+
+
+ def reset(self):
+@@ -542,3 +572,12 @@ class Panel(ibus.PanelBase):
+ flags=glib.SPAWN_DO_NOT_REAP_CHILD)[0]
+ self.__setup_pid = pid
+ glib.child_watch_add(self.__setup_pid, self.__child_watch_cb)
++
++ def __engine_get_layout_wrapper(self, engine):
++ # This code is for the back compatibility.
++ # Should we remove the codes after all IM engines are changed
++ # to "default" layout?
++ if engine.name != None and engine.name.startswith("xkb:layout:"):
++ return engine.layout
++ else:
++ return "default"
+diff --git a/xkb/Makefile.am b/xkb/Makefile.am
+new file mode 100644
+index 0000000..ad9cdd9
+--- /dev/null
++++ b/xkb/Makefile.am
+@@ -0,0 +1,104 @@
++# vim:set noet ts=4:
++#
++# ibus - The Input Bus
++#
++# Copyright (C) 2011 Takao Fujiwara <takao.fujiwara1 at gmail.com>
++# Copyright (c) 2011 Peng Huang <shawn.p.huang at gmail.com>
++# Copyright (c) 2011 Red Hat, Inc.
++#
++# This library is free software; you can redistribute it and/or
++# modify it under the terms of the GNU Lesser General Public
++# License as published by the Free Software Foundation; either
++# version 2 of the License, or (at your option) any later version.
++#
++# This library is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU Lesser General Public License for more details.
++#
++# You should have received a copy of the GNU Lesser General Public
++# License along with this program; if not, write to the
++# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
++# Boston, MA 02111-1307 USA
++
++libibus = $(top_builddir)/src/libibus- at IBUS_API_VERSION@.la
++
++INCLUDES = \
++ -I$(top_srcdir) \
++ -I$(top_srcdir)/src \
++ -DIBUS_LOCALEDIR=\"$(datadir)/locale\" \
++ -DLIBEXECDIR=\""$(libexecdir)"\" \
++ $(NULL)
++
++noinst_PROGRAMS = $(TESTS)
++libexec_PROGRAMS =
++EXTRA_DIST =
++DISTCLEANFILES =
++
++if ENABLE_XKB
++libexec_PROGRAMS += ibus-xkb
++ibus_xkb_SOURCES = \
++ ibus-xkb-main.c \
++ xkblib.h \
++ xkblib.c \
++ $(NULL)
++ibus_xkb_CFLAGS = \
++ @XKB_CFLAGS@ \
++ @X11_CFLAGS@ \
++ @GLIB2_CFLAGS@ \
++ $(NULL)
++ibus_xkb_LDADD = \
++ @XKB_LIBS@ \
++ @X11_LIBS@ \
++ @GLIB2_LIBS@ \
++ $(libibus) \
++ $(NULL)
++
++libexec_PROGRAMS += ibus-engine-xkb
++ibus_engine_xkb_SOURCES = \
++ ibus-engine-xkb-main.c \
++ ibus-engine-xkb-main.h \
++ xkbxml.c \
++ xkbxml.h \
++ $(NULL)
++ibus_engine_xkb_CFLAGS = \
++ @GLIB2_CFLAGS@ \
++ @GOBJECT2_CFLAGS@ \
++ @GCONF_CFLAGS@ \
++ $(NULL)
++ibus_engine_xkb_LDADD = \
++ @GLIB2_LIBS@ \
++ @GOBJECT2_LIBS@ \
++ @GCONF_LIBS@ \
++ $(libibus) \
++ $(NULL)
++
++xkblayoutdir = $(datadir)/ibus/component
++xkblayout_in_files = xkblayout.xml.in
++xkblayout_DATA = $(xkblayout_in_files:.xml.in=.xml)
++
++xkblayoutconfigdir = $(datadir)/ibus/xkb
++xkblayoutconfig_in_files = xkblayoutconfig.xml.in
++xkblayoutconfig_DATA = $(xkblayoutconfig_in_files:.xml.in=.xml)
++
++%.xml : %.xml.in
++ @sed -e "s|\@libexecdir\@|$(libexecdir)|g" \
++ -e "s|\@datadir\@|$(datadir)|g" \
++ -e "s|\@XKB_PRELOAD_LAYOUTS\@|$(XKB_PRELOAD_LAYOUTS)|g" \
++ $< > $@
++
++INCLUDES += \
++ -DXKBLAYOUTCONFIG_FILE=\""$(xkblayoutconfigdir)/$(xkblayoutconfig_DATA)"\" \
++ $(NULL)
++
++EXTRA_DIST += \
++ $(xkblayout_in_files) \
++ $(xkblayoutconfig_in_files) \
++ $(NULL)
++
++DISTCLEANFILES += \
++ $(xkblayout_DATA) \
++ $(xkblayoutconfig_DATA) \
++ $(NULL)
++
++endif
+diff --git a/xkb/ibus-engine-xkb-main.c b/xkb/ibus-engine-xkb-main.c
+new file mode 100644
+index 0000000..5d748cc
+--- /dev/null
++++ b/xkb/ibus-engine-xkb-main.c
+@@ -0,0 +1,397 @@
++/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
++/* vim:set et sts=4: */
++/* bus - The Input Bus
++ * Copyright (C) 2011 Takao Fujiwara <takao.fujiwara1 at gmail.com>
++ * Copyright (C) 2011 Peng Huang <shawn.p.huang at gmail.com>
++ * Copyright (C) 2011 Red Hat, Inc.
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
++#include <gconf/gconf-client.h>
++#include <ibus.h>
++#include <stdlib.h>
++
++#ifdef ENABLE_NLS
++#include <locale.h>
++#endif
++
++#include "ibus-engine-xkb-main.h"
++#include "xkbxml.h"
++
++#define IBUS_TYPE_XKB_ENGINE (ibus_xkb_engine_get_type ())
++
++static IBusBus *bus = NULL;
++static IBusFactory *factory = NULL;
++static IBusEngineClass *parent_class = NULL;
++static gboolean ibus = FALSE;
++static gboolean xml = FALSE;
++
++static const GOptionEntry entries[] =
++{
++ { "ibus", 'i', 0, G_OPTION_ARG_NONE, &ibus, "component is executed by ibus", NULL },
++ { "xml", 'x', 0, G_OPTION_ARG_NONE, &xml, "print component xml", NULL },
+ { NULL },
+};
+
@@ -2808,16 +3466,16 @@ index 0000000..e1861e8
+}
diff --git a/xkb/ibus-engine-xkb-main.h b/xkb/ibus-engine-xkb-main.h
new file mode 100644
-index 0000000..8007631
+index 0000000..c17c857
--- /dev/null
+++ b/xkb/ibus-engine-xkb-main.h
@@ -0,0 +1,46 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* vim:set et sts=4: */
+/* bus - The Input Bus
-+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright (C) 2008-2010 Red Hat, Inc.
++ * Copyright (C) 2011 Takao Fujiwara <takao.fujiwara1 at gmail.com>
++ * Copyright (C) 2011 Peng Huang <shawn.p.huang at gmail.com>
++ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
@@ -2860,16 +3518,16 @@ index 0000000..8007631
+#endif
diff --git a/xkb/ibus-xkb-main.c b/xkb/ibus-xkb-main.c
new file mode 100644
-index 0000000..9db7d0a
+index 0000000..ef57553
--- /dev/null
+++ b/xkb/ibus-xkb-main.c
-@@ -0,0 +1,105 @@
+@@ -0,0 +1,112 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* vim:set et sts=4: */
+/* bus - The Input Bus
-+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright (C) 2008-2010 Red Hat, Inc.
++ * Copyright (C) 2011 Takao Fujiwara <takao.fujiwara1 at gmail.com>
++ * Copyright (C) 2011 Peng Huang <shawn.p.huang at gmail.com>
++ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
@@ -2902,9 +3560,11 @@ index 0000000..9db7d0a
+#include "xkblib.h"
+
+static gboolean get_layout = FALSE;
++static gboolean get_group = FALSE;
+static gchar *layout = NULL;
+static gchar *model = NULL;
+static gchar *option = NULL;
++static int group = 0;
+
+static const GOptionEntry entries[] =
+{
@@ -2913,6 +3573,7 @@ index 0000000..9db7d0a
+ { "layout", 'l', 0, G_OPTION_ARG_STRING, &layout, N_("Set xkb layout"), "layout" },
+ { "model", 'm', 0, G_OPTION_ARG_STRING, &model, N_("Set xkb model"), "model" },
+ { "option", 'o', 0, G_OPTION_ARG_STRING, &option, N_("Set xkb option"), "option" },
++ { "get-group", 'G', 0, G_OPTION_ARG_NONE, &get_group, N_("Get current xkb state"), NULL },
+ { NULL },
+};
+
@@ -2964,6 +3625,10 @@ index 0000000..9db7d0a
+ g_free (model);
+ g_free (option);
+ }
++ if (get_group) {
++ group = ibus_xkb_get_current_group ();
++ g_printf ("group: %d\n", group);
++ }
+
+ ibus_xkb_finit ();
+
@@ -3005,16 +3670,16 @@ index 0000000..b1212d1
+</xkblayout>
diff --git a/xkb/xkblib.c b/xkb/xkblib.c
new file mode 100644
-index 0000000..640f783
+index 0000000..293cdaf
--- /dev/null
+++ b/xkb/xkblib.c
-@@ -0,0 +1,303 @@
+@@ -0,0 +1,327 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* vim:set et sts=4: */
+/* bus - The Input Bus
-+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright (C) 2008-2010 Red Hat, Inc.
++ * Copyright (C) 2011 Takao Fujiwara <takao.fujiwara1 at gmail.com>
++ * Copyright (C) 2011 Peng Huang <shawn.p.huang at gmail.com>
++ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
@@ -3292,7 +3957,7 @@ index 0000000..640f783
+
+ if (default_layouts == NULL) {
+ g_warning ("Your system seems not to support XKB.");
-+ return NULL;
++ return FALSE;
+ }
+
+ if (layouts == NULL || g_strcmp0 (layouts, "default") == 0) {
@@ -3312,18 +3977,42 @@ index 0000000..640f783
+
+ return retval;
+}
++
++int
++ibus_xkb_get_current_group (void)
++{
++ Display *xdisplay = get_xdisplay (NULL);
++ XkbStateRec state;
++
++ if (default_layouts == NULL) {
++ g_warning ("Your system seems not to support XKB.");
++ return 0;
++ }
++
++ if (xdisplay == NULL) {
++ g_warning ("ibus-xkb is not initialized.");
++ return 0;
++ }
++
++ if (XkbGetState (xdisplay, XkbUseCoreKbd, &state) != Success) {
++ g_warning ("Could not get state");
++ return 0;
++ }
++
++ return state.group;
++}
diff --git a/xkb/xkblib.h b/xkb/xkblib.h
new file mode 100644
-index 0000000..09d506d
+index 0000000..15e5d18
--- /dev/null
+++ b/xkb/xkblib.h
-@@ -0,0 +1,40 @@
+@@ -0,0 +1,41 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* vim:set et sts=4: */
+/* bus - The Input Bus
-+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright (C) 2008-2010 Red Hat, Inc.
++ * Copyright (C) 2011 Takao Fujiwara <takao.fujiwara1 at gmail.com>
++ * Copyright (C) 2011 Peng Huang <shawn.p.huang at gmail.com>
++ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
@@ -3355,21 +4044,22 @@ index 0000000..09d506d
+gboolean ibus_xkb_set_layout (const char *layouts,
+ const char *variants,
+ const char *options);
++int ibus_xkb_get_current_group (void);
+
+G_END_DECLS
+#endif
diff --git a/xkb/xkbxml.c b/xkb/xkbxml.c
new file mode 100644
-index 0000000..f5582ff
+index 0000000..2ce7bcf
--- /dev/null
+++ b/xkb/xkbxml.c
-@@ -0,0 +1,696 @@
+@@ -0,0 +1,335 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* vim:set et sts=4: */
+/* bus - The Input Bus
-+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright (C) 2008-2010 Red Hat, Inc.
++ * Copyright (C) 2011 Takao Fujiwara <takao.fujiwara1 at gmail.com>
++ * Copyright (C) 2011 Peng Huang <shawn.p.huang at gmail.com>
++ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
@@ -3392,294 +4082,29 @@ index 0000000..f5582ff
+
+#include <glib.h>
+
-+#include "xkbxml.h"
-+#include "ibus.h"
-+
-+#ifndef XKB_RULES_XML_FILE
-+#define XKB_RULES_XML_FILE "/usr/share/X11/xkb/rules/evdev.xml"
-+#endif
-+
-+#define IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE(o) \
-+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryPrivate))
-+#define IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE(o) \
-+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_XKB_LAYOUT_CONFIG, IBusXKBLayoutConfigPrivate))
-+
-+typedef struct _IBusXKBConfigRegistryPrivate IBusXKBConfigRegistryPrivate;
-+typedef struct _IBusXKBLayoutConfigPrivate IBusXKBLayoutConfigPrivate;
-+
-+enum {
-+ PROP_0,
-+ PROP_SYSTEM_CONFIG_FILE,
-+};
-+
-+struct _IBusXKBConfigRegistryPrivate {
-+ GHashTable *layout_list;
-+ GHashTable *layout_lang;
-+ GHashTable *layout_desc;
-+ GHashTable *variant_desc;
-+};
-+
-+struct _IBusXKBLayoutConfigPrivate {
-+ gchar *system_config_file;
-+ GList *preload_layouts;
-+};
-+
-+/* functions prototype */
-+static void ibus_xkb_config_registry_destroy
-+ (IBusXKBConfigRegistry *xkb_config);
-+static void ibus_xkb_layout_config_destroy
-+ (IBusXKBLayoutConfig *xkb_layout_config);
-+
-+G_DEFINE_TYPE (IBusXKBConfigRegistry, ibus_xkb_config_registry, IBUS_TYPE_OBJECT)
-+G_DEFINE_TYPE (IBusXKBLayoutConfig, ibus_xkb_layout_config, IBUS_TYPE_OBJECT)
-+
-+static void
-+parse_xkb_xml_languagelist_node (IBusXKBConfigRegistryPrivate *priv,
-+ XMLNode *parent_node,
-+ const gchar *layout_name)
-+{
-+ XMLNode *node = parent_node;
-+ XMLNode *sub_node;
-+ GList *p;
-+ GList *lang_list = NULL;
-+
-+ g_assert (node != NULL);
-+ g_assert (layout_name != NULL);
-+ for (p = node->sub_nodes; p; p = p->next) {
-+ sub_node = (XMLNode *) p->data;
-+ if (g_strcmp0 (sub_node->name, "iso639Id") == 0) {
-+ lang_list = g_list_append (lang_list,
-+ (gpointer) g_strdup (sub_node->text));
-+ continue;
-+ }
-+ }
-+ if (lang_list == NULL) {
-+ /* some nodes have no lang */
-+ return;
-+ }
-+ if (g_hash_table_lookup (priv->layout_lang, layout_name) != NULL) {
-+ g_warning ("duplicated name %s exists", layout_name);
-+ return;
-+ }
-+ g_hash_table_insert (priv->layout_lang,
-+ (gpointer) g_strdup (layout_name),
-+ (gpointer) lang_list);
-+}
-+
-+static const gchar *
-+parse_xkb_xml_configitem_node (IBusXKBConfigRegistryPrivate *priv,
-+ XMLNode *parent_node)
-+{
-+ XMLNode *node = parent_node;
-+ XMLNode *sub_node;
-+ GList *p;
-+ gchar *name = NULL;
-+ gchar *description = NULL;
-+
-+ g_assert (node != NULL);
-+ for (p = node->sub_nodes; p; p = p->next) {
-+ sub_node = (XMLNode *) p->data;
-+ if (g_strcmp0 (sub_node->name, "name") == 0) {
-+ name = sub_node->text;
-+ continue;
-+ }
-+ if (g_strcmp0 (sub_node->name, "description") == 0) {
-+ description = sub_node->text;
-+ continue;
-+ }
-+ if (g_strcmp0 (sub_node->name, "languageList") == 0) {
-+ if (name == NULL) {
-+ g_warning ("layout name is NULL in node %s", node->name);
-+ continue;
-+ }
-+ parse_xkb_xml_languagelist_node (priv, sub_node, name);
-+ continue;
-+ }
-+ }
-+ if (name == NULL) {
-+ g_warning ("No name in layout node");
-+ return NULL;
-+ }
-+ if (g_hash_table_lookup (priv->layout_desc, name) != NULL) {
-+ g_warning ("duplicated name %s exists", name);
-+ return name;
-+ }
-+ g_hash_table_insert (priv->layout_desc,
-+ (gpointer) g_strdup (name),
-+ (gpointer) g_strdup (description));
-+
-+ return name;
-+}
-+
-+static const gchar *
-+parse_xkb_xml_variant_configitem_node (IBusXKBConfigRegistryPrivate *priv,
-+ XMLNode *parent_node,
-+ const gchar *layout_name)
-+{
-+ XMLNode *node = parent_node;
-+ XMLNode *sub_node;
-+ GList *p;
-+ gchar *name = NULL;
-+ gchar *description = NULL;
-+ gchar *variant_lang_name = NULL;
-+
-+ g_assert (node != NULL);
-+ g_assert (layout_name != NULL);
-+ for (p = node->sub_nodes; p; p = p->next) {
-+ sub_node = (XMLNode *) p->data;
-+ if (g_strcmp0 (sub_node->name, "name") == 0) {
-+ name = sub_node->text;
-+ continue;
-+ }
-+ if (g_strcmp0 (sub_node->name, "description") == 0) {
-+ description = sub_node->text;
-+ continue;
-+ }
-+ if (g_strcmp0 (sub_node->name, "languageList") == 0) {
-+ if (name == NULL) {
-+ g_warning ("layout name is NULL in node %s", node->name);
-+ continue;
-+ }
-+ variant_lang_name = g_strdup_printf ("%s(%s)", layout_name, name);
-+ parse_xkb_xml_languagelist_node (priv, sub_node, variant_lang_name);
-+ g_free (variant_lang_name);
-+ continue;
-+ }
-+ }
-+ if (name == NULL) {
-+ g_warning ("No name in layout node");
-+ return NULL;
-+ }
-+ if (g_hash_table_lookup (priv->variant_desc, name) != NULL) {
-+ /* This is an expected case. */
-+ return name;
-+ }
-+ g_hash_table_insert (priv->variant_desc,
-+ (gpointer) g_strdup (name),
-+ (gpointer) g_strdup (description));
-+ return name;
-+}
-+
-+static const gchar *
-+parse_xkb_xml_variant_node (IBusXKBConfigRegistryPrivate *priv,
-+ XMLNode *parent_node,
-+ const gchar *layout_name)
-+{
-+ XMLNode *node = parent_node;
-+ XMLNode *sub_node;
-+ GList *p;
-+ const gchar *variant_name = NULL;
-+
-+ g_assert (node != NULL);
-+ g_assert (layout_name != NULL);
-+ for (p = node->sub_nodes; p; p = p->next) {
-+ sub_node = (XMLNode *) p->data;
-+ if (g_strcmp0 (sub_node->name, "configItem") == 0) {
-+ variant_name = parse_xkb_xml_variant_configitem_node (priv, sub_node, layout_name);
-+ continue;
-+ }
-+ }
-+ return variant_name;
-+}
-+
-+static GList *
-+parse_xkb_xml_variantlist_node (IBusXKBConfigRegistryPrivate *priv,
-+ XMLNode *parent_node,
-+ const gchar *layout_name,
-+ GList *variant_list)
-+{
-+ XMLNode *node = parent_node;
-+ XMLNode *sub_node;
-+ GList *p;
-+ const gchar *variant_name = NULL;
-+
-+ g_assert (node != NULL);
-+ g_assert (layout_name != NULL);
-+ for (p = node->sub_nodes; p; p = p->next) {
-+ sub_node = (XMLNode *) p->data;
-+ if (g_strcmp0 (sub_node->name, "variant") == 0) {
-+ variant_name = parse_xkb_xml_variant_node (priv, sub_node, layout_name);
-+ if (variant_name != NULL) {
-+ variant_list = g_list_append (variant_list,
-+ (gpointer) g_strdup (variant_name));
-+ }
-+ continue;
-+ }
-+ }
-+ return variant_list;
-+}
++#include "xkbxml.h"
++#include "ibus.h"
+
-+static void
-+parse_xkb_xml_layout_node (IBusXKBConfigRegistryPrivate *priv,
-+ XMLNode *parent_node)
-+{
-+ XMLNode *node = parent_node;
-+ XMLNode *sub_node;
-+ GList *p;
-+ const gchar *name = NULL;
-+ GList *variant_list = NULL;
++#define IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE(o) \
++ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_XKB_LAYOUT_CONFIG, IBusXKBLayoutConfigPrivate))
+
-+ g_assert (node != NULL);
-+ for (p = node->sub_nodes; p; p = p->next) {
-+ sub_node = (XMLNode *) p->data;
-+ if (g_strcmp0 (sub_node->name, "configItem") == 0) {
-+ name = parse_xkb_xml_configitem_node (priv, sub_node);
-+ continue;
-+ }
-+ if (g_strcmp0 (sub_node->name, "variantList") == 0) {
-+ if (name == NULL) {
-+ g_warning ("layout name is NULL in node %s", node->name);
-+ continue;
-+ }
-+ variant_list = parse_xkb_xml_variantlist_node (priv, sub_node,
-+ name,
-+ variant_list);
-+ continue;
-+ }
-+ }
-+ if (g_hash_table_lookup (priv->layout_list, name) != NULL) {
-+ g_warning ("duplicated name %s exists", name);
-+ return;
-+ }
-+ g_hash_table_insert (priv->layout_list,
-+ (gpointer) g_strdup (name),
-+ (gpointer) variant_list);
-+}
++typedef struct _IBusXKBLayoutConfigPrivate IBusXKBLayoutConfigPrivate;
+
-+static void
-+parse_xkb_xml_top_node (IBusXKBConfigRegistryPrivate *priv,
-+ XMLNode *parent_node)
-+{
-+ XMLNode *node = parent_node;
-+ XMLNode *sub_node;
-+ GList *p;
++enum {
++ PROP_0,
++ PROP_SYSTEM_CONFIG_FILE,
++};
+
-+ g_assert (priv != NULL);
-+ g_assert (node != NULL);
++struct _IBusXKBLayoutConfigPrivate {
++ gchar *system_config_file;
++ GList *preload_layouts;
++};
+
-+ if (g_strcmp0 (node->name, "xkbConfigRegistry") != 0) {
-+ g_warning ("node has no xkbConfigRegistry name");
-+ return;
-+ }
-+ for (p = node->sub_nodes; p; p = p->next) {
-+ sub_node = (XMLNode *) p->data;
-+ if (g_strcmp0 (sub_node->name, "layoutList") == 0) {
-+ break;
-+ }
-+ }
-+ if (p == NULL) {
-+ g_warning ("xkbConfigRegistry node has no layoutList node");
-+ return;
-+ }
-+ node = sub_node;
-+ for (p = node->sub_nodes; p; p = p->next) {
-+ sub_node = (XMLNode *) p->data;
-+ if (g_strcmp0 (sub_node->name, "layout") == 0) {
-+ parse_xkb_xml_layout_node (priv, sub_node);
-+ continue;
-+ }
-+ }
-+}
++/* functions prototype */
++static void ibus_xkb_layout_config_destroy
++ (IBusXKBLayoutConfig *xkb_layout_config);
++
++G_DEFINE_TYPE (IBusXKBLayoutConfig, ibus_xkb_layout_config, IBUS_TYPE_OBJECT)
+
+static void
+free_lang_list (GList *list)
@@ -3693,35 +4118,6 @@ index 0000000..f5582ff
+ g_list_free (list);
+}
+
-+static void
-+parse_xkb_config_registry_file (IBusXKBConfigRegistryPrivate *priv,
-+ const gchar *file)
-+{
-+ XMLNode *node;
-+
-+ g_assert (file != NULL);
-+
-+ priv->layout_list = g_hash_table_new_full (g_str_hash,
-+ (GEqualFunc) g_str_equal,
-+ (GDestroyNotify) g_free,
-+ (GDestroyNotify) free_lang_list);
-+ priv->layout_desc = g_hash_table_new_full (g_str_hash,
-+ (GEqualFunc) g_str_equal,
-+ (GDestroyNotify) g_free,
-+ (GDestroyNotify) g_free);
-+ priv->layout_lang = g_hash_table_new_full (g_str_hash,
-+ (GEqualFunc) g_str_equal,
-+ (GDestroyNotify) g_free,
-+ (GDestroyNotify) free_lang_list);
-+ priv->variant_desc = g_hash_table_new_full (g_str_hash,
-+ (GEqualFunc) g_str_equal,
-+ (GDestroyNotify) g_free,
-+ (GDestroyNotify) g_free);
-+ node = ibus_xml_parse_file (file);
-+ parse_xkb_xml_top_node (priv, node);
-+ ibus_xml_free (node);
-+}
-+
+static GList *
+parse_xkblayoutconfig_file (gchar *path)
+{
@@ -3794,47 +4190,6 @@ index 0000000..f5582ff
+}
+
+static void
-+ibus_xkb_config_registry_init (IBusXKBConfigRegistry *xkb_config)
-+{
-+ IBusXKBConfigRegistryPrivate *priv;
-+ const gchar *file = XKB_RULES_XML_FILE;
-+
-+ priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config);
-+ parse_xkb_config_registry_file (priv, file);
-+}
-+
-+static void
-+ibus_xkb_config_registry_destroy (IBusXKBConfigRegistry *xkb_config)
-+{
-+ IBusXKBConfigRegistryPrivate *priv;
-+
-+ g_return_if_fail (xkb_config != NULL);
-+
-+ priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config);
-+
-+ g_hash_table_destroy (priv->layout_list);
-+ priv->layout_list = NULL;
-+ g_hash_table_destroy (priv->layout_lang);
-+ priv->layout_lang= NULL;
-+ g_hash_table_destroy (priv->layout_desc);
-+ priv->layout_desc= NULL;
-+ g_hash_table_destroy (priv->variant_desc);
-+ priv->variant_desc = NULL;
-+
-+ IBUS_OBJECT_CLASS(ibus_xkb_config_registry_parent_class)->destroy (IBUS_OBJECT (xkb_config));
-+}
-+
-+static void
-+ibus_xkb_config_registry_class_init (IBusXKBConfigRegistryClass *klass)
-+{
-+ IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
-+
-+ g_type_class_add_private (klass, sizeof (IBusXKBConfigRegistryPrivate));
-+
-+ ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_xkb_config_registry_destroy;
-+}
-+
-+static void
+ibus_xkb_layout_config_init (IBusXKBLayoutConfig *xkb_layout_config)
+{
+ IBusXKBLayoutConfigPrivate *priv;
@@ -3945,32 +4300,6 @@ index 0000000..f5582ff
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
-+IBusXKBConfigRegistry *
-+ibus_xkb_config_registry_new (void)
-+{
-+ IBusXKBConfigRegistry *xkb_config;
-+
-+ xkb_config = IBUS_XKB_CONFIG_REGISTRY (g_object_new (IBUS_TYPE_XKB_CONFIG_REGISTRY, NULL));
-+ return xkb_config;
-+}
-+
-+#define TABLE_FUNC(field_name) const GHashTable * \
-+ibus_xkb_config_registry_get_##field_name (IBusXKBConfigRegistry *xkb_config) \
-+{ \
-+ IBusXKBConfigRegistryPrivate *priv; \
-+ \
-+ g_return_val_if_fail (xkb_config != NULL, NULL); \
-+ priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config); \
-+ return priv->field_name; \
-+}
-+
-+TABLE_FUNC (layout_list)
-+TABLE_FUNC (layout_lang)
-+TABLE_FUNC (layout_desc)
-+TABLE_FUNC (variant_desc)
-+
-+#undef TABLE_FUNC
-+
+IBusComponent *
+ibus_xkb_component_new (void)
+{
@@ -4062,16 +4391,16 @@ index 0000000..f5582ff
+}
diff --git a/xkb/xkbxml.h b/xkb/xkbxml.h
new file mode 100644
-index 0000000..f4858fa
+index 0000000..56811ef
--- /dev/null
+++ b/xkb/xkbxml.h
-@@ -0,0 +1,189 @@
+@@ -0,0 +1,110 @@
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
+/* vim:set et sts=4: */
+/* bus - The Input Bus
-+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright (C) 2008-2010 Red Hat, Inc.
++ * Copyright (C) 2011 Takao Fujiwara <takao.fujiwara1 at gmail.com>
++ * Copyright (C) 2011 Peng Huang <shawn.p.huang at gmail.com>
++ * Copyright (C) 2011 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
@@ -4088,28 +4417,14 @@ index 0000000..f4858fa
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
-+#ifndef __IBUS_XKB_H_
-+#define __IBUS_XKB_H_
++#ifndef __XKBXML_H_
++#define __XKBXML_H_
+
+#include "ibus.h"
+
+/*
+ * Type macros.
+ */
-+/* define IBusXKBConfigRegistry macros */
-+#define IBUS_TYPE_XKB_CONFIG_REGISTRY \
-+ (ibus_xkb_config_registry_get_type ())
-+#define IBUS_XKB_CONFIG_REGISTRY(obj) \
-+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistry))
-+#define IBUS_XKB_CONFIG_REGISTRY_CLASS(klass) \
-+ (G_TYPE_CHECK_CLASS_CAST ((klass), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryClass))
-+#define IBUS_IS_XKB_CONFIG_REGISTRY(obj) \
-+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY))
-+#define IBUS_IS_XKB_CONFIG_REGISTRY_CLASS(klass) \
-+ (G_TYPE_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_XKB_CONFIG_REGISTRY))
-+#define IBUS_XKB_CONFIG_REGISTRY_GET_CLASS(obj) \
-+ (G_TYPE_INSTANCE_GET_CLASS ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryClass))
-+
+/* define IBusXKBLayoutConfig macros */
+#define IBUS_TYPE_XKB_LAYOUT_CONFIG \
+ (ibus_xkb_layout_config_get_type ())
@@ -4126,23 +4441,9 @@ index 0000000..f4858fa
+
+G_BEGIN_DECLS
+
-+typedef struct _IBusXKBConfigRegistry IBusXKBConfigRegistry;
-+typedef struct _IBusXKBConfigRegistryClass IBusXKBConfigRegistryClass;
+typedef struct _IBusXKBLayoutConfig IBusXKBLayoutConfig;
+typedef struct _IBusXKBLayoutConfigClass IBusXKBLayoutConfigClass;
+
-+struct _IBusXKBConfigRegistry {
-+ IBusObject parent;
-+};
-+
-+struct _IBusXKBConfigRegistryClass {
-+ IBusObjectClass parent;
-+ /* signals */
-+ /*< private >*/
-+ /* padding */
-+ gpointer pdummy[8];
-+};
-+
+struct _IBusXKBLayoutConfig {
+ IBusObject parent;
+};
@@ -4156,57 +4457,6 @@ index 0000000..f4858fa
+};
+
+
-+GType ibus_xkb_config_registry_get_type
-+ (void);
-+/**
-+ * ibus_xkb_config_registry_new:
-+ * @returns: A newly allocated IBusXKBConfigRegistry
-+ *
-+ * New an IBusXKBConfigRegistry.
-+ */
-+IBusXKBConfigRegistry *
-+ ibus_xkb_config_registry_new
-+ (void);
-+/**
-+ * ibus_xkb_config_registry_get_layout_list:
-+ * @xkb_config: An IBusXKBConfigRegistry.
-+ * @returns: A const GHashTable
-+ *
-+ * a const GHashTable
-+ */
-+const GHashTable *
-+ ibus_xkb_config_registry_get_layout_list
-+ (IBusXKBConfigRegistry *xkb_config);
-+/**
-+ * ibus_xkb_config_registry_get_layout_lang:
-+ * @xkb_config: An IBusXKBConfigRegistry.
-+ * @returns: A const GHashTable
-+ *
-+ * a const GHashTable
-+ */
-+const GHashTable *
-+ ibus_xkb_config_registry_get_layout_lang
-+ (IBusXKBConfigRegistry *xkb_config);
-+/**
-+ * ibus_xkb_config_registry_get_layout_desc:
-+ * @xkb_config: An IBusXKBConfigRegistry.
-+ * @returns: A const GHashTable
-+ *
-+ * a const GHashTable
-+ */
-+const GHashTable *
-+ ibus_xkb_config_registry_get_layout_desc
-+ (IBusXKBConfigRegistry *xkb_config);
-+/**
-+ * ibus_xkb_config_registry_get_variant_desc:
-+ * @xkb_config: An IBusXKBConfigRegistry.
-+ * @returns: A const GHashTable
-+ *
-+ * a const GHashTable
-+ */
-+const GHashTable *
-+ ibus_xkb_config_registry_get_variant_desc
-+ (IBusXKBConfigRegistry *xkb_config);
+/**
+ * ibus_xkb_component_new:
+ * @returns: A newly allocated IBusComponent.
diff --git a/ibus-HEAD.patch b/ibus-HEAD.patch
index c6a8da5..4be8960 100644
--- a/ibus-HEAD.patch
+++ b/ibus-HEAD.patch
@@ -226,3 +226,744 @@ index 0e9418e..39ad784 100644
--
1.7.4.4
+From d059132885d3c90647f08f3083e39daa9f82b700 Mon Sep 17 00:00:00 2001
+From: Ryo Onodera <onodera at clear-code.com>
+Date: Tue, 17 May 2011 20:07:40 +0900
+Subject: [PATCH] fix wrong forward key event signature
+
+---
+ ibus/engine.py | 4 ++--
+ ibus/interface/iengine.py | 4 ++--
+ 2 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/ibus/engine.py b/ibus/engine.py
+index 8cbcee3..fe5dd98 100644
+--- a/ibus/engine.py
++++ b/ibus/engine.py
+@@ -114,8 +114,8 @@ class EngineBase(object.Object):
+ text = serializable.serialize_object(text)
+ return self.__proxy.CommitText(text)
+
+- def forward_key_event(self, keyval, state):
+- return self.__proxy.ForwardKeyEvent(keyval, state)
++ def forward_key_event(self, keyval, keycode, state):
++ return self.__proxy.ForwardKeyEvent(keyval, keycode, state)
+
+ def update_preedit_text(self, text, cursor_pos, visible, mode=common.IBUS_ENGINE_PREEDIT_CLEAR):
+ text = serializable.serialize_object(text)
+diff --git a/ibus/interface/iengine.py b/ibus/interface/iengine.py
+index 0e0f4ee..9e0d981 100644
+--- a/ibus/interface/iengine.py
++++ b/ibus/interface/iengine.py
+@@ -104,8 +104,8 @@ class IEngine(dbus.service.Object):
+ @signal(signature="v")
+ def CommitText(self, text): pass
+
+- @signal(signature="uu")
+- def ForwardKeyEvent(self, keyval, state): pass
++ @signal(signature="uuu")
++ def ForwardKeyEvent(self, keyval, keycode, state): pass
+
+ @signal(signature="vubu")
+ def UpdatePreeditText(self, text, cursor_pos, visible, mode): pass
+--
+1.7.4.4
+
+From d3e750eab6db7035f494fcdb328b87b2923e33a2 Mon Sep 17 00:00:00 2001
+From: Yusuke Sato <yusukes at chromium.org>
+Date: Wed, 1 Jun 2011 23:37:14 +0900
+Subject: [PATCH] Send the new capabilities to ibus-daemon in
+ ibus_im_context_set_use_preedit.
+
+BUG=none
+TEST=none
+
+Review URL: http://codereview.appspot.com/4529103
+---
+ client/gtk2/ibusimcontext.c | 2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
+index ebae09d..4a894b0 100644
+--- a/client/gtk2/ibusimcontext.c
++++ b/client/gtk2/ibusimcontext.c
+@@ -942,6 +942,8 @@ ibus_im_context_set_use_preedit (GtkIMContext *context, gboolean use_preedit)
+ else {
+ ibusimcontext->caps &= ~IBUS_CAP_PREEDIT_TEXT;
+ }
++ ibus_input_context_set_capabilities (ibusimcontext->ibuscontext,
++ ibusimcontext->caps);
+ }
+ gtk_im_context_set_use_preedit (ibusimcontext->slave, use_preedit);
+ }
+--
+1.7.4.4
+
+From 52425daa537a32bed1781958e1ef62dbf199ad8b Mon Sep 17 00:00:00 2001
+From: Peng Huang <shawn.p.huang at gmail.com>
+Date: Mon, 6 Jun 2011 09:30:27 -0400
+Subject: [PATCH] Fix Python input context binding.
+
+Export "forward-key-event" and "delete-surrounding-text" signals to Python; clear __needs_surrounding_text property on "enabled" and "disabled" signals.
+
+BUG=none
+TEST=briefly tested, at least I don't see any regression
+
+Review URL: http://codereview.appspot.com/4437062
+---
+ ibus/inputcontext.py | 26 +++++++++++++++++++++++++-
+ ibus/interface/iinputcontext.py | 3 +++
+ 2 files changed, 28 insertions(+), 1 deletions(-)
+
+diff --git a/ibus/inputcontext.py b/ibus/inputcontext.py
+index d143727..ceeb56d 100644
+--- a/ibus/inputcontext.py
++++ b/ibus/inputcontext.py
+@@ -116,6 +116,16 @@ class InputContext(object.Object):
+ gobject.TYPE_NONE,
+ ()
+ ),
++ "forward-key-event" : (
++ gobject.SIGNAL_RUN_LAST,
++ gobject.TYPE_NONE,
++ (gobject.TYPE_UINT, gobject.TYPE_UINT, gobject.TYPE_UINT)
++ ),
++ "delete-surrounding-text" : (
++ gobject.SIGNAL_RUN_LAST,
++ gobject.TYPE_NONE,
++ (gobject.TYPE_INT, gobject.TYPE_UINT)
++ ),
+ }
+
+ def __init__(self, bus, path, watch_signals=False):
+@@ -142,8 +152,14 @@ class InputContext(object.Object):
+ self.__signal_matches.append(m)
+ m = self.__context.connect_to_signal("RequireSurroundingText", self.__require_surrounding_text_cb)
+ self.__signal_matches.append(m)
++ m = self.__context.connect_to_signal("Enabled", self.__enabled_cb)
++ self.__signal_matches.append(m)
++ m = self.__context.connect_to_signal("Disabled", self.__disabled_cb)
++ self.__signal_matches.append(m)
+
+- m = self.__context.connect_to_signal("Enabled", lambda *args: self.emit("enabled"))
++ m = self.__context.connect_to_signal("ForwardKeyEvent", lambda *args: self.emit("forward-key-event", *args))
++ self.__signal_matches.append(m)
++ m = self.__context.connect_to_signal("DeleteSurroundingText", lambda *args: self.emit("delete-surrounding-text", *args))
+ self.__signal_matches.append(m)
+ m = self.__context.connect_to_signal("Disabled", lambda *args: self.emit("disabled"))
+ self.__signal_matches.append(m)
+@@ -168,6 +184,14 @@ class InputContext(object.Object):
+ m = self.__context.connect_to_signal("CursorDownLookupTable", lambda *args: self.emit("cursor-down-lookup-table"))
+ self.__signal_matches.append(m)
+
++ def __enabled_cb(self, *args):
++ self.__needs_surrounding_text = False
++ self.emit("enabled")
++
++ def __disabled_cb(self, *args):
++ self.__needs_surrounding_text = False
++ self.emit("disabled")
++
+ def __commit_text_cb(self, *args):
+ text = serializable.deserialize_object(args[0])
+ self.emit("commit-text", text)
+diff --git a/ibus/interface/iinputcontext.py b/ibus/interface/iinputcontext.py
+index 2db1c9b..1d3cd2a 100644
+--- a/ibus/interface/iinputcontext.py
++++ b/ibus/interface/iinputcontext.py
+@@ -95,6 +95,9 @@ class IInputContext(dbus.service.Object):
+ @signal(signature="uuu")
+ def ForwardKeyEvent(self, keyval, keycode, state): pass
+
++ @signal(signature="iu")
++ def DeleteSurroundingText(self, offset_from_cursor, nchars): pass
++
+ @signal(signature="vub")
+ def UpdatePreeditText(self, text, cursor_pos, visible): pass
+
+--
+1.7.4.4
+
+From 59ce675e335e599ed18d74ab8849b9a5fe75d4be Mon Sep 17 00:00:00 2001
+From: Peng Huang <shawn.p.huang at gmail.com>
+Date: Mon, 13 Jun 2011 13:18:29 -0400
+Subject: [PATCH] Fix some race condition between idle and timeout
+ events. Also fix a memory leak.
+
+BUG=http://crosbug.com/16387
+TEST=Linux desktop
+
+Review URL: http://codereview.appspot.com/4568072
+---
+ bus/engineproxy.c | 46 ++++++++++++++++++++++++++++++----------------
+ 1 files changed, 30 insertions(+), 16 deletions(-)
+
+diff --git a/bus/engineproxy.c b/bus/engineproxy.c
+index 0c6f45d..f74af12 100644
+--- a/bus/engineproxy.c
++++ b/bus/engineproxy.c
+@@ -603,7 +603,8 @@ bus_engine_proxy_new_internal (const gchar *path,
+ g_assert (IBUS_IS_ENGINE_DESC (desc));
+ g_assert (G_IS_DBUS_CONNECTION (connection));
+
+-
++ GDBusProxyFlags flags = G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START |
++ G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES;
+ BusEngineProxy *engine =
+ (BusEngineProxy *) g_initable_new (BUS_TYPE_ENGINE_PROXY,
+ NULL,
+@@ -613,7 +614,7 @@ bus_engine_proxy_new_internal (const gchar *path,
+ "g-interface-name", IBUS_INTERFACE_ENGINE,
+ "g-object-path", path,
+ "g-default-timeout", g_gdbus_timeout,
+- "g-flags", G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START | G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
++ "g-flags", flags,
+ NULL);
+ const gchar *layout = ibus_engine_desc_get_layout (desc);
+ if (layout != NULL && layout[0] != '\0') {
+@@ -638,24 +639,33 @@ static void
+ engine_proxy_new_data_free (EngineProxyNewData *data)
+ {
+ if (data->simple != NULL) {
+- if (data->handler_id != 0)
+- g_signal_handler_disconnect (data->component, data->handler_id);
+ g_object_unref (data->simple);
+ }
+
+- if (data->component != NULL)
++ if (data->desc != NULL) {
++ g_object_unref (data->desc);
++ }
++
++ if (data->component != NULL) {
++ if (data->handler_id != 0) {
++ g_signal_handler_disconnect (data->component, data->handler_id);
++ }
+ g_object_unref (data->component);
++ }
+
+- if (data->factory != NULL)
++ if (data->factory != NULL) {
+ g_object_unref (data->factory);
++ }
+
+- if (data->timeout_id != 0)
++ if (data->timeout_id != 0) {
+ g_source_remove (data->timeout_id);
++ }
+
+ if (data->cancellable != NULL) {
+- if (data->cancelled_handler_id != 0)
++ if (data->cancelled_handler_id != 0) {
+ g_cancellable_disconnect (data->cancellable,
+- data->cancelled_handler_id);
++ data->cancelled_handler_id);
++ }
+ g_object_unref (data->cancellable);
+ }
+
+@@ -772,7 +782,8 @@ timeout_cb (EngineProxyNewData *data)
+ /**
+ * cancelled_cb:
+ *
+- * A callback function to be called when someone calls g_cancellable_cancel() for the cancellable object for bus_engine_proxy_new.
++ * A callback function to be called when someone calls g_cancellable_cancel()
++ * for the cancellable object for bus_engine_proxy_new.
+ * Call the GAsyncReadyCallback.
+ */
+ static gboolean
+@@ -793,8 +804,12 @@ static void
+ cancelled_cb (GCancellable *cancellable,
+ EngineProxyNewData *data)
+ {
+- /* Cancel the bus_engine_proxy_new() in idle to avoid deadlock */
+- g_idle_add ((GSourceFunc) cancelled_idle_cb, data);
++ /* Cancel the bus_engine_proxy_new() in idle to avoid deadlock.
++ * And use HIGH priority to avoid timeout event happening before
++ * idle callback. */
++ g_idle_add_full (G_PRIORITY_HIGH,
++ (GSourceFunc) cancelled_idle_cb,
++ data, NULL);
+ }
+
+ void
+@@ -831,13 +846,12 @@ bus_engine_proxy_new (IBusEngineDesc *desc,
+ data->simple = simple;
+ data->timeout = timeout;
+
+- g_object_set_data ((GObject *)data->simple, "EngineProxyNewData", data);
+-
+ data->factory = bus_component_get_factory (data->component);
+
+ if (data->factory == NULL) {
+- /* The factory is not ready yet. Create the factory first, and wait for the "notify::factory" signal.
+- * In the handler of "notify::factory", we'll create the engine proxy. */
++ /* The factory is not ready yet. Create the factory first, and wait for
++ * the "notify::factory" signal. In the handler of "notify::factory",
++ * we'll create the engine proxy. */
+ data->handler_id = g_signal_connect (data->component,
+ "notify::factory",
+ G_CALLBACK (notify_factory_cb),
+--
+1.7.4.4
+
+From fc9dedec30f724e91e7b3bb9111177e96b58ee43 Mon Sep 17 00:00:00 2001
+From: Peng Huang <shawn.p.huang at gmail.com>
+Date: Wed, 15 Jun 2011 10:38:17 -0400
+Subject: [PATCH] Add IBUS_ERROR domain and reply IBUS_ERROR_NO_ENGINE
+ in org.freedesktop.IBus.InputContext.GetEngine
+
+BUG=None
+TEST=Manually
+
+Review URL: http://codereview.appspot.com/4528140
+---
+ bus/inputcontext.c | 7 ++++-
+ src/Makefile.am | 2 +
+ src/ibus.h | 1 +
+ src/ibuserror.c | 41 +++++++++++++++++++++++++++++++++
+ src/ibuserror.h | 46 +++++++++++++++++++++++++++++++++++++
+ src/ibusinputcontext.c | 15 +++++++++--
+ src/ibusshare.c | 1 +
+ src/ibustypes.h | 9 +++++++
+ src/tests/ibus-gi-inputcontext.py | 34 +++++++++++++++++++++++++++
+ 9 files changed, 151 insertions(+), 5 deletions(-)
+ create mode 100644 src/ibuserror.c
+ create mode 100644 src/ibuserror.h
+ create mode 100755 src/tests/ibus-gi-inputcontext.py
+
+diff --git a/bus/inputcontext.c b/bus/inputcontext.c
+index bad90ec..1567c5f 100644
+--- a/bus/inputcontext.c
++++ b/bus/inputcontext.c
+@@ -1040,8 +1040,11 @@ _ic_get_engine (BusInputContext *context,
+ g_variant_new ("(v)", ibus_serializable_serialize ((IBusSerializable *)desc)));
+ }
+ else {
+- g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+- "Input context does not have engine.");
++ g_dbus_method_invocation_return_error (
++ invocation,
++ IBUS_ERROR,
++ IBUS_ERROR_NO_ENGINE,
++ "Input context does not have engine.");
+ }
+ }
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 632fc72..a53bd23 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -70,6 +70,7 @@ ibus_sources = \
+ ibusservice.c \
+ ibusfactory.c \
+ ibusengine.c \
++ ibuserror.c \
+ ibustext.c \
+ ibuskeymap.c \
+ ibusattribute.c \
+@@ -114,6 +115,7 @@ ibus_headers = \
+ ibusservice.h \
+ ibusfactory.h \
+ ibusengine.h \
++ ibuserror.h \
+ ibustext.h \
+ ibuskeymap.h \
+ ibusattribute.h \
+diff --git a/src/ibus.h b/src/ibus.h
+index 8df7160..c408f3d 100644
+--- a/src/ibus.h
++++ b/src/ibus.h
+@@ -35,6 +35,7 @@
+ #include <ibusservice.h>
+ #include <ibusfactory.h>
+ #include <ibusengine.h>
++#include <ibuserror.h>
+ #include <ibusproperty.h>
+ #include <ibusproplist.h>
+ #include <ibuslookuptable.h>
+diff --git a/src/ibuserror.c b/src/ibuserror.c
+new file mode 100644
+index 0000000..c50c164
+--- /dev/null
++++ b/src/ibuserror.c
+@@ -0,0 +1,41 @@
++/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
++/* vim:set et sts=4: */
++/* ibus - The Input Bus
++ * Copyright (C) 2011 Peng Huang <shawn.p.huang at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#include "ibuserror.h"
++
++#include <gio/gio.h>
++#include "ibustypes.h"
++
++static const GDBusErrorEntry ibus_error_entries[] =
++{
++ { IBUS_ERROR_NO_ENGINE, "org.freedesktop.IBus.Error.NoEngine" },
++};
++
++GQuark
++ibus_error_quark (void)
++{
++ static volatile gsize quark_volatile = 0;
++ g_dbus_error_register_error_domain ("ibus-error-quark",
++ &quark_volatile,
++ ibus_error_entries,
++ G_N_ELEMENTS (ibus_error_entries));
++ return (GQuark) quark_volatile;
++}
+diff --git a/src/ibuserror.h b/src/ibuserror.h
+new file mode 100644
+index 0000000..75c64b9
+--- /dev/null
++++ b/src/ibuserror.h
+@@ -0,0 +1,46 @@
++/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
++/* vim:set et sts=4: */
++/* ibus - The Input Bus
++ * Copyright (C) 2011 Peng Huang <shawn.p.huang at gmail.com>
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#if !defined (__IBUS_H_INSIDE__) && !defined (IBUS_COMPILATION)
++#error "Only <ibus.h> can be included directly"
++#endif
++
++/**
++ * SECTION: ibusshare
++ * @short_description: Shared utility functions and definition.
++ * @stability: Stable
++ *
++ * This file defines some utility functions and definition
++ * which are shared among ibus component and services.
++ */
++
++#ifndef __IBUS_ERROR_H_
++#define __IBUS_ERROR_H_
++
++#include <glib.h>
++
++G_BEGIN_DECLS
++
++#define IBUS_ERROR ibus_error_quark()
++GQuark ibus_error_quark (void);
++
++G_END_DECLS
++#endif
+diff --git a/src/ibusinputcontext.c b/src/ibusinputcontext.c
+index e6f97e8..78d454e 100644
+--- a/src/ibusinputcontext.c
++++ b/src/ibusinputcontext.c
+@@ -27,6 +27,7 @@
+ #include "ibusattribute.h"
+ #include "ibuslookuptable.h"
+ #include "ibusproplist.h"
++#include "ibuserror.h"
+
+ #define IBUS_INPUT_CONTEXT_GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_INPUT_CONTEXT, IBusInputContextPrivate))
+@@ -1164,7 +1165,7 @@ IBusEngineDesc *
+ ibus_input_context_get_engine (IBusInputContext *context)
+ {
+ g_assert (IBUS_IS_INPUT_CONTEXT (context));
+- GVariant *result;
++ GVariant *result = NULL;
+ GError *error = NULL;
+ result = g_dbus_proxy_call_sync ((GDBusProxy *) context,
+ "GetEngine", /* method_name */
+@@ -1174,9 +1175,17 @@ ibus_input_context_get_engine (IBusInputContext *context)
+ NULL, /* cancellable */
+ &error /* error */
+ );
+-
+ if (result == NULL) {
+- g_warning ("%s.GetEngine: %s", IBUS_INTERFACE_INPUT_CONTEXT, error->message);
++ if (g_error_matches (error, IBUS_ERROR, IBUS_ERROR_NO_ENGINE)) {
++ g_debug ("%s.GetEngine: %s",
++ IBUS_INTERFACE_INPUT_CONTEXT,
++ error->message);
++ }
++ else {
++ g_warning ("%s.GetEngine: %s",
++ IBUS_INTERFACE_INPUT_CONTEXT,
++ error->message);
++ }
+ g_error_free (error);
+ return NULL;
+ }
+diff --git a/src/ibusshare.c b/src/ibusshare.c
+index 1b8ae2a..19f9f65 100644
+--- a/src/ibusshare.c
++++ b/src/ibusshare.c
+@@ -318,6 +318,7 @@ void
+ ibus_init (void)
+ {
+ g_type_init ();
++ IBUS_ERROR;
+ IBUS_TYPE_TEXT;
+ IBUS_TYPE_ATTRIBUTE;
+ IBUS_TYPE_ATTR_LIST;
+diff --git a/src/ibustypes.h b/src/ibustypes.h
+index 6a31847..8146719 100644
+--- a/src/ibustypes.h
++++ b/src/ibustypes.h
+@@ -177,6 +177,15 @@ typedef enum {
+ } IBusBusRequestNameReply;
+
+ /**
++ * IBusError:
++ * @IBUS_ERROR_NO_ENGINE:
++ * There is no engine associated with input context.
++ */
++typedef enum {
++ IBUS_ERROR_NO_ENGINE,
++} IBusError;
++
++/**
+ * IBusRectangle:
+ * @x: x coordinate.
+ * @y: y coordinate.
+diff --git a/src/tests/ibus-gi-inputcontext.py b/src/tests/ibus-gi-inputcontext.py
+new file mode 100755
+index 0000000..80fb97b
+--- /dev/null
++++ b/src/tests/ibus-gi-inputcontext.py
+@@ -0,0 +1,34 @@
++#!/usr/bin/env python
++# vim:set et sts=4 sw=4:
++#
++# ibus - The Input Bus
++#
++# Copyright (c) 2011 Peng Huang <shawn.p.huang at gmail.com>
++#
++# This library is free software; you can redistribute it and/or
++# modify it under the terms of the GNU Lesser General Public
++# License as published by the Free Software Foundation; either
++# version 2 of the License, or (at your option) any later version.
++#
++# This library is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++# GNU Lesser General Public License for more details.
++#
++# You should have received a copy of the GNU Lesser General Public
++# License along with this program; if not, write to the
++# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
++# Boston, MA 02111-1307 USA
++
++
++import glib
++import gio
++from gi.repository import IBus
++IBus.init()
++main = glib.MainLoop()
++bus = IBus.Bus()
++ic = bus.create_input_context("ibus-test")
++ic.get_engine()
++ic.get_engine()
++ic.get_engine()
++ic.get_engine()
+--
+1.7.4.4
+
+From aec97ac090980dfcd7eeef55c1755f6cd3f87a01 Mon Sep 17 00:00:00 2001
+From: Daiki Ueno <daiki.ueno at gmail.com>
+Date: Sat, 18 Jun 2011 00:03:07 -0400
+Subject: [PATCH] Simplify surrounding-text initialization.
+
+Currently the immodule tries to retrieve surrounding-text unconditionally
+on focus_in and enabled. These calls could be eliminated if engine were
+able to proclaim that it will need surrounding-text.
+
+This patch extends ibus_engine_get_surrounding_text() to allow this.
+Engines that need surrounding-text are expected to have:
+
+ /* Indicate we will use surrounding-text. */
+ ibus_engine_get_surrounding_text (engine, NULL, NULL);
+
+in their enable() method. This would work because enable() is called before
+SetCapabilities DBus call.
+
+BUG=none
+TEST=manually with ibus-m17n, with the above change.
+
+Review URL: http://codereview.appspot.com/4613043
+Patch from Daiki Ueno <daiki.ueno at gmail.com>.
+---
+ client/gtk2/ibusimcontext.c | 23 +++++++++--------------
+ src/ibusengine.c | 10 ++++++----
+ src/ibusengine.h | 9 +++++++--
+ 3 files changed, 22 insertions(+), 20 deletions(-)
+
+diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
+index ec764ef..a4e7a16 100644
+--- a/client/gtk2/ibusimcontext.c
++++ b/client/gtk2/ibusimcontext.c
+@@ -147,8 +147,7 @@ static gboolean _slave_delete_surroundin
+ gint offset_from_cursor,
+ guint nchars,
+ IBusIMContext *context);
+-static void _request_surrounding_text (IBusIMContext *context,
+- gboolean force);
++static void _request_surrounding_text (IBusIMContext *context);
+ static void _create_fake_input_context (void);
+
+
+@@ -263,17 +262,13 @@ _process_key_event_done (GObject *o
+ /* emit "retrieve-surrounding" glib signal of GtkIMContext, if
+ * context->caps has IBUS_CAP_SURROUNDING_TEXT and the current IBus
+ * engine needs surrounding-text.
+- *
+- * if "force" is TRUE, emit the signal regardless of whether the
+- * engine needs surrounding-text.
+ */
+ static void
+-_request_surrounding_text (IBusIMContext *context, gboolean force)
++_request_surrounding_text (IBusIMContext *context)
+ {
+- if (context->enable &&
++ if (context && context->enable &&
+ (context->caps & IBUS_CAP_SURROUNDING_TEXT) != 0 &&
+- (force ||
+- ibus_input_context_needs_surrounding_text (context->ibuscontext))) {
++ ibus_input_context_needs_surrounding_text (context->ibuscontext)) {
+ gboolean return_value;
+ IDEBUG ("requesting surrounding text");
+ g_signal_emit (context, _signal_retrieve_surrounding_id, 0,
+@@ -368,9 +363,8 @@ _key_snooper_cb (GtkWidget *widget,
+
+ } while (0);
+
+- _request_surrounding_text (ibusimcontext, FALSE);
+-
+ if (ibusimcontext != NULL) {
++ _request_surrounding_text (ibusimcontext);
+ ibusimcontext->time = event->time;
+ }
+
+@@ -680,7 +674,7 @@ ibus_im_context_filter_keypress (GtkIMCo
+ if (ibusimcontext->client_window == NULL && event->window != NULL)
+ gtk_im_context_set_client_window ((GtkIMContext *)ibusimcontext, event->window);
+
+- _request_surrounding_text (ibusimcontext, FALSE);
++ _request_surrounding_text (ibusimcontext);
+
+ if (ibusimcontext != NULL) {
+ ibusimcontext->time = event->time;
+@@ -763,7 +757,7 @@ ibus_im_context_focus_in (GtkIMContext *
+
+ /* retrieve the initial surrounding-text (regardless of whether
+ * the current IBus engine needs surrounding-text) */
+- _request_surrounding_text (ibusimcontext, TRUE);
++ _request_surrounding_text (ibusimcontext);
+
+ g_object_add_weak_pointer ((GObject *) context,
+ (gpointer *) &_focus_im_context);
+@@ -1000,7 +996,7 @@ _ibus_context_commit_text_cb (IBusInputC
+
+ g_signal_emit (ibusimcontext, _signal_commit_id, 0, text->text);
+
+- _request_surrounding_text (ibusimcontext, FALSE);
++ _request_surrounding_text (ibusimcontext);
+ }
+
+ static gboolean
+@@ -1296,7 +1292,7 @@ _ibus_context_show_preedit_text_cb (IBus
+ g_signal_emit (ibusimcontext, _signal_preedit_start_id, 0);
+ g_signal_emit (ibusimcontext, _signal_preedit_changed_id, 0);
+
+- _request_surrounding_text (ibusimcontext, FALSE);
++ _request_surrounding_text (ibusimcontext);
+ }
+
+ static void
+@@ -1323,7 +1319,7 @@ _ibus_context_enabled_cb (IBusInputConte
+
+ /* retrieve the initial surrounding-text (regardless of whether
+ * the current IBus engine needs surrounding-text) */
+- _request_surrounding_text (ibusimcontext, TRUE);
++ _request_surrounding_text (ibusimcontext);
+ }
+
+ static void
+diff --git a/src/ibusengine.c b/src/ibusengine.c
+index f545bef..620d07f 100644
+--- a/src/ibusengine.c
++++ b/src/ibusengine.c
+@@ -1382,13 +1382,15 @@ ibus_engine_get_surrounding_text (IBusEngine *engine,
+ IBusEnginePrivate *priv;
+
+ g_return_if_fail (IBUS_IS_ENGINE (engine));
+- g_return_if_fail (text != NULL);
+- g_return_if_fail (cursor_pos != NULL);
++ g_return_if_fail ((text != NULL && cursor_pos != NULL) ||
++ (text == NULL && cursor_pos == NULL));
+
+ priv = IBUS_ENGINE_GET_PRIVATE (engine);
+
+- *text = g_object_ref (priv->surrounding_text);
+- *cursor_pos = priv->surrounding_cursor_pos;
++ if (text && cursor_pos) {
++ *text = g_object_ref (priv->surrounding_text);
++ *cursor_pos = priv->surrounding_cursor_pos;
++ }
+
+ /* tell the client that this engine will utilize surrounding-text
+ * feature, which causes periodical update. Note that the client
+diff --git a/src/ibusengine.h b/src/ibusengine.h
+index 29b8f1d..6da342a 100644
+--- a/src/ibusengine.h
++++ b/src/ibusengine.h
+@@ -407,11 +407,16 @@ void ibus_engine_delete_surrounding_text(IBusEngine *engine,
+ /**
+ * ibus_engine_get_surrounding_text:
+ * @engine: An IBusEngine.
+- * @text: Location to store surrounding text.
+- * @cursor_pos: Cursor position in characters in @text.
++ * @text: (allow-none): Location to store surrounding text.
++ * @cursor_pos: (allow-none): Cursor position in characters in @text.
+ *
+ * Get surrounding text.
+ *
++ * It is also used to tell the input-context that the engine will
++ * utilize surrounding-text. In that case, it must be called in
++ * #IBusEngine::enable handler, with both @text and @cursor set to
++ * %NULL.
++ *
+ * @see_also #IBusEngine::set-surrounding-text
+ */
+ void ibus_engine_get_surrounding_text(IBusEngine *engine,
+--
+1.7.4.4
+
diff --git a/ibus-xx-bridge-hotkey.patch b/ibus-xx-bridge-hotkey.patch
new file mode 100644
index 0000000..824dd81
--- /dev/null
+++ b/ibus-xx-bridge-hotkey.patch
@@ -0,0 +1,874 @@
+From a3a7b364410511b3a17f2b1566ba4c4c4f0de2cf Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1 at gmail.com>
+Date: Tue, 21 Jun 2011 17:00:54 +0900
+Subject: [PATCH] Add a bridge hotkey which use prev-next engines instead
+ of on-off.
+
+---
+ bus/Makefile.am | 20 ++--
+ bus/ibusimpl.c | 244 ++++++++++++++++++++++++++++----------
+ bus/registry.c | 35 ++++++
+ configure.ac | 31 +++++
+ data/Makefile.am | 6 +-
+ data/ibus.schemas.in | 286 --------------------------------------------
+ data/ibus.schemas.in.in | 286 ++++++++++++++++++++++++++++++++++++++++++++
+ ibus/_config.py.in | 6 +
+ ibus/inputcontext.py | 4 +
+ src/Makefile.am | 1 +
+ src/ibusbus.c | 6 +
+ src/ibusbus.h | 9 ++
+ src/ibusenginedesc.c | 4 +
+ src/ibushotkey.c | 11 ++
+ src/ibushotkey.h | 11 ++
+ ui/gtk/panel.py | 60 +++++++++-
+ xkb/Makefile.am | 2 +
+ xkb/ibus-engine-xkb-main.c | 8 ++
+ xkb/xkbxml.c | 8 +-
+ 19 files changed, 677 insertions(+), 361 deletions(-)
+ delete mode 100644 data/ibus.schemas.in
+ create mode 100644 data/ibus.schemas.in.in
+
+diff --git a/bus/Makefile.am b/bus/Makefile.am
+index 074b456..0efaa1b 100644
+--- a/bus/Makefile.am
++++ b/bus/Makefile.am
+@@ -29,15 +29,17 @@ INCLUDES = \
+ -I$(top_builddir)/src \
+ $(NULL)
+
+-AM_CFLAGS = \
+- @GLIB2_CFLAGS@ \
+- @GIO2_CFLAGS@ \
+- @GTHREAD2_CFLAGS@ \
+- -DG_LOG_DOMAIN=\"IBUS\" \
+- -DPKGDATADIR=\"$(pkgdatadir)\" \
+- -DLIBEXECDIR=\"$(libexecdir)\" \
+- -DBINDIR=\"@bindir@\" \
+- $(INCLUDES) \
++AM_CFLAGS = \
++ @GLIB2_CFLAGS@ \
++ @GIO2_CFLAGS@ \
++ @GTHREAD2_CFLAGS@ \
++ -DG_LOG_DOMAIN=\"IBUS\" \
++ -DPKGDATADIR=\"$(pkgdatadir)\" \
++ -DLIBEXECDIR=\"$(libexecdir)\" \
++ -DBINDIR=\"@bindir@\" \
++ -DUSE_BRIDGE_HOTKEY=$(USE_BRIDGE_HOTKEY) \
++ -DDEFAULT_BRIDGE_ENGINE_NAME=\"$(DEFAULT_BRIDGE_ENGINE_NAME)\" \
++ $(INCLUDES) \
+ $(NULL)
+ AM_LDADD = \
+ @GOBJECT2_LIBS@ \
+diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c
+index 38d6d11..3b2d539 100644
+--- a/bus/ibusimpl.c
++++ b/bus/ibusimpl.c
+@@ -20,6 +20,10 @@
+ * Boston, MA 02111-1307, USA.
+ */
+
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
+ #include <unistd.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+@@ -79,6 +83,8 @@ struct _BusIBusImpl {
+ /* engine-specific hotkeys */
+ IBusHotkeyProfile *engines_hotkey_profile;
+ GHashTable *hotkey_to_engines_map;
++
++ IBusEngineDesc *prev_hotkey_engine;
+ };
+
+ struct _BusIBusImplClass {
+@@ -285,6 +291,30 @@ _panel_destroy_cb (BusPanelProxy *panel,
+ g_object_unref (panel);
+ }
+
++static IBusEngineDesc *
++_find_engine_desc_by_name (BusIBusImpl *ibus,
++ const gchar *engine_name)
++{
++ IBusEngineDesc *desc = NULL;
++ GList *p;
++
++ /* find engine in registered engine list */
++ for (p = ibus->register_engine_list; p != NULL; p = p->next) {
++ desc = (IBusEngineDesc *) p->data;
++ if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0)
++ return desc;
++ }
++
++ /* find engine in preload engine list */
++ for (p = ibus->engine_list; p != NULL; p = p->next) {
++ desc = (IBusEngineDesc *) p->data;
++ if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0)
++ return desc;
++ }
++
++ return NULL;
++}
++
+ static void
+ _config_set_value_done (GObject *object,
+ GAsyncResult *res,
+@@ -475,8 +505,17 @@ _set_preload_engines (BusIBusImpl *ibus,
+ g_variant_unref (value);
+ }
+
+- g_list_foreach (engine_list, (GFunc) g_object_ref, NULL);
+ ibus->engine_list = engine_list;
++#if USE_BRIDGE_HOTKEY
++ if (_find_engine_desc_by_name (ibus, DEFAULT_BRIDGE_ENGINE_NAME) == NULL) {
++ IBusEngineDesc *engine = bus_registry_find_engine_by_name (ibus->registry,
++ DEFAULT_BRIDGE_ENGINE_NAME);
++ g_assert (engine != NULL);
++ engine_list = g_list_append (engine_list, engine);
++ ibus->engine_list = engine_list;
++ }
++#endif
++ g_list_foreach (engine_list, (GFunc) g_object_ref, NULL);
+
+ if (ibus->engine_list) {
+ BusComponent *component = bus_component_from_engine_desc ((IBusEngineDesc *) ibus->engine_list->data);
+@@ -1182,28 +1221,110 @@ _ibus_get_address (BusIBusImpl
+ g_variant_new ("(s)", bus_server_get_address ()));
+ }
+
+-static IBusEngineDesc *
+-_find_engine_desc_by_name (BusIBusImpl *ibus,
+- const gchar *engine_name)
+-{
+- IBusEngineDesc *desc = NULL;
+- GList *p;
++/**
++ * _foreach_remove_engine_hotkey:
++ *
++ * Remove the engine-specific hot key of the engine, and update ibus->engines_hotkey_profile.
++ */
++gboolean
++_foreach_remove_engine_hotkey (gpointer key,
++ gpointer value,
++ gpointer data)
++{
++ GQuark event = GPOINTER_TO_UINT (value);
++ struct _impl_and_desc {
++ BusIBusImpl *ibus;
++ IBusEngineDesc *desc;
++ } *id = (struct _impl_and_desc *) data;
++ BusIBusImpl *ibus = id->ibus;
++ IBusEngineDesc *desc = id->desc;
++ GList *engine_list;
+
+- /* find engine in registered engine list */
+- for (p = ibus->register_engine_list; p != NULL; p = p->next) {
+- desc = (IBusEngineDesc *) p->data;
+- if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0)
+- return desc;
++ g_assert (ibus != NULL);
++ g_assert (desc != NULL);
++
++ if (event == 0) {
++ return FALSE;
+ }
+
+- /* find engine in preload engine list */
+- for (p = ibus->engine_list; p != NULL; p = p->next) {
+- desc = (IBusEngineDesc *) p->data;
+- if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0)
+- return desc;
++ engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map,
++ GUINT_TO_POINTER (event));
++
++ /* As we will rebuild the engines hotkey map whenever an engine was
++ * added or removed, we don't need to hold a reference of the engine
++ * here. */
++ if (engine_list && g_list_find (engine_list, desc) != NULL) {
++ engine_list = g_list_remove (engine_list, desc);
+ }
+
+- return NULL;
++ /* We need to steal the value before adding it back, otherwise it will
++ * be destroyed. */
++ g_hash_table_steal (ibus->hotkey_to_engines_map, GUINT_TO_POINTER (event));
++
++ if (engine_list != NULL) {
++ g_hash_table_insert (ibus->hotkey_to_engines_map,
++ GUINT_TO_POINTER (event), engine_list);
++ }
++
++ return FALSE;
++}
++
++/**
++ * _add_engine_hotkey_with_hotkeys:
++ *
++ * Check the engine-specific hot key of the engine, and update ibus->engines_hotkey_profile.
++ */
++static void
++_add_engine_hotkey_with_hotkeys (IBusEngineDesc *engine,
++ BusIBusImpl *ibus,
++ const gchar *hotkeys)
++{
++ gchar **hotkey_list;
++ gchar **p;
++ gchar *hotkey;
++ GList *engine_list;
++
++ GQuark event;
++ guint keyval;
++ guint modifiers;
++
++ g_assert (engine != NULL);
++ g_assert (hotkeys && *hotkeys);
++
++ hotkey_list = g_strsplit_set (hotkeys, ";,", 0);
++
++ for (p = hotkey_list; p && *p; ++p) {
++ hotkey = g_strstrip (*p);
++ if (!*hotkey || !ibus_key_event_from_string (hotkey, &keyval, &modifiers)) {
++ continue;
++ }
++
++ /* If the hotkey already exists, we won't need to add it again. */
++ event = ibus_hotkey_profile_lookup_hotkey (ibus->engines_hotkey_profile,
++ keyval, modifiers);
++ if (event == 0) {
++ event = g_quark_from_string (hotkey);
++ ibus_hotkey_profile_add_hotkey (ibus->engines_hotkey_profile,
++ keyval, modifiers, event);
++ }
++
++ engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map,
++ GUINT_TO_POINTER (event));
++
++ /* As we will rebuild the engines hotkey map whenever an engine was
++ * added or removed, we don't need to hold a reference of the engine
++ * here. */
++ engine_list = g_list_append (engine_list, engine);
++
++ /* We need to steal the value before adding it back, otherwise it will
++ * be destroyed. */
++ g_hash_table_steal (ibus->hotkey_to_engines_map, GUINT_TO_POINTER (event));
++
++ g_hash_table_insert (ibus->hotkey_to_engines_map,
++ GUINT_TO_POINTER (event), engine_list);
++ }
++
++ g_strfreev (hotkey_list);
+ }
+
+ /**
+@@ -1216,7 +1337,39 @@ _context_request_engine_cb (BusInputCont
+ const gchar *engine_name,
+ BusIBusImpl *ibus)
+ {
+- return bus_ibus_impl_get_engine_desc (ibus, engine_name);
++ IBusEngineDesc *desc = bus_ibus_impl_get_engine_desc (ibus, engine_name);
++ struct _impl_and_desc {
++ BusIBusImpl *ibus;
++ IBusEngineDesc *desc;
++ } id = {ibus, desc};
++
++#if USE_BRIDGE_HOTKEY
++ IBusEngineDesc *current_desc = NULL;
++ if (context) {
++ BusEngineProxy *engine = bus_input_context_get_engine (context);
++ if (engine != NULL) {
++ current_desc = bus_engine_proxy_get_desc (engine);
++ }
++ }
++ if (current_desc) {
++ ibus->prev_hotkey_engine = current_desc;
++ }
++ if (current_desc != NULL && desc != NULL &&
++ g_strcmp0 (ibus_engine_desc_get_name (current_desc),
++ ibus_engine_desc_get_name (desc)) != 0 &&
++ g_strcmp0 (ibus_engine_desc_get_name (desc),
++ DEFAULT_BRIDGE_ENGINE_NAME) == 0) {
++ const gchar *hotkeys = ibus_engine_desc_get_hotkeys (current_desc);
++ if (!hotkeys || !*hotkeys) {
++ hotkeys = "Control+space";
++ }
++ ibus_hotkey_profile_foreach_hotkey (ibus->engines_hotkey_profile,
++ _foreach_remove_engine_hotkey,
++ &id);
++ _add_engine_hotkey_with_hotkeys (desc, ibus, hotkeys);
++ }
++#endif
++ return desc;
+ }
+
+ /**
+@@ -2357,6 +2510,11 @@ bus_ibus_impl_filter_keyboard_shortcuts
+ * the same hotkey, then we should switch to the next engine with the
+ * same hotkey in the list. Otherwise, we just switch to the first
+ * engine in the list. */
++#if USE_BRIDGE_HOTKEY
++ if (ibus->prev_hotkey_engine) {
++ new_engine_desc = ibus->prev_hotkey_engine;
++ }
++#else
+ GList *p = engine_list;
+ for (; p->next != NULL; p = p->next) {
+ if (current_engine_desc == (IBusEngineDesc *) p->data) {
+@@ -2364,9 +2522,14 @@ bus_ibus_impl_filter_keyboard_shortcuts
+ break;
+ }
+ }
++#endif
+
+ if (current_engine_desc != new_engine_desc) {
++ ibus->prev_hotkey_engine = current_engine_desc;
+ bus_ibus_impl_set_context_engine_from_desc (ibus, context, new_engine_desc);
++ } else {
++ g_warning ("The engine %s is registered twice in hotkeys",
++ ibus_engine_desc_get_name (current_engine_desc));
+ }
+
+ return TRUE;
+@@ -2470,14 +2633,6 @@ static void
+ _add_engine_hotkey (IBusEngineDesc *engine, BusIBusImpl *ibus)
+ {
+ const gchar *hotkeys;
+- gchar **hotkey_list;
+- gchar **p;
+- gchar *hotkey;
+- GList *engine_list;
+-
+- GQuark event;
+- guint keyval;
+- guint modifiers;
+
+ if (!engine) {
+ return;
+@@ -2489,40 +2644,7 @@ _add_engine_hotkey (IBusEngineDesc *engi
+ return;
+ }
+
+- hotkey_list = g_strsplit_set (hotkeys, ";,", 0);
+-
+- for (p = hotkey_list; p && *p; ++p) {
+- hotkey = g_strstrip (*p);
+- if (!*hotkey || !ibus_key_event_from_string (hotkey, &keyval, &modifiers)) {
+- continue;
+- }
+-
+- /* If the hotkey already exists, we won't need to add it again. */
+- event = ibus_hotkey_profile_lookup_hotkey (ibus->engines_hotkey_profile,
+- keyval, modifiers);
+- if (event == 0) {
+- event = g_quark_from_string (hotkey);
+- ibus_hotkey_profile_add_hotkey (ibus->engines_hotkey_profile,
+- keyval, modifiers, event);
+- }
+-
+- engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map,
+- GUINT_TO_POINTER (event));
+-
+- /* As we will rebuild the engines hotkey map whenever an engine was
+- * added or removed, we don't need to hold a reference of the engine
+- * here. */
+- engine_list = g_list_append (engine_list, engine);
+-
+- /* We need to steal the value before adding it back, otherwise it will
+- * be destroyed. */
+- g_hash_table_steal (ibus->hotkey_to_engines_map, GUINT_TO_POINTER (event));
+-
+- g_hash_table_insert (ibus->hotkey_to_engines_map,
+- GUINT_TO_POINTER (event), engine_list);
+- }
+-
+- g_strfreev (hotkey_list);
++ _add_engine_hotkey_with_hotkeys (engine, ibus, hotkeys);
+ }
+
+ /**
+diff --git a/bus/registry.c b/bus/registry.c
+index bc6680d..f47f727 100644
+--- a/bus/registry.c
++++ b/bus/registry.c
+@@ -19,6 +19,11 @@
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
++
++#ifdef HAVE_CONFIG_H
++#include <config.h>
++#endif
++
+ #include "registry.h"
+ #include <glib/gstdio.h>
+ #include <gio/gio.h>
+@@ -101,6 +106,9 @@ bus_registry_init (BusRegistry *registry)
+ registry->observed_paths = NULL;
+ registry->components = NULL;
+ registry->engine_table = g_hash_table_new (g_str_hash, g_str_equal);
++#if USE_BRIDGE_HOTKEY
++ gboolean has_default_engine = FALSE;
++#endif
+
+ #ifdef G_THREADS_ENABLED
+ /* If glib supports thread, we'll create a thread to monitor changes in IME
+@@ -145,12 +153,39 @@ bus_registry_init (BusRegistry *registry)
+ GList *p1;
+ for (p1 = engines; p1 != NULL; p1 = p1->next) {
+ IBusEngineDesc *desc = (IBusEngineDesc *) p1->data;
++#if USE_BRIDGE_HOTKEY
++ if (g_strcmp0 (ibus_engine_desc_get_name (desc),
++ DEFAULT_BRIDGE_ENGINE_NAME) == 0) {
++ has_default_engine = TRUE;
++ }
++#endif
+ g_hash_table_insert (registry->engine_table,
+ (gpointer) ibus_engine_desc_get_name (desc),
+ desc);
+ }
+ g_list_free (engines);
+ }
++
++#if USE_BRIDGE_HOTKEY
++ if (has_default_engine == FALSE) {
++ bus_registry_remove_all (registry);
++ bus_registry_load (registry);
++ bus_registry_save_cache (registry);
++
++ for (p = registry->components; p != NULL; p = p->next) {
++ BusComponent *comp = (BusComponent *) p->data;
++ GList *engines = bus_component_get_engines (comp);
++ GList *p1;
++ for (p1 = engines; p1 != NULL; p1 = p1->next) {
++ IBusEngineDesc *desc = (IBusEngineDesc *) p1->data;
++ g_hash_table_insert (registry->engine_table,
++ (gpointer) ibus_engine_desc_get_name (desc),
++ desc);
++ }
++ g_list_free (engines);
++ }
++ }
++#endif
+ }
+
+ static void
+diff --git a/configure.ac b/configure.ac
+index 85e5e30..a6974d4 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -438,6 +438,34 @@ else
+ enable_surrounding_text="no (disabled, use --enable-surrounding-text to enable)"
+ fi
+
++# option for bridge hotkey
++AC_ARG_ENABLE(bridge-hotkey,
++ AS_HELP_STRING([--enable-bridge-hotkey],
++ [Enable bridge hotkey instead of ON/OFF hotkey]),
++ [enable_bridge_hotkey=$enableval],
++ [enable_bridge_hotkey=no]
++)
++
++if test x"$enable_bridge_hotkey" = x"yes"; then
++ USE_BRIDGE_HOTKEY=1
++ TRIGGER_HOTKEYS=""
++else
++ USE_BRIDGE_HOTKEY=0
++ TRIGGER_HOTKEYS="Control+space,Zenkaku_Hankaku,Alt+Kanji,Alt+grave,Hangul,Alt+Release+Alt_R"
++ enable_bridge_hotkey="no (disabled, use --enable-bridge-hotkey to enable)"
++fi
++AC_SUBST(USE_BRIDGE_HOTKEY)
++AC_SUBST(TRIGGER_HOTKEYS)
++
++# define default bridge engine name
++AC_ARG_WITH(bridge-engine,
++ AS_HELP_STRING([--with-bridge-engine[=bridge_engine_name]],
++ [Set bridge engine name in IM bridge hotkey. (default: xkb:layout:default)]),
++ [DEFAULT_BRIDGE_ENGINE_NAME=$with_bridge_engine],
++ [DEFAULT_BRIDGE_ENGINE_NAME="xkb:layout:default"]
++)
++AC_SUBST(DEFAULT_BRIDGE_ENGINE_NAME)
++
+ # check iso-codes
+ PKG_CHECK_MODULES(ISOCODES, [
+ iso-codes
+@@ -464,6 +492,7 @@ bus/Makefile
+ util/Makefile
+ util/IMdkit/Makefile
+ data/Makefile
++data/ibus.schemas.in
+ data/icons/Makefile
+ data/keymaps/Makefile
+ docs/Makefile
+@@ -512,5 +541,7 @@ Build options:
+ No snooper regexes "$NO_SNOOPER_APPS"
+ Panel icon "$IBUS_ICON_KEYBOARD"
+ Enable surrounding-text $enable_surrounding_text
++ Enable bridge hotkey $enable_bridge_hotkey
++ Default bridge engine $DEFAULT_BRIDGE_ENGINE_NAME
+ ])
+
+diff --git a/data/Makefile.am b/data/Makefile.am
+index ba9f4bb..a909e5b 100644
+--- a/data/Makefile.am
++++ b/data/Makefile.am
+@@ -26,7 +26,8 @@ SUBDIRS = \
+ $(NULL)
+
+ schemasdir = $(GCONF_SCHEMA_FILE_DIR)
+-schemas_in_files = ibus.schemas.in
++schemas_in_in_files = ibus.schemas.in.in
++schemas_in_files = $(schemas_in_in_files:.schemas.in.in=.schemas.in)
+ schemas_DATA = $(schemas_in_files:.schemas.in=.schemas)
+ @INTLTOOL_SCHEMAS_RULE@
+
+@@ -41,11 +42,12 @@ if GCONF_SCHEMAS_INSTALL
+ endif
+
+ EXTRA_DIST = \
+- $(schemas_in_files) \
++ $(schemas_in_in_files) \
+ $(NULL)
+
+ DISTCLEANFILES = \
+ $(schemas_DATA) \
++ $(schemas_in_files) \
+ $(NULL)
+
+ -include $(top_srcdir)/git.mk
+diff --git a/data/ibus.schemas.in b/data/ibus.schemas.in.in
+index 7ca4899..42d9297
+--- a/data/ibus.schemas.in
++++ b/data/ibus.schemas.in.in
+@@ -31,7 +31,7 @@
+ <owner>ibus</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+- <default>[Control+space,Zenkaku_Hankaku,Alt+Kanji,Alt+grave,Hangul,Alt+Release+Alt_R]</default>
++ <default>[@TRIGGER_HOTKEYS@]</default>
+ <locale name="C">
+ <short>Trigger shortcut keys</short>
+ <long>The shortcut keys for turning input method on or off</long>
+diff --git a/ibus/_config.py.in b/ibus/_config.py.in
+index a830136..4c3c980 100644
+--- a/ibus/_config.py.in
++++ b/ibus/_config.py.in
+@@ -25,6 +25,8 @@ __all__ = (
+ "get_copyright",
+ "get_license",
+ "get_ICON_KEYBOARD",
++ "use_bridge_hotkey",
++ "DEFAULT_BRIDGE_ENGINE_NAME",
+ "ISOCODES_PREFIX",
+ "_"
+ )
+@@ -51,4 +53,8 @@ def get_ICON_KEYBOARD():
+ icon = 'ibus-keyboard'
+ return icon
+
++def use_bridge_hotkey():
++ return True if @USE_BRIDGE_HOTKEY@ == 1 else False
++
++DEFAULT_BRIDGE_ENGINE_NAME='@DEFAULT_BRIDGE_ENGINE_NAME@'
+ ISOCODES_PREFIX='@ISOCODES_PREFIX@'
+diff --git a/ibus/inputcontext.py b/ibus/inputcontext.py
+index ceeb56d..2694fa3 100644
+--- a/ibus/inputcontext.py
++++ b/ibus/inputcontext.py
+@@ -28,6 +28,7 @@ import sys
+ import gobject
+ import dbus
+ import dbus.lowlevel
++import _config
+ import object
+ import common
+ import serializable
+@@ -282,6 +283,9 @@ class InputContext(object.Object):
+ def set_engine(self, engine):
+ return self.__context.SetEngine(engine.name)
+
++ def set_bridge_engine(self):
++ return self.__context.SetEngine(_config.DEFAULT_BRIDGE_ENGINE_NAME)
++
+ def introspect(self):
+ return self.__context.Introspect()
+
+diff --git a/src/Makefile.am b/src/Makefile.am
+index 6454522..443b0db 100644
+--- a/src/Makefile.am
++++ b/src/Makefile.am
+@@ -46,6 +46,7 @@ AM_CPPFLAGS = \
+ -DIBUS_DATA_DIR=\"$(pkgdatadir)\" \
+ -DIBUS_COMPILATION \
+ -DISOCODES_PREFIX=\"$(ISOCODES_PREFIX)\" \
++ -DUSE_BRIDGE_HOTKEY=$(USE_BRIDGE_HOTKEY) \
+ $(NULL)
+
+ # ibus library
+diff --git a/src/ibusbus.c b/src/ibusbus.c
+index 39ad784..5a8f9a9 100644
+--- a/src/ibusbus.c
++++ b/src/ibusbus.c
+@@ -1902,3 +1902,9 @@ ibus_bus_call_async (IBusBus *bus,
+ (GAsyncReadyCallback) ibus_bus_call_async_done,
+ simple);
+ }
++
++gboolean
++ibus_bus_use_bridge_hotkey (IBusBus *bus)
++{
++ return (USE_BRIDGE_HOTKEY == 1) ? TRUE : FALSE;
++}
+diff --git a/src/ibusbus.h b/src/ibusbus.h
+index 77d3916..4bdf760 100644
+--- a/src/ibusbus.h
++++ b/src/ibusbus.h
+@@ -971,5 +971,14 @@ void ibus_bus_set_watch_ibus_signal
+ */
+ IBusConfig *ibus_bus_get_config (IBusBus *bus);
+
++/**
++ * ibus_bus_use_bridge_hotkey:
++ * @bus: An #IBusBus.
++ * @returns: %TRUE if @bus use bridge hotkey, %FALSE otherwise.
++ *
++ * Return %TRUE if @bus use bridge hotkey.
++ */
++gboolean ibus_bus_use_bridge_hotkey (IBusBus *bus);
++
+ G_END_DECLS
+ #endif
+diff --git a/src/ibusenginedesc.c b/src/ibusenginedesc.c
+index d3800e1..a9e68be 100644
+--- a/src/ibusenginedesc.c
++++ b/src/ibusenginedesc.c
+@@ -233,7 +233,11 @@ ibus_engine_desc_class_init (IBusEngineDescClass *class)
+ g_param_spec_string ("hotkeys",
+ "description hotkeys",
+ "The hotkeys of engine description",
++#if USE_BRIDGE_HOTKEY
++ "Control+space",
++#else
+ "",
++#endif
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ /**
+diff --git a/src/ibushotkey.c b/src/ibushotkey.c
+index 32f8338..bef7dfc 100644
+--- a/src/ibushotkey.c
++++ b/src/ibushotkey.c
+@@ -562,3 +562,14 @@ ibus_hotkey_profile_lookup_hotkey (IBusHotkeyProfile *profile,
+
+ return (GQuark) GPOINTER_TO_UINT (g_tree_lookup (priv->hotkeys, &hotkey));
+ }
++
++void
++ibus_hotkey_profile_foreach_hotkey (IBusHotkeyProfile *profile,
++ GTraverseFunc func,
++ gpointer user_data)
++{
++ IBusHotkeyProfilePrivate *priv;
++ priv = IBUS_HOTKEY_PROFILE_GET_PRIVATE (profile);
++
++ g_tree_foreach (priv->hotkeys, func, user_data);
++}
+diff --git a/src/ibushotkey.h b/src/ibushotkey.h
+index 9a341f6..92ec6af 100644
+--- a/src/ibushotkey.h
++++ b/src/ibushotkey.h
+@@ -179,5 +179,16 @@ GQuark ibus_hotkey_profile_lookup_hotkey
+ guint keyval,
+ guint modifiers);
+
++/**
++ * ibus_hotkey_profile_foreach_hotkey:
++ * @profile: An IBusHotkeyProfile.
++ * @func: (scope call): A GTraverseFunc for g_tree_traverse.
++ * @user_data: A gpointer for g_tree_traverse.
++ */
++void ibus_hotkey_profile_foreach_hotkey
++ (IBusHotkeyProfile *profile,
++ GTraverseFunc func,
++ gpointer user_data);
++
+ G_END_DECLS
+ #endif
+diff --git a/ui/gtk/panel.py b/ui/gtk/panel.py
+index de64920..7f2edcd 100644
+--- a/ui/gtk/panel.py
++++ b/ui/gtk/panel.py
+@@ -133,6 +133,11 @@ class Panel(ibus.PanelBase):
+ # self.__bus.request_name(ibus.panel.IBUS_SERVICE_PANEL, 0)
+
+ # init xkb
++ self.__default_layout = 'default'
++ self.__default_model = 'default'
++ self.__default_option = 'default'
++ self.__disabled_engine = None
++
+ self.__xkblayout = ibus.XKBLayout(self.__config)
+ use_xkb = self.__config.get_value("general", "use_system_keyboard_layout", False)
+ if not use_xkb:
+@@ -142,11 +147,18 @@ class Panel(ibus.PanelBase):
+ value = 'default'
+ if value != 'default':
+ self.__xkblayout.set_default_layout(value)
++ if value.find('(') >= 0:
++ self.__default_layout = value.split('(')[0]
++ self.__default_model = value.split('(')[1].split(')')[0]
++ else:
++ self.__default_layout = value
++ self.__default_model = None
+ value = str(self.__config.get_value("general", "system_keyboard_option", ''))
+ if value == '':
+ value = 'default'
+ if value != 'default':
+ self.__xkblayout.set_default_option(value)
++ self.__default_option = value
+
+ def set_cursor_location(self, x, y, w, h):
+ self.__candidate_panel.set_cursor_location(x, y, w, h)
+@@ -233,6 +245,41 @@ class Panel(ibus.PanelBase):
+ def __set_im_name(self, name):
+ self.__language_bar.set_im_name(name)
+
++ def __set_default_layout_engine(self):
++ default_layout = self.__default_layout
++ default_model = self.__default_model
++ if default_layout == 'default':
++ default_layout = self.__xkblayout.get_default_layout()[0]
++ default_model = None
++ if default_model == 'default':
++ default_model = self.__xkblayout.get_default_layout()[1]
++ layouts = default_layout.split(',')
++ group = self.__xkblayout.get_group()
++ layout = layouts[group]
++ model = None
++ if default_model != None and default_model != '':
++ models = default_model.split(',')
++ if group < models.length:
++ model = models[group]
++ registry = ibus.XKBConfigRegistry()
++ langs = registry.get_layout_lang()[layout]
++ lang = 'en'
++ im_icon = layout[:2]
++ if langs != None:
++ im_icon = langs[0][:2]
++ lang = str(langs[0])
++ if self.__disabled_engine == None:
++ self.__disabled_engine = registry.engine_desc_new(lang,
++ self.__default_layout,
++ 'Default Layout',
++ default_model,
++ None)
++ if self.__focus_ic != None:
++ prev_engine = self.__focus_ic.get_engine()
++ if prev_engine == None or \
++ prev_engine.name != self.__disabled_engine.name:
++ self.__focus_ic.set_bridge_engine()
++
+ def focus_in(self, ic):
+ self.reset()
+ self.__focus_ic = ibus.InputContext(self.__bus, ic)
+@@ -240,6 +287,9 @@ class Panel(ibus.PanelBase):
+ self.__language_bar.set_enabled(enabled)
+
+ if not enabled:
++ if ibus.use_bridge_hotkey():
++ self.__set_default_layout_engine()
++
+ self.__set_im_icon(ICON_KEYBOARD)
+ self.__set_im_name(None)
+ if self.__bus.get_use_sys_layout():
+@@ -453,7 +503,12 @@ class Panel(ibus.PanelBase):
+ size = gtk.icon_size_lookup(gtk.ICON_SIZE_MENU)
+ menu = gtk.Menu()
+ for i, engine in enumerate(engines):
+- lang = ibus.get_language_name(engine.language)
++ language = engine.language
++ if ibus.use_bridge_hotkey() and \
++ engine.name == ibus.DEFAULT_BRIDGE_ENGINE_NAME and \
++ self.__disabled_engine != None:
++ language = self.__disabled_engine.language
++ lang = ibus.get_language_name(language)
+ item = gtk.ImageMenuItem("%s - %s" % (lang, engine.longname))
+ if current_engine and current_engine.name == engine.name:
+ for widget in item.get_children():
+@@ -471,7 +526,8 @@ class Panel(ibus.PanelBase):
+ item.connect("activate", self.__im_menu_item_activate_cb, None)
+ if self.__focus_ic == None or not self.__focus_ic.is_enabled():
+ item.set_sensitive(False)
+- menu.add(item)
++ if not ibus.use_bridge_hotkey():
++ menu.add(item)
+
+ menu.show_all()
+ menu.set_take_focus(False)
+diff --git a/xkb/Makefile.am b/xkb/Makefile.am
+index ad9cdd9..c4d5afb 100644
+--- a/xkb/Makefile.am
++++ b/xkb/Makefile.am
+@@ -28,6 +28,8 @@ INCLUDES = \
+ -I$(top_srcdir)/src \
+ -DIBUS_LOCALEDIR=\"$(datadir)/locale\" \
+ -DLIBEXECDIR=\""$(libexecdir)"\" \
++ -DUSE_BRIDGE_HOTKEY=$(USE_BRIDGE_HOTKEY) \
++ -DDEFAULT_BRIDGE_ENGINE_NAME=\"$(DEFAULT_BRIDGE_ENGINE_NAME)\" \
+ $(NULL)
+
+ noinst_PROGRAMS = $(TESTS)
+diff --git a/xkb/ibus-engine-xkb-main.c b/xkb/ibus-engine-xkb-main.c
+index 5d748cc..a80f349 100644
+--- a/xkb/ibus-engine-xkb-main.c
++++ b/xkb/ibus-engine-xkb-main.c
+@@ -288,6 +288,14 @@ print_component ()
+ layout_desc = (GHashTable *) ibus_xkb_config_registry_get_layout_desc (config_registry);
+ variant_desc = (GHashTable *) ibus_xkb_config_registry_get_variant_desc (config_registry);
+ component = ibus_xkb_component_new ();
++#if USE_BRIDGE_HOTKEY
++ engine = ibus_xkb_engine_desc_new ("en",
++ "default",
++ "Default Layout",
++ NULL,
++ NULL);
++ ibus_component_add_engine (component, engine);
++#endif
+ for (keys = g_hash_table_get_keys (layout_list); keys; keys = keys->next) {
+ if (keys->data == NULL) {
+ continue;
+diff --git a/xkb/xkbxml.c b/xkb/xkbxml.c
+index 2ce7bcf..de6648f 100644
+--- a/xkb/xkbxml.c
++++ b/xkb/xkbxml.c
+@@ -273,6 +273,7 @@ ibus_xkb_engine_desc_new (const gchar *lang,
+ gchar *longname = NULL;
+ gchar *desc = NULL;
+ gchar *engine_layout = NULL;
++ const gchar *icon = "ibus-engine";
+
+ g_return_val_if_fail (lang != NULL && layout != NULL, NULL);
+
+@@ -294,6 +295,11 @@ ibus_xkb_engine_desc_new (const gchar *lang,
+ desc = g_strdup_printf ("XKB %s keyboard layout", layout);
+ engine_layout = g_strdup (layout);
+ }
++#if USE_BRIDGE_HOTKEY
++ if (g_strcmp0 (name, DEFAULT_BRIDGE_ENGINE_NAME) == 0) {
++ icon = "input-keyboard-symbolic";
++ }
++#endif
+
+ engine = ibus_engine_desc_new (name,
+ longname,
+@@ -301,7 +307,7 @@ ibus_xkb_engine_desc_new (const gchar *lang,
+ lang,
+ "LGPL2.1",
+ "Takao Fujiwara <takao.fujiwara1 at gmail.com>",
+- "ibus-engine",
++ icon,
+ engine_layout);
+
+ g_free (name);
+--
+1.7.4.4
+
diff --git a/ibus-xx-icon-symbol.patch b/ibus-xx-icon-symbol.patch
new file mode 100644
index 0000000..eb0802d
--- /dev/null
+++ b/ibus-xx-icon-symbol.patch
@@ -0,0 +1,331 @@
+From ec02d646dccd213e1309011160d9d73a26174044 Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1 at gmail.com>
+Date: Mon, 20 Jun 2011 19:10:21 +0900
+Subject: [PATCH] Add icon_symbol property in IBusEngineDesc.
+
+---
+ bus/engineproxy.c | 22 +++++++++++++++
+ bus/ibusimpl.c | 33 ++++++++++++++++++++++
+ bus/ibusimpl.h | 4 +++
+ ibus/engine.py | 3 ++
+ ibus/interface/iengine.py | 3 ++
+ src/ibusenginedesc.c | 66 +++++++++++++++++++++++++++++++++++++++++++++
+ src/ibusenginedesc.h | 10 +++++++
+ 7 files changed, 141 insertions(+), 0 deletions(-)
+
+diff --git a/bus/engineproxy.c b/bus/engineproxy.c
+index f74af12..5c0cbb2 100644
+--- a/bus/engineproxy.c
++++ b/bus/engineproxy.c
+@@ -591,6 +591,28 @@ bus_engine_proxy_g_signal (GDBusProxy *proxy,
+ return;
+ }
+
++ if (g_strcmp0 (signal_name, "SetIconSymbol") == 0) {
++ const gchar *name = NULL;
++ gchar *icon_symbol = NULL;
++ GValue value = { 0, };
++
++ name = ibus_engine_desc_get_name (engine->desc);
++ g_return_if_fail (name != NULL);
++ g_variant_get (parameters, "(s)", &icon_symbol);
++ g_return_if_fail (icon_symbol != NULL);
++
++ g_value_init (&value, G_TYPE_STRING);
++ g_value_set_string (&value, icon_symbol);
++ g_object_set_property (G_OBJECT (engine->desc), "icon_symbol", &value);
++ g_value_unset (&value);
++
++ bus_ibus_impl_set_icon_symbol_with_engine_name (BUS_DEFAULT_IBUS,
++ name,
++ icon_symbol);
++ g_free (icon_symbol);
++ return;
++ }
++
+ g_return_if_reached ();
+ }
+
+diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c
+index b356b2c..38d6d11 100644
+--- a/bus/ibusimpl.c
++++ b/bus/ibusimpl.c
+@@ -2342,3 +2342,36 @@ bus_ibus_impl_get_focused_input_context (BusIBusImpl *ibus)
+
+ return ibus->focused_context;
+ }
++
++void
++bus_ibus_impl_set_icon_symbol_with_engine_name (BusIBusImpl *ibus,
++ const gchar *name,
++ const gchar *icon_symbol)
++{
++ IBusEngineDesc *desc = NULL;
++ GValue value = { 0, };
++
++ g_assert (BUS_IS_IBUS_IMPL (ibus));
++ g_assert (name != NULL);
++ g_assert (icon_symbol != NULL);
++
++ desc = bus_ibus_impl_get_engine_desc (ibus, name);
++
++ if (desc == NULL) {
++ return;
++ }
++
++ g_value_init (&value, G_TYPE_STRING);
++ g_value_set_string (&value, icon_symbol);
++ g_object_set_property (G_OBJECT (desc), "icon_symbol", &value);
++ g_value_unset (&value);
++
++ /* Update status icon.
++ * "enabled" signal is caught by ibus->panel and ibus->panel calls
++ * StateChanged dbus method. */
++ if (ibus->panel && ibus->focused_context) {
++ if (bus_input_context_is_enabled (ibus->focused_context)) {
++ bus_input_context_enable (ibus->focused_context);
++ }
++ }
++}
+diff --git a/bus/ibusimpl.h b/bus/ibusimpl.h
+index 42edbf8..4f37cbc 100644
+--- a/bus/ibusimpl.h
++++ b/bus/ibusimpl.h
+@@ -99,6 +99,10 @@ gboolean bus_ibus_impl_is_embed_preedit_text
+ (BusIBusImpl *ibus);
+ BusInputContext *bus_ibus_impl_get_focused_input_context
+ (BusIBusImpl *ibus);
++void bus_ibus_impl_set_icon_symbol_with_engine_name
++ (BusIBusImpl *ibus,
++ const gchar *name,
++ const gchar *icon_symbol);
+
+ G_END_DECLS
+ #endif
+diff --git a/ibus/engine.py b/ibus/engine.py
+index fe5dd98..e827408 100644
+--- a/ibus/engine.py
++++ b/ibus/engine.py
+@@ -176,6 +176,9 @@ class EngineBase(object.Object):
+ self.__proxy = None
+ super(EngineBase,self).do_destroy()
+
++ def set_icon_symbol(self, icon_symbol):
++ return self.__proxy.SetIconSymbol(icon_symbol)
++
+
+ class EngineProxy(interface.IEngine):
+ def __init__(self, engine, conn, object_path):
+diff --git a/ibus/interface/iengine.py b/ibus/interface/iengine.py
+index 9e0d981..7cefcdf 100644
+--- a/ibus/interface/iengine.py
++++ b/ibus/interface/iengine.py
+@@ -157,3 +157,6 @@ class IEngine(dbus.service.Object):
+
+ @signal()
+ def RequireSurroundingText(self): pass
++
++ @signal(signature="s")
++ def SetIconSymbol(self, icon_symbol): pass
+diff --git a/src/ibusenginedesc.c b/src/ibusenginedesc.c
+index ca5ef60..d3800e1 100644
+--- a/src/ibusenginedesc.c
++++ b/src/ibusenginedesc.c
+@@ -22,6 +22,7 @@
+ #include <stdlib.h>
+ #include "ibusenginedesc.h"
+ #include "ibusxml.h"
++#include "ibusenumtypes.h"
+
+ enum {
+ LAST_SIGNAL,
+@@ -39,6 +40,7 @@ enum {
+ PROP_LAYOUT,
+ PROP_RANK,
+ PROP_HOTKEYS,
++ PROP_ICON_SYMBOL,
+ };
+
+
+@@ -54,6 +56,7 @@ struct _IBusEngineDescPrivate {
+ gchar *layout;
+ guint rank;
+ gchar *hotkeys;
++ gchar *icon_symbol;
+ };
+
+ #define IBUS_ENGINE_DESC_GET_PRIVATE(o) \
+@@ -232,6 +235,19 @@ ibus_engine_desc_class_init (IBusEngineDescClass *class)
+ "The hotkeys of engine description",
+ "",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
++
++ /**
++ * IBusEngineDesc:icon_symbol:
++ *
++ * The symbol chars of engine description instead of icon image
++ */
++ g_object_class_install_property (gobject_class,
++ PROP_ICON_SYMBOL,
++ g_param_spec_string ("icon_symbol",
++ "description icon_symbol",
++ "The icon symbol chars of engine description",
++ "",
++ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ }
+
+ static void
+@@ -249,6 +265,7 @@ ibus_engine_desc_init (IBusEngineDesc *desc)
+ desc->priv->layout = NULL;
+ desc->priv->rank = 0;
+ desc->priv->hotkeys = NULL;
++ desc->priv->icon_symbol = NULL;
+ }
+
+ static void
+@@ -263,6 +280,7 @@ ibus_engine_desc_destroy (IBusEngineDesc *desc)
+ g_free (desc->priv->icon);
+ g_free (desc->priv->layout);
+ g_free (desc->priv->hotkeys);
++ g_free (desc->priv->icon_symbol);
+
+ IBUS_OBJECT_CLASS (ibus_engine_desc_parent_class)->destroy (IBUS_OBJECT (desc));
+ }
+@@ -313,6 +331,10 @@ ibus_engine_desc_set_property (IBusEngineDesc *desc,
+ g_assert (desc->priv->hotkeys == NULL);
+ desc->priv->hotkeys = g_value_dup_string (value);
+ break;
++ case PROP_ICON_SYMBOL:
++ g_free (desc->priv->icon_symbol);
++ desc->priv->icon_symbol = g_value_dup_string (value);
++ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (desc, prop_id, pspec);
+ }
+@@ -355,6 +377,9 @@ ibus_engine_desc_get_property (IBusEngineDesc *desc,
+ case PROP_HOTKEYS:
+ g_value_set_string (value, ibus_engine_desc_get_hotkeys (desc));
+ break;
++ case PROP_ICON_SYMBOL:
++ g_value_set_string (value, ibus_engine_desc_get_icon_symbol (desc));
++ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (desc, prop_id, pspec);
+ }
+@@ -382,9 +407,28 @@ ibus_engine_desc_serialize (IBusEngineDesc *desc,
+ g_variant_builder_add (builder, "u", desc->priv->rank);
+ g_variant_builder_add (builder, "s", NOTNULL (desc->priv->hotkeys));
+ #undef NOTNULL
++
++ /* append extra properties */
++ GVariantBuilder array;
++ g_variant_builder_init (&array, G_VARIANT_TYPE ("a{sv}"));
++ g_variant_builder_add (&array, "{sv}", "icon_symbol", g_variant_new_string (desc->priv->icon_symbol));
++ g_variant_builder_add (builder, "v", g_variant_builder_end (&array));
++
+ return TRUE;
+ }
+
++static gboolean
++ibus_engine_desc_deserialize_property (IBusEngineDesc *desc,
++ const gchar *name,
++ GVariant *variant)
++{
++ if (g_strcmp0 (name, "icon_symbol") == 0) {
++ g_variant_get (variant, "s", &desc->priv->icon_symbol);
++ return TRUE;
++ }
++ return FALSE;
++}
++
+ static gint
+ ibus_engine_desc_deserialize (IBusEngineDesc *desc,
+ GVariant *variant)
+@@ -405,6 +449,23 @@ ibus_engine_desc_deserialize (IBusEngineDesc *desc,
+ g_variant_get_child (variant, retval++, "u", &desc->priv->rank);
+ g_variant_get_child (variant, retval++, "s", &desc->priv->hotkeys);
+
++ /* extract extra properties */
++ GVariantIter iter;
++ GVariant *child, *array;
++
++ g_variant_get_child (variant, retval++, "v", &array);
++ g_variant_iter_init (&iter, array);
++ while ((child = g_variant_iter_next_value (&iter))) {
++ gchar *name;
++ GVariant *value;
++ g_variant_get (child, "{sv}", &name, &value);
++ if (ibus_engine_desc_deserialize_property (desc, name, value))
++ retval++;
++ g_free (name);
++ g_variant_unref (value);
++ g_variant_unref (child);
++ }
++
+ return retval;
+ }
+
+@@ -428,6 +489,7 @@ ibus_engine_desc_copy (IBusEngineDesc *dest,
+ dest->priv->layout = g_strdup (src->priv->layout);
+ dest->priv->rank = src->priv->rank;
+ dest->priv->hotkeys = g_strdup (src->priv->hotkeys);
++ dest->priv->icon_symbol = g_strdup (src->priv->icon_symbol);
+ return TRUE;
+ }
+
+@@ -465,6 +527,7 @@ ibus_engine_desc_output (IBusEngineDesc *desc,
+ OUTPUT_ENTRY_1(icon);
+ OUTPUT_ENTRY_1(layout);
+ OUTPUT_ENTRY_1(hotkeys);
++ OUTPUT_ENTRY_1(icon_symbol);
+ g_string_append_indent (output, indent + 1);
+ g_string_append_printf (output, "<rank>%u</rank>\n", desc->priv->rank);
+ #undef OUTPUT_ENTRY
+@@ -498,6 +561,7 @@ ibus_engine_desc_parse_xml_node (IBusEngineDesc *desc,
+ PARSE_ENTRY_1(icon);
+ PARSE_ENTRY_1(layout);
+ PARSE_ENTRY_1(hotkeys);
++ PARSE_ENTRY_1(icon_symbol);
+ #undef PARSE_ENTRY
+ #undef PARSE_ENTRY_1
+ if (g_strcmp0 (sub_node->name , "rank") == 0) {
+@@ -526,6 +590,7 @@ IBUS_ENGINE_DESC_GET_PROPERTY (icon, const gchar *)
+ IBUS_ENGINE_DESC_GET_PROPERTY (layout, const gchar *)
+ IBUS_ENGINE_DESC_GET_PROPERTY (rank, guint)
+ IBUS_ENGINE_DESC_GET_PROPERTY (hotkeys, const gchar *)
++IBUS_ENGINE_DESC_GET_PROPERTY (icon_symbol, const gchar *)
+ #undef IBUS_ENGINE_DESC_GET_PROPERTY
+
+ IBusEngineDesc *
+@@ -573,6 +638,7 @@ ibus_engine_desc_new_varargs (const gchar *first_property_name, ...)
+ g_assert (desc->priv->icon);
+ g_assert (desc->priv->layout);
+ g_assert (desc->priv->hotkeys);
++ g_assert (desc->priv->icon_symbol);
+
+ return desc;
+ }
+diff --git a/src/ibusenginedesc.h b/src/ibusenginedesc.h
+index 9718b15..e3194c3 100644
+--- a/src/ibusenginedesc.h
++++ b/src/ibusenginedesc.h
+@@ -249,6 +249,16 @@ guint ibus_engine_desc_get_rank (IBusEngineDesc *info);
+ const gchar *ibus_engine_desc_get_hotkeys (IBusEngineDesc *info);
+
+ /**
++ * ibus_engine_desc_get_icon_symbol:
++ * @info: An IBusEngineDesc
++ * @returns: icon_symbol property in IBusEngineDesc
++ *
++ * Return the icon_symbol property in IBusEngineDesc. It should not be freed.
++ */
++const gchar *ibus_engine_desc_get_icon_symbol
++ (IBusEngineDesc *info);
++
++/**
+ * ibus_engine_desc_output:
+ * @info: An IBusEngineDesc
+ * @output: XML-formatted Input method engine description.
+--
+1.7.4.4
+
diff --git a/ibus-xx-setup-frequent-lang.patch b/ibus-xx-setup-frequent-lang.patch
index a019fa8..a65949e 100644
--- a/ibus-xx-setup-frequent-lang.patch
+++ b/ibus-xx-setup-frequent-lang.patch
@@ -1,6 +1,6 @@
-From 231285d6d9e1b0b868edb842b46c30974a5c517a Mon Sep 17 00:00:00 2001
+From 735a4d98ac057ded317dae9b85777ce56d8af0fd Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1 at gmail.com>
-Date: Wed, 25 May 2011 18:52:25 +0900
+Date: Mon, 20 Jun 2011 19:04:51 +0900
Subject: [PATCH] Enable ibus-setup to show the frequently used languages
only in IME list.
@@ -10,10 +10,10 @@ Subject: [PATCH] Enable ibus-setup to show the frequently used languages
setup/main.py | 1 +
3 files changed, 300 insertions(+), 22 deletions(-)
-diff --git a/data/ibus.schemas.in b/data/ibus.schemas.in
-index 39922a0..2e33b2c 100644
---- a/data/ibus.schemas.in
-+++ b/data/ibus.schemas.in
+diff --git a/data/ibus.schemas.in.in b/data/ibus.schemas.in.in
+index d4334e1..5ef2ac2 100644
+--- a/data/ibus.schemas.in.in
++++ b/data/ibus.schemas.in.in
@@ -239,6 +239,174 @@
</locale>
</schema>
@@ -413,10 +413,10 @@ index 7383177..bff2407 100644
return self.__title
diff --git a/setup/main.py b/setup/main.py
-index 9cdce02..5201139 100644
+index 192fb88..5a0170d 100644
--- a/setup/main.py
+++ b/setup/main.py
-@@ -226,6 +226,7 @@ class Setup(object):
+@@ -227,6 +227,7 @@ class Setup(object):
button.connect("toggled", self.__checkbutton_preload_engine_mode_toggled_cb)
self.__engines = self.__bus.list_engines()
self.__combobox = self.__builder.get_object("combobox_engines")
diff --git a/ibus.spec b/ibus.spec
index 15a20f6..592d36b 100644
--- a/ibus.spec
+++ b/ibus.spec
@@ -13,7 +13,7 @@
Name: ibus
Version: 1.3.99.20110419
-Release: 2%{?dist}
+Release: 3%{?dist}
Summary: Intelligent Input Bus for Linux OS
License: LGPLv2+
Group: System Environment/Libraries
@@ -21,14 +21,16 @@ URL: http://code.google.com/p/ibus/
Source0: http://ibus.googlecode.com/files/%{name}-%{version}.tar.gz
Source1: xinput-ibus
%if %have_gjsfile
-Source2: http://fujiwara.fedorapeople.org/ibus/gnome-shell/gnome-shell-ibus-plugins-20110601.tar.bz2
+Source2: http://fujiwara.fedorapeople.org/ibus/gnome-shell/gnome-shell-ibus-plugins-20110621.tar.bz2
%endif
Source3: https://www.transifex.net/projects/p/ibus/resource/master/l/da/download/ibus_master_da.po
+Source4: http://ueno.fedorapeople.org/ibus-indicator/ibus-indicator.tar.bz2
Patch0: ibus-HEAD.patch
-Patch1: ibus-435880-surrounding-text.patch
-Patch2: ibus-541492-xkb.patch
-Patch3: ibus-530711-preload-sys.patch
-Patch4: ibus-xx-setup-frequent-lang.patch
+Patch1: ibus-530711-preload-sys.patch
+Patch2: ibus-xx-icon-symbol.patch
+Patch3: ibus-541492-xkb.patch
+Patch4: ibus-xx-bridge-hotkey.patch
+Patch5: ibus-xx-setup-frequent-lang.patch
# Workaround for oxygen-gtk icon theme until bug 699103 is fixed.
Patch91: ibus-711632-fedora-fallback-icon.patch
@@ -121,6 +123,21 @@ Requires(post): glib2 >= %{glib_ver}
%description gtk3
This package contains ibus im module for gtk3
+%package gnome3
+Summary: IBus gnome-shell-extension for GNOME3
+Group: System Environment/Libraries
+Requires: %{name} = %{version}-%{release}
+Requires: %{name}-libs = %{version}-%{release}
+Requires: gnome-shell
+
+%description gnome3
+This is a transitional package which allows users to try out new IBus
+GUI for GNOME3 in development. Note that this package will be marked
+as obsolete once the integration has completed in the GNOME3 upstream.
+
+%description gnome3
+This package contains ibus im module for gtk3
+
%package devel
Summary: Development tools for ibus
Group: Development/Libraries
@@ -150,18 +167,19 @@ sed -i \
-e "s|Config.IBUS_XKB|'/usr/libexec/ibus-xkb'|" \
-e "s|Config.HAVE_IBUS_XKB|true|" \
js/ui/status/ibus/xkbLayout.js
+bzcat %SOURCE4 | tar xf -
%endif
cp %SOURCE3 po/da.po
%patch0 -p1
-# start surrounding patch
-%patch1 -p1 -b .surrounding
cp client/gtk2/ibusimcontext.c client/gtk3/ibusimcontext.c
-# end surrounding patch
+%patch1 -p1 -b .preload-sys
+%patch2 -p1 -b .icon-symbol
%if %have_libxkbfile
-%patch2 -p1 -b .xkb
+%patch3 -p1 -b .xkb
%endif
-%patch3 -p1 -b .preload-sys
-%patch4 -p1 -b .setup-frequent-lang
+mv data/ibus.schemas.in data/ibus.schemas.in.in
+%patch4 -p1 -b .bridge-key
+%patch5 -p1 -b .setup-frequent-lang
%patch91 -p1 -b .fallback-icon
@@ -180,6 +198,7 @@ automake -a -c -f
--disable-gtk-doc \
--with-no-snooper-apps='gnome-do,Do.*,firefox.*,.*chrome.*,.*chromium.*' \
--enable-surrounding-text \
+ --enable-bridge-hotkey \
--enable-introspection
# make -C po update-gmo
@@ -215,19 +234,11 @@ desktop-file-install --delete-original \
$RPM_BUILD_ROOT%{_datadir}/applications/*
%if %have_gjsfile
-cp -R js/ui/status/ibus $RPM_BUILD_ROOT%{_datadir}/ibus/ui/gjs-g-s
-cat >> $RPM_BUILD_ROOT%{_datadir}/ibus/ui/gjs-g-s/README <<_EOF
-IBus Panel for GNOME-Shell
---------------------------
-
-This is an alpha version of IBus Panel for GNOME-Shell.
-These files under this directory are prepared for the test purpose.
-It is planned to integrate the files into gnome-shell finally.
-Please refer the installation:
-https://fedoraproject.org/wiki/I18N/InputMethods#GNOME-Shell
-Bug Report:
-https://bugzilla.redhat.com/show_bug.cgi?id=657165
-_EOF
+# https://bugzilla.redhat.com/show_bug.cgi?id=657165
+install -dm 755 $RPM_BUILD_ROOT%{_datadir}/gnome-shell
+cp -R js $RPM_BUILD_ROOT%{_datadir}/gnome-shell
+install -dm 755 $RPM_BUILD_ROOT%{_datadir}/gnome-shell/extensions
+cp -R ibus-indicator at example.com $RPM_BUILD_ROOT%{_datadir}/gnome-shell/extensions
%endif
# FIXME: no version number
@@ -323,6 +334,11 @@ fi
%defattr(-,root,root,-)
%{_libdir}/gtk-3.0/%{gtk3_binary_version}/immodules/im-ibus.so
+%files gnome3
+%defattr(-,root,root,-)
+%{_datadir}/gnome-shell/js/ui/status/ibus
+%{_datadir}/gnome-shell/extensions/ibus-indicator at example.com
+
%files devel
%defattr(-,root,root,-)
%{_libdir}/lib*.so
@@ -337,9 +353,14 @@ fi
%{_datadir}/gtk-doc/html/*
%changelog
-* Wed Jun 08 2011 Takao Fujiwara <tfujiwar at redhat.com> - 1.3.99.20110419-2
+* Mon Jun 20 2011 Takao Fujiwara <tfujiwar at redhat.com> - 1.3.99.20110419-3
+- Updated ibus-HEAD.patch for upstream.
+- Removed ibus-435880-surrounding-text.patch as upstream.
- Added ibus-711632-fedora-fallback-icon.patch
Fixed SEGV with no icon in oxygen-gtk icon theme.
+- Added ibus-xx-icon-symbol.patch
+- Added ibus-xx-bridge-hotkey.patch
+- Added transitional ibus-gnome3 package.
* Thu May 26 2011 Takao Fujiwara <tfujiwar at redhat.com> - 1.3.99.20110419-1
- Updated to 1.3.99.20110419
diff --git a/sources b/sources
index a92cbb8..0b35584 100644
--- a/sources
+++ b/sources
@@ -1,3 +1,4 @@
d4f2729fecb92ae6b41f26c770b1a772 ibus-1.3.99.20110419.tar.gz
-64e556364ee619d51e80397086b1d244 gnome-shell-ibus-plugins-20110601.tar.bz2
+ecd3a320faca906b1b8edaae1988f512 gnome-shell-ibus-plugins-20110621.tar.bz2
698c90edf0f037488e1aa969804e891f ibus_master_da.po
+23756d25109745bdc1c3a54db370d210 ibus-indicator.tar.bz2
More information about the scm-commits
mailing list