[packages/ibus] - updated to 1.5.9 - refreshed patchsets from fedora - ibus-xkb is no longer needed/used

baggins baggins at pld-linux.org
Mon Dec 8 21:20:33 CET 2014


commit 4c73ba7f1e1d8f45cdea6d43cd629829083864c1
Author: Jan Rękorajski <baggins at pld-linux.org>
Date:   Mon Dec 8 21:19:51 2014 +0100

    - updated to 1.5.9
    - refreshed patchsets from fedora
    - ibus-xkb is no longer needed/used

 ibus-1136623-lost-by-another-focus.patch  |   24 +
 ibus-530711-preload-sys.patch             |  394 ----
 ibus-541492-xkb.patch                     | 3534 -----------------------------
 ibus-810211-no-switch-by-no-trigger.patch |   36 -
 ibus-HEAD.patch                           |  672 ++++++
 ibus-xx-increase-timeout.patch            |   84 +
 ibus-xx-setup-frequent-lang.patch         |  427 ----
 ibus.spec                                 |   30 +-
 python-path.patch                         |   11 +
 9 files changed, 801 insertions(+), 4411 deletions(-)
---
diff --git a/ibus.spec b/ibus.spec
index f7930db..ecf83f6 100644
--- a/ibus.spec
+++ b/ibus.spec
@@ -5,23 +5,22 @@
 %bcond_without	static_libs	# don't build static library
 %bcond_without	vala		# Vala API
 %bcond_without	wayland		# Wayland client
-%bcond_with	ibus_xkb	# XKB backend (available also in ibus-xkb module?) and Fedora patches
 
 Summary:	Intelligent Input Bus for Linux OS
 Summary(pl.UTF-8):	IBus - inteligentna szyna wejściowa dla Linuksa
 Name:		ibus
-Version:	1.5.5
-Release:	2
+Version:	1.5.9
+Release:	1
 License:	LGPL v2+
 Group:		Libraries
 #Source0Download: http://code.google.com/p/ibus/downloads/list
-Source0:	http://ibus.googlecode.com/files/%{name}-%{version}.tar.gz
-# Source0-md5:	59b8d2fbed3ceb14edac130f882ccfd4
+Source0:	https://github.com/ibus/ibus/releases/download/%{version}/%{name}-%{version}.tar.gz
+# Source0-md5:	a6e820db4fe3d82c825398f1ed19c77e
 Source1:	%{name}.xinputd
-Patch0:		%{name}-810211-no-switch-by-no-trigger.patch
-Patch1:		%{name}-541492-xkb.patch
-Patch2:		%{name}-530711-preload-sys.patch
-Patch3:		%{name}-xx-setup-frequent-lang.patch
+Patch0:		%{name}-1136623-lost-by-another-focus.patch
+Patch1:		%{name}-HEAD.patch
+Patch2:		%{name}-xx-increase-timeout.patch
+Patch3:		python-path.patch
 URL:		http://code.google.com/p/ibus/
 BuildRequires:	GConf2-devel >= 2.12
 BuildRequires:	atk-devel
@@ -39,7 +38,6 @@ BuildRequires:	gtk+3-devel >= 3.0
 BuildRequires:	gtk-doc >= 1.9
 BuildRequires:	intltool >= 0.35.0
 BuildRequires:	iso-codes
-%{?with_ibus_xkb:BuildRequires:	libgnomekbd-devel}
 BuildRequires:	libnotify-devel >= 0.7
 BuildRequires:	libtool
 BuildRequires:	pkgconfig
@@ -54,19 +52,18 @@ BuildRequires:	rpmbuild(macros) >= 1.596
 %{?with_wayland:BuildRequires:	wayland-devel >= 1.2.0}
 BuildRequires:	xorg-lib-libX11-devel
 %{?with_wayland:BuildRequires:	xorg-lib-libxkbcommon-devel}
-%{?with_ibus_xkb:BuildRequires:	xorg-lib-libxkbfile-devel}
 Requires:	%{name}-conf = %{version}-%{release}
 Requires:	%{name}-libs = %{version}-%{release}
 Requires:	dbus >= 1.2.4
 Requires:	gtk-update-icon-cache
 Requires:	hicolor-icon-theme
-Requires:	ibus-xkb
 Requires:	im-chooser
 Requires:	iso-codes
 Requires:	libnotify >= 0.7
 Requires:	python-ibus = %{version}-%{release}
 Requires:	python-pygtk-gtk
 Requires:	python-pynotify
+Requires:       xorg-app-setxkbmap
 # input-keyboard-symbolic icon
 Suggests:	gnome-icon-theme-symbolic
 BuildRoot:	%{tmpdir}/%{name}-%{version}-root-%(id -u -n)
@@ -252,11 +249,9 @@ Bashowe dopełnianie parametrów dla poleceń ibus.
 %prep
 %setup -q
 %patch0 -p1
-%if %{with ibus_xkb}
 %patch1 -p1
 %patch2 -p1
 %patch3 -p1
-%endif
 
 %build
 %{__libtoolize}
@@ -272,7 +267,6 @@ Bashowe dopełnianie parametrów dla poleceń ibus.
 	--enable-gtk2 \
 	--enable-gtk3 \
 	--enable-introspection \
-	%{?with_ibus_xkb:--enable-libgnomekbd} \
 	--enable-python-library \
 	%{?with_static_libs:--enable-static} \
 	--enable-surrounding-text \
@@ -280,8 +274,7 @@ Bashowe dopełnianie parametrów dla poleceń ibus.
 	%{?with_wayland:--enable-wayland} \
 	--enable-xim \
 	--with-html-dir=%{_gtkdocdir} \
-	--with-no-snooper-apps='gnome-do,Do.*,firefox.*,.*chrome.*,.*chromium.*' \
-	%{?with_ibus_xkb:--with-xkb-command=ibus-xkb}
+	--with-no-snooper-apps='gnome-do,Do.*,firefox.*,.*chrome.*,.*chromium.*'
 
 %{__make} -C ui/gtk3 maintainer-clean-generic
 
@@ -369,9 +362,6 @@ rm -rf $RPM_BUILD_ROOT
 %attr(755,root,root) %{_libexecdir}/ibus-engine-simple
 %attr(755,root,root) %{_libexecdir}/ibus-ui-gtk3
 %attr(755,root,root) %{_libexecdir}/ibus-x11
-%if %{with ibus_xkb}
-%attr(755,root,root) %{_libexecdir}/ibus-xkb
-%endif
 %dir %{_datadir}/ibus
 %dir %{_datadir}/ibus/component
 %{_datadir}/ibus/component/gtkpanel.xml
