Blob Blame History Raw
From a3819467deea74b82c55a4cfc8cecd6285f54e00 Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
Date: Mon, 23 Aug 2010 11:31:55 +0900
Subject: [PATCH] Add XKB layouts

---
 Makefile.am                |    7 +
 configure.ac               |   53 ++++
 data/ibus.schemas.in       |   24 ++
 ibus/Makefile.am           |   26 ++
 ibus/__init__.py           |    2 +
 ibus/bus.py                |    3 +
 ibus/interface/iibus.py    |    3 +
 ibus/xkblayout.py.in       |   86 ++++++
 ibus/xkbxml.py.in          |  337 +++++++++++++++++++++
 setup/main.py              |  228 ++++++++++++++-
 setup/setup.ui             |  300 +++++++++++++++++++-
 src/ibusfactory.c          |   17 +-
 src/ibusfactory.h          |    5 +-
 ui/gtk/panel.py            |   30 ++
 xkb/Makefile.am            |  104 +++++++
 xkb/ibus-engine-xkb-main.c |  396 +++++++++++++++++++++++++
 xkb/ibus-engine-xkb-main.h |   45 +++
 xkb/ibus-xkb-main.c        |   82 ++++++
 xkb/xkblayout.xml.in       |   16 +
 xkb/xkblayoutconfig.xml.in |    6 +
 xkb/xkblib.c               |  259 ++++++++++++++++
 xkb/xkblib.h               |   36 +++
 xkb/xkbxml.c               |  695 ++++++++++++++++++++++++++++++++++++++++++++
 xkb/xkbxml.h               |  188 ++++++++++++
 24 files changed, 2941 insertions(+), 7 deletions(-)
 create mode 100644 ibus/xkblayout.py.in
 create mode 100644 ibus/xkbxml.py.in
 create mode 100644 xkb/Makefile.am
 create mode 100644 xkb/ibus-engine-xkb-main.c
 create mode 100644 xkb/ibus-engine-xkb-main.h
 create mode 100644 xkb/ibus-xkb-main.c
 create mode 100644 xkb/xkblayout.xml.in
 create mode 100644 xkb/xkblayoutconfig.xml.in
 create mode 100644 xkb/xkblib.c
 create mode 100644 xkb/xkblib.h
 create mode 100644 xkb/xkbxml.c
 create mode 100644 xkb/xkbxml.h

diff --git a/Makefile.am b/Makefile.am
index 7895940..9f534a4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -39,6 +39,12 @@ MEMCONF_DIRS = \
 	$(NULL)
 endif
 
+if ENABLE_XKB
+XKB_DIRS = \
+	xkb \
+	$(NULL)
+endif
+
 SUBDIRS = \
 	src \
 	bus \
@@ -53,6 +59,7 @@ SUBDIRS = \
 	$(PYTHON_DIRS) \
 	$(GCONF_DIRS) \
 	$(MEMCONF_DIRS) \
+	$(XKB_DIRS) \
 	$(NULL)
 
 ACLOCAL_AMFLAGS = -I m4
diff --git a/configure.ac b/configure.ac
index 3346d0c..15788bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -168,6 +168,57 @@ else
     enable_xim="no (disabled, use --enable-xim to enable)"
 fi
 
+AC_ARG_ENABLE(xkb,
+    AS_HELP_STRING([--disable-xkb],
+                   [Do not build xkb]),
+    [enable_xkb=$enableval],
+    [enable_xkb=yes]
+)
+
+AM_CONDITIONAL([ENABLE_XKB], [test x"$enable_xkb" = x"yes"])
+if test x"$enable_xkb" = x"yes"; then
+    PKG_CHECK_MODULES(X11, [
+        x11
+    ])
+    PKG_CHECK_MODULES(XKB,
+        [xkbfile],,
+        [XKB_LIBS="-lxkbfile"]
+    )
+    AC_DEFINE(HAVE_XKB, 1, [define to 1 if you have xkbfile])
+else
+    enable_xkb="no (disabled, use --enable-xkb to enable)"
+fi
+
+# 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])
+AC_SUBST(XKB_RULES_XML_FILE)
+
+# define XKB preload layouts
+AC_ARG_WITH(xkb-preload-layouts,
+    AS_HELP_STRING([--with-xkb-preload-layouts[=layout,...]],
+        [Set preload xkb layouts (default: us,fr,de,...)]),
+    XKB_PRELOAD_LAYOUTS=$with_xkb_preload_layouts,
+    [XKB_PRELOAD_LAYOUTS=""\
+"us,us(chr),ad,al,am,ar,az,ba,bd,be,bg,br,bt,by,"\
+"de,dk,ca,ch,cn,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(ben),in(guj),in(guru),in(jhelum),in(kan),in(mal),in(ori),in(tam),"\
+"in(tel),in(urd-phonetic),in(bolnagri),iq,iq(ku),ir,ir(ku),is,it,jp,"\
+"kg,kh,kr,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"]
+)
+AC_SUBST(XKB_PRELOAD_LAYOUTS)
+
 # GObject introspection
 GOBJECT_INTROSPECTION_CHECK([0.6.8])
 
@@ -368,6 +419,7 @@ gconf/Makefile
 gconf/gconf.xml.in
 bindings/Makefile
 bindings/vala/Makefile
+xkb/Makefile
 ])
 
 AC_OUTPUT
@@ -382,6 +434,7 @@ Build options:
   Build gtk2 immodule       $enable_gtk2
   Build gtk3 immodule       $enable_gtk3
   Build XIM agent server    $enable_xim
+  Build XKB                 $enable_xkb
   Build python modules      $enable_python
   Build gconf modules       $enable_gconf
   Build memconf modules     $enable_memconf
diff --git a/data/ibus.schemas.in b/data/ibus.schemas.in
index 4695d0b..98a786e 100644
--- a/data/ibus.schemas.in
+++ b/data/ibus.schemas.in
@@ -167,6 +167,30 @@
       </locale>
     </schema>
     <schema>
+      <key>/schemas/desktop/ibus/general/default_system_layout</key>
+      <applyto>/desktop/ibus/general/default_system_layout</applyto>
+      <owner>ibus</owner>
+      <type>string</type>
+      <default>default</default>
+      <gettext_domain>ibus</gettext_domain>
+      <locale name="C">
+        <short>Set default keyboard layout</short>
+            <long>Override default system keyboard layout. default is 'default'</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,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/panel/use_custom_font</key>
       <applyto>/desktop/ibus/panel/use_custom_font</applyto>
       <owner>ibus</owner>
diff --git a/ibus/Makefile.am b/ibus/Makefile.am
index d1cd750..783b4dc 100644
--- a/ibus/Makefile.am
+++ b/ibus/Makefile.am
@@ -58,12 +58,38 @@ nodist_ibus_PYTHON = \
 
 ibusdir = @pkgpythondir@
 
+xkblayout_py_in_files = \
+	xkblayout.py.in \
+	xkbxml.py.in \
+	$(NULL)
+xkblayout_py_DATA = $(xkblayout_py_in_files:.py.in=.py)
+xkblayout_pydir = @pkgpythondir@
+
+ibus_PYTHON += $(xkblayout_py_DATA)
+
+if ENABLE_XKB
+XKB_COMMAND=\\\""$(libexecdir)/ibus-xkb"\\\"
+HAVE_XKB=True
+else
+XKB_COMMAND="None"
+HAVE_XKB=False
+endif
+
+%.py : %.py.in
+	@sed -e "s|\@XKB_COMMAND\@|$(XKB_COMMAND)|g" \
+	     -e "s|\@XKB_RULES_XML_FILE\@|$(XKB_RULES_XML_FILE)|g" \
+	     -e "s|\@HAVE_XKB\@|$(HAVE_XKB)|g" \
+	     -e "s|\@datadir\@|$(datadir)|g" \
+	$< > $@
+
 EXTRA_DIST = \
 	_config.py.in \
+	$(xkblayout_py_in_files) \
 	$(NULL)
 
 CLEANFILES = \
 	*.pyc \
+	$(xkblayout_py_DATA) \
 	$(NULL)
 
 DISTCLEANFILES = \
diff --git a/ibus/__init__.py b/ibus/__init__.py
index 7c8f8be..3c25605 100644
--- a/ibus/__init__.py
+++ b/ibus/__init__.py
@@ -41,4 +41,6 @@ from text import *
 from observedpath import *
 from enginedesc import *
 from component import *
+from xkblayout import *
+from xkbxml import *
 from _config import *
diff --git a/ibus/bus.py b/ibus/bus.py
index 15a8fd3..74b6820 100644
--- a/ibus/bus.py
+++ b/ibus/bus.py
@@ -154,6 +154,9 @@ class Bus(object.Object):
             data = serializable.deserialize_object(data)
         return data
 
+    def get_use_sys_layout(self):
+        return self.__ibus.GetUseSysLayout();
+
     def introspect_ibus(self):
         return self.__ibus.Introspect()
 
diff --git a/ibus/interface/iibus.py b/ibus/interface/iibus.py
index e63caa3..8b7b6f7 100644
--- a/ibus/interface/iibus.py
+++ b/ibus/interface/iibus.py
@@ -72,6 +72,9 @@ class IIBus(dbus.service.Object):
     @method(in_signature="v", out_signature="v")
     def Ping(self, data, dbusconn): pass
 
+    @method(out_signature="b")
+    def GetUseSysLayout(self, dbusconn): pass
+
     @signal(signature="")
     def RegistryChanged(self): pass
 
