[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