[ibus/f14/master] Update to 1.3.7

Takao Fujiwara fujiwara at fedoraproject.org
Mon Aug 23 03:40:00 UTC 2010


commit 0dd0fd00f1f322b3dedae0355ab645674830c56f
Author: Takao Fujiwara <tfujiwar at redhat.com>
Date:   Mon Aug 23 12:18:36 2010 +0900

    Update to 1.3.7

 .gitignore            |    1 +
 ibus-541492-xkb.patch | 3360 +++++++++++++++++++++++++++++++++++++++++++++++++
 ibus-HEAD.patch       |   51 -
 ibus.spec             |   30 +-
 sources               |    2 +-
 5 files changed, 3388 insertions(+), 56 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index 26f0647..e7fcc74 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
 ibus-1.3.6.tar.gz
+/ibus-1.3.7.tar.gz
diff --git a/ibus-541492-xkb.patch b/ibus-541492-xkb.patch
new file mode 100644
index 0000000..13ccfc6
--- /dev/null
+++ b/ibus-541492-xkb.patch
@@ -0,0 +1,3360 @@
+From a3819467deea74b82c55a4cfc8cecd6285f54e00 Mon Sep 17 00:00:00 2001
+From: fujiwarat <takao.fujiwara1 at 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 at gmail.com>
++# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang at gmail.com>
++# Copyright (c) 2007-2010 Red Hat, Inc.
++#
++# This library is free software; you can redistribute it and/or
++# modify it under the terms of the GNU Lesser General Public
++# License as published by the Free Software Foundation; either
++# version 2 of the License, or (at your option) any later version.
++#
++# This library is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU Lesser General Public License for more details.
++#
++# You should have received a copy of the GNU Lesser General Public
++# License along with this program; if not, write to the
++# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
++# Boston, MA  02111-1307  USA
++
++__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 at gmail.com>
++# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang at gmail.com>
++# Copyright (c) 2007-2010 Red Hat, Inc.
++#
++# This library is free software; you can redistribute it and/or
++# modify it under the terms of the GNU Lesser General Public
++# License as published by the Free Software Foundation; either
++# version 2 of the License, or (at your option) any later version.
++#
++# This library is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU Lesser General Public License for more details.
++#
++# You should have received a copy of the GNU Lesser General Public
++# License along with this program; if not, write to the
++# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
++# Boston, MA  02111-1307  USA
++
++__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 at 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 at gmail.com>
++# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang at gmail.com>
++# Copyright (c) 2007-2010 Red Hat, Inc.
++#
++# This library is free software; you can redistribute it and/or
++# modify it under the terms of the GNU Lesser General Public
++# License as published by the Free Software Foundation; either
++# version 2 of the License, or (at your option) any later version.
++#
++# This library is distributed in the hope that it will be useful,
++# but WITHOUT ANY WARRANTY; without even the implied warranty of
++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++# GNU Lesser General Public License for more details.
++#
++# You should have received a copy of the GNU Lesser General Public
++# License along with this program; if not, write to the
++# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
++# Boston, MA  02111-1307  USA
++
++libibus = $(top_builddir)/src/libibus.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 at gmail.com>
++ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at 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 at 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 at gmail.com>
++ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at 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 at gmail.com>
++ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at 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 at 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 at gmail.com>
++ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at 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 at gmail.com>
++ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at 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 at gmail.com>
++ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at 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 at 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 at 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 at gmail.com>
++ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang at 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
+
diff --git a/ibus-HEAD.patch b/ibus-HEAD.patch
index 396ac1b..8b13789 100644
--- a/ibus-HEAD.patch
+++ b/ibus-HEAD.patch
@@ -1,52 +1 @@
-commit 674bc53c30c8ac40e021da660f2af533ab015587
-Author: Daiki Ueno <ueno at unixuser.org>
-Date:   Wed Jun 30 12:05:32 2010 +0900
 