diff --git a/ibus/xkblayout.py.in b/ibus/xkblayout.py.in
new file mode 100644
index 0000000..b5f1a06
--- /dev/null
+++ b/ibus/xkblayout.py.in
@@ -0,0 +1,86 @@
+# vim:set et sts=4 sw=4:
+#
+# ibus - The Input Bus
+#
+# Copyright (c) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2007-2010 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA  02111-1307  USA
+
+__all__ = (
+        "XKBLayout",
+    )
+
+import os
+
+XKB_COMMAND = @XKB_COMMAND@
+
+class XKBLayout():
+    def __init__(self, config = None, command=XKB_COMMAND):
+        self.__config = config
+        self.__command = command
+        self.__default_layout = self.get_layout()
+        self.__xkb_latin_layouts = list(self.__config.get_value("general",
+                                                               "xkb_latin_layouts",
+                                                               []))
+
+
+    def get_layout(self):
+        if self.__command == None:
+            return None
+        exec_command = "%s %s" % (self.__command, "--get")
+        retval = None
+        for line in os.popen(exec_command).readlines():
+            line = line.strip()
+            if line.startswith("layout: "):
+                retval = line[len("layout: "):]
+                break
+        return retval
+
+    def set_layout(self, layout="default"):
+        if self.__command == None:
+            return
+        args = []
+        args.append(self.__command)
+        args.append(os.path.basename(self.__command))
+        args.append("--set")
+        layout = str(layout)
+        if layout == "default":
+            layout = self.__default_layout
+        need_us_layout = False
+        for latin_layout in self.__xkb_latin_layouts:
+            latin_layout = str(latin_layout)
+            if layout == latin_layout:
+                need_us_layout = True
+                break
+        if need_us_layout:
+            layout = layout + ",us"
+        args.append(layout)
+        os.spawnl(os.P_NOWAIT, *args)
+
+    def set_default_layout(self, layout="default"):
+        if self.__command == None:
+            return
+        if layout == 'default':
+            self.__default_layout = self.get_layout()
+        else:
+            self.__default_layout = layout
+
+    def reload_default_layout(self):
+        if self.__command == None:
+            return
+        self.__default_layout = self.get_layout()
diff --git a/ibus/xkbxml.py.in b/ibus/xkbxml.py.in
new file mode 100644
index 0000000..5880104
--- /dev/null
+++ b/ibus/xkbxml.py.in
@@ -0,0 +1,337 @@
+# vim:set et sts=4 sw=4:
+#
+# ibus - The Input Bus
+#
+# Copyright (c) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2007-2010 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA  02111-1307  USA
+
+__all__ = (
+        "XKBConfigRegistry",
+        "XKBLayoutConfig",
+    )
+
+import os
+import string
+import xml.sax as sax
+import enginedesc
+from xml.sax.saxutils import XMLFilterBase, XMLGenerator
+from xml.sax._exceptions import SAXParseException
+from cStringIO import StringIO
+
+try:
+    from glib import get_user_config_dir
+except ImportError:
+    get_user_config_dir = lambda : None
+
+XKB_RULES_XML_FILE = "@XKB_RULES_XML_FILE@"
+
+class XKBConfigRegistryHandler(XMLFilterBase):
+    def __init__(self, parser=None, root='root'):
+        XMLFilterBase.__init__(self, parser)
+        self.__root = root
+        self.__current_node = root
+        self.__layoutlist = None
+        self.__layout = False
+        self.__layout_label = None
+        self.__layout_desc = {}
+        self.__layout_lang = {}
+        self.__variantlist = False
+        self.__variant = False
+        self.__variant_label = None
+        self.__variant_desc = {}
+
+    def startElement(self, name, attrs):
+        self.__current_node = name
+        if name == "layoutList":
+            self.__layoutlist = {}
+        elif name == "layout":
+            self.__layout = True
+            self.__layout_label = None
+        elif name == "variantList":
+            self.__variantlist = True
+        elif name == "variant":
+            self.__variant = True
+            self.__variant_label = None
+
+    def endElement(self, name):
+        self.__current_node = self.__root
+        if name == "layoutList":
+            pass
+        elif name == "layout":
+            self.__layout = False
+        elif name == "variantList":
+            self.__variantlist = False
+        elif name == "variant":
+            self.__variant = False
+
+    def characters(self, text):
+        if self.__current_node == self.__root:
+            return
+        if self.__layoutlist == None:
+            return
+        if not self.__layout:
+            return
+        if self.__variant:
+            if self.__current_node == "name":
+                self.__variant_label = text
+                if self.__layout_label != None and \
+                   self.__layout_label in self.__layoutlist:
+                    self.__layoutlist[self.__layout_label].append(text)
+            elif self.__current_node == "description":
+                self.__variant_desc[self.__variant_label] = text
+            elif self.__current_node == "iso639Id":
+                label = self.__layout_label
+                if label != None:
+                    label = "%s(%s)" % (label, self.__variant_label)
+                else:
+                    label = self.__variant_label
+                if label not in self.__layout_lang:
+                    self.__layout_lang[label] = []
+                self.__layout_lang[label].append(text)
+            else:
+                pass
+        else:
+            if self.__current_node == "name":
+                self.__layout_label = text
+                self.__layoutlist[self.__layout_label] = []
+            elif self.__current_node == "description":
+                self.__layout_desc[self.__layout_label] = text
+            elif self.__current_node == "iso639Id":
+                if self.__layout_label not in self.__layout_lang:
+                    self.__layout_lang[self.__layout_label] = []
+                self.__layout_lang[self.__layout_label].append(text)
+            else:
+                pass
+
+    def getLayoutList(self):
+        return self.__layoutlist
+
+    def getLayoutDesc(self):
+        return self.__layout_desc
+
+    def getLayoutLang(self):
+        return self.__layout_lang
+
+    def getVariantDesc(self):
+        return self.__variant_desc
+
+class XKBLayoutConfigHandler(XMLFilterBase):
+    def __init__(self,
+                 parser=None,
+                 downstream=None,
+                 preload_layouts=None,
+                 root='root'):
+        XMLFilterBase.__init__(self, parser)
+        self.__downstream = downstream
+        self.__preload_layouts = preload_layouts
+        self.__root = root
+        self.__current_node = root
+        self.__xkblayout = False 
+        self.__config = False 
+
+    def startDocument(self):
+        if self.__downstream != None:
+            self.__downstream.startDocument()
+
+    def endDocument(self):
+        if self.__downstream != None:
+            self.__downstream.endDocument()
+
+    def startElement(self, name, attrs):
+        self.__current_node = name
+        if name == "xkblayout":
+            self.__xkblayout = True
+        if name == "config":
+            self.__config = True
+        if self.__downstream != None:
+            self.__downstream.startElement(name, {})
+
+    def endElement(self, name):
+        self.__current_node = self.__root
+        if name == "xkblayout":
+            self.__xkblayout = False
+        if name == "config":
+            self.__config = False
+        if self.__downstream != None:
+            self.__downstream.endElement(name)
+
+    def characters(self, text):
+        if self.__current_node == self.__root:
+            return
+        if not self.__xkblayout or not self.__config:
+            return
+        if self.__current_node == "preload_layouts":
+            if self.__preload_layouts == None:
+                self.__preload_layouts = text.split(',')
+                self.__preload_layouts.sort()
+            if self.__downstream != None:
+                self.__downstream.characters(string.join(self.__preload_layouts,
+                                                         ','))
+
+    def getPreloadLayouts(self):
+        return self.__preload_layouts
+
+class XKBConfigRegistry():
+    def __init__(self, file_path=XKB_RULES_XML_FILE):
+        self.__handler = None
+        parser = sax.make_parser()
+        parser.setFeature(sax.handler.feature_namespaces, 0)
+        self.__handler = XKBConfigRegistryHandler(parser)
+        parser.setContentHandler(self.__handler)
+        f = file(file_path, 'r')
+        try:
+            parser.parse(f)
+        except SAXParseException:
+            print "ERROR: invalid file format", file_path
+        finally:
+            f.close()
+
+    def get_layout_list(self):
+        return self.__handler.getLayoutList()
+
+    def get_layout_desc(self):
+        return self.__handler.getLayoutDesc()
+
+    def get_layout_lang(self):
+        return self.__handler.getLayoutLang()
+
+    def get_variant_desc(self):
+        return self.__handler.getVariantDesc()
+
+    @classmethod
+    def have_xkb(self):
+        return @HAVE_XKB@
+
+    @classmethod
+    def engine_desc_new(self,
+                        lang,
+                        layout,
+                        layout_desc=None,
+                        variant=None,
+                        variant_desc=None):
+        if layout_desc != None and variant_desc != None:
+            longname = layout_desc + " - " + variant_desc
+        elif layout != None and variant != None:
+            longname = layout + " - " + variant
+        elif layout_desc != None:
+            longname = layout_desc
+        else:
+            longname = layout
+        if variant != None:
+            name = "xkb:layout:" + layout + ":" + variant
+            desc = "XKB " + layout + "(" + variant + ") keyboard layout"
+            engine_layout = layout + "(" + variant + ")"
+        else:
+            name = "xkb:layout:" + layout
+            desc = "XKB " + layout + " keyboard layout"
+            engine_layout = layout
+
+        engine = enginedesc.EngineDesc(name, longname, desc, lang,
+                                       "LGPL2.1",
+                                       "Takao Fujiwara <takao.fujiwara1@gmail.com>",
+                                       "ibus-engine",
+                                       engine_layout)
+        return engine
+
+class XKBLayoutConfig():
+    def __init__(self,
+                 system_config="@datadir@/ibus/xkb/xkblayoutconfig.xml"):
+        self.__user_config = get_user_config_dir()
+        if self.__user_config == None:
+            self.__user_config = os.environ['HOME'] + "/.config"
+        self.__user_config = self.__user_config + \
+            "/ibus/xkb/xkblayoutconfig.xml"
+        self.__system_config = system_config
+        self.__filter_handler = None
+        self.__load()
+
+    def __load(self, downstream=None, preload_layouts=None):
+        parser = sax.make_parser()
+        parser.setFeature(sax.handler.feature_namespaces, 0)
+        self.__filter_handler = XKBLayoutConfigHandler(parser,
+                                                       downstream,
+                                                       preload_layouts)
+        parser.setContentHandler(self.__filter_handler)
+        f = None
+        if os.path.exists(self.__user_config):
+            f = file(self.__user_config)
+        elif os.path.exists(self.__system_config):
+            f = file(self.__system_config)
+        if f == None:
+            return
+        try:
+            parser.parse(f)
+        except SAXParseException:
+            print "ERROR: invalid file format", self.__user_config
+        finally:
+            f.close()
+
+    def get_preload_layouts(self):
+        return self.__filter_handler.getPreloadLayouts()
+
+    def save_preload_layouts(self, layouts):
+        if layouts == None:
+            if os.path.exists(self.__user_config):
+                os.unlink(self.__user_config)
+                return
+        parser = sax.make_parser()
+        parser.setFeature(sax.handler.feature_namespaces, 0)
+        result = StringIO()
+        downstream_handler = XMLGenerator(result, 'utf-8')
+        self.__load(downstream_handler, layouts)
+        contents = result.getvalue()
+        dir = os.path.dirname(self.__user_config)
+        if not os.path.exists(dir):
+            os.makedirs(dir, 0700)
+        f = open(self.__user_config, 'w')
+        f.write(contents)
+        f.close()
+        os.chmod(self.__user_config, 0600)
+
+def test():
+    xkbconfig = XKBConfigRegistry()
+    layout_list = xkbconfig.get_layout_list()
+    layout_desc = xkbconfig.get_layout_desc()
+    layout_lang = xkbconfig.get_layout_lang()
+    variant_desc = xkbconfig.get_variant_desc()
+    for layout in layout_list.keys():
+        if layout not in layout_lang:
+            print "layout name:", layout, "NO-LANG description:", layout_desc[layout]
+            continue
+        lang = layout_lang[layout]
+        print "layout name:", layout, "lang:", lang, "description:", layout_desc[layout]
+        for variant in layout_list[layout]:
+            label = "%s(%s)" % (layout, variant)
+            if label in layout_lang:
+                lang = layout_lang[label]
+            print "  variant name:", variant, "lang:", lang, "description:", variant_desc[variant]
+
+def test2():
+    xkblayoutconfig = XKBLayoutConfig("../xkb/xkblayoutconfig.xml")
+    list = xkblayoutconfig.get_preload_layouts()
+    print list
+    if list == None:
+        list = []
+    list.append("gb(test)")
+    list.sort()
+    #xkblayoutconfig.save_preload_layouts(list)
+
+if __name__ == "__main__":
+    test()
+    test2()
diff --git a/setup/main.py b/setup/main.py
index d778ac3..1335215 100644
--- a/setup/main.py
+++ b/setup/main.py
@@ -183,10 +183,20 @@ class Setup(object):
 
         # use system keyboard layout setting
         self.__checkbutton_use_sys_layout = self.__builder.get_object("checkbutton_use_sys_layout")
-        self.__checkbutton_use_sys_layout.set_active(
-            self.__config.get_value("general", "use_system_keyboard_layout", True))
+        use_system_keyboard_layout = self.__config.get_value("general", "use_system_keyboard_layout", True)
+        self.__checkbutton_use_sys_layout.set_active(use_system_keyboard_layout)
         self.__checkbutton_use_sys_layout.connect("toggled", self.__checkbutton_use_sys_layout_toggled_cb)
 