diff --git a/ibus-1136623-lost-by-another-focus.patch b/ibus-1136623-lost-by-another-focus.patch
new file mode 100644
index 0000000..93bf76b
--- /dev/null
+++ b/ibus-1136623-lost-by-another-focus.patch
@@ -0,0 +1,24 @@
+--- ibus-1.5.8/client/gtk2/ibusimcontext.c.orig	2014-10-16 18:35:07.229056767 +0900
++++ ibus-1.5.8/client/gtk2/ibusimcontext.c	2014-10-17 12:36:29.138998318 +0900
+@@ -857,12 +857,7 @@ ibus_im_context_focus_in (GtkIMContext *
+         }
+     }
+ 
+-    if (_focus_im_context != NULL) {
+-        g_assert (_focus_im_context != context);
+-        gtk_im_context_focus_out (_focus_im_context);
+-        g_assert (_focus_im_context == NULL);
+-    }
+-    else {
++    if (_focus_im_context == NULL) {
+         /* focus out fake context */
+         if (_fake_context != NULL) {
+             ibus_input_context_focus_out (_fake_context);
+@@ -903,7 +898,6 @@ ibus_im_context_focus_out (GtkIMContext
+         return;
+     }
+ 
+-    g_assert (context == _focus_im_context);
+     g_object_remove_weak_pointer ((GObject *) context,
+                                   (gpointer *) &_focus_im_context);
+     _focus_im_context = NULL;
diff --git a/ibus-530711-preload-sys.patch b/ibus-530711-preload-sys.patch
deleted file mode 100644
index 5f781db..0000000
--- a/ibus-530711-preload-sys.patch
+++ /dev/null
@@ -1,394 +0,0 @@
-From 2c4bbcc26f735d6c274483a79b4b27f730afa7b2 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1 at gmail.com>
-Date: Fri, 14 Sep 2012 18:49:59 +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_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,
-ibus-daemon do not update the gconf value preload_engines.
-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'.
----
- data/ibus.schemas.in |   24 +++++++++
- setup/main.py        |   61 ++++++++++++++++++++--
- setup/setup.ui       |   22 ++++++--
- src/ibustypes.h      |   10 ++++
- ui/gtk3/panel.vala   |  136 ++++++++++++++++++++++++++++++++++++++++++++++++++
- 5 files changed, 246 insertions(+), 7 deletions(-)
-
-diff --git a/data/ibus.schemas.in b/data/ibus.schemas.in
-index 07169ae..4086f67 100644
---- a/data/ibus.schemas.in
-+++ b/data/ibus.schemas.in
-@@ -2,6 +2,30 @@
- <gconfschemafile>
-   <schemalist>
-     <schema>
-+      <key>/schemas/desktop/ibus/general/preload_engine_mode</key>
-+      <applyto>/desktop/ibus/general/preload_engine_mode</applyto>
-+      <owner>ibus</owner>
-+      <type>int</type>
-+      <default>0</default>
-+      <locale name="C">
-+        <short>Preload engine mode</short>
-+            <long>Preload engines are loaded with this mode.
-+                  0 = user customized engines.
-+                  1 = language related engines.</long>
-+      </locale>
-+    </schema>
-+    <schema>
-+      <key>/schemas/desktop/ibus/general/preload_engines_inited</key>
-+      <applyto>/desktop/ibus/general/preload_engines_inited</applyto>
-+      <owner>ibus</owner>
-+      <type>bool</type>
-+      <default>false</default>
-+      <locale name="C">
-+        <short>The key preload_engines is initialized</short>
-+            <long>The key preload_engines is initialized</long>
-+      </locale>
-+    </schema>
-+    <schema>
-       <key>/schemas/desktop/ibus/general/preload_engines</key>
-       <applyto>/desktop/ibus/general/preload_engines</applyto>
-       <owner>ibus</owner>
-diff --git a/setup/main.py b/setup/main.py
-index 2a19c49..000a03b 100644
---- a/setup/main.py
-+++ b/setup/main.py
-@@ -196,6 +196,20 @@ class Setup(object):
-         self.__checkbutton_use_global_engine.connect("toggled",
-                 self.__checkbutton_use_global_engine_toggled_cb)
- 
-+        # set preload mode
-+        preload_engine_mode = IBus.PreloadEngineMode.USER
-+        variant = self.__config.get_value("general", "preload_engine_mode")
-+        if variant != None:
-+            preload_engine_mode = variant.get_int32()
-+        button = self.__builder.get_object("checkbutton_preload_engine_mode")
-+        if preload_engine_mode == IBus.PreloadEngineMode.USER:
-+            button.set_active(True)
-+            self.__builder.get_object("hbox_customize_active_input_methods").set_sensitive(True)
-+        else:
-+            button.set_active(False)
-+            self.__builder.get_object("hbox_customize_active_input_methods").set_sensitive(False)
-+        button.connect("toggled", self.__checkbutton_preload_engine_mode_toggled_cb)
-+
-         # init engine page
-         self.__engines = self.__bus.list_engines()
-         value = self.__config.get_value("general", "load_xkb_layouts")
-@@ -257,6 +271,7 @@ class Setup(object):
-                 self.__checkbutton_auto_start_toggled_cb)
- 
-         self.__config = self.__bus.get_config()
-+        self.__config.connect("value-changed", self.__config_value_changed_cb)
- 
-         self.__init_hotkey()
-         self.__init_panel()
-@@ -271,8 +286,8 @@ class Setup(object):
-     def __combobox_notify_active_engine_cb(self, combobox, property):
-         engine = self.__combobox.get_active_engine()
-         button = self.__builder.get_object("button_engine_add")
--        button.set_sensitive(
--                engine != None and engine not in self.__treeview.get_engines())
-+        button.set_sensitive(engine != None and \
-+                engine.get_name() not in map(lambda e: e.get_name(), self.__treeview.get_engines()))
- 
-     def __get_engine_setup_exec_args(self, engine):
-         args = []
-@@ -351,6 +366,34 @@ class Setup(object):
-             del self.__engine_setup_exec_list[name]
-         self.__engine_setup_exec_list[name] = os.spawnl(os.P_NOWAIT, *args)
- 
-+    def __checkbutton_preload_engine_mode_toggled_cb(self, button):
-+        if button.get_active():
-+            variant = GLib.Variant.new_int32(IBus.PreloadEngineMode.USER)
-+            self.__config.set_value("general",
-+                                    "preload_engine_mode",
-+                                    variant)
-+            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.MessageType.QUESTION,
-+                    buttons = Gtk.ButtonsType.YES_NO,
-+                    message_format = message)
-+            id = dlg.run()
-+            dlg.destroy()
-+            self.__flush_gtk_events()
-+            if id != Gtk.ResponseType.YES:
-+                button.set_active(True)
-+                return
-+            variant = GLib.Variant.new_int32(IBus.PreloadEngineMode.LANG_RELATIVE)
-+            self.__config.set_value("general",
-+                                    "preload_engine_mode",
-+                                    variant)
-+            self.__builder.get_object("hbox_customize_active_input_methods").set_sensitive(False)
-+
-     def __init_bus(self):
-         self.__bus = IBus.Bus()
-         if self.__bus.is_connected():
-@@ -561,8 +604,18 @@ class Setup(object):
-         value = GLib.Variant.new_boolean(value)
-         self.__config.set_value("general", "use_global_engine", value)
- 
--    def __config_value_changed_cb(self, bus, section, name, value):
--        pass
-+    def __config_value_changed_cb(self, bus, section, name, variant):
-+        if section == 'general' and name == 'preload_engines':
-+            value = []
-+            if variant != None:
-+                value = self.__variant_dup_strv(variant)
-+            engines = self.__get_engine_descs_from_names(value)
-+            current_engines = self.__treeview.get_engines()
-+            engines_csv = str.join(',', map(lambda e: e.get_name(), engines))
-+            current_engines_csv = \
-+                    str.join(',', map(lambda e: e.get_name(), current_engines))
-+            if engines_csv != current_engines_csv:
-+                self.__treeview.set_engines(engines)
- 
-     def __config_reloaded_cb(self, bus):
-         pass
-diff --git a/setup/setup.ui b/setup/setup.ui
-index 8121d62..2026172 100644
---- a/setup/setup.ui
-+++ b/setup/setup.ui
-@@ -653,7 +653,23 @@
-                     <property name="visible">True</property>
-                     <property name="can_focus">False</property>
-                     <child>
--                      <object class="GtkHBox" id="hbox1">
-+                      <object class="GtkCheckButton" id="checkbutton_preload_engine_mode">
-+                        <property name="visible">True</property>
-+                        <property name="label" translatable="yes">Customize active input _methods</property>
-+                        <property name="use_underline">True</property>
-+                        <property name="can_focus">True</property>
-+                        <property name="receives_default">False</property>
-+                        <property name="tooltip_text" translatable="yes">Customize active input methods</property>
-+                        <property name="draw_indicator">True</property>
-+                      </object>
-+                      <packing>
-+                        <property name="expand">False</property>
-+                        <property name="fill">True</property>
-+                        <property name="position">0</property>
-+                      </packing>
-+                    </child>
-+                    <child>
-+                      <object class="GtkHBox" id="hbox_customize_active_input_methods">
-                         <property name="visible">True</property>
-                         <property name="can_focus">False</property>
-                         <child>
-@@ -842,7 +858,7 @@
-                       <packing>
-                         <property name="expand">True</property>
-                         <property name="fill">True</property>
--                        <property name="position">0</property>
-+                        <property name="position">1</property>
-                       </packing>
-                     </child>
-                     <child>
-@@ -889,7 +905,7 @@ You may use up/down buttons to change it.</i></small></property>
-                       <packing>
-                         <property name="expand">False</property>
-                         <property name="fill">True</property>
--                        <property name="position">1</property>
-+                        <property name="position">2</property>
-                       </packing>
-                     </child>
-                   </object>
-diff --git a/src/ibustypes.h b/src/ibustypes.h
-index 737b3e2..8ce5a16 100644
---- a/src/ibustypes.h
-+++ b/src/ibustypes.h
-@@ -204,6 +204,16 @@ typedef enum {
- } IBusError;
- 
- /**
-+ * IBusPreloadEngineMode:
-+ * @IBUS_PRELOAD_ENGINE_MODE_USER: user custimized engines
-+ * @IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE: language related engines.
-+ */
-+typedef enum {
-+    IBUS_PRELOAD_ENGINE_MODE_USER          = 0,
-+    IBUS_PRELOAD_ENGINE_MODE_LANG_RELATIVE = 1,
-+} IBusPreloadEngineMode;
-+
-+/**
-  * IBusRectangle:
-  * @x: x coordinate.
-  * @y: y coordinate.
-diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala
-index 8e6f756..01cc7aa 100644
---- a/ui/gtk3/panel.vala
-+++ b/ui/gtk3/panel.vala
-@@ -291,6 +291,8 @@ class Panel : IBus.PanelService {
-         if (m_config != null) {
-             m_config.value_changed.connect(config_value_changed_cb);
-             m_config.watch("general", "preload_engines");
-+            m_config.watch("general", "preload_engines_inited");
-+            m_config.watch("general", "preload_engine_mode");
-             m_config.watch("general", "engines_order");
-             m_config.watch("general/hotkey", "trigger_accel");
-             m_config.watch("general/hotkey", "trigger_accel_backward");
-@@ -352,7 +354,136 @@ class Panel : IBus.PanelService {
-             init_gkbd();
-         }
- 
-+        GLib.Variant var_engines = 
-+                m_config.get_value("general", "preload_engines");
-+        string[] preload_engines = {};
-+
-+        if (var_engines != null) {
-+            preload_engines = var_engines.dup_strv();
-+        }
-+
-+        bool preload_engines_inited = false;
-+        GLib.Variant var_preload_engines_inited =
-+                m_config.get_value("general", "preload_engines_inited");
-+
-+        if (var_preload_engines_inited != null) {
-+            preload_engines_inited = var_preload_engines_inited.get_boolean();
-+        }
-+
-+        // Set preload_engines_inited = true for back compatibility
-+        if (preload_engines.length != 0 && !preload_engines_inited) {
-+                preload_engines_inited = true;
-+                m_config.set_value("general",
-+                                   "preload_engines_inited",
-+                                   new GLib.Variant.boolean(true));
-+        }
-+
-         update_xkb_engines();
-+
-+        // Before update preload_engine_mode, update_xkb_engines() is called
-+        // because config_value_changed_cb() calls update_im_engines().
-+        if (!preload_engines_inited) {
-+            GLib.Variant variant = new GLib.Variant.int32(
-+                    IBus.PreloadEngineMode.LANG_RELATIVE);
-+            m_config.set_value("general",
-+                               "preload_engine_mode",
-+                               variant);
-+        }
-+
-+        update_im_engines();
-+
-+        if (!preload_engines_inited) {
-+            m_config.set_value("general",
-+                               "preload_engines_inited",
-+                               new GLib.Variant.boolean(true));
-+        }
-+    }
-+
-+    private bool set_lang_relative_preload_engines() {
-+        string locale = Intl.setlocale(LocaleCategory.CTYPE, null);
-+
-+        if (locale == null) {
-+            locale = "C";
-+        }
-+
-+        string lang = locale.split(".")[0];
-+        GLib.List<IBus.EngineDesc> engines = m_bus.list_engines();
-+        string[] im_engines = {};
-+
-+        for (unowned GLib.List<IBus.EngineDesc> p = engines;
-+             p != null;
-+             p = p.next) {
-+            unowned IBus.EngineDesc engine = p.data;
-+            if (engine.get_language() == lang &&
-+                engine.get_rank() > 0) {
-+                im_engines += engine.get_name();
-+            }
-+        }
-+
-+        lang = lang.split("_")[0];
-+        if (im_engines.length == 0) {
-+            for (unowned GLib.List<IBus.EngineDesc> p = engines;
-+                 p != null;
-+                 p = p.next) {
-+                unowned IBus.EngineDesc engine = p.data;
-+                if (engine.get_language() == lang &&
-+                    engine.get_rank() > 0) {
-+                    im_engines += engine.get_name();
-+                }
-+            }
-+        }
-+
-+        if (im_engines.length == 0) {
-+            return false;
-+        }
-+
-+        GLib.Variant var_engines = 
-+                m_config.get_value("general", "preload_engines");
-+        string[] orig_preload_engines = {};
-+        string[] preload_engines = {};
-+
-+        if (var_engines != null) {
-+            orig_preload_engines = var_engines.dup_strv();
-+        }
-+
-+        // clear input method engines
-+        foreach (string name in orig_preload_engines) {
-+            if (name.ascii_ncasecmp("xkb:", 4) != 0) {
-+                continue;
-+            }
-+            preload_engines += name;
-+        }
-+
-+        foreach (string name in im_engines) {
-+            if (!(name in preload_engines)) {
-+                preload_engines += name;
-+            }
-+        }
-+
-+        if ("".joinv(",", orig_preload_engines) !=
-+            "".joinv(",", preload_engines)) {
-+            m_config.set_value("general",
-+                               "preload_engines",
-+                               new GLib.Variant.strv(preload_engines));
-+        }
-+
-+        return true;
-+    }
-+
-+    private void update_im_engines() {
-+        int preload_engine_mode = IBus.PreloadEngineMode.USER;
-+        GLib.Variant var_preload_engine_mode =
-+                m_config.get_value("general", "preload_engine_mode");
-+
-+        if (var_preload_engine_mode != null) {
-+            preload_engine_mode = var_preload_engine_mode.get_int32();
-+        }
-+
-+        if (preload_engine_mode == IBus.PreloadEngineMode.USER) {
-+            return;
-+        }
-+
-+        set_lang_relative_preload_engines();
-     }
- 
-     private void update_xkb_engines() {
-@@ -513,6 +644,11 @@ class Panel : IBus.PanelService {
-                                          string section,
-                                          string name,
-                                          Variant variant) {
-+        if (section == "general" && name == "preload_engine_mode") {
-+            update_im_engines();
-+            return;
-+        }
-+
-         if (section == "general" && name == "preload_engines") {
-             update_engines(variant, null);
-             return;
--- 
-1.7.10.4
-
diff --git a/ibus-541492-xkb.patch b/ibus-541492-xkb.patch
deleted file mode 100644
index be8f2ca..0000000
--- a/ibus-541492-xkb.patch
+++ /dev/null
@@ -1,3534 +0,0 @@
-From 965f09a94744b6374656247ff091eb91b5bad0b2 Mon Sep 17 00:00:00 2001
-From: fujiwarat <takao.fujiwara1 at gmail.com>
-Date: Mon, 10 Dec 2012 16:24:34 +0900
-Subject: [PATCH] Add ibus-xkb and libgnomekbd.
-
----
- bindings/vala/Gkbd-3.0.metadata |   1 +
- bindings/vala/Makefile.am       |  23 ++
- bindings/vala/Xkl-1.0.metadata  |   3 +
- configure.ac                    |  68 +++++
- data/ibus.schemas.in            |  94 +++++++
- engine/Makefile.am              |   6 +
- engine/ibus-xkb/Makefile.am     |  61 ++++
- engine/ibus-xkb/ibus-xkb-main.c | 173 ++++++++++++
- engine/ibus-xkb/xkblib.c        | 327 ++++++++++++++++++++++
- engine/ibus-xkb/xkblib.h        |  41 +++
- engine/main.vala                |  86 ++++++
- engine/simple.xml.in.in         | 605 +---------------------------------------
- ibus-1.0.pc.in                  |   4 +
- ibus.spec.in                    |  12 +
- setup/main.py                   |  38 ++-
- src/Makefile.am                 |   5 +
- src/ibus.h                      |   1 +
- src/ibusxkbxml.c                | 466 +++++++++++++++++++++++++++++++
- src/ibusxkbxml.h                | 187 +++++++++++++
- ui/gtk3/Makefile.am             |  37 +++
- ui/gtk3/gkbdlayout.vala.false   |  63 +++++
- ui/gtk3/gkbdlayout.vala.true    | 108 +++++++
- ui/gtk3/panel.vala              | 362 ++++++++++++++++++++++--
- ui/gtk3/xkblayout.vala          | 465 ++++++++++++++++++++++++++++++
- 24 files changed, 2597 insertions(+), 639 deletions(-)
- create mode 100644 bindings/vala/Gkbd-3.0.metadata
- create mode 100644 bindings/vala/Xkl-1.0.metadata
- create mode 100644 engine/ibus-xkb/Makefile.am
- create mode 100644 engine/ibus-xkb/ibus-xkb-main.c
- create mode 100644 engine/ibus-xkb/xkblib.c
- create mode 100644 engine/ibus-xkb/xkblib.h
- create mode 100644 src/ibusxkbxml.c
- create mode 100644 src/ibusxkbxml.h
- create mode 100644 ui/gtk3/gkbdlayout.vala.false
- create mode 100644 ui/gtk3/gkbdlayout.vala.true
- create mode 100644 ui/gtk3/xkblayout.vala
-
-diff --git a/bindings/vala/Gkbd-3.0.metadata b/bindings/vala/Gkbd-3.0.metadata
-new file mode 100644
-index 0000000..661e6fd
---- /dev/null
-+++ b/bindings/vala/Gkbd-3.0.metadata
-@@ -0,0 +1 @@
-+Configuration cheader_filename="libgnomekbd/gkbd-configuration.h"
-diff --git a/bindings/vala/Makefile.am b/bindings/vala/Makefile.am
-index abcc543..307a161 100644
---- a/bindings/vala/Makefile.am
-+++ b/bindings/vala/Makefile.am
-@@ -22,9 +22,16 @@
- 
- -include $(VAPIGEN_MAKEFILE)
- 
-+if ENABLE_LIBGNOMEKBD
-+kbd_dep = $(builddir)/gkbd.vapi
-+else
-+kbd_dep =
-+endif
-+
- vapi_deps = \
- 	IBus-1.0.metadata \
- 	IBus-1.0-custom.vala \
-+	$(kbd_dep) \
- 	$(top_builddir)/src/IBus-1.0.gir \
- 	$(NULL)
- 
-@@ -42,12 +49,25 @@
- vapidir = $(datadir)/vala/vapi
- vapi_DATA = $(VAPIGEN_VAPIS) $(VAPIGEN_VAPIS:.vapi=.deps)
- 
-+if ENABLE_LIBGNOMEKBD
-+$(builddir)/gkbd.vapi:
-+	$(AM_V_GEN) $(VAPIGEN) --library gkbd \
-+	    --metadatadir $(srcdir) \
-+	    --pkg gtk+-3.0 --pkg glib-2.0 --pkg gmodule-2.0 \
-+	    /usr/share/gir-1.0/Gkbd-3.0.gir
-+	$(NULL)
-+endif
-+
- EXTRA_DIST = \
-+	Gkbd-3.0.metadata \
- 	IBus-1.0.metadata \
- 	IBus-1.0-custom.vala \
- 	ibus-1.0.deps \
- 	config.vapi \
- 	xi.vapi \
-+	Xkl-1.0.metadata \
- 	$(NULL)
- 
-+CLEANFILES = gkbd.vapi
-+
- -include $(top_srcdir)/git.mk
-diff --git a/bindings/vala/Xkl-1.0.metadata b/bindings/vala/Xkl-1.0.metadata
-new file mode 100644
-index 0000000..4961d0c
---- /dev/null
-+++ b/bindings/vala/Xkl-1.0.metadata
-@@ -0,0 +1,3 @@
-+Xkl cheader_filename="libxklavier/xklavier.h"
-+Engine
-+    .filter_events.evt ref type="X.Event"
-diff --git a/configure.ac b/configure.ac
-index cc7d0e0..246b3fc 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -252,6 +252,71 @@ else
-     enable_xim="no (disabled, use --enable-xim to enable)"
- fi
- 
-+# Option for XKB command.
-+AC_ARG_WITH(xkb-command,
-+    AS_HELP_STRING([--with-xkb-command[=XKB_COMMAND]],
-+        [Use XKB_COMMAND to set keymap. ibus-xkb is available. (default is setxkbmap)]),
-+    XKB_COMMAND=$with_xkb_command,
-+    XKB_COMMAND=setxkbmap
-+)
-+AC_DEFINE_UNQUOTED(XKB_COMMAND, "$XKB_COMMAND",
-+                   [xkb command line to set xkb keymaps.])
-+
-+if test x"$XKB_COMMAND" = x"ibus-xkb"; then
-+    enable_ibus_xkb=yes
-+else
-+    enable_ibus_xkb=no
-+fi
-+
-+AM_CONDITIONAL([ENABLE_IBUS_XKB], [test x"$enable_ibus_xkb" = x"yes"])
-+if test x"$enable_ibus_xkb" = x"yes"; then
-+    PKG_CHECK_MODULES(X11, [
-+        x11
-+    ])
-+    PKG_CHECK_MODULES(XKB,
-+        [xkbfile],,
-+        [XKB_LIBS="-lxkbfile"]
-+    )
-+    AC_DEFINE(HAVE_IBUS_XKB, 1, [define to 1 if you have xkbfile])
-+    HAVE_IBUS_XKB=true
-+else
-+    HAVE_IBUS_XKB=false
-+fi
-+AC_SUBST(HAVE_IBUS_XKB)
-+
-+# --enable-libgnomekbd option.
-+AC_ARG_ENABLE(libgnomekbd,
-+    AS_HELP_STRING([--enable-libgnomekbd],
-+                   [Use libgnomekbd to handle the keymaps]),
-+    [enable_libgnomekbd=$enableval],
-+    [enable_libgnomekbd=no]
-+)
-+AM_CONDITIONAL([ENABLE_LIBGNOMEKBD], [test x"$enable_libgnomekbd" = x"yes"])
-+if test x"$enable_libgnomekbd" = x"yes"; then
-+    # check for libgnomekbd
-+    PKG_CHECK_MODULES(LIBGNOMEKBDUI, [
-+        libgnomekbdui
-+    ])
-+    PKG_CHECK_MODULES(ATK, [
-+        atk
-+    ])
-+    HAVE_IBUS_GKBD=true
-+else
-+    enable_libgnomekbd="no (disabled, use --enable-libgnomekbd to enable)"
-+    HAVE_IBUS_GKBD=false
-+fi
-+AC_SUBST(HAVE_IBUS_GKBD)
-+
-+# Define XKB rules file
-+AC_ARG_WITH(xkb-rules-xml,
-+    AS_HELP_STRING([--with-xkb-rules-xml[=$DIR/evdev.xml]],
-+        [Set evdev.xml file path (default: /usr/share/X11/xkb/rules/evdev.xml)]),
-+    XKB_RULES_XML_FILE=$with_xkb_rules_xml,
-+    XKB_RULES_XML_FILE="/usr/share/X11/xkb/rules/evdev.xml"
-+)
-+AC_DEFINE_UNQUOTED(XKB_RULES_XML_FILE, "$XKB_RULES_XML_FILE",
-+    [Define file path of evdev.xml])
-+
- # GObject introspection
- GOBJECT_INTROSPECTION_CHECK([0.6.8])
- 
-@@ -519,6 +584,7 @@
- src/tests/Makefile
- bus/Makefile
- engine/Makefile
-+engine/ibus-xkb/Makefile
- util/Makefile
- util/IMdkit/Makefile
- data/Makefile
-@@ -576,6 +642,8 @@ Build options:
-   No snooper regexes        "$NO_SNOOPER_APPS"
-   Panel icon                "$IBUS_ICON_KEYBOARD"
-   Enable surrounding-text   $enable_surrounding_text
-+  XKB command               $XKB_COMMAND
-+  Build libgnomebkd         $enable_libgnomekbd
-   Run test cases            $enable_tests
- ])
- 
-diff --git a/data/ibus.schemas.in b/data/ibus.schemas.in
-index a8c7d7f..1a0e2d2 100644
---- a/data/ibus.schemas.in
-+++ b/data/ibus.schemas.in
-@@ -42,6 +42,52 @@
-       </locale>
-     </schema>
-     <schema>
-+      <key>/schemas/desktop/ibus/general/use_xmodmap</key>
-+      <applyto>/desktop/ibus/general/use_xmodmap</applyto>
-+      <owner>ibus</owner>
-+      <type>bool</type>
-+      <default>true</default>
-+      <locale name="C">
-+        <short>Use xmodmap</short>
-+           <long>Run xmodmap if .xmodmap/.Xmodmap exists.</long>
-+      </locale>
-+    </schema>
-+    <schema>
-+      <key>/schemas/desktop/ibus/general/xkb_latin_layouts</key>
-+      <applyto>/desktop/ibus/general/xkb_latin_layouts</applyto>
-+      <owner>ibus</owner>
-+      <type>list</type>
-+      <list_type>string</list_type>
-+      <default>[ara,bg,cz,dev,gr,gur,in,jp(kana),mal,mkd,ru,ua]</default>
-+      <locale name="C">
-+        <short>Latin layout which have no ASCII</short>
-+           <long>us layout is appended to the latin layouts. variant is not needed.</long>
-+      </locale>
-+    </schema>
-+    <schema>
-+      <key>/schemas/desktop/ibus/general/load_xkb_layouts</key>
-+      <applyto>/desktop/ibus/general/load_xkb_layouts</applyto>
-+      <owner>ibus</owner>
-+      <type>list</type>
-+      <list_type>string</list_type>
-+      <default>[us,us(chr),us(dvorak),ad,al,am,ara,az,ba,bd,be,bg,br,bt,by,
-+de,dk,ca,ch,cn(tib),cz,ee,epo,es,et,fi,fo,fr,
-+gb,ge,ge(dsb),ge(ru),ge(os),gh,gh(akan),gh(ewe),gh(fula),gh(ga),gh(hausa),
-+gn,gr,hu,hr,ie,ie(CloGaelach),il,
-+in,
-+in(tel),in(bolnagri),iq,iq(ku),ir,ir(ku),is,it,jp,
-+kg,kh,kz,la,latam,lk,lk(tam_unicode),lt,lv,ma,ma(tifinagh),mal,mao,
-+me,mk,mm,mt,mv,ng,ng(hausa),ng,ng(igbo),ng(yoruba),nl,no,no(smi),np,
-+pk,pl,pl(csb),pt,ro,rs,ru,ru(cv),ru(kom),ru(sah),ru(tt),ru(xal),
-+se,si,sk,sy,sy(ku),th,tj,tr,ua,uz,vn
-+]</default>
-+      <locale name="C">
-+        <short>XKB layout list which is shown on ibus-setup</short>
-+           <long>XKB layout list which is shown on ibus-setup.
-+                 The format is "layout" or "layout(variant)".</long>
-+      </locale>
-+    </schema>
-+    <schema>
-       <key>/schemas/desktop/ibus/general/hotkey/trigger</key>
-       <applyto>/desktop/ibus/general/hotkey/trigger</applyto>
-       <owner>ibus</owner>
-@@ -66,6 +112,30 @@
-       </locale>
-     </schema>
-     <schema>
-+      <key>/schemas/desktop/ibus/general/hotkey/trigger_ja</key>
-+      <applyto>/desktop/ibus/general/hotkey/trigger_ja</applyto>
-+      <owner>ibus</owner>
-+      <type>list</type>
-+      <list_type>string</list_type>
-+      <default>[Zenkaku_Hankaku]</default>
-+      <locale name="C">
-+        <short>Trigger shortcut keys for ja gtk_accelerator_parse</short>
-+	    <long>The shortcut keys for turning input method on or off</long>
-+      </locale>
-+    </schema>
-+    <schema>
-+      <key>/schemas/desktop/ibus/general/hotkey/trigger_ko</key>
-+      <applyto>/desktop/ibus/general/hotkey/trigger_ko</applyto>
-+      <owner>ibus</owner>
-+      <type>list</type>
-+      <list_type>string</list_type>
-+      <default>[Hangul, Alt_R]</default>
-+      <locale name="C">
-+        <short>Trigger shortcut keys for ko gtk_accelerator_parse</short>
-+	    <long>The shortcut keys for turning input method on or off</long>
-+      </locale>
-+    </schema>
-+    <schema>
-       <key>/schemas/desktop/ibus/general/hotkey/enable_unconditional</key>
-       <applyto>/desktop/ibus/general/hotkey/enable_unconditional</applyto>
-       <owner>ibus</owner>
-diff --git a/engine/Makefile.am b/engine/Makefile.am
-index b3b46be..90c6fde 100644
---- a/engine/Makefile.am
-+++ b/engine/Makefile.am
-@@ -22,6 +22,12 @@
- 
- libibus = $(top_builddir)/src/libibus- at IBUS_API_VERSION@.la
- 
-+SUBDIRS =
-+
-+if ENABLE_IBUS_XKB
-+SUBDIRS += ibus-xkb
-+endif
-+
- INCLUDES = \
- 	-I$(top_srcdir)/src \
- 	-I$(top_builddir)/src \
-diff --git a/engine/ibus-xkb/Makefile.am b/engine/ibus-xkb/Makefile.am
-new file mode 100644
-index 0000000..4a32e87
---- /dev/null
-+++ b/engine/ibus-xkb/Makefile.am
-@@ -0,0 +1,61 @@
-+# vim:set noet ts=4:
-+#
-+# ibus - The Input Bus
-+#
-+# Copyright (c) 2012 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+# Copyright (c) 2012 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)/src \
-+	-I$(top_builddir)/src \
-+	$(NULL)
-+
-+AM_CFLAGS = \
-+	$(INCLUDES) \
-+	-DG_LOG_DOMAIN=\"IBUS\" \
-+	-DIBUS_DISABLE_DEPRECATED \
-+	-Wno-unused-variable \
-+	-Wno-unused-but-set-variable \
-+	-Wno-unused-function \
-+	$(NULL)
-+
-+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)
-+
-+$(libibus):
-+	$(MAKE) -C $(top_builddir)/src
-+
-+-include $(top_srcdir)/git.mk
-diff --git a/engine/ibus-xkb/ibus-xkb-main.c b/engine/ibus-xkb/ibus-xkb-main.c
-new file mode 100644
-index 0000000..3dfd987
---- /dev/null
-+++ b/engine/ibus-xkb/ibus-xkb-main.c
-@@ -0,0 +1,173 @@
-+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
-+/* vim:set et sts=4: */
-+/* bus - The Input Bus
-+ * Copyright (C) 2012 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+ * Copyright (C) 2012 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright (C) 2012 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 <glib.h>
-+#include <glib/gprintf.h>
-+#include <glib/gi18n.h>
-+#include <X11/Xlib.h>
-+
-+#ifdef ENABLE_NLS
-+#include <locale.h>
-+#endif
-+
-+#include "xkblib.h"
-+
-+static gboolean query = FALSE;
-+static gboolean get_group = FALSE;
-+static gchar *layout = NULL;
-+static gchar *variant = NULL;
-+static gchar *option = NULL;
-+static int group = 0;
-+
-+static const GOptionEntry entries[] =
-+{
-+    { "get", 'g', 0, G_OPTION_ARG_NONE, &query, N_("Query the current xkb layout"), NULL },
-+    { "layout", 'l', 0, G_OPTION_ARG_STRING, &layout, N_("Set xkb LAYOUT"), N_("LAYOUT") },
-+    { "variant", 'v', 0, G_OPTION_ARG_STRING, &variant, N_("Set xkb VARIANT"), N_("VARIANT") },
-+    { "option", 'o', 0, G_OPTION_ARG_STRING, &option, N_("Set xkb OPTION"), N_("OPTION") },
-+    { "get-group", 'G', 0, G_OPTION_ARG_NONE, &get_group, N_("Get current xkb state"), NULL },
-+    { NULL },
-+};
-+
-+
-+gboolean
-+parse_setxkbmap_args (int *pargc, char ***pargv)
-+{
-+    int argc = *pargc;
-+    char **argv = *pargv;
-+    char **new_argv = NULL;
-+    int n = 1;
-+    int i;
-+    gboolean retval = FALSE;
-+
-+    for (i = 0; i < argc; i++) {
-+        if (g_strcmp0 (argv[i], "-layout") == 0 && i + 1 < argc) {
-+            g_free (layout);
-+            layout = g_strdup (argv[i + 1]);
-+            i++;
-+            retval = TRUE;
-+            continue;
-+        }
-+        if (g_strcmp0 (argv[i], "-variant") == 0 && i + 1 < argc) {
-+            g_free (variant);
-+            variant = g_strdup (argv[i + 1]);
-+            i++;
-+            retval = TRUE;
-+            continue;
-+        }
-+        if (g_strcmp0 (argv[i], "-option") == 0 && i + 1 < argc) {
-+            g_free (option);
-+            option = g_strdup (argv[i + 1]);
-+            i++;
-+            retval = TRUE;
-+            continue;
-+        }
-+        if (g_strcmp0 (argv[i], "-query") == 0) {
-+            query = TRUE;
-+            retval = TRUE;
-+            continue;
-+        }
-+
-+        new_argv = g_renew(char*, new_argv, n);
-+        new_argv[n - 1] = g_strdup (argv[i]);
-+        n++;
-+    }
-+
-+    *pargc = n - 1;
-+    *pargv = new_argv;
-+
-+    return retval;
-+}
-+
-+int
-+main (int argc, char *argv[])
-+{
-+    gboolean parsed;
-+    GOptionContext *context;
-+    GError *error = NULL;
-+    Display *xdisplay;
-+
-+#ifdef ENABLE_NLS
-+    setlocale (LC_ALL, "");
-+
-+    bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
-+    bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-+#endif
-+
-+    parsed = parse_setxkbmap_args (&argc, &argv);
-+
-+    context = g_option_context_new ("- ibus daemon");
-+
-+    g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
-+    g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
-+
-+    if (!parsed && !g_option_context_parse (context, &argc, &argv, &error)) {
-+        g_printerr ("Option parsing failed: %s\n", error->message);
-+        return -1;
-+    }
-+
-+    xdisplay = XOpenDisplay (NULL);
-+    if (xdisplay == NULL) {
-+        g_warning ("Could not open display");
-+        return -1;
-+    }
-+    ibus_xkb_init (xdisplay);
-+
-+    if (layout) {
-+        if (option == NULL) {
-+            option = ibus_xkb_get_current_option ();
-+        }
-+
-+        ibus_xkb_set_layout (layout, variant, option);
-+    }
-+
-+    if (query) {
-+        g_free (layout);
-+        g_free (variant);
-+        g_free (option);
-+
-+        layout = ibus_xkb_get_current_layout ();
-+        variant = ibus_xkb_get_current_variant ();
-+        option = ibus_xkb_get_current_option ();
-+        g_printf ("layout: %s\n"
-+                  "variant: %s\n"
-+                  "option: %s\n",
-+                  layout ? layout : "",
-+                  variant ? variant : "",
-+                  option ? option : "");
-+        g_free (layout);
-+        g_free (variant);
-+        g_free (option);
-+    }
-+    if (get_group) {
-+        group = ibus_xkb_get_current_group ();
-+        g_printf ("group: %d\n", group);
-+    }
-+
-+    ibus_xkb_finit ();
-+
-+    return 0;
-+}
-diff --git a/engine/ibus-xkb/xkblib.c b/engine/ibus-xkb/xkblib.c
-new file mode 100644
-index 0000000..bb25455
---- /dev/null
-+++ b/engine/ibus-xkb/xkblib.c
-@@ -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) 2012 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+ * Copyright (C) 2012 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright (C) 2012 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 <glib.h>
-+#include <X11/Xlib.h>
-+#include <X11/Xatom.h>
-+#include <X11/XKBlib.h>
-+#include <stdio.h> /* for XKBrules.h */
-+#include <X11/extensions/XKBrules.h>
-+#include <X11/extensions/XKBstr.h>
-+#include <string.h>
-+
-+#include "xkblib.h"
-+
-+#ifndef XKB_RULES_XML_FILE
-+#define XKB_RULES_XML_FILE "/usr/share/X11/xkb/rules/evdev.xml"
-+#endif
-+
-+static gchar          **default_layouts;
-+static gchar          **default_variants;
-+static gchar          **default_options;
-+static int              default_layout_group;
-+
-+static Display *
-+get_xdisplay (Display *xdisplay)
-+{
-+    static Display *saved_xdisplay = NULL;
-+    if (xdisplay != NULL) {
-+        saved_xdisplay = xdisplay;
-+    }
-+    return saved_xdisplay;
-+}
-+
-+static void
-+init_xkb_default_layouts (Display *xdisplay)
-+{
-+    XkbStateRec state;
-+    Atom xkb_rules_name, type;
-+    int format;
-+    unsigned long l, nitems, bytes_after;
-+    unsigned char *prop = NULL;
-+
-+    xkb_rules_name = XInternAtom (xdisplay, "_XKB_RULES_NAMES", TRUE);
-+    if (xkb_rules_name == None) {
-+        g_warning ("Could not get XKB rules atom");
-+        return;
-+    }
-+    if (XGetWindowProperty (xdisplay,
-+                            XDefaultRootWindow (xdisplay),
-+                            xkb_rules_name,
-+                            0, 1024, FALSE, XA_STRING,
-+                            &type, &format, &nitems, &bytes_after, &prop) != Success) {
-+        g_warning ("Could not get X property");
-+        return;
-+    }
-+    if (nitems < 3) {
-+        g_warning ("Could not get group layout from X property");
-+        return;
-+    }
-+    for (l = 0; l < 2; l++) {
-+        prop += strlen ((const char *) prop) + 1;
-+    }
-+    if (prop == NULL || *prop == '\0') {
-+        g_warning ("No layouts form X property");
-+        return;
-+    }
-+    default_layouts = g_strsplit ((gchar *) prop, ",", -1);
-+    prop += strlen ((const char *) prop) + 1;
-+    default_variants = g_strsplit ((gchar *) prop, ",", -1);
-+    prop += strlen ((const char *) prop) + 1;
-+    default_options = g_strsplit ((gchar *) prop, ",", -1);
-+
-+    if (XkbGetState (xdisplay, XkbUseCoreKbd, &state) != Success) {
-+        g_warning ("Could not get state");
-+        return;
-+    }
-+    default_layout_group = state.group;
-+}
-+
-+static Bool
-+set_xkb_rules (Display *xdisplay,
-+               const char *rules_file, const char *model,
-+               const char *all_layouts, const char *all_variants,
-+               const char *all_options)
-+{
-+    gchar *rules_path;
-+    XkbRF_RulesPtr rules;
-+    XkbRF_VarDefsRec rdefs;
-+    XkbComponentNamesRec rnames;
-+    XkbDescPtr xkb;
-+
-+    rules_path = g_strdup ("./rules/evdev");
-+    rules = XkbRF_Load (rules_path, "C", TRUE, TRUE);
-+    if (rules == NULL) {
-+        g_return_val_if_fail (XKB_RULES_XML_FILE != NULL, FALSE);
-+
-+        g_free (rules_path);
-+        if (g_str_has_suffix (XKB_RULES_XML_FILE, ".xml")) {
-+            rules_path = g_strndup (XKB_RULES_XML_FILE,
-+                                    strlen (XKB_RULES_XML_FILE) - 4);
-+        } else {
-+            rules_path = g_strdup (XKB_RULES_XML_FILE);
-+        }
-+        rules = XkbRF_Load (rules_path, "C", TRUE, TRUE);
-+    }
-+    g_return_val_if_fail (rules != NULL, FALSE);
-+
-+    memset (&rdefs, 0, sizeof (XkbRF_VarDefsRec));
-+    memset (&rnames, 0, sizeof (XkbComponentNamesRec));
-+    rdefs.model = model ? g_strdup (model) : NULL;
-+    rdefs.layout = all_layouts ? g_strdup (all_layouts) : NULL;
-+    rdefs.variant = all_variants ? g_strdup (all_variants) : NULL;
-+    rdefs.options = all_options ? g_strdup (all_options) : NULL;
-+    XkbRF_GetComponents (rules, &rdefs, &rnames);
-+    xkb = XkbGetKeyboardByName (xdisplay, XkbUseCoreKbd, &rnames,
-+                                XkbGBN_AllComponentsMask,
-+                                XkbGBN_AllComponentsMask &
-+                                (~XkbGBN_GeometryMask), True);
-+    if (!xkb) {
-+        g_warning ("Cannot load new keyboard description.");
-+        return FALSE;
-+    }
-+    XkbRF_SetNamesProp (xdisplay, rules_path, &rdefs);
-+    g_free (rules_path);
-+    g_free (rdefs.model);
-+    g_free (rdefs.layout);
-+    g_free (rdefs.variant);
-+    g_free (rdefs.options);
-+
-+    return TRUE;
-+}
-+
-+static Bool
-+update_xkb_properties (Display *xdisplay,
-+                       const char *rules_file, const char *model,
-+                       const char *all_layouts, const char *all_variants,
-+                       const char *all_options)
-+{
-+    int len;
-+    char *pval;
-+    char *next;
-+    Atom rules_atom;
-+    Window root_window;
-+
-+    len = (rules_file ? strlen (rules_file) : 0);
-+    len += (model ? strlen (model) : 0);
-+    len += (all_layouts ? strlen (all_layouts) : 0);
-+    len += (all_variants ? strlen (all_variants) : 0);
-+    len += (all_options ? strlen (all_options) : 0);
-+
-+    if (len < 1) {
-+        return TRUE;
-+    }
-+    len += 5; /* trailing NULs */
-+
-+    rules_atom = XInternAtom (xdisplay, _XKB_RF_NAMES_PROP_ATOM, False);
-+    root_window = XDefaultRootWindow (xdisplay);
-+    pval = next = g_new0 (char, len + 1);
-+    if (!pval) {
-+        return TRUE;
-+    }
-+
-+    if (rules_file) {
-+        strcpy (next, rules_file);
-+        next += strlen (rules_file);
-+    }
-+    *next++ = '\0';
-+    if (model) {
-+        strcpy (next, model);
-+        next += strlen (model);
-+    }
-+    *next++ = '\0';
-+    if (all_layouts) {
-+        strcpy (next, all_layouts);
-+        next += strlen (all_layouts);
-+    }
-+    *next++ = '\0';
-+    if (all_variants) {
-+        strcpy (next, all_variants);
-+        next += strlen (all_variants);
-+    }
-+    *next++ = '\0';
-+    if (all_options) {
-+        strcpy (next, all_options);
-+        next += strlen (all_options);
-+    }
-+    *next++ = '\0';
-+    if ((next - pval) != len) {
-+        g_free (pval);
-+        return TRUE;
-+    }
-+
-+    XChangeProperty (xdisplay, root_window,
-+                    rules_atom, XA_STRING, 8, PropModeReplace,
-+                    (unsigned char *) pval, len);
-+    XSync(xdisplay, False);
-+
-+    return TRUE;
-+}
-+
-+void
-+ibus_xkb_init (Display *xdisplay)
-+{
-+    get_xdisplay (xdisplay);
-+    init_xkb_default_layouts (xdisplay);
-+}
-+
-+void
-+ibus_xkb_finit (void)
-+{
-+    g_strfreev (default_layouts);
-+    default_layouts = NULL;
-+    g_strfreev (default_variants);
-+    default_variants = NULL;
-+    g_strfreev (default_options);
-+    default_options = NULL;
-+}
-+
-+gchar *
-+ibus_xkb_get_current_layout (void)
-+{
-+    if (default_layouts == NULL) {
-+        g_warning ("Your system seems not to support XKB.");
-+        return NULL;
-+    }
-+
-+    return g_strjoinv (",", (gchar **) default_layouts);
-+}
-+
-+gchar *
-+ibus_xkb_get_current_variant (void)
-+{
-+    if (default_variants == NULL) {
-+        return NULL;
-+    }
-+
-+    return g_strjoinv (",", (gchar **) default_variants);
-+}
-+
-+gchar *
-+ibus_xkb_get_current_option (void)
-+{
-+    if (default_options == NULL) {
-+        return NULL;
-+    }
-+
-+    return g_strjoinv (",", (gchar **) default_options);
-+}
-+
-+gboolean
-+ibus_xkb_set_layout  (const char *layouts,
-+                      const char *variants,
-+                      const char *options)
-+{
-+    Display *xdisplay;
-+    gboolean retval;
-+    gchar *layouts_line;
-+
-+    if (default_layouts == NULL) {
-+        g_warning ("Your system seems not to support XKB.");
-+        return FALSE;
-+    }
-+
-+    if (layouts == NULL || g_strcmp0 (layouts, "default") == 0) {
-+        layouts_line = g_strjoinv (",", (gchar **) default_layouts);
-+    } else {
-+        layouts_line = g_strdup (layouts);
-+    }
-+
-+    xdisplay = get_xdisplay (NULL);
-+    retval = set_xkb_rules (xdisplay,
-+                            "evdev", "evdev",
-+                            layouts_line, variants, options);
-+    update_xkb_properties (xdisplay,
-+                           "evdev", "evdev",
-+                           layouts_line, variants, options);
-+    g_free (layouts_line);
-+
-+    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/engine/ibus-xkb/xkblib.h b/engine/ibus-xkb/xkblib.h
-new file mode 100644
-index 0000000..36597c3
---- /dev/null
-+++ b/engine/ibus-xkb/xkblib.h
-@@ -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) 2012 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+ * Copyright (C) 2012 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright (C) 2012 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 __XKBLIB_H_
-+#define __XKBLIB_H_
-+
-+#include <X11/Xlib.h>
-+
-+G_BEGIN_DECLS
-+
-+void             ibus_xkb_init                   (Display *xdisplay);
-+void             ibus_xkb_finit                  (void);
-+gchar           *ibus_xkb_get_current_layout     (void);
-+gchar           *ibus_xkb_get_current_variant    (void);
-+gchar           *ibus_xkb_get_current_option     (void);
-+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/engine/main.vala b/engine/main.vala
-index acfa737..afadca0 100644
---- a/engine/main.vala
-+++ b/engine/main.vala
-@@ -21,6 +21,85 @@
-  */
- 
- using IBus;
-+using GLib;
-+
-+private void print_xml(string  layout,
-+                       string  layout_desc,
-+                       string? variant,
-+                       string? variant_desc,
-+                       string  lang) {
-+    string name = "xkb:%s:%s:%s".printf(layout, variant ?? "", lang);
-+    string keymap = layout;
-+    string desc = layout_desc;
-+    string symbol = lang;
-+
-+    if (variant != null) {
-+        keymap = "%s(%s)".printf(layout, variant);
-+    }
-+
-+    if (variant_desc != null) {
-+        desc = variant_desc;
-+    }
-+
-+    desc = desc.replace("<", "<").replace(">", ">");
-+
-+    if (lang.length > 2) {
-+        symbol = lang[0:2];
-+    }
-+
-+    string engine = "
-+              <engine>
-+                        <name>%s</name>
-+                        <language>%s</language>
-+                        <license>GPL</license>
-+                        <author>Peng Huang <shawn.p.huang at gmail.com></author>
-+                        <layout>%s</layout>
-+                        <longname>%s</longname>
-+                        <description>%s</description>
-+                        <icon>ibus-keyboard</icon>
-+                        <symbol>%s</symbol>
-+                        <rank>%d</rank>
-+              </engine>".printf(name, lang, keymap, desc, desc, symbol, 99);
-+    print (engine);
-+}
-+
-+private void print_component() {
-+    IBus.XKBConfigRegistry registry = new IBus.XKBConfigRegistry();
-+    GLib.List layouts = registry.layout_list_get_layouts();
-+    GLib.List variants;
-+    GLib.List langs;
-+    string layout_desc;
-+    const string header = "<engines>";
-+    const string footer = "
-+</engines>";
-+
-+    print (header);
-+    for (unowned GLib.List<string> l = layouts; l != null; l = l.next) {
-+        variants = registry.layout_list_get_variants(l.data);
-+        langs = registry.layout_lang_get_langs(l.data);
-+        layout_desc = registry.layout_desc_get_desc(l.data);
-+        for (unowned GLib.List<string> lg = langs; lg != null; lg = lg.next) {
-+            print_xml(l.data, layout_desc, null, null, lg.data);
-+        }
-+        for (unowned GLib.List<string> v = variants; v != null; v = v.next) {
-+            var l_v = "%s(%s)".printf(l.data, v.data);
-+            unowned GLib.List<string> l_v_langs = null;
-+            GLib.List<string> _l_v_langs = registry.layout_lang_get_langs(l_v);
-+            l_v_langs = _l_v_langs;
-+            if (l_v_langs == null) {
-+                l_v_langs = langs;
-+            }
-+            for (unowned GLib.List<string> lg = l_v_langs; lg != null; lg = lg.next) {
-+                print_xml(l.data,
-+                          layout_desc,
-+                          v.data,
-+                          registry.variant_desc_get_desc(l_v),
-+                          lg.data);
-+            }
-+        }
-+    }
-+    print (footer);
-+}
- 
- class DummyEngine : IBus.EngineSimple {
- }
-@@ -28,6 +107,13 @@ class DummyEngine : IBus.EngineSimple {
- public int main(string[] args) {
-     IBus.init();
- 
-+    if (args.length >= 2) {
-+        if (args[1] == "--xml" || args[1] == "-x") {
-+            print_component();
-+            return 0;
-+        }
-+    }
-+
-     IBus.Bus bus = new IBus.Bus();
-     if (!bus.is_connected()) {
-         warning("ibus-daemon does not exist.");
-diff --git a/engine/simple.xml.in b/engine/simple.xml.in
-index d064ad6..d14ad93 100644
---- a/engine/simple.xml.in
-+++ b/engine/simple.xml.in
-@@ -7,620 +7,5 @@
- 	<license>GPL</license>
- 	<homepage>http://code.google.com/p/ibus</homepage>
- 	<textdomain>ibus</textdomain>
--	<engines>
--		<engine>
--			<name>xkb:us::eng</name>
--			<language>eng</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>us</layout>
--			<longname>English (US)</longname>
--			<description>English (US)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:us:intl:eng</name>
--			<language>eng</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>us</layout>
--			<layout_variant>intl</layout_variant>
--			<longname>English (US, international with dead keys)</longname>
--			<description>English (US, international with dead keys)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:us:colemak:eng</name>
--			<language>eng</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>us</layout>
--			<layout_variant>colemak</layout_variant>
--			<longname>English (Colemak)</longname>
--			<description>English (Colemak)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:us:dvorak:eng</name>
--			<language>eng</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>us</layout>
--			<layout_variant>dvorak</layout_variant>
--			<longname>English (Dvorak)</longname>
--			<description>English (Dvorak)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:us:altgr-intl:eng</name>
--			<language>eng</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>us</layout>
--			<layout_variant>altgr-intl</layout_variant>
--			<longname>English (international AltGr dead keys)</longname>
--			<description>English (international AltGr dead keys)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:ara::ara</name>
--			<language>ara</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>ara</layout>
--			<longname>Arabic</longname>
--			<description>Arabic</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:be::ger</name>
--			<language>ger</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>be</layout>
--			<longname>Belgian</longname>
--			<description>Belgian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:be::nld</name>
--			<language>nld</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>be</layout>
--			<longname>Belgian</longname>
--			<description>Belgian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:be::fra</name>
--			<language>fra</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>be</layout>
--			<longname>Belgian</longname>
--			<description>Belgian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:br::por</name>
--			<language>por</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>br</layout>
--			<longname>Portuguese (Brazil)</longname>
--			<description>Portuguese (Brazil)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:br:dvorak:por</name>
--			<language>por</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>br</layout>
--			<layout_variant>dvorak</layout_variant>
--			<longname>Portuguese (Brazil, Dvorak)</longname>
--			<description>Portuguese (Brazil, Dvorak)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:bg::bul</name>
--			<language>bul</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>bg</layout>
--			<longname>Bulgarian</longname>
--			<description>Bulgarian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:bg:phonetic:bul</name>
--			<language>bul</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>bg</layout>
--			<layout_variant>phonetic</layout_variant>
--			<longname>Bulgarian (traditional phonetic)</longname>
--			<description>Bulgarian (traditional phonetic)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:ca::fra</name>
--			<language>fra</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>ca</layout>
--			<longname>French (Canada)</longname>
--			<description>French (Canada)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:ca:eng:eng</name>
--			<language>eng</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>ca</layout>
--			<layout_variant>eng</layout_variant>
--			<longname>English (Canada)</longname>
--			<description>English (Canada)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:hr::scr</name>
--			<language>scr</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>hr</layout>
--			<longname>Croatian</longname>
--			<description>Croatian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:cz::cze</name>
--			<language>cze</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>cz</layout>
--			<longname>Czech</longname>
--			<description>Czech</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:dk::dan</name>
--			<language>dan</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>dk</layout>
--			<longname>Danish</longname>
--			<description>Danish</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:ee::est</name>
--			<language>est</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>ee</layout>
--			<longname>Estonian</longname>
--			<description>Estonian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:fi::fin</name>
--			<language>fin</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>fi</layout>
--			<longname>Finnish</longname>
--			<description>Finnish</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:fr::fra</name>
--			<language>fra</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>fr</layout>
--			<longname>French</longname>
--			<description>French</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:fr:bepo:fra</name>
--			<language>fra</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>fr</layout>
--			<layout_variant>bepo</layout_variant>
--			<longname>French (Bepo, ergonomic, Dvorak way)</longname>
--			<description>French (Bepo, ergonomic, Dvorak way)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>1</rank>
--		</engine>
--		<engine>
--			<name>xkb:fr:dvorak:fra</name>
--			<language>fra</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>fr</layout>
--			<layout_variant>dvorak</layout_variant>
--			<longname>French (Dvorak)</longname>
--			<description>French (Dvorak)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:de::ger</name>
--			<language>ger</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>de</layout>
--			<longname>German</longname>
--			<description>German</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:de:dvorak:ger</name>
--			<language>ger</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>de</layout>
--			<layout_variant>dvorak</layout_variant>
--			<longname>German (Dvorak)</longname>
--			<description>German (Dvorak)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:de:neo:ger</name>
--			<language>ger</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>de</layout>
--			<layout_variant>neo</layout_variant>
--			<longname>German (Neo 2)</longname>
--			<description>German (Neo 2)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:gr::gre</name>
--			<language>gre</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>gr</layout>
--			<longname>Greek</longname>
--			<description>Greek</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:hu::hun</name>
--			<language>hun</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>hu</layout>
--			<longname>Hungarian</longname>
--			<description>Hungarian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:il::heb</name>
--			<language>heb</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>il</layout>
--			<longname>Hebrew</longname>
--			<description>Hebrew</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:it::ita</name>
--			<language>ita</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>it</layout>
--			<longname>Italian</longname>
--			<description>Italian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:jp::jpn</name>
--			<language>jpn</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>jp</layout>
--			<longname>Japanese</longname>
--			<description>Japanese</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:latam::spa</name>
--			<language>spa</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>latam</layout>
--			<longname>Spanish (Latin American)</longname>
--			<description>Spanish (Latin American)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:lt::lit</name>
--			<language>lit</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>lt</layout>
--			<longname>Lithuanian</longname>
--			<description>Lithuanian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:lv:apostrophe:lav</name>
--			<language>lav</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>lv</layout>
--			<layout_variant>apostrophe</layout_variant>
--			<longname>Latvian (apostrophe variant)</longname>
--			<description>Latvian (apostrophe variant)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:pl::pol</name>
--			<language>pol</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>pl</layout>
--			<longname>Polish</longname>
--			<description>Polish</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:pl:dvorak:pol</name>
--			<language>pol</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>pl</layout>
--			<layout_variant>dvorak</layout_variant>
--			<longname>Polish (Dvorak)</longname>
--			<description>Polish (Dvorak)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:pt::por</name>
--			<language>por</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>pt</layout>
--			<longname>Portuguese</longname>
--			<description>Portuguese</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:ro::rum</name>
--			<language>rum</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>ro</layout>
--			<longname>Romanian</longname>
--			<description>Romanian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:ru::rus</name>
--			<language>rus</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>ru</layout>
--			<longname>Russian</longname>
--			<description>Russian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:ru:phonetic:rus</name>
--			<language>rus</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>ru</layout>
--			<layout_variant>phonetic</layout_variant>
--			<longname>Russian (phonetic)</longname>
--			<description>Russian (phonetic)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:rs::srp</name>
--			<language>srp</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>rs</layout>
--			<longname>Serbian</longname>
--			<description>Serbian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:si::slv</name>
--			<language>slv</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>si</layout>
--			<longname>Slovenian</longname>
--			<description>Slovenian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:sk::slo</name>
--			<language>slo</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>sk</layout>
--			<longname>Slovak</longname>
--			<description>Slovak</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:es::spa</name>
--			<language>spa</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>es</layout>
--			<longname>Spanish</longname>
--			<description>Spanish</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:es:cat:cat</name>
--			<language>cat</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>es</layout>
--			<layout_variant>cat</layout_variant>
--			<longname>Catalan (Spain, with middle-dot L)</longname>
--			<description>Catalan (Spain, with middle-dot L)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:se::swe</name>
--			<language>swe</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>se</layout>
--			<longname>Swedish</longname>
--			<description>Swedish</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:se:dvorak:swe</name>
--			<language>swe</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>se</layout>
--			<layout_variant>dvorak</layout_variant>
--			<longname>Swedish (Dvorak)</longname>
--			<description>Swedish (Dvorak)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:ch::ger</name>
--			<language>ger</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>ch</layout>
--			<longname>German (Switzerland)</longname>
--			<description>German (Switzerland)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:ch:fr:fra</name>
--			<language>fra</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>ch</layout>
--			<layout_variant>fr</layout_variant>
--			<longname>French (Switzerland)</longname>
--			<description>French (Switzerland)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:tr::tur</name>
--			<language>tur</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>tr</layout>
--			<longname>Turkish</longname>
--			<description>Turkish</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:ua::ukr</name>
--			<language>ukr</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>ua</layout>
--			<longname>Ukrainian</longname>
--			<description>Ukrainian</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:gb:extd:eng</name>
--			<language>eng</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>gb</layout>
--			<layout_variant>extd</layout_variant>
--			<longname>English (UK, extended WinKeys)</longname>
--			<description>English (UK, extended WinKeys)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:gb:dvorak:eng</name>
--			<language>eng</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>gb</layout>
--			<layout_variant>dvorak</layout_variant>
--			<longname>English (UK, Dvorak)</longname>
--			<description>English (UK, Dvorak)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--		<engine>
--			<name>xkb:kr:kr104:kor</name>
--			<language>kor</language>
--			<license>GPL</license>
--			<author>Peng Huang <shawn.p.huang at gmail.com></author>
--			<layout>kr</layout>
--			<layout_variant>kr104</layout_variant>
--			<longname>Korean (101/104 key compatible)</longname>
--			<description>Korean (101/104 key compatible)</description>
--                        <icon>ibus-keyboard</icon>
--			<rank>99</rank>
--		</engine>
--	</engines>
-+        <engines exec=\"${libexecdir}/ibus-engine-simple --xml\" />
- </component>
-diff --git a/ibus-1.0.pc.in b/ibus-1.0.pc.in
-index 9f593ab..66b902a 100644
---- a/ibus-1.0.pc.in
-+++ b/ibus-1.0.pc.in
-@@ -1,9 +1,13 @@
- prefix=@prefix@
- exec_prefix=@exec_prefix@
- libdir=@libdir@
-+libexecdir=@libexecdir@
- includedir=@includedir@
- datadir=@datadir@
- pkgdatadir=@datadir@/ibus
-+have_ibus_xkb=@HAVE_IBUS_XKB@
-+ibus_xkb=${libexecdir}/ibus-xkb
-+have_ibus_gkbd=@HAVE_IBUS_GKBD@
- 
- Name: IBus
- Description: IBus Library
-diff --git a/ibus.spec.in b/ibus.spec.in
-index 58cac38..4b6f869 100644
---- a/ibus.spec.in
-+++ b/ibus.spec.in
-@@ -4,6 +4,7 @@
- 
- # Build flags
- %define build_python_library 0
-+%define build_xkb 0
- 
- %define glib_ver %([ -a %{_libdir}/pkgconfig/glib-2.0.pc ] && pkg-config --modversion glib-2.0 | cut -d. -f 1,2 || echo -n "999")
- %define gconf2_version 2.12.0
-@@ -38,6 +39,10 @@ BuildRequires:  GConf2-devel
- BuildRequires:  pygobject2-devel
- BuildRequires:  intltool
- BuildRequires:  iso-codes-devel
-+%if %{build_xkb}
-+BuildRequires:  libxkbfile-devel
-+BuildRequires:  libgnomekbd-devel
-+%endif
- 
- Requires:   %{name}-libs = %{version}-%{release}
- Requires:   %{name}-gtk2 = %{version}-%{release}
-@@ -51,6 +56,9 @@ Requires:   im-chooser >= %{im_chooser_version}
- Requires:   GConf2 >= %{gconf2_version}
- Requires:   notify-python
- Requires:   librsvg2
-+%if %{build_xkb}
-+Requires:   libgnomekbd
-+%endif
- 
- Requires(post):  desktop-file-utils
- Requires(postun):  desktop-file-utils
-@@ -132,6 +140,10 @@ OPTIONS="$OPTIONS --enable-python-library"
- OPTIONS="$OPTIONS --disable-python-library"
- %endif
- 
-+%if %{build_xkb}
-+OPTIONS="$OPTIONS --enable-xkb --enable-libgnomekbd"
-+%endif
-+
- %configure $OPTIONS
- 
- # make -C po update-gmo
-diff --git a/setup/main.py b/setup/main.py
-index f527da1..c02229b 100644
---- a/setup/main.py
-+++ b/setup/main.py
-@@ -67,6 +67,13 @@ class Setup(object):
-     def __init__(self):
-         super(Setup, self).__init__()
- 
-+        # In the latest pygobject3 3.3.4 or later, g_variant_dup_strv
-+        # returns the allocated strv but in the previous release,
-+        # it returned the tuple of (strv, length)
-+        self.__tuple_for_variant_strv = False
-+        if type(GLib.Variant.new_strv([]).dup_strv()) == tuple:
-+            self.__tuple_for_variant_strv = True
-+
-         # IBus.Bus() calls ibus_bus_new().
-         # Gtk.Builder().add_from_file() also calls ibus_bus_new_async()
-         # via ibus_im_context_new().
-@@ -191,14 +198,22 @@ class Setup(object):
- 
-         # init engine page
-         self.__engines = self.__bus.list_engines()
-+        value = self.__config.get_value("general", "load_xkb_layouts")
-+        load_layouts = []
-+        if value != None:
-+            load_layouts = self.__variant_dup_strv(value)
-+        engines = []
-+        for engine in self.__engines:
-+            if not engine.get_name().startswith('xkb:'):
-+                engines.append(engine)
-+            elif engine.get_layout() in load_layouts:
-+                engines.append(engine)
-+
-         self.__combobox = self.__builder.get_object("combobox_engines")
--        self.__combobox.set_engines(self.__engines)
-+        self.__combobox.set_engines(engines)
- 
--        tmp_dict = {}
--        for e in self.__engines:
--            tmp_dict[e.get_name()] = e
-         engine_names = values.get("preload_engines", [])
--        engines = [tmp_dict[name] for name in engine_names if name in tmp_dict]
-+        engines = self.__get_engine_descs_from_names(engine_names)
- 
-         self.__treeview = self.__builder.get_object("treeview_engines")
-         self.__treeview.set_engines(engines)
-@@ -247,6 +262,12 @@ class Setup(object):
-         self.__init_panel()
-         self.__init_general()
- 
-+    def __variant_dup_strv(self, variant):
-+        if self.__tuple_for_variant_strv:
-+            return variant.dup_strv()[0]
-+        else:
-+            return variant.dup_strv()
-+
-     def __combobox_notify_active_engine_cb(self, combobox, property):
-         engine = self.__combobox.get_active_engine()
-         button = self.__builder.get_object("button_engine_add")
-@@ -271,6 +292,13 @@ class Setup(object):
-             args.append(path.basename(setup_path))
-         return args
- 
-+    def __get_engine_descs_from_names(self, engine_names):
-+        tmp_dict = {}
-+        for e in self.__engines:
-+            tmp_dict[e.get_name()] = e
-+        engines = [tmp_dict[name] for name in engine_names if name in tmp_dict]
-+        return engines
-+
-     def __treeview_notify_cb(self, treeview, prop):
-         if prop.name not in ("active-engine", "engines"):
-             return
-diff --git a/src/Makefile.am b/src/Makefile.am
-index df4ada3..f8499a8 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -97,6 +97,9 @@
-     ibusutil.c              \
-     ibusenginesimple.c      \
-     $(NULL)
-+if ENABLE_IBUS_XKB
-+ibus_sources += ibusxkbxml.c
-+endif
- libibus_1_0_la_SOURCES =    \
-     ibusmarshalers.c        \
-     ibusenumtypes.c         \
-@@ -145,6 +148,9 @@
-     ibusutil.h              \
-     ibusenginesimple.h      \
-     $(NULL)
-+if ENABLE_IBUS_XKB
-+ibus_headers += ibusxkbxml.h
-+endif
- ibusincludedir = $(includedir)/ibus- at IBUS_API_VERSION@
- ibus_public_headers =       \
-     $(ibus_headers)         \
-diff --git a/src/ibus.h b/src/ibus.h
-index ef811a4..f82a162 100644
---- a/src/ibus.h
-+++ b/src/ibus.h
-@@ -47,6 +47,7 @@
- #include <ibuskeys.h>
- #include <ibusenumtypes.h>
- #include <ibushotkey.h>
-+#include <ibusxkbxml.h>
- #include <ibusxml.h>
- #include <ibusenginedesc.h>
- #include <ibusobservedpath.h>
-diff --git a/src/ibusxkbxml.c b/src/ibusxkbxml.c
-new file mode 100644
-index 0000000..4792664
---- /dev/null
-+++ b/src/ibusxkbxml.c
-@@ -0,0 +1,466 @@
-+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
-+/* vim:set et sts=4: */
-+/* bus - The Input Bus
-+ * Copyright (C) 2012 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+ * Copyright (C) 2012 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright (C) 2012 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 <glib.h>
-+
-+#include "ibus.h"
-+#include "ibusxkbxml.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))
-+
-+typedef struct _IBusXKBConfigRegistryPrivate IBusXKBConfigRegistryPrivate;
-+
-+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;
-+    }
-+    variant_lang_name = g_strdup_printf ("%s(%s)", layout_name, name);
-+    g_hash_table_insert (priv->variant_desc,
-+                         (gpointer) variant_lang_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
-+
-+GList *
-+ibus_xkb_config_registry_layout_list_get_layouts (IBusXKBConfigRegistry *xkb_config)
-+{
-+    GHashTable *table;
-+    GList *list = NULL;
-+
-+    table = (GHashTable *)
-+        ibus_xkb_config_registry_get_layout_list (xkb_config);
-+    list = (GList *) g_hash_table_get_keys (table);
-+    return list;
-+}
-+
-+/* vala could use GLib.List<string> for the returned pointer and
-+ * the declaration calls g_list_foreach (retval, g_free, NULL).
-+ * When I think about GLib.List<string> v.s. GLib.List, probably
-+ * I think GLib.List<string> is better for the function and set
-+ * g_strdup() here. I do not know about GJS implementation.
-+ */
-+#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;                                                 \
-+    GList *retval= NULL;                                                \
-+    GList *p = NULL;                                                    \
-+                                                                        \
-+    table = (GHashTable *)                                              \
-+        ibus_xkb_config_registry_get_##field_name (xkb_config);         \
-+    list = (GList *) g_hash_table_lookup (table, key);                  \
-+    retval = g_list_copy (list);                                        \
-+    for (p = retval; p; p = p->next) {                                  \
-+        p->data = g_strdup (p->data);                                   \
-+    }                                                                   \
-+    return retval;                                                      \
-+}
-+
-+#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..6f5b7bd
---- /dev/null
-+++ b/src/ibusxkbxml.h
-@@ -0,0 +1,187 @@
-+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
-+/* vim:set et sts=4: */
-+/* bus - The Input Bus
-+ * Copyright (C) 2012 Takao Fujiwara <takao.fujiwara1 at gmail.com>
-+ * Copyright (C) 2012 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright (C) 2012 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_
-+
-+#if !defined (__IBUS_H_INSIDE__) && !defined (IBUS_COMPILATION)
-+#error "Only <ibus.h> can be included directly"
-+#endif
-+
-+#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_layouts:
-+ * @xkb_config: An IBusXKBConfigRegistry.
-+ * @returns: (transfer container) (element-type utf8): A GList of layouts
-+ *
-+ * a GList of layouts
-+ */
-+GList *
-+                 ibus_xkb_config_registry_layout_list_get_layouts
-+                                                 (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/gtk3/Makefile.am b/ui/gtk3/Makefile.am
-index 5473027..6cb02a1 100644
---- a/ui/gtk3/Makefile.am
-+++ b/ui/gtk3/Makefile.am
-@@ -45,6 +45,8 @@
- # force include config.h before gi18n.h.
- AM_CPPFLAGS = -include $(CONFIG_HEADER)
- 
-+HAVE_IBUS_GKBD_C = $(strip $(subst false, FALSE, $(subst true, TRUE, $(HAVE_IBUS_GKBD))))
-+
- AM_CFLAGS = \
- 	@GLIB2_CFLAGS@ \
- 	@GIO2_CFLAGS@ \
-@@ -56,6 +58,9 @@
- 	-DBINDIR=\"$(bindir)\" \
- 	-DIBUS_DISABLE_DEPRECATED \
- 	-DSWITCHER_USE_SYMBOL_ICON=$(USE_SYMBOL_ICON) \
-+	-DHAVE_IBUS_GKBD=$(HAVE_IBUS_GKBD_C) \
-+	-DIBUS_XKB_COMMAND=\"$(libexecdir)/ibus-xkb\" \
-+	-DXKB_LAYOUTS_MAX_LENGTH=4 \
- 	-Wno-unused-variable \
- 	-Wno-unused-but-set-variable \
- 	-Wno-unused-function \
-@@ -89,6 +94,7 @@
- 	application.vala \
- 	candidatearea.vala \
- 	candidatepanel.vala \
-+	gkbdlayout.vala \
- 	handle.vala \
- 	iconwidget.vala \
- 	keybindingmanager.vala \
-@@ -97,17 +103,48 @@
- 	property.vala \
- 	separator.vala \
- 	switcher.vala \
-+	xkblayout.vala \
- 	$(NULL)
- 
- ibus_ui_gtk3_LDADD = \
- 	$(AM_LDADD) \
- 	$(NULL)
- 
-+if ENABLE_LIBGNOMEKBD
-+AM_CFLAGS += \
-+	@LIBGNOMEKBDUI_CFLAGS@ \
-+	@ATK_CFLAGS@ \
-+	$(NULL)
-+
-+AM_LDADD += \
-+	@LIBGNOMEKBDUI_LIBS@ \
-+	@ATK_LIBS@ \
-+	$(NULL)
-+
-+AM_VALAFLAGS += \
-+	--vapidir=. \
-+	--metadatadir=$(top_srcdir)/bindings/vala \
-+	--pkg=glib-2.0 \
-+	--pkg=gmodule-2.0 \
-+	--pkg=gkbd \
-+	--pkg=Xkl-1.0 \
-+	$(NULL)
-+
-+$(srcdir)/gkbdlayout.vala: $(top_builddir)/bindings/vala/gkbd.vapi
-+	@cp $(srcdir)/gkbdlayout.vala.true $(srcdir)/gkbdlayout.vala
-+else
-+$(srcdir)/gkbdlayout.vala:
-+	@cp $(srcdir)/gkbdlayout.vala.false $(srcdir)/gkbdlayout.vala
-+endif
-+
- CLEANFILES = \
-+	gkbdlayout.vala \
- 	gtkpanel.xml \
- 	$(NULL)
- 
- EXTRA_DIST = \
-+	gkbdlayout.vala.false \
-+	gkbdlayout.vala.true \
- 	gtkpanel.xml.in \
- 	$(NULL)
- 
-diff --git a/ui/gtk3/gkbdlayout.vala.false b/ui/gtk3/gkbdlayout.vala.false
-new file mode 100644
-index 0000000..a387de9
---- /dev/null
-+++ b/ui/gtk3/gkbdlayout.vala.false
-@@ -0,0 +1,63 @@
-+/* vim:set et sts=4 sw=4:
-+ *
-+ * ibus - The Input Bus
-+ *
-+ * Copyright 2012 Red Hat, Inc.
-+ * Copyright(c) 2012 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright(c) 2012 Takao Fujiwara <tfujiwar at redhat.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
-+ */
-+
-+public class GkbdLayout
-+{
-+    public signal void changed();
-+    public signal void group_changed (int object);
-+
-+    public GkbdLayout() {
-+    }
-+
-+    public string[] get_layouts() {
-+        return new string[0];
-+    }
-+
-+    public string[] get_group_names() {
-+        return new string[0];
-+    }
-+
-+    public void lock_group(int id) {
-+    }
-+
-+    public void start_listen() {
-+    }
-+
-+    public void stop_listen() {
-+    }
-+
-+    /*
-+    public static int main(string[] args) {
-+        GkbdLayout ibus_layouts = new GkbdLayout();
-+
-+        string[] layouts = ibus_layouts.get_layouts();
-+        string[] names = ibus_layouts.get_group_names();
-+        for (int i = 0; layouts != null && i < layouts.length; i++) {
-+            stdout.printf("%s %s\n", layouts[i], names[i]);
-+        }
-+
-+        return 0;
-+    }
-+    */
-+}
-diff --git a/ui/gtk3/gkbdlayout.vala.true b/ui/gtk3/gkbdlayout.vala.true
-new file mode 100644
-index 0000000..2b78c69
---- /dev/null
-+++ b/ui/gtk3/gkbdlayout.vala.true
-@@ -0,0 +1,108 @@
-+/* vim:set et sts=4 sw=4:
-+ *
-+ * ibus - The Input Bus
-+ *
-+ * Copyright 2012 Red Hat, Inc.
-+ * Copyright(c) 2012 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright(c) 2012 Takao Fujiwara <tfujiwar at redhat.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
-+ */
-+
-+public class GkbdLayout
-+{
-+    public signal void changed();
-+    public signal void group_changed (int object);
-+
-+    private Gkbd.Configuration m_config = null;
-+
-+    public GkbdLayout() {
-+        m_config = Gkbd.Configuration.get();
-+        if (m_config != null) {
-+            m_config.changed.connect(config_changed_cb);
-+            m_config.group_changed.connect(config_group_changed_cb);
-+        }
-+    }
-+
-+    ~GkbdLayout() {
-+        if (m_config != null) {
-+            m_config.changed.disconnect(config_changed_cb);
-+            m_config.group_changed.disconnect(config_group_changed_cb);
-+            /* gkbd_configuration_get reuses the object and do not
-+             * destroy m_config here. */
-+            m_config.ref();
-+            m_config = null;
-+        }
-+    }
-+
-+    private void config_changed_cb() {
-+        changed();
-+    }
-+
-+    private void config_group_changed_cb(int object) {
-+        group_changed(object);
-+    }
-+
-+    public string[] get_layouts() {
-+        if (m_config == null) {
-+            return new string[0];
-+        }
-+        return m_config.get_short_group_names();
-+    }
-+
-+    public string[] get_group_names() {
-+        if (m_config == null) {
-+            return new string[0];
-+        }
-+        return m_config.get_group_names();
-+    }
-+
-+    public void lock_group(int id) {
-+        if (m_config == null) {
-+            return;
-+        }
-+        m_config.lock_group(id);
-+    }
-+
-+    public void start_listen() {
-+        if (m_config == null) {
-+            return;
-+        }
-+        m_config.start_listen();
-+    }
-+
-+    public void stop_listen() {
-+        if (m_config == null) {
-+            return;
-+        }
-+        m_config.stop_listen();
-+    }
-+
-+    /*
-+    public static int main(string[] args) {
-+        Gtk.init(ref args);
-+        GkbdLayout ibus_layouts = new GkbdLayout();
-+
-+        string[] layouts = ibus_layouts.get_layouts();
-+        string[] names = ibus_layouts.get_group_names();
-+        for (int i = 0; layouts != null && i < layouts.length; i++) {
-+            stdout.printf("%s %s\n", layouts[i], names[i]);
-+        }
-+
-+        return 0;
-+    }
-+    */
-+}
-diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala
-index c159693..63b0cde 100644
---- a/ui/gtk3/panel.vala
-+++ b/ui/gtk3/panel.vala
-@@ -48,8 +48,16 @@
-     private Gtk.AboutDialog m_about_dialog;
-     private Gtk.CssProvider m_css_provider;
-     private int m_switcher_delay_time = 400;
-+    private GkbdLayout m_gkbdlayout = null;
-+    private XKBLayout m_xkblayout = null;
-+    private string[] m_layouts = {};
-+    private string[] m_variants = {};
-+    private int m_fallback_lock_id = -1;
-+    private bool m_changed_xkb_option = false;
-+    private GLib.Timer m_changed_layout_timer;
-     private bool m_use_system_keyboard_layout = false;
-     private const string ACCELERATOR_SWITCH_IME_FOREWARD = "<Control>space";
-+    private const string ACCELERATOR_SWITCH_IME_BACKWARD = "<Control><Shift>space";
- 
-     private GLib.List<Keybinding> m_keybindings = new GLib.List<Keybinding>();
- 
-@@ -91,6 +99,14 @@
- 
-     ~Panel() {
-         unbind_switch_shortcut();
-+
-+        if (HAVE_IBUS_GKBD && m_gkbdlayout != null) {
-+            m_gkbdlayout.changed.disconnect(gkbdlayout_changed_cb);
-+            m_gkbdlayout.stop_listen();
-+            m_gkbdlayout = null;
-+        }
-+
-+        m_xkblayout = null;
-     }
- 
-     private void keybinding_manager_bind(KeybindingManager keybinding_manager,
-@@ -153,6 +169,12 @@
-     }
- 
-     private void bind_switch_shortcut(Variant? variant) {
-+        string locale = GLib.Intl.setlocale(GLib.LocaleCategory.ALL,
-+                                            null);
-+        if (locale == null) {
-+            locale = "C";
-+        }
-+
-         string[] accelerators = {};
-         Variant var_trigger = variant;
- 
-@@ -167,6 +189,20 @@
-             accelerators += ACCELERATOR_SWITCH_IME_FOREWARD;
-         }
- 
-+        if (accelerators.length == 1 &&
-+            accelerators[0] == ACCELERATOR_SWITCH_IME_FOREWARD) {
-+            // FIXME: When us keyboard is used, Zenkaku_Hankaku does not work.
-+            /*
-+            if (locale[0:2] == "ja") {
-+                accelerators += "Zenkaku_Hankaku";
-+            }
-+            */
-+            if (locale[0:2] == "ko") {
-+                accelerators += "Hangul";
-+                accelerators += "Alt_R";
-+            }
-+        }
-+
-         var keybinding_manager = KeybindingManager.get_instance();
- 
-         foreach (var accelerator in accelerators) {
-@@ -299,6 +335,7 @@
-             m_config.watch("general/hotkey", "triggers");
-             m_config.watch("panel", "custom_font");
-             m_config.watch("panel", "use_custom_font");
-+            init_engines_order();
-             // Update m_use_system_keyboard_layout before update_engines()
-             // is called.
-             set_use_system_keyboard_layout(null);
-@@ -359,6 +396,200 @@
-         }
-     }
- 
-+    private void gkbdlayout_changed_cb() {
-+        /* The callback is called four times after set_layout is called
-+         * so check the elapsed and take the first signal only. */
-+        double elapsed = m_changed_layout_timer.elapsed();
-+        if (elapsed < 1.0 && elapsed > 0.0) {
-+            return;
-+        }
-+
-+        if (m_fallback_lock_id != -1) {
-+            /* Call lock_group only when set_layout is called. */
-+            m_gkbdlayout.lock_group(m_fallback_lock_id);
-+            m_fallback_lock_id = -1;
-+        } else {
-+            /* Reset default layout when gnome-control-center is called. */
-+            m_xkblayout.reset_layout();
-+        }
-+
-+        update_xkb_engines();
-+        m_changed_layout_timer.reset();
-+    }
-+
-+    private void init_gkbd() {
-+        m_gkbdlayout = new GkbdLayout();
-+        m_gkbdlayout.changed.connect(gkbdlayout_changed_cb);
-+
-+        /* Probably we cannot support both keyboard and ibus indicators
-+         * How can I get the engine from keymap of group_id?
-+         * e.g. 'en' could be owned by xkb:en and pinyin engines. */
-+        //m_gkbdlayout.group_changed.connect((object) => {});
-+
-+        m_changed_layout_timer = new GLib.Timer();
-+        m_changed_layout_timer.start();
-+        m_gkbdlayout.start_listen();
-+    }
-+
-+    private void init_engines_order() {
-+        if (m_config == null) {
-+            return;
-+        }
-+
-+        m_xkblayout = new XKBLayout(m_config);
-+        string session = Environment.get_variable("DESKTOP_SESSION");
-+
-+        if (HAVE_IBUS_GKBD &&
-+            session != null && session.length >= 5 &&
-+            session[0:5] == "gnome") {
-+            init_gkbd();
-+        }
-+
-+        update_xkb_engines();
-+    }
-+
-+    private void update_xkb_engines() {
-+        string var_layout = m_xkblayout.get_layout();
-+        string var_variant = m_xkblayout.get_variant();
-+        if (var_layout == "") {
-+            return;
-+        }
-+
-+        m_layouts = var_layout.split(",");
-+        m_variants = var_variant.split(",");
-+
-+        IBus.XKBConfigRegistry registry = new IBus.XKBConfigRegistry();
-+        string[] var_xkb_engine_names = {};
-+        for (int i = 0; i < m_layouts.length; i++) {
-+            string name = m_layouts[i];
-+            string lang = null;
-+
-+            if (i < m_variants.length && m_variants[i] != "") {
-+                name = "%s:%s".printf(name, m_variants[i]);
-+                string layout = "%s(%s)".printf(name, m_variants[i]);
-+                GLib.List<string> langs =
-+                        registry.layout_lang_get_langs(layout);
-+                if (langs.length() != 0) {
-+                    lang = langs.data;
-+                }
-+            } else {
-+                name = "%s:".printf(name);
-+            }
-+
-+            if (lang == null) {
-+                GLib.List<string> langs =
-+                        registry.layout_lang_get_langs(m_layouts[i]);
-+                if (langs.length() != 0) {
-+                    lang = langs.data;
-+                }
-+            }
-+
-+            var_xkb_engine_names += "%s:%s:%s".printf("xkb", name, lang);
-+        }
-+
-+        GLib.Variant var_engines = 
-+           m_config.get_value("general", "preload_engines");
-+        string[] engine_names = {};
-+        bool updated_engine_names = false;
-+
-+        if (var_engines != null) {
-+            engine_names = var_engines.dup_strv();
-+        }
-+
-+        foreach (string name in var_xkb_engine_names) {
-+            if (name in engine_names)
-+                continue;
-+            updated_engine_names = true;
-+            engine_names += name;
-+        }
-+
-+        if (updated_engine_names) {
-+            m_config.set_value("general",
-+                               "preload_engines",
-+                               new GLib.Variant.strv(engine_names));
-+        }
-+
-+        GLib.Variant var_order =
-+            m_config.get_value("general", "engines_order");
-+        string[] order_names = {};
-+        bool updated_order_names = false;
-+
-+        if (var_order != null) {
-+            order_names = var_order.dup_strv();
-+        }
-+
-+        foreach (var name in var_xkb_engine_names) {
-+            if (name in order_names)
-+                continue;
-+            order_names += name;
-+            updated_order_names = true;
-+        }
-+
-+        if (updated_order_names) {
-+            m_config.set_value("general",
-+                               "engines_order",
-+                               new GLib.Variant.strv(order_names));
-+        }
-+    }
-+
-+    private void set_xkb_group_layout(string layout) {
-+        int[] retval = m_xkblayout.set_layout(layout,
-+                                              "default",
-+                                              "default",
-+                                              true);
-+        if (retval[0] >= 0) {
-+            /* If an XKB keymap is added into the XKB group,
-+             * this._gkbdlayout.lock_group will be called after
-+             * 'group-changed' signal is received. */
-+            m_fallback_lock_id = retval[0];
-+            m_changed_xkb_option = (retval[1] != 0) ? true : false;
-+        }
-+    }
-+
-+    private bool set_gkbd_layout(string layout) {
-+        /* If a previous ibus engine changed XKB options, need to set the
-+         * default XKB option. */
-+        if (m_changed_xkb_option == true) {
-+            m_changed_xkb_option = false;
-+            return false;
-+        }
-+
-+        int gkbd_len = m_gkbdlayout.get_group_names().length;
-+        for (int i = 0; i < m_layouts.length && i < gkbd_len; i++) {
-+            string sys_layout = m_layouts[i];
-+            if (i < m_variants.length && m_variants[i] != "") {
-+                sys_layout = "%s(%s)".printf(sys_layout, m_variants[i]);
-+            }
-+            if (sys_layout == layout) {
-+                m_gkbdlayout.lock_group(i);
-+                return true;
-+            }
-+        }
-+        return false;
-+    }
-+
-+    private void set_layout(IBus.EngineDesc engine) {
-+        string layout = engine.get_layout();
-+
-+        if (layout == "default" || layout == null) {
-+            return;
-+        }
-+
-+        if (m_xkblayout == null) {
-+            init_engines_order();
-+        }
-+
-+        if (HAVE_IBUS_GKBD && m_gkbdlayout != null) {
-+            if (set_gkbd_layout(layout)) {
-+                return;
-+            }
-+            set_xkb_group_layout(layout);
-+            return;
-+        }
-+
-+        m_xkblayout.set_layout(layout);
-+    }
-+
-     private void switch_engine(int i, bool force = false) {
-         GLib.assert(i >= 0 && i < m_engines.length);
- 
-@@ -374,7 +605,7 @@
-         }
-         // set xkb layout
-         if (!m_use_system_keyboard_layout) {
--            exec_setxkbmap(engine);
-+            set_layout(engine);
-         }
-     }
- 
-@@ -391,6 +622,12 @@
-             unbind_switch_shortcut();
-             bind_switch_shortcut(variant);
-             return;
-+        }
-+
-+        if (section == "general/hotkey" && name == "trigger_accel") {
-+            unbind_switch_shortcut();
-+            bind_switch_shortcut(variant);
-+            return;
-         }
- 
-         if (section == "panel" && (name == "custom_font" ||
-diff --git a/ui/gtk3/xkblayout.vala b/ui/gtk3/xkblayout.vala
-new file mode 100644
-index 0000000..2092a60
---- /dev/null
-+++ b/ui/gtk3/xkblayout.vala
-@@ -0,0 +1,465 @@
-+/* vim:set et sts=4 sw=4:
-+ *
-+ * ibus - The Input Bus
-+ *
-+ * Copyright 2012 Red Hat, Inc.
-+ * Copyright(c) 2012 Peng Huang <shawn.p.huang at gmail.com>
-+ * Copyright(c) 2012 Takao Fujiwara <tfujiwar at redhat.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
-+ */
-+
-+public extern const bool HAVE_IBUS_GKBD;
-+public extern const bool HAVE_IBUS_XKB;
-+public extern const int XKB_LAYOUTS_MAX_LENGTH;
-+public extern const string IBUS_XKB_COMMAND;
-+
-+class XKBLayout
-+{
-+    string m_xkb_command = IBUS_XKB_COMMAND;
-+    IBus.Config m_config = null;
-+    string[] m_xkb_latin_layouts = {};
-+    GLib.Pid m_xkb_pid = -1;
-+    GLib.Pid m_xmodmap_pid = -1;
-+    string m_xmodmap_command = "xmodmap";
-+    bool m_use_xmodmap = true;
-+    string[] m_xmodmap_known_files = {".xmodmap", ".xmodmaprc",
-+                                      ".Xmodmap", ".Xmodmaprc"};
-+    string m_default_layout = "";
-+    string m_default_variant = "";
-+    string m_default_option = "";
-+
-+    public XKBLayout(IBus.Config? config) {
-+        if (!HAVE_IBUS_XKB) {
-+            m_xkb_command = "setxkbmap";
-+        }
-+
-+        m_config = config;
-+
-+        if (config != null) {
-+            var value  = config.get_value("general", "xkb_latin_layouts");
-+            for (int i = 0; value != null && i < value.n_children(); i++) {
-+                m_xkb_latin_layouts +=
-+                        value.get_child_value(i).dup_string();
-+            }
-+            if (m_use_xmodmap) {
-+                m_use_xmodmap = config.get_value("general", "use_xmodmap").get_boolean();
-+            }
-+        }
-+    }
-+
-+    private string get_output_from_cmdline(string arg, string element) {
-+        string[] exec_command = {};
-+        exec_command += m_xkb_command;
-+        exec_command += arg;
-+        string standard_output = null;
-+        string standard_error = null;
-+        int exit_status = 0;
-+        string retval = "";
-+        try {
-+            GLib.Process.spawn_sync(null,
-+                                    exec_command,
-+                                    null,
-+                                    GLib.SpawnFlags.SEARCH_PATH,
-+                                    null,
-+                                    out standard_output,
-+                                    out standard_error,
-+                                    out exit_status);
-+        } catch (GLib.SpawnError err) {
-+            stderr.printf("IBUS_ERROR: %s\n", err.message);
-+        }
-+        if (exit_status != 0) {
-+            stderr.printf("IBUS_ERROR: %s\n", standard_error ?? "");
-+        }
-+        if (standard_output == null) {
-+            return "";
-+        }
-+        foreach (string line in standard_output.split("\n")) {
-+            if (element.length <= line.length &&
-+                line[0:element.length] == element) {
-+                retval = line[element.length:line.length];
-+            }
-+        }
-+        return retval;
-+    }
-+
-+    private void set_layout_cb(GLib.Pid pid, int status) {
-+        if (m_xkb_pid != pid) {
-+            stderr.printf("IBUS_ERROR: set_layout_cb has another pid\n");
-+            return;
-+        }
-+        GLib.Process.close_pid(m_xkb_pid);
-+        m_xkb_pid = -1;
-+        set_xmodmap();
-+    }
-+
-+    private void set_xmodmap_cb(GLib.Pid pid, int status) {
-+        if (m_xmodmap_pid != pid) {
-+            stderr.printf("IBUS_ERROR: set_xmodmap_cb has another pid\n");
-+            return;
-+        }
-+        GLib.Process.close_pid(m_xmodmap_pid);
-+        m_xmodmap_pid = -1;
-+    }
-+
-+    private string get_fullpath(string command) {
-+        string envpath = GLib.Environment.get_variable("PATH");
-+        foreach (string dir in envpath.split(":")) {
-+            string filepath = GLib.Path.build_filename(dir, command);
-+            if (GLib.FileUtils.test(filepath, GLib.FileTest.EXISTS)) {
-+                return filepath;
-+            }
-+        }
-+        return "";
-+    }
-+
-+    private string[] get_xkb_group_layout (string layout,
-+                                           string variant,
-+                                           int layouts_max_length) {
-+        int group_id = 0;
-+        int i = 0;
-+        string[] layouts = m_default_layout.split(",");
-+        string[] variants = m_default_variant.split(",");
-+        string group_layouts = "";
-+        string group_variants = "";
-+        bool has_variant = false;
-+        bool include_keymap = false;
-+
-+        for (i = 0; i < layouts.length; i++) {
-+            if (i >= layouts_max_length - 1) {
-+                break;
-+            }
-+
-+            if (i == 0) {
-+                group_layouts = layouts[i];
-+            } else {
-+                group_layouts = "%s,%s".printf(group_layouts, layouts[i]);
-+            }
-+
-+            if (i >= variants.length) {
-+                if (i == 0) {
-+                    group_variants = "";
-+                } else {
-+                    group_variants += ",";
-+                }
-+                if (layout == layouts[i] && variant == "") {
-+                    include_keymap = true;
-+                    group_id = i;
-+                }
-+                continue;
-+            }
-+            if (layout == layouts[i] && variant == variants[i]) {
-+                include_keymap = true;
-+                group_id = i;
-+            }
-+
-+            if (variants[i] != "") {
-+                has_variant = true;
-+            }
-+
-+            if (i == 0) {
-+                group_variants = variants[i];
-+            } else {
-+                group_variants = "%s,%s".printf(group_variants, variants[i]);
-+            }
-+        }
-+
-+        if (variant != "") {
-+            has_variant = true;
-+        }
-+
-+        if (!include_keymap) {
-+            group_layouts = "%s,%s".printf(group_layouts, layout);
-+            group_variants = "%s,%s".printf(group_variants, variant);
-+            group_id = i;
-+        }
-+
-+        if (!has_variant) {
-+            group_variants = null;
-+        }
-+
-+        return {group_layouts, group_variants, group_id.to_string()};
-+    }
-+
-+    public string[] get_variant_from_layout(string layout) {
-+        int left_bracket = layout.index_of("(");
-+        int right_bracket = layout.index_of(")");
-+        if (left_bracket >= 0 && right_bracket > left_bracket) {
-+            return {layout[0:left_bracket] +
-+                    layout[right_bracket + 1:layout.length],
-+                    layout[left_bracket + 1:right_bracket]};
-+        }
-+        return {layout, "default"};
-+    }
-+
-+    public string[] get_option_from_layout(string layout) {
-+        int left_bracket = layout.index_of("[");
-+        int right_bracket = layout.index_of("]");
-+        if (left_bracket >= 0 && right_bracket > left_bracket) {
-+            return {layout[0:left_bracket] +
-+                    layout[right_bracket + 1:layout.length],
-+                    layout[left_bracket + 1:right_bracket]};
-+        }
-+        return {layout, "default"};
-+    }
-+
-+    public string get_layout() {
-+        if (HAVE_IBUS_XKB) {
-+            return get_output_from_cmdline("--get", "layout: ");
-+        } else {
-+            return get_output_from_cmdline("-query", "layout: ");
-+        }
-+    }
-+
-+    public string get_variant() {
-+        if (HAVE_IBUS_XKB) {
-+            return get_output_from_cmdline("--get", "variant: ");
-+        } else {
-+            return get_output_from_cmdline("-query", "variant: ");
-+        }
-+    }
-+
-+    public string get_option() {
-+        if (HAVE_IBUS_XKB) {
-+            return get_output_from_cmdline("--get", "option: ");
-+        } else {
-+            return get_output_from_cmdline("-query", "options: ");
-+        }
-+    }
-+
-+    /*
-+    public string get_group() {
-+        return get_output_from_cmdline("--get-group", "group: ");
-+    }
-+    */
-+
-+    public int[] set_layout(string _layout="default",
-+                            string _variant="default",
-+                            string _option="default",
-+                            bool   use_group_layout=false) {
-+        assert (_layout != null);
-+
-+        int xkb_group_id = 0;
-+        int changed_option = 0;
-+
-+        if (m_xkb_pid != -1) {
-+            return {-1, 0};
-+        }
-+
-+        if (_layout == "default" && _variant == "default" &&
-+            _option == "default") {
-+            return {-1, 0};
-+        }
-+        // const gchar to gchar
-+        string layout = _layout;
-+        string variant = _variant;
-+        string option = _option;
-+
-+        if (variant == "default") {
-+            string[] array = get_variant_from_layout(layout);
-+            layout = array[0];
-+            variant = array[1];
-+        }
-+
-+        if (option == "default") {
-+            string[] array = get_option_from_layout(layout);
-+            layout = array[0];
-+            option = array[1];
-+        }
-+
-+        bool need_us_layout = false;
-+        foreach (string latin_layout in m_xkb_latin_layouts) {
-+            if (layout == latin_layout && variant != "eng") {
-+                need_us_layout = true;
-+                break;
-+            }
-+            if (variant != null &&
-+                "%s(%s)".printf(layout, variant) == latin_layout) {
-+                need_us_layout = true;
-+                break;
-+            }
-+        }
-+
-+        int layouts_max_length =  XKB_LAYOUTS_MAX_LENGTH;
-+        if (need_us_layout) {
-+            layouts_max_length--;
-+        }
-+
-+        if (m_default_layout == "") {
-+            m_default_layout = get_layout();
-+        }
-+        if (m_default_variant  == "") {
-+            m_default_variant  = get_variant();
-+        }
-+        if (m_default_option == "") {
-+            m_default_option = get_option();
-+        }
-+
-+        if (layout == "default") {
-+            layout = m_default_layout;
-+            variant = m_default_variant;
-+        } else {
-+            if (use_group_layout) {
-+                if (variant == "default") {
-+                    variant = "";
-+                }
-+                string[] retval = get_xkb_group_layout (layout, variant,
-+                                                        layouts_max_length);
-+                layout = retval[0];
-+                variant = retval[1];
-+                xkb_group_id = int.parse(retval[2]);
-+            }
-+        }
-+
-+        if (layout == "") {
-+            warning("Could not get the correct layout");
-+            return {-1, 0};
-+        }
-+
-+        if (variant == "default" || variant == "") {
-+            variant = null;
-+        }
-+
-+        if (option == "default" || option == "") {
-+            option = m_default_option;
-+        } else {
-+            if (!(option in m_default_option.split(","))) {
-+                option = "%s,%s".printf(m_default_option, option);
-+                changed_option = 1;
-+            } else {
-+                option = m_default_option;
-+            }
-+        }
-+
-+        if (option == "") {
-+            option = null;
-+        }
-+
-+        if (need_us_layout) {
-+            layout += ",us";
-+            if (variant != null) {
-+                variant += ",";
-+            }
-+        }
-+
-+        string[] args = {};
<Skipped 1369 lines>
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/ibus.git/commitdiff/4c73ba7f1e1d8f45cdea6d43cd629829083864c1




More information about the pld-cvs-commit mailing list