-    Fix "Show language panel: Embedded in menu" behavior.
-    
-    Signed-off-by: Daiki Ueno <ueno at unixuser.org>
-
-diff --git a/ui/gtk/languagebar.py b/ui/gtk/languagebar.py
-index f22080f..2fc1cb7 100644
---- a/ui/gtk/languagebar.py
-+++ b/ui/gtk/languagebar.py
-@@ -29,6 +29,7 @@ from handle import Handle
- from menu import menu_position,\
-     ImageMenuItem,\
-     Menu,\
-+    CheckMenuItem,\
-     RadioMenuItem,\
-     SeparatorMenuItem
- from engineabout import EngineAbout
-@@ -378,6 +379,8 @@ class LanguageBar(gtk.Toolbar):
-                 item = ImageMenuItem(prop = prop)
-                 self.__set_item_icon(item, prop)
-             elif prop.type == ibus.PROP_TYPE_TOGGLE:
-+                item = CheckMenuItem(prop = prop)
-+            elif prop.type == ibus.PROP_TYPE_RADIO:
-                 item = RadioMenuItem(radio_group, prop = prop)
-                 radio_group = item
-             elif prop.type == ibus.PROP_TYPE_SEPARATOR:
-diff --git a/ui/gtk/menu.py b/ui/gtk/menu.py
-index b9a6b44..53fa39f 100644
---- a/ui/gtk/menu.py
-+++ b/ui/gtk/menu.py
-@@ -59,7 +59,7 @@ class Menu(gtk.Menu, PropItem):
-                 item = SeparatorMenuItem()
-                 radio_group = None
-             elif prop.type == ibus.PROP_TYPE_MENU:
--                item = gtk.ImageMenuItem()
-+                item = ImageMenuItem(prop)
-                 if prop.icon:
-                     size = gtk.icon_size_lookup(gtk.ICON_SIZE_MENU)
-                     item.set_image(icon.IconWidget(prop.icon, size[0]))
-@@ -238,6 +238,9 @@ class SeparatorMenuItem(gtk.SeparatorMenuItem, PropItem):
-        (gobject.TYPE_STRING, gobject.TYPE_INT)),
-     }
- 
-+    def __init__(self):
-+        gtk.SeparatorMenuItem.__init__(self)
-+        PropItem.__init__(self, None)
- 
- 
- def menu_position(menu, button):
diff --git a/ibus.spec b/ibus.spec
index a9843d0..484b094 100644
--- a/ibus.spec
+++ b/ibus.spec
@@ -2,21 +2,24 @@
 %{!?gtk2_binary_version: %define gtk2_binary_version %(pkg-config  --variable=gtk_binary_version gtk+-2.0)}
 %{!?gtk3_binary_version: %define gtk3_binary_version %(pkg-config  --variable=gtk_binary_version gtk+-3.0)}
 
+%define have_libxkbfile 1
+
 %define glib_ver %([ -a %{_libdir}/pkgconfig/glib-2.0.pc ] && pkg-config --modversion glib-2.0 | cut -d. -f 1,2 || echo -n "999")
 %define gconf2_version 2.12.0
 %define dbus_python_version 0.83.0
 %define im_chooser_version 1.2.5
 
 Name:       ibus
-Version:    1.3.6
-Release:    5%{?dist}
+Version:    1.3.7
+Release:    1%{?dist}
 Summary:    Intelligent Input Bus for Linux OS
 License:    LGPLv2+
 Group:      System Environment/Libraries
 URL:        http://code.google.com/p/ibus/
 Source0:    http://ibus.googlecode.com/files/%{name}-%{version}.tar.gz
 Source1:    xinput-ibus
-Patch0:     ibus-HEAD.patch
+# Patch0:     ibus-HEAD.patch
+Patch1:     ibus-541492-xkb.patch
 
 BuildRoot:  %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
@@ -35,6 +38,9 @@ BuildRequires:  GConf2-devel
 BuildRequires:  pygobject2-devel
 BuildRequires:  intltool
 BuildRequires:  iso-codes-devel
+%if %have_libxkbfile
+BuildRequires:  libxkbfile-devel
+%endif
 
 Requires:   %{name}-libs = %{version}-%{release}
 Requires:   %{name}-gtk2 = %{version}-%{release}
@@ -117,9 +123,18 @@ The ibus-devel-docs package contains developer documentation for ibus
 
 %prep
 %setup -q
-%patch0 -p1
+# %patch0 -p1
+%if %have_libxkbfile
+%patch1 -p1 -b .xkb
+%endif
 
 %build
+%if %have_libxkbfile
+aclocal -I m4
+autoheader
+autoconf -f
+automake -a -c -f
+%endif
 %configure \
     --disable-static \
     --enable-gtk2 \
@@ -223,6 +238,10 @@ fi
 # %{_sysconfdir}/xdg/autostart/ibus.desktop
 %{_sysconfdir}/gconf/schemas/ibus.schemas
 %config %{_xinputconf}
+%if %have_libxkbfile
+%{_libexecdir}/ibus-engine-xkb
+%{_libexecdir}/ibus-xkb
+%endif
 
 %files libs
 %defattr(-,root,root,-)
@@ -250,6 +269,9 @@ fi
 %{_datadir}/gtk-doc/html/*
 
 %changelog
+* Mon Aug 23 2010 Takao Fujiwara <tfujiwar at redhat.com> - 1.3.7-1
+- Update to 1.3.7
+
 * Wed Jul 28 2010 Mamoru Tasaka <mtasaka at ioa.s.u-tokyo.ac.jp> - 1.3.6-5
 - Rebuild against python 2.7
 
diff --git a/sources b/sources
index 34df577..48076a8 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-8380b51bcf53220dff947a1deb33fd95  ibus-1.3.6.tar.gz
+5a2acbda6cad23f6403c88347ac60e2d  ibus-1.3.7.tar.gz


More information about the scm-commits mailing list