+        # default keyboard layout setting
+        self.__button_default_system_layout = self.__builder.get_object("button_default_system_layout")
+        text = str(self.__config.get_value("general", "default_system_layout", ''))
+        if text == 'default' or text == '':
+            text = _("Default")
+        self.__button_default_system_layout.set_label(text)
+        if not use_system_keyboard_layout:
+            self.__button_default_system_layout.set_sensitive(False)
+        self.__button_default_system_layout.connect("clicked", self.__button_default_system_layout_cb)
+
         # use global ime setting
         self.__checkbutton_use_global_engine = self.__builder.get_object("checkbutton_use_global_engine")
         self.__checkbutton_use_global_engine.set_active(
@@ -223,6 +233,145 @@ class Setup(object):
         self.__combobox.connect("notify::active-engine", self.__combobox_notify_active_engine_cb)
         self.__treeview.connect("notify", self.__treeview_notify_cb)
 
+        self.__xkblayoutconfig = None
+        self.__preload_xkb_engines = []
+        self.__other_xkb_engines = []
+        if ibus.XKBConfigRegistry.have_xkb():
+            self.__xkblayoutconfig = ibus.XKBLayoutConfig()
+
+        # config layouts dialog
+        self.__init_config_layouts()
+
+        # default system layout dialog
+        self.__init_default_system_layout()
+
+    def __get_xkbengines(self):
+        xkbengines = []
+        xkbconfig = ibus.XKBConfigRegistry()
+        layout_list = xkbconfig.get_layout_list()
+        layout_desc = xkbconfig.get_layout_desc()
+        layout_lang = xkbconfig.get_layout_lang()
+        variant_desc = xkbconfig.get_variant_desc()
+        for layout in layout_list.keys():
+            if layout not in layout_lang:
+                continue
+            langs = layout_lang[layout]
+            for lang in langs:
+                engine = ibus.XKBConfigRegistry.engine_desc_new(
+                    lang,
+                    layout,
+                    layout_desc[layout],
+                    None,
+                    None)
+                xkbengines.append(engine)
+            for variant in layout_list[layout]:
+                label = "%s(%s)" % (layout, variant)
+                if label in layout_lang:
+                    langs = layout_lang[label]
+                for lang in langs:
+                    engine = ibus.XKBConfigRegistry.engine_desc_new(
+                        lang,
+                        layout,
+                        layout_desc[layout],
+                        variant,
+                        variant_desc[variant])
+                    xkbengines.append(engine)
+        return xkbengines
+
+    def __init_config_layouts(self):
+        if not ibus.XKBConfigRegistry.have_xkb():
+            button = self.__builder.get_object("button_config_layouts")
+            button.hide()
+            return
+
+        self.__dialog_config_layouts = self.__builder.get_object("dialog_config_layouts")
+        self.__button_config_layouts_cancel = self.__builder.get_object("button_config_layouts_cancel")
+        self.__button_config_layouts_cancel.connect("clicked", self.__button_config_layouts_cancel_cb)
+        self.__button_config_layouts_ok = self.__builder.get_object("button_config_layouts_ok")
+        self.__button_config_layouts_ok.connect("clicked", self.__button_config_layouts_ok_cb)
+
+        xkbengines = self.__get_xkbengines()
+        preload_engine_list = []
+        other_engine_list = []
+
+        if len(xkbengines) > 0:
+            button = self.__builder.get_object("button_config_layouts")
+            button.connect("clicked", self.__button_config_layouts_cb)
+            button.set_sensitive(True)
+
+        engine = ibus.XKBConfigRegistry.engine_desc_new(
+                     "xkb:layout:none",
+                     "none",
+                     _("No Selection"),
+                     None,
+                     None)
+        self.__preload_xkb_engines.append(engine)
+        self.__other_xkb_engines.append(engine)
+
+        preload_xkb_engines = self.__xkblayoutconfig.get_preload_layouts()
+        for engine in xkbengines:
+            if not engine.name.startswith("xkb:layout:"):
+                continue
+            sub_name = engine.name[len("xkb:layout:"):]
+            layout_list = sub_name.split(':')
+            if len(layout_list) > 1:
+                layout = "%s(%s)" % (layout_list[0], layout_list[1])
+            else:
+                layout = layout_list[0]
+            has_preloaded = False
+            for preload_name in preload_xkb_engines:
+                preload_name = str(preload_name)
+                if len(preload_name) == 0:
+                    continue
+                if layout == preload_name:
+                    has_preloaded = True
+                    break
+            if has_preloaded:
+                self.__preload_xkb_engines.append(engine)
+            else:
+                self.__other_xkb_engines.append(engine)
+        self.__combobox_add_layout = self.__builder.get_object("combobox_add_layout_engines")
+        self.__combobox_add_layout.set_engines(self.__other_xkb_engines)
+        self.__combobox_remove_layout = self.__builder.get_object("combobox_remove_layout_engines")
+        self.__combobox_remove_layout.set_engines(self.__preload_xkb_engines)
+
+    def __init_default_system_layout(self):
+        if not ibus.XKBConfigRegistry.have_xkb():
+            hbox = self.__builder.get_object("hbox_default_system_layout")
+            hbox.hide()
+            return
+
+        self.__dialog_default_system_layout = self.__builder.get_object("dialog_default_system_layout")
+        self.__button_default_system_layout_cancel = self.__builder.get_object("button_default_system_layout_cancel")
+        self.__button_default_system_layout_cancel.connect("clicked", self.__button_default_system_layout_cancel_cb)
+        self.__button_default_system_layout_ok = self.__builder.get_object("button_default_system_layout_ok")
+        self.__button_default_system_layout_ok.connect("clicked", self.__button_default_system_layout_ok_cb)
+
+        # get xkb layouts
+        xkbengines = self.__get_xkbengines()
+        engine = ibus.XKBConfigRegistry.engine_desc_new(
+                     "xkb:layout:default",
+                     "default",
+                     _("Default layout for reset"),
+                     None,
+                     None)
+        xkbengines.append(engine)
+
+        self.__combobox_default_system_layout = self.__builder.get_object("combobox_default_system_layout_engines")
+        self.__combobox_default_system_layout.set_engines(xkbengines)
+        self.__entry_default_system_layout = self.__builder.get_object("entry_default_system_layout")
+        self.__entry_default_system_layout.set_sensitive(False)
+        text = str(self.__config.get_value("general", "default_system_layout", ''))
+        if text != None:
+            self.__entry_default_system_layout.set_text(text)
+        button = self.__builder.get_object("radiobutton_combobox_default_system_layout")
+        button.set_property("name", "radiobutton_combobox_default_system_layout")
+        button.set_active(True)
+        button.connect("clicked", self.__radiobutton_default_system_layout_cb)
+        button = self.__builder.get_object("radiobutton_entry_default_system_layout")
+        button.set_property("name", "radiobutton_entry_default_system_layout")
+        button.connect("clicked", self.__radiobutton_default_system_layout_cb)
+
     def __combobox_notify_active_engine_cb(self, combobox, property):
         engine = self.__combobox.get_active_engine()
         button = self.__builder.get_object("button_engine_add")
@@ -255,6 +404,80 @@ class Setup(object):
             about.run()
             about.destroy()
 
+    def __button_config_layouts_cb(self, button):
+        self.__dialog_config_layouts.run()
+        self.__dialog_config_layouts.hide()
+
+    def __button_config_layouts_cancel_cb(self, button):
+        self.__dialog_config_layouts.hide()
+
+    def __button_config_layouts_ok_cb(self, button):
+        self.__dialog_config_layouts.hide()
+        add_engine = self.__combobox_add_layout.get_active_engine()
+        remove_engine = self.__combobox_remove_layout.get_active_engine()
+        is_modified = False
+        if add_engine != None and add_engine.name != "xkb:layout:none":
+            self.__preload_xkb_engines.append(add_engine)
+            self.__other_xkb_engines.remove(add_engine)
+            is_modified = True
+        if remove_engine != None and remove_engine.name != "xkb:layout:none":
+            self.__preload_xkb_engines.remove(remove_engine)
+            self.__other_xkb_engines.append(remove_engine)
+            is_modified = True
+        if is_modified == False:
+            return
+        self.__combobox_add_layout.set_engines(self.__other_xkb_engines)
+        self.__combobox_remove_layout.set_engines(self.__preload_xkb_engines)
+        engine_list = []
+        for engine in self.__preload_xkb_engines:
+            if not engine.name.startswith("xkb:layout:"):
+                continue
+            if engine.name == "xkb:layout:none":
+                continue
+            sub_name = engine.name[len("xkb:layout:"):]
+            layout_list = sub_name.split(':')
+            if len(layout_list) > 1:
+                layout = "%s(%s)" % (layout_list[0], layout_list[1])
+            else:
+                layout = layout_list[0]
+            engine_list.append(layout)
+        if len(engine_list) > 0:
+            engine_list.sort()
+            self.__xkblayoutconfig.save_preload_layouts(engine_list)
+
+    def __button_default_system_layout_cb(self, button):
+        self.__dialog_default_system_layout.run()
+        self.__dialog_default_system_layout.hide()
+
+    def __button_default_system_layout_cancel_cb(self, button):
+        self.__dialog_default_system_layout.hide()
+
+    def __button_default_system_layout_ok_cb(self, button):
+        self.__dialog_default_system_layout.hide()
+        layout = "default"
+        if self.__combobox_default_system_layout.get_sensitive():
+            engine = self.__combobox_default_system_layout.get_active_engine()
+            if engine != None:
+                layout = engine.layout
+        elif self.__entry_default_system_layout.get_sensitive():
+            layout = self.__entry_default_system_layout.get_text()
+        if layout == None or layout == "":
+            layout = "default"
+        self.__config.set_value("general", "default_system_layout", layout)
+        if layout == "default":
+            layout = _("Default")
+        self.__button_default_system_layout.set_label(layout)
+
+    def __radiobutton_default_system_layout_cb(self, button):
+        if button.get_active() != True:
+            return
+        if button.name == "radiobutton_combobox_default_system_layout":
+            self.__combobox_default_system_layout.set_sensitive(True)
+            self.__entry_default_system_layout.set_sensitive(False)
+        elif button.name == "radiobutton_entry_default_system_layout":
+            self.__combobox_default_system_layout.set_sensitive(False)
+            self.__entry_default_system_layout.set_sensitive(True)
+
     def __init_bus(self):
         try:
             self.__bus = ibus.Bus()
@@ -439,6 +662,7 @@ class Setup(object):
     def __checkbutton_use_sys_layout_toggled_cb(self, button):
         value = self.__checkbutton_use_sys_layout.get_active()
         self.__config.set_value("general", "use_system_keyboard_layout", value)
+        self.__button_default_system_layout.set_sensitive(value)
 
     def __checkbutton_use_global_engine_toggled_cb(self, button):
         value = self.__checkbutton_use_global_engine.get_active()
diff --git a/setup/setup.ui b/setup/setup.ui
index 0e31a78..cb275a9 100644
--- a/setup/setup.ui
+++ b/setup/setup.ui
@@ -129,7 +129,6 @@
                                 <child>
                                   <object class="GtkLabel" id="label9">
                                     <property name="visible">True</property>
-                                    <property name="sensitive">False</property>
                                     <property name="tooltip_text" translatable="yes">The shortcut keys for switching to previous input method in the list</property>
                                     <property name="xalign">0</property>
                                     <property name="label" translatable="yes">Previous input method:</property>
@@ -216,7 +215,6 @@
                                     <child>
                                       <object class="GtkEntry" id="entry_prev_engine">
                                         <property name="visible">True</property>
-                                        <property name="sensitive">False</property>
                                         <property name="can_focus">True</property>
                                         <property name="editable">False</property>
                                       </object>
@@ -228,7 +226,6 @@
                                       <object class="GtkButton" id="button_prev_engine">
                                         <property name="label" translatable="yes">...</property>
                                         <property name="visible">True</property>
-                                        <property name="sensitive">False</property>
                                         <property name="can_focus">True</property>
                                         <property name="receives_default">False</property>
                                         <property name="use_underline">True</property>
@@ -550,6 +547,7 @@
                                 <property name="orientation">vertical</property>
                                 <property name="spacing">5</property>
                                 <property name="layout_style">start</property>
+                                <property name="no_show_all">True</property>
                                 <child>
                                   <object class="GtkButton" id="button_engine_add">
                                     <property name="label">gtk-add</property>
@@ -630,6 +628,22 @@
                                     <property name="position">4</property>
                                   </packing>
                                 </child>
+                                <child>
+                                  <object class="GtkButton" id="button_config_layouts">
+                                    <property name="label">Configure _Layouts</property>
+                                    <property name="visible">True</property>
+                                    <property name="sensitive">False</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">True</property>
+                                    <property name="tooltip_text" translatable="yes">Configure keyboard layouts</property>
+                                    <property name="use_underline">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">5</property>
+                                  </packing>
+                                </child>
                               </object>
                             </child>
                           </object>
@@ -729,6 +743,7 @@ You may use up/down buttons to change it.&lt;/i&gt;&lt;/small&gt;</property>
                                     <property name="visible">True</property>
                                     <property name="orientation">vertical</property>
                                     <property name="spacing">6</property>
+                                    <property name="no_show_all">True</property>
                                     <child>
                                       <object class="GtkCheckButton" id="checkbutton_use_sys_layout">
                                         <property name="label" translatable="yes">Use system keyboard layout</property>
@@ -744,6 +759,43 @@ You may use up/down buttons to change it.&lt;/i&gt;&lt;/small&gt;</property>
                                         <property name="position">0</property>
                                       </packing>
                                     </child>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox_default_system_layout">
+                                        <property name="visible">True</property>
+                                        <property name="spacing">6</property>
+                                        <child>
+                                          <object class="GtkLabel" id="label18">
+                                            <property name="visible">True</property>
+                                            <property name="label" translatable="yes">System Layout:</property>
+                                            <property name="use_markup">True</property>
+                                            <property name="justify">center</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkButton" id="button_default_system_layout">
+                                            <property name="label"></property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">False</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="expand">False</property>
+                                        <property name="fill">False</property>
+                                        <property name="position">1</property>
+                                      </packing>
+                                    </child>
                                   </object>
                                 </child>
                               </object>
@@ -942,4 +994,246 @@ Homepage: http://code.google.com/p/ibus
       </object>
     </child>
   </object>
+  <object class="GtkDialog" id="dialog_config_layouts">
+    <property name="title" translatable="yes">Layouts Setup</property>
+    <property name="icon_name">ibus-setup</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="vbox101">
+        <property name="orientation">vertical</property>
+        <property name="visible">True</property>
+        <property name="border-width">10</property>
+        <property name="spacing">12</property>
+        <child>
+          <object class="GtkTable" id="table101">
+            <property name="visible">True</property>
+            <property name="n_rows">2</property>
+            <property name="n_columns">2</property>
+            <property name="column_spacing">12</property>
+            <property name="row_spacing">6</property>
+            <child>
+              <object class="GtkLabel" id="label101">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Add Layout:</property>
+                <property name="tooltip_text" translatable="yes">Add layout</property>
+                <property name="xalign">0</property>
+              </object>
+              <packing>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options">GTK_FILL</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkAlignment" id="alignment101">
+                <property name="visible">True</property>
+                <child>
+                  <object class="EngineComboBox" id="combobox_add_layout_engines">
+                   <property name="visible">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options">GTK_FILL</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label102">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Remove Layout:</property>
+                <property name="tooltip_text" translatable="yes">Remove layout</property>
+                <property name="xalign">0</property>
+              </object>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options">GTK_FILL</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkAlignment" id="alignment102">
+                <property name="visible">True</property>
+                <child>
+                  <object class="EngineComboBox" id="combobox_remove_layout_engines">
+                   <property name="visible">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options">GTK_FILL</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="hbuttonbox101">
+            <property name="visible">True</property>
+            <property name="homogeneous">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button_config_layouts_cancel">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button_config_layouts_ok">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="use_stock">True</property>
+                <property name="receives_default">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
+  <object class="GtkDialog" id="dialog_default_system_layout">
+    <property name="title" translatable="yes">Default System Layout Setup</property>
+    <property name="icon_name">ibus-setup</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="vbox201">
+        <property name="orientation">vertical</property>
+        <property name="visible">True</property>
+        <property name="border-width">10</property>
+        <property name="spacing">12</property>
+        <child>
+          <object class="GtkTable" id="table201">
+            <property name="visible">True</property>
+            <property name="n_rows">2</property>
+            <property name="n_columns">2</property>
+            <property name="column_spacing">12</property>
+            <property name="row_spacing">6</property>
+            <child>
+              <object class="GtkRadioButton" id="radiobutton_combobox_default_system_layout">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Choose From:</property>
+                <property name="tooltip_text" translatable="yes">choose default keyboard from list</property>
+              </object>
+              <packing>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options">GTK_FILL</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkAlignment" id="alignment201">
+                <property name="visible">True</property>
+                <child>
+                  <object class="EngineComboBox" id="combobox_default_system_layout_engines">
+                    <property name="visible">True</property>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options">GTK_FILL</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkRadioButton" id="radiobutton_entry_default_system_layout">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">Manual Type:</property>
+                <property name="tooltip_text" translatable="yes">Type default keyboard layout by manual (comma-separated values)</property>
+                <property name="group">radiobutton_combobox_default_system_layout</property>
+              </object>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options">GTK_FILL</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkEntry" id="entry_default_system_layout">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="editable">True</property>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options">GTK_FILL</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="hbuttonbox201">
+            <property name="visible">True</property>
+            <property name="homogeneous">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button_default_system_layout_cancel">
+                <property name="label">gtk-cancel</property>
+                <property name="visible">True</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="button_default_system_layout_ok">
+                <property name="label">gtk-ok</property>
+                <property name="visible">True</property>
+                <property name="use_stock">True</property>
+                <property name="receives_default">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </object>
 </interface>
diff --git a/src/ibusfactory.c b/src/ibusfactory.c
index e0ec2a5..c70bfde 100644
--- a/src/ibusfactory.c
+++ b/src/ibusfactory.c
@@ -28,6 +28,7 @@
    (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_FACTORY, IBusFactoryPrivate))
 
 enum {
+    LOOKUP_ENGINE_NAME,
     LAST_SIGNAL,
 };
 
