[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.</i></small></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.</i></small></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 <takao.fujiwara1 at gmail.com></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