Merge lp:~attente/unity-settings-daemon/fcitx-transition into lp:unity-settings-daemon

Proposed by William Hua
Status: Merged
Approved by: Sebastien Bacher
Approved revision: 4064
Merged at revision: 4069
Proposed branch: lp:~attente/unity-settings-daemon/fcitx-transition
Merge into: lp:unity-settings-daemon
Diff against target: 1362 lines (+998/-66)
8 files modified
.bzrignore (+1/-0)
configure.ac (+22/-2)
debian/control (+4/-1)
debian/rules (+1/-1)
plugins/keyboard/Makefile.am (+7/-0)
plugins/keyboard/gsd-keyboard-manager.c (+633/-50)
plugins/keyboard/input-method-engines.gperf (+203/-0)
plugins/media-keys/gsd-media-keys-manager.c (+127/-12)
To merge this branch: bzr merge lp:~attente/unity-settings-daemon/fcitx-transition
Reviewer Review Type Date Requested Status
Sebastien Bacher Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+230289@code.launchpad.net

Commit message

Basic Fcitx support.

Description of the change

Basic Fcitx support.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4049. By William Hua

Revert.

4050. By William Hua

Use fcitx-gclient API instead.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Sebastien Bacher (seb128) wrote :

Thanks, looks mostly fine, some comments:

- we shouldn't recommend both ibus and fcitx from the settings daemon, we should rather seed fcitx if we want it installed by default

- we need to have the fcitx MIR approved because we can land the changes, since it adds a build-depends on packages which are currently in universe

- looks fine to land otherwise

setting needs fixing for the recommend, then it's good to go, once the fcitx MIR is ready

review: Needs Fixing
4051. By William Hua

Remove fcitx from recommends.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4052. By William Hua

Sync Fcitx engine list to input sources.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4053. By William Hua

Activate Fcitx when disabled.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4054. By William Hua

Translate keyboard layout names properly to Fcitx.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4055. By William Hua

Update current index when Fcitx engine changes.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4056. By William Hua

Sync fcitx engines to dconf.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4057. By William Hua

Fix migration; WIP: finish get_fcitx_engine_for_ibus_engine ().

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4058. By William Hua

Finish get_fcitx_engine_for_ibus_engine ().

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
4059. By William Hua

Add gperf as build dependency.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4060. By William Hua

Set initial IM when Fcitx appears.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4061. By William Hua

Use Fcitx current IM instead of current source when available.

4062. By William Hua

Migrate per-window setting to Fcitx.

4063. By William Hua

Remember to zero struct.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
4064. By William Hua

Merge trunk.

Revision history for this message
William Hua (attente) wrote :

Hi, could we please reconsider this for approval now that Fcitx is approved for main? I don't remember why I added fcitx-data as a Recommends, but if it's wrong, I'll remove it.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Sebastien Bacher (seb128) wrote :

