4234 lines
162 KiB
Diff
4234 lines
162 KiB
Diff
From 245b932b2a72bd23ab8f40ec624184da7ad53b8d Mon Sep 17 00:00:00 2001
|
|
From: fujiwarat <takao.fujiwara1@gmail.com>
|
|
Date: Fri, 4 Feb 2011 19:48:10 +0900
|
|
Subject: [PATCH] Add XKB layouts
|
|
|
|
---
|
|
Makefile.am | 7 +
|
|
configure.ac | 53 ++++
|
|
data/ibus.schemas.in | 36 +++
|
|
ibus/Makefile.am | 26 ++
|
|
ibus/__init__.py | 2 +
|
|
ibus/bus.py | 3 +
|
|
ibus/interface/iibus.py | 3 +
|
|
ibus/xkblayout.py.in | 225 ++++++++++++++
|
|
ibus/xkbxml.py.in | 412 ++++++++++++++++++++++++++
|
|
setup/Makefile.am | 1 +
|
|
setup/enginecombobox.py | 7 +-
|
|
setup/main.py | 3 +
|
|
setup/setup.ui | 609 ++++++++++++++++++++++++++++++++++++++-
|
|
setup/xkbsetup.py | 451 ++++++++++++++++++++++++++++
|
|
src/ibusfactory.c | 21 ++-
|
|
src/ibusfactory.h | 5 +-
|
|
ui/gtk/panel.py | 39 +++
|
|
xkb/Makefile.am | 104 +++++++
|
|
xkb/ibus-engine-xkb-main.c | 397 +++++++++++++++++++++++++
|
|
xkb/ibus-engine-xkb-main.h | 46 +++
|
|
xkb/ibus-xkb-main.c | 105 +++++++
|
|
xkb/xkblayout.xml.in | 16 +
|
|
xkb/xkblayoutconfig.xml.in | 6 +
|
|
xkb/xkblib.c | 297 +++++++++++++++++++
|
|
xkb/xkblib.h | 40 +++
|
|
xkb/xkbxml.c | 696 ++++++++++++++++++++++++++++++++++++++++++++
|
|
xkb/xkbxml.h | 189 ++++++++++++
|
|
27 files changed, 3793 insertions(+), 6 deletions(-)
|
|
create mode 100644 ibus/xkblayout.py.in
|
|
create mode 100644 ibus/xkbxml.py.in
|
|
create mode 100644 setup/xkbsetup.py
|
|
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 02b7163..6cbe82a 100644
|
|
--- a/Makefile.am
|
|
+++ b/Makefile.am
|
|
@@ -42,6 +42,12 @@ DAEMON_DIRS = \
|
|
$(NULL)
|
|
endif
|
|
|
|
+if ENABLE_XKB
|
|
+XKB_DIRS = \
|
|
+ xkb \
|
|
+ $(NULL)
|
|
+endif
|
|
+
|
|
if ENABLE_MEMCONF
|
|
MEMCONF_DIRS = \
|
|
memconf \
|
|
@@ -60,6 +66,7 @@ SUBDIRS = \
|
|
$(DAEMON_DIRS) \
|
|
$(PYTHON_DIRS) \
|
|
$(GCONF_DIRS) \
|
|
+ $(XKB_DIRS) \
|
|
$(MEMCONF_DIRS) \
|
|
$(NULL)
|
|
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 0c06fbc..8667510 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -185,6 +185,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,ara,az,ba,bd,be,bg,br,bt,by,"\
|
|
+"de,dk,ca,ch,cn(tib),cz,ee,epo,es,et,fi,fo,fr,"\
|
|
+"gb,ge,ge(dsb),ge(ru),ge(os),gh,gh(akan),gh(ewe),gh(fula),gh(ga),gh(hausa),"\
|
|
+"gn,gr,hu,hr,ie,ie(CloGaelach),il,"\
|
|
+"in,in(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,"\
|
|
+"kg,kh,kz,la,latam,lk,lk(tam_unicode),lt,lv,ma,ma(tifinagh),mal,mao,"\
|
|
+"me,mk,mm,mt,mv,ng,ng(hausa),ng,ng(igbo),ng(yoruba),nl,no,no(smi),np,"\
|
|
+"pk,pl,pl(csb),pt,ro,rs,ru,ru(cv),ru(kom),ru(sah),ru(tt),ru(xal),"\
|
|
+"se,si,sk,sy,sy(ku),th,tj,tr,ua,uz,vn"]
|
|
+)
|
|
+AC_SUBST(XKB_PRELOAD_LAYOUTS)
|
|
+
|
|
# GObject introspection
|
|
GOBJECT_INTROSPECTION_CHECK([0.6.8])
|
|
|
|
@@ -427,6 +478,7 @@ gconf/Makefile
|
|
gconf/gconf.xml.in
|
|
bindings/Makefile
|
|
bindings/vala/Makefile
|
|
+xkb/Makefile
|
|
])
|
|
|
|
AC_OUTPUT
|
|
@@ -442,6 +494,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 aa66aa5..54709ce 100644
|
|
--- a/data/ibus.schemas.in
|
|
+++ b/data/ibus.schemas.in
|
|
@@ -167,6 +167,42 @@
|
|
</locale>
|
|
</schema>
|
|
<schema>
|
|
+ <key>/schemas/desktop/ibus/general/system_keyboard_layout</key>
|
|
+ <applyto>/desktop/ibus/general/system_keyboard_layout</applyto>
|
|
+ <owner>ibus</owner>
|
|
+ <type>string</type>
|
|
+ <default>default</default>
|
|
+ <gettext_domain>ibus</gettext_domain>
|
|
+ <locale name="C">
|
|
+ <short>Set system keyboard layout</short>
|
|
+ <long>Override default system keyboard layout. default is 'default'</long>
|
|
+ </locale>
|
|
+ </schema>
|
|
+ <schema>
|
|
+ <key>/schemas/desktop/ibus/general/system_keyboard_option</key>
|
|
+ <applyto>/desktop/ibus/general/system_keyboard_option</applyto>
|
|
+ <owner>ibus</owner>
|
|
+ <type>string</type>
|
|
+ <default>default</default>
|
|
+ <gettext_domain>ibus</gettext_domain>
|
|
+ <locale name="C">
|
|
+ <short>Set system keyboard option</short>
|
|
+ <long>Override default system keyboard option. default is 'default'</long>
|
|
+ </locale>
|
|
+ </schema>
|
|
+ <schema>
|
|
+ <key>/schemas/desktop/ibus/general/xkb_latin_layouts</key>
|
|
+ <applyto>/desktop/ibus/general/xkb_latin_layouts</applyto>
|
|
+ <owner>ibus</owner>
|
|
+ <type>list</type>
|
|
+ <list_type>string</list_type>
|
|
+ <default>[ara,bg,cz,dev,gr,gur,in,jp(kana),mal,mkd,ru,ua]</default>
|
|
+ <locale name="C">
|
|
+ <short>Latin layout which have no ASCII</short>
|
|
+ <long>us layout is appended to the latin layouts. variant is not needed.</long>
|
|
+ </locale>
|
|
+ </schema>
|
|
+ <schema>
|
|
<key>/schemas/desktop/ibus/panel/use_custom_font</key>
|
|
<applyto>/desktop/ibus/panel/use_custom_font</applyto>
|
|
<owner>ibus</owner>
|
|
diff --git a/ibus/Makefile.am b/ibus/Makefile.am
|
|
index d1cd750..7f8590c 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..7685776
|
|
--- /dev/null
|
|
+++ b/ibus/xkblayout.py.in
|
|
@@ -0,0 +1,225 @@
|
|
+# vim:set et sts=4 sw=4:
|
|
+#
|
|
+# ibus - The Input Bus
|
|
+#
|
|
+# Copyright (c) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
|
|
+# Copyright (c) 2007-2010 Red Hat, Inc.
|
|
+#
|
|
+# This library is free software; you can redistribute it and/or
|
|
+# modify it under the terms of the GNU Lesser General Public
|
|
+# License as published by the Free Software Foundation; either
|
|
+# version 2 of the License, or (at your option) any later version.
|
|
+#
|
|
+# This library is distributed in the hope that it will be useful,
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+# GNU Lesser General Public License for more details.
|
|
+#
|
|
+# You should have received a copy of the GNU Lesser General Public
|
|
+# License along with this program; if not, write to the
|
|
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
+# Boston, MA 02111-1307 USA
|
|
+
|
|
+__all__ = (
|
|
+ "XKBLayout",
|
|
+ )
|
|
+
|
|
+import os, sys, time
|
|
+
|
|
+XKB_COMMAND = @XKB_COMMAND@
|
|
+XKB_SESSION_TIME_OUT = 30.0
|
|
+
|
|
+class XKBLayout():
|
|
+ def __init__(self, config = None, command=XKB_COMMAND):
|
|
+ self.__config = config
|
|
+ self.__command = command
|
|
+ self.__use_xkb = True
|
|
+ if self.__command == None:
|
|
+ self.__use_xkb = False
|
|
+ self.__default_layout = self.get_layout()
|
|
+ self.__default_model = self.get_model()
|
|
+ self.__default_option = self.get_option()
|
|
+ self.__time_lag_session_xkb_layout = True
|
|
+ self.__time_lag_session_xkb_option = True
|
|
+ self.__time_lag_session_xkb_timer = time.time()
|
|
+ self.__xkb_latin_layouts = []
|
|
+ if config != None:
|
|
+ self.__xkb_latin_layouts = list(self.__config.get_value("general",
|
|
+ "xkb_latin_layouts",
|
|
+ []))
|
|
+
|
|
+
|
|
+ def __get_model_from_layout(self, layout):
|
|
+ layout_array = layout.split(',')
|
|
+ option_array = []
|
|
+ is_bracket = False
|
|
+ for i, l in enumerate(layout_array):
|
|
+ option_array.append("")
|
|
+ left_bracket = l.find('(')
|
|
+ right_bracket = l.find(')')
|
|
+ if left_bracket >= 0 and right_bracket > left_bracket:
|
|
+ is_bracket = True
|
|
+ layout_array[i] = l[:left_bracket]
|
|
+ option_array[i] = l[left_bracket + 1:right_bracket]
|
|
+ if is_bracket == False:
|
|
+ return (layout, "default")
|
|
+ layout = ','.join(layout_array)
|
|
+ option = ','.join(option_array)
|
|
+ return (layout, option)
|
|
+
|
|
+ def use_xkb(self, enable):
|
|
+ if self.__command == None:
|
|
+ return
|
|
+ self.__use_xkb = enable
|
|
+
|
|
+ def get_layout(self):
|
|
+ if not self.__use_xkb:
|
|
+ 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 get_model(self):
|
|
+ if not self.__use_xkb:
|
|
+ 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("model: "):
|
|
+ retval = line[len("model: "):]
|
|
+ break
|
|
+ return retval
|
|
+
|
|
+ def get_option(self):
|
|
+ if not self.__use_xkb:
|
|
+ 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("option: "):
|
|
+ retval = line[len("option: "):]
|
|
+ break
|
|
+ return retval
|
|
+
|
|
+ def set_layout(self, layout="default", model="default", option="default"):
|
|
+ if not self.__use_xkb:
|
|
+ return
|
|
+ if layout == None:
|
|
+ return
|
|
+ if self.__default_layout == None:
|
|
+ # Maybe opening display was failed in constructor.
|
|
+ self.reload_default_layout()
|
|
+ if self.__default_layout == None:
|
|
+ return
|
|
+ layout = str(layout)
|
|
+ # if set_default_layout() is not default, the default layout is
|
|
+ # pulled from the current XKB. But it's possible gnome-settings-daemon
|
|
+ # does not run yet. I added XKB_SESSION_TIME_OUT for the timer.
|
|
+ if self.__time_lag_session_xkb_layout == True:
|
|
+ self.__default_layout = self.get_layout()
|
|
+ self.__default_model = self.get_model()
|
|
+ if self.__time_lag_session_xkb_option == True:
|
|
+ self.__default_option = self.get_option()
|
|
+ if (self.__time_lag_session_xkb_layout == True or \
|
|
+ self.__time_lag_session_xkb_option == True ) and \
|
|
+ (self.__time_lag_session_xkb_timer - time.time() \
|
|
+ > XKB_SESSION_TIME_OUT):
|
|
+ self.__time_lag_session_xkb_layout = False
|
|
+ self.__time_lag_session_xkb_option = False
|
|
+ if layout == "default":
|
|
+ layout = self.__default_layout
|
|
+ else:
|
|
+ self.__time_lag_session_xkb_layout = False
|
|
+ if model != None:
|
|
+ model = str(model)
|
|
+ if model == "default":
|
|
+ (layout, model) = self.__get_model_from_layout(layout)
|
|
+ if model == "default":
|
|
+ model = self.__default_model
|
|
+ else:
|
|
+ self.__time_lag_session_xkb_layout = False
|
|
+ if option != None:
|
|
+ option = str(option)
|
|
+ if option == "default":
|
|
+ option = self.__default_option
|
|
+ else:
|
|
+ self.__time_lag_session_xkb_option = False
|
|
+ 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 model != None and layout + '(' + model + ')' == latin_layout:
|
|
+ need_us_layout = True
|
|
+ break
|
|
+ if need_us_layout:
|
|
+ layout = layout + ",us"
|
|
+ if model != None:
|
|
+ model = model + ","
|
|
+ if layout == self.get_layout() and \
|
|
+ model == self.get_model() and \
|
|
+ option == self.get_option():
|
|
+ return
|
|
+ args = []
|
|
+ args.append(self.__command)
|
|
+ args.append(os.path.basename(self.__command))
|
|
+ args.append("--layout")
|
|
+ args.append(layout)
|
|
+ if model != None:
|
|
+ args.append("--model")
|
|
+ args.append(model)
|
|
+ if option != None:
|
|
+ args.append("--option")
|
|
+ args.append(option)
|
|
+ pid = os.spawnl(os.P_NOWAIT, *args)
|
|
+ os.waitpid(pid, 0)
|
|
+
|
|
+ def set_default_layout(self, layout="default", model="default"):
|
|
+ if not self.__use_xkb:
|
|
+ return
|
|
+ if layout == None:
|
|
+ print >> sys.stderr, "ibus.xkblayout: None layout"
|
|
+ return
|
|
+ if model == None:
|
|
+ print >> sys.stderr, "ibus.xkblayout: None model"
|
|
+ return
|
|
+ if layout == 'default':
|
|
+ self.__default_layout = self.get_layout()
|
|
+ self.__default_model = self.get_model()
|
|
+ else:
|
|
+ if model == 'default':
|
|
+ (layout, model) = self.__get_model_from_layout(layout)
|
|
+ self.__default_layout = layout
|
|
+ self.__time_lag_session_xkb_layout = False
|
|
+ if model == 'default':
|
|
+ self.__default_model = None
|
|
+ else:
|
|
+ self.__default_model = model
|
|
+
|
|
+ def set_default_option(self, option="default"):
|
|
+ if not self.__use_xkb:
|
|
+ return
|
|
+ if option == None:
|
|
+ print >> sys.stderr, "ibus.xkblayout: None option"
|
|
+ return
|
|
+ if option == 'default':
|
|
+ self.__default_option = self.get_option()
|
|
+ else:
|
|
+ self.__default_option = option
|
|
+ self.__time_lag_session_xkb_option = False
|
|
+
|
|
+ def reload_default_layout(self):
|
|
+ if not self.__use_xkb:
|
|
+ return
|
|
+ self.__default_layout = self.get_layout()
|
|
+ self.__default_model = self.get_model()
|
|
+ self.__default_option = self.get_option()
|
|
diff --git a/ibus/xkbxml.py.in b/ibus/xkbxml.py.in
|
|
new file mode 100644
|
|
index 0000000..5f0a3ea
|
|
--- /dev/null
|
|
+++ b/ibus/xkbxml.py.in
|
|
@@ -0,0 +1,412 @@
|
|
+# vim:set et sts=4 sw=4:
|
|
+#
|
|
+# ibus - The Input Bus
|
|
+#
|
|
+# Copyright (c) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
|
|
+# Copyright (c) 2007-2010 Red Hat, Inc.
|
|
+#
|
|
+# This library is free software; you can redistribute it and/or
|
|
+# modify it under the terms of the GNU Lesser General Public
|
|
+# License as published by the Free Software Foundation; either
|
|
+# version 2 of the License, or (at your option) any later version.
|
|
+#
|
|
+# This library is distributed in the hope that it will be useful,
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+# GNU Lesser General Public License for more details.
|
|
+#
|
|
+# You should have received a copy of the GNU Lesser General Public
|
|
+# License along with this program; if not, write to the
|
|
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
+# Boston, MA 02111-1307 USA
|
|
+
|
|
+__all__ = (
|
|
+ "XKBConfigRegistry",
|
|
+ "XKBLayoutConfig",
|
|
+ )
|
|
+
|
|
+import os
|
|
+import string
|
|
+import xml.sax as sax
|
|
+import enginedesc
|
|
+from xml.sax.saxutils import XMLFilterBase, XMLGenerator
|
|
+from xml.sax._exceptions import SAXParseException
|
|
+from cStringIO import StringIO
|
|
+
|
|
+try:
|
|
+ from glib import get_user_config_dir
|
|
+except ImportError:
|
|
+ get_user_config_dir = lambda : None
|
|
+
|
|
+XKB_RULES_XML_FILE = "@XKB_RULES_XML_FILE@"
|
|
+
|
|
+class XKBConfigRegistryHandler(XMLFilterBase):
|
|
+ def __init__(self, parser=None, root='root'):
|
|
+ XMLFilterBase.__init__(self, parser)
|
|
+ self.__root = root
|
|
+ self.__current_node = root
|
|
+ self.__layoutlist_array = {}
|
|
+ self.__layoutlist = False
|
|
+ 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 = {}
|
|
+ self.__optionlist_array = {}
|
|
+ self.__optionlist = False
|
|
+ self.__option_group_desc = {}
|
|
+ self.__option_desc = {}
|
|
+ self.__option = False
|
|
+ self.__option_label = None
|
|
+ self.__group = False
|
|
+ self.__group_label = None
|
|
+
|
|
+ def __characters_layoutlist(self, text):
|
|
+ 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_array:
|
|
+ self.__layoutlist_array[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_array[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 __characters_optionlist(self, text):
|
|
+ if not self.__group:
|
|
+ return
|
|
+ if self.__option:
|
|
+ if self.__current_node == "name":
|
|
+ self.__option_label = text
|
|
+ if self.__group_label != None and \
|
|
+ self.__group_label in self.__optionlist_array:
|
|
+ self.__optionlist_array[self.__group_label].append(text)
|
|
+ elif self.__current_node == "description":
|
|
+ self.__option_desc[self.__option_label] = text
|
|
+ else:
|
|
+ pass
|
|
+ else:
|
|
+ if self.__current_node == "name":
|
|
+ self.__group_label = text
|
|
+ self.__optionlist_array[self.__group_label] = []
|
|
+ elif self.__current_node == "description":
|
|
+ self.__option_group_desc[self.__group_label] = text
|
|
+ else:
|
|
+ pass
|
|
+
|
|
+ def startElement(self, name, attrs):
|
|
+ self.__current_node = name
|
|
+ if name == "layoutList":
|
|
+ self.__layoutlist = True
|
|
+ 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
|
|
+ elif name == "optionList":
|
|
+ self.__optionlist = True
|
|
+ elif name == "option":
|
|
+ self.__option = True
|
|
+ self.__option_label = None
|
|
+ elif name == "group":
|
|
+ self.__group = True
|
|
+ self.__group_label = None
|
|
+
|
|
+ def endElement(self, name):
|
|
+ self.__current_node = self.__root
|
|
+ if name == "layoutList":
|
|
+ self.__layoutlist = False
|
|
+ elif name == "layout":
|
|
+ self.__layout = False
|
|
+ elif name == "variantList":
|
|
+ self.__variantlist = False
|
|
+ elif name == "variant":
|
|
+ self.__variant = False
|
|
+ elif name == "optionList":
|
|
+ self.__optionlist = False
|
|
+ elif name == "option":
|
|
+ self.__option = False
|
|
+ elif name == "group":
|
|
+ self.__group = False
|
|
+
|
|
+ def characters(self, text):
|
|
+ if self.__current_node == self.__root:
|
|
+ return
|
|
+ if self.__layoutlist:
|
|
+ self.__characters_layoutlist(text)
|
|
+ elif self.__optionlist:
|
|
+ self.__characters_optionlist(text)
|
|
+
|
|
+ def getLayoutList(self):
|
|
+ return self.__layoutlist_array
|
|
+
|
|
+ def getLayoutDesc(self):
|
|
+ return self.__layout_desc
|
|
+
|
|
+ def getLayoutLang(self):
|
|
+ return self.__layout_lang
|
|
+
|
|
+ def getVariantDesc(self):
|
|
+ return self.__variant_desc
|
|
+
|
|
+ def getOptionList(self):
|
|
+ return self.__optionlist_array
|
|
+
|
|
+ def getOptionGroupDesc(self):
|
|
+ return self.__option_group_desc
|
|
+
|
|
+ def getOptionDesc(self):
|
|
+ return self.__option_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()
|
|
+
|
|
+ def get_option_list(self):
|
|
+ return self.__handler.getOptionList()
|
|
+
|
|
+ def get_option_group_desc(self):
|
|
+ return self.__handler.getOptionGroupDesc()
|
|
+
|
|
+ def get_option_desc(self):
|
|
+ return self.__handler.getOptionDesc()
|
|
+
|
|
+ @classmethod
|
|
+ def have_xkb(self):
|
|
+ return @HAVE_XKB@
|
|
+
|
|
+ @classmethod
|
|
+ def engine_desc_new(self,
|
|
+ lang,
|
|
+ layout,
|
|
+ layout_desc=None,
|
|
+ variant=None,
|
|
+ variant_desc=None):
|
|
+ if layout_desc != None and variant_desc != None:
|
|
+ longname = layout_desc + " - " + variant_desc
|
|
+ elif layout != None and variant != None:
|
|
+ longname = layout + " - " + variant
|
|
+ elif layout_desc != None:
|
|
+ longname = layout_desc
|
|
+ else:
|
|
+ longname = layout
|
|
+ if variant != None:
|
|
+ name = "xkb:layout:" + layout + ":" + variant
|
|
+ desc = "XKB " + layout + "(" + variant + ") keyboard layout"
|
|
+ engine_layout = layout + "(" + variant + ")"
|
|
+ else:
|
|
+ name = "xkb:layout:" + layout
|
|
+ desc = "XKB " + layout + " keyboard layout"
|
|
+ engine_layout = layout
|
|
+
|
|
+ engine = enginedesc.EngineDesc(name, longname, desc, lang,
|
|
+ "LGPL2.1",
|
|
+ "Takao Fujiwara <takao.fujiwara1@gmail.com>",
|
|
+ "ibus-engine",
|
|
+ engine_layout)
|
|
+ return engine
|
|
+
|
|
+class XKBLayoutConfig():
|
|
+ def __init__(self,
|
|
+ system_config="@datadir@/ibus/xkb/xkblayoutconfig.xml"):
|
|
+ self.__user_config = get_user_config_dir()
|
|
+ if self.__user_config == None:
|
|
+ self.__user_config = os.environ['HOME'] + "/.config"
|
|
+ self.__user_config = self.__user_config + \
|
|
+ "/ibus/xkb/xkblayoutconfig.xml"
|
|
+ self.__system_config = system_config
|
|
+ self.__filter_handler = None
|
|
+ self.__load()
|
|
+
|
|
+ def __load(self, downstream=None, preload_layouts=None):
|
|
+ parser = sax.make_parser()
|
|
+ parser.setFeature(sax.handler.feature_namespaces, 0)
|
|
+ self.__filter_handler = XKBLayoutConfigHandler(parser,
|
|
+ downstream,
|
|
+ preload_layouts)
|
|
+ parser.setContentHandler(self.__filter_handler)
|
|
+ f = None
|
|
+ if os.path.exists(self.__user_config):
|
|
+ f = file(self.__user_config)
|
|
+ elif os.path.exists(self.__system_config):
|
|
+ f = file(self.__system_config)
|
|
+ if f == None:
|
|
+ return
|
|
+ try:
|
|
+ parser.parse(f)
|
|
+ except SAXParseException:
|
|
+ print "ERROR: invalid file format", self.__user_config
|
|
+ finally:
|
|
+ f.close()
|
|
+
|
|
+ def get_preload_layouts(self):
|
|
+ return self.__filter_handler.getPreloadLayouts()
|
|
+
|
|
+ def save_preload_layouts(self, layouts):
|
|
+ if layouts == None:
|
|
+ if os.path.exists(self.__user_config):
|
|
+ os.unlink(self.__user_config)
|
|
+ return
|
|
+ parser = sax.make_parser()
|
|
+ parser.setFeature(sax.handler.feature_namespaces, 0)
|
|
+ result = StringIO()
|
|
+ downstream_handler = XMLGenerator(result, 'utf-8')
|
|
+ self.__load(downstream_handler, layouts)
|
|
+ contents = result.getvalue()
|
|
+ dir = os.path.dirname(self.__user_config)
|
|
+ if not os.path.exists(dir):
|
|
+ os.makedirs(dir, 0700)
|
|
+ f = open(self.__user_config, 'w')
|
|
+ f.write(contents)
|
|
+ f.close()
|
|
+ os.chmod(self.__user_config, 0600)
|
|
+
|
|
+def test():
|
|
+ xkbconfig = XKBConfigRegistry()
|
|
+ layout_list = xkbconfig.get_layout_list()
|
|
+ layout_desc = xkbconfig.get_layout_desc()
|
|
+ layout_lang = xkbconfig.get_layout_lang()
|
|
+ variant_desc = xkbconfig.get_variant_desc()
|
|
+ for layout in layout_list.keys():
|
|
+ if layout not in layout_lang:
|
|
+ print "layout name:", layout, "NO-LANG description:", layout_desc[layout]
|
|
+ continue
|
|
+ lang = layout_lang[layout]
|
|
+ print "layout name:", layout, "lang:", lang, "description:", layout_desc[layout]
|
|
+ for variant in layout_list[layout]:
|
|
+ label = "%s(%s)" % (layout, variant)
|
|
+ if label in layout_lang:
|
|
+ lang = layout_lang[label]
|
|
+ print " variant name:", variant, "lang:", lang, "description:", variant_desc[variant]
|
|
+
|
|
+ option_list = xkbconfig.get_option_list()
|
|
+ option_group_desc = xkbconfig.get_option_group_desc()
|
|
+ option_desc = xkbconfig.get_option_desc()
|
|
+ for option_group in option_list.keys():
|
|
+ print "option group name:", option_group, "description:", option_group_desc[option_group]
|
|
+ for option in option_list[option_group]:
|
|
+ print " option name:", option, "description:", option_desc[option]
|
|
+
|
|
+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/Makefile.am b/setup/Makefile.am
|
|
index 1730ec0..249856d 100644
|
|
--- a/setup/Makefile.am
|
|
+++ b/setup/Makefile.am
|
|
@@ -28,6 +28,7 @@ ibussetup_PYTHON = \
|
|
enginetreeview.py \
|
|
engineabout.py \
|
|
keyboardshortcut.py \
|
|
+ xkbsetup.py \
|
|
$(NULL)
|
|
|
|
ibussetup_DATA = \
|
|
diff --git a/setup/enginecombobox.py b/setup/enginecombobox.py
|
|
index 2fd8876..7383177 100644
|
|
--- a/setup/enginecombobox.py
|
|
+++ b/setup/enginecombobox.py
|
|
@@ -43,6 +43,7 @@ class EngineComboBox(gtk.ComboBox):
|
|
self.connect("notify::active", self.__notify_active_cb)
|
|
|
|
self.__model = None
|
|
+ self.__title = _("Select an input method")
|
|
|
|
renderer = gtk.CellRendererPixbuf()
|
|
renderer.set_property("xalign", 0)
|
|
@@ -117,7 +118,7 @@ class EngineComboBox(gtk.ComboBox):
|
|
renderer.set_property("weight", pango.WEIGHT_NORMAL)
|
|
elif isinstance(engine, int):
|
|
renderer.set_property("sensitive", True)
|
|
- renderer.set_property("text", _("Select an input method"))
|
|
+ renderer.set_property("text", self.__title)
|
|
renderer.set_property("weight", pango.WEIGHT_NORMAL)
|
|
else:
|
|
renderer.set_property("sensitive", True)
|
|
@@ -140,5 +141,9 @@ class EngineComboBox(gtk.ComboBox):
|
|
def get_active_engine(self):
|
|
return self.get_property("active-engine")
|
|
|
|
+ def get_title(self):
|
|
+ return self.__title
|
|
|
|
+ def set_title(self, title):
|
|
+ self.__title = title
|
|
|
|
diff --git a/setup/main.py b/setup/main.py
|
|
index 96e9456..8bac900 100644
|
|
--- a/setup/main.py
|
|
+++ b/setup/main.py
|
|
@@ -37,6 +37,7 @@ from gtk import gdk
|
|
from enginecombobox import EngineComboBox
|
|
from enginetreeview import EngineTreeView
|
|
from engineabout import EngineAbout
|
|
+from xkbsetup import XKBSetup
|
|
from i18n import DOMAINNAME, _, N_, init as i18n_init
|
|
|
|
(
|
|
@@ -219,6 +220,8 @@ class Setup(object):
|
|
self.__combobox.connect("notify::active-engine", self.__combobox_notify_active_engine_cb)
|
|
self.__treeview.connect("notify", self.__treeview_notify_cb)
|
|
|
|
+ XKBSetup(self.__config, self.__builder)
|
|
+
|
|
def __combobox_notify_active_engine_cb(self, combobox, property):
|
|
engine = self.__combobox.get_active_engine()
|
|
button = self.__builder.get_object("button_engine_add")
|
|
diff --git a/setup/setup.ui b/setup/setup.ui
|
|
index 0e31a78..de58446 100644
|
|
--- a/setup/setup.ui
|
|
+++ b/setup/setup.ui
|
|
@@ -129,7 +129,6 @@
|
|
<child>
|
|
<object class="GtkLabel" id="label9">
|
|
<property name="visible">True</property>
|
|
- <property name="sensitive">False</property>
|
|
<property name="tooltip_text" translatable="yes">The shortcut keys for switching to previous input method in the list</property>
|
|
<property name="xalign">0</property>
|
|
<property name="label" translatable="yes">Previous input method:</property>
|
|
@@ -216,7 +215,6 @@
|
|
<child>
|
|
<object class="GtkEntry" id="entry_prev_engine">
|
|
<property name="visible">True</property>
|
|
- <property name="sensitive">False</property>
|
|
<property name="can_focus">True</property>
|
|
<property name="editable">False</property>
|
|
</object>
|
|
@@ -228,7 +226,6 @@
|
|
<object class="GtkButton" id="button_prev_engine">
|
|
<property name="label" translatable="yes">...</property>
|
|
<property name="visible">True</property>
|
|
- <property name="sensitive">False</property>
|
|
<property name="can_focus">True</property>
|
|
<property name="receives_default">False</property>
|
|
<property name="use_underline">True</property>
|
|
@@ -729,6 +726,7 @@ You may use up/down buttons to change it.</i></small></property>
|
|
<property name="visible">True</property>
|
|
<property name="orientation">vertical</property>
|
|
<property name="spacing">6</property>
|
|
+ <property name="no_show_all">True</property>
|
|
<child>
|
|
<object class="GtkCheckButton" id="checkbutton_use_sys_layout">
|
|
<property name="label" translatable="yes">Use system keyboard layout</property>
|
|
@@ -797,6 +795,57 @@ You may use up/down buttons to change it.</i></small></property>
|
|
<property name="position">0</property>
|
|
</packing>
|
|
</child>
|
|
+ <child>
|
|
+ <object class="GtkHBox" id="hbox_system_keyboard_layout">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="spacing">6</property>
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="label18">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label" translatable="yes">System Keyboard Layout:</property>
|
|
+ <property name="use_markup">True</property>
|
|
+ <property name="justify">center</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkButton" id="button_system_keyboard_layout">
|
|
+ <property name="label"></property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="receives_default">False</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkButton" id="button_config_layouts">
|
|
+ <property name="label">Add or remove layouts in 'Select an input method' list</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="receives_default">False</property>
|
|
+ <property name="tooltip_text" translatable="yes">Add or remove keyboard layouts in all input method engnines</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">2</property>
|
|
+ </packing>
|
|
+ </child>
|
|
</object>
|
|
</child>
|
|
</object>
|
|
@@ -942,4 +991,558 @@ Homepage: http://code.google.com/p/ibus
|
|
</object>
|
|
</child>
|
|
</object>
|
|
+ <object class="GtkDialog" id="dialog_config_layouts">
|
|
+ <property name="title" translatable="yes">Add or Remove Layouts</property>
|
|
+ <property name="icon_name">ibus-setup</property>
|
|
+ <child internal-child="vbox">
|
|
+ <object class="GtkVBox" id="vbox101">
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="border-width">10</property>
|
|
+ <property name="spacing">12</property>
|
|
+ <child>
|
|
+ <object class="GtkAlignment" id="alignment101">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="top_padding">12</property>
|
|
+ <property name="left_padding">12</property>
|
|
+ <child>
|
|
+ <object class="GtkFrame" id="frame101">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label_xalign">0</property>
|
|
+ <property name="shadow_type">none</property>
|
|
+ <child>
|
|
+ <object class="GtkAlignment" id="alignment102">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="top_padding">12</property>
|
|
+ <property name="left_padding">12</property>
|
|
+ <child>
|
|
+ <object class="GtkVBox" id="vbox102">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="spacing">6</property>
|
|
+ <child>
|
|
+ <object class="GtkScrolledWindow" id="scrolledwindow101">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="border_width">5</property>
|
|
+ <property name="width_request">450</property>
|
|
+ <property name="height_request">350</property>
|
|
+ <property name="hscrollbar_policy">automatic</property>
|
|
+ <property name="vscrollbar_policy">automatic</property>
|
|
+ <property name="shadow_type">out</property>
|
|
+ <child>
|
|
+ <object class="GtkViewport" id="viewport101">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="shadow_type">none</property>
|
|
+ <child>
|
|
+ <object class="GtkVBox" id="vbox_all_keyboard_layouts">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ <child type="label">
|
|
+ <object class="GtkLabel" id="label101">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label" translatable="yes"><b>Keyboard Layout</b></property>
|
|
+ <property name="use_markup">True</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child internal-child="action_area">
|
|
+ <object class="GtkHButtonBox" id="hbuttonbox101">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="homogeneous">True</property>
|
|
+ <property name="layout_style">end</property>
|
|
+ <child>
|
|
+ <object class="GtkButton" id="button_config_layouts_cancel">
|
|
+ <property name="label">gtk-cancel</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="use_stock">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkButton" id="button_config_layouts_ok">
|
|
+ <property name="label">gtk-ok</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="use_stock">True</property>
|
|
+ <property name="receives_default">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="pack_type">end</property>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <object class="GtkDialog" id="dialog_system_keyboard_layout">
|
|
+ <property name="title" translatable="yes">System Keyboard Layout Setup</property>
|
|
+ <property name="icon_name">ibus-setup</property>
|
|
+ <child internal-child="vbox">
|
|
+ <object class="GtkVBox" id="vbox201">
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="border-width">10</property>
|
|
+ <property name="spacing">12</property>
|
|
+ <child>
|
|
+ <object class="GtkAlignment" id="alignment201">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="top_padding">12</property>
|
|
+ <property name="left_padding">12</property>
|
|
+ <child>
|
|
+ <object class="GtkFrame" id="frame201">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label_xalign">0</property>
|
|
+ <property name="shadow_type">none</property>
|
|
+ <child>
|
|
+ <object class="GtkAlignment" id="alignment202">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="top_padding">12</property>
|
|
+ <property name="left_padding">12</property>
|
|
+ <child>
|
|
+ <object class="GtkVBox" id="vbox202">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="spacing">6</property>
|
|
+ <child>
|
|
+ <object class="GtkHBox" id="hbox201">
|
|
+ <property name="visible">True</property>
|
|
+ <child>
|
|
+ <object class="GtkVBox" id="vbox203">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="spacing">6</property>
|
|
+ <child>
|
|
+ <object class="EngineComboBox" id="combobox_system_keyboard_layout_engines">
|
|
+ <property name="visible">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkScrolledWindow" id="scrolledwindow201">
|
|
+ <property name="height_request">150</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="hscrollbar_policy">automatic</property>
|
|
+ <property name="vscrollbar_policy">automatic</property>
|
|
+ <property name="shadow_type">in</property>
|
|
+ <child>
|
|
+ <object class="EngineTreeView" id="treeview_system_keyboard_layout_engines">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="height_request">150</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkVButtonBox" id="vbuttonbox201">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="spacing">5</property>
|
|
+ <property name="layout_style">start</property>
|
|
+ <child>
|
|
+ <object class="GtkButton" id="button_system_keyboard_layout_engine_add">
|
|
+ <property name="label">gtk-add</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="sensitive">False</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="receives_default">True</property>
|
|
+ <property name="tooltip_text" translatable="yes">Add the selected keyboard layout into the system keyboard layouts</property>
|
|
+ <property name="use_stock">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkButton" id="button_system_keyboard_layout_engine_remove">
|
|
+ <property name="label">gtk-remove</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="sensitive">False</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="receives_default">True</property>
|
|
+ <property name="tooltip_text" translatable="yes">Remove the selected keyboard layout from the system keyboard layouts</property>
|
|
+ <property name="use_stock">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkButton" id="button_system_keyboard_layout_engine_up">
|
|
+ <property name="label">gtk-go-up</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="sensitive">False</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="receives_default">True</property>
|
|
+ <property name="tooltip_text" translatable="yes">Move up the selected keyboard layout in the system keyboard layouts list</property>
|
|
+ <property name="use_stock">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">2</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkButton" id="button_system_keyboard_layout_engine_down">
|
|
+ <property name="label">gtk-go-down</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="sensitive">False</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="receives_default">True</property>
|
|
+ <property name="tooltip_text" translatable="yes">Move down the selected keyboard layout in the system keyboard layouts list</property>
|
|
+ <property name="use_stock">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">3</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkButton" id="button_system_keyboard_layout_engine_reset">
|
|
+ <property name="label" translatable="yes">Rese_t</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="sensitive">False</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="receives_default">True</property>
|
|
+ <property name="tooltip_text" translatable="yes">Reset the system keyboard layouts list</property>
|
|
+ <property name="use_underline">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">4</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkHBox" id="hbox202">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="spacing">6</property>
|
|
+ <child>
|
|
+ <object class="GtkImage" id="image201">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="stock">gtk-info</property>
|
|
+ <property name="icon-size">2</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkLabel" id="label_system_keyboard_layout_engines">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="xalign">0</property>
|
|
+ <property name="use_markup">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ <child type="label">
|
|
+ <object class="GtkLabel" id="label201">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label" translatable="yes"><b>Keyboard Layout</b></property>
|
|
+ <property name="use_markup">True</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkAlignment" id="alignment204">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="top_padding">12</property>
|
|
+ <property name="left_padding">12</property>
|
|
+ <child>
|
|
+ <object class="GtkFrame" id="frame202">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label_xalign">0</property>
|
|
+ <property name="shadow_type">none</property>
|
|
+ <child>
|
|
+ <object class="GtkAlignment" id="alignment205">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="top_padding">12</property>
|
|
+ <property name="left_padding">12</property>
|
|
+ <child>
|
|
+ <object class="GtkVBox" id="vbox204">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="spacing">6</property>
|
|
+ <child>
|
|
+ <object class="GtkHButtonBox" id="hbuttonbox201">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="homogeneous">True</property>
|
|
+ <property name="layout_style">start</property>
|
|
+ <child>
|
|
+ <object class="GtkButton" id="button_system_keyboard_option_setup">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label" translatable="yes">_Options...</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="use_underline">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ <child type="label">
|
|
+ <object class="GtkLabel" id="label202">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label" translatable="yes"><b>Keyboard Option</b></property>
|
|
+ <property name="use_markup">True</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child internal-child="action_area">
|
|
+ <object class="GtkHButtonBox" id="hbuttonbox202">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="homogeneous">True</property>
|
|
+ <property name="layout_style">end</property>
|
|
+ <child>
|
|
+ <object class="GtkButton" id="button_system_keyboard_layout_cancel">
|
|
+ <property name="label">gtk-cancel</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="use_stock">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkButton" id="button_system_keyboard_layout_ok">
|
|
+ <property name="label">gtk-ok</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="use_stock">True</property>
|
|
+ <property name="receives_default">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="pack_type">end</property>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <object class="GtkDialog" id="dialog_system_keyboard_option">
|
|
+ <property name="title" translatable="yes">System Keyboard Option Setup</property>
|
|
+ <property name="icon_name">ibus-setup</property>
|
|
+ <child internal-child="vbox">
|
|
+ <object class="GtkVBox" id="vbox301">
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="border-width">10</property>
|
|
+ <property name="spacing">12</property>
|
|
+ <child>
|
|
+ <object class="GtkAlignment" id="alignment301">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="top_padding">12</property>
|
|
+ <property name="left_padding">12</property>
|
|
+ <child>
|
|
+ <object class="GtkFrame" id="frame301">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label_xalign">0</property>
|
|
+ <property name="shadow_type">none</property>
|
|
+ <child>
|
|
+ <object class="GtkAlignment" id="alignment302">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="top_padding">12</property>
|
|
+ <property name="left_padding">12</property>
|
|
+ <child>
|
|
+ <object class="GtkVBox" id="vbox302">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ <property name="spacing">6</property>
|
|
+ <child>
|
|
+ <object class="GtkCheckButton" id="checkbutton_use_system_keyboard_option">
|
|
+ <property name="label" translatable="yes">Use the default keyboard option</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="receives_default">False</property>
|
|
+ <property name="tooltip_text" translatable="yes">Use the defualt XKB option</property>
|
|
+ <property name="draw_indicator">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child>
|
|
+ <object class="GtkScrolledWindow" id="scrolledwindow301">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="can_focus">True</property>
|
|
+ <property name="border_width">5</property>
|
|
+ <property name="width_request">450</property>
|
|
+ <property name="height_request">350</property>
|
|
+ <property name="hscrollbar_policy">automatic</property>
|
|
+ <property name="vscrollbar_policy">automatic</property>
|
|
+ <property name="shadow_type">out</property>
|
|
+ <child>
|
|
+ <object class="GtkViewport" id="viewport301">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="shadow_type">none</property>
|
|
+ <child>
|
|
+ <object class="GtkVBox" id="vbox_system_keyboard_options">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="orientation">vertical</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ <child type="label">
|
|
+ <object class="GtkLabel" id="label301">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="label" translatable="yes"><b>Keyboard Option</b></property>
|
|
+ <property name="use_markup">True</property>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ <child internal-child="action_area">
|
|
+ <object class="GtkHButtonBox" id="hbuttonbox301">
|
|
+ <property name="visible">True</property>
|
|
+ <property name="homogeneous">True</property>
|
|
+ <property name="layout_style">end</property>
|
|
+ <child>
|
|
+ <object class="GtkButton" id="button_system_keyboard_option_close">
|
|
+ <property name="label">gtk-close</property>
|
|
+ <property name="visible">True</property>
|
|
+ <property name="use_stock">True</property>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="position">0</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ <packing>
|
|
+ <property name="expand">False</property>
|
|
+ <property name="fill">False</property>
|
|
+ <property name="pack_type">end</property>
|
|
+ <property name="position">1</property>
|
|
+ </packing>
|
|
+ </child>
|
|
+ </object>
|
|
+ </child>
|
|
+ </object>
|
|
</interface>
|
|
diff --git a/setup/xkbsetup.py b/setup/xkbsetup.py
|
|
new file mode 100644
|
|
index 0000000..0d57a1a
|
|
--- /dev/null
|
|
+++ b/setup/xkbsetup.py
|
|
@@ -0,0 +1,451 @@
|
|
+# vim:set et sts=4 sw=4:
|
|
+#
|
|
+# ibus - The Input Bus
|
|
+#
|
|
+# Copyright (c) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
|
|
+# Copyright (c) 2007-2010 Red Hat, Inc.
|
|
+#
|
|
+# This library is free software; you can redistribute it and/or
|
|
+# modify it under the terms of the GNU Lesser General Public
|
|
+# License as published by the Free Software Foundation; either
|
|
+# version 2 of the License, or (at your option) any later version.
|
|
+#
|
|
+# This library is distributed in the hope that it will be useful,
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+# GNU Lesser General Public License for more details.
|
|
+#
|
|
+# You should have received a copy of the GNU Lesser General Public
|
|
+# License along with this program; if not, write to the
|
|
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
+# Boston, MA 02111-1307 USA
|
|
+
|
|
+import gettext
|
|
+import gobject
|
|
+import gtk
|
|
+import ibus
|
|
+
|
|
+_ = lambda a : gettext.dgettext("ibus", a)
|
|
+XKB_MAX_LAYOUTS = 4
|
|
+
|
|
+class XKBSetup(gobject.GObject):
|
|
+ def __init__(self, config, builder):
|
|
+ super(XKBSetup, self).__init__()
|
|
+
|
|
+ self.__config = config
|
|
+ self.__builder = builder
|
|
+
|
|
+ # system keyboard layout setting
|
|
+ self.__button_system_keyboard_layout = self.__builder.get_object("button_system_keyboard_layout")
|
|
+ text = str(self.__config.get_value("general", "system_keyboard_layout", ''))
|
|
+ if text == 'default' or text == '':
|
|
+ text = _("Default")
|
|
+ self.__button_system_keyboard_layout.set_label(text)
|
|
+ if not self.__config.get_value("general", "use_system_keyboard_layout", True):
|
|
+ self.__button_system_keyboard_layout.set_sensitive(False)
|
|
+ self.__button_system_keyboard_layout.connect("clicked", self.__button_system_keyboard_layout_cb)
|
|
+
|
|
+ # use system keyboard layout setting
|
|
+ button = self.__builder.get_object("checkbutton_use_sys_layout")
|
|
+ button.connect("toggled", lambda button: self.__button_system_keyboard_layout.set_sensitive(button.get_active()))
|
|
+
|
|
+ self.__xkblayoutconfig = None
|
|
+ self.__preload_xkb_engines = []
|
|
+ self.__other_xkb_engines = []
|
|
+ self.__default_xkb_engine = None
|
|
+ if ibus.XKBConfigRegistry.have_xkb():
|
|
+ self.__xkblayoutconfig = ibus.XKBLayoutConfig()
|
|
+
|
|
+ # config layouts dialog
|
|
+ self.__init_config_layouts()
|
|
+
|
|
+ # default system keyboard dialog
|
|
+ self.__init_system_keyboard()
|
|
+
|
|
+ def __get_xkb_engines(self):
|
|
+ xkb_engines = []
|
|
+ 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)
|
|
+ xkb_engines.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])
|
|
+ xkb_engines.append(engine)
|
|
+ return xkb_engines
|
|
+
|
|
+ def __get_default_xkb_engine(self):
|
|
+ if self.__default_xkb_engine != None:
|
|
+ return self.__default_xkb_engine
|
|
+ self.__default_xkb_engine = ibus.XKBConfigRegistry.engine_desc_new(
|
|
+ "other",
|
|
+ "default",
|
|
+ _("Default"),
|
|
+ None,
|
|
+ None)
|
|
+ return self.__default_xkb_engine
|
|
+
|
|
+ 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)
|
|
+ self.__vbox_all_keyboard_layouts = self.__builder.get_object("vbox_all_keyboard_layouts")
|
|
+
|
|
+ xkb_engines = self.__get_xkb_engines()
|
|
+ if len(xkb_engines) > 0:
|
|
+ button = self.__builder.get_object("button_config_layouts")
|
|
+ button.connect("clicked", self.__button_config_layouts_cb)
|
|
+ button.set_sensitive(True)
|
|
+
|
|
+ engine_dict = {}
|
|
+ for engine in xkb_engines:
|
|
+ if not engine.name.startswith("xkb:layout:"):
|
|
+ continue
|
|
+ lang = ibus.get_language_name(engine.language)
|
|
+ if lang not in engine_dict:
|
|
+ engine_dict[lang] = []
|
|
+ engine_dict[lang].append(engine)
|
|
+
|
|
+ keys = engine_dict.keys()
|
|
+ keys.sort()
|
|
+ if ibus.get_language_name("Other") in keys:
|
|
+ keys.remove(ibus.get_language_name("Other"))
|
|
+ keys += [ibus.get_language_name("Other")]
|
|
+
|
|
+ preload_xkb_engines = self.__xkblayoutconfig.get_preload_layouts()
|
|
+ for lang in keys:
|
|
+ expander = gtk.Expander("")
|
|
+ self.__vbox_all_keyboard_layouts.pack_start(expander, True, True, 0)
|
|
+ expander.show()
|
|
+ label = expander.get_label_widget()
|
|
+ label.set_label(lang)
|
|
+ align = gtk.Alignment(0, 0, 1, 0)
|
|
+ align.set_padding(6, 0, 18, 0)
|
|
+ expander.add(align)
|
|
+ align.show()
|
|
+ vbox = gtk.VBox(False, 0)
|
|
+ align.add(vbox)
|
|
+ vbox.show()
|
|
+
|
|
+ def cmp_engine(a, b):
|
|
+ if a.rank == b.rank:
|
|
+ return cmp(a.longname, b.longname)
|
|
+ return int(b.rank - a.rank)
|
|
+ engine_dict[lang].sort(cmp_engine)
|
|
+
|
|
+ for engine in engine_dict[lang]:
|
|
+ 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
|
|
+
|
|
+ checkbutton = gtk.CheckButton(engine.longname)
|
|
+ checkbutton.set_data("layout", layout)
|
|
+ if has_preloaded:
|
|
+ checkbutton.set_active(True)
|
|
+ vbox.pack_start(checkbutton, False, True, 0)
|
|
+ checkbutton.show()
|
|
+
|
|
+ def __init_system_keyboard_layout(self):
|
|
+ self.__dialog_system_keyboard_layout = self.__builder.get_object("dialog_system_keyboard_layout")
|
|
+ self.__button_system_keyboard_layout_cancel = self.__builder.get_object("button_system_keyboard_layout_cancel")
|
|
+ self.__button_system_keyboard_layout_cancel.connect("clicked", self.__button_system_keyboard_layout_cancel_cb)
|
|
+ self.__button_system_keyboard_layout_ok = self.__builder.get_object("button_system_keyboard_layout_ok")
|
|
+ self.__button_system_keyboard_layout_ok.connect("clicked", self.__button_system_keyboard_layout_ok_cb)
|
|
+
|
|
+ # get xkb layouts
|
|
+ xkb_engines = self.__get_xkb_engines()
|
|
+
|
|
+ self.__combobox_system_keyboard_layout = self.__builder.get_object("combobox_system_keyboard_layout_engines")
|
|
+ self.__combobox_system_keyboard_layout.set_engines(xkb_engines)
|
|
+ self.__combobox_system_keyboard_layout.set_title(_("Select keyboard layouts"))
|
|
+ self.__combobox_system_keyboard_layout.connect("notify::active-engine", self.__combobox_notify_active_system_keyboard_layout_cb)
|
|
+ self.__treeview_system_keyboard_layout = self.__builder.get_object("treeview_system_keyboard_layout_engines")
|
|
+ self.__treeview_system_keyboard_layout.connect("notify", self.__treeview_notify_system_keyboard_layout_cb)
|
|
+ column = self.__treeview_system_keyboard_layout.get_column(0)
|
|
+ column.set_title(_("Keyboard Layouts"))
|
|
+ button = self.__builder.get_object("button_system_keyboard_layout_engine_add")
|
|
+ button.connect("clicked", self.__button_system_keyboard_layout_add_cb)
|
|
+ button = self.__builder.get_object("button_system_keyboard_layout_engine_remove")
|
|
+ button.connect("clicked", self.__button_system_keyboard_layout_remove_cb)
|
|
+ button = self.__builder.get_object("button_system_keyboard_layout_engine_up")
|
|
+ button.connect("clicked", lambda *args:self.__treeview_system_keyboard_layout.move_up_engine())
|
|
+
|
|
+ button = self.__builder.get_object("button_system_keyboard_layout_engine_down")
|
|
+ button.connect("clicked", lambda *args:self.__treeview_system_keyboard_layout.move_down_engine())
|
|
+ button = self.__builder.get_object("button_system_keyboard_layout_engine_reset")
|
|
+ button.connect("clicked", self.__button_system_keyboard_layout_reset_cb)
|
|
+ button_reset = button
|
|
+ text = str(self.__config.get_value("general", "system_keyboard_layout", ''))
|
|
+ if text == "default" or text == None:
|
|
+ engine = self.__get_default_xkb_engine()
|
|
+ self.__treeview_system_keyboard_layout.set_engines([engine])
|
|
+ button_reset.set_sensitive(False)
|
|
+ else:
|
|
+ for layout in text.split(','):
|
|
+ layout_engine = None
|
|
+ for engine in xkb_engines:
|
|
+ if layout == engine.layout:
|
|
+ layout_engine = engine
|
|
+ break
|
|
+ if layout_engine != None:
|
|
+ self.__treeview_system_keyboard_layout.append_engine(layout_engine)
|
|
+ button_reset.set_sensitive(True)
|
|
+ label = self.__builder.get_object("label_system_keyboard_layout_engines")
|
|
+ label.set_markup(_("<small><i>The system keyboard layouts "
|
|
+ "can be set less than or equal to %d.\n"
|
|
+ "You may use Up/Down buttons to change the order."
|
|
+ "</i></small>") % XKB_MAX_LAYOUTS)
|
|
+
|
|
+ def __init_system_keyboard_option(self):
|
|
+ self.__dialog_system_keyboard_option = self.__builder.get_object("dialog_system_keyboard_option")
|
|
+ self.__button_system_keyboard_option_close = self.__builder.get_object("button_system_keyboard_option_close")
|
|
+ self.__button_system_keyboard_option_close.connect(
|
|
+ "clicked", lambda button: self.__dialog_system_keyboard_option.hide())
|
|
+
|
|
+ button = self.__builder.get_object("button_system_keyboard_option_setup")
|
|
+ button.connect("clicked", self.__button_system_keyboard_option_cb)
|
|
+ self.__checkbutton_use_system_keyboard_option = self.__builder.get_object("checkbutton_use_system_keyboard_option")
|
|
+ self.__vbox_system_keyboard_options = self.__builder.get_object("vbox_system_keyboard_options")
|
|
+ option_array = []
|
|
+ text = str(self.__config.get_value("general", "system_keyboard_option", ''))
|
|
+ if text == None or text == "default":
|
|
+ self.__checkbutton_use_system_keyboard_option.set_active(True)
|
|
+ self.__vbox_system_keyboard_options.set_sensitive(False)
|
|
+ else:
|
|
+ self.__checkbutton_use_system_keyboard_option.set_active(False)
|
|
+ self.__vbox_system_keyboard_options.set_sensitive(True)
|
|
+ option_array = text.split(',')
|
|
+ self.__checkbutton_use_system_keyboard_option.connect(
|
|
+ "toggled", lambda button: self.__vbox_system_keyboard_options.set_sensitive(not button.get_active()))
|
|
+
|
|
+ xkbconfig = ibus.XKBConfigRegistry()
|
|
+ option_list = xkbconfig.get_option_list()
|
|
+ option_group_desc = xkbconfig.get_option_group_desc()
|
|
+ option_desc = xkbconfig.get_option_desc()
|
|
+ for option_group in option_list.keys():
|
|
+ expander = gtk.Expander("")
|
|
+ self.__vbox_system_keyboard_options.pack_start(expander, True, True, 0)
|
|
+ expander.show()
|
|
+ checked = 0
|
|
+ label = expander.get_label_widget()
|
|
+ label.set_label(option_group_desc[option_group])
|
|
+ label.set_data("option_group", option_group)
|
|
+ expander.set_data("checked", checked)
|
|
+ align = gtk.Alignment(0, 0, 1, 0)
|
|
+ align.set_padding(6, 0, 18, 0)
|
|
+ expander.add(align)
|
|
+ align.show()
|
|
+ vbox = gtk.VBox(False, 0)
|
|
+ align.add(vbox)
|
|
+ vbox.show()
|
|
+ for option in option_list[option_group]:
|
|
+ checkbutton = gtk.CheckButton(option_desc[option])
|
|
+ checkbutton.set_data("option", option)
|
|
+ if option in option_array:
|
|
+ checkbutton.set_active(True)
|
|
+ label.set_markup("<b>" +
|
|
+ option_group_desc[option_group] +
|
|
+ "</b>")
|
|
+ checked = checked + 1
|
|
+ expander.set_data("checked", checked)
|
|
+ checkbutton.connect("toggled",
|
|
+ self.__checkbutton_system_keyboard_option_toggled_cb,
|
|
+ expander)
|
|
+ vbox.pack_start(checkbutton, False, True, 0)
|
|
+ checkbutton.show()
|
|
+
|
|
+ def __init_system_keyboard(self):
|
|
+ if not ibus.XKBConfigRegistry.have_xkb():
|
|
+ hbox = self.__builder.get_object("hbox_system_keyboard_layout")
|
|
+ hbox.hide()
|
|
+ return
|
|
+
|
|
+ self.__init_system_keyboard_layout()
|
|
+ self.__init_system_keyboard_option()
|
|
+
|
|
+ def __combobox_notify_active_system_keyboard_layout_cb(self, combobox, property):
|
|
+ engine = self.__combobox_system_keyboard_layout.get_active_engine()
|
|
+ button = self.__builder.get_object("button_system_keyboard_layout_engine_add")
|
|
+ engines = self.__treeview_system_keyboard_layout.get_engines()
|
|
+ button.set_sensitive(engine != None and \
|
|
+ engine not in engines and \
|
|
+ len(engines) < XKB_MAX_LAYOUTS)
|
|
+
|
|
+ def __treeview_notify_system_keyboard_layout_cb(self, treeview, property):
|
|
+ if property.name != "active-engine" and property.name != "engines":
|
|
+ return
|
|
+
|
|
+ engines = self.__treeview_system_keyboard_layout.get_engines()
|
|
+ engine = self.__treeview_system_keyboard_layout.get_active_engine()
|
|
+
|
|
+ button = self.__builder.get_object("button_system_keyboard_layout_engine_remove")
|
|
+ button.set_sensitive(engine != None)
|
|
+ button = self.__builder.get_object("button_system_keyboard_layout_engine_up")
|
|
+ button.set_sensitive(engine not in engines[:1])
|
|
+ button = self.__builder.get_object("button_system_keyboard_layout_engine_down")
|
|
+ button.set_sensitive(engine not in engines[-1:])
|
|
+
|
|
+ def __button_system_keyboard_layout_add_cb(self, button):
|
|
+ engines = self.__treeview_system_keyboard_layout.get_engines()
|
|
+ engine = self.__combobox_system_keyboard_layout.get_active_engine()
|
|
+ if len(engines) > 0 and engines[0].layout == "default":
|
|
+ self.__treeview_system_keyboard_layout.set_engines([engine])
|
|
+ else:
|
|
+ self.__treeview_system_keyboard_layout.append_engine(engine)
|
|
+ button_reset = self.__builder.get_object("button_system_keyboard_layout_engine_reset")
|
|
+ button_reset.set_sensitive(True)
|
|
+ if len(self.__treeview_system_keyboard_layout.get_engines()) >= XKB_MAX_LAYOUTS:
|
|
+ button.set_sensitive(False)
|
|
+
|
|
+ def __button_system_keyboard_layout_remove_cb(self, button):
|
|
+ self.__treeview_system_keyboard_layout.remove_engine()
|
|
+ if len(self.__treeview_system_keyboard_layout.get_engines()) < XKB_MAX_LAYOUTS:
|
|
+ button_add = self.__builder.get_object("button_system_keyboard_layout_engine_add")
|
|
+ button_add.set_sensitive(True)
|
|
+ button_reset = self.__builder.get_object("button_system_keyboard_layout_engine_reset")
|
|
+ button_reset.set_sensitive(True)
|
|
+
|
|
+ def __button_system_keyboard_layout_reset_cb(self, button):
|
|
+ engine = self.__get_default_xkb_engine()
|
|
+ self.__treeview_system_keyboard_layout.set_engines([engine])
|
|
+ button.set_sensitive(False)
|
|
+
|
|
+ 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()
|
|
+ engine_list = []
|
|
+ for expander in self.__vbox_all_keyboard_layouts.get_children():
|
|
+ align = expander.get_children()[0]
|
|
+ vbox = align.get_children()[0]
|
|
+ for checkbutton in vbox.get_children():
|
|
+ if checkbutton.get_active():
|
|
+ engine_list.append(checkbutton.get_data("layout"))
|
|
+ if len(engine_list) == 0:
|
|
+ return
|
|
+ engine_list.sort()
|
|
+ self.__xkblayoutconfig.save_preload_layouts(engine_list)
|
|
+ message = _("Please restart IBus to reload your configuration.")
|
|
+ dlg = gtk.MessageDialog(type = gtk.MESSAGE_INFO,
|
|
+ buttons = gtk.BUTTONS_OK,
|
|
+ message_format = message)
|
|
+ dlg.run()
|
|
+ dlg.destroy()
|
|
+
|
|
+ def __button_system_keyboard_layout_cb(self, button):
|
|
+ self.__dialog_system_keyboard_layout.run()
|
|
+ self.__dialog_system_keyboard_layout.hide()
|
|
+
|
|
+ def __button_system_keyboard_layout_cancel_cb(self, button):
|
|
+ self.__dialog_system_keyboard_layout.hide()
|
|
+
|
|
+ def __button_system_keyboard_layout_ok_cb(self, button):
|
|
+ self.__dialog_system_keyboard_layout.hide()
|
|
+ layout = "default"
|
|
+ for engine in self.__treeview_system_keyboard_layout.get_engines():
|
|
+ if layout == "default":
|
|
+ layout = engine.layout
|
|
+ else:
|
|
+ layout = "%s,%s" % (layout, engine.layout)
|
|
+ if layout == None or layout == "":
|
|
+ layout = "default"
|
|
+ org_layout = str(self.__config.get_value("general", "system_keyboard_layout", None))
|
|
+ if layout != org_layout:
|
|
+ self.__config.set_value("general", "system_keyboard_layout", layout)
|
|
+ if layout == "default":
|
|
+ layout = _("Default")
|
|
+ self.__button_system_keyboard_layout.set_label(layout)
|
|
+ option = "default"
|
|
+ if not self.__checkbutton_use_system_keyboard_option.get_active():
|
|
+ for expander in self.__vbox_system_keyboard_options.get_children():
|
|
+ align = expander.get_children()[0]
|
|
+ vbox = align.get_children()[0]
|
|
+ for checkbutton in vbox.get_children():
|
|
+ if checkbutton.get_active():
|
|
+ data = checkbutton.get_data("option")
|
|
+ if option == "default":
|
|
+ option = data
|
|
+ else:
|
|
+ option = "%s,%s" % (option, data)
|
|
+ if option == None or option == "":
|
|
+ option = "default"
|
|
+ if option != "default" and option.find(':') < 0:
|
|
+ message = _("The keyboard option cannot be chosen.")
|
|
+ dlg = gtk.MessageDialog(type = gtk.MESSAGE_INFO,
|
|
+ buttons = gtk.BUTTONS_OK,
|
|
+ message_format = message)
|
|
+ dlg.run()
|
|
+ dlg.destroy()
|
|
+ return
|
|
+ org_option = str(self.__config.get_value("general", "system_keyboard_option", None))
|
|
+ if option != org_option:
|
|
+ self.__config.set_value("general", "system_keyboard_option", option)
|
|
+ message = _("Please restart IBus to reload your configuration.")
|
|
+ dlg = gtk.MessageDialog(type = gtk.MESSAGE_INFO,
|
|
+ buttons = gtk.BUTTONS_OK,
|
|
+ message_format = message)
|
|
+ dlg.run()
|
|
+ dlg.destroy()
|
|
+
|
|
+ def __button_system_keyboard_option_cb(self, button):
|
|
+ self.__dialog_system_keyboard_option.run()
|
|
+ self.__dialog_system_keyboard_option.hide()
|
|
+
|
|
+ def __checkbutton_system_keyboard_option_toggled_cb(self, button, user_data):
|
|
+ expander = user_data
|
|
+ checked = expander.get_data("checked")
|
|
+ label = expander.get_label_widget()
|
|
+ if button.get_active():
|
|
+ checked = checked + 1
|
|
+ label.set_markup("<b>" + label.get_text() + "</b>")
|
|
+ else:
|
|
+ checked = checked - 1
|
|
+ if checked <= 0:
|
|
+ label.set_text(label.get_text())
|
|
+ expander.set_data("checked", checked)
|
|
+
|
|
diff --git a/src/ibusfactory.c b/src/ibusfactory.c
|
|
index 11d9a6d..7770216 100644
|
|
--- a/src/ibusfactory.c
|
|
+++ b/src/ibusfactory.c
|
|
@@ -21,6 +21,7 @@
|
|
*/
|
|
#include "ibusfactory.h"
|
|
#include "ibusengine.h"
|
|
+#include "ibusmarshalers.h"
|
|
#include "ibusshare.h"
|
|
#include "ibusinternal.h"
|
|
|
|
@@ -28,6 +29,7 @@
|
|
(G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_FACTORY, IBusFactoryPrivate))
|
|
|
|
enum {
|
|
+ LOOKUP_ENGINE_NAME,
|
|
LAST_SIGNAL,
|
|
};
|
|
|
|
@@ -42,6 +44,8 @@ struct _IBusFactoryPrivate {
|
|
GHashTable *engine_table;
|
|
};
|
|
|
|
+static guint factory_signals[LAST_SIGNAL] = { 0 };
|
|
+
|
|
/* functions prototype */
|
|
static void ibus_factory_destroy (IBusFactory *factory);
|
|
static void ibus_factory_set_property (IBusFactory *engine,
|
|
@@ -113,6 +117,17 @@ ibus_factory_class_init (IBusFactoryClass *class)
|
|
ibus_service_class_add_interfaces (IBUS_SERVICE_CLASS (class), introspection_xml);
|
|
|
|
g_type_class_add_private (class, sizeof (IBusFactoryPrivate));
|
|
+
|
|
+ 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
|
|
@@ -190,8 +205,12 @@ ibus_factory_service_method_call (IBusService *service,
|
|
|
|
if (g_strcmp0 (method_name, "CreateEngine") == 0) {
|
|
gchar *engine_name = NULL;
|
|
+ GType engine_type;
|
|
+
|
|
g_variant_get (parameters, "(&s)", &engine_name);
|
|
- GType engine_type = (GType )g_hash_table_lookup (factory->priv->engine_table, engine_name);
|
|
+ g_signal_emit (factory, factory_signals[LOOKUP_ENGINE_NAME],
|
|
+ 0, engine_name);
|
|
+ engine_type = (GType) g_hash_table_lookup (factory->priv->engine_table, engine_name);
|
|
|
|
if (engine_type == G_TYPE_INVALID) {
|
|
gchar *error_message = g_strdup_printf ("Can not fond engine %s", engine_name);
|
|
diff --git a/src/ibusfactory.h b/src/ibusfactory.h
|
|
index 47c06e0..102081c 100644
|
|
--- a/src/ibusfactory.h
|
|
+++ b/src/ibusfactory.h
|
|
@@ -127,10 +127,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 07b0fa2..d058b4e 100644
|
|
--- a/ui/gtk/panel.py
|
|
+++ b/ui/gtk/panel.py
|
|
@@ -117,6 +117,22 @@ 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)
|
|
+ use_xkb = self.__config.get_value("general", "use_system_keyboard_layout", False)
|
|
+ if not use_xkb:
|
|
+ self.__xkblayout.use_xkb(use_xkb)
|
|
+ value = str(self.__config.get_value("general", "system_keyboard_layout", ''))
|
|
+ if value == '':
|
|
+ value = 'default'
|
|
+ if value != 'default':
|
|
+ self.__xkblayout.set_default_layout(value)
|
|
+ value = str(self.__config.get_value("general", "system_keyboard_option", ''))
|
|
+ if value == '':
|
|
+ value = 'default'
|
|
+ if value != 'default':
|
|
+ self.__xkblayout.set_default_option(value)
|
|
+
|
|
def set_cursor_location(self, x, y, w, h):
|
|
self.__candidate_panel.set_cursor_location(x, y, w, h)
|
|
|
|
@@ -201,14 +217,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):
|
|
@@ -218,6 +240,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:
|
|
@@ -230,14 +254,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,3 +547,12 @@ class Panel(ibus.PanelBase):
|
|
flags=glib.SPAWN_DO_NOT_REAP_CHILD)[0]
|
|
self.__setup_pid = pid
|
|
glib.child_watch_add(self.__setup_pid, self.__child_watch_cb)
|
|
+
|
|
+ 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..64b1fc8
|
|
--- /dev/null
|
|
+++ b/xkb/Makefile.am
|
|
@@ -0,0 +1,104 @@
|
|
+# vim:set noet ts=4:
|
|
+#
|
|
+# ibus - The Input Bus
|
|
+#
|
|
+# Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+# Copyright (c) 2007-2010 Peng Huang <shawn.p.huang@gmail.com>
|
|
+# Copyright (c) 2007-2010 Red Hat, Inc.
|
|
+#
|
|
+# This library is free software; you can redistribute it and/or
|
|
+# modify it under the terms of the GNU Lesser General Public
|
|
+# License as published by the Free Software Foundation; either
|
|
+# version 2 of the License, or (at your option) any later version.
|
|
+#
|
|
+# This library is distributed in the hope that it will be useful,
|
|
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+# GNU Lesser General Public License for more details.
|
|
+#
|
|
+# You should have received a copy of the GNU Lesser General Public
|
|
+# License along with this program; if not, write to the
|
|
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
|
|
+# Boston, MA 02111-1307 USA
|
|
+
|
|
+libibus = $(top_builddir)/src/libibus-@IBUS_API_VERSION@.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..e1861e8
|
|
--- /dev/null
|
|
+++ b/xkb/ibus-engine-xkb-main.c
|
|
@@ -0,0 +1,397 @@
|
|
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
|
+/* vim:set et sts=4: */
|
|
+/* bus - The Input Bus
|
|
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Red Hat, Inc.
|
|
+ *
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Lesser General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2 of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This library is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * Lesser General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Lesser General Public
|
|
+ * License along with this library; if not, write to the
|
|
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ * Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+#ifdef HAVE_CONFIG_H
|
|
+#include <config.h>
|
|
+#endif
|
|
+
|
|
+#include <gconf/gconf-client.h>
|
|
+#include <ibus.h>
|
|
+#include <stdlib.h>
|
|
+
|
|
+#ifdef ENABLE_NLS
|
|
+#include <locale.h>
|
|
+#endif
|
|
+
|
|
+#include "ibus-engine-xkb-main.h"
|
|
+#include "xkbxml.h"
|
|
+
|
|
+#define IBUS_TYPE_XKB_ENGINE (ibus_xkb_engine_get_type ())
|
|
+
|
|
+static IBusBus *bus = NULL;
|
|
+static IBusFactory *factory = NULL;
|
|
+static IBusEngineClass *parent_class = NULL;
|
|
+static gboolean ibus = FALSE;
|
|
+static gboolean xml = FALSE;
|
|
+
|
|
+static const GOptionEntry entries[] =
|
|
+{
|
|
+ { "ibus", 'i', 0, G_OPTION_ARG_NONE, &ibus, "component is executed by ibus", NULL },
|
|
+ { "xml", 'x', 0, G_OPTION_ARG_NONE, &xml, "print component xml", NULL },
|
|
+ { NULL },
|
|
+};
|
|
+
|
|
+static GObject*
|
|
+ibus_xkb_engine_constructor (GType type,
|
|
+ guint n_construct_params,
|
|
+ GObjectConstructParam *construct_params)
|
|
+{
|
|
+ IBusXKBEngine *engine;
|
|
+
|
|
+ engine = (IBusXKBEngine *) G_OBJECT_CLASS (parent_class)->constructor (type,
|
|
+ n_construct_params,
|
|
+ construct_params);
|
|
+
|
|
+ return (GObject *) engine;
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_engine_destroy (IBusObject *object)
|
|
+{
|
|
+ IBUS_OBJECT_CLASS (parent_class)->destroy (object);
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_engine_enable (IBusEngine *engine)
|
|
+{
|
|
+ parent_class->enable (engine);
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_engine_disable (IBusEngine *engine)
|
|
+{
|
|
+ parent_class->disable (engine);
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_engine_focus_in (IBusEngine *engine)
|
|
+{
|
|
+ parent_class->focus_in (engine);
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_engine_focus_out (IBusEngine *engine)
|
|
+{
|
|
+ parent_class->focus_out (engine);
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_engine_class_init (IBusXKBEngineClass *klass)
|
|
+{
|
|
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
+ IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
|
|
+ IBusEngineClass *engine_class = IBUS_ENGINE_CLASS (klass);
|
|
+
|
|
+ parent_class = (IBusEngineClass *) g_type_class_peek_parent (klass);
|
|
+ object_class->constructor = ibus_xkb_engine_constructor;
|
|
+ ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_xkb_engine_destroy;
|
|
+ engine_class->enable = ibus_xkb_engine_enable;
|
|
+ engine_class->disable = ibus_xkb_engine_disable;
|
|
+ engine_class->focus_in = ibus_xkb_engine_focus_in;
|
|
+ engine_class->focus_out = ibus_xkb_engine_focus_out;
|
|
+
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_engine_init (IBusXKBEngine *engine)
|
|
+{
|
|
+}
|
|
+
|
|
+GType
|
|
+ibus_xkb_engine_get_type (void)
|
|
+{
|
|
+ static GType type = 0;
|
|
+
|
|
+ static const GTypeInfo type_info = {
|
|
+ sizeof (IBusXKBEngineClass),
|
|
+ (GBaseInitFunc) NULL,
|
|
+ (GBaseFinalizeFunc) NULL,
|
|
+ (GClassInitFunc) ibus_xkb_engine_class_init,
|
|
+ NULL,
|
|
+ NULL,
|
|
+ sizeof (IBusXKBEngine),
|
|
+ 0,
|
|
+ (GInstanceInitFunc) ibus_xkb_engine_init,
|
|
+ };
|
|
+
|
|
+ if (type == 0) {
|
|
+ type = g_type_register_static (IBUS_TYPE_ENGINE,
|
|
+ "IBusXKBEngine",
|
|
+ &type_info,
|
|
+ (GTypeFlags) 0);
|
|
+ }
|
|
+
|
|
+ return type;
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_disconnected_cb (IBusBus *bus,
|
|
+ gpointer user_data)
|
|
+{
|
|
+ g_debug ("bus disconnected");
|
|
+ ibus_quit ();
|
|
+}
|
|
+
|
|
+static void
|
|
+_factory_lookup_engine_name_cb (IBusFactory *factory,
|
|
+ const gchar *engine_name,
|
|
+ gpointer data)
|
|
+{
|
|
+ static GList *engine_list = NULL;
|
|
+ GList *list;
|
|
+ gboolean has_name = FALSE;
|
|
+
|
|
+ g_return_if_fail (engine_name != NULL);
|
|
+
|
|
+ if (g_strcmp0 (engine_name, "xkb:layout:us") == 0) {
|
|
+ return;
|
|
+ }
|
|
+ list = engine_list;
|
|
+ while (list) {
|
|
+ if (g_strcmp0 (list->data, engine_name) == 0) {
|
|
+ has_name = TRUE;
|
|
+ break;
|
|
+ }
|
|
+ list = list->next;
|
|
+ }
|
|
+ if (has_name) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ ibus_factory_add_engine (factory, engine_name, IBUS_TYPE_XKB_ENGINE);
|
|
+ engine_list = g_list_append (engine_list, (gpointer) g_strdup (engine_name));
|
|
+}
|
|
+
|
|
+static void
|
|
+start_component (int argc, char **argv)
|
|
+{
|
|
+ IBusComponent *component;
|
|
+
|
|
+ ibus_init ();
|
|
+
|
|
+ bus = ibus_bus_new ();
|
|
+ g_signal_connect (bus, "disconnected", G_CALLBACK (ibus_disconnected_cb), NULL);
|
|
+
|
|
+ component = ibus_component_new ("org.freedesktop.IBus.XKB",
|
|
+ "XKB Component",
|
|
+ VERSION,
|
|
+ "LGPL2.1",
|
|
+ "Takao Fujiwara <takao.fujiwara1@gmail.com>",
|
|
+ "http://code.google.com/p/ibus/",
|
|
+ "",
|
|
+ GETTEXT_PACKAGE);
|
|
+ ibus_component_add_engine (component,
|
|
+ ibus_xkb_engine_desc_new ("eng",
|
|
+ "us",
|
|
+ "USA",
|
|
+ NULL,
|
|
+ NULL));
|
|
+
|
|
+ factory = ibus_factory_new (ibus_bus_get_connection (bus));
|
|
+
|
|
+ ibus_factory_add_engine (factory, "xkb:layout:us", IBUS_TYPE_XKB_ENGINE);
|
|
+
|
|
+ g_signal_connect (G_OBJECT (factory), "lookup-engine-name",
|
|
+ G_CALLBACK (_factory_lookup_engine_name_cb),
|
|
+ NULL);
|
|
+ if (ibus) {
|
|
+ ibus_bus_request_name (bus, "org.freedesktop.IBus.XKB", 0);
|
|
+ }
|
|
+ else {
|
|
+ ibus_bus_register_component (bus, component);
|
|
+ }
|
|
+
|
|
+ g_object_unref (component);
|
|
+
|
|
+ ibus_main ();
|
|
+}
|
|
+
|
|
+static gboolean
|
|
+is_included_engine_in_preload (const GList * preload_xkb_engines,
|
|
+ const gchar *layout,
|
|
+ const gchar *variant)
|
|
+{
|
|
+ const GList *list = preload_xkb_engines;
|
|
+ gchar *key = NULL;
|
|
+ gboolean retval = FALSE;
|
|
+
|
|
+ g_return_val_if_fail (layout != NULL, FALSE);
|
|
+
|
|
+ if (variant == NULL) {
|
|
+ key = g_strdup (layout);
|
|
+ } else {
|
|
+ key = g_strdup_printf ("%s(%s)", layout, variant);
|
|
+ }
|
|
+ while (list) {
|
|
+ if (list->data == NULL) {
|
|
+ continue;
|
|
+ }
|
|
+ if (g_strcmp0 ((const gchar *) list->data,
|
|
+ (const gchar *) key) == 0) {
|
|
+ retval = TRUE;
|
|
+ break;
|
|
+ }
|
|
+ list = list->next;
|
|
+ }
|
|
+ g_free (key);
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+static void
|
|
+print_component ()
|
|
+{
|
|
+ IBusXKBLayoutConfig *layout_config;
|
|
+ IBusXKBConfigRegistry *config_registry;
|
|
+ GHashTable *layout_list;
|
|
+ GHashTable *layout_lang;
|
|
+ GHashTable *layout_desc;
|
|
+ GHashTable *variant_desc;
|
|
+ IBusComponent *component;
|
|
+ IBusEngineDesc *engine;
|
|
+ const GList *preload_xkb_engines = NULL;
|
|
+ GList *keys;
|
|
+ GList *variants;
|
|
+ GList *langs;
|
|
+ gboolean is_preload;
|
|
+ gchar *layout_name;
|
|
+ const gchar *desc;
|
|
+ gchar *output;
|
|
+ GString *str;
|
|
+
|
|
+#ifdef XKBLAYOUTCONFIG_FILE
|
|
+ layout_config = ibus_xkb_layout_config_new (XKBLAYOUTCONFIG_FILE);
|
|
+ preload_xkb_engines = ibus_xkb_layout_config_get_preload_layouts (layout_config);
|
|
+#endif
|
|
+
|
|
+ config_registry = ibus_xkb_config_registry_new ();
|
|
+ layout_list = (GHashTable *) ibus_xkb_config_registry_get_layout_list (config_registry);
|
|
+ layout_lang = (GHashTable *) ibus_xkb_config_registry_get_layout_lang (config_registry);
|
|
+ layout_desc = (GHashTable *) ibus_xkb_config_registry_get_layout_desc (config_registry);
|
|
+ variant_desc = (GHashTable *) ibus_xkb_config_registry_get_variant_desc (config_registry);
|
|
+ component = ibus_xkb_component_new ();
|
|
+ for (keys = g_hash_table_get_keys (layout_list); keys; keys = keys->next) {
|
|
+ if (keys->data == NULL) {
|
|
+ continue;
|
|
+ }
|
|
+ desc = (const gchar *) g_hash_table_lookup (layout_desc, keys->data);
|
|
+ langs = (GList *) g_hash_table_lookup (layout_lang, keys->data);
|
|
+ for (;langs; langs = langs->next) {
|
|
+ if (langs->data == NULL) {
|
|
+ continue;
|
|
+ }
|
|
+ is_preload = FALSE;
|
|
+ if (!preload_xkb_engines) {
|
|
+ is_preload = TRUE;
|
|
+ } else {
|
|
+ is_preload = is_included_engine_in_preload (preload_xkb_engines,
|
|
+ (const gchar *) keys->data,
|
|
+ NULL);
|
|
+ }
|
|
+ if (is_preload) {
|
|
+ engine = ibus_xkb_engine_desc_new ((const gchar *) langs->data,
|
|
+ (const gchar *) keys->data,
|
|
+ desc,
|
|
+ NULL,
|
|
+ NULL);
|
|
+ ibus_component_add_engine (component, engine);
|
|
+ }
|
|
+ }
|
|
+ variants = (GList *) g_hash_table_lookup (layout_list, keys->data);
|
|
+ for (;variants; variants = variants->next) {
|
|
+ if (variants->data == NULL) {
|
|
+ continue;
|
|
+ }
|
|
+ layout_name = g_strdup_printf ("%s(%s)", (gchar *) keys->data,
|
|
+ (gchar *) variants->data);
|
|
+ langs = (GList *) g_hash_table_lookup (layout_lang, layout_name);
|
|
+ if (langs == NULL) {
|
|
+ g_free (layout_name);
|
|
+ layout_name = g_strdup ((gchar *) keys->data);
|
|
+ langs = (GList *) g_hash_table_lookup (layout_lang, layout_name);
|
|
+ }
|
|
+ g_free (layout_name);
|
|
+ for (;langs; langs = langs->next) {
|
|
+ if (langs->data == NULL) {
|
|
+ continue;
|
|
+ }
|
|
+ is_preload = FALSE;
|
|
+ if (!preload_xkb_engines) {
|
|
+ is_preload = TRUE;
|
|
+ } else {
|
|
+ is_preload = is_included_engine_in_preload (preload_xkb_engines,
|
|
+ (const gchar *) keys->data,
|
|
+ (const gchar *) variants->data);
|
|
+ }
|
|
+ if (is_preload) {
|
|
+ engine = ibus_xkb_engine_desc_new ((const gchar *) langs->data,
|
|
+ (const gchar *) keys->data,
|
|
+ desc,
|
|
+ (const gchar *) variants->data,
|
|
+ (const gchar *) g_hash_table_lookup (variant_desc, variants->data));
|
|
+ ibus_component_add_engine (component, engine);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ g_object_unref (G_OBJECT (config_registry));
|
|
+#ifdef XKBLAYOUTCONFIG_FILE
|
|
+ g_object_unref (G_OBJECT (layout_config));
|
|
+#endif
|
|
+
|
|
+ str = g_string_new (NULL);
|
|
+ ibus_component_output_engines (component , str, 0);
|
|
+ g_object_unref (G_OBJECT (component));
|
|
+
|
|
+ output = g_string_free (str, FALSE);
|
|
+ g_print ("%s\n", output);
|
|
+ g_free (output);
|
|
+}
|
|
+
|
|
+int
|
|
+main (int argc, char **argv)
|
|
+{
|
|
+ GError *error = NULL;
|
|
+ GOptionContext *context;
|
|
+
|
|
+#ifdef ENABLE_NLS
|
|
+ setlocale (LC_ALL, "");
|
|
+#endif
|
|
+
|
|
+ g_type_init ();
|
|
+
|
|
+ context = g_option_context_new ("- ibus xkb engine component");
|
|
+
|
|
+ g_option_context_add_main_entries (context, entries, "ibus-xbl");
|
|
+
|
|
+ if (!g_option_context_parse (context, &argc, &argv, &error)) {
|
|
+ g_print ("Option parsing failed: %s\n", error->message);
|
|
+ exit (-1);
|
|
+ }
|
|
+
|
|
+ if (xml) {
|
|
+ print_component ();
|
|
+ return 0;
|
|
+ }
|
|
+ start_component (argc, argv);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/xkb/ibus-engine-xkb-main.h b/xkb/ibus-engine-xkb-main.h
|
|
new file mode 100644
|
|
index 0000000..8007631
|
|
--- /dev/null
|
|
+++ b/xkb/ibus-engine-xkb-main.h
|
|
@@ -0,0 +1,46 @@
|
|
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
|
+/* vim:set et sts=4: */
|
|
+/* bus - The Input Bus
|
|
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Red Hat, Inc.
|
|
+ *
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Lesser General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2 of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This library is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * Lesser General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Lesser General Public
|
|
+ * License along with this library; if not, write to the
|
|
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ * Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+#ifndef __IBUS_ENGINE_XKB_MAIN_H_
|
|
+#define __IBUS_ENGINE_XKB_MAIN_H_
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+#include <config.h>
|
|
+#endif
|
|
+
|
|
+#include <ibus.h>
|
|
+
|
|
+G_BEGIN_DECLS
|
|
+
|
|
+typedef struct _IBusXKBEngine IBusXKBEngine;
|
|
+typedef struct _IBusXKBEngineClass IBusXKBEngineClass;
|
|
+
|
|
+struct _IBusXKBEngine {
|
|
+ IBusEngine engine;
|
|
+};
|
|
+
|
|
+struct _IBusXKBEngineClass {
|
|
+ IBusEngineClass parent;
|
|
+};
|
|
+
|
|
+G_END_DECLS
|
|
+#endif
|
|
diff --git a/xkb/ibus-xkb-main.c b/xkb/ibus-xkb-main.c
|
|
new file mode 100644
|
|
index 0000000..9db7d0a
|
|
--- /dev/null
|
|
+++ b/xkb/ibus-xkb-main.c
|
|
@@ -0,0 +1,105 @@
|
|
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
|
+/* vim:set et sts=4: */
|
|
+/* bus - The Input Bus
|
|
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Red Hat, Inc.
|
|
+ *
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Lesser General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2 of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This library is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * Lesser General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Lesser General Public
|
|
+ * License along with this library; if not, write to the
|
|
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ * Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+#ifdef HAVE_CONFIG_H
|
|
+#include <config.h>
|
|
+#endif
|
|
+
|
|
+#include <glib.h>
|
|
+#include <glib/gprintf.h>
|
|
+#include <glib/gi18n.h>
|
|
+#include <X11/Xlib.h>
|
|
+
|
|
+#ifdef ENABLE_NLS
|
|
+#include <locale.h>
|
|
+#endif
|
|
+
|
|
+#include "xkblib.h"
|
|
+
|
|
+static gboolean get_layout = FALSE;
|
|
+static gchar *layout = NULL;
|
|
+static gchar *model = NULL;
|
|
+static gchar *option = 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. */
|
|
+ { "layout", 'l', 0, G_OPTION_ARG_STRING, &layout, N_("Set xkb layout"), "layout" },
|
|
+ { "model", 'm', 0, G_OPTION_ARG_STRING, &model, N_("Set xkb model"), "model" },
|
|
+ { "option", 'o', 0, G_OPTION_ARG_STRING, &option, N_("Set xkb option"), "option" },
|
|
+ { 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);
|
|
+ if (xdisplay == NULL) {
|
|
+ g_warning ("Could not open display");
|
|
+ return -1;
|
|
+ }
|
|
+ ibus_xkb_init (xdisplay);
|
|
+
|
|
+ if (layout) {
|
|
+ ibus_xkb_set_layout (layout, model, option);
|
|
+ }
|
|
+ if (get_layout) {
|
|
+ layout = ibus_xkb_get_current_layout ();
|
|
+ model = ibus_xkb_get_current_model ();
|
|
+ option = ibus_xkb_get_current_option ();
|
|
+ g_printf ("layout: %s\n"
|
|
+ "model: %s\n"
|
|
+ "option: %s\n",
|
|
+ layout ? layout : "",
|
|
+ model ? model : "",
|
|
+ option ? option : "");
|
|
+ g_free (layout);
|
|
+ g_free (model);
|
|
+ g_free (option);
|
|
+ }
|
|
+
|
|
+ ibus_xkb_finit ();
|
|
+
|
|
+ return 0;
|
|
+}
|
|
diff --git a/xkb/xkblayout.xml.in b/xkb/xkblayout.xml.in
|
|
new file mode 100644
|
|
index 0000000..0b5a4dc
|
|
--- /dev/null
|
|
+++ b/xkb/xkblayout.xml.in
|
|
@@ -0,0 +1,16 @@
|
|
+<?xml version="1.0" encoding="utf-8"?>
|
|
+<component>
|
|
+ <name>org.freedesktop.IBus.XKB</name>
|
|
+ <description>XKB Component</description>
|
|
+ <exec>@libexecdir@/ibus-engine-xkb --ibus</exec>
|
|
+ <version>0.0.0</version>
|
|
+ <author>Takao Fujiwara <takao.fujiwara1@gmail.com></author>
|
|
+ <license>LGPL2.1</license>
|
|
+ <homepage>http://code.google.com/p/ibus/</homepage>
|
|
+ <textdomain>ibus</textdomain>
|
|
+ <observed-paths>
|
|
+ <path>@datadir@/ibus/xkb/xkblayoutconfig.xml</path>
|
|
+ <path>~/.config/ibus/xkb/xkblayoutconfig.xml</path>
|
|
+ </observed-paths>
|
|
+ <engines exec="@libexecdir@/ibus-engine-xkb --xml"/>
|
|
+</component>
|
|
diff --git a/xkb/xkblayoutconfig.xml.in b/xkb/xkblayoutconfig.xml.in
|
|
new file mode 100644
|
|
index 0000000..b1212d1
|
|
--- /dev/null
|
|
+++ b/xkb/xkblayoutconfig.xml.in
|
|
@@ -0,0 +1,6 @@
|
|
+<?xml version="1.0" encoding="utf-8"?>
|
|
+<xkblayout>
|
|
+ <config>
|
|
+ <preload_layouts>@XKB_PRELOAD_LAYOUTS@</preload_layouts>
|
|
+ </config>
|
|
+</xkblayout>
|
|
diff --git a/xkb/xkblib.c b/xkb/xkblib.c
|
|
new file mode 100644
|
|
index 0000000..1f6f8d7
|
|
--- /dev/null
|
|
+++ b/xkb/xkblib.c
|
|
@@ -0,0 +1,297 @@
|
|
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
|
+/* vim:set et sts=4: */
|
|
+/* bus - The Input Bus
|
|
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Red Hat, Inc.
|
|
+ *
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Lesser General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2 of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This library is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * Lesser General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Lesser General Public
|
|
+ * License along with this library; if not, write to the
|
|
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ * Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+#ifdef HAVE_CONFIG_H
|
|
+#include <config.h>
|
|
+#endif
|
|
+
|
|
+#include <glib.h>
|
|
+#include <X11/Xlib.h>
|
|
+#include <X11/Xatom.h>
|
|
+#include <X11/XKBlib.h>
|
|
+#include <stdio.h> /* for XKBrules.h */
|
|
+#include <X11/extensions/XKBrules.h>
|
|
+#include <X11/extensions/XKBstr.h>
|
|
+#include <string.h>
|
|
+
|
|
+#include "xkblib.h"
|
|
+
|
|
+#ifndef XKB_RULES_XML_FILE
|
|
+#define XKB_RULES_XML_FILE "/usr/share/X11/xkb/rules/evdev.xml"
|
|
+#endif
|
|
+
|
|
+static gchar **default_layouts;
|
|
+static gchar **default_models;
|
|
+static gchar **default_options;
|
|
+static int default_layout_group;
|
|
+
|
|
+static Display *
|
|
+get_xdisplay (Display *xdisplay)
|
|
+{
|
|
+ static Display *saved_xdisplay = NULL;
|
|
+ if (xdisplay != NULL) {
|
|
+ saved_xdisplay = xdisplay;
|
|
+ }
|
|
+ return saved_xdisplay;
|
|
+}
|
|
+
|
|
+static void
|
|
+init_xkb_default_layouts (Display *xdisplay)
|
|
+{
|
|
+ XkbStateRec state;
|
|
+ Atom xkb_rules_name, type;
|
|
+ int format;
|
|
+ unsigned long l, nitems, bytes_after;
|
|
+ unsigned char *prop = NULL;
|
|
+
|
|
+ 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);
|
|
+ prop += strlen ((const char *) prop) + 1;
|
|
+ default_models = g_strsplit ((gchar *) prop, ",", -1);
|
|
+ prop += strlen ((const char *) prop) + 1;
|
|
+ default_options = 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);
|
|
+}
|
|
+
|
|
+void
|
|
+ibus_xkb_finit (void)
|
|
+{
|
|
+ g_strfreev (default_layouts);
|
|
+ default_layouts = NULL;
|
|
+ g_strfreev (default_models);
|
|
+ default_models = NULL;
|
|
+ g_strfreev (default_options);
|
|
+ default_options = NULL;
|
|
+}
|
|
+
|
|
+gchar *
|
|
+ibus_xkb_get_current_layout (void)
|
|
+{
|
|
+ g_assert (default_layouts != NULL);
|
|
+
|
|
+ return g_strjoinv (",", (gchar **) default_layouts);
|
|
+}
|
|
+
|
|
+gchar *
|
|
+ibus_xkb_get_current_model (void)
|
|
+{
|
|
+ if (default_models == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return g_strjoinv (",", (gchar **) default_models);
|
|
+}
|
|
+
|
|
+gchar *
|
|
+ibus_xkb_get_current_option (void)
|
|
+{
|
|
+ if (default_options == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ return g_strjoinv (",", (gchar **) default_options);
|
|
+}
|
|
+
|
|
+gboolean
|
|
+ibus_xkb_set_layout (const char *layouts,
|
|
+ const char *variants,
|
|
+ const char *options)
|
|
+{
|
|
+ Display *xdisplay;
|
|
+ gboolean retval;
|
|
+ gchar *layouts_line;
|
|
+
|
|
+ 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..09d506d
|
|
--- /dev/null
|
|
+++ b/xkb/xkblib.h
|
|
@@ -0,0 +1,40 @@
|
|
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
|
+/* vim:set et sts=4: */
|
|
+/* bus - The Input Bus
|
|
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Red Hat, Inc.
|
|
+ *
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Lesser General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2 of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This library is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * Lesser General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Lesser General Public
|
|
+ * License along with this library; if not, write to the
|
|
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ * Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+#ifndef __XKBLIB_H_
|
|
+#define __XKBLIB_H_
|
|
+
|
|
+#include <X11/Xlib.h>
|
|
+
|
|
+G_BEGIN_DECLS
|
|
+
|
|
+void ibus_xkb_init (Display *xdisplay);
|
|
+void ibus_xkb_finit (void);
|
|
+gchar *ibus_xkb_get_current_layout (void);
|
|
+gchar *ibus_xkb_get_current_model (void);
|
|
+gchar *ibus_xkb_get_current_option (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..5e9885c
|
|
--- /dev/null
|
|
+++ b/xkb/xkbxml.c
|
|
@@ -0,0 +1,696 @@
|
|
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
|
+/* vim:set et sts=4: */
|
|
+/* bus - The Input Bus
|
|
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Red Hat, Inc.
|
|
+ *
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Lesser General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2 of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This library is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * Lesser General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Lesser General Public
|
|
+ * License along with this library; if not, write to the
|
|
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ * Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+#ifdef HAVE_CONFIG_H
|
|
+#include <config.h>
|
|
+#endif
|
|
+
|
|
+#include <glib.h>
|
|
+
|
|
+#include "xkbxml.h"
|
|
+#include "ibus.h"
|
|
+
|
|
+#ifndef XKB_RULES_XML_FILE
|
|
+#define XKB_RULES_XML_FILE "/usr/share/X11/xkb/rules/evdev.xml"
|
|
+#endif
|
|
+
|
|
+#define IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE(o) \
|
|
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryPrivate))
|
|
+#define IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE(o) \
|
|
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_XKB_LAYOUT_CONFIG, IBusXKBLayoutConfigPrivate))
|
|
+
|
|
+typedef struct _IBusXKBConfigRegistryPrivate IBusXKBConfigRegistryPrivate;
|
|
+typedef struct _IBusXKBLayoutConfigPrivate IBusXKBLayoutConfigPrivate;
|
|
+
|
|
+enum {
|
|
+ PROP_0,
|
|
+ PROP_SYSTEM_CONFIG_FILE,
|
|
+};
|
|
+
|
|
+struct _IBusXKBConfigRegistryPrivate {
|
|
+ GHashTable *layout_list;
|
|
+ GHashTable *layout_lang;
|
|
+ GHashTable *layout_desc;
|
|
+ GHashTable *variant_desc;
|
|
+};
|
|
+
|
|
+struct _IBusXKBLayoutConfigPrivate {
|
|
+ gchar *system_config_file;
|
|
+ GList *preload_layouts;
|
|
+};
|
|
+
|
|
+/* functions prototype */
|
|
+static void ibus_xkb_config_registry_destroy
|
|
+ (IBusXKBConfigRegistry *xkb_config);
|
|
+static void ibus_xkb_layout_config_destroy
|
|
+ (IBusXKBLayoutConfig *xkb_layout_config);
|
|
+
|
|
+G_DEFINE_TYPE (IBusXKBConfigRegistry, ibus_xkb_config_registry, IBUS_TYPE_OBJECT)
|
|
+G_DEFINE_TYPE (IBusXKBLayoutConfig, ibus_xkb_layout_config, IBUS_TYPE_OBJECT)
|
|
+
|
|
+static void
|
|
+parse_xkb_xml_languagelist_node (IBusXKBConfigRegistryPrivate *priv,
|
|
+ XMLNode *parent_node,
|
|
+ const gchar *layout_name)
|
|
+{
|
|
+ XMLNode *node = parent_node;
|
|
+ XMLNode *sub_node;
|
|
+ GList *p;
|
|
+ GList *lang_list = NULL;
|
|
+
|
|
+ g_assert (node != NULL);
|
|
+ g_assert (layout_name != NULL);
|
|
+ for (p = node->sub_nodes; p; p = p->next) {
|
|
+ sub_node = (XMLNode *) p->data;
|
|
+ if (g_strcmp0 (sub_node->name, "iso639Id") == 0) {
|
|
+ lang_list = g_list_append (lang_list,
|
|
+ (gpointer) g_strdup (sub_node->text));
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ if (lang_list == NULL) {
|
|
+ /* some nodes have no lang */
|
|
+ return;
|
|
+ }
|
|
+ if (g_hash_table_lookup (priv->layout_lang, layout_name) != NULL) {
|
|
+ g_warning ("duplicated name %s exists", layout_name);
|
|
+ return;
|
|
+ }
|
|
+ g_hash_table_insert (priv->layout_lang,
|
|
+ (gpointer) g_strdup (layout_name),
|
|
+ (gpointer) lang_list);
|
|
+}
|
|
+
|
|
+static const gchar *
|
|
+parse_xkb_xml_configitem_node (IBusXKBConfigRegistryPrivate *priv,
|
|
+ XMLNode *parent_node)
|
|
+{
|
|
+ XMLNode *node = parent_node;
|
|
+ XMLNode *sub_node;
|
|
+ GList *p;
|
|
+ gchar *name = NULL;
|
|
+ gchar *description = NULL;
|
|
+
|
|
+ g_assert (node != NULL);
|
|
+ for (p = node->sub_nodes; p; p = p->next) {
|
|
+ sub_node = (XMLNode *) p->data;
|
|
+ if (g_strcmp0 (sub_node->name, "name") == 0) {
|
|
+ name = sub_node->text;
|
|
+ continue;
|
|
+ }
|
|
+ if (g_strcmp0 (sub_node->name, "description") == 0) {
|
|
+ description = sub_node->text;
|
|
+ continue;
|
|
+ }
|
|
+ if (g_strcmp0 (sub_node->name, "languageList") == 0) {
|
|
+ if (name == NULL) {
|
|
+ g_warning ("layout name is NULL in node %s", node->name);
|
|
+ continue;
|
|
+ }
|
|
+ parse_xkb_xml_languagelist_node (priv, sub_node, name);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ if (name == NULL) {
|
|
+ g_warning ("No name in layout node");
|
|
+ return NULL;
|
|
+ }
|
|
+ if (g_hash_table_lookup (priv->layout_desc, name) != NULL) {
|
|
+ g_warning ("duplicated name %s exists", name);
|
|
+ return name;
|
|
+ }
|
|
+ g_hash_table_insert (priv->layout_desc,
|
|
+ (gpointer) g_strdup (name),
|
|
+ (gpointer) g_strdup (description));
|
|
+
|
|
+ return name;
|
|
+}
|
|
+
|
|
+static const gchar *
|
|
+parse_xkb_xml_variant_configitem_node (IBusXKBConfigRegistryPrivate *priv,
|
|
+ XMLNode *parent_node,
|
|
+ const gchar *layout_name)
|
|
+{
|
|
+ XMLNode *node = parent_node;
|
|
+ XMLNode *sub_node;
|
|
+ GList *p;
|
|
+ gchar *name = NULL;
|
|
+ gchar *description = NULL;
|
|
+ gchar *variant_lang_name = NULL;
|
|
+
|
|
+ g_assert (node != NULL);
|
|
+ g_assert (layout_name != NULL);
|
|
+ for (p = node->sub_nodes; p; p = p->next) {
|
|
+ sub_node = (XMLNode *) p->data;
|
|
+ if (g_strcmp0 (sub_node->name, "name") == 0) {
|
|
+ name = sub_node->text;
|
|
+ continue;
|
|
+ }
|
|
+ if (g_strcmp0 (sub_node->name, "description") == 0) {
|
|
+ description = sub_node->text;
|
|
+ continue;
|
|
+ }
|
|
+ if (g_strcmp0 (sub_node->name, "languageList") == 0) {
|
|
+ if (name == NULL) {
|
|
+ g_warning ("layout name is NULL in node %s", node->name);
|
|
+ continue;
|
|
+ }
|
|
+ variant_lang_name = g_strdup_printf ("%s(%s)", layout_name, name);
|
|
+ parse_xkb_xml_languagelist_node (priv, sub_node, variant_lang_name);
|
|
+ g_free (variant_lang_name);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ if (name == NULL) {
|
|
+ g_warning ("No name in layout node");
|
|
+ return NULL;
|
|
+ }
|
|
+ if (g_hash_table_lookup (priv->variant_desc, name) != NULL) {
|
|
+ /* This is an expected case. */
|
|
+ return name;
|
|
+ }
|
|
+ g_hash_table_insert (priv->variant_desc,
|
|
+ (gpointer) g_strdup (name),
|
|
+ (gpointer) g_strdup (description));
|
|
+ return name;
|
|
+}
|
|
+
|
|
+static const gchar *
|
|
+parse_xkb_xml_variant_node (IBusXKBConfigRegistryPrivate *priv,
|
|
+ XMLNode *parent_node,
|
|
+ const gchar *layout_name)
|
|
+{
|
|
+ XMLNode *node = parent_node;
|
|
+ XMLNode *sub_node;
|
|
+ GList *p;
|
|
+ const gchar *variant_name = NULL;
|
|
+
|
|
+ g_assert (node != NULL);
|
|
+ g_assert (layout_name != NULL);
|
|
+ for (p = node->sub_nodes; p; p = p->next) {
|
|
+ sub_node = (XMLNode *) p->data;
|
|
+ if (g_strcmp0 (sub_node->name, "configItem") == 0) {
|
|
+ variant_name = parse_xkb_xml_variant_configitem_node (priv, sub_node, layout_name);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ return variant_name;
|
|
+}
|
|
+
|
|
+static GList *
|
|
+parse_xkb_xml_variantlist_node (IBusXKBConfigRegistryPrivate *priv,
|
|
+ XMLNode *parent_node,
|
|
+ const gchar *layout_name,
|
|
+ GList *variant_list)
|
|
+{
|
|
+ XMLNode *node = parent_node;
|
|
+ XMLNode *sub_node;
|
|
+ GList *p;
|
|
+ const gchar *variant_name = NULL;
|
|
+
|
|
+ g_assert (node != NULL);
|
|
+ g_assert (layout_name != NULL);
|
|
+ for (p = node->sub_nodes; p; p = p->next) {
|
|
+ sub_node = (XMLNode *) p->data;
|
|
+ if (g_strcmp0 (sub_node->name, "variant") == 0) {
|
|
+ variant_name = parse_xkb_xml_variant_node (priv, sub_node, layout_name);
|
|
+ if (variant_name != NULL) {
|
|
+ variant_list = g_list_append (variant_list,
|
|
+ (gpointer) g_strdup (variant_name));
|
|
+ }
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ return variant_list;
|
|
+}
|
|
+
|
|
+static void
|
|
+parse_xkb_xml_layout_node (IBusXKBConfigRegistryPrivate *priv,
|
|
+ XMLNode *parent_node)
|
|
+{
|
|
+ XMLNode *node = parent_node;
|
|
+ XMLNode *sub_node;
|
|
+ GList *p;
|
|
+ const gchar *name = NULL;
|
|
+ GList *variant_list = NULL;
|
|
+
|
|
+ g_assert (node != NULL);
|
|
+ for (p = node->sub_nodes; p; p = p->next) {
|
|
+ sub_node = (XMLNode *) p->data;
|
|
+ if (g_strcmp0 (sub_node->name, "configItem") == 0) {
|
|
+ name = parse_xkb_xml_configitem_node (priv, sub_node);
|
|
+ continue;
|
|
+ }
|
|
+ if (g_strcmp0 (sub_node->name, "variantList") == 0) {
|
|
+ if (name == NULL) {
|
|
+ g_warning ("layout name is NULL in node %s", node->name);
|
|
+ continue;
|
|
+ }
|
|
+ variant_list = parse_xkb_xml_variantlist_node (priv, sub_node,
|
|
+ name,
|
|
+ variant_list);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+ if (g_hash_table_lookup (priv->layout_list, name) != NULL) {
|
|
+ g_warning ("duplicated name %s exists", name);
|
|
+ return;
|
|
+ }
|
|
+ g_hash_table_insert (priv->layout_list,
|
|
+ (gpointer) g_strdup (name),
|
|
+ (gpointer) variant_list);
|
|
+}
|
|
+
|
|
+static void
|
|
+parse_xkb_xml_top_node (IBusXKBConfigRegistryPrivate *priv,
|
|
+ XMLNode *parent_node)
|
|
+{
|
|
+ XMLNode *node = parent_node;
|
|
+ XMLNode *sub_node;
|
|
+ GList *p;
|
|
+
|
|
+ g_assert (priv != NULL);
|
|
+ g_assert (node != NULL);
|
|
+
|
|
+ if (g_strcmp0 (node->name, "xkbConfigRegistry") != 0) {
|
|
+ g_warning ("node has no xkbConfigRegistry name");
|
|
+ return;
|
|
+ }
|
|
+ for (p = node->sub_nodes; p; p = p->next) {
|
|
+ sub_node = (XMLNode *) p->data;
|
|
+ if (g_strcmp0 (sub_node->name, "layoutList") == 0) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (p == NULL) {
|
|
+ g_warning ("xkbConfigRegistry node has no layoutList node");
|
|
+ return;
|
|
+ }
|
|
+ node = sub_node;
|
|
+ for (p = node->sub_nodes; p; p = p->next) {
|
|
+ sub_node = (XMLNode *) p->data;
|
|
+ if (g_strcmp0 (sub_node->name, "layout") == 0) {
|
|
+ parse_xkb_xml_layout_node (priv, sub_node);
|
|
+ continue;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+free_lang_list (GList *list)
|
|
+{
|
|
+ GList *l = list;
|
|
+ while (l) {
|
|
+ g_free (l->data);
|
|
+ l->data = NULL;
|
|
+ l = l->next;
|
|
+ }
|
|
+ g_list_free (list);
|
|
+}
|
|
+
|
|
+static void
|
|
+parse_xkb_config_registry_file (IBusXKBConfigRegistryPrivate *priv,
|
|
+ const gchar *file)
|
|
+{
|
|
+ XMLNode *node;
|
|
+
|
|
+ g_assert (file != NULL);
|
|
+
|
|
+ priv->layout_list = g_hash_table_new_full (g_str_hash,
|
|
+ (GEqualFunc) g_str_equal,
|
|
+ (GDestroyNotify) g_free,
|
|
+ (GDestroyNotify) free_lang_list);
|
|
+ priv->layout_desc = g_hash_table_new_full (g_str_hash,
|
|
+ (GEqualFunc) g_str_equal,
|
|
+ (GDestroyNotify) g_free,
|
|
+ (GDestroyNotify) g_free);
|
|
+ priv->layout_lang = g_hash_table_new_full (g_str_hash,
|
|
+ (GEqualFunc) g_str_equal,
|
|
+ (GDestroyNotify) g_free,
|
|
+ (GDestroyNotify) free_lang_list);
|
|
+ priv->variant_desc = g_hash_table_new_full (g_str_hash,
|
|
+ (GEqualFunc) g_str_equal,
|
|
+ (GDestroyNotify) g_free,
|
|
+ (GDestroyNotify) g_free);
|
|
+ node = ibus_xml_parse_file (file);
|
|
+ parse_xkb_xml_top_node (priv, node);
|
|
+ ibus_xml_free (node);
|
|
+}
|
|
+
|
|
+static GList *
|
|
+parse_xkblayoutconfig_file (gchar *path)
|
|
+{
|
|
+ XMLNode *node = NULL;
|
|
+ XMLNode *sub_node;
|
|
+ XMLNode *sub_sub_node;
|
|
+ GList *p;
|
|
+ GList *retval = NULL;
|
|
+ gchar **array;
|
|
+ int i;
|
|
+
|
|
+ node = ibus_xml_parse_file (path);
|
|
+ if (node == NULL) {
|
|
+ return NULL;
|
|
+ }
|
|
+ if (g_strcmp0 (node->name, "xkblayout") != 0) {
|
|
+ ibus_xml_free (node);
|
|
+ return NULL;
|
|
+ }
|
|
+ for (p = node->sub_nodes; p != NULL; p = p->next) {
|
|
+ sub_node = (XMLNode *) p->data;
|
|
+ if (g_strcmp0 (sub_node->name, "config") == 0) {
|
|
+ GList *pp;
|
|
+ for (pp = sub_node->sub_nodes; pp != NULL; pp = pp->next) {
|
|
+ sub_sub_node = (XMLNode *) pp->data;
|
|
+ if (g_strcmp0 (sub_sub_node->name, "preload_layouts") == 0) {
|
|
+ if (sub_sub_node->text != NULL) {
|
|
+ array = g_strsplit ((gchar *) sub_sub_node->text,
|
|
+ ",", -1);
|
|
+ for (i = 0; array[i]; i++) {
|
|
+ retval = g_list_append (retval, g_strdup (array[i]));
|
|
+ }
|
|
+ g_strfreev (array);
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ if (retval != NULL) {
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ ibus_xml_free (node);
|
|
+ return retval;
|
|
+}
|
|
+
|
|
+static void
|
|
+parse_xkb_layout_config (IBusXKBLayoutConfigPrivate *priv)
|
|
+{
|
|
+ gchar *basename;
|
|
+ gchar *user_config;
|
|
+ GList *list = NULL;
|
|
+
|
|
+ g_return_if_fail (priv->system_config_file != NULL);
|
|
+
|
|
+ basename = g_path_get_basename (priv->system_config_file);
|
|
+ user_config = g_build_filename (g_get_user_config_dir (),
|
|
+ "ibus", "xkb",
|
|
+ basename, NULL);
|
|
+ g_free (basename);
|
|
+ list = parse_xkblayoutconfig_file (user_config);
|
|
+ g_free (user_config);
|
|
+ if (list) {
|
|
+ priv->preload_layouts = list;
|
|
+ return;
|
|
+ }
|
|
+ list = parse_xkblayoutconfig_file (priv->system_config_file);
|
|
+ priv->preload_layouts = list;
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_config_registry_init (IBusXKBConfigRegistry *xkb_config)
|
|
+{
|
|
+ IBusXKBConfigRegistryPrivate *priv;
|
|
+ const gchar *file = XKB_RULES_XML_FILE;
|
|
+
|
|
+ priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config);
|
|
+ parse_xkb_config_registry_file (priv, file);
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_config_registry_destroy (IBusXKBConfigRegistry *xkb_config)
|
|
+{
|
|
+ IBusXKBConfigRegistryPrivate *priv;
|
|
+
|
|
+ g_return_if_fail (xkb_config != NULL);
|
|
+
|
|
+ priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config);
|
|
+
|
|
+ g_hash_table_destroy (priv->layout_list);
|
|
+ priv->layout_list = NULL;
|
|
+ g_hash_table_destroy (priv->layout_lang);
|
|
+ priv->layout_lang= NULL;
|
|
+ g_hash_table_destroy (priv->layout_desc);
|
|
+ priv->layout_desc= NULL;
|
|
+ g_hash_table_destroy (priv->variant_desc);
|
|
+ priv->variant_desc = NULL;
|
|
+
|
|
+ IBUS_OBJECT_CLASS(ibus_xkb_config_registry_parent_class)->destroy (IBUS_OBJECT (xkb_config));
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_config_registry_class_init (IBusXKBConfigRegistryClass *klass)
|
|
+{
|
|
+ IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
|
|
+
|
|
+ g_type_class_add_private (klass, sizeof (IBusXKBConfigRegistryPrivate));
|
|
+
|
|
+ ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_xkb_config_registry_destroy;
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_layout_config_init (IBusXKBLayoutConfig *xkb_layout_config)
|
|
+{
|
|
+ IBusXKBLayoutConfigPrivate *priv;
|
|
+
|
|
+ priv = IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE (xkb_layout_config);
|
|
+ priv->system_config_file = NULL;
|
|
+ priv->preload_layouts = NULL;
|
|
+}
|
|
+
|
|
+static GObject *
|
|
+ibus_xkb_layout_config_constructor (GType type,
|
|
+ guint n_construct_params,
|
|
+ GObjectConstructParam *construct_params)
|
|
+{
|
|
+ GObject *obj;
|
|
+ IBusXKBLayoutConfig *xkb_layout_config;
|
|
+ IBusXKBLayoutConfigPrivate *priv;
|
|
+
|
|
+ obj = G_OBJECT_CLASS (ibus_xkb_layout_config_parent_class)->constructor (type, n_construct_params, construct_params);
|
|
+ xkb_layout_config = IBUS_XKB_LAYOUT_CONFIG (obj);
|
|
+ priv = IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE (xkb_layout_config);
|
|
+ parse_xkb_layout_config (priv);
|
|
+
|
|
+ return obj;
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_layout_config_destroy (IBusXKBLayoutConfig *xkb_layout_config)
|
|
+{
|
|
+ IBusXKBLayoutConfigPrivate *priv;
|
|
+
|
|
+ g_return_if_fail (xkb_layout_config != NULL);
|
|
+
|
|
+ priv = IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE (xkb_layout_config);
|
|
+
|
|
+ g_free (priv->system_config_file);
|
|
+ priv->system_config_file = NULL;
|
|
+ free_lang_list (priv->preload_layouts);
|
|
+ priv->preload_layouts = NULL;
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_layout_config_set_property (IBusXKBLayoutConfig *xkb_layout_config,
|
|
+ guint prop_id,
|
|
+ const GValue *value,
|
|
+ GParamSpec *pspec)
|
|
+{
|
|
+ IBusXKBLayoutConfigPrivate *priv;
|
|
+
|
|
+ g_return_if_fail (xkb_layout_config != NULL);
|
|
+ priv = IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE (xkb_layout_config);
|
|
+
|
|
+ switch (prop_id) {
|
|
+ case PROP_SYSTEM_CONFIG_FILE:
|
|
+ g_assert (priv->system_config_file == NULL);
|
|
+ priv->system_config_file = g_strdup (g_value_get_string (value));
|
|
+ break;
|
|
+ default:
|
|
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (xkb_layout_config, prop_id, pspec);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_layout_config_get_property (IBusXKBLayoutConfig *xkb_layout_config,
|
|
+ guint prop_id,
|
|
+ GValue *value,
|
|
+ GParamSpec *pspec)
|
|
+{
|
|
+ IBusXKBLayoutConfigPrivate *priv;
|
|
+
|
|
+ g_return_if_fail (xkb_layout_config != NULL);
|
|
+ priv = IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE (xkb_layout_config);
|
|
+
|
|
+ switch (prop_id) {
|
|
+ case PROP_SYSTEM_CONFIG_FILE:
|
|
+ g_value_set_string (value, priv->system_config_file);
|
|
+ break;
|
|
+ default:
|
|
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (xkb_layout_config, prop_id, pspec);
|
|
+
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+ibus_xkb_layout_config_class_init (IBusXKBLayoutConfigClass *klass)
|
|
+{
|
|
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
+ IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
|
|
+
|
|
+ g_type_class_add_private (klass, sizeof (IBusXKBLayoutConfigPrivate));
|
|
+
|
|
+ gobject_class->constructor = ibus_xkb_layout_config_constructor;
|
|
+ gobject_class->set_property = (GObjectSetPropertyFunc) ibus_xkb_layout_config_set_property;
|
|
+ gobject_class->get_property = (GObjectGetPropertyFunc) ibus_xkb_layout_config_get_property;
|
|
+ ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_xkb_layout_config_destroy;
|
|
+
|
|
+ /**
|
|
+ * IBusProxy:interface:
|
|
+ *
|
|
+ * The interface of the proxy object.
|
|
+ */
|
|
+ g_object_class_install_property (gobject_class,
|
|
+ PROP_SYSTEM_CONFIG_FILE,
|
|
+ g_param_spec_string ("system_config_file",
|
|
+ "system_config_file",
|
|
+ "The system file of xkblayoutconfig",
|
|
+ NULL,
|
|
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
|
+}
|
|
+
|
|
+IBusXKBConfigRegistry *
|
|
+ibus_xkb_config_registry_new (void)
|
|
+{
|
|
+ IBusXKBConfigRegistry *xkb_config;
|
|
+
|
|
+ xkb_config = IBUS_XKB_CONFIG_REGISTRY (g_object_new (IBUS_TYPE_XKB_CONFIG_REGISTRY, NULL));
|
|
+ return xkb_config;
|
|
+}
|
|
+
|
|
+#define TABLE_FUNC(field_name) const GHashTable * \
|
|
+ibus_xkb_config_registry_get_##field_name (IBusXKBConfigRegistry *xkb_config) \
|
|
+{ \
|
|
+ IBusXKBConfigRegistryPrivate *priv; \
|
|
+ \
|
|
+ g_return_val_if_fail (xkb_config != NULL, NULL); \
|
|
+ priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config); \
|
|
+ return priv->field_name; \
|
|
+}
|
|
+
|
|
+TABLE_FUNC (layout_list)
|
|
+TABLE_FUNC (layout_lang)
|
|
+TABLE_FUNC (layout_desc)
|
|
+TABLE_FUNC (variant_desc)
|
|
+
|
|
+#undef TABLE_FUNC
|
|
+
|
|
+IBusComponent *
|
|
+ibus_xkb_component_new (void)
|
|
+{
|
|
+ IBusComponent *component;
|
|
+
|
|
+ component = ibus_component_new ("org.freedesktop.IBus.XKB",
|
|
+ "XKB Component",
|
|
+ VERSION,
|
|
+ "LGPL2.1",
|
|
+ "Takao Fujiwara <takao.fujiwara1@gmail.com>",
|
|
+ "http://code.google.com/p/ibus/",
|
|
+ LIBEXECDIR "/ibus-engine-xkb --ibus",
|
|
+ GETTEXT_PACKAGE);
|
|
+
|
|
+ return component;
|
|
+}
|
|
+
|
|
+IBusEngineDesc *
|
|
+ibus_xkb_engine_desc_new (const gchar *lang,
|
|
+ const gchar *layout,
|
|
+ const gchar *layout_desc,
|
|
+ const gchar *variant,
|
|
+ const gchar *variant_desc)
|
|
+{
|
|
+ IBusEngineDesc *engine;
|
|
+ gchar *name = NULL;
|
|
+ gchar *longname = NULL;
|
|
+ gchar *desc = NULL;
|
|
+ gchar *engine_layout = NULL;
|
|
+
|
|
+ g_return_val_if_fail (lang != NULL && layout != NULL, NULL);
|
|
+
|
|
+ if (layout_desc && variant_desc) {
|
|
+ longname = g_strdup_printf ("%s - %s", layout_desc, variant_desc);
|
|
+ } else if (layout && variant) {
|
|
+ longname = g_strdup_printf ("%s - %s", layout, variant);
|
|
+ } else if (layout_desc) {
|
|
+ longname = g_strdup (layout_desc);
|
|
+ } else {
|
|
+ longname = g_strdup (layout);
|
|
+ }
|
|
+ if (variant) {
|
|
+ name = g_strdup_printf ("xkb:layout:%s:%s", layout, variant);
|
|
+ desc = g_strdup_printf ("XKB %s(%s) keyboard layout", layout, variant);
|
|
+ engine_layout = g_strdup_printf ("%s(%s)", layout, variant);
|
|
+ } else {
|
|
+ name = g_strdup_printf ("xkb:layout:%s", layout);
|
|
+ desc = g_strdup_printf ("XKB %s keyboard layout", layout);
|
|
+ engine_layout = g_strdup (layout);
|
|
+ }
|
|
+
|
|
+ engine = ibus_engine_desc_new (name,
|
|
+ longname,
|
|
+ desc,
|
|
+ lang,
|
|
+ "LGPL2.1",
|
|
+ "Takao Fujiwara <takao.fujiwara1@gmail.com>",
|
|
+ "ibus-engine",
|
|
+ engine_layout);
|
|
+
|
|
+ g_free (name);
|
|
+ g_free (longname);
|
|
+ g_free (desc);
|
|
+ g_free (engine_layout);
|
|
+
|
|
+ return engine;
|
|
+}
|
|
+
|
|
+IBusXKBLayoutConfig *
|
|
+ibus_xkb_layout_config_new (const gchar *system_config_file)
|
|
+{
|
|
+ IBusXKBLayoutConfig *xkb_layout_config;
|
|
+
|
|
+ xkb_layout_config = IBUS_XKB_LAYOUT_CONFIG (g_object_new (IBUS_TYPE_XKB_LAYOUT_CONFIG,
|
|
+ "system_config_file",
|
|
+ system_config_file,
|
|
+ NULL));
|
|
+ return xkb_layout_config;
|
|
+}
|
|
+
|
|
+const GList *
|
|
+ibus_xkb_layout_config_get_preload_layouts (IBusXKBLayoutConfig *xkb_layout_config)
|
|
+{
|
|
+ IBusXKBLayoutConfigPrivate *priv;
|
|
+
|
|
+ g_return_val_if_fail (xkb_layout_config != NULL, NULL);
|
|
+ priv = IBUS_XKB_LAYOUT_CONFIG_GET_PRIVATE (xkb_layout_config);
|
|
+ return (const GList *) priv->preload_layouts;
|
|
+}
|
|
diff --git a/xkb/xkbxml.h b/xkb/xkbxml.h
|
|
new file mode 100644
|
|
index 0000000..f4858fa
|
|
--- /dev/null
|
|
+++ b/xkb/xkbxml.h
|
|
@@ -0,0 +1,189 @@
|
|
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
|
|
+/* vim:set et sts=4: */
|
|
+/* bus - The Input Bus
|
|
+ * Copyright (C) 2010 Takao Fujiwara <takao.fujiwara1@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Peng Huang <shawn.p.huang@gmail.com>
|
|
+ * Copyright (C) 2008-2010 Red Hat, Inc.
|
|
+ *
|
|
+ * This library is free software; you can redistribute it and/or
|
|
+ * modify it under the terms of the GNU Lesser General Public
|
|
+ * License as published by the Free Software Foundation; either
|
|
+ * version 2 of the License, or (at your option) any later version.
|
|
+ *
|
|
+ * This library is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ * Lesser General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU Lesser General Public
|
|
+ * License along with this library; if not, write to the
|
|
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
+ * Boston, MA 02111-1307, USA.
|
|
+ */
|
|
+#ifndef __IBUS_XKB_H_
|
|
+#define __IBUS_XKB_H_
|
|
+
|
|
+#include "ibus.h"
|
|
+
|
|
+/*
|
|
+ * Type macros.
|
|
+ */
|
|
+/* define IBusXKBConfigRegistry macros */
|
|
+#define IBUS_TYPE_XKB_CONFIG_REGISTRY \
|
|
+ (ibus_xkb_config_registry_get_type ())
|
|
+#define IBUS_XKB_CONFIG_REGISTRY(obj) \
|
|
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistry))
|
|
+#define IBUS_XKB_CONFIG_REGISTRY_CLASS(klass) \
|
|
+ (G_TYPE_CHECK_CLASS_CAST ((klass), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryClass))
|
|
+#define IBUS_IS_XKB_CONFIG_REGISTRY(obj) \
|
|
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY))
|
|
+#define IBUS_IS_XKB_CONFIG_REGISTRY_CLASS(klass) \
|
|
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_XKB_CONFIG_REGISTRY))
|
|
+#define IBUS_XKB_CONFIG_REGISTRY_GET_CLASS(obj) \
|
|
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryClass))
|
|
+
|
|
+/* 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.3.2
|
|
|