@@ -45,6 +46,8 @@ struct _IBusFactoryPrivate {
 };
 typedef struct _IBusFactoryPrivate IBusFactoryPrivate;
 
+static guint            factory_signals[LAST_SIGNAL] = { 0 };
+
 /* functions prototype */
 static void     ibus_factory_destroy        (IBusFactory        *factory);
 static void     ibus_factory_set_property   (IBusFactory        *engine,
@@ -111,7 +114,16 @@ ibus_factory_class_init (IBusFactoryClass *klass)
                 IBUS_TYPE_CONNECTION,
                 G_PARAM_READWRITE |  G_PARAM_CONSTRUCT_ONLY));
 
-
+    factory_signals[LOOKUP_ENGINE_NAME] =
+        g_signal_new (I_("lookup-engine-name"),
+            G_TYPE_FROM_CLASS (gobject_class),
+            G_SIGNAL_RUN_LAST,
+            G_STRUCT_OFFSET (IBusFactoryClass, lookup_engine_name),
+            NULL, NULL,
+            ibus_marshal_VOID__STRING,
+            G_TYPE_NONE,
+            1,
+            G_TYPE_STRING);
 }
 
 static void
@@ -245,6 +257,9 @@ ibus_factory_ibus_message (IBusFactory    *factory,
             return TRUE;
         }
 
