aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore19
-rw-r--r--configure.ac4
-rw-r--r--debian/control1
-rw-r--r--deps/Fcitx-1.0.metadata7
-rw-r--r--deps/README47
-rw-r--r--deps/fcitx.vapi98
-rw-r--r--lib/Makefile.am3
-rw-r--r--lib/indicator-menu.vala77
-rw-r--r--lib/main.vala236
-rw-r--r--lib/source.vala141
-rw-r--r--tests/indicator-keyboard-test.in1
11 files changed, 491 insertions, 143 deletions
diff --git a/.bzrignore b/.bzrignore
index d1af5121..f59e91ad 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -10,15 +10,19 @@
.timestamp
Makefile
Makefile.in
+aclocal.m4
autom4te.cache
build-aux
config.log
config.status
configure
data/com.canonical.indicator.keyboard
+data/gschemas.compiled
data/indicator-keyboard-icon-generator
+data/indicator-keyboard.conf
+data/indicator-keyboard.desktop
data/indicator-keyboard.service
-data/gschemas.compiled
+data/upstart/indicator-keyboard.desktop
debian/autoreconf.after
debian/autoreconf.before
debian/files
@@ -26,6 +30,12 @@ debian/indicator-keyboard
debian/tmp
lib/indicator-keyboard-service
libtool
+m4/intltool.m4
+m4/libtool.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+m4/lt~obsolete.m4
po/POTFILES
po/stamp-it
tests/config.vala
@@ -35,10 +45,3 @@ tests/indicator-keyboard-test
tests/indicator-keyboard-test.trs
tests/indicator-keyboard-tests
tests/services/indicator-keyboard.service
-aclocal.m4
-m4/intltool.m4
-m4/libtool.m4
-m4/lt~obsolete.m4
-m4/ltoptions.m4
-m4/ltsugar.m4
-m4/ltversion.m4
diff --git a/configure.ac b/configure.ac
index 5c09f8fc..dc90e15d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -70,6 +70,10 @@ PKG_CHECK_MODULES([IBUS], [ibus-1.0])
AC_SUBST([IBUS_CFLAGS])
AC_SUBST([IBUS_LIBS])
+PKG_CHECK_MODULES([FCITX_GCLIENT], [fcitx-gclient])
+AC_SUBST([FCITX_GCLIENT_CFLAGS])
+AC_SUBST([FCITX_GCLIENT_LIBS])
+
PKG_CHECK_MODULES([ACCOUNTSSERVICE], [accountsservice])
AC_SUBST([ACCOUNTSSERVICE_CFLAGS])
AC_SUBST([ACCOUNTSSERVICE_LIBS])
diff --git a/debian/control b/debian/control
index 585af9c5..a359f3d9 100644
--- a/debian/control
+++ b/debian/control
@@ -7,6 +7,7 @@ Build-Depends: debhelper (>= 9.0.0),
dh-autoreconf,
dh-translations,
dbus,
+ fcitx-libs-dev (>= 1:4.2.8.3),
libaccountsservice-dev,
libgee-dev,
libgirepository1.0-dev,
diff --git a/deps/Fcitx-1.0.metadata b/deps/Fcitx-1.0.metadata
new file mode 100644
index 00000000..81c20f3c
--- /dev/null
+++ b/deps/Fcitx-1.0.metadata
@@ -0,0 +1,7 @@
+Client cheader_filename="fcitx-gclient/fcitxclient.h"
+Connection cheader_filename="fcitx-gclient/fcitxconnection.h"
+IMItem cheader_filename="fcitx-gclient/fcitxinputmethod.h"
+InputMethod cheader_filename="fcitx-gclient/fcitxinputmethod.h"
+Kbd cheader_filename="fcitx-gclient/fcitxkbd.h"
+LayoutItem cheader_filename="fcitx-gclient/fcitxkbd.h"
+PreeditItem cheader_filename="fcitx-gclient/fcitxclient.h"
diff --git a/deps/README b/deps/README
new file mode 100644
index 00000000..c3666140
--- /dev/null
+++ b/deps/README
@@ -0,0 +1,47 @@
+To generate fontconfig.vapi:
+
+vapigen --library fontconfig /path/to/fontconfig-2.0.gir
+
+To generate freetype2.vapi:
+
+vapigen --library freetype2 /path/to/freetype2-2.0.gir
+
+To generate pangoft2.vapi:
+
+vapigen --library pangoft2 /path/to/PangoFT2-1.0.gir
+
+To generate gnome-desktop-3.0.vapi:
+
+vapigen --pkg gio-2.0 --pkg gtk+-3.0 --library gnome-desktop-3.0 /path/to/GnomeDesktop-3.0.gir
+
+To generate gnome-desktop-3.0.vapi docs:
+
+valadoc --vapidir /path/to/vapi/dir --pkg gdk-3.0 -o gnome-desktop-3.0 gnome-desktop-3.0.vapi
+
+To generate libxklavier.vapi:
+
+vapigen --metadatadir . --pkg x11 --library libxklavier /path/to/Xkl-1.0.gir
+
+To generate libxklavier.vapi docs:
+
+valadoc --vapidir /path/to/vapi/dir --pkg x11 -o libxklavier libxklavier.vapi
+
+To generate libgnomekbd.vapi:
+
+vapigen --metadatadir . --pkg gtk+-3.0 --library libgnomekbd /path/to/Gkbd-3.0.gir
+
+To generate libgnomekbd.vapi docs:
+
+valadoc --metadatadir . --vapidir /path/to/vapi/dir --pkg gtk+-3.0 --pkg Xkl-1.0 -o libgnomekbd libgnomekbd.vapi
+
+To generate ibus-1.0.vapi docs:
+
+valadoc --vapidir /path/to/vapi/dir -o ibus-1.0 /path/to/ibus-1.0.vapi
+
+To generate fcitx.vapi:
+
+vapigen --metadatadir . --pkg gio-2.0 --library fcitx /path/to/Fcitx-1.0.gir
+
+To generate libbamf3.vapi:
+
+vapigen --library libbamf3 /path/to/Bamf-3.gir
diff --git a/deps/fcitx.vapi b/deps/fcitx.vapi
new file mode 100644
index 00000000..70ce5849
--- /dev/null
+++ b/deps/fcitx.vapi
@@ -0,0 +1,98 @@
+/* fcitx.vapi generated by vapigen, do not modify. */
+
+[CCode (cprefix = "Fcitx", gir_namespace = "Fcitx", gir_version = "1.0", lower_case_cprefix = "fcitx_")]
+namespace Fcitx {
+ [CCode (cheader_filename = "fcitx-gclient/fcitxclient.h", type_id = "fcitx_client_get_type ()")]
+ public class Client : GLib.Object {
+ [CCode (has_construct_function = false)]
+ public Client ();
+ public void close_ic ();
+ public void enable_ic ();
+ public void focus_in ();
+ public void focus_out ();
+ public bool is_valid ();
+ [Deprecated]
+ public async int process_key (uint32 keyval, uint32 keycode, uint32 state, int type, uint32 t);
+ public async int process_key_async (uint32 keyval, uint32 keycode, uint32 state, int type, uint32 t, int timeout_msec, GLib.Cancellable? cancellable);
+ public int process_key_sync (uint32 keyval, uint32 keycode, uint32 state, int type, uint32 t);
+ public void reset ();
+ public void set_capacity (uint flags);
+ public void set_cursor_rect (int x, int y, int w, int h);
+ [Deprecated]
+ public void set_cusor_rect (int x, int y, int w, int h);
+ public void set_surrounding_text (string? text, uint cursor, uint anchor);
+ public signal void close_im ();
+ public signal void commit_string (string string);
+ public signal void connected ();
+ public signal void delete_surrounding_text (int cursor, uint len);
+ public signal void disconnected ();
+ public signal void enable_im ();
+ public signal void forward_key (uint keyval, int state, int type);
+ public signal void update_client_side_ui (string auxup, string auxdown, string preedit, string candidateword, string imname, int cursor_pos);
+ public signal void update_formatted_preedit (GLib.GenericArray<Fcitx.PreeditItem> preedit, int cursor);
+ }
+ [CCode (cheader_filename = "fcitx-gclient/fcitxconnection.h", type_id = "fcitx_connection_get_type ()")]
+ public class Connection : GLib.Object {
+ [CCode (has_construct_function = false)]
+ public Connection ();
+ public unowned GLib.DBusConnection get_g_dbus_connection ();
+ public bool is_valid ();
+ public signal void connected ();
+ public signal void disconnected ();
+ }
+ [CCode (cheader_filename = "fcitx-gclient/fcitxinputmethod.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "fcitx_im_item_get_type ()")]
+ [Compact]
+ public class IMItem {
+ public bool enable;
+ public weak string langcode;
+ public weak string name;
+ public weak string unique_name;
+ [CCode (has_construct_function = false)]
+ public IMItem (string name, string unique_name, string langcode, bool enable);
+ }
+ [CCode (cheader_filename = "fcitx-gclient/fcitxinputmethod.h", type_id = "fcitx_input_method_get_type ()")]
+ public class InputMethod : GLib.DBusProxy, GLib.AsyncInitable, GLib.DBusInterface, GLib.Initable {
+ [CCode (has_construct_function = false)]
+ public InputMethod (GLib.BusType bus_type, GLib.DBusProxyFlags flags, int display_number, GLib.Cancellable? cancellable = null) throws GLib.Error;
+ public void activate ();
+ public void configure ();
+ public void configure_addon (string addon);
+ public void configure_im (string imname);
+ public void exit ();
+ public string get_current_im ();
+ public int get_current_state ();
+ public string get_current_ui ();
+ public string get_im_addon (string imname);
+ public GLib.GenericArray<Fcitx.IMItem> get_imlist_nofree ();
+ public void inactivate ();
+ public void reload_config ();
+ public void restart ();
+ public void set_current_im (string imname);
+ public void set_imlist (GLib.GenericArray<Fcitx.IMItem> array);
+ public void toggle ();
+ public string current_im { owned get; set construct; }
+ public signal void imlist_changed ();
+ }
+ [CCode (cheader_filename = "fcitx-gclient/fcitxkbd.h", type_id = "fcitx_kbd_get_type ()")]
+ public class Kbd : GLib.DBusProxy, GLib.AsyncInitable, GLib.DBusInterface, GLib.Initable {
+ [CCode (has_construct_function = false)]
+ public Kbd (GLib.BusType bus_type, GLib.DBusProxyFlags flags, int display_number, GLib.Cancellable? cancellable = null) throws GLib.Error;
+ public void get_layout_for_im (string imname, out string layout, out string variant);
+ public GLib.GenericArray<Fcitx.LayoutItem> get_layouts_nofree ();
+ public void set_default_layout (string layout, string variant);
+ public void set_layout_for_im (string imname, string layout, string variant);
+ }
+ [CCode (cheader_filename = "fcitx-gclient/fcitxkbd.h", copy_function = "g_boxed_copy", free_function = "g_boxed_free", type_id = "fcitx_layout_item_get_type ()")]
+ [Compact]
+ public class LayoutItem {
+ public weak string langcode;
+ public weak string layout;
+ public weak string name;
+ public weak string variant;
+ }
+ [CCode (cheader_filename = "fcitx-gclient/fcitxclient.h", has_type_id = false)]
+ public struct PreeditItem {
+ public weak global::string string;
+ public int32 type;
+ }
+}
diff --git a/lib/Makefile.am b/lib/Makefile.am
index c57725c1..14c8f1ba 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -26,6 +26,7 @@ indicator_keyboard_service_VALAFLAGS = $(AM_VALAFLAGS) \
--pkg Xkl-1.0 \
--pkg Gkbd-3.0 \
--pkg ibus-1.0 \
+ --pkg fcitx \
--pkg accountsservice \
--pkg liblightdm-gobject-1
indicator_keyboard_service_CFLAGS = $(AM_CFLAGS) \
@@ -36,6 +37,7 @@ indicator_keyboard_service_CFLAGS = $(AM_CFLAGS) \
$(LIBXKLAVIER_CFLAGS) \
$(LIBGNOMEKBD_CFLAGS) \
$(IBUS_CFLAGS) \
+ $(FCITX_GCLIENT_CFLAGS) \
$(ACCOUNTSSERVICE_CFLAGS) \
$(LIGHTDM_CFLAGS) \
$(COVERAGE_CFLAGS)
@@ -47,6 +49,7 @@ indicator_keyboard_service_LDFLAGS = $(AM_LDFLAGS) \
$(LIBXKLAVIER_LIBS) \
$(LIBGNOMEKBD_LIBS) \
$(IBUS_LIBS) \
+ $(FCITX_GCLIENT_LIBS) \
$(ACCOUNTSSERVICE_LIBS) \
$(LIGHTDM_LIBS) \
$(COVERAGE_LDFLAGS)
diff --git a/lib/indicator-menu.vala b/lib/indicator-menu.vala
index 8e5661e2..209fcbf1 100644
--- a/lib/indicator-menu.vala
+++ b/lib/indicator-menu.vala
@@ -19,10 +19,12 @@
public class Indicator.Keyboard.IndicatorMenu : MenuModel {
public enum Options {
- NONE = 0x0,
- DCONF = 0x1,
- IBUS = 0x2,
- SETTINGS = 0x4
+ NONE = 0x00,
+ DCONF = 0x01,
+ XKB = 0x02,
+ IBUS = 0x04,
+ FCITX = 0x08,
+ SETTINGS = 0x10
}
private Options options;
@@ -32,42 +34,45 @@ public class Indicator.Keyboard.IndicatorMenu : MenuModel {
private IBusMenu properties_section;
public IndicatorMenu (ActionMap? action_map = null, Options options = Options.NONE) {
- var submenu = new Menu ();
+ this.options = options;
+ indicator_menu = new Menu ();
sources_section = new Menu ();
- submenu.append_section (null, sources_section);
- if ((options & Options.IBUS) != Options.NONE) {
- properties_section = new IBusMenu (action_map);
- properties_section.activate.connect ((property, state) => { activate (property, state); });
- submenu.append_section (null, properties_section);
- }
+ if ((options & ~Options.DCONF) != Options.NONE) {
+ var submenu = new Menu ();
- if ((options & Options.SETTINGS) != Options.NONE) {
- var settings_section = new Menu ();
- settings_section.append (_ ("Character Map"), "indicator.map");
- settings_section.append (_ ("Keyboard Layout Chart"), "indicator.chart");
- settings_section.append (_ ("Text Entry Settings..."), "indicator.settings");
- submenu.append_section (null, settings_section);
- }
+ submenu.append_section (null, sources_section);
- var indicator = new MenuItem.submenu (null, submenu);
- indicator.set_detailed_action ("indicator.indicator");
- indicator.set_attribute ("x-canonical-type", "s", "com.canonical.indicator.root");
-
- /* We need special mouse actions on the lock screen. */
- if ((options & Options.DCONF) != Options.NONE) {
- indicator.set_attribute ("x-canonical-secondary-action", "s", "indicator.next");
- indicator.set_attribute ("x-canonical-scroll-action", "s", "indicator.scroll");
- } else {
- indicator.set_attribute ("x-canonical-secondary-action", "s", "indicator.locked_next");
- indicator.set_attribute ("x-canonical-scroll-action", "s", "indicator.locked_scroll");
- }
+ if ((options & Options.IBUS) != Options.NONE) {
+ properties_section = new IBusMenu (action_map);
+ properties_section.activate.connect ((property, state) => { activate (property, state); });
+ submenu.append_section (null, properties_section);
+ }
- indicator_menu = new Menu ();
- indicator_menu.append_item (indicator);
+ if ((options & Options.SETTINGS) != Options.NONE) {
+ var settings_section = new Menu ();
+ settings_section.append (_ ("Character Map"), "indicator.map");
+ settings_section.append (_ ("Keyboard Layout Chart"), "indicator.chart");
+ settings_section.append (_ ("Text Entry Settings..."), "indicator.settings");
+ submenu.append_section (null, settings_section);
+ }
- this.options = options;
+ var indicator = new MenuItem.submenu (null, submenu);
+ indicator.set_detailed_action ("indicator.indicator");
+ indicator.set_attribute ("x-canonical-type", "s", "com.canonical.indicator.root");
+
+ /* We need special mouse actions on the lock screen. */
+ if ((options & Options.DCONF) != Options.NONE) {
+ indicator.set_attribute ("x-canonical-secondary-action", "s", "indicator.next");
+ indicator.set_attribute ("x-canonical-scroll-action", "s", "indicator.scroll");
+ } else {
+ indicator.set_attribute ("x-canonical-secondary-action", "s", "indicator.locked_next");
+ indicator.set_attribute ("x-canonical-scroll-action", "s", "indicator.locked_scroll");
+ }
+
+ indicator_menu.append_item (indicator);
+ }
}
public signal void activate (IBus.Property property, IBus.PropState state);
@@ -76,7 +81,11 @@ public class Indicator.Keyboard.IndicatorMenu : MenuModel {
sources_section.remove_all ();
for (var i = 0; i < sources.length; i++) {
- if (!sources[i].is_ibus || (options & Options.IBUS) != Options.NONE) {
+ var visible = (sources[i].is_xkb && (options & Options.XKB) != Options.NONE) ||
+ (sources[i].is_ibus && (options & Options.IBUS) != Options.NONE) ||
+ (sources[i].is_fcitx && (options & Options.FCITX) != Options.NONE);
+
+ if (visible) {
string action;
if ((options & Options.DCONF) != Options.NONE) {
diff --git a/lib/main.vala b/lib/main.vala
index 1cb3896c..41ff5ff7 100644
--- a/lib/main.vala
+++ b/lib/main.vala
@@ -33,7 +33,7 @@ public class Indicator.Keyboard.Service : Object {
private SList<Act.User> users;
private WindowStack? window_stack;
- private Gee.HashMap<uint, uint>? window_sources;
+ private Gee.HashMap<uint, Source>? window_sources;
private uint focused_window_id;
private IBus.Bus? ibus;
@@ -41,6 +41,8 @@ public class Indicator.Keyboard.Service : Object {
private ulong ibus_connected_id;
private uint panel_timeout;
+ private Fcitx.InputMethod? fcitx;
+
private Source[]? sources;
private SimpleActionGroup? action_group;
@@ -118,11 +120,13 @@ public class Indicator.Keyboard.Service : Object {
handle_unity_name_appeared,
handle_unity_name_vanished);
- Bus.watch_name (BusType.SESSION,
- "com.canonical.Unity.WindowStack",
- BusNameWatcherFlags.NONE,
- handle_window_stack_name_appeared,
- handle_window_stack_name_vanished);
+ if (!is_fcitx_active ()) {
+ Bus.watch_name (BusType.SESSION,
+ "com.canonical.Unity.WindowStack",
+ BusNameWatcherFlags.NONE,
+ handle_window_stack_name_appeared,
+ handle_window_stack_name_vanished);
+ }
}
indicator_settings = new Settings ("com.canonical.indicator.keyboard");
@@ -146,6 +150,26 @@ public class Indicator.Keyboard.Service : Object {
}
[DBus (visible = false)]
+ private static bool is_ibus_active () {
+ if (is_login_user ()) {
+ return false;
+ }
+
+ var module = Environment.get_variable ("GTK_IM_MODULE");
+ return module != null && (!) module == "ibus";
+ }
+
+ [DBus (visible = false)]
+ private static bool is_fcitx_active () {
+ if (is_login_user ()) {
+ return false;
+ }
+
+ var module = Environment.get_variable ("GTK_IM_MODULE");
+ return module != null && (!) module == "fcitx";
+ }
+
+ [DBus (visible = false)]
private IBus.Bus get_ibus () {
if (ibus == null) {
IBus.init ();
@@ -210,6 +234,20 @@ public class Indicator.Keyboard.Service : Object {
}
[DBus (visible = false)]
+ private Fcitx.InputMethod? get_fcitx () {
+ if (is_fcitx_active () && fcitx == null) {
+ try {
+ fcitx = new Fcitx.InputMethod (BusType.SESSION, DBusProxyFlags.NONE, 0);
+ ((!) fcitx).notify["current-im"].connect ((pspec) => { handle_changed_current ("current"); });
+ } catch (Error error) {
+ warning ("error: %s", error.message);
+ }
+ }
+
+ return fcitx;
+ }
+
+ [DBus (visible = false)]
public void up () {
if (loop == null) {
loop = new MainLoop ();
@@ -254,11 +292,9 @@ public class Indicator.Keyboard.Service : Object {
Act.User? user = manager.get_user ((!) greeter_user);
if (user != null && ((!) user).is_loaded) {
- VariantIter outer;
- VariantIter inner;
+ var outer = ((!) user).input_sources.iterator ();
- var sources = ((!) user).input_sources;
- sources.get ("aa{ss}", out outer);
+ VariantIter inner;
while (outer.next ("a{ss}", out inner)) {
unowned string key;
@@ -340,7 +376,7 @@ public class Indicator.Keyboard.Service : Object {
[DBus (visible = false)]
private void migrate_keyboard_layouts () {
if (is_login_user ()) {
- lightdm_current = source_settings.get_uint ("current");
+ lightdm_current = get_current ();
var manager = Act.UserManager.get_default ();
@@ -448,14 +484,11 @@ public class Indicator.Keyboard.Service : Object {
foreach (var user in users) {
if (user.is_loaded) {
+ var outer = user.input_sources.iterator ();
var done = false;
- VariantIter outer;
VariantIter inner;
- var sources = user.input_sources;
- sources.get ("aa{ss}", out outer);
-
while (outer.next ("a{ss}", out inner)) {
unowned string key;
unowned string source;
@@ -548,7 +581,7 @@ public class Indicator.Keyboard.Service : Object {
private void update_login_layout () {
if (is_login_user ()) {
unowned List<LightDM.Layout> layouts = LightDM.get_layouts ();
- var current = source_settings.get_uint ("current");
+ var current = get_current ();
if (current < get_sources ().length) {
var source = get_sources ()[current];
@@ -594,10 +627,12 @@ public class Indicator.Keyboard.Service : Object {
warning ("error: %s", error.message);
}
- window_sources = new Gee.HashMap<uint, uint> ();
+ window_sources = new Gee.HashMap<uint, Source> ();
+ ((!) window_stack).window_destroyed.connect (handle_window_destroyed);
((!) window_stack).focused_window_changed.connect (handle_focused_window_changed);
} else {
((!) window_stack).focused_window_changed.disconnect (handle_focused_window_changed);
+ ((!) window_stack).window_destroyed.disconnect (handle_window_destroyed);
window_sources = null;
}
}
@@ -610,22 +645,49 @@ public class Indicator.Keyboard.Service : Object {
}
[DBus (visible = false)]
+ private void handle_window_destroyed (uint window_id, string app_id) {
+ ((!) window_sources).unset (window_id);
+ }
+
+ [DBus (visible = false)]
private void handle_focused_window_changed (uint window_id, string app_id, uint stage) {
- var old_current = source_settings.get_uint ("current");
+ var sources = get_sources ();
+ var old_current = get_current ();
- ((!) window_sources)[focused_window_id] = old_current;
+ if (old_current < sources.length) {
+ ((!) window_sources)[focused_window_id] = sources[old_current];
+ }
if (!(((!) window_sources).has_key (window_id))) {
var default_group = per_window_settings.get_int ("default-group");
- if (default_group >= 0 && default_group != old_current) {
- source_settings.set_uint ("current", (uint) default_group);
+ if (default_group >= 0) {
+ for (var offset = 0; offset < sources.length; offset++) {
+ var current = (default_group + offset) % sources.length;
+ var source = sources[current];
+
+ if (source.is_xkb ||
+ (source.is_ibus && is_ibus_active ()) ||
+ (source.is_fcitx && is_fcitx_active ())) {
+ if (current != old_current) {
+ source_settings.set_uint ("current", current);
+ }
+
+ break;
+ }
+ }
}
} else {
- var current = ((!) window_sources)[window_id];
+ var source = ((!) window_sources)[window_id];
- if (current != old_current) {
- source_settings.set_uint ("current", current);
+ for (var current = 0; current < sources.length; current++) {
+ if (sources[current] == source) {
+ if (current != old_current) {
+ source_settings.set_uint ("current", current);
+ }
+
+ break;
+ }
}
}
@@ -633,6 +695,40 @@ public class Indicator.Keyboard.Service : Object {
}
[DBus (visible = false)]
+ private uint get_current () {
+ if (is_fcitx_active () && get_fcitx () != null) {
+ string? engine = ((!) get_fcitx ()).current_im;
+
+ if (engine != null) {
+ var is_xkb = ((!) engine).has_prefix ("fcitx-keyboard-");
+ var type = is_xkb ? "xkb" : "fcitx";
+ var name = (!) engine;
+
+ if (is_xkb) {
+ name = name.substring ("fcitx-keyboard-".length);
+ var index = name.index_of ("-");
+ if (index >= 0) {
+ name.data[index] = '+';
+ }
+ }
+
+ var iter = source_settings.get_value ("sources").iterator ();
+
+ unowned string source_type;
+ unowned string source_name;
+
+ for (var i = 0; iter.next ("(&s&s)", out source_type, out source_name); i++) {
+ if (source_name == name && source_type == type) {
+ return i;
+ }
+ }
+ }
+ }
+
+ return source_settings.get_uint ("current");
+ }
+
+ [DBus (visible = false)]
private Source[] get_sources () {
if (sources == null) {
var array = source_settings.get_value ("sources");
@@ -743,7 +839,7 @@ public class Indicator.Keyboard.Service : Object {
[DBus (visible = false)]
private void update_active_action () {
if (active_action != null) {
- ((!) active_action).set_state (source_settings.get_value ("current"));
+ ((!) active_action).set_state (new Variant.uint32 (get_current ()));
update_indicator_action ();
}
}
@@ -751,8 +847,7 @@ public class Indicator.Keyboard.Service : Object {
[DBus (visible = false)]
private Action get_active_action () {
if (active_action == null) {
- var current = source_settings.get_value ("current");
- active_action = new SimpleAction.stateful ("active", VariantType.UINT32, current);
+ active_action = new SimpleAction.stateful ("active", VariantType.UINT32, new Variant.uint32 (get_current ()));
((!) active_action).activate.connect ((parameter) => { ((!) active_action).change_state (parameter); });
((!) active_action).change_state.connect (handle_changed_active);
}
@@ -768,13 +863,41 @@ public class Indicator.Keyboard.Service : Object {
[DBus (visible = false)]
private void handle_scroll_wheel (Variant? parameter) {
if (parameter != null) {
- var sources = source_settings.get_value ("sources");
- var current = source_settings.get_uint ("current");
- var length = (int) sources.n_children ();
+ var old_current = get_current ();
+ var sources = get_sources ();
+ var length = 0;
- if (length > 0) {
- var offset = ((!) parameter).get_int32 () % length;
- source_settings.set_uint ("current", (current + (length - offset)) % length);
+ foreach (var source in sources) {
+ if (source.is_xkb ||
+ (source.is_ibus && is_ibus_active ()) ||
+ (source.is_fcitx && is_fcitx_active ())) {
+ length++;
+ }
+ }
+
+ if (length > 1) {
+ var current = old_current;
+ var offset = -((!) parameter).get_int32 () % length;
+
+ /* Go backward. */
+ for (; offset < 0; offset++) {
+ do {
+ current = (current + sources.length - 1) % sources.length;
+ } while ((sources[current].is_ibus && !is_ibus_active ()) ||
+ (sources[current].is_fcitx && !is_fcitx_active ()));
+ }
+
+ /* Go forward. */
+ for (; offset > 0; offset--) {
+ do {
+ current = (current + 1) % sources.length;
+ } while ((sources[current].is_ibus && !is_ibus_active ()) ||
+ (sources[current].is_fcitx && !is_fcitx_active ()));
+ }
+
+ if (current != old_current) {
+ source_settings.set_uint ("current", current);
+ }
}
}
}
@@ -788,30 +911,30 @@ public class Indicator.Keyboard.Service : Object {
private void handle_scroll_wheel_when_locked (Variant? parameter) {
if (parameter != null) {
var sources = get_sources ();
- var non_ibus_length = 0;
+ var xkb_length = 0;
- /* Figure out how many non-IBus sources we have. */
+ /* Figure out how many Xkb sources we have. */
foreach (var source in sources) {
- if (!source.is_ibus) {
- non_ibus_length++;
+ if (source.is_xkb) {
+ xkb_length++;
}
}
- if (non_ibus_length > 1) {
+ if (xkb_length > 1) {
var active_action = get_active_action ();
var active = active_action.get_state ().get_uint32 ();
- var offset = -((!) parameter).get_int32 () % non_ibus_length;
+ var offset = -((!) parameter).get_int32 () % xkb_length;
- /* Make offset positive modulo non_ibus_length. */
+ /* Make offset positive modulo xkb_length. */
if (offset < 0) {
- offset += non_ibus_length;
+ offset += xkb_length;
}
- /* We need to cycle through non-IBus sources only. */
+ /* We need to cycle through Xkb sources only. */
while (offset > 0) {
do {
active = (active + 1) % sources.length;
- } while (sources[active].is_ibus);
+ } while (!sources[active].is_xkb);
offset--;
}
@@ -881,9 +1004,15 @@ public class Indicator.Keyboard.Service : Object {
[DBus (visible = false)]
public IndicatorMenu get_desktop_menu () {
if (desktop_menu == null) {
- var options = IndicatorMenu.Options.DCONF
- | IndicatorMenu.Options.IBUS
- | IndicatorMenu.Options.SETTINGS;
+ var options = IndicatorMenu.Options.DCONF;
+
+ if (!is_fcitx_active ()) {
+ options |= IndicatorMenu.Options.XKB | IndicatorMenu.Options.SETTINGS;
+
+ if (is_ibus_active ()) {
+ options |= IndicatorMenu.Options.IBUS;
+ }
+ }
desktop_menu = new IndicatorMenu (get_action_group (), options);
((!) desktop_menu).set_sources (get_sources ());
@@ -906,7 +1035,8 @@ public class Indicator.Keyboard.Service : Object {
[DBus (visible = false)]
public IndicatorMenu get_desktop_greeter_menu () {
if (desktop_greeter_menu == null) {
- var options = IndicatorMenu.Options.DCONF;
+ var options = IndicatorMenu.Options.DCONF |
+ IndicatorMenu.Options.XKB;
desktop_greeter_menu = new IndicatorMenu (get_action_group (), options);
((!) desktop_greeter_menu).set_sources (get_sources ());
@@ -918,7 +1048,7 @@ public class Indicator.Keyboard.Service : Object {
[DBus (visible = false)]
public IndicatorMenu get_desktop_lockscreen_menu () {
if (desktop_lockscreen_menu == null) {
- var options = IndicatorMenu.Options.NONE;
+ var options = IndicatorMenu.Options.XKB;
desktop_lockscreen_menu = new IndicatorMenu (get_action_group (), options);
((!) desktop_lockscreen_menu).set_sources (get_sources ());
@@ -965,7 +1095,7 @@ public class Indicator.Keyboard.Service : Object {
string? variant = null;
var sources = get_sources ();
- var current = source_settings.get_uint ("current");
+ var current = get_current ();
if (current < sources.length) {
layout = sources[current].layout;
@@ -1038,11 +1168,11 @@ public class Indicator.Keyboard.Service : Object {
var sources = get_sources ();
if (sources.length > 0) {
- var current = source_settings.get_uint ("current");
+ var current = get_current ();
- if (current < sources.length && sources[current].is_ibus) {
+ if (current < sources.length && !sources[current].is_xkb) {
for (var i = 0; i < sources.length; i++) {
- if (!sources[i].is_ibus) {
+ if (sources[i].is_xkb) {
get_active_action ().change_state (new Variant.uint32 (i));
break;
}
@@ -1051,7 +1181,7 @@ public class Indicator.Keyboard.Service : Object {
}
});
((!) unity_session).unlocked.connect (() => {
- get_active_action ().change_state (source_settings.get_value ("current"));
+ get_active_action ().change_state (new Variant.uint32 (get_current ()));
});
} catch (IOError error) {
warning ("error: %s", error.message);
diff --git a/lib/source.vala b/lib/source.vala
index 5fe7157d..f73b4b69 100644
--- a/lib/source.vala
+++ b/lib/source.vala
@@ -19,10 +19,12 @@
public class Indicator.Keyboard.Source : Object {
private static Gnome.XkbInfo? xkb_info;
- private static IBus.Bus? bus;
+ private static IBus.Bus? ibus_bus;
+ private static Fcitx.InputMethod? fcitx_proxy;
private string? xkb;
private string? ibus;
+ private string? fcitx;
private string? _name;
private string? _short_name;
@@ -77,6 +79,10 @@ public class Indicator.Keyboard.Source : Object {
get { return ibus != null; }
}
+ public bool is_fcitx {
+ get { return fcitx != null; }
+ }
+
public Source (Variant variant, bool use_gtk = false) {
Object (use_gtk: use_gtk);
@@ -90,19 +96,22 @@ public class Indicator.Keyboard.Source : Object {
xkb = name;
} else if (type == "ibus") {
ibus = name;
+ } else if (type == "fcitx") {
+ fcitx = name;
}
} else if (variant.is_of_type (new VariantType ("a{ss}"))) {
- VariantIter iter;
+ var iter = variant.iterator ();
+
unowned string key;
unowned string value;
- variant.get ("a{ss}", out iter);
-
while (iter.next ("{&s&s}", out key, out value)) {
if (key == "xkb") {
xkb = value;
} else if (key == "ibus") {
ibus = value;
+ } else if (key == "fcitx") {
+ fcitx = value;
}
}
}
@@ -116,13 +125,21 @@ public class Indicator.Keyboard.Source : Object {
return (!) xkb_info;
}
- private static IBus.Bus get_bus () {
- if (bus == null) {
+ private static IBus.Bus get_ibus_bus () {
+ if (ibus_bus == null) {
IBus.init ();
- bus = new IBus.Bus ();
+ ibus_bus = new IBus.Bus ();
}
- return (!) bus;
+ return (!) ibus_bus;
+ }
+
+ private static Fcitx.InputMethod get_fcitx_proxy () throws Error {
+ if (fcitx_proxy == null) {
+ fcitx_proxy = new Fcitx.InputMethod (BusType.SESSION, DBusProxyFlags.NONE, 0);
+ }
+
+ return (!) fcitx_proxy;
}
private IBus.EngineDesc? get_engine () {
@@ -132,7 +149,7 @@ public class Indicator.Keyboard.Source : Object {
var names = new string[2];
names[0] = (!) ibus;
- var engines = get_bus ().get_engines_by_names (names);
+ var engines = get_ibus_bus ().get_engines_by_names (names);
if (engines.length > 0) {
engine = engines[0];
@@ -145,31 +162,7 @@ public class Indicator.Keyboard.Source : Object {
protected virtual string? _get_name () {
string? name = null;
- var engine = get_engine ();
-
- if (engine != null) {
- string? language = ((!) engine).get_language ();
- string? display_name = ((!) engine).get_longname ();
- var has_language = language != null && ((!) language).get_char () != '\0';
- var has_display_name = display_name != null && ((!) display_name).get_char () != '\0';
-
- if (has_language) {
- language = Xkl.get_language_name ((!) language);
- has_language = language != null && ((!) language).get_char () != '\0';
- }
-
- if (has_language && has_display_name) {
- name = @"$((!) language) ($((!) display_name))";
- } else if (has_language) {
- name = language;
- } else if (has_display_name) {
- name = display_name;
- }
- }
-
- var has_name = name != null && ((!) name).get_char () != '\0';
-
- if (!has_name && xkb != null) {
+ if (xkb != null) {
string? display_name = null;
string? layout = null;
@@ -194,14 +187,53 @@ public class Indicator.Keyboard.Source : Object {
name = country;
}
}
- }
- if (name == null || ((!) name).get_char () == '\0') {
- if (ibus != null) {
- name = ibus;
- } else if (xkb != null) {
+ if (name == null || ((!) name).get_char () == '\0') {
name = xkb;
}
+ } else if (ibus != null) {
+ var engine = get_engine ();
+
+ if (engine != null) {
+ string? language = ((!) engine).get_language ();
+ string? display_name = ((!) engine).get_longname ();
+ var has_language = language != null && ((!) language).get_char () != '\0';
+ var has_display_name = display_name != null && ((!) display_name).get_char () != '\0';
+
+ if (has_language) {
+ language = Xkl.get_language_name ((!) language);
+ has_language = language != null && ((!) language).get_char () != '\0';
+ }
+
+ if (has_language && has_display_name) {
+ name = @"$((!) language) ($((!) display_name))";
+ } else if (has_language) {
+ name = language;
+ } else if (has_display_name) {
+ name = display_name;
+ }
+ }
+
+ if (name == null || ((!) name).get_char () == '\0') {
+ name = ibus;
+ }
+ } else if (fcitx != null) {
+ try {
+ var input_methods = get_fcitx_proxy ().get_imlist_nofree ();
+
+ for (var i = 0; i < input_methods.length; i++) {
+ if (input_methods.get (i).unique_name == (!) fcitx) {
+ name = input_methods.get (i).name;
+ break;
+ }
+ }
+ } catch (Error error) {
+ warning ("error: %s", error.message);
+ }
+
+ if (name == null || ((!) name).get_char () == '\0') {
+ name = fcitx;
+ }
}
return name;
@@ -212,23 +244,36 @@ public class Indicator.Keyboard.Source : Object {
if (xkb != null) {
get_xkb_info ().get_layout_info ((!) xkb, null, out short_name, null, null);
- }
- var has_short_name = short_name != null && ((!) short_name).get_char () != '\0';
-
- if (!has_short_name) {
+ if (short_name == null || ((!) short_name).get_char () == '\0') {
+ short_name = xkb;
+ }
+ } else if (ibus != null) {
var engine = get_engine ();
if (engine != null) {
short_name = ((!) engine).get_name ();
}
- }
- if (short_name == null || ((!) short_name).get_char () == '\0') {
- if (ibus != null) {
+ if (short_name == null || ((!) short_name).get_char () == '\0') {
short_name = ibus;
- } else if (xkb != null) {
- short_name = xkb;
+ }
+ } else if (fcitx != null) {
+ try {
+ var input_methods = get_fcitx_proxy ().get_imlist_nofree ();
+
+ for (var i = 0; i < input_methods.length; i++) {
+ if (input_methods.get (i).unique_name == (!) fcitx) {
+ short_name = input_methods.get (i).langcode;
+ break;
+ }
+ }
+ } catch (Error error) {
+ warning ("error: %s", error.message);
+ }
+
+ if (short_name == null || ((!) short_name).get_char () == '\0') {
+ short_name = fcitx;
}
}
diff --git a/tests/indicator-keyboard-test.in b/tests/indicator-keyboard-test.in
index 621133dd..3d43d8ab 100644
--- a/tests/indicator-keyboard-test.in
+++ b/tests/indicator-keyboard-test.in
@@ -4,6 +4,7 @@ export PATH="@abs_top_builddir@/tests/execute:$PATH"
export DCONF_PROFILE="@abs_top_builddir@/tests/profiles/indicator-keyboard-test"
export GSETTINGS_SCHEMA_DIR="@abs_top_builddir@/data"
export XDG_RUNTIME_DIR="@abs_top_builddir@/tests"
+export GTK_IM_MODULE="ibus"
if xvfb-run -a ./indicator-keyboard-tests
then