ibus/ibus-xx-bridge-hotkey.patch

1941 lines
72 KiB
Diff
Raw Normal View History

From 9d5387ea430adbce81899a1a2bece6c8520848b1 Mon Sep 17 00:00:00 2001
From: fujiwarat <takao.fujiwara1@gmail.com>
Date: Fri, 5 Aug 2011 20:54:37 +0900
Subject: [PATCH] Add a bridge hotkey which use prev-next engines instead
of on-off.
---
bus/Makefile.am | 20 +-
bus/ibusimpl.c | 425 +++++++++++++++++++++++++++++++++------
bus/inputcontext.c | 39 ++++
bus/inputcontext.h | 22 ++
bus/registry.c | 36 ++++
configure.ac | 31 +++
data/Makefile.am | 6 +-
data/ibus.schemas.in | 287 --------------------------
data/ibus.schemas.in.in | 300 +++++++++++++++++++++++++++
ibus/_config.py.in | 6 +
ibus/inputcontext.py | 14 ++-
ibus/interface/iinputcontext.py | 4 +-
ibus/xkbxml.py.in | 4 +
setup/enginecombobox.py | 3 +
setup/enginetreeview.py | 16 ++-
setup/main.py | 24 +++
setup/setup.ui | 55 +++++-
src/Makefile.am | 18 +-
src/ibushotkey.c | 11 +
src/ibushotkey.h | 11 +
src/ibusutil.c | 12 +
src/ibusutil.h | 14 ++
ui/gtk/Makefile.am | 2 +
ui/gtk/panel.py | 288 ++++++++++++++++++++++++--
ui/gtk/xkbengine.py | 93 +++++++++
ui/gtk/xkbfactory.py | 117 +++++++++++
xkb/Makefile.am | 2 +
xkb/xkbxml.c | 10 +-
28 files changed, 1480 insertions(+), 390 deletions(-)
delete mode 100644 data/ibus.schemas.in
create mode 100644 data/ibus.schemas.in.in
create mode 100644 ui/gtk/xkbengine.py
create mode 100644 ui/gtk/xkbfactory.py
diff --git a/bus/Makefile.am b/bus/Makefile.am
index 074b456..0efaa1b 100644
--- a/bus/Makefile.am
+++ b/bus/Makefile.am
@@ -29,15 +29,17 @@ INCLUDES = \
-I$(top_builddir)/src \
$(NULL)
-AM_CFLAGS = \
- @GLIB2_CFLAGS@ \
- @GIO2_CFLAGS@ \
- @GTHREAD2_CFLAGS@ \
- -DG_LOG_DOMAIN=\"IBUS\" \
- -DPKGDATADIR=\"$(pkgdatadir)\" \
- -DLIBEXECDIR=\"$(libexecdir)\" \
- -DBINDIR=\"@bindir@\" \
- $(INCLUDES) \
+AM_CFLAGS = \
+ @GLIB2_CFLAGS@ \
+ @GIO2_CFLAGS@ \
+ @GTHREAD2_CFLAGS@ \
+ -DG_LOG_DOMAIN=\"IBUS\" \
+ -DPKGDATADIR=\"$(pkgdatadir)\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DBINDIR=\"@bindir@\" \
+ -DUSE_BRIDGE_HOTKEY=$(USE_BRIDGE_HOTKEY) \
+ -DDEFAULT_BRIDGE_ENGINE_NAME=\"$(DEFAULT_BRIDGE_ENGINE_NAME)\" \
+ $(INCLUDES) \
$(NULL)
AM_LDADD = \
@GOBJECT2_LIBS@ \
diff --git a/bus/ibusimpl.c b/bus/ibusimpl.c
index f13d8e0..44fe954 100644
--- a/bus/ibusimpl.c
+++ b/bus/ibusimpl.c
@@ -20,12 +20,17 @@
* Boston, MA 02111-1307, USA.
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <locale.h>
#include <strings.h>
+#include <string.h>
#include "types.h"
#include "ibusimpl.h"
#include "dbusimpl.h"
@@ -79,6 +84,10 @@ struct _BusIBusImpl {
/* engine-specific hotkeys */
IBusHotkeyProfile *engines_hotkey_profile;
GHashTable *hotkey_to_engines_map;
+
+#if USE_BRIDGE_HOTKEY
+ IBusEngineDesc *prev_hotkey_engine;
+#endif
};
struct _BusIBusImplClass {
@@ -99,6 +108,8 @@ enum {
static guint _signals[LAST_SIGNAL] = { 0 };
*/
+static gchar *_bridge_trigger_keys = NULL;
+
/* functions prototype */
static void bus_ibus_impl_destroy (BusIBusImpl *ibus);
static void bus_ibus_impl_service_method_call
@@ -285,6 +296,30 @@ _panel_destroy_cb (BusPanelProxy *panel,
g_object_unref (panel);
}
+static IBusEngineDesc *
+_find_engine_desc_by_name (BusIBusImpl *ibus,
+ const gchar *engine_name)
+{
+ IBusEngineDesc *desc = NULL;
+ GList *p;
+
+ /* find engine in registered engine list */
+ for (p = ibus->register_engine_list; p != NULL; p = p->next) {
+ desc = (IBusEngineDesc *) p->data;
+ if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0)
+ return desc;
+ }
+
+ /* find engine in preload engine list */
+ for (p = ibus->engine_list; p != NULL; p = p->next) {
+ desc = (IBusEngineDesc *) p->data;
+ if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0)
+ return desc;
+ }
+
+ return NULL;
+}
+
static void
_config_set_value_done (GObject *object,
GAsyncResult *res,
@@ -562,6 +597,67 @@ bus_ibus_impl_set_hotkey (BusIBusImpl *i
}
+#if USE_BRIDGE_HOTKEY
+static gboolean
+use_bridge_hotkey (BusIBusImpl *ibus)
+{
+ GVariant *variant = NULL;
+ gboolean _use_bridge_hotkey = TRUE;
+
+ g_assert (ibus != NULL);
+
+ if (!ibus->config) {
+ return TRUE;
+ }
+
+ variant = ibus_config_get_value (ibus->config,
+ "general/hotkey",
+ "use_bridge_hotkey");
+
+ if (variant != NULL) {
+ g_variant_get (variant, "b", &_use_bridge_hotkey);
+ g_variant_unref (variant);
+ }
+
+ return _use_bridge_hotkey;
+}
+
+static void
+bus_ibus_impl_set_bridge_trigger_keys (BusIBusImpl *ibus,
+ GQuark hotkey,
+ GVariant *value)
+{
+ g_assert (BUS_IS_IBUS_IMPL (ibus));
+
+ ibus_hotkey_profile_remove_hotkey_by_event (ibus->hotkey_profile, hotkey);
+
+ if (value == NULL) {
+ return;
+ }
+
+ GVariantIter iter;
+ g_variant_iter_init (&iter, value);
+ const gchar *str = NULL;
+
+ g_free (_bridge_trigger_keys);
+ _bridge_trigger_keys = NULL;
+
+ while (g_variant_iter_loop (&iter,"&s", &str)) {
+ if (str != NULL) {
+ gchar *tmp =NULL;
+
+ if (_bridge_trigger_keys) {
+ tmp = g_strdup_printf ("%s,%s", _bridge_trigger_keys, str);
+ } else {
+ tmp = g_strdup (str);
+ }
+ g_free (_bridge_trigger_keys);
+ _bridge_trigger_keys = tmp;
+ }
+ }
+}
+#endif
+
/**
* bus_ibus_impl_set_trigger:
*
@@ -573,7 +669,15 @@ bus_ibus_impl_set_trigger (BusIBusImpl *
{
GQuark hotkey = g_quark_from_static_string ("trigger");
if (value != NULL) {
+#if USE_BRIDGE_HOTKEY
+ if (use_bridge_hotkey (ibus)) {
+ bus_ibus_impl_set_bridge_trigger_keys (ibus, hotkey, value);
+ } else {
+ bus_ibus_impl_set_hotkey (ibus, hotkey, value);
+ }
+#else
bus_ibus_impl_set_hotkey (ibus, hotkey, value);
+#endif
}
#ifndef OS_CHROMEOS
else {
@@ -1182,28 +1286,110 @@ _ibus_get_address (BusIBusImpl
g_variant_new ("(s)", bus_server_get_address ()));
}
-static IBusEngineDesc *
-_find_engine_desc_by_name (BusIBusImpl *ibus,
- const gchar *engine_name)
-{
- IBusEngineDesc *desc = NULL;
- GList *p;
+/**
+ * _foreach_remove_engine_hotkey:
+ *
+ * Remove the engine-specific hot key of the engine, and update ibus->engines_hotkey_profile.
+ */
+gboolean
+_foreach_remove_engine_hotkey (gpointer key,
+ gpointer value,
+ gpointer data)
+{
+ GQuark event = GPOINTER_TO_UINT (value);
+ struct _impl_and_desc {
+ BusIBusImpl *ibus;
+ IBusEngineDesc *desc;
+ } *id = (struct _impl_and_desc *) data;
+ BusIBusImpl *ibus = id->ibus;
+ IBusEngineDesc *desc = id->desc;
+ GList *engine_list;
- /* find engine in registered engine list */
- for (p = ibus->register_engine_list; p != NULL; p = p->next) {
- desc = (IBusEngineDesc *) p->data;
- if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0)
- return desc;
+ g_assert (ibus != NULL);
+ g_assert (desc != NULL);
+
+ if (event == 0) {
+ return FALSE;
}
- /* find engine in preload engine list */
- for (p = ibus->engine_list; p != NULL; p = p->next) {
- desc = (IBusEngineDesc *) p->data;
- if (g_strcmp0 (ibus_engine_desc_get_name (desc), engine_name) == 0)
- return desc;
+ engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map,
+ GUINT_TO_POINTER (event));
+
+ /* As we will rebuild the engines hotkey map whenever an engine was
+ * added or removed, we don't need to hold a reference of the engine
+ * here. */
+ if (engine_list && g_list_find (engine_list, desc) != NULL) {
+ engine_list = g_list_remove (engine_list, desc);
}
- return NULL;
+ /* We need to steal the value before adding it back, otherwise it will
+ * be destroyed. */
+ g_hash_table_steal (ibus->hotkey_to_engines_map, GUINT_TO_POINTER (event));
+
+ if (engine_list != NULL) {
+ g_hash_table_insert (ibus->hotkey_to_engines_map,
+ GUINT_TO_POINTER (event), engine_list);
+ }
+
+ return FALSE;
+}
+
+/**
+ * _add_engine_hotkey_with_hotkeys:
+ *
+ * Check the engine-specific hot key of the engine, and update ibus->engines_hotkey_profile.
+ */
+static void
+_add_engine_hotkey_with_hotkeys (IBusEngineDesc *engine,
+ BusIBusImpl *ibus,
+ const gchar *hotkeys)
+{
+ gchar **hotkey_list;
+ gchar **p;
+ gchar *hotkey;
+ GList *engine_list;
+
+ GQuark event;
+ guint keyval;
+ guint modifiers;
+
+ g_assert (engine != NULL);
+ g_assert (hotkeys && *hotkeys);
+
+ hotkey_list = g_strsplit_set (hotkeys, ";,", 0);
+
+ for (p = hotkey_list; p && *p; ++p) {
+ hotkey = g_strstrip (*p);
+ if (!*hotkey || !ibus_key_event_from_string (hotkey, &keyval, &modifiers)) {
+ continue;
+ }
+
+ /* If the hotkey already exists, we won't need to add it again. */
+ event = ibus_hotkey_profile_lookup_hotkey (ibus->engines_hotkey_profile,
+ keyval, modifiers);
+ if (event == 0) {
+ event = g_quark_from_string (hotkey);
+ ibus_hotkey_profile_add_hotkey (ibus->engines_hotkey_profile,
+ keyval, modifiers, event);
+ }
+
+ engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map,
+ GUINT_TO_POINTER (event));
+
+ /* As we will rebuild the engines hotkey map whenever an engine was
+ * added or removed, we don't need to hold a reference of the engine
+ * here. */
+ engine_list = g_list_append (engine_list, engine);
+
+ /* We need to steal the value before adding it back, otherwise it will
+ * be destroyed. */
+ g_hash_table_steal (ibus->hotkey_to_engines_map, GUINT_TO_POINTER (event));
+
+ g_hash_table_insert (ibus->hotkey_to_engines_map,
+ GUINT_TO_POINTER (event), engine_list);
+ }
+
+ g_strfreev (hotkey_list);
}
/**
@@ -1216,7 +1402,71 @@ _context_request_engine_cb (BusInputCont
const gchar *engine_name,
BusIBusImpl *ibus)
{
- return bus_ibus_impl_get_engine_desc (ibus, engine_name);
+ IBusEngineDesc *desc = bus_ibus_impl_get_engine_desc (ibus, engine_name);
+ struct _impl_and_desc {
+ BusIBusImpl *ibus;
+ IBusEngineDesc *desc;
+ } id = {ibus, desc};
+
+#if USE_BRIDGE_HOTKEY
+ IBusEngineDesc *current_desc = NULL;
+
+ if (!use_bridge_hotkey (ibus)) {
+ return desc;
+ }
+
+ if (context) {
+ BusEngineProxy *engine = bus_input_context_get_engine (context);
+ if (engine != NULL) {
+ current_desc = bus_engine_proxy_get_desc (engine);
+ }
+ }
+
+ if (current_desc) {
+ if (context) {
+ bus_input_context_set_prev_hotkey_engine (context, current_desc);
+ } else {
+ ibus->prev_hotkey_engine = current_desc;
+ }
+ }
+
+ if (((current_desc == NULL && desc != NULL) ||
+ (current_desc != NULL && desc != NULL &&
+ g_strcmp0 (ibus_engine_desc_get_name (current_desc),
+ ibus_engine_desc_get_name (desc)) != 0)) &&
+ g_ascii_strncasecmp (ibus_engine_desc_get_name (desc),
+ DEFAULT_BRIDGE_ENGINE_NAME,
+ strlen (DEFAULT_BRIDGE_ENGINE_NAME)) == 0) {
+ const gchar *hotkeys = NULL;
+
+ /* If the user customized the trigger key, the trigger key is used for
+ * any IBus engines. */
+ if (_bridge_trigger_keys != NULL &&
+ *_bridge_trigger_keys != '\0' &&
+ g_strcmp0 (_bridge_trigger_keys, "Control+space") != 0) {
+
+ hotkeys = (const gchar *) _bridge_trigger_keys;
+ } else if (current_desc) {
+ hotkeys = ibus_engine_desc_get_hotkeys (current_desc);
+ }
+
+ /* If engine hotkeys are not defined in the compose xml file,
+ * IBus trigger keys are used. */
+ if (!hotkeys || !*hotkeys) {
+ hotkeys = (const gchar *) _bridge_trigger_keys;
+ }
+
+ if (!hotkeys || !*hotkeys) {
+ return desc;
+ }
+
+ ibus_hotkey_profile_foreach_hotkey (ibus->engines_hotkey_profile,
+ _foreach_remove_engine_hotkey,
+ &id);
+ _add_engine_hotkey_with_hotkeys (desc, ibus, hotkeys);
+ }
+#endif
+ return desc;
}
/**
@@ -2270,6 +2520,9 @@ bus_ibus_impl_filter_keyboard_shortcuts
GQuark event;
GList *engine_list;
+#if USE_BRIDGE_HOTKEY
+ IBusEngineDesc *prev_hotkey_engine = NULL;
+#endif
if (trigger == 0) {
trigger = g_quark_from_static_string ("trigger");
@@ -2334,6 +2587,12 @@ bus_ibus_impl_filter_keyboard_shortcuts
return FALSE;
}
+#if USE_BRIDGE_HOTKEY
+ if (!use_bridge_hotkey (ibus)) {
+ return FALSE;
+ }
+#endif
+
/* Then try engines hotkeys. */
event = ibus_hotkey_profile_filter_key_event (ibus->engines_hotkey_profile,
keyval,
@@ -2355,6 +2614,24 @@ bus_ibus_impl_filter_keyboard_shortcuts
g_assert (new_engine_desc);
+#if USE_BRIDGE_HOTKEY
+ if (context) {
+ prev_hotkey_engine = bus_input_context_get_prev_hotkey_engine (context);
+ if (prev_hotkey_engine == NULL && ibus->prev_hotkey_engine) {
+ prev_hotkey_engine = ibus->prev_hotkey_engine;
+ bus_input_context_set_prev_hotkey_engine (context,
+ prev_hotkey_engine);
+ }
+ }
+
+ /* If the previous engine is not included in engine_list,
+ * this enables a new engine instead of toggling the engines
+ * so should not enable the previous engine. */
+ if (prev_hotkey_engine &&
+ g_list_find (engine_list, prev_hotkey_engine) != NULL) {
+ new_engine_desc = prev_hotkey_engine;
+ }
+#else
/* Find out what engine we should switch to. If the current engine has
* the same hotkey, then we should switch to the next engine with the
* same hotkey in the list. Otherwise, we just switch to the first
@@ -2366,8 +2643,47 @@ bus_ibus_impl_filter_keyboard_shortcuts
break;
}
}
+#endif
+
+#if USE_BRIDGE_HOTKEY
+ if (context == NULL) {
+ return FALSE;
+ }
+
+ /* This means RequestEngine signal might be done but SetEngine signal
+ * has not been done yet by ibus status icon. */
+ if (current_engine_desc == NULL &&
+ !bus_input_context_inited_engine (context)) {
+ return FALSE;
+ }
+
+ if (current_engine_desc != new_engine_desc) {
+ if (current_engine_desc) {
+ if (context) {
+ bus_input_context_set_prev_hotkey_engine (context,
+ current_engine_desc);
+ }
+ }
+ /* If the previous engine is not included in engine_list and
+ * the current engine is the defualt bridge engine,
+ * the current engine is also not included in engine_list.
+ * So the engine is added here. */
2011-07-05 05:07:17 +00:00
+ if (current_engine_desc != NULL &&
+ g_list_find (engine_list, current_engine_desc) == NULL &&
+ g_ascii_strncasecmp (ibus_engine_desc_get_name (current_engine_desc),
+ DEFAULT_BRIDGE_ENGINE_NAME,
+ strlen (DEFAULT_BRIDGE_ENGINE_NAME)) == 0) {
+ engine_list = g_list_append (engine_list, current_engine_desc);
+
+ g_hash_table_steal (ibus->hotkey_to_engines_map,
+ GUINT_TO_POINTER (event));
+ g_hash_table_insert (ibus->hotkey_to_engines_map,
+ GUINT_TO_POINTER (event), engine_list);
+ }
+#else
if (current_engine_desc != new_engine_desc) {
+#endif
bus_ibus_impl_set_context_engine_from_desc (ibus, context, new_engine_desc);
}
@@ -2472,59 +2788,54 @@ static void
_add_engine_hotkey (IBusEngineDesc *engine, BusIBusImpl *ibus)
{
const gchar *hotkeys;
- gchar **hotkey_list;
- gchar **p;
- gchar *hotkey;
- GList *engine_list;
-
- GQuark event;
- guint keyval;
- guint modifiers;
if (!engine) {
return;
}
- hotkeys = ibus_engine_desc_get_hotkeys (engine);
-
- if (!hotkeys || !*hotkeys) {
+#if USE_BRIDGE_HOTKEY
+ if (!use_bridge_hotkey (ibus)) {
return;
}
- hotkey_list = g_strsplit_set (hotkeys, ";,", 0);
-
- for (p = hotkey_list; p && *p; ++p) {
- hotkey = g_strstrip (*p);
- if (!*hotkey || !ibus_key_event_from_string (hotkey, &keyval, &modifiers)) {
- continue;
- }
-
- /* If the hotkey already exists, we won't need to add it again. */
- event = ibus_hotkey_profile_lookup_hotkey (ibus->engines_hotkey_profile,
- keyval, modifiers);
- if (event == 0) {
- event = g_quark_from_string (hotkey);
- ibus_hotkey_profile_add_hotkey (ibus->engines_hotkey_profile,
- keyval, modifiers, event);
- }
+ /* Do not register hotkeys for the default keymap engines
+ * but register hotkeys for only input-method engines
+ * in 'RegisterComponent' dbus method.
+ * The hotkeys for an activated keymap engine will be registered
+ * in 'SetEngine' dbus method. */
+ if (g_ascii_strncasecmp (ibus_engine_desc_get_name (engine),
+ DEFAULT_BRIDGE_ENGINE_NAME,
+ strlen (DEFAULT_BRIDGE_ENGINE_NAME)) == 0) {
+ return;
+ }
- engine_list = g_hash_table_lookup (ibus->hotkey_to_engines_map,
- GUINT_TO_POINTER (event));
+ /* If the user customized the trigger key, the trigger key is used for
+ * any IBus engines. */
+ if (_bridge_trigger_keys != NULL &&
+ *_bridge_trigger_keys != '\0' &&
+ g_strcmp0 (_bridge_trigger_keys, "Control+space") != 0) {
- /* As we will rebuild the engines hotkey map whenever an engine was
- * added or removed, we don't need to hold a reference of the engine
- * here. */
- engine_list = g_list_append (engine_list, engine);
+ hotkeys = (const gchar *) _bridge_trigger_keys;
+ } else {
+ hotkeys = ibus_engine_desc_get_hotkeys (engine);
+ }
+#else
+ hotkeys = ibus_engine_desc_get_hotkeys (engine);
+#endif
- /* We need to steal the value before adding it back, otherwise it will
- * be destroyed. */
- g_hash_table_steal (ibus->hotkey_to_engines_map, GUINT_TO_POINTER (event));
+#if USE_BRIDGE_HOTKEY
+ /* If engine hotkeys are not defined in the compose xml file, IBus trigger
+ * keys are used. */
+ if (!hotkeys || !*hotkeys) {
+ hotkeys = (const gchar *) _bridge_trigger_keys;
+ }
+#endif
- g_hash_table_insert (ibus->hotkey_to_engines_map,
- GUINT_TO_POINTER (event), engine_list);
+ if (!hotkeys || !*hotkeys) {
+ return;
}
- g_strfreev (hotkey_list);
+ _add_engine_hotkey_with_hotkeys (engine, ibus, hotkeys);
}
/**
diff --git a/bus/inputcontext.c b/bus/inputcontext.c
index 4e8cdc5..43dedc0 100644
--- a/bus/inputcontext.c
+++ b/bus/inputcontext.c
@@ -90,6 +90,12 @@ struct _BusInputContext {
/* incompleted set engine by desc request */
SetEngineByDescData *data;
+
+ /* if init engine */
+ gboolean inited_engine;
+
+ /* previous hotkey engine for bridge hotkey mode */
+ IBusEngineDesc *prev_hotkey_engine;
};
struct _BusInputContextClass {
@@ -647,6 +653,11 @@ bus_input_context_destroy (BusInputContext *context)
context->client = NULL;
}
+ if (context->prev_hotkey_engine) {
+ g_object_unref (context->prev_hotkey_engine);
+ context->prev_hotkey_engine = NULL;
+ }
+
IBUS_OBJECT_CLASS (bus_input_context_parent_class)->destroy (IBUS_OBJECT (context));
}
@@ -2211,6 +2222,7 @@ bus_input_context_set_engine (BusInputContext *context,
}
else {
gint i;
+ context->inited_engine = TRUE;
context->engine = engine;
g_object_ref (context->engine);
@@ -2538,3 +2550,30 @@ bus_input_context_get_client (BusInputContext *context)
g_assert (BUS_IS_INPUT_CONTEXT (context));
return context->client;
}
+
+gboolean
+bus_input_context_inited_engine (BusInputContext *context)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ return context->inited_engine;
+}
+
+IBusEngineDesc *
+bus_input_context_get_prev_hotkey_engine (BusInputContext *context)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ return context->prev_hotkey_engine;
+}
+
+void
+bus_input_context_set_prev_hotkey_engine (BusInputContext *context,
+ IBusEngineDesc *desc)
+{
+ g_assert (BUS_IS_INPUT_CONTEXT (context));
+ g_assert (desc == NULL || IBUS_IS_ENGINE_DESC (desc));
+
+ if (context->prev_hotkey_engine) {
+ g_object_unref (context->prev_hotkey_engine);
+ }
+ context->prev_hotkey_engine = desc ? g_object_ref (desc) : NULL;
+}
diff --git a/bus/inputcontext.h b/bus/inputcontext.h
index bc4e096..c79e033 100644
--- a/bus/inputcontext.h
+++ b/bus/inputcontext.h
@@ -213,5 +213,27 @@ void bus_input_context_set_capabilities (BusInputContext *con
*/
const gchar *bus_input_context_get_client (BusInputContext *context);
+/**
+ * bus_input_context_inited_engine:
+ * @returns: context->inited_engine.
+ */
+gboolean bus_input_context_inited_engine
+ (BusInputContext *context);
+
+/**
+ * bus_input_context_get_prev_hotkey_engine:
+ * @returns: context->prev_hotkey_engine.
+ */
+IBusEngineDesc *bus_input_context_get_prev_hotkey_engine
+ (BusInputContext *context);
+
+/**
+ * bus_input_context_set_prev_hotkey_engine:
+ * @desc: Assign the desc to context->prev_hotkey_engine.
+ */
+void bus_input_context_set_prev_hotkey_engine
+ (BusInputContext *context,
+ IBusEngineDesc *desc);
+
G_END_DECLS
#endif
diff --git a/bus/registry.c b/bus/registry.c
index 7b74781..07e9148 100644
--- a/bus/registry.c
+++ b/bus/registry.c
@@ -19,6 +19,11 @@
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include "registry.h"
#include <glib/gstdio.h>
#include <gio/gio.h>
@@ -101,6 +106,9 @@ bus_registry_init (BusRegistry *registry)
registry->observed_paths = NULL;
registry->components = NULL;
registry->engine_table = g_hash_table_new (g_str_hash, g_str_equal);
+#if USE_BRIDGE_HOTKEY
+ gboolean has_default_engine = FALSE;
+#endif
#ifdef G_THREADS_ENABLED
/* If glib supports thread, we'll create a thread to monitor changes in IME
@@ -145,12 +153,40 @@ bus_registry_init (BusRegistry *registry)
GList *p1;
for (p1 = engines; p1 != NULL; p1 = p1->next) {
IBusEngineDesc *desc = (IBusEngineDesc *) p1->data;
+#if USE_BRIDGE_HOTKEY
+ if (g_ascii_strncasecmp (ibus_engine_desc_get_name (desc),
+ DEFAULT_BRIDGE_ENGINE_NAME,
+ strlen (DEFAULT_BRIDGE_ENGINE_NAME)) == 0) {
+ has_default_engine = TRUE;
+ }
+#endif
g_hash_table_insert (registry->engine_table,
(gpointer) ibus_engine_desc_get_name (desc),
desc);
}
g_list_free (engines);
}
+
+#if USE_BRIDGE_HOTKEY
+ if (has_default_engine == FALSE) {
+ bus_registry_remove_all (registry);
+ bus_registry_load (registry);
+ bus_registry_save_cache (registry);
+
+ for (p = registry->components; p != NULL; p = p->next) {
+ BusComponent *comp = (BusComponent *) p->data;
+ GList *engines = bus_component_get_engines (comp);
+ GList *p1;
+ for (p1 = engines; p1 != NULL; p1 = p1->next) {
+ IBusEngineDesc *desc = (IBusEngineDesc *) p1->data;
+ g_hash_table_insert (registry->engine_table,
+ (gpointer) ibus_engine_desc_get_name (desc),
+ desc);
+ }
+ g_list_free (engines);
+ }
+ }
+#endif
}
static void
diff --git a/configure.ac b/configure.ac
index 4c20ae7..21d35c3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -456,6 +456,34 @@ else
enable_surrounding_text="no (disabled, use --enable-surrounding-text to enable)"
fi
+# option for bridge hotkey
+AC_ARG_ENABLE(bridge-hotkey,
+ AS_HELP_STRING([--enable-bridge-hotkey],
+ [Enable bridge hotkey instead of ON/OFF hotkey]),
+ [enable_bridge_hotkey=$enableval],
+ [enable_bridge_hotkey=no]
+)
+
+if test x"$enable_bridge_hotkey" = x"yes"; then
+ USE_BRIDGE_HOTKEY=1
+ TRIGGER_HOTKEYS="Control+space"
+else
+ USE_BRIDGE_HOTKEY=0
+ TRIGGER_HOTKEYS="Control+space,Zenkaku_Hankaku,Alt+Kanji,Alt+grave,Hangul,Alt+Release+Alt_R"
+ enable_bridge_hotkey="no (disabled, use --enable-bridge-hotkey to enable)"
+fi
+AC_SUBST(USE_BRIDGE_HOTKEY)
+AC_SUBST(TRIGGER_HOTKEYS)
+
+# define default bridge engine name
+AC_ARG_WITH(bridge-engine,
+ AS_HELP_STRING([--with-bridge-engine[=bridge_engine_name]],
+ [Set bridge engine name in IM bridge hotkey. (default: xkb:layout:default:)]),
+ [DEFAULT_BRIDGE_ENGINE_NAME=$with_bridge_engine],
+ [DEFAULT_BRIDGE_ENGINE_NAME="xkb:layout:default:"]
+)
+AC_SUBST(DEFAULT_BRIDGE_ENGINE_NAME)
+
# check iso-codes
PKG_CHECK_MODULES(ISOCODES, [
iso-codes
@@ -482,6 +510,7 @@ bus/Makefile
util/Makefile
util/IMdkit/Makefile
data/Makefile
+data/ibus.schemas.in
data/icons/Makefile
data/keymaps/Makefile
docs/Makefile
@@ -534,5 +563,7 @@ Build options:
No snooper regexes "$NO_SNOOPER_APPS"
Panel icon "$IBUS_ICON_KEYBOARD"
Enable surrounding-text $enable_surrounding_text
+ Enable bridge hotkey $enable_bridge_hotkey
+ Default bridge engine $DEFAULT_BRIDGE_ENGINE_NAME
])
diff --git a/data/Makefile.am b/data/Makefile.am
index 99be41c..824da76 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -30,7 +30,8 @@ SUBDIRS = \
$(NULL)
schemasdir = $(GCONF_SCHEMA_FILE_DIR)
-schemas_in_files = ibus.schemas.in
+schemas_in_in_files = ibus.schemas.in.in
+schemas_in_files = $(schemas_in_in_files:.schemas.in.in=.schemas.in)
schemas_DATA = $(schemas_in_files:.schemas.in=.schemas)
@INTLTOOL_SCHEMAS_RULE@
@@ -45,11 +46,12 @@ if GCONF_SCHEMAS_INSTALL
endif
EXTRA_DIST = \
- $(schemas_in_files) \
+ $(schemas_in_in_files) \
$(NULL)
DISTCLEANFILES = \
$(schemas_DATA) \
+ $(schemas_in_files) \
$(NULL)
-include $(top_srcdir)/git.mk
diff --git a/data/ibus.schemas.in b/data/ibus.schemas.in.in
index 7ca4899..42d9297
--- a/data/ibus.schemas.in
+++ b/data/ibus.schemas.in.in
@@ -31,7 +31,7 @@
<owner>ibus</owner>
<type>list</type>
<list_type>string</list_type>
- <default>[Control+space,Zenkaku_Hankaku,Alt+Kanji,Alt+grave,Hangul,Alt+Release+Alt_R]</default>
+ <default>[@TRIGGER_HOTKEYS@]</default>
<locale name="C">
<short>Trigger shortcut keys</short>
<long>The shortcut keys for turning input method on or off</long>
diff --git a/ibus/_config.py.in b/ibus/_config.py.in
index a830136..4c3c980 100644
--- a/ibus/_config.py.in
+++ b/ibus/_config.py.in
@@ -25,6 +25,8 @@ __all__ = (
"get_copyright",
"get_license",
"get_ICON_KEYBOARD",
+ "use_bridge_hotkey",
+ "DEFAULT_BRIDGE_ENGINE_NAME",
"ISOCODES_PREFIX",
"_"
)
@@ -51,4 +53,8 @@ def get_ICON_KEYBOARD():
icon = 'ibus-keyboard'
return icon
+def use_bridge_hotkey():
+ return True if @USE_BRIDGE_HOTKEY@ == 1 else False
+
+DEFAULT_BRIDGE_ENGINE_NAME='@DEFAULT_BRIDGE_ENGINE_NAME@'
ISOCODES_PREFIX='@ISOCODES_PREFIX@'
diff --git a/ibus/inputcontext.py b/ibus/inputcontext.py
index ceeb56d..b3c2f65 100644
--- a/ibus/inputcontext.py
+++ b/ibus/inputcontext.py
@@ -28,6 +28,7 @@ import sys
import gobject
import dbus
import dbus.lowlevel
+import _config
import object
import common
import serializable
@@ -279,8 +280,19 @@ class InputContext(object.Object):
except:
return None
+ def __handle_ic_reply(self):
+ pass
+
+ def __handle_ic_error(self, e):
+ print self.__gtype_name__, str(e)
+
def set_engine(self, engine):
- return self.__context.SetEngine(engine.name)
+ return self.__context.SetEngine(engine.name,
+ reply_handler=self.__handle_ic_reply,
+ error_handler=self.__handle_ic_error)
+
+ def set_bridge_engine(self):
+ return self.__context.SetEngine(_config.DEFAULT_BRIDGE_ENGINE_NAME)
def introspect(self):
return self.__context.Introspect()
diff --git a/ibus/interface/iinputcontext.py b/ibus/interface/iinputcontext.py
index 1d3cd2a..58d75e5 100644
--- a/ibus/interface/iinputcontext.py
+++ b/ibus/interface/iinputcontext.py
@@ -76,8 +76,8 @@ class IInputContext(dbus.service.Object):
@method(out_signature="v")
def GetEngine(self): pass
- @method(in_signature="s")
- def SetEngine(self, engine_name): pass
+ @async_method(in_signature="s")
+ def SetEngine(self, engine_name, reply_cb, error_cb): pass
@method()
def Destroy(self): pass
diff --git a/ibus/xkbxml.py.in b/ibus/xkbxml.py.in
index 16f47df..85d0651 100644
--- a/ibus/xkbxml.py.in
+++ b/ibus/xkbxml.py.in
@@ -33,6 +33,8 @@ import enginedesc
from xml.sax.saxutils import XMLFilterBase, XMLGenerator
from xml.sax._exceptions import SAXParseException
from cStringIO import StringIO
+from _config import DEFAULT_BRIDGE_ENGINE_NAME
+from _config import get_ICON_KEYBOARD
try:
from glib import get_user_config_dir
@@ -312,6 +314,8 @@ class XKBConfigRegistry():
engine_layout = layout
icon = 'ibus-engine'
+ if name_prefix == DEFAULT_BRIDGE_ENGINE_NAME:
+ icon = get_ICON_KEYBOARD()
engine = enginedesc.EngineDesc(name, longname, desc, lang,
'LGPL2.1',
diff --git a/setup/enginecombobox.py b/setup/enginecombobox.py
index 7383177..d35757d 100644
--- a/setup/enginecombobox.py
+++ b/setup/enginecombobox.py
@@ -64,6 +64,9 @@ class EngineComboBox(gtk.ComboBox):
self.__model.set(iter1, 0, 0)
lang = {}
for e in engines:
+ if ibus.use_bridge_hotkey() and \
+ e.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
+ continue
l = ibus.get_language_name(e.language)
if l not in lang:
lang[l] = []
diff --git a/setup/enginetreeview.py b/setup/enginetreeview.py
index f620361..20cde3b 100644
--- a/setup/enginetreeview.py
+++ b/setup/enginetreeview.py
@@ -162,6 +162,14 @@ class EngineTreeView(gtk.TreeView):
return row[0]
elif property.name == "engines":
engines = [ r[0] for r in self.__model if r[0] != None]
+ for i, e in enumerate(self.__engines):
+ if ibus.use_bridge_hotkey() and \
+ e.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
+ if i < len(engines):
+ engines.insert(i, e)
+ else:
+ engines.append(e)
+ break
return engines
else:
raise AttributeError, 'unknown property %s' % property.name
@@ -172,8 +180,12 @@ class EngineTreeView(gtk.TreeView):
for e in engines:
if e in self.__engines:
continue
- iter = self.__model.append(None)
- self.__model.set(iter, 0, e)
+ if ibus.use_bridge_hotkey() and \
+ e.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
+ pass
+ else:
+ iter = self.__model.append(None)
+ self.__model.set(iter, 0, e)
self.__engines.add(e)
self.__emit_changed()
diff --git a/setup/main.py b/setup/main.py
index 7f4a040..a22ac78 100644
--- a/setup/main.py
+++ b/setup/main.py
@@ -213,6 +213,25 @@ class Setup(object):
self.__config.get_value("general", "use_global_engine", False))
self.__checkbutton_use_global_engine.connect("toggled", self.__checkbutton_use_global_engine_toggled_cb)
+ # hotkey settings
+ if ibus.use_bridge_hotkey():
+ label = self.__builder.get_object("label_trigger_hotkey")
+ label.set_label(_("Toggle:"))
+ label.set_tooltip_text(_("The trigger shortcut keys to toggle "
+ "the previous and next input methods"))
+ self.__checkbutton_use_on_off_hotkey = \
+ self.__builder.get_object("checkbutton_use_on_off_hotkey")
+ self.__checkbutton_use_on_off_hotkey.set_active(
+ not self.__config.get_value("general/hotkey",
+ "use_bridge_hotkey",
+ True))
+ self.__checkbutton_use_on_off_hotkey.connect("toggled",
+ self.__checkbutton_use_on_off_hotkey_cb)
+ else:
+ checkbutton = self.__builder.get_object("checkbutton_use_on_off_hotkey")
+ checkbutton.hide()
+ checkbutton.set_no_show_all(True)
+
# init engine page
preload_engine_mode = self.__config.get_value("general",
"preload_engine_mode",
@@ -519,6 +538,11 @@ class Setup(object):
value = self.__checkbutton_use_global_engine.get_active()
self.__config.set_value("general", "use_global_engine", value)
+ def __checkbutton_use_on_off_hotkey_cb(self, button):
+ value = self.__checkbutton_use_on_off_hotkey.get_active()
+ self.__config.set_value("general/hotkey", "use_bridge_hotkey",
+ not value)
+
def __config_value_changed_cb(self, bus, section, name, value):
if section == 'general' and name == 'preload_engines':
engines = self.__get_engine_descs_from_names(value)
diff --git a/setup/setup.ui b/setup/setup.ui
index f1e6d0b..77714a7 100644
--- a/setup/setup.ui
+++ b/setup/setup.ui
@@ -232,7 +232,7 @@
</packing>
</child>
<child>
- <object class="GtkLabel" id="label7">
+ <object class="GtkLabel" id="label_trigger_hotkey">
<property name="visible">True</property>
<property name="tooltip_text" translatable="yes">The shortcut keys for turning input method on or off</property>
<property name="xalign">0</property>
@@ -962,6 +962,59 @@ You may use up/down buttons to change it.&lt;/i&gt;&lt;/small&gt;</property>
<property name="position">1</property>
</packing>
</child>
+ <child>
+ <object class="GtkFrame" id="frame6">
+ <property name="visible">True</property>
+ <property name="label_xalign">0</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkAlignment" id="alignment14">
+ <property name="visible">True</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkAlignment" id="alignment15">
+ <property name="visible">True</property>
+ <property name="top_padding">6</property>
+ <property name="left_padding">12</property>
+ <child>
+ <object class="GtkVBox" id="vbox10">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkCheckButton" id="checkbutton_use_on_off_hotkey">
+ <property name="label" translatable="yes">Use trigger keys to enable or disable an input method</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="label">
+ <object class="GtkLabel" id="label50">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Hot keys setting&lt;/b&gt;</property>
+ <property name="use_markup">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
</object>
</child>
</object>
diff --git a/src/Makefile.am b/src/Makefile.am
index 6454522..319df3c 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -38,14 +38,16 @@ INTROSPECTION_GIRS =
CLEANFILES =
# C preprocessor flags
-AM_CPPFLAGS = \
- -DG_LOG_DOMAIN=\"IBUS\" \
- @GLIB2_CFLAGS@ \
- @GOBJECT2_CFLAGS@ \
- @GIO2_CFLAGS@ \
- -DIBUS_DATA_DIR=\"$(pkgdatadir)\" \
- -DIBUS_COMPILATION \
- -DISOCODES_PREFIX=\"$(ISOCODES_PREFIX)\" \
+AM_CPPFLAGS = \
+ -DG_LOG_DOMAIN=\"IBUS\" \
+ @GLIB2_CFLAGS@ \
+ @GOBJECT2_CFLAGS@ \
+ @GIO2_CFLAGS@ \
+ -DIBUS_DATA_DIR=\"$(pkgdatadir)\" \
+ -DIBUS_COMPILATION \
+ -DISOCODES_PREFIX=\"$(ISOCODES_PREFIX)\" \
+ -DUSE_BRIDGE_HOTKEY=$(USE_BRIDGE_HOTKEY) \
+ -DDEFAULT_BRIDGE_ENGINE_NAME=\"$(DEFAULT_BRIDGE_ENGINE_NAME)\" \
$(NULL)
# ibus library
diff --git a/src/ibushotkey.c b/src/ibushotkey.c
index 32f8338..bef7dfc 100644
--- a/src/ibushotkey.c
+++ b/src/ibushotkey.c
@@ -562,3 +562,14 @@ ibus_hotkey_profile_lookup_hotkey (IBusHotkeyProfile *profile,
return (GQuark) GPOINTER_TO_UINT (g_tree_lookup (priv->hotkeys, &hotkey));
}
+
+void
+ibus_hotkey_profile_foreach_hotkey (IBusHotkeyProfile *profile,
+ GTraverseFunc func,
+ gpointer user_data)
+{
+ IBusHotkeyProfilePrivate *priv;
+ priv = IBUS_HOTKEY_PROFILE_GET_PRIVATE (profile);
+
+ g_tree_foreach (priv->hotkeys, func, user_data);
+}
diff --git a/src/ibushotkey.h b/src/ibushotkey.h
index 9a341f6..92ec6af 100644
--- a/src/ibushotkey.h
+++ b/src/ibushotkey.h
@@ -179,5 +179,16 @@ GQuark ibus_hotkey_profile_lookup_hotkey
guint keyval,
guint modifiers);
+/**
+ * ibus_hotkey_profile_foreach_hotkey:
+ * @profile: An IBusHotkeyProfile.
+ * @func: (scope call): A GTraverseFunc for g_tree_traverse.
+ * @user_data: A gpointer for g_tree_traverse.
+ */
+void ibus_hotkey_profile_foreach_hotkey
+ (IBusHotkeyProfile *profile,
+ GTraverseFunc func,
+ gpointer user_data);
+
G_END_DECLS
#endif
diff --git a/src/ibusutil.c b/src/ibusutil.c
index ddb6b9e..46dab1a 100644
--- a/src/ibusutil.c
+++ b/src/ibusutil.c
@@ -145,3 +145,15 @@ ibus_get_language_name(const gchar *_locale) {
}
return retval;
}
+
+gboolean
+ibus_use_bridge_hotkey (void)
+{
+ return (USE_BRIDGE_HOTKEY == 1) ? TRUE : FALSE;
+}
+
+const gchar *
+ibus_get_default_bridge_engine_name (void)
+{
+ return DEFAULT_BRIDGE_ENGINE_NAME;
+}
diff --git a/src/ibusutil.h b/src/ibusutil.h
index 7cf1995..a19d16e 100644
--- a/src/ibusutil.h
+++ b/src/ibusutil.h
@@ -43,4 +43,18 @@
*/
const gchar * ibus_get_language_name (const gchar *_locale);
+/**
+ * ibus_bus_use_bridge_hotkey:
+ * @bus: An #IBusBus.
+ * @returns: %TRUE if @bus use bridge hotkey, %FALSE otherwise.
+ */
+gboolean ibus_use_bridge_hotkey (void);
+
+/**
+ * ibus_bus_get_default_bridge_engine_name:
+ * @bus: An #IBusBus.
+ * @returns: A default bridge engine name.
+ */
+const gchar * ibus_get_default_bridge_engine_name (void);
+
#endif
diff --git a/ui/gtk/Makefile.am b/ui/gtk/Makefile.am
index 1f19748..1702613 100644
--- a/ui/gtk/Makefile.am
+++ b/ui/gtk/Makefile.am
@@ -33,6 +33,8 @@ ui_gtk_PYTHON = \
propitem.py \
toolitem.py \
engineabout.py \
+ xkbengine.py \
+ xkbfactory.py \
$(NULL)
ui_gtkdir = $(pkgdatadir)/ui/gtk
diff --git a/ui/gtk/panel.py b/ui/gtk/panel.py
index 8804634..d87c1d2 100644
--- a/ui/gtk/panel.py
+++ b/ui/gtk/panel.py
@@ -133,6 +133,15 @@ class Panel(ibus.PanelBase):
# self.__bus.request_name(ibus.panel.IBUS_SERVICE_PANEL, 0)
# init xkb
+ self.__default_layout = 'default'
+ self.__default_model = 'default'
+ self.__default_option = 'default'
+ self.__disabled_engines = None
+ self.__disabled_engines_id = -1
+ self.__disabled_engines_prev_id = -1
+ self.__disabled_engines_swapped = 0
+ self.__show = 0
+
self.__xkblayout = ibus.XKBLayout(self.__config)
use_xkb = self.__config.get_value("general", "use_system_keyboard_layout", False)
if not use_xkb:
@@ -142,11 +151,18 @@ class Panel(ibus.PanelBase):
value = 'default'
if value != 'default':
self.__xkblayout.set_default_layout(value)
+ if value.find('(') >= 0:
+ self.__default_layout = value.split('(')[0]
+ self.__default_model = value.split('(')[1].split(')')[0]
+ else:
+ self.__default_layout = value
+ self.__default_model = None
value = str(self.__config.get_value("general", "system_keyboard_option", ''))
if value == '':
value = 'default'
if value != 'default':
self.__xkblayout.set_default_option(value)
+ self.__default_option = value
def set_cursor_location(self, x, y, w, h):
self.__candidate_panel.set_cursor_location(x, y, w, h)
@@ -233,12 +249,113 @@ class Panel(ibus.PanelBase):
def __set_im_name(self, name):
self.__language_bar.set_im_name(name)
+ def __use_bridge_hotkey(self):
+ if not ibus.use_bridge_hotkey():
+ return False
+ if self.__config == None:
+ return True
+ return self.__config.get_value("general/hotkey", "use_bridge_hotkey",
+ True)
+
+ def __set_default_layout_engine(self, use_bridge_hotkey):
+ default_layout = self.__default_layout
+ default_model = self.__default_model
+ if default_layout == 'default':
+ default_layout = self.__xkblayout.get_default_layout()[0]
+ default_model = self.__xkblayout.get_default_layout()[1]
+ if default_model == 'default':
+ default_model = self.__xkblayout.get_default_layout()[1]
+ layouts = default_layout.split(',')
+ models = None
+ if default_model != None and default_model != '':
+ models = default_model.split(',')
+ if self.__disabled_engines == None or self.__disabled_engines == []:
+ self.__disabled_engines = []
+ for i, layout in enumerate(layouts):
+ registry = ibus.XKBConfigRegistry()
+ langs = registry.get_layout_lang()[layout]
+ lang = 'en'
+ if langs != None:
+ lang = str(langs[0])
+ model = None
+ if i == 0:
+ layout = default_layout
+ model = default_model
+ elif i < len(models):
+ model = models[i]
+ if model == '':
+ model = None
+ model_desc = _("Default Layout")
+ if model != None:
+ model_desc = model_desc + " (" + model + ")"
+ engine = registry.engine_desc_new(lang,
+ layout,
+ _("Default Layout"),
+ model,
+ model_desc,
+ ibus.DEFAULT_BRIDGE_ENGINE_NAME)
+ self.__disabled_engines.append(engine)
+ self.__disabled_engines_id = self.__xkblayout.get_group()
+ if not use_bridge_hotkey:
+ return
+ if self.__disabled_engines != None and self.__disabled_engines != []:
+ component = ibus.Component("org.freedesktop.IBus.XKB",
+ _("XKB Component"),
+ "1.0",
+ "GPL",
+ "Takao Fujiwara",
+ "https://github.com/fujiwarat/ibus/tree/gjs")
+ for engine in self.__disabled_engines:
+ component.add_engine(engine.name,
+ engine.longname,
+ engine.description,
+ engine.language,
+ engine.license,
+ engine.author,
+ engine.icon,
+ engine.layout,
+ engine.hotkeys)
+
+ import xkbfactory
+ self.__factory = xkbfactory.EngineFactory(self.__bus)
+ self.__bus.register_component(component)
+ if not use_bridge_hotkey:
+ return
+ if self.__disabled_engines != None and self.__disabled_engines != []:
+ if self.__focus_ic == None:
+ return
+ engine = self.__focus_ic.get_engine()
+ if engine == None:
+ if self.__disabled_engines_id < 0:
+ self.__disabled_engines_id = 0
+ self.__focus_ic.focus_in()
+ self.__focus_ic.set_engine(self.__disabled_engines[self.__disabled_engines_id])
+ elif engine != None and \
+ not self.__focus_ic.is_enabled():
+ self.__focus_ic.focus_in()
+ self.__focus_ic.enable()
+
def focus_in(self, ic):
self.reset()
self.__focus_ic = ibus.InputContext(self.__bus, ic)
enabled = self.__focus_ic.is_enabled()
- self.__language_bar.set_enabled(enabled)
+ use_bridge_hotkey = self.__use_bridge_hotkey()
+ self.__set_default_layout_engine(use_bridge_hotkey)
+ if use_bridge_hotkey:
+ if self.__show != 1:
+ self.__language_bar.set_enabled(enabled)
+ elif enabled:
+ engine = self.__focus_ic.get_engine()
+ if engine != None and \
+ not engine.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
+ self.__language_bar.set_enabled(enabled)
+ else:
+ self.__language_bar.set_enabled(False)
+ else:
+ self.__language_bar.set_enabled(False)
+ else:
+ self.__language_bar.set_enabled(enabled)
if not enabled:
self.__set_im_icon(ICON_KEYBOARD)
self.__set_im_name(None)
@@ -250,7 +367,7 @@ class Panel(ibus.PanelBase):
self.__set_im_icon(engine.icon)
self.__set_im_name(engine.longname)
if self.__bus.get_use_sys_layout():
- self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine))
+ self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine, False))
else:
self.__set_im_icon(ICON_KEYBOARD)
self.__set_im_name(None)
@@ -260,6 +377,8 @@ class Panel(ibus.PanelBase):
def focus_out(self, ic):
self.reset()
+ if self.__focus_ic and self.__focus_ic.is_enabled():
+ self.__focus_ic.disable()
self.__focus_ic = None
self.__language_bar.set_enabled(False)
self.__language_bar.focus_out()
@@ -273,7 +392,21 @@ class Panel(ibus.PanelBase):
return
enabled = self.__focus_ic.is_enabled()
- self.__language_bar.set_enabled(enabled)
+
+ if self.__use_bridge_hotkey():
+ if self.__show != 1:
+ self.__language_bar.set_enabled(enabled)
+ elif enabled:
+ engine = self.__focus_ic.get_engine()
+ if engine != None and \
+ not engine.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
+ self.__language_bar.set_enabled(enabled)
+ else:
+ self.__language_bar.set_enabled(False)
+ else:
+ self.__language_bar.set_enabled(False)
+ else:
+ self.__language_bar.set_enabled(enabled)
if enabled == False:
self.reset()
@@ -287,7 +420,7 @@ class Panel(ibus.PanelBase):
self.__set_im_icon(engine.icon)
self.__set_im_name(engine.longname)
if self.__bus.get_use_sys_layout():
- self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine))
+ self.__xkblayout.set_layout(self.__engine_get_layout_wrapper(engine, True))
else:
self.__set_im_icon(ICON_KEYBOARD)
self.__set_im_name(None)
@@ -315,6 +448,7 @@ class Panel(ibus.PanelBase):
def __config_load_show(self):
show = self.__config.get_value("panel", "show", 0)
+ self.__show = show
self.__language_bar.set_show(show)
def __config_load_position(self):
@@ -443,6 +577,21 @@ class Panel(ibus.PanelBase):
# menu.set_take_focus(False)
# return menu
+ def __add_engine_in_menu(self, menu, engine, is_bold, size):
+ language = engine.language
+ lang = ibus.get_language_name(language)
+ item = gtk.ImageMenuItem("%s - %s" % (lang, engine.longname))
+ if is_bold:
+ for widget in item.get_children():
+ if isinstance(widget, gtk.Label):
+ widget.set_markup("<b>%s</b>" % widget.get_text())
+ if engine.icon:
+ item.set_image(_icon.IconWidget(engine.icon, size[0]))
+ else:
+ item.set_image(_icon.IconWidget(ICON_ENGINE, size[0]))
+ item.connect("activate", self.__im_menu_item_activate_cb, engine)
+ menu.add(item)
+
def __create_im_menu(self):
engines = self.__bus.list_active_engines()
current_engine = \
@@ -453,25 +602,34 @@ class Panel(ibus.PanelBase):
size = gtk.icon_size_lookup(gtk.ICON_SIZE_MENU)
menu = gtk.Menu()
for i, engine in enumerate(engines):
- lang = ibus.get_language_name(engine.language)
- item = gtk.ImageMenuItem("%s - %s" % (lang, engine.longname))
- if current_engine and current_engine.name == engine.name:
- for widget in item.get_children():
- if isinstance(widget, gtk.Label):
- widget.set_markup("<b>%s</b>" % widget.get_text())
- if engine.icon:
- item.set_image(_icon.IconWidget(engine.icon, size[0]))
- else:
- item.set_image(_icon.IconWidget(ICON_ENGINE, size[0]))
- item.connect("activate", self.__im_menu_item_activate_cb, engine)
- menu.add(item)
+ if self.__use_bridge_hotkey() and \
+ engine.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME) and \
+ self.__disabled_engines != None:
+ engine.is_bridge = True
+ engine.disabled_engines_id = 0
+ for j, kb_engine in enumerate(self.__disabled_engines):
+ if engine.name == kb_engine.name:
+ engine.disabled_engines_id = j
+ break
+ is_bold = True if (current_engine != None and \
+ current_engine.name == engine.name and \
+ j == self.__disabled_engines_id) else False
+ self.__add_engine_in_menu(menu, engine,
+ is_bold,
+ size)
+ continue
+ engine.is_bridge = False
+ is_bold = True if (current_engine != None and \
+ current_engine.name == engine.name) else False
+ self.__add_engine_in_menu(menu, engine, is_bold, size)
item = gtk.ImageMenuItem(_("Turn off input method"))
item.set_image(_icon.IconWidget("gtk-close", size[0]))
item.connect("activate", self.__im_menu_item_activate_cb, None)
if self.__focus_ic == None or not self.__focus_ic.is_enabled():
item.set_sensitive(False)
- menu.add(item)
+ if not self.__use_bridge_hotkey():
+ menu.add(item)
menu.show_all()
menu.set_take_focus(False)
@@ -523,8 +681,25 @@ class Panel(ibus.PanelBase):
if not self.__focus_ic:
return
if engine:
- self.__focus_ic.set_engine(engine)
+ if self.__use_bridge_hotkey() and engine.is_bridge:
+ engines = self.__bus.list_active_engines()
+ current_engine = \
+ (self.__focus_ic != None and self.__focus_ic.get_engine()) or \
+ (engines and engines[0]) or \
+ None
+ if current_engine and \
+ current_engine.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
+ self.__disabled_engines_prev_id = self.__disabled_engines_id
+ self.__disabled_engines_swapped = 0
+ else:
+ self.__disabled_engines_prev_id = -1
+ self.__disabled_engines_id = engine.disabled_engines_id
+ self.__focus_ic.set_engine(self.__disabled_engines[self.__disabled_engines_id])
+ else:
+ self.__disabled_engines_prev_id = -1
+ self.__focus_ic.set_engine(engine)
else:
+ self.__disabled_engines_prev_id = -1
self.__focus_ic.disable()
def __sys_menu_item_activate_cb(self, item, command):
@@ -573,12 +748,85 @@ class Panel(ibus.PanelBase):
self.__setup_pid = pid
glib.child_watch_add(self.__setup_pid, self.__child_watch_cb)
- def __engine_get_layout_wrapper(self, engine):
+ def __get_model_from_layout(self, layout):
+ left_bracket = layout.find('(')
+ right_bracket = layout.find(')')
+ if left_bracket >= 0 and right_bracket > left_bracket:
+ return (layout[:left_bracket] + layout[right_bracket + 1:], \
+ layout[left_bracket + 1:right_bracket])
+ return (layout, "default")
+
+ def __get_option_from_layout(self, layout):
+ left_bracket = layout.find('[')
+ right_bracket = layout.find(']')
+ if left_bracket >= 0 and right_bracket > left_bracket:
+ return (layout[:left_bracket] + layout[right_bracket + 1:], \
+ layout[left_bracket + 1:right_bracket])
+ return (layout, "default")
+
+ def __merge_models_and_options(self, cur_layout, engine_layout):
+ orig_layout = cur_layout
+ engine_model = "default"
+ engine_option = "default"
+ (engine_layout, engine_model) = \
+ self.__get_model_from_layout(engine_layout)
+ (engine_layout, engine_option) = \
+ self.__get_option_from_layout(engine_layout)
+ if (engine_model == None or engine_model == "default") and \
+ (engine_option == None or engine_option == "default"):
+ return cur_layout
+ cur_model = "default"
+ cur_option = "default"
+ (cur_layout, cur_model) = \
+ self.__get_model_from_layout(cur_layout)
+ (cur_layout, cur_option) = \
+ self.__get_option_from_layout(cur_layout)
+ # Currently implemented options only.
+ # Merging layouts and models are a little complicated.
+ # e.g. ja,ru + ja(kana) == ja,ru,ja(,,kana)
+ if engine_option != None and engine_option != "default":
+ if cur_option == None or cur_option == "default":
+ cur_option = engine_option
+ elif cur_option != None and cur_option != "default":
+ cur_option = "%s,%s" % (cur_option, engine_option)
+ if cur_model != None and cur_model != "default":
+ cur_layout = "%s(%s)" % (cur_layout, cur_model)
+ if cur_option != None and cur_option != "default":
+ cur_layout = "%s[%s]" % (cur_layout, cur_option)
+ return cur_layout
+ return orig_layout
+
+ def __engine_get_layout_wrapper(self, engine, changed_state):
# This code is for the back compatibility.
# Should we remove the codes after all IM engines are changed
# to "default" layout?
- if engine.name != None and engine.name.startswith("xkb:layout:"):
+ if engine.name != None and engine.name.startswith("xkb:layout:") and \
+ not self.__use_bridge_hotkey():
+ return engine.layout
+ elif engine.name != None and \
+ engine.name.startswith("xkb:layout:") and \
+ self.__use_bridge_hotkey() and \
+ not engine.name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
return engine.layout
+ elif self.__use_bridge_hotkey() and \
+ self.__disabled_engines_id >= 0 and \
+ self.__disabled_engines != None and \
+ self.__disabled_engines_id < len(self.__disabled_engines):
+ if changed_state and self.__disabled_engines_prev_id != -1:
+ # state_changed is always called twice because we change
+ # the engine. So the first two calls are ignored here.
+ if self.__disabled_engines_swapped < 2:
+ self.__disabled_engines_swapped = \
+ self.__disabled_engines_swapped + 1
+ else:
+ x = self.__disabled_engines_prev_id
+ self.__disabled_engines_prev_id = self.__disabled_engines_id
+ self.__disabled_engines_id = x
+ self.__disabled_engines_swapped = 1
+ retval = self.__disabled_engines[self.__disabled_engines_id].layout
+ if engine.layout != None and engine.layout.startswith("default"):
+ return self.__merge_models_and_options(retval, engine.layout)
+ return retval
elif engine.layout != None and engine.layout.startswith("default"):
return engine.layout
else:
diff --git a/ui/gtk/xkbengine.py b/ui/gtk/xkbengine.py
new file mode 100644
index 0000000..12c07cf
--- /dev/null
+++ b/ui/gtk/xkbengine.py
@@ -0,0 +1,93 @@
+# vim:set et sts=4 sw=4:
+#
+# ibus - The Input Bus
+#
+# Copyright(c) 2011 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright(c) 2011 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright(c) 2011 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or(at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA 02111-1307 USA
+
+import ibus
+
+class Engine(ibus.EngineBase):
+ def __init__(self, bus, object_path):
+ super(Engine, self).__init__(bus, object_path)
+
+ def update_aux_string(self, string, attrs, visible):
+ self.update_auxiliary_text(ibus.Text(string, attrs), visible)
+
+ def page_up(self):
+ return True
+
+ def page_down(self):
+ return True
+
+ def cursor_up(self):
+ return True
+
+ def cursor_down(self):
+ return True
+
+ def candidate_clicked(self, index, button, state):
+ pass
+
+ if ibus.get_version() >= '1.2.0':
+ def process_key_event(self, keyval, keycode, state):
+ try:
+ return self.process_key_event_internal2(keyval, keycode, state)
+ except:
+ import traceback
+ traceback.print_exc()
+ return False
+ else:
+ def process_key_event(self, keyval, state):
+ try:
+ return self.process_key_event_internal2(keyval, 0, state)
+ except:
+ import traceback
+ traceback.print_exc()
+ return False
+
+ def property_activate(self, prop_name, state):
+ pass
+
+ def focus_in(self):
+ pass
+
+ def focus_out(self):
+ pass
+
+ def disable(self):
+ pass
+
+ def reset(self):
+ pass
+
+ def do_destroy(self):
+ super(Engine,self).do_destroy()
+
+#=======================================================================
+ @classmethod
+ def CONFIG_RELOADED(cls, bus):
+ print 'RELOADED'
+
+ @classmethod
+ def CONFIG_VALUE_CHANGED(cls, bus, section, name, value):
+ print 'VALUE_CHAMGED =', section, name, value
+
+ def process_key_event_internal2(self, keyval, keycode, state):
+ return False
diff --git a/ui/gtk/xkbfactory.py b/ui/gtk/xkbfactory.py
new file mode 100644
index 0000000..014e20b
--- /dev/null
+++ b/ui/gtk/xkbfactory.py
@@ -0,0 +1,117 @@
+# vim:set et sts=4 sw=4:
+#
+# ibus - The Input Bus
+#
+# Copyright(c) 2011 Peng Huang <shawn.p.huang@gmail.com>
+# Copyright(c) 2011 Takao Fujiwara <takao.fujiwara1@gmail.com>
+# Copyright(c) 2011 Red Hat, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or(at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+# Boston, MA 02111-1307 USA
+
+import ibus
+import xkbengine
+
+from gettext import dgettext
+_ = lambda a : dgettext("ibus", a)
+N_ = lambda a : a
+
+
+class EngineFactory(ibus.EngineFactoryBase):
+ FACTORY_PATH = "/com/redhat/IBus/engines/XKB/Factory"
+ ENGINE_PATH = "/com/redhat/IBus/engines/XKB/Engine"
+ NAME = "XKBFactory"
+ LANG = "en"
+ ICON = "ibus-engine"
+ AUTHORS = "Takao Fujiwara <takao.fujiwara1@gmail.com>"
+ CREDITS = "GPLv2"
+
+ def __init__(self, bus):
+ self.__bus = bus
+ super(EngineFactory, self).__init__(bus)
+
+ self.__id = 0
+
+ def create_engine(self, engine_name):
+ if engine_name and \
+ engine_name.startswith(ibus.DEFAULT_BRIDGE_ENGINE_NAME):
+
+ self.__id += 1
+ return xkbengine.Engine(self.__bus, "%s/%d" % (self.ENGINE_PATH, self.__id))
+ return super(EngineFactory, self).create_engine(engine_name)
+
+
+def test():
+ import gtk
+ component = ibus.Component("org.freedesktop.IBus.XKB",
+ _("XKB Component"),
+ "1.0",
+ "GPL",
+ "Takao Fujiwara",
+ "https://github.com/fujiwara")
+ engines = []
+ engine = ibus.EngineDesc("xkb:layout:default:jp,us",
+ "Default Layout",
+ "XKB jp,us keyboard layout",
+ "jpn",
+ "LGPL2.1",
+ "fujiwara",
+ "ibus-engine",
+ "jp,us")
+ engines.append(engine)
+ engine = ibus.EngineDesc("xkb:layout:default:us",
+ "Default Layout",
+ "XKB us keyboard layout",
+ "eng",
+ "LGPL2.1",
+ "fujiwara",
+ "ibus-engine",
+ "us")
+ engines.append(engine)
+ for engine in engines:
+ component.add_engine(engine.name,
+ engine.longname,
+ engine.description,
+ engine.language,
+ engine.license,
+ engine.author,
+ engine.icon,
+ engine.layout,
+ engine.hotkeys)
+
+ class TestWindow(gtk.Window):
+ def __init__(self):
+ super(TestWindow, self).__init__()
+ self.__bus = ibus.Bus()
+ self.__bus.connect("disconnected", gtk.main_quit)
+ path = self.__bus.create_input_context("Test")
+ self.__ic = ibus.InputContext(self.__bus, path)
+ self.__ic.set_capabilities(9)
+ factory = EngineFactory(self.__bus)
+ self.__bus.register_component(component)
+ #self.__bus.request_name("org.freedesktop.IBus.XKB", 0)
+ self.connect("focus-in-event", self.__focus_in)
+
+ def __focus_in(self, widget, event):
+ print "focused in"
+ self.__ic.focus_in()
+ self.__ic.set_engine(engines[0])
+
+ window = TestWindow()
+ window.show_all()
+ gtk.main()
+
+if __name__ == "__main__":
+ test()
diff --git a/xkb/Makefile.am b/xkb/Makefile.am
index ad9cdd9..c4d5afb 100644
--- a/xkb/Makefile.am
+++ b/xkb/Makefile.am
@@ -28,6 +28,8 @@ INCLUDES = \
-I$(top_srcdir)/src \
-DIBUS_LOCALEDIR=\"$(datadir)/locale\" \
-DLIBEXECDIR=\""$(libexecdir)"\" \
+ -DUSE_BRIDGE_HOTKEY=$(USE_BRIDGE_HOTKEY) \
+ -DDEFAULT_BRIDGE_ENGINE_NAME=\"$(DEFAULT_BRIDGE_ENGINE_NAME)\" \
$(NULL)
noinst_PROGRAMS = $(TESTS)
diff --git a/xkb/xkbxml.c b/xkb/xkbxml.c
index ad10c28..968fb86 100644
--- a/xkb/xkbxml.c
+++ b/xkb/xkbxml.c
@@ -25,6 +25,7 @@
#endif
#include <glib.h>
+#include <string.h>
#include "xkbxml.h"
#include "ibus.h"
@@ -274,6 +275,7 @@ ibus_xkb_engine_desc_new (const gchar *lang,
gchar *longname = NULL;
gchar *desc = NULL;
gchar *engine_layout = NULL;
+ const gchar *icon = "ibus-engine";
g_return_val_if_fail (lang != NULL && layout != NULL, NULL);
@@ -298,6 +300,12 @@ ibus_xkb_engine_desc_new (const gchar *lang,
desc = g_strdup_printf ("XKB %s keyboard layout", layout);
engine_layout = g_strdup (layout);
}
+#if USE_BRIDGE_HOTKEY
+ if (g_ascii_strncasecmp (name, DEFAULT_BRIDGE_ENGINE_NAME,
+ strlen (DEFAULT_BRIDGE_ENGINE_NAME)) == 0) {
+ icon = "input-keyboard-symbolic";
+ }
+#endif
engine = ibus_engine_desc_new (name,
longname,
@@ -305,7 +313,7 @@ ibus_xkb_engine_desc_new (const gchar *lang,
lang,
"LGPL2.1",
"Takao Fujiwara <takao.fujiwara1@gmail.com>",
- "ibus-engine",
+ icon,
engine_layout);
g_free (name);
--
1.7.5.4