+        g_signal_emit (factory, factory_signals[LOOKUP_ENGINE_NAME],
+                       0, engine_name);
+
         engine_type = (GType )g_hash_table_lookup (priv->engine_table, engine_name);
 
         if (engine_type == G_TYPE_INVALID) {
diff --git a/src/ibusfactory.h b/src/ibusfactory.h
index e92c810..570e464 100644
--- a/src/ibusfactory.h
+++ b/src/ibusfactory.h
@@ -117,10 +117,13 @@ struct _IBusFactoryClass {
     IBusServiceClass parent;
 
     /* signals */
+    void        (* lookup_engine_name)
+                                    (IBusFactory    *factory,
+                                     const gchar    *engine_name);
 
     /*< private >*/
     /* padding */
-    gpointer pdummy[8];
+    gpointer pdummy[7];
 };
 
 /**
diff --git a/ui/gtk/panel.py b/ui/gtk/panel.py
index 0efc85b..c011f49 100644
--- a/ui/gtk/panel.py
+++ b/ui/gtk/panel.py
@@ -121,6 +121,14 @@ class Panel(ibus.PanelBase):
         self.__config_load_show_im_name()
         # self.__bus.request_name(ibus.panel.IBUS_SERVICE_PANEL, 0)
 
+        # init xkb
+        self.__xkblayout = ibus.XKBLayout(self.__config)
+        value = str(self.__config.get_value("general", "default_system_layout", ''))
+        if value == '':
+            value = 'default'
+        if value != 'default':
+            self.__xkblayout.set_default_layout(value)
+
     def set_cursor_location(self, x, y, w, h):
         self.__candidate_panel.set_cursor_location(x + w, y + h)
 
@@ -205,14 +213,20 @@ class Panel(ibus.PanelBase):
         if not enabled:
             self.__set_im_icon(ICON_KEYBOARD)
             self.__set_im_name(None)
+            if self.__bus.get_use_sys_layout():
+                self.__xkblayout.set_layout()
         else:
             engine = self.__focus_ic.get_engine()
             if engine:
                 self.__set_im_icon(engine.icon)
                 self.__set_im_name(engine.longname)
+                if self.__bus.get_use_sys_layout():
+                    self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine))
             else:
                 self.__set_im_icon(ICON_KEYBOARD)
                 self.__set_im_name(None)
+                if self.__bus.get_use_sys_layout():
+                    self.__xkblayout.set_layout()
         self.__language_bar.focus_in()
 
     def focus_out(self, ic):
@@ -222,6 +236,8 @@ class Panel(ibus.PanelBase):
         self.__language_bar.focus_out()
         self.__set_im_icon(ICON_KEYBOARD)
         self.__set_im_name(None)
+        if self.__bus.get_use_sys_layout():
+            self.__xkblayout.set_layout()
 
     def state_changed(self):
         if not self.__focus_ic:
@@ -234,14 +250,20 @@ class Panel(ibus.PanelBase):
             self.reset()
             self.__set_im_icon(ICON_KEYBOARD)
             self.__set_im_name(None)
+            if self.__bus.get_use_sys_layout():
+                self.__xkblayout.set_layout()
         else:
             engine = self.__focus_ic.get_engine()
             if engine:
                 self.__set_im_icon(engine.icon)
                 self.__set_im_name(engine.longname)
+                if self.__bus.get_use_sys_layout():
+                    self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine))
             else:
                 self.__set_im_icon(ICON_KEYBOARD)
                 self.__set_im_name(None)
+                if self.__bus.get_use_sys_layout():
+                    self.__xkblayout.set_layout()
 
 
     def reset(self):
@@ -517,4 +539,12 @@ class Panel(ibus.PanelBase):
                 return
             self.__setup_pid = 0
         self.__setup_pid = os.spawnl(os.P_NOWAIT, self.__setup_cmd, "ibus-setup")
+    def __engine_get_layout_wrapper(self, engine):
+        # This code is for the back compatibility.
+        # Should we remove the codes after all IM engines are changed
+        # to "default" layout?
+        if engine.name != None and engine.name.startswith("xkb:layout:"):
+            return engine.layout
+        else:
+            return "default"
 
diff --git a/xkb/Makefile.am b/xkb/Makefile.am
new file mode 100644
index 0000000..49b82eb
--- /dev/null
+++ b/xkb/Makefile.am
@@ -0,0 +1,104 @@
+# vim:set noet ts=4:
+#
+# ibus - The Input Bus
+#
+# Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright (c) 2007-2010 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA  02111-1307  USA
+
+libibus = $(top_builddir)/src/libibus.la
+
+INCLUDES = \
+        -I$(top_srcdir) \
+        -I$(top_srcdir)/src \
+	-DIBUS_LOCALEDIR=\"$(datadir)/locale\" \
+	-DLIBEXECDIR=\""$(libexecdir)"\" \
+        $(NULL)
+
+noinst_PROGRAMS = $(TESTS)
+libexec_PROGRAMS =
+EXTRA_DIST =
+DISTCLEANFILES =
+
+if ENABLE_XKB
+libexec_PROGRAMS += ibus-xkb
+ibus_xkb_SOURCES = \
+	ibus-xkb-main.c \
+	xkblib.h \
+	xkblib.c \
+	$(NULL)
+ibus_xkb_CFLAGS = \
+	@XKB_CFLAGS@ \
+	@X11_CFLAGS@ \
+	@GLIB2_CFLAGS@ \
+	$(NULL)
+ibus_xkb_LDADD = \
+	@XKB_LIBS@ \
+	@X11_LIBS@ \
+	@GLIB2_LIBS@ \
+	$(libibus) \
+	$(NULL)
+
+libexec_PROGRAMS += ibus-engine-xkb
+ibus_engine_xkb_SOURCES = \
+        ibus-engine-xkb-main.c \
+        ibus-engine-xkb-main.h \
+        xkbxml.c \
+        xkbxml.h \
+        $(NULL)
+ibus_engine_xkb_CFLAGS = \
+	@GLIB2_CFLAGS@ \
+	@GOBJECT2_CFLAGS@ \
+	@GCONF_CFLAGS@ \
+        $(NULL)
+ibus_engine_xkb_LDADD = \
+	@GLIB2_LIBS@ \
+	@GOBJECT2_LIBS@ \
+	@GCONF_LIBS@ \
+	$(libibus) \
+        $(NULL)
+
+xkblayoutdir = $(datadir)/ibus/component
+xkblayout_in_files = xkblayout.xml.in
+xkblayout_DATA = $(xkblayout_in_files:.xml.in=.xml)
+
+xkblayoutconfigdir = $(datadir)/ibus/xkb
+xkblayoutconfig_in_files = xkblayoutconfig.xml.in
+xkblayoutconfig_DATA = $(xkblayoutconfig_in_files:.xml.in=.xml)
+
+%.xml : %.xml.in
+	@sed -e "s|\@libexecdir\@|$(libexecdir)|g" \
+	     -e "s|\@datadir\@|$(datadir)|g" \
+	     -e "s|\@XKB_PRELOAD_LAYOUTS\@|$(XKB_PRELOAD_LAYOUTS)|g" \
+	$< > $@
+
+INCLUDES += \
+	-DXKBLAYOUTCONFIG_FILE=\""$(xkblayoutconfigdir)/$(xkblayoutconfig_DATA)"\" \
+	$(NULL)
+
+EXTRA_DIST += \
+        $(xkblayout_in_files) \
+        $(xkblayoutconfig_in_files) \
+        $(NULL)
+
+DISTCLEANFILES += \
+        $(xkblayout_DATA) \
+        $(xkblayoutconfig_DATA) \
+        $(NULL)
+
+endif
diff --git a/xkb/ibus-engine-xkb-main.c b/xkb/ibus-engine-xkb-main.c
new file mode 100644
index 0000000..7fd6a7f
--- /dev/null
+++ b/xkb/ibus-engine-xkb-main.c
@@ -0,0 +1,396 @@
+/* vim:set et sts=4: */
+/* bus - The Input Bus
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gconf/gconf-client.h>
+#include <ibus.h>
+#include <stdlib.h>
+
+#ifdef ENABLE_NLS
+#include <locale.h>
+#endif
+
+#include "ibus-engine-xkb-main.h"
+#include "xkbxml.h"
+
+#define IBUS_TYPE_XKB_ENGINE (ibus_xkb_engine_get_type ())
+
+static IBusBus *bus = NULL;
+static IBusFactory *factory = NULL;
+static IBusEngineClass *parent_class = NULL;
+static gboolean ibus = FALSE;
+static gboolean xml = FALSE;
+
+static const GOptionEntry entries[] =
+{
+    { "ibus", 'i', 0, G_OPTION_ARG_NONE, &ibus, "component is executed by ibus", NULL },
+    { "xml", 'x', 0, G_OPTION_ARG_NONE, &xml, "print component xml", NULL },
+    { NULL },
+};
+
+static GObject*
+ibus_xkb_engine_constructor (GType                   type,
+                             guint                   n_construct_params,
+                             GObjectConstructParam  *construct_params)
+{
+    IBusXKBEngine *engine;
+
+    engine = (IBusXKBEngine *) G_OBJECT_CLASS (parent_class)->constructor (type,
+                                               n_construct_params,
+                                               construct_params);
+
+    return (GObject *) engine;
+}
+
+static void
+ibus_xkb_engine_destroy (IBusObject *object)
+{
+    IBUS_OBJECT_CLASS (parent_class)->destroy (object);
+}
+
+static void
+ibus_xkb_engine_enable (IBusEngine *engine)
+{
+    parent_class->enable (engine);
+}
+
+static void
+ibus_xkb_engine_disable (IBusEngine *engine)
+{
+    parent_class->disable (engine);
+}
+
+static void
+ibus_xkb_engine_focus_in (IBusEngine *engine)
+{
+    parent_class->focus_in (engine);
+}
+
+static void
+ibus_xkb_engine_focus_out (IBusEngine *engine)
+{
+    parent_class->focus_out (engine);
+}
+
+static void
+ibus_xkb_engine_class_init (IBusXKBEngineClass *klass)
+{
+    GObjectClass *object_class = G_OBJECT_CLASS (klass);
+    IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
+    IBusEngineClass *engine_class = IBUS_ENGINE_CLASS (klass);
+
+    parent_class = (IBusEngineClass *) g_type_class_peek_parent (klass);
+    object_class->constructor = ibus_xkb_engine_constructor;
+    ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_xkb_engine_destroy;
+    engine_class->enable = ibus_xkb_engine_enable;
+    engine_class->disable = ibus_xkb_engine_disable;
+    engine_class->focus_in = ibus_xkb_engine_focus_in;
+    engine_class->focus_out = ibus_xkb_engine_focus_out;
+
+}
+
+static void
+ibus_xkb_engine_init (IBusXKBEngine *engine)
+{
+}
+
+GType
+ibus_xkb_engine_get_type (void)
+{
+    static GType type = 0;
+
+    static const GTypeInfo type_info = {
+        sizeof (IBusXKBEngineClass),
+        (GBaseInitFunc)     NULL,
+        (GBaseFinalizeFunc) NULL,
+        (GClassInitFunc)    ibus_xkb_engine_class_init,
+        NULL,
+        NULL,
+        sizeof (IBusXKBEngine),
+        0,
+        (GInstanceInitFunc) ibus_xkb_engine_init,
+    };
+
+    if (type == 0) {
+            type = g_type_register_static (IBUS_TYPE_ENGINE,
+                                           "IBusXKBEngine",
+                                           &type_info,
+                                           (GTypeFlags) 0);
+    }
+
+    return type;
+}
+
+static void
+ibus_disconnected_cb (IBusBus  *bus,
+                      gpointer  user_data)
+{
+    g_debug ("bus disconnected");
+    ibus_quit ();
+}
+
+static void
+_factory_lookup_engine_name_cb (IBusFactory *factory,
+                                const gchar *engine_name,
+                                gpointer     data)
+{
+    static GList *engine_list = NULL;
+    GList *list;
+    gboolean has_name = FALSE;
+
+    g_return_if_fail (engine_name != NULL);
+
+    if (g_strcmp0 (engine_name, "xkb:layout:us") == 0) {
+        return;
+    }
+    list = engine_list;
+    while (list) {
+        if (g_strcmp0 (list->data, engine_name) == 0) {
+            has_name = TRUE;
+            break;
+        }
+        list = list->next;
+    }
+    if (has_name) {
+        return;
+    }
+
+    ibus_factory_add_engine (factory, engine_name, IBUS_TYPE_XKB_ENGINE);
+    engine_list = g_list_append (engine_list, (gpointer) g_strdup (engine_name));
+}
+
+static void
+start_component (int argc, char **argv)
+{
+    IBusComponent *component;
+
+    ibus_init ();
+
+    bus = ibus_bus_new ();
+    g_signal_connect (bus, "disconnected", G_CALLBACK (ibus_disconnected_cb), NULL);
+
+    component = ibus_component_new ("org.freedesktop.IBus.XKB",
+                                    "XKB Component",
+                                    VERSION,
+                                    "LGPL2.1",
+                                    "Takao Fujiwara <takao.fujiwara1@gmail.com>",
+                                    "http://code.google.com/p/ibus/",
+                                    "",
+                                    GETTEXT_PACKAGE);
+    ibus_component_add_engine (component,
+                               ibus_xkb_engine_desc_new ("eng",
+                                                         "us",
+                                                         "USA",
+                                                         NULL,
+                                                         NULL));
+
+    factory = ibus_factory_new (ibus_bus_get_connection (bus));
+
+    ibus_factory_add_engine (factory, "xkb:layout:us", IBUS_TYPE_XKB_ENGINE);
+
+    g_signal_connect (G_OBJECT (factory), "lookup-engine-name",
+                      G_CALLBACK (_factory_lookup_engine_name_cb),
+                      NULL);
+    if (ibus) {
+        ibus_bus_request_name (bus, "org.freedesktop.IBus.XKB", 0);
+    }
+    else {
+        ibus_bus_register_component (bus, component);
+    }
+
+    g_object_unref (component);
+
+    ibus_main ();
+}
+
+static gboolean
+is_included_engine_in_preload (const GList * preload_xkb_engines,
+                               const gchar *layout,
+                               const gchar *variant)
+{
+    const GList *list = preload_xkb_engines;
+    gchar *key = NULL;
+    gboolean retval = FALSE;
+
+    g_return_val_if_fail (layout != NULL, FALSE);
+
+    if (variant == NULL) {
+        key = g_strdup (layout);
+    } else {
+        key = g_strdup_printf ("%s(%s)", layout, variant);
+    }
+    while (list) {
+        if (list->data == NULL) {
+            continue;
+        }
+        if (g_strcmp0 ((const gchar *) list->data,
+                       (const gchar *) key) == 0) {
+            retval = TRUE;
+            break;
+        }
+        list = list->next;
+    }
+    g_free (key);
+    return retval;
+}
+
+static void
+print_component ()
+{
+    IBusXKBLayoutConfig *layout_config;
+    IBusXKBConfigRegistry *config_registry;
+    GHashTable *layout_list;
+    GHashTable *layout_lang;
+    GHashTable *layout_desc;
+    GHashTable *variant_desc;
+    IBusComponent *component;
+    IBusEngineDesc *engine;
+    const GList *preload_xkb_engines = NULL;
+    GList *keys;
+    GList *variants;
+    GList *langs;
+    gboolean is_preload;
+    gchar *layout_name;
+    const gchar *desc;
+    gchar *output;
+    GString *str;
+
+#ifdef XKBLAYOUTCONFIG_FILE
+    layout_config = ibus_xkb_layout_config_new (XKBLAYOUTCONFIG_FILE);
+    preload_xkb_engines = ibus_xkb_layout_config_get_preload_layouts (layout_config);
+#endif
+
+    config_registry = ibus_xkb_config_registry_new ();
+    layout_list = (GHashTable *) ibus_xkb_config_registry_get_layout_list (config_registry);
+    layout_lang = (GHashTable *) ibus_xkb_config_registry_get_layout_lang (config_registry);
+    layout_desc = (GHashTable *) ibus_xkb_config_registry_get_layout_desc (config_registry);
+    variant_desc = (GHashTable *) ibus_xkb_config_registry_get_variant_desc (config_registry);
+    component = ibus_xkb_component_new ();
+    for (keys = g_hash_table_get_keys (layout_list); keys; keys = keys->next) {
+        if (keys->data == NULL) {
+            continue;
+        }
+        desc = (const gchar *) g_hash_table_lookup (layout_desc, keys->data);
+        langs = (GList *) g_hash_table_lookup (layout_lang, keys->data);
+        for (;langs; langs = langs->next) {
+            if (langs->data == NULL) {
+                continue;
+            }
+            is_preload = FALSE;
+            if (!preload_xkb_engines) {
+                is_preload = TRUE;
+            } else {
+                is_preload = is_included_engine_in_preload (preload_xkb_engines,
+                                                            (const gchar *) keys->data,
+                                                            NULL);
+            }
+            if (is_preload) {
+                engine = ibus_xkb_engine_desc_new ((const gchar *) langs->data,
+                                                   (const gchar *) keys->data,
+                                                   desc,
+                                                   NULL,
+                                                   NULL);
+            ibus_component_add_engine (component, engine);
+            }
+        }
+        variants = (GList *) g_hash_table_lookup (layout_list, keys->data);
+        for (;variants; variants = variants->next) {
+            if (variants->data == NULL) {
+                continue;
+            }
+            layout_name = g_strdup_printf ("%s(%s)", (gchar *) keys->data,
+                                                     (gchar *) variants->data);
+            langs = (GList *) g_hash_table_lookup (layout_lang, layout_name);
+            if (langs == NULL) {
+                g_free (layout_name);
+                layout_name = g_strdup ((gchar *) keys->data);
+                langs = (GList *) g_hash_table_lookup (layout_lang, layout_name);
+            }
+            g_free (layout_name);
+            for (;langs; langs = langs->next) {
+                if (langs->data == NULL) {
+                    continue;
+                }
+                is_preload = FALSE;
+                if (!preload_xkb_engines) {
+                   is_preload = TRUE;
+                } else {
+                    is_preload = is_included_engine_in_preload (preload_xkb_engines,
+                                                                (const gchar *) keys->data,
+                                                                (const gchar *) variants->data);
+                }
+                if (is_preload) {
+                    engine = ibus_xkb_engine_desc_new ((const gchar *) langs->data,
+                                                       (const gchar *) keys->data,
+                                                       desc,
+                                                       (const gchar *) variants->data,
+                                                       (const gchar *) g_hash_table_lookup (variant_desc, variants->data));
+                    ibus_component_add_engine (component, engine);
+                }
+            }
+        }
+    }
+    g_object_unref (G_OBJECT (config_registry));
+#ifdef XKBLAYOUTCONFIG_FILE
+    g_object_unref (G_OBJECT (layout_config));
+#endif
+
+    str = g_string_new (NULL);
+    ibus_component_output_engines (component , str, 0);
+    g_object_unref (G_OBJECT (component));
+
+    output = g_string_free (str, FALSE);
+    g_print ("%s\n", output);
+    g_free (output);
+}
+
+int
+main (int argc, char **argv)
+{
+    GError *error = NULL;
+    GOptionContext *context;
+
+#ifdef ENABLE_NLS
+    setlocale (LC_ALL, "");
+#endif
+
+    g_type_init ();
+
+    context = g_option_context_new ("- ibus xkb engine component");
+
+    g_option_context_add_main_entries (context, entries, "ibus-xbl");
+
+    if (!g_option_context_parse (context, &argc, &argv, &error)) {
+        g_print ("Option parsing failed: %s\n", error->message);
+        exit (-1);
+    }
+
+    if (xml) {
+        print_component ();
+        return 0;
+    }
+    start_component (argc, argv);
+
+    return 0;
+}
diff --git a/xkb/ibus-engine-xkb-main.h b/xkb/ibus-engine-xkb-main.h
new file mode 100644
index 0000000..db31de9
--- /dev/null
+++ b/xkb/ibus-engine-xkb-main.h
@@ -0,0 +1,45 @@
+/* vim:set et sts=4: */
+/* bus - The Input Bus
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __IBUS_ENGINE_XKB_MAIN_H_
+#define __IBUS_ENGINE_XKB_MAIN_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <ibus.h>
+
+G_BEGIN_DECLS
+
+typedef struct _IBusXKBEngine IBusXKBEngine;
+typedef struct _IBusXKBEngineClass IBusXKBEngineClass;
+
+struct _IBusXKBEngine {
+    IBusEngine engine;
+};
+
+struct _IBusXKBEngineClass {
+    IBusEngineClass parent;
+};
+
+G_END_DECLS
+#endif
diff --git a/xkb/ibus-xkb-main.c b/xkb/ibus-xkb-main.c
new file mode 100644
index 0000000..971c4d9
--- /dev/null
+++ b/xkb/ibus-xkb-main.c
@@ -0,0 +1,82 @@
+/* vim:set et sts=4: */
+/* bus - The Input Bus
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this 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 get_layout = FALSE;
+static gchar *layout = NULL;
+
+static const GOptionEntry entries[] =
+{
+    { "get", 'g', 0, G_OPTION_ARG_NONE, &get_layout, N_("Get current xkb layout"), NULL },
+    /* Translators: the "layout" should not be translated due to a variable. */
+    { "set", 's', 0, G_OPTION_ARG_STRING, &layout, N_("Set xkb layout"), "layout" },
+    { NULL },
+};
+
+int
+main (int argc, char *argv[])
+{
+    GOptionContext *context;
+    GError *error = NULL;
+    Display *xdisplay;
+
+#ifdef ENABLE_NLS
+    setlocale (LC_ALL, "");
+
+    bindtextdomain (GETTEXT_PACKAGE, IBUS_LOCALEDIR);
+    bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+    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 (!g_option_context_parse (context, &argc, &argv, &error)) {
+        g_printerr ("Option parsing failed: %s\n", error->message);
+        return -1;
+    }
+
+    xdisplay = XOpenDisplay (NULL);
+    ibus_xkb_init (xdisplay);
+
+    if (layout) {
+        ibus_xkb_set_layout (layout, NULL, NULL);
+    }
+    if (get_layout) {
+        g_printf ("layout: %s\n", ibus_xkb_get_current_layout ());
+    }
+    return 0;
+}
diff --git a/xkb/xkblayout.xml.in b/xkb/xkblayout.xml.in
new file mode 100644
index 0000000..0b5a4dc
--- /dev/null
+++ b/xkb/xkblayout.xml.in
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<component>
+        <name>org.freedesktop.IBus.XKB</name>
+        <description>XKB Component</description>
+        <exec>@libexecdir@/ibus-engine-xkb --ibus</exec>
+        <version>0.0.0</version>
+        <author>Takao Fujiwara &lt;takao.fujiwara1@gmail.com&gt;</author>
+        <license>LGPL2.1</license>
+        <homepage>http://code.google.com/p/ibus/</homepage>
+        <textdomain>ibus</textdomain>
+        <observed-paths>
+                <path>@datadir@/ibus/xkb/xkblayoutconfig.xml</path>
+                <path>~/.config/ibus/xkb/xkblayoutconfig.xml</path>
+        </observed-paths>
+        <engines exec="@libexecdir@/ibus-engine-xkb --xml"/>
+</component>
diff --git a/xkb/xkblayoutconfig.xml.in b/xkb/xkblayoutconfig.xml.in
new file mode 100644
index 0000000..b1212d1
--- /dev/null
+++ b/xkb/xkblayoutconfig.xml.in
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xkblayout>
+  <config>
+    <preload_layouts>@XKB_PRELOAD_LAYOUTS@</preload_layouts>
+  </config>
+</xkblayout>
diff --git a/xkb/xkblib.c b/xkb/xkblib.c
new file mode 100644
index 0000000..5faeee7
--- /dev/null
+++ b/xkb/xkblib.c
@@ -0,0 +1,259 @@
+/* vim:set et sts=4: */
+/* bus - The Input Bus
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this 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 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;
+
+    if (XkbGetState (xdisplay, XkbUseCoreKbd, &state) != Success) {
+        g_warning ("Could not get state");
+        return;
+    }
+    default_layout_group = state.group;
+
+    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);
+}
+
+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);
+}
+
+gchar *
+ibus_xkb_get_current_layout (void)
+{
+    g_assert (default_layouts != NULL);
+
+    return g_strjoinv (",", (gchar **) default_layouts);
+}
+
+gboolean
+ibus_xkb_set_layout  (const char *layouts,
+                      const char *variants,
+                      const char *options)
+{
+    Display *xdisplay;
+    gboolean retval;
+    gchar *layouts_line;
+
+    g_assert (default_layouts != NULL);
+
+    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;
+}
diff --git a/xkb/xkblib.h b/xkb/xkblib.h
new file mode 100644
index 0000000..50a715a
--- /dev/null
+++ b/xkb/xkblib.h
@@ -0,0 +1,36 @@
+/* vim:set et sts=4: */
+/* bus - The Input Bus
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this 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);
+gchar           *ibus_xkb_get_current_layout     (void);
+gboolean         ibus_xkb_set_layout             (const char *layouts,
+                                                  const char *variants,
+                                                  const char *options);
+
+G_END_DECLS
+#endif
diff --git a/xkb/xkbxml.c b/xkb/xkbxml.c
new file mode 100644
index 0000000..ab53ae1
--- /dev/null
+++ b/xkb/xkbxml.c
@@ -0,0 +1,695 @@
+/* vim:set et sts=4: */
+/* bus - The Input Bus
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this 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 "xkbxml.h"
+#include "ibuscomponent.h"
+
+#ifndef XKB_RULES_XML_FILE
+#define XKB_RULES_XML_FILE "/usr/share/X11/xkb/rules/evdev.xml"
+#endif
+
+#define IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE(o)  \
+   (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryPrivate))
+#define IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE(o)  \
+   (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_XKB_LAYOUT_CONFIG, IBusXKBLayoutConfigPrivate))
+
+typedef struct _IBusXKBConfigRegistryPrivate IBusXKBConfigRegistryPrivate;
+typedef struct _IBusXKBLayoutConfigPrivate IBusXKBLayoutConfigPrivate;
+
+enum {
+    PROP_0,
+    PROP_SYSTEM_CONFIG_FILE,
+};
+
+struct _IBusXKBConfigRegistryPrivate {
+    GHashTable *layout_list;
+    GHashTable *layout_lang;
+    GHashTable *layout_desc;
+    GHashTable *variant_desc;
+};
+
+struct _IBusXKBLayoutConfigPrivate {
+    gchar *system_config_file;
+    GList *preload_layouts;
+};
+
+/* functions prototype */
+static void         ibus_xkb_config_registry_destroy
+                                           (IBusXKBConfigRegistry *xkb_config);
+static void         ibus_xkb_layout_config_destroy
+                                           (IBusXKBLayoutConfig *xkb_layout_config);
+
+G_DEFINE_TYPE (IBusXKBConfigRegistry, ibus_xkb_config_registry, IBUS_TYPE_OBJECT)
+G_DEFINE_TYPE (IBusXKBLayoutConfig, ibus_xkb_layout_config, IBUS_TYPE_OBJECT)
+
+static void
+parse_xkb_xml_languagelist_node (IBusXKBConfigRegistryPrivate *priv,
+                                 XMLNode *parent_node,
+                                 const gchar *layout_name)
+{
+    XMLNode *node = parent_node;
+    XMLNode *sub_node;
+    GList *p;
+    GList *lang_list = NULL;
+
+    g_assert (node != NULL);
+    g_assert (layout_name != NULL);
+    for (p = node->sub_nodes; p; p = p->next) {
+        sub_node = (XMLNode *) p->data;
+        if (g_strcmp0 (sub_node->name, "iso639Id") == 0) {
+            lang_list = g_list_append (lang_list,
+                                       (gpointer) g_strdup (sub_node->text));
+            continue;
+        }
+    }
+    if (lang_list == NULL) {
+        /* some nodes have no lang */
+        return;
+    }
+    if (g_hash_table_lookup (priv->layout_lang, layout_name) != NULL) {
+        g_warning ("duplicated name %s exists", layout_name);
+        return;
+    }
+    g_hash_table_insert (priv->layout_lang,
+                         (gpointer) g_strdup (layout_name),
+                         (gpointer) lang_list);
+}
+
+static const gchar *
+parse_xkb_xml_configitem_node (IBusXKBConfigRegistryPrivate *priv,
+                               XMLNode *parent_node)
+{
+    XMLNode *node = parent_node;
+    XMLNode *sub_node;
+    GList *p;
+    gchar *name = NULL;
+    gchar *description = NULL;
+
+    g_assert (node != NULL);
+    for (p = node->sub_nodes; p; p = p->next) {
+        sub_node = (XMLNode *) p->data;
+        if (g_strcmp0 (sub_node->name, "name") == 0) {
+            name = sub_node->text;
+            continue;
+        }
+        if (g_strcmp0 (sub_node->name, "description") == 0) {
+            description = sub_node->text;
+            continue;
+        }
+        if (g_strcmp0 (sub_node->name, "languageList") == 0) {
+            if (name == NULL) {
+                g_warning ("layout name is NULL in node %s", node->name);
+                continue;
+            }
+            parse_xkb_xml_languagelist_node (priv, sub_node, name);
+            continue;
+        }
+    }
+    if (name == NULL) {
+        g_warning ("No name in layout node");
+        return NULL;
+    }
+    if (g_hash_table_lookup (priv->layout_desc, name) != NULL) {
+        g_warning ("duplicated name %s exists", name);
+        return name;
+    }
+    g_hash_table_insert (priv->layout_desc,
+                         (gpointer) g_strdup (name),
+                         (gpointer) g_strdup (description));
+
+    return name;
+}
+
+static const gchar *
+parse_xkb_xml_variant_configitem_node (IBusXKBConfigRegistryPrivate *priv,
+                            XMLNode *parent_node,
+                            const gchar *layout_name)
+{
+    XMLNode *node = parent_node;
+    XMLNode *sub_node;
+    GList *p;
+    gchar *name = NULL;
+    gchar *description = NULL;
+    gchar *variant_lang_name = NULL;
+
+    g_assert (node != NULL);
+    g_assert (layout_name != NULL);
+    for (p = node->sub_nodes; p; p = p->next) {
+        sub_node = (XMLNode *) p->data;
+        if (g_strcmp0 (sub_node->name, "name") == 0) {
+            name = sub_node->text;
+            continue;
+        }
+        if (g_strcmp0 (sub_node->name, "description") == 0) {
+            description = sub_node->text;
+            continue;
+        }
+        if (g_strcmp0 (sub_node->name, "languageList") == 0) {
+            if (name == NULL) {
+                g_warning ("layout name is NULL in node %s", node->name);
+                continue;
+            }
+            variant_lang_name = g_strdup_printf ("%s(%s)", layout_name, name);
+            parse_xkb_xml_languagelist_node (priv, sub_node, variant_lang_name);
+            g_free (variant_lang_name);
+            continue;
+        }
+    }
+    if (name == NULL) {
+        g_warning ("No name in layout node");
+        return NULL;
+    }
+    if (g_hash_table_lookup (priv->variant_desc, name) != NULL) {
+        /* This is an expected case. */
+        return name;
+    }
+    g_hash_table_insert (priv->variant_desc,
+                         (gpointer) g_strdup (name),
+                         (gpointer) g_strdup (description));
+    return name;
+}
+
+static const gchar *
+parse_xkb_xml_variant_node (IBusXKBConfigRegistryPrivate *priv,
+                            XMLNode *parent_node,
+                            const gchar *layout_name)
+{
+    XMLNode *node = parent_node;
+    XMLNode *sub_node;
+    GList *p;
+    const gchar *variant_name = NULL;
+
+    g_assert (node != NULL);
+    g_assert (layout_name != NULL);
+    for (p = node->sub_nodes; p; p = p->next) {
+        sub_node = (XMLNode *) p->data;
+        if (g_strcmp0 (sub_node->name, "configItem") == 0) {
+            variant_name = parse_xkb_xml_variant_configitem_node (priv, sub_node, layout_name);
+            continue;
+        }
+    }
+    return variant_name;
+}
+
+static GList *
+parse_xkb_xml_variantlist_node (IBusXKBConfigRegistryPrivate *priv,
+                                XMLNode *parent_node,
+                                const gchar *layout_name,
+                                GList *variant_list)
+{
+    XMLNode *node = parent_node;
+    XMLNode *sub_node;
+    GList *p;
+    const gchar *variant_name = NULL;
+
+    g_assert (node != NULL);
+    g_assert (layout_name != NULL);
+    for (p = node->sub_nodes; p; p = p->next) {
+        sub_node = (XMLNode *) p->data;
+        if (g_strcmp0 (sub_node->name, "variant") == 0) {
+            variant_name = parse_xkb_xml_variant_node (priv, sub_node, layout_name);
+            if (variant_name != NULL) {
+                variant_list = g_list_append (variant_list,
+                                              (gpointer) g_strdup (variant_name));
+            }
+            continue;
+        }
+    }
+    return variant_list;
+}
+
+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 GList *
+parse_xkblayoutconfig_file (gchar *path)
+{
+    XMLNode *node = NULL;
+    XMLNode *sub_node;
+    XMLNode *sub_sub_node;
+    GList *p;
+    GList *retval = NULL;
+    gchar **array;
+    int i;
+
+    node = ibus_xml_parse_file (path);
+    if (node == NULL) {
+        return NULL;
+    }
+    if (g_strcmp0 (node->name, "xkblayout") != 0) {
+        ibus_xml_free (node);
+        return NULL;
+    }
+    for (p = node->sub_nodes; p != NULL; p = p->next) {
+        sub_node = (XMLNode *) p->data;
+        if (g_strcmp0 (sub_node->name, "config") == 0) {
+            GList *pp;
+            for (pp = sub_node->sub_nodes; pp != NULL; pp = pp->next) {
+                sub_sub_node = (XMLNode *) pp->data;
+                if  (g_strcmp0 (sub_sub_node->name, "preload_layouts") == 0) {
+                    if (sub_sub_node->text != NULL) {
+                        array = g_strsplit ((gchar *) sub_sub_node->text,
+                                            ",", -1);
+                        for (i = 0; array[i]; i++) {
+                            retval = g_list_append (retval, g_strdup (array[i]));
+                        }
+                        g_strfreev (array);
+                        break;
+                    }
+                }
+            }
+        }
+        if (retval != NULL) {
+            break;
+        }
+    }
+
+    ibus_xml_free (node);
+    return retval;
+}
+
+static void
+parse_xkb_layout_config (IBusXKBLayoutConfigPrivate *priv)
+{
+    gchar *basename;
+    gchar *user_config;
+    GList *list = NULL;
+
+    g_return_if_fail (priv->system_config_file != NULL);
+
+    basename = g_path_get_basename (priv->system_config_file);
+    user_config = g_build_filename (g_get_user_config_dir (),
+                                    "ibus", "xkb",
+                                    basename, NULL);
+    g_free (basename);
+    list = parse_xkblayoutconfig_file (user_config);
+    g_free (user_config);
+    if (list) {
+        priv->preload_layouts = list;
+        return;
+    }
+    list = parse_xkblayoutconfig_file (priv->system_config_file);
+    priv->preload_layouts = list;
+}
+
+static void
+ibus_xkb_config_registry_init (IBusXKBConfigRegistry *xkb_config)
+{
+    IBusXKBConfigRegistryPrivate *priv;
+    const gchar *file = XKB_RULES_XML_FILE;
+
+    priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config);
+    parse_xkb_config_registry_file (priv, file);
+}
+
+static void
+ibus_xkb_config_registry_destroy (IBusXKBConfigRegistry *xkb_config)
+{
+    IBusXKBConfigRegistryPrivate *priv;
+
+    g_return_if_fail (xkb_config != NULL);
+
+    priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config);
+
+    g_hash_table_destroy (priv->layout_list);
+    priv->layout_list = NULL;
+    g_hash_table_destroy (priv->layout_lang);
+    priv->layout_lang= NULL;
+    g_hash_table_destroy (priv->layout_desc);
+    priv->layout_desc= NULL;
+    g_hash_table_destroy (priv->variant_desc);
+    priv->variant_desc = NULL;
+
+    IBUS_OBJECT_CLASS(ibus_xkb_config_registry_parent_class)->destroy (IBUS_OBJECT (xkb_config));
+}
+
+static void
+ibus_xkb_config_registry_class_init (IBusXKBConfigRegistryClass *klass)
+{
+    IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
+
+    g_type_class_add_private (klass, sizeof (IBusXKBConfigRegistryPrivate));
+
+    ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_xkb_config_registry_destroy;
+}
+
+static void
+ibus_xkb_layout_config_init (IBusXKBLayoutConfig *xkb_layout_config)
+{
+    IBusXKBLayoutConfigPrivate *priv;
+
+    priv = IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE (xkb_layout_config);
+    priv->system_config_file = NULL;
+    priv->preload_layouts = NULL;
+}
+
+static GObject *
+ibus_xkb_layout_config_constructor (GType type,
+                                    guint n_construct_params,
+                                    GObjectConstructParam *construct_params)
+{
+    GObject *obj;
+    IBusXKBLayoutConfig *xkb_layout_config;
+    IBusXKBLayoutConfigPrivate *priv;
+
+    obj = G_OBJECT_CLASS (ibus_xkb_layout_config_parent_class)->constructor (type, n_construct_params, construct_params);
+    xkb_layout_config = IBUS_XKB_LAYOUT_CONFIG (obj);
+    priv = IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE (xkb_layout_config);
+    parse_xkb_layout_config (priv);
+
+    return obj;
+}
+
+static void
+ibus_xkb_layout_config_destroy (IBusXKBLayoutConfig *xkb_layout_config)
+{
+    IBusXKBLayoutConfigPrivate *priv;
+
+    g_return_if_fail (xkb_layout_config != NULL);
+
+    priv = IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE (xkb_layout_config);
+
+    g_free (priv->system_config_file);
+    priv->system_config_file = NULL;
+    free_lang_list (priv->preload_layouts);
+    priv->preload_layouts = NULL;
+}
+
+static void
+ibus_xkb_layout_config_set_property (IBusXKBLayoutConfig *xkb_layout_config,
+                                     guint                prop_id,
+                                     const GValue        *value,
+                                     GParamSpec          *pspec)
+{
+    IBusXKBLayoutConfigPrivate *priv;
+
+    g_return_if_fail (xkb_layout_config != NULL);
+    priv = IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE (xkb_layout_config);
+
+    switch (prop_id) {
+    case PROP_SYSTEM_CONFIG_FILE:
+        g_assert (priv->system_config_file == NULL);
+        priv->system_config_file = g_strdup (g_value_get_string (value));
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (xkb_layout_config, prop_id, pspec);
+    }
+}
+
+static void
+ibus_xkb_layout_config_get_property (IBusXKBLayoutConfig *xkb_layout_config,
+                                     guint                prop_id,
+                                     GValue              *value,
+                                     GParamSpec          *pspec)
+{
+    IBusXKBLayoutConfigPrivate *priv;
+
+    g_return_if_fail (xkb_layout_config != NULL);
+    priv = IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE (xkb_layout_config);
+
+    switch (prop_id) {
+    case PROP_SYSTEM_CONFIG_FILE:
+        g_value_set_string (value, priv->system_config_file);
+        break;
+    default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (xkb_layout_config, prop_id, pspec);
+
+    }
+}
+
+static void
+ibus_xkb_layout_config_class_init (IBusXKBLayoutConfigClass *klass)
+{
+    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+    IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
+
+    g_type_class_add_private (klass, sizeof (IBusXKBLayoutConfigPrivate));
+
+    gobject_class->constructor = ibus_xkb_layout_config_constructor;
+    gobject_class->set_property = (GObjectSetPropertyFunc) ibus_xkb_layout_config_set_property;
+    gobject_class->get_property = (GObjectGetPropertyFunc) ibus_xkb_layout_config_get_property;
+    ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_xkb_layout_config_destroy;
+
+    /**
+     * IBusProxy:interface:
+     *
+     * The interface of the proxy object.
+     */
+    g_object_class_install_property (gobject_class,
+                    PROP_SYSTEM_CONFIG_FILE,
+                    g_param_spec_string ("system_config_file",
+                        "system_config_file",
+                        "The system file of xkblayoutconfig",
+                        NULL,
+                        G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+IBusXKBConfigRegistry *
+ibus_xkb_config_registry_new (void)
+{
+    IBusXKBConfigRegistry *xkb_config;
+
+    xkb_config = IBUS_XKB_CONFIG_REGISTRY (g_object_new (IBUS_TYPE_XKB_CONFIG_REGISTRY, NULL));
+    return xkb_config;
+}
+
+#define TABLE_FUNC(field_name) const GHashTable *                       \
+ibus_xkb_config_registry_get_##field_name  (IBusXKBConfigRegistry *xkb_config) \
+{                                                                       \
+    IBusXKBConfigRegistryPrivate *priv;                                 \
+                                                                        \
+    g_return_val_if_fail (xkb_config != NULL, NULL);                    \
+    priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config);           \
+    return priv->field_name;                                            \
+}
+
+TABLE_FUNC (layout_list)
+TABLE_FUNC (layout_lang)
+TABLE_FUNC (layout_desc)
+TABLE_FUNC (variant_desc)
+
+#undef TABLE_FUNC
+
+IBusComponent *
+ibus_xkb_component_new (void)
+{
+    IBusComponent *component;
+
+    component = ibus_component_new ("org.freedesktop.IBus.XKB",
+                                    "XKB Component",
+                                    VERSION,
+                                    "LGPL2.1",
+                                    "Takao Fujiwara <takao.fujiwara1@gmail.com>",
+                                    "http://code.google.com/p/ibus/",
+                                    LIBEXECDIR "/ibus-engine-xkb --ibus",
+                                    GETTEXT_PACKAGE);
+
+    return component;
+}
+
+IBusEngineDesc *
+ibus_xkb_engine_desc_new (const gchar *lang,
+                          const gchar *layout,
+                          const gchar *layout_desc,
+                          const gchar *variant,
+                          const gchar *variant_desc)
+{
+    IBusEngineDesc *engine;
+    gchar *name = NULL;
+    gchar *longname = NULL;
+    gchar *desc = NULL;
+    gchar *engine_layout = NULL;
+
+    g_return_val_if_fail (lang != NULL && layout != NULL, NULL);
+
+    if (layout_desc && variant_desc) {
+        longname = g_strdup_printf ("%s - %s", layout_desc, variant_desc);
+    } else if (layout && variant) {
+        longname = g_strdup_printf ("%s - %s", layout, variant);
+    } else if (layout_desc) {
+        longname = g_strdup (layout_desc);
+    } else {
+        longname = g_strdup (layout);
+    }
+    if (variant) {
+        name = g_strdup_printf ("xkb:layout:%s:%s", layout, variant);
+        desc = g_strdup_printf ("XKB %s(%s) keyboard layout", layout, variant);
+        engine_layout = g_strdup_printf ("%s(%s)", layout, variant);
+    } else {
+        name = g_strdup_printf ("xkb:layout:%s", layout);
+        desc = g_strdup_printf ("XKB %s keyboard layout", layout);
+        engine_layout = g_strdup (layout);
+    }
+
+    engine = ibus_engine_desc_new (name,
+                                   longname,
+                                   desc,
+                                   lang,
+                                   "LGPL2.1",
+                                   "Takao Fujiwara <takao.fujiwara1@gmail.com>",
+                                   "ibus-engine",
+                                   engine_layout);
+
+    g_free (name);
+    g_free (longname);
+    g_free (desc);
+    g_free (engine_layout);
+
+    return engine;
+}
+
+IBusXKBLayoutConfig *
+ibus_xkb_layout_config_new (const gchar *system_config_file)
+{
+    IBusXKBLayoutConfig *xkb_layout_config;
+
+    xkb_layout_config = IBUS_XKB_LAYOUT_CONFIG (g_object_new (IBUS_TYPE_XKB_LAYOUT_CONFIG,
+                                                              "system_config_file",
+                                                              system_config_file,
+                                                              NULL));
+    return xkb_layout_config;
+}
+
+const GList *
+ibus_xkb_layout_config_get_preload_layouts (IBusXKBLayoutConfig *xkb_layout_config)
+{
+    IBusXKBLayoutConfigPrivate *priv;
+
+    g_return_val_if_fail (xkb_layout_config != NULL, NULL);
+    priv = IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE (xkb_layout_config);
+    return (const GList *) priv->preload_layouts;
+}
diff --git a/xkb/xkbxml.h b/xkb/xkbxml.h
new file mode 100644
index 0000000..0ba04d1
--- /dev/null
+++ b/xkb/xkbxml.h
@@ -0,0 +1,188 @@
+/* vim:set et sts=4: */
+/* bus - The Input Bus
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
+ * Copyright (C) 2008-2010 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __IBUS_XKB_H_
+#define __IBUS_XKB_H_
+
+#include "ibuscomponent.h"
+
+/*
+ * Type macros.
+ */
+/* define IBusXKBConfigRegistry macros */
+#define IBUS_TYPE_XKB_CONFIG_REGISTRY                   \
+    (ibus_xkb_config_registry_get_type ())
+#define IBUS_XKB_CONFIG_REGISTRY(obj)                   \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistry))
+#define IBUS_XKB_CONFIG_REGISTRY_CLASS(klass)           \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryClass))
+#define IBUS_IS_XKB_CONFIG_REGISTRY(obj)                \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY))
+#define IBUS_IS_XKB_CONFIG_REGISTRY_CLASS(klass)        \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_XKB_CONFIG_REGISTRY))
+#define IBUS_XKB_CONFIG_REGISTRY_GET_CLASS(obj)         \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryClass))
+
+/* define IBusXKBLayoutConfig macros */
+#define IBUS_TYPE_XKB_LAYOUT_CONFIG                     \
+    (ibus_xkb_layout_config_get_type ())
+#define IBUS_XKB_LAYOUT_CONFIG(obj)                     \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), IBUS_TYPE_XKB_LAYOUT_CONFIG, IBusXKBLayoutConfig))
+#define IBUS_XKB_LAYOUT_CONFIG_CLASS(klass)             \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), IBUS_TYPE_XKB_LAYOUT_CONFIG, IBusXKBLayoutConfigClass))
+#define IBUS_IS_XKB_LAYOUT_CONFIG(obj)                  \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IBUS_TYPE_XKB_LAYOUT_CONFIG))
+#define IBUS_IS_XKB_LAYOUT_CONFIG_CLASS(klass)          \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_XKB_LAYOUT_CONFIG))
+#define IBUS_XKB_LAYOUT_CONFIG_GET_CLASS(obj)           \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), IBUS_TYPE_XKB_LAYOUT_CONFIG, IBusXKBLayoutConfigClass))
+
+G_BEGIN_DECLS
+
+typedef struct _IBusXKBConfigRegistry IBusXKBConfigRegistry;
+typedef struct _IBusXKBConfigRegistryClass IBusXKBConfigRegistryClass;
+typedef struct _IBusXKBLayoutConfig IBusXKBLayoutConfig;
+typedef struct _IBusXKBLayoutConfigClass IBusXKBLayoutConfigClass;
+
+struct _IBusXKBConfigRegistry {
+    IBusObject parent;
+};
+
+struct _IBusXKBConfigRegistryClass {
+    IBusObjectClass parent;
+    /* signals */
+    /*< private >*/
+    /* padding */
+    gpointer pdummy[8];
+};
+
+struct _IBusXKBLayoutConfig {
+    IBusObject parent;
+};
+
+struct _IBusXKBLayoutConfigClass {
+    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:
+ * @xkb_config: An IBusXKBConfigRegistry.
+ * @returns: A const GHashTable
+ *
+ * a const GHashTable
+ */
+const GHashTable *
+                 ibus_xkb_config_registry_get_layout_list
+                                                 (IBusXKBConfigRegistry *xkb_config);
+/**
+ * ibus_xkb_config_registry_get_layout_lang:
+ * @xkb_config: An IBusXKBConfigRegistry.
+ * @returns: A const GHashTable
+ *
+ * a const GHashTable
+ */
+const GHashTable *
+                 ibus_xkb_config_registry_get_layout_lang
+                                                 (IBusXKBConfigRegistry *xkb_config);
+/**
+ * ibus_xkb_config_registry_get_layout_desc:
+ * @xkb_config: An IBusXKBConfigRegistry.
+ * @returns: A const GHashTable
+ *
+ * a const GHashTable
+ */
+const GHashTable *
+                 ibus_xkb_config_registry_get_layout_desc
+                                                 (IBusXKBConfigRegistry *xkb_config);
+/**
+ * ibus_xkb_config_registry_get_variant_desc:
+ * @xkb_config: An IBusXKBConfigRegistry.
+ * @returns: A const GHashTable
+ *
+ * a const GHashTable
+ */
+const GHashTable *
+                 ibus_xkb_config_registry_get_variant_desc
+                                                 (IBusXKBConfigRegistry *xkb_config);
+/**
+ * ibus_xkb_component_new:
+ * @returns: A newly allocated IBusComponent.
+ *
+ * New an IBusComponent.
+ */
+IBusComponent   *ibus_xkb_component_new          (void);
+
+/**
+ * ibus_xkb_engine_desc_new:
+ * @lang: Language (e.g. zh, jp) supported by this input method engine.
+ * @layout: Keyboard layout
+ * @layout_desc: Keyboard layout description for engine description
+ * @variant: Keyboard variant
+ * @variant_desc: Keyboard variant description for engine description
+ * @returns: A newly allocated IBusEngineDesc.
+ *
+ * New a IBusEngineDesc.
+ */
+IBusEngineDesc  *ibus_xkb_engine_desc_new        (const gchar *lang,
+                                                  const gchar *layout,
+                                                  const gchar *layout_desc,
+                                                  const gchar *variant,
+                                                  const gchar *variant_desc);
+
+GType            ibus_xkb_layout_config_get_type (void);
+
+/**
+ * ibus_xkb_layout_config_new:
+ * @returns: A newly allocated IBusXKBLayoutConfig
+ *
+ * New an IBusXKBLayoutConfig
+ */
+IBusXKBLayoutConfig *
+                 ibus_xkb_layout_config_new      (const gchar *system_config_file);
+
+/**
+ * ibus_xkb_layout_config_get_preload_layouts:
+ * @xkb_layout_config: An IBusXKBLayoutConfig.
+ * @returns: A const GList
+ *
+ * a const GList
+ */
+const GList *    ibus_xkb_layout_config_get_preload_layouts
+                                                 (IBusXKBLayoutConfig *xkb_layout_config);
+
+G_END_DECLS
+#endif
-- 
1.7.2.1