summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeng Huang <shawn.p.huang@gmail.com>2010-07-23 16:11:22 +0800
committerPeng Huang <shawn.p.huang@gmail.com>2010-07-30 17:57:56 +0800
commit519e649849d7ce1f1550f5a653238080f3b0f67e (patch)
treebcbbcae06ca30d1a92fa3577eb1e6a56fe9f43bb
parent3609568f318b0d6ae831d0d4eb2a24398f81531f (diff)
downloadibus-519e649849d7ce1f1550f5a653238080f3b0f67e.tar.gz
Support switching keyboard by hotkey without input focus Add fake input context in im module. The fake input context will hold the focus if no other input context has focus. This change for fixing input method switch issue if no focus input context.
BUG=http://crosbug.com/4381 Review URL: http://codereview.chromium.org/3052003
-rw-r--r--bus/inputcontext.c6
-rw-r--r--bus/inputcontext.h3
-rw-r--r--client/gtk2/ibusimcontext.c108
3 files changed, 91 insertions, 26 deletions
diff --git a/bus/inputcontext.c b/bus/inputcontext.c
index 10cb6257..4e56a6ec 100644
--- a/bus/inputcontext.c
+++ b/bus/inputcontext.c
@@ -171,6 +171,9 @@ bus_input_context_new (BusConnection *connection,
context->connection = connection;
context->client = g_strdup (client);
+ /* it is a fake input context, just need process hotkey */
+ context->fake = (g_strcmp0 (client, "fake") == 0);
+
g_signal_connect (context->connection,
"destroy",
(GCallback) _connection_destroy_cb,
@@ -701,7 +704,8 @@ _ic_process_key_event (BusInputContext *context,
}
}
- if (context->has_focus && context->enabled && context->engine) {
+ /* ignore key events, if it is a fake input context */
+ if (context->has_focus && context->enabled && context->engine && context->fake == FALSE) {
CallData *call_data;
call_data = g_slice_new (CallData);
diff --git a/bus/inputcontext.h b/bus/inputcontext.h
index ba3fdb27..ebbe4ba8 100644
--- a/bus/inputcontext.h
+++ b/bus/inputcontext.h
@@ -88,6 +88,9 @@ struct _BusInputContext {
/* filter release */
gboolean filter_release;
+
+ /* is fake context */
+ gboolean fake;
};
struct _BusInputContextClass {
diff --git a/client/gtk2/ibusimcontext.c b/client/gtk2/ibusimcontext.c
index 2bd37a9d..f0f0f97d 100644
--- a/client/gtk2/ibusimcontext.c
+++ b/client/gtk2/ibusimcontext.c
@@ -79,6 +79,7 @@ static const gchar *_snooper_apps = SNOOPER_APPS;
static gboolean _use_key_snooper = ENABLE_SNOOPER;
static GtkIMContext *_focus_im_context = NULL;
+static IBusInputContext *_fake_context = NULL;
/* functions prototype */
static void ibus_im_context_class_init (IBusIMContextClass *klass);
@@ -130,6 +131,7 @@ static void _slave_delete_surrounding_cb
gint offset_from_cursor,
guint nchars,
IBusIMContext *context);
+static void _create_fake_input_context (void);
@@ -204,15 +206,21 @@ _key_snooper_cb (GtkWidget *widget,
IDEBUG ("%s", __FUNCTION__);
gboolean retval = FALSE;
- IBusIMContext *ibusimcontext = (IBusIMContext *)_focus_im_context;
+ IBusIMContext *ibusimcontext = (IBusIMContext *) _focus_im_context;
+ IBusInputContext *ibuscontext = NULL;
- if (G_UNLIKELY (!_use_key_snooper))
- return retval;
-
- if (ibusimcontext == NULL)
- return FALSE;
+ if (ibusimcontext != NULL &&
+ ibusimcontext->has_focus == TRUE) {
+ /* has IC with focus and use_key_snooper is true */
+ if (_use_key_snooper)
+ ibuscontext = ibusimcontext->ibuscontext;
+ }
+ else {
+ /* If no IC has focus, and fake IC has been created, then pass key events to fake IC. */
+ ibuscontext = _fake_context;
+ }
- if (G_UNLIKELY (ibusimcontext->ibuscontext == NULL || ibusimcontext->has_focus == FALSE))
+ if (ibuscontext == NULL)
return FALSE;
if (G_UNLIKELY (event->state & IBUS_HANDLED_MASK))
@@ -223,13 +231,13 @@ _key_snooper_cb (GtkWidget *widget,
switch (event->type) {
case GDK_KEY_RELEASE:
- retval = ibus_input_context_process_key_event (ibusimcontext->ibuscontext,
+ retval = ibus_input_context_process_key_event (ibuscontext,
event->keyval,
event->hardware_keycode - 8,
event->state | IBUS_RELEASE_MASK);
break;
case GDK_KEY_PRESS:
- retval = ibus_input_context_process_key_event (ibusimcontext->ibuscontext,
+ retval = ibus_input_context_process_key_event (ibuscontext,
event->keyval,
event->hardware_keycode - 8,
event->state);
@@ -326,10 +334,19 @@ ibus_im_context_class_init (IBusIMContextClass *klass)
}
}
- IDEBUG ("snooper = %d", _use_key_snooper);
- if (_use_key_snooper) {
- gtk_key_snooper_install (_key_snooper_cb, NULL);
+ /* init bus object */
+ if (_bus == NULL) {
+ ibus_set_display (gdk_display_get_name (gdk_display_get_default ()));
+ _bus = ibus_bus_new();
}
+
+ if (ibus_bus_is_connected (_bus)) {
+ _create_fake_input_context ();
+ }
+ g_signal_connect (_bus, "connected", G_CALLBACK (_bus_connected_cb), NULL);
+
+ /* always install snooper */
+ gtk_key_snooper_install (_key_snooper_cb, NULL);
}
static void
@@ -388,12 +405,6 @@ ibus_im_context_init (GObject *obj)
G_CALLBACK (_slave_delete_surrounding_cb),
ibusimcontext);
- /* init bus object */
- if (_bus == NULL) {
- ibus_set_display (gdk_display_get_name (gdk_display_get_default ()));
- _bus = ibus_bus_new();
- }
-
if (ibus_bus_is_connected (_bus)) {
_create_input_context (ibusimcontext);
}
@@ -538,7 +549,12 @@ ibus_im_context_focus_out (GtkIMContext *context)
if (ibusimcontext->ibuscontext) {
ibus_input_context_focus_out (ibusimcontext->ibuscontext);
}
+
gtk_im_context_focus_out (ibusimcontext->slave);
+
+ /* focus in the fake ic */
+ if (_fake_context)
+ ibus_input_context_focus_in (_fake_context);
}
static void
@@ -684,10 +700,10 @@ _bus_connected_cb (IBusBus *bus,
IBusIMContext *ibusimcontext)
{
IDEBUG ("%s", __FUNCTION__);
- g_assert (IBUS_IS_IM_CONTEXT (ibusimcontext));
- g_assert (ibusimcontext->ibuscontext == NULL);
-
- _create_input_context (ibusimcontext);
+ if (ibusimcontext)
+ _create_input_context (ibusimcontext);
+ else
+ _create_fake_input_context ();
}
static void
@@ -746,11 +762,10 @@ _create_gdk_event (IBusIMContext *ibusimcontext,
{
gunichar c = 0;
gchar buf[8];
- GdkEventKey *event;
- event = (GdkEventKey *)gdk_event_new ((state & IBUS_RELEASE_MASK) ? GDK_KEY_RELEASE : GDK_KEY_PRESS);
+ GdkEventKey *event = (GdkEventKey *)gdk_event_new ((state & IBUS_RELEASE_MASK) ? GDK_KEY_RELEASE : GDK_KEY_PRESS);
- if (ibusimcontext->client_window)
+ if (ibusimcontext && ibusimcontext->client_window)
event->window = g_object_ref (ibusimcontext->client_window);
event->time = GDK_CURRENT_TIME;
event->send_event = FALSE;
@@ -1116,3 +1131,46 @@ _slave_delete_surrounding_cb (GtkIMContext *slave,
g_signal_emit (ibusimcontext, _signal_delete_surrounding_id, 0, offset_from_cursor, nchars, &return_value);
}
+#ifdef OS_CHROMEOS
+static void
+_ibus_fake_context_destroy_cb (IBusInputContext *ibuscontext,
+ gpointer user_data)
+{
+ /* The fack IC may be destroyed when the connection is lost.
+ * Should release it. */
+ g_assert (ibuscontext == _fake_context);
+ g_object_unref (_fake_context);
+ _fake_context = NULL;
+}
+
+static void
+_create_fake_input_context (void)
+{
+ g_return_if_fail (_fake_context == NULL);
+
+ /* Global engine is always enabled in Chrome OS,
+ * so create fake IC, and set focus if no other IC has focus.
+ */
+ _fake_context = ibus_bus_create_input_context (_bus, "fake");
+ g_return_if_fail (_fake_context != NULL);
+ g_object_ref_sink (_fake_context);
+
+ g_signal_connect (_fake_context, "forward-key-event",
+ G_CALLBACK (_ibus_context_forward_key_event_cb),
+ NULL);
+ g_signal_connect (_fake_context, "destroy",
+ G_CALLBACK (_ibus_fake_context_destroy_cb),
+ NULL);
+
+ guint32 caps = IBUS_CAP_PREEDIT_TEXT | IBUS_CAP_FOCUS | IBUS_CAP_SURROUNDING_TEXT;
+ ibus_input_context_set_capabilities (_fake_context, caps);
+
+ ibus_input_context_focus_in (_fake_context);
+}
+#else
+static void
+_create_fake_input_context (void)
+{
+ /* For Linux desktop, do not use fake IC. */
+}
+#endif