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 +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 @@ + + + ++ /schemas/desktop/ibus/general/default_system_layout ++ /desktop/ibus/general/default_system_layout ++ ibus ++ string ++ default ++ ibus ++ ++ Set default keyboard layout ++ Override default system keyboard layout. default is 'default' ++ ++ ++ ++ /schemas/desktop/ibus/general/xkb_latin_layouts ++ /desktop/ibus/general/xkb_latin_layouts ++ ibus ++ list ++ string ++ [ara,bg,cz,dev,gr,gur,in,mal,mkd,ru,ua] ++ ++ Latin layout which have no ASCII ++ us layout is appended to the latin layouts. variant is not needed. ++ ++ ++ + /schemas/desktop/ibus/panel/use_custom_font + /desktop/ibus/panel/use_custom_font + ibus +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 ++# Copyright (c) 2007-2010 Peng Huang ++# 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 ++# Copyright (c) 2007-2010 Peng Huang ++# 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 ", ++ "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 @@ + + + True +- False + The shortcut keys for switching to previous input method in the list + 0 + Previous input method: +@@ -216,7 +215,6 @@ + + + True +- False + True + False + +@@ -228,7 +226,6 @@ + + ... + True +- False + True + False + True +@@ -550,6 +547,7 @@ + vertical + 5 + start ++ True + + + gtk-add +@@ -630,6 +628,22 @@ + 4 + + ++ ++ ++ Configure _Layouts ++ True ++ False ++ True ++ True ++ Configure keyboard layouts ++ True ++ ++ ++ False ++ False ++ 5 ++ ++ + + + +@@ -729,6 +743,7 @@ You may use up/down buttons to change it.</i></small> + True + vertical + 6 ++ True + + + Use system keyboard layout +@@ -744,6 +759,43 @@ You may use up/down buttons to change it.</i></small> + 0 + + ++ ++ ++ True ++ 6 ++ ++ ++ True ++ System Layout: ++ True ++ center ++ ++ ++ False ++ False ++ 0 ++ ++ ++ ++ ++ ++ True ++ True ++ False ++ ++ ++ False ++ False ++ 1 ++ ++ ++ ++ ++ False ++ False ++ 1 ++ ++ + + + +@@ -942,4 +994,246 @@ Homepage: http://code.google.com/p/ibus + + + ++ ++ Layouts Setup ++ ibus-setup ++ ++ ++ vertical ++ True ++ 10 ++ 12 ++ ++ ++ True ++ 2 ++ 2 ++ 12 ++ 6 ++ ++ ++ True ++ Add Layout: ++ Add layout ++ 0 ++ ++ ++ GTK_FILL ++ GTK_FILL ++ ++ ++ ++ ++ True ++ ++ ++ True ++ ++ ++ ++ ++ 1 ++ 2 ++ GTK_FILL ++ GTK_FILL ++ ++ ++ ++ ++ True ++ Remove Layout: ++ Remove layout ++ 0 ++ ++ ++ 1 ++ 2 ++ GTK_FILL ++ GTK_FILL ++ ++ ++ ++ ++ True ++ ++ ++ True ++ ++ ++ ++ ++ 1 ++ 2 ++ 1 ++ 2 ++ GTK_FILL ++ GTK_FILL ++ ++ ++ ++ ++ False ++ 0 ++ ++ ++ ++ ++ True ++ True ++ end ++ ++ ++ gtk-cancel ++ True ++ True ++ ++ ++ False ++ False ++ 0 ++ ++ ++ ++ ++ gtk-ok ++ True ++ True ++ True ++ ++ ++ False ++ False ++ 1 ++ ++ ++ ++ ++ False ++ False ++ end ++ 1 ++ ++ ++ ++ ++ ++ ++ Default System Layout Setup ++ ibus-setup ++ ++ ++ vertical ++ True ++ 10 ++ 12 ++ ++ ++ True ++ 2 ++ 2 ++ 12 ++ 6 ++ ++ ++ True ++ Choose From: ++ choose default keyboard from list ++ ++ ++ GTK_FILL ++ GTK_FILL ++ ++ ++ ++ ++ True ++ ++ ++ True ++ ++ ++ ++ ++ 1 ++ 2 ++ GTK_FILL ++ GTK_FILL ++ ++ ++ ++ ++ True ++ Manual Type: ++ Type default keyboard layout by manual (comma-separated values) ++ radiobutton_combobox_default_system_layout ++ ++ ++ 1 ++ 2 ++ GTK_FILL ++ GTK_FILL ++ ++ ++ ++ ++ True ++ True ++ True ++ ++ ++ 1 ++ 2 ++ 1 ++ 2 ++ GTK_FILL ++ GTK_FILL ++ ++ ++ ++ ++ False ++ 0 ++ ++ ++ ++ ++ True ++ True ++ end ++ ++ ++ gtk-cancel ++ True ++ True ++ ++ ++ False ++ False ++ 0 ++ ++ ++ ++ ++ gtk-ok ++ True ++ True ++ True ++ ++ ++ False ++ False ++ 1 ++ ++ ++ ++ ++ False ++ False ++ end ++ 1 ++ ++ ++ ++ ++ + +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 ++# Copyright (c) 2007-2010 Peng Huang ++# 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 ++ * Copyright (C) 2008-2010 Peng Huang ++ * 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 ++#endif ++ ++#include ++#include ++#include ++ ++#ifdef ENABLE_NLS ++#include ++#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 ", ++ "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 ++ * Copyright (C) 2008-2010 Peng Huang ++ * 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 ++#endif ++ ++#include ++ ++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 ++ * Copyright (C) 2008-2010 Peng Huang ++ * 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 ++#endif ++ ++#include ++#include ++#include ++#include ++ ++#ifdef ENABLE_NLS ++#include ++#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 @@ ++ ++ ++ org.freedesktop.IBus.XKB ++ XKB Component ++ @libexecdir@/ibus-engine-xkb --ibus ++ 0.0.0 ++ Takao Fujiwara <takao.fujiwara1@gmail.com> ++ LGPL2.1 ++ http://code.google.com/p/ibus/ ++ ibus ++ ++ @datadir@/ibus/xkb/xkblayoutconfig.xml ++ ~/.config/ibus/xkb/xkblayoutconfig.xml ++ ++ ++ +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 @@ ++ ++ ++ ++ @XKB_PRELOAD_LAYOUTS@ ++ ++ +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 ++ * Copyright (C) 2008-2010 Peng Huang ++ * 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 ++#endif ++ ++#include ++#include ++#include ++#include ++#include /* for XKBrules.h */ ++#include ++#include ++#include ++ ++#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 ++ * Copyright (C) 2008-2010 Peng Huang ++ * 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 ++ ++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 ++ * Copyright (C) 2008-2010 Peng Huang ++ * 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 ++#endif ++ ++#include ++ ++#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 ", ++ "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 ", ++ "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 ++ * Copyright (C) 2008-2010 Peng Huang ++ * 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 -Date: Wed Jun 30 12:05:32 2010 +0900 - Fix "Show language panel: Embedded in menu" behavior. - - Signed-off-by: Daiki Ueno - -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 - 1.3.7-1 +- Update to 1.3.7 + * Wed Jul 28 2010 Mamoru Tasaka - 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