Thanks, seems like we don't have anyone available to do a detailed review, so based on a read of the changes and testing in a ppa let's approve that, if there are issues we can sort them out with another landing

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2013-12-04 23:55:26 +0000
3+++ .bzrignore 2015-02-12 15:57:03 +0000
4@@ -48,6 +48,7 @@
5 plugins/datetime/gsd-datetime-mechanism-glue.h
6 plugins/datetime/org.gnome.SettingsDaemon.DateTimeMechanism.service
7 plugins/datetime/org.gnome.settingsdaemon.datetimemechanism.policy
8+plugins/keyboard/input-method-engines.c
9 plugins/media-keys/gsd-marshal.c
10 plugins/media-keys/gsd-marshal.h
11 plugins/media-keys/gsd-media-keys-manager-glue.h
12
13=== modified file 'configure.ac'
14--- configure.ac 2014-10-07 23:50:00 +0000
15+++ configure.ac 2015-02-12 15:57:03 +0000
16@@ -204,7 +204,26 @@
17 fi
18 AM_CONDITIONAL(HAVE_IBUS, test "x$enable_ibus" == "xyes")
19
20-PKG_CHECK_MODULES(KEYBOARD, accountsservice xkbfile xkeyboard-config $IBUS_MODULE gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION)
21+AC_ARG_ENABLE(fcitx,
22+ AS_HELP_STRING([--disable-fcitx],
23+ [Disable Fcitx support]),
24+ enable_fcitx=$enableval,
25+ enable_fcitx=yes)
26+
27+if test "x$enable_fcitx" = "xyes" ; then
28+ FCITX_MODULE="fcitx-config fcitx-gclient"
29+ AC_DEFINE(HAVE_FCITX, 1, [Defined if Fcitx support is enabled])
30+
31+ AC_CHECK_PROG(HAVE_GPERF, gperf, yes)
32+ if test "x$HAVE_GPERF" != "xyes" ; then
33+ AC_MSG_ERROR([gperf needed for Fcitx support])
34+ fi
35+else
36+ FCITX_MODULE=
37+fi
38+AM_CONDITIONAL(HAVE_FCITX, test "x$enable_fcitx" == "xyes")
39+
40+PKG_CHECK_MODULES(KEYBOARD, accountsservice xkbfile xkeyboard-config $IBUS_MODULE $FCITX_MODULE gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION)
41
42 XKB_BASE=$($PKG_CONFIG --variable xkb_base xkeyboard-config)
43 AC_SUBST(XKB_BASE)
44@@ -218,7 +237,7 @@
45 dnl - media-keys plugin stuff
46 dnl ---------------------------------------------------------------------------
47
48-PKG_CHECK_MODULES(MEDIA_KEYS, [gio-unix-2.0 libpulse >= $PA_REQUIRED_VERSION $GUDEV_PKG libpulse-mainloop-glib >= $PA_REQUIRED_VERSION libcanberra-gtk3 libnotify alsa])
49+PKG_CHECK_MODULES(MEDIA_KEYS, [gio-unix-2.0 libpulse >= $PA_REQUIRED_VERSION $GUDEV_PKG libpulse-mainloop-glib >= $PA_REQUIRED_VERSION libcanberra-gtk3 libnotify alsa $FCITX_MODULE])
50 PKG_CHECK_MODULES(GVC, [gobject-2.0 libpulse >= $PA_REQUIRED_VERSION libpulse-mainloop-glib >= $PA_REQUIRED_VERSION])
51 AM_CONDITIONAL(HAVE_INTROSPECTION, false)
52
53@@ -564,6 +583,7 @@
54 Session tracking: ${SESSION_TRACKING}
55 LCMS DICT support: ${have_new_lcms}
56 IBus support: ${enable_ibus}
57+ Fcitx support: ${enable_fcitx}
58 Libnotify support: ${have_libnotify}
59 PackageKit support: ${have_packagekit}
60 Smartcard support: ${have_smartcard_support}
61
62=== modified file 'debian/control'
63--- debian/control 2014-11-27 10:32:03 +0000
64+++ debian/control 2015-02-12 15:57:03 +0000
65@@ -41,6 +41,8 @@
66 libxklavier-dev,
67 libsystemd-login-dev (>= 183),
68 libibus-1.0-dev (>= 1.5.0),
69+ fcitx-libs-dev,
70+ gperf,
71 libgl1-mesa-dev,
72 libxkbfile-dev,
73 xkb-data,
74@@ -56,7 +58,8 @@
75 nautilus-data (>= 2.91.3-1),
76 gnome-settings-daemon-schemas (>= 3.8),
77 gsettings-ubuntu-schemas (>= 0.0.1+14.04.20140224),
78-Recommends: ibus (>= 1.5.0),
79+Recommends: fcitx-data,
80+ ibus (>= 1.5.0),
81 pulseaudio,
82 systemd-services
83 Pre-Depends: ${misc:Pre-Depends}
84
85=== modified file 'debian/rules'
86--- debian/rules 2014-10-07 23:50:00 +0000
87+++ debian/rules 2015-02-12 15:57:03 +0000
88@@ -8,7 +8,7 @@
89
90 DEB_DH_MAKESHLIBS_ARGS_ALL += -X/usr/lib/unity-settings-daemon-1.0
91 DEB_CONFIGURE_SCRIPT := ./autogen.sh
92-DEB_CONFIGURE_EXTRA_FLAGS = --enable-systemd --disable-packagekit --enable-ibus
93+DEB_CONFIGURE_EXTRA_FLAGS = --enable-systemd --disable-packagekit --enable-ibus --enable-fcitx
94
95 build/unity-settings-daemon::
96 gcc -o gnome-settings-daemon/gnome-update-wallpaper-cache debian/gnome-update-wallpaper-cache.c `pkg-config --cflags --libs glib-2.0 gdk-3.0 gdk-x11-3.0 gio-2.0 gnome-desktop-3.0`
97
98=== modified file 'plugins/keyboard/Makefile.am'
99--- plugins/keyboard/Makefile.am 2014-09-29 11:08:12 +0000
100+++ plugins/keyboard/Makefile.am 2015-02-12 15:57:03 +0000
101@@ -15,6 +15,13 @@
102 kbd-capslock-off.png kbd-numlock-off.png kbd-scrolllock-off.png \
103 kbd-capslock-on.png kbd-numlock-on.png kbd-scrolllock-on.png
104
105+if HAVE_FCITX
106+BUILT_SOURCES = input-method-engines.c
107+endif
108+
109+input-method-engines.c: $(srcdir)/input-method-engines.gperf
110+ $(AM_V_GEN) gperf --output-file=input-method-engines.c $<
111+
112 libkeyboard_la_SOURCES = \
113 gsd-keyboard-plugin.c \
114 gsd-keyboard-manager.h \
115
116=== modified file 'plugins/keyboard/gsd-keyboard-manager.c'
117--- plugins/keyboard/gsd-keyboard-manager.c 2014-09-29 11:08:12 +0000
118+++ plugins/keyboard/gsd-keyboard-manager.c 2015-02-12 15:57:03 +0000
119@@ -48,6 +48,11 @@
120 #include <ibus.h>
121 #endif
122
123+#ifdef HAVE_FCITX
124+#include <fcitx-config/fcitx-config.h>
125+#include <fcitx-gclient/fcitxinputmethod.h>
126+#endif
127+
128 #include <act/act.h>
129
130 #include "gnome-settings-session.h"
131@@ -57,6 +62,10 @@
132 #include "gsd-enums.h"
133 #include "gsd-xkb-utils.h"
134
135+#ifdef HAVE_FCITX
136+#include "input-method-engines.c"
137+#endif
138+
139 #define GSD_KEYBOARD_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_KEYBOARD_MANAGER, GsdKeyboardManagerPrivate))
140
141 #define GSD_KEYBOARD_DIR "org.gnome.settings-daemon.peripherals.keyboard"
142@@ -76,9 +85,11 @@
143
144 #define GNOME_DESKTOP_INTERFACE_DIR "org.gnome.desktop.interface"
145
146+#define ENV_GTK_IM_MODULE "GTK_IM_MODULE"
147 #define KEY_GTK_IM_MODULE "gtk-im-module"
148 #define GTK_IM_MODULE_SIMPLE "gtk-im-context-simple"
149 #define GTK_IM_MODULE_IBUS "ibus"
150+#define GTK_IM_MODULE_FCITX "fcitx"
151
152 #define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources"
153
154@@ -86,8 +97,11 @@
155 #define KEY_INPUT_SOURCES "sources"
156 #define KEY_KEYBOARD_OPTIONS "xkb-options"
157
158-#define INPUT_SOURCE_TYPE_XKB "xkb"
159-#define INPUT_SOURCE_TYPE_IBUS "ibus"
160+#define INPUT_SOURCE_TYPE_XKB "xkb"
161+#define INPUT_SOURCE_TYPE_IBUS "ibus"
162+#define INPUT_SOURCE_TYPE_FCITX "fcitx"
163+
164+#define FCITX_XKB_PREFIX "fcitx-keyboard-"
165
166 #define DEFAULT_LANGUAGE "en_US"
167 #define DEFAULT_LAYOUT "us"
168@@ -108,6 +122,13 @@
169 IBusBus *ibus;
170 GHashTable *ibus_engines;
171 GCancellable *ibus_cancellable;
172+ gboolean is_ibus_active;
173+#endif
174+#ifdef HAVE_FCITX
175+ FcitxInputMethod *fcitx;
176+ GCancellable *fcitx_cancellable;
177+ gulong fcitx_signal_id;
178+ gboolean is_fcitx_active;
179 #endif
180 gint xkb_event_base;
181 GsdNumLockState old_state;
182@@ -1079,6 +1100,186 @@
183 }
184 }
185
186+#ifdef HAVE_FCITX
187+static gchar *
188+get_xkb_name (const gchar *name)
189+{
190+ gchar *xkb_name;
191+ gchar *separator;
192+
193+ if (g_str_has_prefix (name, FCITX_XKB_PREFIX))
194+ name += strlen (FCITX_XKB_PREFIX);
195+
196+ xkb_name = g_strdup (name);
197+ separator = strchr (xkb_name, '-');
198+
199+ if (separator)
200+ *separator = '+';
201+
202+ return xkb_name;
203+}
204+
205+static gchar *
206+get_fcitx_name (const gchar *name)
207+{
208+ gchar *fcitx_name = g_strdup (name);
209+ gchar *separator = strchr (fcitx_name, '+');
210+
211+ if (separator)
212+ *separator = '-';
213+
214+ return fcitx_name;
215+}
216+
217+static gboolean
218+input_source_is_fcitx_engine (const gchar *type,
219+ const gchar *name,
220+ const gchar *engine)
221+{
222+ if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) {
223+ if (g_str_has_prefix (engine, FCITX_XKB_PREFIX)) {
224+ gboolean equal;
225+ gchar *fcitx_name = get_fcitx_name (name);
226+ equal = g_str_equal (fcitx_name, engine + strlen (FCITX_XKB_PREFIX));
227+ g_free (fcitx_name);
228+ return equal;
229+ }
230+ } else if (g_str_equal (type, INPUT_SOURCE_TYPE_FCITX)) {
231+ return g_str_equal (name, engine);
232+ }
233+
234+ return FALSE;
235+}
236+
237+static void
238+fcitx_engine_changed (GsdKeyboardManager *manager,
239+ GParamSpec *pspec,
240+ FcitxInputMethod *fcitx)
241+{
242+ GSettings *settings = manager->priv->input_sources_settings;
243+ gchar *engine = fcitx_input_method_get_current_im (manager->priv->fcitx);
244+
245+ if (engine) {
246+ GVariant *sources = g_settings_get_value (settings, KEY_INPUT_SOURCES);
247+ guint current = g_settings_get_uint (settings, KEY_CURRENT_INPUT_SOURCE);
248+ gboolean update = TRUE;
249+
250+ if (current >= 0 && current < g_variant_n_children (sources)) {
251+ const gchar *type;
252+ const gchar *name;
253+
254+ g_variant_get_child (sources, current, "(&s&s)", &type, &name);
255+ update = !input_source_is_fcitx_engine (type, name, engine);
256+ }
257+
258+ if (update) {
259+ gsize i;
260+
261+ for (i = 0; i < g_variant_n_children (sources); i++) {
262+ const gchar *type;
263+ const gchar *name;
264+
265+ if (i == current)
266+ continue;
267+
268+ g_variant_get_child (sources, i, "(&s&s)", &type, &name);
269+
270+ if (input_source_is_fcitx_engine (type, name, engine)) {
271+ g_settings_set_uint (settings, KEY_CURRENT_INPUT_SOURCE, i);
272+ break;
273+ }
274+ }
275+ }
276+
277+ g_variant_unref (sources);
278+ g_free (engine);
279+ }
280+}
281+
282+static gboolean
283+should_update_input_sources (GVariant *sources,
284+ GPtrArray *engines)
285+{
286+ GVariantIter iter;
287+ const gchar *type;
288+ const gchar *name;
289+ guint i = 0;
290+
291+ g_variant_iter_init (&iter, sources);
292+ while (g_variant_iter_next (&iter, "(&s&s)", &type, &name)) {
293+ if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB) ||
294+ g_str_equal (type, INPUT_SOURCE_TYPE_FCITX)) {
295+ FcitxIMItem *engine;
296+
297+ /* get the next enabled fcitx engine */
298+ for (; i < engines->len; i++) {
299+ engine = g_ptr_array_index (engines, i);
300+
301+ if (engine->enable)
302+ break;
303+ }
304+
305+ /* there should be an enabled engine and it should match, otherwise we need to update */
306+ if (i++ >= engines->len || !input_source_is_fcitx_engine (type, name, engine->unique_name))
307+ return TRUE;
308+ }
309+ }
310+
311+ /* if there are more enabled engines, we need to update */
312+ for (; i < engines->len; i++) {
313+ FcitxIMItem *engine = g_ptr_array_index (engines, i);
314+
315+ if (engine->enable)
316+ return TRUE;
317+ }
318+
319+ return FALSE;
320+}
321+
322+static void
323+update_input_sources_from_fcitx_engines (GsdKeyboardManager *manager,
324+ FcitxInputMethod *fcitx)
325+{
326+ GPtrArray *engines = fcitx_input_method_get_imlist (manager->priv->fcitx);
327+
328+ if (engines) {
329+ GVariant *sources = g_settings_get_value (manager->priv->input_sources_settings, KEY_INPUT_SOURCES);
330+
331+ if (should_update_input_sources (sources, engines)) {
332+ GVariantBuilder builder;
333+ gboolean update = FALSE;
334+ guint i;
335+
336+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(ss)"));
337+
338+ for (i = 0; i < engines->len; i++) {
339+ FcitxIMItem *engine = g_ptr_array_index (engines, i);
340+
341+ if (engine->enable) {
342+ if (g_str_has_prefix (engine->unique_name, FCITX_XKB_PREFIX)) {
343+ gchar *name = get_xkb_name (engine->unique_name);
344+ g_variant_builder_add (&builder, "(ss)", INPUT_SOURCE_TYPE_XKB, name);
345+ g_free (name);
346+ } else {
347+ g_variant_builder_add (&builder, "(ss)", INPUT_SOURCE_TYPE_FCITX, engine->unique_name);
348+ }
349+
350+ update = TRUE;
351+ }
352+ }
353+
354+ if (update)
355+ g_settings_set_value (manager->priv->input_sources_settings, KEY_INPUT_SOURCES, g_variant_builder_end (&builder));
356+ else
357+ g_variant_builder_clear (&builder);
358+ }
359+
360+ g_variant_unref (sources);
361+ g_ptr_array_unref (engines);
362+ }
363+}
364+#endif
365+
366 static gboolean
367 apply_input_source (GsdKeyboardManager *manager,
368 guint current)
369@@ -1103,7 +1304,9 @@
370 priv->active_input_source = current;
371
372 #ifdef HAVE_IBUS
373- maybe_start_ibus (manager);
374+ if (priv->is_ibus_active) {
375+ maybe_start_ibus (manager);
376+ }
377 #endif
378
379 g_variant_get_child (sources, current, "(&s&s)", &type, &id);
380@@ -1119,44 +1322,86 @@
381 g_warning ("Couldn't find XKB input source '%s'", id);
382 goto exit;
383 }
384+
385+#ifdef HAVE_FCITX
386+ if (priv->is_fcitx_active && priv->fcitx) {
387+ gchar *name = g_strdup_printf (FCITX_XKB_PREFIX "%s", id);
388+ gchar *fcitx_name = get_fcitx_name (name);
389+ fcitx_input_method_activate (priv->fcitx);
390+ fcitx_input_method_set_current_im (priv->fcitx, fcitx_name);
391+ g_free (fcitx_name);
392+ g_free (name);
393+ }
394+#endif
395+
396 #ifdef HAVE_IBUS
397- set_gtk_im_module (manager, sources);
398- set_ibus_xkb_engine (manager);
399+ if (priv->is_ibus_active) {
400+ set_gtk_im_module (manager, sources);
401+ set_ibus_xkb_engine (manager);
402+ }
403 #endif
404 } else if (g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) {
405 #ifdef HAVE_IBUS
406- IBusEngineDesc *engine_desc = NULL;
407-
408- if (priv->ibus_engines)
409- engine_desc = g_hash_table_lookup (priv->ibus_engines, id);
410- else
411- goto exit; /* we'll be called again when ibus is up and running */
412-
413- if (engine_desc) {
414- const gchar *ibus_layout;
415- ibus_layout = ibus_engine_desc_get_layout (engine_desc);
416-
417- if (ibus_layout) {
418- layout = layout_from_ibus_layout (ibus_layout);
419- variant = variant_from_ibus_layout (ibus_layout);
420- options = options_from_ibus_layout (ibus_layout);
421+ if (priv->is_ibus_active) {
422+ IBusEngineDesc *engine_desc = NULL;
423+
424+ if (priv->ibus_engines)
425+ engine_desc = g_hash_table_lookup (priv->ibus_engines, id);
426+ else
427+ goto exit; /* we'll be called again when ibus is up and running */
428+
429+ if (engine_desc) {
430+ const gchar *ibus_layout;
431+ ibus_layout = ibus_engine_desc_get_layout (engine_desc);
432+
433+ if (ibus_layout) {
434+ layout = layout_from_ibus_layout (ibus_layout);
435+ variant = variant_from_ibus_layout (ibus_layout);
436+ options = options_from_ibus_layout (ibus_layout);
437+ }
438+ } else {
439+ g_warning ("Couldn't find IBus input source '%s'", id);
440+ goto exit;
441 }
442+
443+ /* NULL here is a shortcut for "I already know I
444+ need the IBus module". */
445+ set_gtk_im_module (manager, NULL);
446+ set_ibus_engine (manager, id);
447 } else {
448- g_warning ("Couldn't find IBus input source '%s'", id);
449- goto exit;
450+ g_warning ("IBus input source type specified but IBus is not active");
451 }
452-
453- /* NULL here is a shortcut for "I already know I
454- need the IBus module". */
455- set_gtk_im_module (manager, NULL);
456- set_ibus_engine (manager, id);
457 #else
458 g_warning ("IBus input source type specified but IBus support was not compiled");
459 #endif
460+ } else if (g_str_equal (type, INPUT_SOURCE_TYPE_FCITX)) {
461+#ifdef HAVE_FCITX
462+ if (priv->is_fcitx_active) {
463+ if (priv->fcitx) {
464+ gchar *name = g_strdup (id);
465+ fcitx_input_method_activate (priv->fcitx);
466+ fcitx_input_method_set_current_im (priv->fcitx, name);
467+ g_free (name);
468+ } else {
469+ g_warning ("Fcitx input method framework unavailable");
470+ }
471+ } else {
472+ g_warning ("Fcitx input source type specified but Fcitx is not active");
473+ }
474+#else
475+ g_warning ("Fcitx input source type specified but Fcitx support was not compiled");
476+#endif
477 } else {
478 g_warning ("Unknown input source type '%s'", type);
479 }
480
481+#ifdef HAVE_FCITX
482+ if (priv->is_fcitx_active && priv->fcitx && !priv->fcitx_signal_id) {
483+ priv->fcitx_signal_id = g_signal_connect_swapped (manager->priv->fcitx, "notify::current-im", G_CALLBACK (fcitx_engine_changed), manager);
484+ g_signal_connect_swapped (manager->priv->fcitx, "imlist-changed", G_CALLBACK (update_input_sources_from_fcitx_engines), manager);
485+ }
486+#endif
487+
488 exit:
489 apply_xkb_settings (manager, layout, variant,
490 prepare_xkb_options (manager, n_sources, options));
491@@ -1168,6 +1413,229 @@
492 return TRUE;
493 }
494
495+#ifdef HAVE_FCITX
496+static const gchar *
497+get_fcitx_engine_for_ibus_engine (const gchar *ibus_engine)
498+{
499+ const struct Engine *engine;
500+
501+ if (!ibus_engine)
502+ return NULL;
503+
504+ engine = get_engine_for_ibus_engine (ibus_engine, strlen (ibus_engine));
505+
506+ return engine ? engine->fcitx_engine : NULL;
507+}
508+
509+static void
510+enable_fcitx_engines (GsdKeyboardManager *manager,
511+ gboolean migrate)
512+{
513+ GsdKeyboardManagerPrivate *priv = manager->priv;
514+ GPtrArray *engines;
515+ GVariant *sources;
516+ GVariantIter iter;
517+ const gchar *type;
518+ const gchar *name;
519+ gboolean changed;
520+ guint i;
521+ guint j;
522+
523+ engines = fcitx_input_method_get_imlist (priv->fcitx);
524+
525+ if (!engines) {
526+ g_warning ("Cannot update Fcitx engine list");
527+ return;
528+ }
529+
530+ sources = g_settings_get_value (priv->input_sources_settings, KEY_INPUT_SOURCES);
531+ changed = FALSE;
532+ i = 0;
533+
534+ g_variant_iter_init (&iter, sources);
535+ while (g_variant_iter_next (&iter, "(&s&s)", &type, &name)) {
536+ if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) {
537+ gchar *fcitx_name = get_fcitx_name (name);
538+
539+ for (j = i; j < engines->len; j++) {
540+ FcitxIMItem *engine = g_ptr_array_index (engines, j);
541+
542+ if (g_str_has_prefix (engine->unique_name, FCITX_XKB_PREFIX) &&
543+ g_str_equal (engine->unique_name + strlen (FCITX_XKB_PREFIX), fcitx_name)) {
544+ if (!engine->enable) {
545+ engine->enable = TRUE;
546+ changed = TRUE;
547+ }
548+
549+ break;
550+ }
551+ }
552+
553+ g_free (fcitx_name);
554+
555+ /* j is either the index of the engine "fcitx-keyboard-<name>"
556+ * or engines->len, meaning it wasn't found. */
557+ } else if (migrate && g_str_equal (type, INPUT_SOURCE_TYPE_IBUS)) {
558+ const gchar *fcitx_name = get_fcitx_engine_for_ibus_engine (name);
559+
560+ if (!fcitx_name)
561+ continue;
562+
563+ for (j = i; j < engines->len; j++) {
564+ FcitxIMItem *engine = g_ptr_array_index (engines, j);
565+
566+ if (g_str_equal (engine->unique_name, fcitx_name)) {
567+ if (!engine->enable) {
568+ engine->enable = TRUE;
569+ changed = TRUE;
570+ }
571+
572+ break;
573+ }
574+ }
575+
576+ /* j is either the index of the engine "<name>"
577+ * or engines->len, meaning it wasn't found. */
578+ } else if (g_str_equal (type, INPUT_SOURCE_TYPE_FCITX)) {
579+ for (j = i; j < engines->len; j++) {
580+ FcitxIMItem *engine = g_ptr_array_index (engines, j);
581+
582+ if (g_str_equal (engine->unique_name, name)) {
583+ if (!engine->enable) {
584+ engine->enable = TRUE;
585+ changed = TRUE;
586+ }
587+
588+ break;
589+ }
590+ }
591+
592+ /* j is either the index of the engine "<name>"
593+ * or engines->len, meaning it wasn't found. */
594+ } else {
595+ continue;
596+ }
597+
598+ if (j < engines->len) {
599+ if (j != i) {
600+ gpointer ptr = engines->pdata[i];
601+ engines->pdata[i] = engines->pdata[j];
602+ engines->pdata[j] = ptr;
603+ changed = TRUE;
604+ }
605+
606+ i++;
607+ } else {
608+ g_warning ("Fcitx engine not found for %s", name);
609+ }
610+ }
611+
612+ /* we should have i enabled fcitx engines: disable everything else. */
613+
614+ for (; i < engines->len; i++) {
615+ FcitxIMItem *engine = g_ptr_array_index (engines, i);
616+
617+ if (engine->enable) {
618+ engine->enable = FALSE;
619+ changed = TRUE;
620+ }
621+ }
622+
623+ if (changed) {
624+ fcitx_input_method_set_imlist (priv->fcitx, engines);
625+ }
626+
627+ g_variant_unref (sources);
628+ g_ptr_array_unref (engines);
629+}
630+
631+struct _FcitxShareStateConfig
632+{
633+ FcitxGenericConfig config;
634+ gint share_state;
635+};
636+
637+typedef struct _FcitxShareStateConfig FcitxShareStateConfig;
638+
639+static CONFIG_BINDING_BEGIN (FcitxShareStateConfig)
640+CONFIG_BINDING_REGISTER ("Program", "ShareStateAmongWindow", share_state)
641+CONFIG_BINDING_END ()
642+
643+static CONFIG_DESC_DEFINE (get_fcitx_config_desc, "config.desc")
644+
645+static void
646+update_share_state_from_per_window (GsdKeyboardManager *manager)
647+{
648+ /* Set Fcitx' share state setting based on the GSettings per-window option. */
649+ GSettings *settings = g_settings_new ("org.gnome.libgnomekbd.desktop");
650+ gboolean per_window = g_settings_get_boolean (settings, "group-per-window");
651+
652+ FcitxShareStateConfig config = { { NULL } };
653+
654+ /* Load the user's Fcitx configuration. */
655+ FILE *file = FcitxXDGGetFileUserWithPrefix (NULL, "config", "r", NULL);
656+ FcitxConfigFile *config_file = FcitxConfigParseConfigFileFp (file, get_fcitx_config_desc ());
657+ FcitxShareStateConfigConfigBind (&config, config_file, get_fcitx_config_desc ());
658+
659+ if (file)
660+ fclose (file);
661+
662+ config.share_state = per_window ? 0 : 1;
663+
664+ /* Save the user's Fcitx configuration. */
665+ file = FcitxXDGGetFileUserWithPrefix (NULL, "config", "w", NULL);
666+ FcitxConfigSaveConfigFileFp (file, &config.config, get_fcitx_config_desc ());
667+
668+ if (file)
669+ fclose (file);
670+
671+ fcitx_input_method_reload_config (manager->priv->fcitx);
672+
673+ g_object_unref (settings);
674+}
675+
676+static void
677+migrate_fcitx_engines (GsdKeyboardManager *manager)
678+{
679+ GPtrArray *engines = fcitx_input_method_get_imlist (manager->priv->fcitx);
680+
681+ if (engines) {
682+ gboolean migrate = FALSE;
683+ gboolean second = FALSE;
684+ guint i;
685+
686+ /* Migrate if there are at least two enabled fcitx engines or
687+ * there is one fcitx engine which is not a keyboard layout.
688+ * These are our criteria for determining which direction to
689+ * sync fcitx engines with input sources. */
690+
691+ for (i = 0; i < engines->len; i++) {
692+ FcitxIMItem *engine = g_ptr_array_index (engines, i);
693+
694+ if (engine->enable) {
695+ if (second || !g_str_has_prefix (engine->unique_name, FCITX_XKB_PREFIX)) {
696+ migrate = TRUE;
697+ break;
698+ }
699+
700+ second = TRUE;
701+ }
702+ }
703+
704+ if (migrate) {
705+ /* Migrate Fcitx to GSettings. */
706+ update_input_sources_from_fcitx_engines (manager, manager->priv->fcitx);
707+ } else {
708+ /* Migrate GSettings to Fcitx. */
709+ enable_fcitx_engines (manager, TRUE);
710+ update_share_state_from_per_window (manager);
711+ }
712+
713+ g_ptr_array_unref (engines);
714+ }
715+}
716+#endif
717+
718 static gboolean
719 apply_input_sources_settings (GSettings *settings,
720 gpointer keys,
721@@ -1181,6 +1649,30 @@
722 ActUserManager *user_manager;
723 gboolean user_manager_loaded;
724
725+#ifdef HAVE_FCITX
726+ if (priv->is_fcitx_active) {
727+ gboolean sources_changed = FALSE;
728+
729+ if (keys) {
730+ GQuark *quarks = keys;
731+ gint i;
732+
733+ for (i = 0; i < n_keys; i++) {
734+ if (quarks[i] == g_quark_try_string (KEY_INPUT_SOURCES)) {
735+ sources_changed = TRUE;
736+ break;
737+ }
738+ }
739+ } else {
740+ sources_changed = TRUE;
741+ }
742+
743+ if (sources_changed) {
744+ enable_fcitx_engines (manager, FALSE);
745+ }
746+ }
747+#endif
748+
749 sources = g_settings_get_value (priv->input_sources_settings, KEY_INPUT_SOURCES);
750 n_sources = g_variant_n_children (sources);
751
752@@ -1546,11 +2038,10 @@
753 g_object_unref (libgnomekbd_settings);
754 }
755
756-static void
757-maybe_convert_old_settings (GSettings *settings)
758+static gboolean
759+should_migrate (const gchar *id)
760 {
761- GVariant *sources;
762- gchar **options;
763+ gboolean migrate = FALSE;
764 gchar *stamp_dir_path = NULL;
765 gchar *stamp_file_path = NULL;
766 GError *error = NULL;
767@@ -1561,23 +2052,11 @@
768 goto out;
769 }
770
771- stamp_file_path = g_build_filename (stamp_dir_path, "input-sources-converted", NULL);
772+ stamp_file_path = g_build_filename (stamp_dir_path, id, NULL);
773 if (g_file_test (stamp_file_path, G_FILE_TEST_EXISTS))
774 goto out;
775
776- sources = g_settings_get_value (settings, KEY_INPUT_SOURCES);
777- if (g_variant_n_children (sources) < 1) {
778- convert_libgnomekbd_layouts (settings);
779-#ifdef HAVE_IBUS
780- convert_ibus (settings);
781-#endif
782- }
783- g_variant_unref (sources);
784-
785- options = g_settings_get_strv (settings, KEY_KEYBOARD_OPTIONS);
786- if (g_strv_length (options) < 1)
787- convert_libgnomekbd_options (settings);
788- g_strfreev (options);
789+ migrate = TRUE;
790
791 if (!g_file_set_contents (stamp_file_path, "", 0, &error)) {
792 g_warning ("%s", error->message);
793@@ -1586,6 +2065,30 @@
794 out:
795 g_free (stamp_file_path);
796 g_free (stamp_dir_path);
797+ return migrate;
798+}
799+
800+static void
801+maybe_convert_old_settings (GSettings *settings)
802+{
803+ if (should_migrate ("input-sources-converted")) {
804+ GVariant *sources;
805+ gchar **options;
806+
807+ sources = g_settings_get_value (settings, KEY_INPUT_SOURCES);
808+ if (g_variant_n_children (sources) < 1) {
809+ convert_libgnomekbd_layouts (settings);
810+#ifdef HAVE_IBUS
811+ convert_ibus (settings);
812+#endif
813+ }
814+ g_variant_unref (sources);
815+
816+ options = g_settings_get_strv (settings, KEY_KEYBOARD_OPTIONS);
817+ if (g_strv_length (options) < 1)
818+ convert_libgnomekbd_options (settings);
819+ g_strfreev (options);
820+ }
821 }
822
823 static void
824@@ -1708,10 +2211,12 @@
825 if (is_set_input_source || is_activate_input_source) {
826 if (priv->invocation) {
827 #ifdef HAVE_IBUS
828- /* This can only happen if there's an
829- * ibus_bus_set_global_engine_async() call
830- * going on. */
831- g_cancellable_cancel (priv->ibus_cancellable);
832+ if (priv->is_ibus_active) {
833+ /* This can only happen if there's an
834+ * ibus_bus_set_global_engine_async() call
835+ * going on. */
836+ g_cancellable_cancel (priv->ibus_cancellable);
837+ }
838 #endif
839 g_clear_pointer (&priv->invocation, set_input_source_return);
840 priv->pending_ops = 0;
841@@ -1840,13 +2345,46 @@
842 register_manager_dbus (manager);
843 }
844
845+#ifdef HAVE_FCITX
846+static void
847+fcitx_appeared (GDBusConnection *connection,
848+ const gchar *name,
849+ const gchar *name_owner,
850+ gpointer user_data)
851+{
852+ GsdKeyboardManager *manager = user_data;
853+ apply_input_sources_settings (manager->priv->input_sources_settings, NULL, 0, manager);
854+}
855+
856+static void
857+fcitx_vanished (GDBusConnection *connection,
858+ const gchar *name,
859+ gpointer user_data)
860+{
861+ GsdKeyboardManager *manager = user_data;
862+ g_signal_handlers_disconnect_by_data (manager->priv->fcitx, manager);
863+ manager->priv->fcitx_signal_id = 0;
864+}
865+#endif
866+
867 static gboolean
868 start_keyboard_idle_cb (GsdKeyboardManager *manager)
869 {
870+ const gchar *module;
871+ GError *error = NULL;
872+
873 gnome_settings_profile_start (NULL);
874
875 g_debug ("Starting keyboard manager");
876
877+ module = g_getenv (ENV_GTK_IM_MODULE);
878+#ifdef HAVE_IBUS
879+ manager->priv->is_ibus_active = g_strcmp0 (module, GTK_IM_MODULE_IBUS) == 0;
880+#endif
881+#ifdef HAVE_FCITX
882+ manager->priv->is_fcitx_active = g_strcmp0 (module, GTK_IM_MODULE_FCITX) == 0;
883+#endif
884+
885 manager->priv->settings = g_settings_new (GSD_KEYBOARD_DIR);
886
887 xkb_init (manager);
888@@ -1857,6 +2395,38 @@
889 manager->priv->interface_settings = g_settings_new (GNOME_DESKTOP_INTERFACE_DIR);
890 manager->priv->xkb_info = gnome_xkb_info_new ();
891
892+#ifdef HAVE_FCITX
893+ if (manager->priv->is_fcitx_active) {
894+ manager->priv->fcitx_cancellable = g_cancellable_new ();
895+ manager->priv->fcitx = fcitx_input_method_new (G_BUS_TYPE_SESSION,
896+ G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
897+ 0,
898+ manager->priv->fcitx_cancellable,
899+ &error);
900+ g_clear_object (&manager->priv->fcitx_cancellable);
901+
902+ if (manager->priv->fcitx) {
903+ manager->priv->fcitx_signal_id = 0;
904+
905+ g_bus_watch_name (G_BUS_TYPE_SESSION,
906+ "org.fcitx.Fcitx",
907+ G_BUS_NAME_WATCHER_FLAGS_NONE,
908+ fcitx_appeared,
909+ fcitx_vanished,
910+ manager,
911+ NULL);
912+
913+ if (should_migrate ("fcitx-engines-migrated"))
914+ migrate_fcitx_engines (manager);
915+ else
916+ enable_fcitx_engines (manager, FALSE);
917+ } else {
918+ g_warning ("Fcitx input method framework unavailable: %s", error->message);
919+ g_error_free (error);
920+ }
921+ }
922+#endif
923+
924 manager->priv->cancellable = g_cancellable_new ();
925
926 g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
927@@ -1933,8 +2503,21 @@
928 g_clear_object (&p->xkb_info);
929 g_clear_object (&p->localed);
930
931+#ifdef HAVE_FCITX
932+ if (p->is_fcitx_active) {
933+ if (p->fcitx_cancellable) {
934+ g_cancellable_cancel (p->fcitx_cancellable);
935+ }
936+
937+ g_clear_object (&p->fcitx_cancellable);
938+ g_clear_object (&p->fcitx);
939+ }
940+#endif
941+
942 #ifdef HAVE_IBUS
943- clear_ibus (manager);
944+ if (p->is_ibus_active) {
945+ clear_ibus (manager);
946+ }
947 #endif
948
949 if (p->device_manager != NULL) {
950
951=== added file 'plugins/keyboard/input-method-engines.gperf'
952--- plugins/keyboard/input-method-engines.gperf 1970-01-01 00:00:00 +0000
953+++ plugins/keyboard/input-method-engines.gperf 2015-02-12 15:57:03 +0000
954@@ -0,0 +1,203 @@
955+%pic
956+%struct-type
957+%readonly-tables
958+%define slot-name ibus_engine
959+%define hash-function-name ibus_engine_hash
960+%define lookup-function-name get_engine_for_ibus_engine
961+struct Engine { int ibus_engine; const char *fcitx_engine; };
962+%%
963+Unikey, "unikey"
964+anthy, "anthy"
965+array, "array30"
966+array30, "array30"
967+array30-big, "array30-big"
968+bopomofo, "zhuyin-libpinyin"
969+cangjie, "cangjie3"
970+cangjie-big, "cangjie-big"
971+cangjie3, "cangjie3"
972+cangjie5, "cangjie5"
973+cantonese, "cantonese"
974+cantonhk, "cantonhk"
975+chewing, "chewing"
976+cns11643, "cns11643"
977+compose, "compose"
978+easy-big, "easy-big"
979+emoji-table, "emoji"
980+erbi, "erbi"
981+erbi-qs, "erbi"
982+googlepinyin, "googlepinyin"
983+hangul, "hangul"
984+# input-pad, NULL
985+ipa-x-sampa, "ipa-x-sampa"
986+jyutping, "jyutping"
987+latex, "latex"
988+libbopomofo, "zhuyin-libpinyin"
989+libpinyin, "pinyin-libpinyin"
990+libthai, "thai"
991+m17n:am:sera, "m17n_am_sera"
992+m17n:ar:kbd, "arabic"
993+m17n:as:inscript, "m17n_as_inscript"
994+m17n:as:itrans, "m17n_as_itrans"
995+m17n:as:phonetic, "m17n_as_phonetic"
996+m17n:ath:phonetic, "m17n_ath_phonetic"
997+m17n:be:kbd, "fcitx-keyboard-by"
998+m17n:bla:phonetic, "m17n_bla_phonetic"
999+m17n:bn:disha, "m17n_bn_disha"
1000+m17n:bn:inscript, "m17n_bn_inscript"
1001+m17n:bn:itrans, "m17n_bn_itrans"
1002+m17n:bn:probhat, "m17n_bn_probhat"
1003+m17n:bn:unijoy, "m17n_bn_unijoy"
1004+m17n:bo:ewts, "m17n_bo_ewts"
1005+m17n:bo:tcrc, "m17n_bo_tcrc"
1006+m17n:bo:wylie, "m17n_bo_wylie"
1007+# m17n:cmc:kbd, NULL
1008+m17n:cr:western, "m17n_cr_western"
1009+m17n:cs:kbd, "fcitx-keyboard-cz-qwerty_bksl"
1010+m17n:da:post, "m17n_da_post"
1011+m17n:dv:phonetic, "m17n_dv_phonetic"
1012+m17n:el:kbd, "fcitx-keyboard-gr-simple"
1013+m17n:eo:h-fundamente, "m17n_eo_h-fundamente"
1014+m17n:eo:h-sistemo, "m17n_eo_h-sistemo"
1015+m17n:eo:plena, "m17n_eo_plena"
1016+m17n:eo:q-sistemo, "m17n_eo_q-sistemo"
1017+m17n:eo:vi-sistemo, "m17n_eo_vi-sistemo"
1018+m17n:eo:x-sistemo, "m17n_eo_x-sistemo"
1019+m17n:fa:isiri, "m17n_fa_isiri"
1020+m17n:fr:azerty, "m17n_fr_azerty"
1021+m17n:grc:mizuochi, "m17n_grc_mizuochi"
1022+m17n:gu:inscript, "m17n_gu_inscript"
1023+m17n:gu:itrans, "m17n_gu_itrans"
1024+m17n:gu:phonetic, "m17n_gu_phonetic"
1025+m17n:he:kbd, "fcitx-keyboard-il"
1026+m17n:hi:inscript, "m17n_hi_inscript"
1027+m17n:hi:itrans, "m17n_hi_itrans"
1028+m17n:hi:phonetic, "m17n_hi_phonetic"
1029+m17n:hi:remington, "m17n_hi_remington"
1030+m17n:hi:typewriter, "m17n_hi_typewriter"
1031+m17n:hi:vedmata, "m17n_hi_vedmata"
1032+m17n:hr:kbd, "fcitx-keyboard-hr"
1033+m17n:hy:kbd, "fcitx-keyboard-am-eastern-alt"
1034+m17n:ii:phonetic, "m17n_ii_phonetic"
1035+m17n:iu:phonetic, "m17n_iu_phonetic"
1036+m17n:ja:tcode, "m17n_ja_tcode"
1037+m17n:ja:trycode, "m17n_ja_trycode"
1038+m17n:ka:kbd, "fcitx-keyboard-ge"
1039+m17n:kk:arabic, "m17n_kk_arabic"
1040+m17n:kk:kbd, "fcitx-keyboard-kz"
1041+m17n:km:yannis, "m17n_km_yannis"
1042+m17n:kn:inscript, "m17n_kn_inscript"
1043+m17n:kn:itrans, "m17n_kn_itrans"
1044+m17n:kn:kgp, "m17n_kn_kgp"
1045+m17n:kn:typewriter, "m17n_kn_typewriter"
1046+# m17n:ko:han2, NULL
1047+# m17n:ko:romaja, NULL
1048+m17n:ks:inscript, "m17n_ks_inscript"
1049+m17n:ks:kbd, "m17n_ks_kbd"
1050+m17n:lo:kbd, "fcitx-keyboard-la-stea"
1051+m17n:lo:lrt, "m17n_lo_lrt"
1052+m17n:mai:inscript, "m17n_mai_inscript"
1053+m17n:ml:inscript, "m17n_ml_inscript"
1054+m17n:ml:itrans, "m17n_ml_itrans"
1055+m17n:ml:mozhi, "m17n_ml_mozhi"
1056+m17n:ml:remington, "m17n_ml_remington"
1057+m17n:ml:swanalekha, "m17n_ml_swanalekha"
1058+m17n:mr:inscript, "m17n_mr_inscript"
1059+m17n:mr:itrans, "m17n_mr_itrans"
1060+m17n:mr:phonetic, "m17n_mr_phonetic"
1061+m17n:my:kbd, "fcitx-keyboard-mm"
1062+m17n:ne:rom, "m17n_ne_rom"
1063+m17n:ne:trad, "m17n_ne_trad"
1064+m17n:nsk:phonetic, "m17n_nsk_phonetic"
1065+m17n:oj:phonetic, "m17n_oj_phonetic"
1066+m17n:or:inscript, "m17n_or_inscript"
1067+m17n:or:itrans, "m17n_or_itrans"
1068+m17n:or:phonetic, "m17n_or_phonetic"
1069+m17n:pa:anmollipi, "m17n_pa_anmollipi"
1070+m17n:pa:inscript, "m17n_pa_inscript"
1071+m17n:pa:itrans, "m17n_pa_itrans"
1072+m17n:pa:jhelum, "m17n_pa_jhelum"
1073+m17n:pa:phonetic, "m17n_pa_phonetic"
1074+m17n:ps:phonetic, "m17n_ps_phonetic"
1075+m17n:ru:kbd, "fcitx-keyboard-ru"
1076+m17n:ru:phonetic, "m17n_ru_phonetic"
1077+m17n:ru:translit, "m17n_ru_translit"
1078+m17n:ru:yawerty, "m17n_ru_yawerty"
1079+m17n:sa:IAST, "m17n_sa_IAST"
1080+m17n:sa:harvard-kyoto, "m17n_sa_harvard-kyoto"
1081+m17n:sa:itrans, "m17n_sa_itrans"
1082+m17n:sd:inscript, "m17n_sd_inscript"
1083+m17n:si:phonetic-dynamic, "m17n_si_phonetic-dynamic"
1084+m17n:si:samanala, "m17n_si_samanala"
1085+m17n:si:singlish, "m17n_si_singlish"
1086+m17n:si:sumihiri, "m17n_si_sumihiri"
1087+m17n:si:transliteration, "m17n_si_transliteration"
1088+m17n:si:wijesekera, "m17n_si_wijesekera"
1089+m17n:sk:kbd, "fcitx-keyboard-sk"
1090+m17n:sr:kbd, "fcitx-keyboard-rs"
1091+m17n:sv:post, "m17n_sv_post"
1092+m17n:t:latn-post, "m17n_t_latn-post"
1093+m17n:t:latn-pre, "m17n_t_latn-pre"
1094+m17n:t:math-latex, "m17n_t_math-latex"
1095+m17n:t:rfc1345, "m17n_t_rfc1345"
1096+m17n:t:syrc-phonetic, "m17n_t_syrc-phonetic"
1097+m17n:t:unicode, "m17n_t_unicode"
1098+m17n:ta:inscript, "m17n_ta_inscript"
1099+m17n:ta:itrans, "m17n_ta_itrans"
1100+m17n:ta:lk-renganathan, "m17n_ta_lk-renganathan"
1101+m17n:ta:phonetic, "m17n_ta_phonetic"
1102+m17n:ta:tamil99, "m17n_ta_tamil99"
1103+m17n:ta:typewriter, "m17n_ta_typewriter"
1104+m17n:ta:vutam, "m17n_ta_vutam"
1105+m17n:tai:sonla-kbd, "m17n_tai_sonla-kbd"
1106+m17n:te:apple, "m17n_te_apple"
1107+m17n:te:inscript, "m17n_te_inscript"
1108+m17n:te:itrans, "m17n_te_itrans"
1109+m17n:te:pothana, "m17n_te_pothana"
1110+m17n:te:rts, "m17n_te_rts"
1111+m17n:te:sarala, "m17n_te_sarala"
1112+m17n:th:kesmanee, "m17n_th_kesmanee"
1113+m17n:th:pattachote, "m17n_th_pattachote"
1114+m17n:th:tis820, "m17n_th_tis820"
1115+m17n:ua:kbd, "fcitx-keyboard-ua"
1116+m17n:ug:kbd, "fcitx-keyboard-cn-ug"
1117+m17n:ur:phonetic, "m17n_ur_phonetic"
1118+m17n:uz:kbd, "fcitx-keyboard-uz"
1119+m17n:vi:han, "m17n_vi_han"
1120+m17n:vi:nomtelex, "m17n_vi_nomtelex"
1121+m17n:vi:nomvni, "m17n_vi_nomvni"
1122+m17n:vi:tcvn, "m17n_vi_tcvn"
1123+m17n:vi:telex, "m17n_vi_telex"
1124+m17n:vi:viqr, "m17n_vi_viqr"
1125+m17n:vi:vni, "m17n_vi_vni"
1126+m17n:yi:yivo, "m17n_yi_yivo"
1127+m17n:zh:bopomofo, "m17n_zh_bopomofo"
1128+m17n:zh:cangjie, "cangjie3"
1129+m17n:zh:pinyin, "m17n_zh_pinyin"
1130+m17n:zh:pinyin-vi, "m17n_zh_pinyin-vi"
1131+# m17n:zh:py, NULL
1132+m17n:zh:quick, "quick3"
1133+# m17n:zh:tonepy, NULL
1134+mozc-jp, "mozc"
1135+pinyin, "pinyin"
1136+quick, "quick3"
1137+quick-classic, "quick-classic"
1138+quick3, "quick3"
1139+quick5, "quick5"
1140+rime, "rime"
1141+rustrad, "rustrad"
1142+scj6, "scj6"
1143+skk, "skk"
1144+stroke5, "stroke5"
1145+sunpinyin, "sunpinyin"
1146+# tegaki, NULL
1147+thai, "thai"
1148+translit, "translit"
1149+translit-ua, "translit-ua"
1150+viqr, "viqr"
1151+wu, "wu"
1152+wubi-haifeng86, "wubi"
1153+wubi-jidian86, "wubi"
1154+# xkbc, NULL
1155+yawerty, "yawerty"
1156+# yong, NULL
1157+%%
1158
1159=== modified file 'plugins/media-keys/gsd-media-keys-manager.c'
1160--- plugins/media-keys/gsd-media-keys-manager.c 2014-12-03 02:42:39 +0000
1161+++ plugins/media-keys/gsd-media-keys-manager.c 2015-02-12 15:57:03 +0000
1162@@ -67,6 +67,10 @@
1163
1164 #include <libnotify/notify.h>
1165
1166+#ifdef HAVE_FCITX
1167+#include <fcitx-gclient/fcitxinputmethod.h>
1168+#endif
1169+
1170 #define GSD_MEDIA_KEYS_DBUS_PATH GSD_DBUS_PATH "/MediaKeys"
1171 #define GSD_MEDIA_KEYS_DBUS_NAME GSD_DBUS_NAME ".MediaKeys"
1172
1173@@ -116,10 +120,20 @@
1174
1175 #define VOLUME_STEP 6 /* percents for one volume button press */
1176
1177+#define ENV_GTK_IM_MODULE "GTK_IM_MODULE"
1178+#define GTK_IM_MODULE_IBUS "ibus"
1179+#define GTK_IM_MODULE_FCITX "fcitx"
1180+
1181 #define GNOME_DESKTOP_INPUT_SOURCES_DIR "org.gnome.desktop.input-sources"
1182 #define KEY_CURRENT_INPUT_SOURCE "current"
1183 #define KEY_INPUT_SOURCES "sources"
1184
1185+#define INPUT_SOURCE_TYPE_XKB "xkb"
1186+#define INPUT_SOURCE_TYPE_IBUS "ibus"
1187+#define INPUT_SOURCE_TYPE_FCITX "fcitx"
1188+
1189+#define FCITX_XKB_PREFIX "fcitx-keyboard-"
1190+
1191 #define SYSTEMD_DBUS_NAME "org.freedesktop.login1"
1192 #define SYSTEMD_DBUS_PATH "/org/freedesktop/login1"
1193 #define SYSTEMD_DBUS_INTERFACE "org.freedesktop.login1.Manager"
1194@@ -218,6 +232,13 @@
1195 guint panel_name_owner_id;
1196 guint have_legacy_keygrabber;
1197
1198+#ifdef HAVE_FCITX
1199+ FcitxInputMethod *fcitx;
1200+#endif
1201+
1202+ gboolean is_ibus_active;
1203+ gboolean is_fcitx_active;
1204+
1205 /* What did you plug in dialog */
1206 pa_backend *wdypi_pa_backend;
1207 };
1208@@ -2131,16 +2152,53 @@
1209
1210 }
1211
1212+#ifdef HAVE_FCITX
1213+static gchar *
1214+get_fcitx_name (const gchar *name)
1215+{
1216+ gchar *fcitx_name = g_strdup (name);
1217+ gchar *separator = strchr (fcitx_name, '+');
1218+
1219+ if (separator)
1220+ *separator = '-';
1221+
1222+ return fcitx_name;
1223+}
1224+
1225+static gboolean
1226+input_source_is_fcitx_engine (const gchar *type,
1227+ const gchar *name,
1228+ const gchar *engine)
1229+{
1230+ if (g_str_equal (type, INPUT_SOURCE_TYPE_XKB)) {
1231+ if (g_str_has_prefix (engine, FCITX_XKB_PREFIX)) {
1232+ gboolean equal;
1233+ gchar *fcitx_name = get_fcitx_name (name);
1234+ equal = g_str_equal (fcitx_name, engine + strlen (FCITX_XKB_PREFIX));
1235+ g_free (fcitx_name);
1236+ return equal;
1237+ }
1238+ } else if (g_str_equal (type, INPUT_SOURCE_TYPE_FCITX)) {
1239+ return g_str_equal (name, engine);
1240+ }
1241+
1242+ return FALSE;
1243+}
1244+#endif
1245+
1246 static void
1247 do_switch_input_source_action (GsdMediaKeysManager *manager,
1248 MediaKeyType type)
1249 {
1250+ GsdMediaKeysManagerPrivate *priv = manager->priv;
1251 GSettings *settings;
1252 GVariant *sources;
1253+ const gchar *source_type;
1254+ guint first;
1255 gint i, n;
1256
1257 if (g_strcmp0 (g_getenv ("DESKTOP_SESSION"), "ubuntu") != 0)
1258- if (!manager->priv->have_legacy_keygrabber)
1259+ if (!priv->have_legacy_keygrabber)
1260 return;
1261
1262 settings = g_settings_new (GNOME_DESKTOP_INPUT_SOURCES_DIR);
1263@@ -2150,19 +2208,52 @@
1264 if (n < 2)
1265 goto out;
1266
1267- i = g_settings_get_uint (settings, KEY_CURRENT_INPUT_SOURCE);
1268-
1269- if (type == SWITCH_INPUT_SOURCE_KEY)
1270- i += 1;
1271- else
1272- i -= 1;
1273+ i = -1;
1274+
1275+#ifdef HAVE_FCITX
1276+ if (priv->is_fcitx_active && priv->fcitx) {
1277+ gchar *engine = fcitx_input_method_get_current_im (priv->fcitx);
1278+
1279+ if (engine) {
1280+ GVariantIter iter;
1281+ const gchar *source_name;
1282+
1283+ g_variant_iter_init (&iter, sources);
1284+ for (i = 0; g_variant_iter_next (&iter, "(&s&s)", &source_type, &source_name); i++) {
1285+ if (input_source_is_fcitx_engine (source_type, source_name, engine)) {
1286+ break;
1287+ }
1288+ }
1289+
1290+ if (i >= g_variant_n_children (sources))
1291+ i = -1;
1292+
1293+ g_free (engine);
1294+ }
1295+ }
1296+#endif
1297
1298 if (i < 0)
1299- i = n - 1;
1300- else if (i >= n)
1301- i = 0;
1302-
1303- g_settings_set_uint (settings, KEY_CURRENT_INPUT_SOURCE, i);
1304+ i = g_settings_get_uint (settings, KEY_CURRENT_INPUT_SOURCE);
1305+
1306+ first = i;
1307+
1308+ if (type == SWITCH_INPUT_SOURCE_KEY) {
1309+ do {
1310+ i = (i + 1) % n;
1311+ g_variant_get_child (sources, i, "(&s&s)", &source_type, NULL);
1312+ } while (i != first && ((g_str_equal (source_type, INPUT_SOURCE_TYPE_IBUS) && !priv->is_ibus_active) ||
1313+ (g_str_equal (source_type, INPUT_SOURCE_TYPE_FCITX) && !priv->is_fcitx_active)));
1314+ } else {
1315+ do {
1316+ i = (i + n - 1) % n;
1317+ g_variant_get_child (sources, i, "(&s&s)", &source_type, NULL);
1318+ } while (i != first && ((g_str_equal (source_type, INPUT_SOURCE_TYPE_IBUS) && !priv->is_ibus_active) ||
1319+ (g_str_equal (source_type, INPUT_SOURCE_TYPE_FCITX) && !priv->is_fcitx_active)));
1320+ }
1321+
1322+ if (i != first)
1323+ g_settings_set_uint (settings, KEY_CURRENT_INPUT_SOURCE, i);
1324
1325 out:
1326 g_variant_unref (sources);
1327@@ -2931,11 +3022,35 @@
1328 static gboolean
1329 start_media_keys_idle_cb (GsdMediaKeysManager *manager)
1330 {
1331+ const gchar *module;
1332 char *theme_name;
1333
1334 g_debug ("Starting media_keys manager");
1335 gnome_settings_profile_start (NULL);
1336
1337+ module = g_getenv (ENV_GTK_IM_MODULE);
1338+#ifdef HAVE_IBUS
1339+ manager->priv->is_ibus_active = g_strcmp0 (module, GTK_IM_MODULE_IBUS) == 0;
1340+#endif
1341+#ifdef HAVE_FCITX
1342+ manager->priv->is_fcitx_active = g_strcmp0 (module, GTK_IM_MODULE_FCITX) == 0;
1343+
1344+ if (manager->priv->is_fcitx_active) {
1345+ GError *error = NULL;
1346+
1347+ manager->priv->fcitx = fcitx_input_method_new (G_BUS_TYPE_SESSION,
1348+ G_DBUS_PROXY_FLAGS_NONE,
1349+ 0,
1350+ NULL,
1351+ &error);
1352+
1353+ if (!manager->priv->fcitx) {
1354+ g_warning ("Fcitx connection unavailable: %s", error->message);
1355+ g_error_free (error);
1356+ }
1357+ }
1358+#endif
1359+
1360 manager->priv->keys = g_ptr_array_new_with_free_func ((GDestroyNotify) media_key_free);
1361
1362 initialize_volume_handler (manager);

Subscribers

People subscribed via source and target branches