1
From bce8b85886075fbdbf28bd5795be8bd41f3a984e Mon Sep 17 00:00:00 2001
2
From: fujiwarat <takao.fujiwara1@gmail.com>
3
Date: Thu, 13 Mar 2014 15:49:11 +0900
4
Subject: [PATCH] Add libgnomekbd and load preload engines.
7
bindings/vala/Gkbd-3.0.metadata | 1 +
8
bindings/vala/Makefile.am | 19 +-
9
bindings/vala/Xkl-1.0.metadata | 3 +
10
bindings/vala/gkbd.deps | 3 +
11
bus/ibusimpl.c | 12 +-
12
configure.ac | 40 ++++
13
data/ibus.schemas.in | 59 +++++
18
src/ibusxkbxml.c | 466 ++++++++++++++++++++++++++++++++++++++++
19
src/ibusxkbxml.h | 187 ++++++++++++++++
20
ui/gtk3/Makefile.am | 36 ++++
21
ui/gtk3/gkbdlayout.vala.false | 63 ++++++
22
ui/gtk3/gkbdlayout.vala.true | 108 ++++++++++
23
ui/gtk3/panel.vala | 230 +++++++++++++++++++-
24
ui/gtk3/xkblayout.vala | 429 ++++++++++++++++++++++++++++++++++++
25
18 files changed, 1668 insertions(+), 5 deletions(-)
26
create mode 100644 bindings/vala/Gkbd-3.0.metadata
27
create mode 100644 bindings/vala/Xkl-1.0.metadata
28
create mode 100644 bindings/vala/gkbd.deps
29
create mode 100644 src/ibusxkbxml.c
30
create mode 100644 src/ibusxkbxml.h
31
create mode 100644 ui/gtk3/gkbdlayout.vala.false
32
create mode 100644 ui/gtk3/gkbdlayout.vala.true
33
create mode 100644 ui/gtk3/xkblayout.vala
35
diff --git a/bindings/vala/Gkbd-3.0.metadata b/bindings/vala/Gkbd-3.0.metadata
37
index 0000000..661e6fd
39
+++ b/bindings/vala/Gkbd-3.0.metadata
41
+Configuration cheader_filename="libgnomekbd/gkbd-configuration.h"
42
diff --git a/bindings/vala/Makefile.am b/bindings/vala/Makefile.am
43
index 29cc1eb..1d28501 100644
44
--- a/bindings/vala/Makefile.am
45
+++ b/bindings/vala/Makefile.am
46
@@ -28,8 +28,6 @@ vapi_deps = \
47
$(top_builddir)/src/IBus-1.0.gir \
50
-ibus-1.0.vapi: $(vapi_deps)
52
VAPIGEN_VAPIS = ibus-1.0.vapi
54
ibus_1_0_vapi_DEPS = gio-2.0
55
@@ -39,19 +37,34 @@ ibus_1_0_vapi_FILES = \
56
$(srcdir)/IBus-1.0-custom.vala \
59
+if ENABLE_LIBGNOMEKBD
60
+ibus-1.0.vapi: $(vapi_deps) gkbd.vapi
62
+VAPIGEN_VAPIS += gkbd.vapi
64
+gkbd_vapi_DEPS = gtk+-3.0 glib-2.0 gmodule-2.0
65
+gkbd_vapi_METADATADIRS = $(srcdir)
66
+gkbd_vapi_FILES = /usr/share/gir-1.0/Gkbd-3.0.gir
68
+ibus-1.0.vapi: $(vapi_deps)
71
vapidir = $(datadir)/vala/vapi
72
-vapi_DATA = $(VAPIGEN_VAPIS) $(VAPIGEN_VAPIS:.vapi=.deps)
73
+vapi_DATA = ibus-1.0.vapi ibus-1.0.deps
75
MAINTAINERCLEANFILES = $(VAPIGEN_VAPIS)
82
IBus-1.0-custom.vala \
90
-include $(top_srcdir)/git.mk
91
diff --git a/bindings/vala/Xkl-1.0.metadata b/bindings/vala/Xkl-1.0.metadata
93
index 0000000..4961d0c
95
+++ b/bindings/vala/Xkl-1.0.metadata
97
+Xkl cheader_filename="libxklavier/xklavier.h"
99
+ .filter_events.evt ref type="X.Event"
100
diff --git a/bindings/vala/gkbd.deps b/bindings/vala/gkbd.deps
102
index 0000000..172632c
104
+++ b/bindings/vala/gkbd.deps
109
diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c
110
index eec6da3..f84c034 100644
113
@@ -1135,7 +1135,17 @@ _ibus_get_engines_by_names (BusIBusImpl *ibus,
114
g_variant_builder_init (&builder, G_VARIANT_TYPE ("av"));
115
while (names[i] != NULL) {
116
IBusEngineDesc *desc = (IBusEngineDesc *) g_hash_table_lookup (
117
- ibus->engine_table, names[i++]);
118
+ ibus->engine_table, names[i]);
120
+ /* preload engines return user XKB so if the engine does not
121
+ * exist in simple.xml, fall back to 'us' layout. */
122
+ if (desc == NULL && g_str_has_prefix (names[i], "xkb:")) {
123
+ desc = (IBusEngineDesc *) g_hash_table_lookup (
124
+ ibus->engine_table, "xkb:us::eng");
131
g_variant_builder_add (
132
diff --git a/configure.ac b/configure.ac
133
index 9a502ec..3ec629d 100644
136
@@ -261,6 +261,45 @@ else
137
enable_wayland="no (disabled, use --enable-wayland to enable)"
140
+# Option for XKB command.
141
+PKG_CHECK_MODULES(XKB,
143
+ [XKB_LIBS="-lxkbfile"]
146
+# --enable-libgnomekbd option.
147
+AC_ARG_ENABLE(libgnomekbd,
148
+ AS_HELP_STRING([--enable-libgnomekbd],
149
+ [Use libgnomekbd to handle the keymaps]),
150
+ [enable_libgnomekbd=$enableval],
151
+ [enable_libgnomekbd=no]
153
+AM_CONDITIONAL([ENABLE_LIBGNOMEKBD], [test x"$enable_libgnomekbd" = x"yes"])
154
+if test x"$enable_libgnomekbd" = x"yes"; then
155
+ # check for libgnomekbd
156
+ PKG_CHECK_MODULES(LIBGNOMEKBDUI, [
159
+ PKG_CHECK_MODULES(ATK, [
162
+ HAVE_IBUS_GKBD=true
164
+ enable_libgnomekbd="no (disabled, use --enable-libgnomekbd to enable)"
165
+ HAVE_IBUS_GKBD=false
167
+AC_SUBST(HAVE_IBUS_GKBD)
169
+# Define XKB rules file
170
+AC_ARG_WITH(xkb-rules-xml,
171
+ AS_HELP_STRING([--with-xkb-rules-xml[=$DIR/evdev.xml]],
172
+ [Set evdev.xml file path (default: /usr/share/X11/xkb/rules/evdev.xml)]),
173
+ XKB_RULES_XML_FILE=$with_xkb_rules_xml,
174
+ XKB_RULES_XML_FILE="/usr/share/X11/xkb/rules/evdev.xml"
176
+AC_DEFINE_UNQUOTED(XKB_RULES_XML_FILE, "$XKB_RULES_XML_FILE",
177
+ [Define file path of evdev.xml])
179
# GObject introspection
180
GOBJECT_INTROSPECTION_CHECK([0.6.8])
182
@@ -640,6 +679,7 @@ Build options:
183
Panel icon "$IBUS_ICON_KEYBOARD"
184
Enable surrounding-text $enable_surrounding_text
185
Enable libnotify $enable_libnotify
186
+ Build libgnomebkd $enable_libgnomekbd
187
Run test cases $enable_tests
190
diff --git a/data/ibus.schemas.in b/data/ibus.schemas.in
191
index 2f76ce3..caec315 100644
192
--- a/data/ibus.schemas.in
193
+++ b/data/ibus.schemas.in
198
+ <key>/schemas/desktop/ibus/general/use_xmodmap</key>
199
+ <applyto>/desktop/ibus/general/use_xmodmap</applyto>
200
+ <owner>ibus</owner>
202
+ <default>true</default>
204
+ <short>Use xmodmap</short>
205
+ <long>Run xmodmap if .xmodmap/.Xmodmap exists.</long>
209
+ <key>/schemas/desktop/ibus/general/xkb_latin_layouts</key>
210
+ <applyto>/desktop/ibus/general/xkb_latin_layouts</applyto>
211
+ <owner>ibus</owner>
213
+ <list_type>string</list_type>
214
+ <default>[ara,bg,cz,dev,gr,gur,in,jp(kana),mal,mkd,ru,ua]</default>
216
+ <short>Latin layout which have no ASCII</short>
217
+ <long>us layout is appended to the latin layouts. variant is not needed.</long>
221
+ <key>/schemas/desktop/ibus/general/load_xkb_layouts</key>
222
+ <applyto>/desktop/ibus/general/load_xkb_layouts</applyto>
223
+ <owner>ibus</owner>
225
+ <list_type>string</list_type>
226
+ <default>[us,us(chr),us(dvorak),ad,al,am,ara,az,ba,bd,be,bg,br,bt,by,
227
+de,dk,ca,ch,cn(tib),cz,ee,epo,es,et,fi,fo,fr,
228
+gb,ge,ge(dsb),ge(ru),ge(os),gh,gh(akan),gh(ewe),gh(fula),gh(ga),gh(hausa),
229
+gn,gr,hu,hr,ie,ie(CloGaelach),il,
231
+in(tel),in(bolnagri),iq,iq(ku),ir,ir(ku),is,it,jp,
232
+kg,kh,kz,la,latam,lk,lk(tam_unicode),lt,lv,ma,ma(tifinagh),mal,mao,
233
+me,mk,mm,mt,mv,ng,ng(hausa),ng,ng(igbo),ng(yoruba),nl,no,no(smi),np,
234
+pk,pl,pl(csb),pt,ro,rs,ru,ru(cv),ru(kom),ru(sah),ru(tt),ru(xal),
235
+se,si,sk,sy,sy(ku),th,tj,tr,ua,uz,vn
238
+ <short>XKB layout list which is shown on ibus-setup</short>
239
+ <long>XKB layout list which is shown on ibus-setup.
240
+ The format is "layout" or "layout(variant)".</long>
244
<key>/schemas/desktop/ibus/general/hotkey/trigger</key>
245
<applyto>/desktop/ibus/general/hotkey/trigger</applyto>
251
+ <key>/schemas/desktop/ibus/general/hotkey/triggers-no-modifiers</key>
252
+ <applyto>/desktop/ibus/general/hotkey/triggers-no-modifiers</applyto>
253
+ <owner>ibus</owner>
255
+ <list_type>string</list_type>
256
+ <default>[]</default>
258
+ <short>Trigger shortcut keys without modifier keys</short>
259
+ <long>Trigger shortcut keys without modifier keys.
260
+ The list is used by ibus-gjs.</long>
264
<key>/schemas/desktop/ibus/general/hotkey/enable_unconditional</key>
265
<applyto>/desktop/ibus/general/hotkey/enable_unconditional</applyto>
267
diff --git a/ibus-1.0.pc.in b/ibus-1.0.pc.in
268
index 9f593ab..c93a0ed 100644
271
@@ -4,6 +4,7 @@ libdir=@libdir@
272
includedir=@includedir@
274
pkgdatadir=@datadir@/ibus
275
+have_ibus_gkbd=@HAVE_IBUS_GKBD@
278
Description: IBus Library
279
diff --git a/ibus.spec.in b/ibus.spec.in
280
index 334f37e..2017af9 100644
286
%define build_python_library 0
287
+%define build_libgnomekbd 0
289
%define glib_ver %([ -a %{_libdir}/pkgconfig/glib-2.0.pc ] && pkg-config --modversion glib-2.0 | cut -d. -f 1,2 || echo -n "999")
290
%define gconf2_version 2.12.0
291
@@ -40,6 +41,10 @@ BuildRequires: dconf-devel
292
BuildRequires: pygobject2-devel
293
BuildRequires: intltool
294
BuildRequires: iso-codes-devel
295
+%if %{build_libgnomekbd}
296
+BuildRequires: libxkbfile-devel
297
+BuildRequires: libgnomekbd-devel
300
Requires: %{name}-libs = %{version}-%{release}
301
Requires: %{name}-gtk2 = %{version}-%{release}
302
@@ -52,6 +57,9 @@ Requires: dbus-python >= %{dbus_python_version}
303
Requires: im-chooser >= %{im_chooser_version}
304
Requires: notify-python
306
+%if %{build_libgnomekbd}
307
+Requires: libgnomekbd
310
Requires(post): desktop-file-utils
311
Requires(postun): desktop-file-utils
312
@@ -152,6 +160,10 @@ OPTIONS="$OPTIONS --enable-python-library"
313
OPTIONS="$OPTIONS --disable-python-library"
316
+%if %{build_libgnomekbd}
317
+OPTIONS="$OPTIONS --enable-libgnomekbd"
322
# make -C po update-gmo
323
diff --git a/src/Makefile.am b/src/Makefile.am
324
index 404e1d2..f00fab7 100644
325
--- a/src/Makefile.am
326
+++ b/src/Makefile.am
327
@@ -202,6 +202,9 @@ typelibs_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
328
CLEANFILES += $(dist_gir_DATA) $(typelibs_DATA)
331
+ibus_sources += ibusxkbxml.c
332
+ibus_headers += ibusxkbxml.h
335
ibusenumtypes.h: $(ibus_headers) ibusenumtypes.h.template
336
$(AM_V_GEN) ( top_builddir=`cd $(top_builddir) && pwd`; \
337
diff --git a/src/ibus.h b/src/ibus.h
338
index d8e226e..f0a9456 100644
342
#include <ibuskeys.h>
343
#include <ibusenumtypes.h>
344
#include <ibushotkey.h>
345
+#include <ibusxkbxml.h>
347
#include <ibusenginedesc.h>
348
#include <ibusobservedpath.h>
349
diff --git a/src/ibusxkbxml.c b/src/ibusxkbxml.c
351
index 0000000..f815e5d
353
+++ b/src/ibusxkbxml.c
355
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
356
+/* vim:set et sts=4: */
357
+/* bus - The Input Bus
358
+ * Copyright (C) 2013 Takao Fujiwara <takao.fujiwara1@gmail.com>
359
+ * Copyright (C) 2013 Peng Huang <shawn.p.huang@gmail.com>
360
+ * Copyright (C) 2013 Red Hat, Inc.
362
+ * This library is free software; you can redistribute it and/or
363
+ * modify it under the terms of the GNU Lesser General Public
364
+ * License as published by the Free Software Foundation; either
365
+ * version 2 of the License, or (at your option) any later version.
367
+ * This library is distributed in the hope that it will be useful,
368
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
369
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
370
+ * Lesser General Public License for more details.
372
+ * You should have received a copy of the GNU Lesser General Public
373
+ * License along with this library; if not, write to the
374
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
375
+ * Boston, MA 02111-1307, USA.
377
+#ifdef HAVE_CONFIG_H
384
+#include "ibusxkbxml.h"
386
+#ifndef XKB_RULES_XML_FILE
387
+#define XKB_RULES_XML_FILE "/usr/share/X11/xkb/rules/evdev.xml"
390
+#define IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE(o) \
391
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryPrivate))
393
+typedef struct _IBusXKBConfigRegistryPrivate IBusXKBConfigRegistryPrivate;
395
+struct _IBusXKBConfigRegistryPrivate {
396
+ GHashTable *layout_list;
397
+ GHashTable *layout_lang;
398
+ GHashTable *layout_desc;
399
+ GHashTable *variant_desc;
403
+/* functions prototype */
404
+static void ibus_xkb_config_registry_destroy
405
+ (IBusXKBConfigRegistry *xkb_config);
407
+G_DEFINE_TYPE (IBusXKBConfigRegistry, ibus_xkb_config_registry, IBUS_TYPE_OBJECT)
410
+parse_xkb_xml_languagelist_node (IBusXKBConfigRegistryPrivate *priv,
411
+ XMLNode *parent_node,
412
+ const gchar *layout_name)
414
+ XMLNode *node = parent_node;
417
+ GList *lang_list = NULL;
419
+ g_assert (node != NULL);
420
+ g_assert (layout_name != NULL);
421
+ for (p = node->sub_nodes; p; p = p->next) {
422
+ sub_node = (XMLNode *) p->data;
423
+ if (g_strcmp0 (sub_node->name, "iso639Id") == 0) {
424
+ lang_list = g_list_append (lang_list,
425
+ (gpointer) g_strdup (sub_node->text));
429
+ if (lang_list == NULL) {
430
+ /* some nodes have no lang */
433
+ if (g_hash_table_lookup (priv->layout_lang, layout_name) != NULL) {
434
+ g_warning ("duplicated name %s exists", layout_name);
437
+ g_hash_table_insert (priv->layout_lang,
438
+ (gpointer) g_strdup (layout_name),
439
+ (gpointer) lang_list);
442
+static const gchar *
443
+parse_xkb_xml_configitem_node (IBusXKBConfigRegistryPrivate *priv,
444
+ XMLNode *parent_node)
446
+ XMLNode *node = parent_node;
449
+ gchar *name = NULL;
450
+ gchar *description = NULL;
452
+ g_assert (node != NULL);
453
+ for (p = node->sub_nodes; p; p = p->next) {
454
+ sub_node = (XMLNode *) p->data;
455
+ if (g_strcmp0 (sub_node->name, "name") == 0) {
456
+ name = sub_node->text;
459
+ if (g_strcmp0 (sub_node->name, "description") == 0) {
460
+ description = sub_node->text;
463
+ if (g_strcmp0 (sub_node->name, "languageList") == 0) {
464
+ if (name == NULL) {
465
+ g_warning ("layout name is NULL in node %s", node->name);
468
+ parse_xkb_xml_languagelist_node (priv, sub_node, name);
472
+ if (name == NULL) {
473
+ g_warning ("No name in layout node");
476
+ if (g_hash_table_lookup (priv->layout_desc, name) != NULL) {
477
+ g_warning ("duplicated name %s exists", name);
480
+ g_hash_table_insert (priv->layout_desc,
481
+ (gpointer) g_strdup (name),
482
+ (gpointer) g_strdup (description));
487
+static const gchar *
488
+parse_xkb_xml_variant_configitem_node (IBusXKBConfigRegistryPrivate *priv,
489
+ XMLNode *parent_node,
490
+ const gchar *layout_name)
492
+ XMLNode *node = parent_node;
495
+ gchar *name = NULL;
496
+ gchar *description = NULL;
497
+ gchar *variant_lang_name = NULL;
499
+ g_assert (node != NULL);
500
+ g_assert (layout_name != NULL);
501
+ for (p = node->sub_nodes; p; p = p->next) {
502
+ sub_node = (XMLNode *) p->data;
503
+ if (g_strcmp0 (sub_node->name, "name") == 0) {
504
+ name = sub_node->text;
507
+ if (g_strcmp0 (sub_node->name, "description") == 0) {
508
+ description = sub_node->text;
511
+ if (g_strcmp0 (sub_node->name, "languageList") == 0) {
512
+ if (name == NULL) {
513
+ g_warning ("layout name is NULL in node %s", node->name);
516
+ variant_lang_name = g_strdup_printf ("%s(%s)", layout_name, name);
517
+ parse_xkb_xml_languagelist_node (priv, sub_node, variant_lang_name);
518
+ g_free (variant_lang_name);
522
+ if (name == NULL) {
523
+ g_warning ("No name in layout node");
526
+ if (g_hash_table_lookup (priv->variant_desc, name) != NULL) {
527
+ /* This is an expected case. */
530
+ variant_lang_name = g_strdup_printf ("%s(%s)", layout_name, name);
531
+ g_hash_table_insert (priv->variant_desc,
532
+ (gpointer) variant_lang_name,
533
+ (gpointer) g_strdup (description));
537
+static const gchar *
538
+parse_xkb_xml_variant_node (IBusXKBConfigRegistryPrivate *priv,
539
+ XMLNode *parent_node,
540
+ const gchar *layout_name)
542
+ XMLNode *node = parent_node;
545
+ const gchar *variant_name = NULL;
547
+ g_assert (node != NULL);
548
+ g_assert (layout_name != NULL);
549
+ for (p = node->sub_nodes; p; p = p->next) {
550
+ sub_node = (XMLNode *) p->data;
551
+ if (g_strcmp0 (sub_node->name, "configItem") == 0) {
552
+ variant_name = parse_xkb_xml_variant_configitem_node (priv, sub_node, layout_name);
556
+ return variant_name;
560
+parse_xkb_xml_variantlist_node (IBusXKBConfigRegistryPrivate *priv,
561
+ XMLNode *parent_node,
562
+ const gchar *layout_name,
563
+ GList *variant_list)
565
+ XMLNode *node = parent_node;
568
+ const gchar *variant_name = NULL;
570
+ g_assert (node != NULL);
571
+ g_assert (layout_name != NULL);
572
+ for (p = node->sub_nodes; p; p = p->next) {
573
+ sub_node = (XMLNode *) p->data;
574
+ if (g_strcmp0 (sub_node->name, "variant") == 0) {
575
+ variant_name = parse_xkb_xml_variant_node (priv, sub_node, layout_name);
576
+ if (variant_name != NULL) {
577
+ variant_list = g_list_append (variant_list,
578
+ (gpointer) g_strdup (variant_name));
583
+ return variant_list;
587
+parse_xkb_xml_layout_node (IBusXKBConfigRegistryPrivate *priv,
588
+ XMLNode *parent_node)
590
+ XMLNode *node = parent_node;
593
+ const gchar *name = NULL;
594
+ GList *variant_list = NULL;
596
+ g_assert (node != NULL);
597
+ for (p = node->sub_nodes; p; p = p->next) {
598
+ sub_node = (XMLNode *) p->data;
599
+ if (g_strcmp0 (sub_node->name, "configItem") == 0) {
600
+ name = parse_xkb_xml_configitem_node (priv, sub_node);
603
+ if (g_strcmp0 (sub_node->name, "variantList") == 0) {
604
+ if (name == NULL) {
605
+ g_warning ("layout name is NULL in node %s", node->name);
608
+ variant_list = parse_xkb_xml_variantlist_node (priv, sub_node,
614
+ if (g_hash_table_lookup (priv->layout_list, name) != NULL) {
615
+ g_warning ("duplicated name %s exists", name);
618
+ g_hash_table_insert (priv->layout_list,
619
+ (gpointer) g_strdup (name),
620
+ (gpointer) variant_list);
624
+parse_xkb_xml_top_node (IBusXKBConfigRegistryPrivate *priv,
625
+ XMLNode *parent_node)
627
+ XMLNode *node = parent_node;
631
+ g_assert (priv != NULL);
632
+ g_assert (node != NULL);
634
+ if (g_strcmp0 (node->name, "xkbConfigRegistry") != 0) {
635
+ g_warning ("node has no xkbConfigRegistry name");
638
+ for (p = node->sub_nodes; p; p = p->next) {
639
+ sub_node = (XMLNode *) p->data;
640
+ if (g_strcmp0 (sub_node->name, "layoutList") == 0) {
645
+ g_warning ("xkbConfigRegistry node has no layoutList node");
649
+ for (p = node->sub_nodes; p; p = p->next) {
650
+ sub_node = (XMLNode *) p->data;
651
+ if (g_strcmp0 (sub_node->name, "layout") == 0) {
652
+ parse_xkb_xml_layout_node (priv, sub_node);
659
+free_lang_list (GList *list)
667
+ g_list_free (list);
671
+parse_xkb_config_registry_file (IBusXKBConfigRegistryPrivate *priv,
676
+ g_assert (file != NULL);
678
+ priv->layout_list = g_hash_table_new_full (g_str_hash,
679
+ (GEqualFunc) g_str_equal,
680
+ (GDestroyNotify) g_free,
681
+ (GDestroyNotify) free_lang_list);
682
+ priv->layout_desc = g_hash_table_new_full (g_str_hash,
683
+ (GEqualFunc) g_str_equal,
684
+ (GDestroyNotify) g_free,
685
+ (GDestroyNotify) g_free);
686
+ priv->layout_lang = g_hash_table_new_full (g_str_hash,
687
+ (GEqualFunc) g_str_equal,
688
+ (GDestroyNotify) g_free,
689
+ (GDestroyNotify) free_lang_list);
690
+ priv->variant_desc = g_hash_table_new_full (g_str_hash,
691
+ (GEqualFunc) g_str_equal,
692
+ (GDestroyNotify) g_free,
693
+ (GDestroyNotify) g_free);
694
+ node = ibus_xml_parse_file (file);
695
+ parse_xkb_xml_top_node (priv, node);
696
+ ibus_xml_free (node);
700
+ibus_xkb_config_registry_init (IBusXKBConfigRegistry *xkb_config)
702
+ IBusXKBConfigRegistryPrivate *priv;
703
+ const gchar *file = XKB_RULES_XML_FILE;
705
+ priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config);
706
+ parse_xkb_config_registry_file (priv, file);
710
+ibus_xkb_config_registry_destroy (IBusXKBConfigRegistry *xkb_config)
712
+ IBusXKBConfigRegistryPrivate *priv;
714
+ g_return_if_fail (xkb_config != NULL);
716
+ priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config);
718
+ g_hash_table_destroy (priv->layout_list);
719
+ priv->layout_list = NULL;
720
+ g_hash_table_destroy (priv->layout_lang);
721
+ priv->layout_lang= NULL;
722
+ g_hash_table_destroy (priv->layout_desc);
723
+ priv->layout_desc= NULL;
724
+ g_hash_table_destroy (priv->variant_desc);
725
+ priv->variant_desc = NULL;
727
+ IBUS_OBJECT_CLASS(ibus_xkb_config_registry_parent_class)->destroy (IBUS_OBJECT (xkb_config));
731
+ibus_xkb_config_registry_class_init (IBusXKBConfigRegistryClass *klass)
733
+ IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (klass);
735
+ g_type_class_add_private (klass, sizeof (IBusXKBConfigRegistryPrivate));
737
+ ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_xkb_config_registry_destroy;
740
+IBusXKBConfigRegistry *
741
+ibus_xkb_config_registry_new (void)
743
+ IBusXKBConfigRegistry *xkb_config;
745
+ xkb_config = IBUS_XKB_CONFIG_REGISTRY (g_object_new (IBUS_TYPE_XKB_CONFIG_REGISTRY, NULL));
749
+#define TABLE_FUNC(field_name) const GHashTable * \
750
+ibus_xkb_config_registry_get_##field_name (IBusXKBConfigRegistry *xkb_config) \
752
+ IBusXKBConfigRegistryPrivate *priv; \
754
+ g_return_val_if_fail (xkb_config != NULL, NULL); \
755
+ priv = IBUS_XKB_CONFIG_REGISTRY_GET_PRIVATE (xkb_config); \
756
+ return priv->field_name; \
759
+TABLE_FUNC (layout_list)
760
+TABLE_FUNC (layout_lang)
761
+TABLE_FUNC (layout_desc)
762
+TABLE_FUNC (variant_desc)
767
+ibus_xkb_config_registry_layout_list_get_layouts (IBusXKBConfigRegistry *xkb_config)
770
+ GList *list = NULL;
772
+ table = (GHashTable *)
773
+ ibus_xkb_config_registry_get_layout_list (xkb_config);
774
+ list = (GList *) g_hash_table_get_keys (table);
778
+/* vala could use GLib.List<string> for the returned pointer and
779
+ * the declaration calls g_list_foreach (retval, g_free, NULL).
780
+ * When I think about GLib.List<string> v.s. GLib.List, probably
781
+ * I think GLib.List<string> is better for the function and set
782
+ * g_strdup() here. I do not know about GJS implementation.
784
+#define TABLE_LOOKUP_LIST_FUNC(field_name, value) GList * \
785
+ibus_xkb_config_registry_##field_name##_get_##value (IBusXKBConfigRegistry *xkb_config, const gchar *key) \
787
+ GHashTable *table; \
788
+ GList *list = NULL; \
789
+ GList *retval= NULL; \
792
+ table = (GHashTable *) \
793
+ ibus_xkb_config_registry_get_##field_name (xkb_config); \
794
+ list = (GList *) g_hash_table_lookup (table, key); \
795
+ retval = g_list_copy (list); \
796
+ for (p = retval; p; p = p->next) { \
797
+ p->data = g_strdup (p->data); \
802
+#define TABLE_LOOKUP_STRING_FUNC(field_name, value) gchar * \
803
+ibus_xkb_config_registry_##field_name##_get_##value (IBusXKBConfigRegistry *xkb_config, const gchar *key) \
805
+ GHashTable *table; \
806
+ const gchar *desc = NULL; \
808
+ table = (GHashTable *) \
809
+ ibus_xkb_config_registry_get_##field_name (xkb_config); \
810
+ desc = (const gchar *) g_hash_table_lookup (table, key); \
811
+ return g_strdup (desc); \
814
+TABLE_LOOKUP_LIST_FUNC (layout_list, variants)
815
+TABLE_LOOKUP_LIST_FUNC (layout_lang, langs)
816
+TABLE_LOOKUP_STRING_FUNC (layout_desc, desc)
817
+TABLE_LOOKUP_STRING_FUNC (variant_desc, desc)
819
+#undef TABLE_LOOKUP_LIST_FUNC
820
+#undef TABLE_LOOKUP_STRING_FUNC
821
diff --git a/src/ibusxkbxml.h b/src/ibusxkbxml.h
823
index 0000000..5aa486d
825
+++ b/src/ibusxkbxml.h
827
+/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
828
+/* vim:set et sts=4: */
829
+/* bus - The Input Bus
830
+ * Copyright (C) 2013 Takao Fujiwara <takao.fujiwara1@gmail.com>
831
+ * Copyright (C) 2013 Peng Huang <shawn.p.huang@gmail.com>
832
+ * Copyright (C) 2013 Red Hat, Inc.
834
+ * This library is free software; you can redistribute it and/or
835
+ * modify it under the terms of the GNU Lesser General Public
836
+ * License as published by the Free Software Foundation; either
837
+ * version 2 of the License, or (at your option) any later version.
839
+ * This library is distributed in the hope that it will be useful,
840
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
841
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
842
+ * Lesser General Public License for more details.
844
+ * You should have received a copy of the GNU Lesser General Public
845
+ * License along with this library; if not, write to the
846
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
847
+ * Boston, MA 02111-1307, USA.
849
+#ifndef __IBUS_XKBXML_H_
850
+#define __IBUS_XKBXML_H_
852
+#if !defined (__IBUS_H_INSIDE__) && !defined (IBUS_COMPILATION)
853
+#error "Only <ibus.h> can be included directly"
861
+/* define IBusXKBConfigRegistry macros */
862
+#define IBUS_TYPE_XKB_CONFIG_REGISTRY \
863
+ (ibus_xkb_config_registry_get_type ())
864
+#define IBUS_XKB_CONFIG_REGISTRY(obj) \
865
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistry))
866
+#define IBUS_XKB_CONFIG_REGISTRY_CLASS(klass) \
867
+ (G_TYPE_CHECK_CLASS_CAST ((klass), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryClass))
868
+#define IBUS_IS_XKB_CONFIG_REGISTRY(obj) \
869
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY))
870
+#define IBUS_IS_XKB_CONFIG_REGISTRY_CLASS(klass) \
871
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), IBUS_TYPE_XKB_CONFIG_REGISTRY))
872
+#define IBUS_XKB_CONFIG_REGISTRY_GET_CLASS(obj) \
873
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), IBUS_TYPE_XKB_CONFIG_REGISTRY, IBusXKBConfigRegistryClass))
877
+typedef struct _IBusXKBConfigRegistry IBusXKBConfigRegistry;
878
+typedef struct _IBusXKBConfigRegistryClass IBusXKBConfigRegistryClass;
880
+struct _IBusXKBConfigRegistry {
884
+struct _IBusXKBConfigRegistryClass {
885
+ IBusObjectClass parent;
889
+ gpointer pdummy[8];
893
+GType ibus_xkb_config_registry_get_type
897
+ * ibus_xkb_config_registry_new:
898
+ * @returns: A newly allocated IBusXKBConfigRegistry
900
+ * New an IBusXKBConfigRegistry.
902
+IBusXKBConfigRegistry *
903
+ ibus_xkb_config_registry_new
907
+ * ibus_xkb_config_registry_get_layout_list: (skip)
908
+ * @xkb_config: An IBusXKBConfigRegistry.
909
+ * @returns: A const GHashTable
911
+ * a const GHashTable
914
+ ibus_xkb_config_registry_get_layout_list
915
+ (IBusXKBConfigRegistry *xkb_config);
918
+ * ibus_xkb_config_registry_get_layout_lang: (skip)
919
+ * @xkb_config: An IBusXKBConfigRegistry.
920
+ * @returns: A const GHashTable
922
+ * a const GHashTable
925
+ ibus_xkb_config_registry_get_layout_lang
926
+ (IBusXKBConfigRegistry *xkb_config);
929
+ * ibus_xkb_config_registry_get_layout_desc: (skip)
930
+ * @xkb_config: An IBusXKBConfigRegistry.
931
+ * @returns: A const GHashTable
933
+ * a const GHashTable
936
+ ibus_xkb_config_registry_get_layout_desc
937
+ (IBusXKBConfigRegistry *xkb_config);
940
+ * ibus_xkb_config_registry_get_variant_desc: (skip)
941
+ * @xkb_config: An IBusXKBConfigRegistry.
942
+ * @returns: A const GHashTable
944
+ * a const GHashTable
947
+ ibus_xkb_config_registry_get_variant_desc
948
+ (IBusXKBConfigRegistry *xkb_config);
951
+ * ibus_xkb_config_registry_layout_list_get_layouts:
952
+ * @xkb_config: An IBusXKBConfigRegistry.
953
+ * @returns: (transfer container) (element-type utf8): A GList of layouts
955
+ * a GList of layouts
958
+ ibus_xkb_config_registry_layout_list_get_layouts
959
+ (IBusXKBConfigRegistry *xkb_config);
962
+ * ibus_xkb_config_registry_layout_list_get_variants:
963
+ * @xkb_config: An IBusXKBConfigRegistry.
964
+ * @layout: A layout.
965
+ * @returns: (transfer container) (element-type utf8): A GList
970
+ ibus_xkb_config_registry_layout_list_get_variants
971
+ (IBusXKBConfigRegistry *xkb_config,
972
+ const gchar *layout);
975
+ * ibus_xkb_config_registry_layout_lang_get_langs:
976
+ * @xkb_config: An IBusXKBConfigRegistry.
977
+ * @layout: A layout.
978
+ * @returns: (transfer container) (element-type utf8): A GList
983
+ ibus_xkb_config_registry_layout_lang_get_langs
984
+ (IBusXKBConfigRegistry *xkb_config,
985
+ const gchar *layout);
988
+ * ibus_xkb_config_registry_layout_desc_get_desc:
989
+ * @xkb_config: An IBusXKBConfigRegistry.
990
+ * @layout: A layout.
991
+ * @returns: A layout description
993
+ * a layout description
996
+ ibus_xkb_config_registry_layout_desc_get_desc
997
+ (IBusXKBConfigRegistry *xkb_config,
998
+ const gchar *layout);
1001
+ * ibus_xkb_config_registry_variant_desc_get_desc:
1002
+ * @xkb_config: An IBusXKBConfigRegistry.
1003
+ * @variant: A variant.
1004
+ * @returns: A variant description
1006
+ * a variant description
1009
+ ibus_xkb_config_registry_variant_desc_get_desc
1010
+ (IBusXKBConfigRegistry *xkb_config,
1011
+ const gchar *variant);
1014
diff --git a/ui/gtk3/Makefile.am b/ui/gtk3/Makefile.am
1015
index b2fb800..f148202 100644
1016
--- a/ui/gtk3/Makefile.am
1017
+++ b/ui/gtk3/Makefile.am
1018
@@ -35,6 +35,8 @@ gtkpanel.xml: gtkpanel.xml.in
1019
-e 's|@libexecdir[@]|$(libexecdir)|g' $< > $@.tmp && \
1022
+HAVE_IBUS_GKBD_C = $(strip $(subst false, FALSE, $(subst true, TRUE, $(HAVE_IBUS_GKBD))))
1024
# force include config.h before gi18n.h.
1026
-I$(top_srcdir)/src \
1027
@@ -51,6 +53,8 @@ AM_CFLAGS = \
1028
-DG_LOG_DOMAIN=\"IBUS\" \
1029
-DBINDIR=\"$(bindir)\" \
1030
-DIBUS_DISABLE_DEPRECATED \
1031
+ -DHAVE_IBUS_GKBD=$(HAVE_IBUS_GKBD_C) \
1032
+ -DXKB_LAYOUTS_MAX_LENGTH=4 \
1033
-Wno-unused-variable \
1034
-Wno-unused-but-set-variable \
1035
-Wno-unused-function \
1036
@@ -94,12 +98,40 @@ AM_VALAFLAGS += \
1040
+if ENABLE_LIBGNOMEKBD
1042
+ @LIBGNOMEKBDUI_CFLAGS@ \
1047
+ @LIBGNOMEKBDUI_LIBS@ \
1053
+ --metadatadir=$(top_srcdir)/bindings/vala \
1055
+ --pkg=gmodule-2.0 \
1060
+$(srcdir)/gkbdlayout.vala: $(top_builddir)/bindings/vala/gkbd.vapi
1061
+ @cp $(srcdir)/gkbdlayout.vala.true $(srcdir)/gkbdlayout.vala
1063
+$(srcdir)/gkbdlayout.vala:
1064
+ @cp $(srcdir)/gkbdlayout.vala.false $(srcdir)/gkbdlayout.vala
1067
libexec_PROGRAMS = ibus-ui-gtk3
1069
ibus_ui_gtk3_SOURCES = \
1071
candidatearea.vala \
1072
candidatepanel.vala \
1076
keybindingmanager.vala \
1077
@@ -109,6 +141,7 @@ ibus_ui_gtk3_SOURCES = \
1078
propertypanel.vala \
1084
ibus_ui_gtk3_LDADD = \
1085
@@ -117,9 +150,12 @@ ibus_ui_gtk3_LDADD = \
1093
+ gkbdlayout.vala.false \
1094
+ gkbdlayout.vala.true \
1098
diff --git a/ui/gtk3/gkbdlayout.vala.false b/ui/gtk3/gkbdlayout.vala.false
1099
new file mode 100644
1100
index 0000000..506aff2
1102
+++ b/ui/gtk3/gkbdlayout.vala.false
1104
+/* vim:set et sts=4 sw=4:
1106
+ * ibus - The Input Bus
1108
+ * Copyright(c) 2013 Red Hat, Inc.
1109
+ * Copyright(c) 2013 Peng Huang <shawn.p.huang@gmail.com>
1110
+ * Copyright(c) 2013 Takao Fujiwara <tfujiwar@redhat.com>
1112
+ * This library is free software; you can redistribute it and/or
1113
+ * modify it under the terms of the GNU Lesser General Public
1114
+ * License as published by the Free Software Foundation; either
1115
+ * version 2 of the License, or(at your option) any later version.
1117
+ * This library is distributed in the hope that it will be useful,
1118
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1119
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1120
+ * GNU Lesser General Public License for more details.
1122
+ * You should have received a copy of the GNU Lesser General Public
1123
+ * License along with this program; if not, write to the
1124
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
1125
+ * Boston, MA 02111-1307 USA
1128
+public class GkbdLayout
1130
+ public signal void changed();
1131
+ public signal void group_changed (int object);
1133
+ public GkbdLayout() {
1136
+ public string[] get_layouts() {
1137
+ return new string[0];
1140
+ public string[] get_group_names() {
1141
+ return new string[0];
1144
+ public void lock_group(int id) {
1147
+ public void start_listen() {
1150
+ public void stop_listen() {
1154
+ public static int main(string[] args) {
1155
+ GkbdLayout ibus_layouts = new GkbdLayout();
1157
+ string[] layouts = ibus_layouts.get_layouts();
1158
+ string[] names = ibus_layouts.get_group_names();
1159
+ for (int i = 0; layouts != null && i < layouts.length; i++) {
1160
+ stdout.printf("%s %s\n", layouts[i], names[i]);
1167
diff --git a/ui/gtk3/gkbdlayout.vala.true b/ui/gtk3/gkbdlayout.vala.true
1168
new file mode 100644
1169
index 0000000..a6e0f8d
1171
+++ b/ui/gtk3/gkbdlayout.vala.true
1173
+/* vim:set et sts=4 sw=4:
1175
+ * ibus - The Input Bus
1177
+ * Copyright(c) 2013 Red Hat, Inc.
1178
+ * Copyright(c) 2013 Peng Huang <shawn.p.huang@gmail.com>
1179
+ * Copyright(c) 2013 Takao Fujiwara <tfujiwar@redhat.com>
1181
+ * This library is free software; you can redistribute it and/or
1182
+ * modify it under the terms of the GNU Lesser General Public
1183
+ * License as published by the Free Software Foundation; either
1184
+ * version 2 of the License, or(at your option) any later version.
1186
+ * This library is distributed in the hope that it will be useful,
1187
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1188
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1189
+ * GNU Lesser General Public License for more details.
1191
+ * You should have received a copy of the GNU Lesser General Public
1192
+ * License along with this program; if not, write to the
1193
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
1194
+ * Boston, MA 02111-1307 USA
1197
+public class GkbdLayout
1199
+ public signal void changed();
1200
+ public signal void group_changed (int object);
1202
+ private Gkbd.Configuration m_config = null;
1204
+ public GkbdLayout() {
1205
+ m_config = Gkbd.Configuration.get();
1206
+ if (m_config != null) {
1207
+ m_config.changed.connect(config_changed_cb);
1208
+ m_config.group_changed.connect(config_group_changed_cb);
1213
+ if (m_config != null) {
1214
+ m_config.changed.disconnect(config_changed_cb);
1215
+ m_config.group_changed.disconnect(config_group_changed_cb);
1216
+ /* gkbd_configuration_get reuses the object and do not
1217
+ * destroy m_config here. */
1223
+ private void config_changed_cb() {
1227
+ private void config_group_changed_cb(int object) {
1228
+ group_changed(object);
1231
+ public string[] get_layouts() {
1232
+ if (m_config == null) {
1233
+ return new string[0];
1235
+ return m_config.get_short_group_names();
1238
+ public string[] get_group_names() {
1239
+ if (m_config == null) {
1240
+ return new string[0];
1242
+ return m_config.get_group_names();
1245
+ public void lock_group(int id) {
1246
+ if (m_config == null) {
1249
+ m_config.lock_group(id);
1252
+ public void start_listen() {
1253
+ if (m_config == null) {
1256
+ m_config.start_listen();
1259
+ public void stop_listen() {
1260
+ if (m_config == null) {
1263
+ m_config.stop_listen();
1267
+ public static int main(string[] args) {
1268
+ Gtk.init(ref args);
1269
+ GkbdLayout ibus_layouts = new GkbdLayout();
1271
+ string[] layouts = ibus_layouts.get_layouts();
1272
+ string[] names = ibus_layouts.get_group_names();
1273
+ for (int i = 0; layouts != null && i < layouts.length; i++) {
1274
+ stdout.printf("%s %s\n", layouts[i], names[i]);
1281
diff --git a/ui/gtk3/panel.vala b/ui/gtk3/panel.vala
1282
index 748cb32..7a15049 100644
1283
--- a/ui/gtk3/panel.vala
1284
+++ b/ui/gtk3/panel.vala
1285
@@ -63,6 +63,13 @@ class Panel : IBus.PanelService {
1287
private Gdk.RGBA m_xkb_icon_rgba = Gdk.RGBA(){
1288
red = 0.0, green = 0.0, blue = 0.0, alpha = 1.0 };
1289
+ private GkbdLayout m_gkbdlayout = null;
1290
+ private XKBLayout m_xkblayout = null;
1291
+ private string[] m_layouts = {};
1292
+ private string[] m_variants = {};
1293
+ private int m_fallback_lock_id = -1;
1294
+ private bool m_changed_xkb_option = false;
1295
+ private GLib.Timer m_changed_layout_timer;
1297
private GLib.List<Keybinding> m_keybindings = new GLib.List<Keybinding>();
1299
@@ -113,6 +120,14 @@ class Panel : IBus.PanelService {
1302
unbind_switch_shortcut();
1304
+ if (HAVE_IBUS_GKBD && m_gkbdlayout != null) {
1305
+ m_gkbdlayout.changed.disconnect(gkbdlayout_changed_cb);
1306
+ m_gkbdlayout.stop_listen();
1307
+ m_gkbdlayout = null;
1310
+ m_xkblayout = null;
1313
private void init_settings() {
1314
@@ -487,6 +502,7 @@ class Panel : IBus.PanelService {
1317
public void load_settings() {
1318
+ init_engines_order();
1319
// Update m_use_system_keyboard_layout before update_engines()
1321
set_use_system_keyboard_layout();
1322
@@ -508,6 +524,184 @@ class Panel : IBus.PanelService {
1326
+ private void gkbdlayout_changed_cb() {
1327
+ /* The callback is called four times after set_layout is called
1328
+ * so check the elapsed and take the first signal only. */
1329
+ double elapsed = m_changed_layout_timer.elapsed();
1330
+ if (elapsed < 1.0 && elapsed > 0.0) {
1334
+ if (m_fallback_lock_id != -1) {
1335
+ /* Call lock_group only when set_layout is called. */
1336
+ m_gkbdlayout.lock_group(m_fallback_lock_id);
1337
+ m_fallback_lock_id = -1;
1339
+ /* Reset default layout when gnome-control-center is called. */
1340
+ m_xkblayout.reset_layout();
1343
+ update_xkb_engines();
1344
+ m_changed_layout_timer.reset();
1347
+ private void init_gkbd() {
1348
+ m_gkbdlayout = new GkbdLayout();
1349
+ m_gkbdlayout.changed.connect(gkbdlayout_changed_cb);
1351
+ /* Probably we cannot support both keyboard and ibus indicators
1352
+ * How can I get the engine from keymap of group_id?
1353
+ * e.g. 'en' could be owned by xkb:en and pinyin engines. */
1354
+ //m_gkbdlayout.group_changed.connect((object) => {});
1356
+ m_changed_layout_timer = new GLib.Timer();
1357
+ m_changed_layout_timer.start();
1358
+ m_gkbdlayout.start_listen();
1361
+ private void init_engines_order() {
1362
+ m_xkblayout = new XKBLayout();
1363
+ string session = Environment.get_variable("DESKTOP_SESSION");
1365
+ if (HAVE_IBUS_GKBD &&
1366
+ session != null && session.length >= 5 &&
1367
+ session[0:5] == "gnome") {
1371
+ update_xkb_engines();
1374
+ private void update_xkb_engines() {
1375
+ string var_layout = m_xkblayout.get_layout();
1376
+ string var_variant = m_xkblayout.get_variant();
1377
+ if (var_layout == "") {
1381
+ m_layouts = var_layout.split(",");
1382
+ m_variants = var_variant.split(",");
1384
+ IBus.XKBConfigRegistry registry = new IBus.XKBConfigRegistry();
1385
+ string[] var_xkb_engine_names = {};
1386
+ for (int i = 0; i < m_layouts.length; i++) {
1387
+ string name = m_layouts[i];
1388
+ string lang = null;
1390
+ if (i < m_variants.length && m_variants[i] != "") {
1391
+ name = "%s:%s".printf(name, m_variants[i]);
1392
+ string layout = "%s(%s)".printf(name, m_variants[i]);
1393
+ GLib.List<string> langs =
1394
+ registry.layout_lang_get_langs(layout);
1395
+ if (langs.length() != 0) {
1396
+ lang = langs.data;
1399
+ name = "%s:".printf(name);
1402
+ if (lang == null) {
1403
+ GLib.List<string> langs =
1404
+ registry.layout_lang_get_langs(m_layouts[i]);
1405
+ if (langs.length() != 0) {
1406
+ lang = langs.data;
1410
+ var_xkb_engine_names += "%s:%s:%s".printf("xkb", name, lang);
1413
+ string[] engine_names =
1414
+ m_settings_general.get_strv("preload-engines");
1415
+ bool updated_engine_names = false;
1417
+ foreach (string name in var_xkb_engine_names) {
1418
+ if (name in engine_names)
1420
+ updated_engine_names = true;
1421
+ engine_names += name;
1424
+ if (updated_engine_names)
1425
+ m_settings_general.set_strv("preload-engines", engine_names);
1427
+ string[] order_names =
1428
+ m_settings_general.get_strv("engines-order");
1429
+ bool updated_order_names = false;
1431
+ foreach (var name in var_xkb_engine_names) {
1432
+ if (name in order_names)
1434
+ order_names += name;
1435
+ updated_order_names = true;
1438
+ if (updated_order_names)
1439
+ m_settings_general.set_strv("engines-order", order_names);
1442
+ private void set_xkb_group_layout(IBus.EngineDesc engine) {
1443
+ int[] retval = m_xkblayout.set_layout(engine, true);
1444
+ if (retval[0] >= 0) {
1445
+ /* If an XKB keymap is added into the XKB group,
1446
+ * this._gkbdlayout.lock_group will be called after
1447
+ * 'group-changed' signal is received. */
1448
+ m_fallback_lock_id = retval[0];
1449
+ m_changed_xkb_option = (retval[1] != 0) ? true : false;
1453
+ private bool set_gkbd_layout(IBus.EngineDesc engine) {
1454
+ string layout = engine.get_layout();
1455
+ string variant = engine.get_layout_variant();
1457
+ /* If a previous ibus engine changed XKB options, need to set the
1458
+ * default XKB option. */
1459
+ if (m_changed_xkb_option == true) {
1460
+ m_changed_xkb_option = false;
1464
+ if (variant != "" && variant != "default") {
1465
+ layout = "%s(%s)".printf(layout, variant);
1468
+ int gkbd_len = m_gkbdlayout.get_group_names().length;
1469
+ for (int i = 0; i < m_layouts.length && i < gkbd_len; i++) {
1470
+ string sys_layout = m_layouts[i];
1471
+ if (i < m_variants.length && m_variants[i] != "") {
1472
+ sys_layout = "%s(%s)".printf(sys_layout, m_variants[i]);
1474
+ if (sys_layout == layout) {
1475
+ m_gkbdlayout.lock_group(i);
1482
+ private void set_layout(IBus.EngineDesc engine) {
1483
+ string layout = engine.get_layout();
1485
+ if (layout == "" || layout == null) {
1489
+ if (m_xkblayout == null) {
1490
+ init_engines_order();
1493
+ if (HAVE_IBUS_GKBD && m_gkbdlayout != null) {
1494
+ if (set_gkbd_layout(engine)) {
1497
+ set_xkb_group_layout(engine);
1501
+ m_xkblayout.set_layout(engine);
1504
private void exec_setxkbmap(IBus.EngineDesc engine) {
1505
string layout = engine.get_layout();
1506
string variant = engine.get_layout_variant();
1507
@@ -573,7 +767,7 @@ class Panel : IBus.PanelService {
1510
if (!m_use_system_keyboard_layout)
1511
- exec_setxkbmap(engine);
1512
+ set_layout(engine);
1514
engine_contexts_insert(engine);
1516
@@ -636,6 +830,39 @@ class Panel : IBus.PanelService {
1520
+ /* IBus.Bus.get_engines_by_names() returns 'us' engine if the name
1521
+ * does not exist in simple.xml and 'us' engine could be duplicated.
1523
+ private IBus.EngineDesc[] uniq_engines(IBus.EngineDesc[] engines) {
1524
+ if (engines.length == 0)
1528
+ IBus.EngineDesc[] retval = {};
1530
+ for (; i < engines.length; i++) {
1531
+ if (engines[i].get_name() == "xkb:us::eng")
1535
+ if (i == engines.length)
1538
+ for (int j = 0; j < engines.length; j++) {
1540
+ retval += engines[j];
1544
+ if (engines[i].get_name() == engines[j].get_name())
1547
+ retval += engines[j];
1553
private void run_preload_engines(IBus.EngineDesc[] engines, int index) {
1554
string[] names = {};
1556
@@ -668,6 +895,7 @@ class Panel : IBus.PanelService {
1559
var engines = m_bus.get_engines_by_names(names);
1560
+ engines = uniq_engines(engines);
1562
if (m_engines.length == 0) {
1563
m_engines = engines;
1564
diff --git a/ui/gtk3/xkblayout.vala b/ui/gtk3/xkblayout.vala
1565
new file mode 100644
1566
index 0000000..b7dfb3e
1568
+++ b/ui/gtk3/xkblayout.vala
1570
+/* vim:set et sts=4 sw=4:
1572
+ * ibus - The Input Bus
1574
+ * Copyright(c) 2013 Red Hat, Inc.
1575
+ * Copyright(c) 2013 Peng Huang <shawn.p.huang@gmail.com>
1576
+ * Copyright(c) 2013 Takao Fujiwara <tfujiwar@redhat.com>
1578
+ * This library is free software; you can redistribute it and/or
1579
+ * modify it under the terms of the GNU Lesser General Public
1580
+ * License as published by the Free Software Foundation; either
1581
+ * version 2 of the License, or(at your option) any later version.
1583
+ * This library is distributed in the hope that it will be useful,
1584
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1585
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1586
+ * GNU Lesser General Public License for more details.
1588
+ * You should have received a copy of the GNU Lesser General Public
1589
+ * License along with this program; if not, write to the
1590
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
1591
+ * Boston, MA 02111-1307 USA
1594
+public extern const bool HAVE_IBUS_GKBD;
1595
+public extern const int XKB_LAYOUTS_MAX_LENGTH;
1599
+ string m_xkb_command = "setxkbmap";
1600
+ GLib.Settings m_settings_general;
1601
+ string[] m_xkb_latin_layouts = {};
1602
+ GLib.Pid m_xkb_pid = -1;
1603
+ GLib.Pid m_xmodmap_pid = -1;
1604
+ string m_xmodmap_command = "xmodmap";
1605
+ bool m_use_xmodmap = true;
1606
+ string[] m_xmodmap_known_files = {".xmodmap", ".xmodmaprc",
1607
+ ".Xmodmap", ".Xmodmaprc"};
1608
+ string m_default_layout = "";
1609
+ string m_default_variant = "";
1610
+ string m_default_option = "";
1612
+ public XKBLayout() {
1613
+ m_settings_general = new GLib.Settings("org.freedesktop.ibus.general");
1615
+ var value = m_settings_general.get_value("xkb-latin-layouts");
1616
+ for (int i = 0; value != null && i < value.n_children(); i++) {
1617
+ m_xkb_latin_layouts +=
1618
+ value.get_child_value(i).dup_string();
1620
+ if (m_use_xmodmap) {
1621
+ m_use_xmodmap = m_settings_general.get_boolean("use-xmodmap");
1625
+ private string get_output_from_cmdline(string arg, string element) {
1626
+ string[] exec_command = {};
1627
+ exec_command += m_xkb_command;
1628
+ exec_command += arg;
1629
+ string standard_output = null;
1630
+ string standard_error = null;
1631
+ int exit_status = 0;
1632
+ string retval = "";
1634
+ GLib.Process.spawn_sync(null,
1637
+ GLib.SpawnFlags.SEARCH_PATH,
1639
+ out standard_output,
1640
+ out standard_error,
1642
+ } catch (GLib.SpawnError err) {
1643
+ stderr.printf("IBUS_ERROR: %s\n", err.message);
1645
+ if (exit_status != 0) {
1646
+ stderr.printf("IBUS_ERROR: %s\n", standard_error ?? "");
1648
+ if (standard_output == null) {
1651
+ foreach (string line in standard_output.split("\n")) {
1652
+ if (element.length <= line.length &&
1653
+ line[0:element.length] == element) {
1654
+ retval = line[element.length:line.length];
1655
+ if (retval == null) {
1658
+ retval = retval.strip();
1665
+ private void set_layout_cb(GLib.Pid pid, int status) {
1666
+ if (m_xkb_pid != pid) {
1667
+ stderr.printf("IBUS_ERROR: set_layout_cb has another pid\n");
1670
+ GLib.Process.close_pid(m_xkb_pid);
1675
+ private void set_xmodmap_cb(GLib.Pid pid, int status) {
1676
+ if (m_xmodmap_pid != pid) {
1677
+ stderr.printf("IBUS_ERROR: set_xmodmap_cb has another pid\n");
1680
+ GLib.Process.close_pid(m_xmodmap_pid);
1681
+ m_xmodmap_pid = -1;
1684
+ private string get_fullpath(string command) {
1685
+ string envpath = GLib.Environment.get_variable("PATH");
1686
+ foreach (string dir in envpath.split(":")) {
1687
+ string filepath = GLib.Path.build_filename(dir, command);
1688
+ if (GLib.FileUtils.test(filepath, GLib.FileTest.EXISTS)) {
1695
+ private string[] get_xkb_group_layout (string layout,
1697
+ int layouts_max_length) {
1700
+ string[] layouts = m_default_layout.split(",");
1701
+ string[] variants = m_default_variant.split(",");
1702
+ string group_layouts = "";
1703
+ string group_variants = "";
1704
+ bool has_variant = false;
1705
+ bool include_keymap = false;
1707
+ for (i = 0; i < layouts.length; i++) {
1708
+ if (i >= layouts_max_length - 1) {
1713
+ group_layouts = layouts[i];
1715
+ group_layouts = "%s,%s".printf(group_layouts, layouts[i]);
1718
+ if (i >= variants.length) {
1720
+ group_variants = "";
1722
+ group_variants += ",";
1724
+ if (layout == layouts[i] && variant == "") {
1725
+ include_keymap = true;
1730
+ if (layout == layouts[i] && variant == variants[i]) {
1731
+ include_keymap = true;
1735
+ if (variants[i] != "") {
1736
+ has_variant = true;
1740
+ group_variants = variants[i];
1742
+ group_variants = "%s,%s".printf(group_variants, variants[i]);
1746
+ if (variant != "") {
1747
+ has_variant = true;
1750
+ if (!include_keymap) {
1751
+ group_layouts = "%s,%s".printf(group_layouts, layout);
1752
+ group_variants = "%s,%s".printf(group_variants, variant);
1756
+ if (!has_variant) {
1757
+ group_variants = null;
1760
+ return {group_layouts, group_variants, group_id.to_string()};
1763
+ public string[] get_variant_from_layout(string layout) {
1764
+ int left_bracket = layout.index_of("(");
1765
+ int right_bracket = layout.index_of(")");
1766
+ if (left_bracket >= 0 && right_bracket > left_bracket) {
1767
+ return {layout[0:left_bracket] +
1768
+ layout[right_bracket + 1:layout.length],
1769
+ layout[left_bracket + 1:right_bracket]};
1771
+ return {layout, "default"};
1774
+ public string[] get_option_from_layout(string layout) {
1775
+ int left_bracket = layout.index_of("[");
1776
+ int right_bracket = layout.index_of("]");
1777
+ if (left_bracket >= 0 && right_bracket > left_bracket) {
1778
+ return {layout[0:left_bracket] +
1779
+ layout[right_bracket + 1:layout.length],
1780
+ layout[left_bracket + 1:right_bracket]};
1782
+ return {layout, "default"};
1785
+ public string get_layout() {
1786
+ return get_output_from_cmdline("-query", "layout: ");
1789
+ public string get_variant() {
1790
+ return get_output_from_cmdline("-query", "variant: ");
1793
+ public string get_option() {
1794
+ return get_output_from_cmdline("-query", "options: ");
1798
+ public string get_group() {
1799
+ return get_output_from_cmdline("--get-group", "group: ");
1803
+ public int[] set_layout(IBus.EngineDesc engine,
1804
+ bool use_group_layout=false) {
1805
+ string layout = engine.get_layout();
1806
+ string variant = engine.get_layout_variant();
1807
+ string option = engine.get_layout_option();
1809
+ assert (layout != null);
1811
+ int xkb_group_id = 0;
1812
+ int changed_option = 0;
1814
+ if (m_xkb_pid != -1) {
1818
+ if (layout == "default" &&
1819
+ (variant == "default" || variant == "") &&
1820
+ (option == "default" || option == "")) {
1824
+ bool need_us_layout = false;
1825
+ foreach (string latin_layout in m_xkb_latin_layouts) {
1826
+ if (layout == latin_layout && variant != "eng") {
1827
+ need_us_layout = true;
1830
+ if (variant != null &&
1831
+ "%s(%s)".printf(layout, variant) == latin_layout) {
1832
+ need_us_layout = true;
1837
+ int layouts_max_length = XKB_LAYOUTS_MAX_LENGTH;
1838
+ if (need_us_layout) {
1839
+ layouts_max_length--;
1842
+ if (m_default_layout == "") {
1843
+ m_default_layout = get_layout();
1845
+ if (m_default_variant == "") {
1846
+ m_default_variant = get_variant();
1848
+ if (m_default_option == "") {
1849
+ m_default_option = get_option();
1852
+ if (layout == "default") {
1853
+ layout = m_default_layout;
1854
+ variant = m_default_variant;
1856
+ if (use_group_layout) {
1857
+ if (variant == "default") {
1860
+ string[] retval = get_xkb_group_layout (layout, variant,
1861
+ layouts_max_length);
1862
+ layout = retval[0];
1863
+ variant = retval[1];
1864
+ xkb_group_id = int.parse(retval[2]);
1868
+ if (layout == "") {
1869
+ warning("Could not get the correct layout");
1873
+ if (variant == "default" || variant == "") {
1877
+ if (option == "default" || option == "") {
1878
+ option = m_default_option;
1880
+ if (!(option in m_default_option.split(","))) {
1881
+ option = "%s,%s".printf(m_default_option, option);
1882
+ changed_option = 1;
1884
+ option = m_default_option;
1888
+ if (option == "") {
1892
+ if (need_us_layout) {
1894
+ if (variant != null) {
1899
+ string[] args = {};
1900
+ args += m_xkb_command;
1901
+ args += "-layout";
1903
+ if (variant != null) {
1904
+ args += "-variant";
1907
+ if (option != null) {
1908
+ /* TODO: Need to get the session XKB options */
1909
+ args += "-option";
1910
+ args += "-option";
1914
+ GLib.Pid child_pid;
1916
+ GLib.Process.spawn_async(null,
1919
+ GLib.SpawnFlags.DO_NOT_REAP_CHILD |
1920
+ GLib.SpawnFlags.SEARCH_PATH,
1923
+ } catch (GLib.SpawnError err) {
1924
+ stderr.printf("Execute setxkbmap failed: %s\n", err.message);
1927
+ m_xkb_pid = child_pid;
1928
+ GLib.ChildWatch.add(m_xkb_pid, set_layout_cb);
1930
+ return {xkb_group_id, changed_option};
1933
+ public void set_xmodmap() {
1934
+ if (!m_use_xmodmap) {
1938
+ if (m_xmodmap_pid != -1) {
1942
+ string xmodmap_cmdpath = get_fullpath(m_xmodmap_command);
1943
+ if (xmodmap_cmdpath == "") {
1944
+ xmodmap_cmdpath = m_xmodmap_command;
1946
+ string homedir = GLib.Environment.get_home_dir();
1947
+ foreach (string xmodmap_file in m_xmodmap_known_files) {
1948
+ string xmodmap_filepath = GLib.Path.build_filename(homedir, xmodmap_file);
1949
+ if (!GLib.FileUtils.test(xmodmap_filepath, GLib.FileTest.EXISTS)) {
1952
+ string[] args = {xmodmap_cmdpath, xmodmap_filepath};
1954
+ GLib.Pid child_pid;
1956
+ GLib.Process.spawn_async(null,
1959
+ GLib.SpawnFlags.DO_NOT_REAP_CHILD |
1960
+ GLib.SpawnFlags.SEARCH_PATH,
1963
+ } catch (GLib.SpawnError err) {
1964
+ stderr.printf("IBUS_ERROR: %s\n", err.message);
1967
+ m_xmodmap_pid = child_pid;
1968
+ GLib.ChildWatch.add(m_xmodmap_pid, set_xmodmap_cb);
1974
+ public void reset_layout() {
1975
+ m_default_layout = get_layout();
1976
+ m_default_variant = get_variant();
1977
+ m_default_option = get_option();
1981
+ public static int main(string[] args) {
1982
+ IBus.Bus bus = new IBus.Bus();
1983
+ IBus.Config config = bus.get_config();
1984
+ XKBLayout xkblayout = new XKBLayout(config);
1985
+ stdout.printf ("layout: %s\n", xkblayout.get_layout());
1986
+ stdout.printf ("variant: %s\n", xkblayout.get_variant());
1987
+ stdout.printf ("option: %s\n", xkblayout.get_option());
1988
+ xkblayout.set_layout("jp");
1989
+ if (config != null) {
1992
+ Gtk.init (ref args);