Use gtk key snooper to get the key events.
authorPeng Huang <shawn.p.huang@gmail.com>
Sun, 29 Mar 2009 05:44:25 +0000 (13:44 +0800)
committerPeng Huang <shawn.p.huang@gmail.com>
Sun, 29 Mar 2009 05:44:25 +0000 (13:44 +0800)
client/gtk2/ibusimcontext.c

index b542bd3..f99e60a 100644 (file)
@@ -32,6 +32,7 @@ struct _IBusIMContext {
     /* instance members */
     GtkIMContext *slave;
     GdkWindow *client_window;
+    GdkWindow *event_window;
 
     /* enabled */
     gboolean        enable;
@@ -62,6 +63,7 @@ static guint    _signal_preedit_end_id = 0;
 static guint    _signal_delete_surrounding_id = 0;
 static guint    _signal_retrieve_surrounding_id = 0;
 static GQuark   _q_ibus_im_context = 0;
+static gboolean _use_key_snooper = TRUE;
 
 /* functions prototype */
 static void     ibus_im_context_class_init  (IBusIMContextClass    *klass);
@@ -81,6 +83,10 @@ static void     ibus_im_context_get_preedit_string
 static void     ibus_im_context_set_client_window
                                             (GtkIMContext           *context,
                                              GdkWindow              *client);
+
+static void     ibus_im_context_set_event_window
+                                            (IBusIMContext          *ibusimcontext,
+                                             GdkWindow              *client);
 static void     ibus_im_context_set_cursor_location
                                             (GtkIMContext           *context,
                                              GdkRectangle           *area);
@@ -175,6 +181,30 @@ ibus_im_context_new (void)
     return obj;
 }
 
+static gint
+_key_snooper_cb (GtkWidget   *widget,
+                 GdkEventKey *event,
+                 gpointer     user_data)
+{
+    GdkWindow *gdkwindow;
+    GtkIMContext *imcontext;
+
+    if (!_use_key_snooper)
+        return 0;
+
+    gdkwindow = gtk_widget_get_window (widget);
+
+    if (gdkwindow == NULL)
+        return 0;
+
+    imcontext = (GtkIMContext *) g_object_get_qdata ((GObject *) gdkwindow, _q_ibus_im_context);
+
+    if (imcontext == NULL)
+        return 0;
+
+    return gtk_im_context_filter_keypress (imcontext, event);
+}
+
 static void
 ibus_im_context_class_init     (IBusIMContextClass *klass)
 {
@@ -218,6 +248,10 @@ ibus_im_context_class_init     (IBusIMContextClass *klass)
     g_assert (_signal_retrieve_surrounding_id != 0);
 
     _q_ibus_im_context = g_quark_from_static_string ("IBusIMContext");
+
+    if (_use_key_snooper) {
+        gtk_key_snooper_install (_key_snooper_cb, NULL);
+    }
 }
 
 static void
@@ -227,6 +261,7 @@ ibus_im_context_init (GObject *obj)
     IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (obj);
 
     ibusimcontext->client_window = NULL;
+    ibusimcontext->event_window = NULL;
 
     // Init ibus status
     ibusimcontext->enable = FALSE;
@@ -300,13 +335,12 @@ ibus_im_context_finalize (GObject *obj)
         ibus_object_destroy ((IBusObject *)ibusimcontext->ibuscontext);
     }
 
-    g_object_unref (ibusimcontext->slave);
+    ibus_im_context_set_client_window ((GtkIMContext *)ibusimcontext, NULL);
+    ibus_im_context_set_event_window (ibusimcontext, NULL);
 
-    if (ibusimcontext->client_window) {
-        if (g_object_steal_qdata ((GObject *) ibusimcontext->client_window, _q_ibus_im_context) == ibusimcontext) {
-            g_object_unref (ibusimcontext);
-        }
-        g_object_unref (ibusimcontext->client_window);
+    if (ibusimcontext->slave) {
+        g_object_unref (ibusimcontext->slave);
+        ibusimcontext->slave = NULL;
     }
 
     // release preedit
@@ -322,13 +356,17 @@ ibus_im_context_finalize (GObject *obj)
 
 static gboolean
 ibus_im_context_filter_keypress (GtkIMContext *context,
-                GdkEventKey  *event)
+                                 GdkEventKey  *event)
 {
     g_return_val_if_fail (context != NULL, FALSE);
     g_return_val_if_fail (IBUS_IS_IM_CONTEXT (context), FALSE);
 
     IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context);
 
+    if (event->window != ibusimcontext->client_window && event->window != ibusimcontext->event_window) {
+        ibus_im_context_set_event_window (ibusimcontext, event->window);
+    }
+
     if (ibusimcontext->ibuscontext && ibusimcontext->has_focus) {
         /* If context does not have focus, ibus will process key event in sync mode.
          * It is a workaround for increase search in treeview.
@@ -454,7 +492,7 @@ ibus_im_context_get_preedit_string (GtkIMContext   *context,
 
 
 static void
-ibus_im_context_set_client_window  (GtkIMContext *context, GdkWindow *client)
+ibus_im_context_set_client_window (GtkIMContext *context, GdkWindow *client)
 {
     g_return_if_fail (context != NULL);
     g_return_if_fail (IBUS_IS_IM_CONTEXT (context));
@@ -462,20 +500,47 @@ ibus_im_context_set_client_window  (GtkIMContext *context, GdkWindow *client)
     IBusIMContext *ibusimcontext = IBUS_IM_CONTEXT (context);
 
     if (ibusimcontext->client_window) {
-        if (g_object_steal_qdata ((GObject *) ibusimcontext->client_window, _q_ibus_im_context) == ibusimcontext) {
-            g_object_unref (ibusimcontext);
+        if (g_object_get_qdata ((GObject *) ibusimcontext->client_window, _q_ibus_im_context) == ibusimcontext) {
+            g_object_set_qdata ((GObject *) ibusimcontext->client_window, _q_ibus_im_context, NULL);
         }
         g_object_unref (ibusimcontext->client_window);
     }
 
+    ibus_im_context_set_event_window (ibusimcontext, NULL);
+
     if (client) {
         g_object_ref (client);
-        g_object_ref (context);
+        g_object_ref (ibusimcontext);
         g_object_set_qdata_full ((GObject *) client, _q_ibus_im_context, context, g_object_unref);
     }
 
     ibusimcontext->client_window = client;
-    gtk_im_context_set_client_window (ibusimcontext->slave, client);
+
+    if (ibusimcontext->slave)
+        gtk_im_context_set_client_window (ibusimcontext->slave, client);
+}
+
+static void
+ibus_im_context_set_event_window (IBusIMContext *ibusimcontext, GdkWindow *window)
+{
+    if (ibusimcontext->event_window) {
+        if (g_object_get_qdata ((GObject *) ibusimcontext->event_window, _q_ibus_im_context) == ibusimcontext) {
+            g_object_set_qdata ((GObject *) ibusimcontext->event_window, _q_ibus_im_context, NULL);
+        }
+        g_object_unref (ibusimcontext->event_window);
+        ibusimcontext->event_window = NULL;
+    }
+
+    if (window == ibusimcontext->client_window)
+        window = NULL;
+
+    if (window != NULL) {
+        g_object_ref (window);
+        g_object_ref (ibusimcontext);
+        g_object_set_qdata_full ((GObject *) window, _q_ibus_im_context, ibusimcontext, g_object_unref);
+    }
+
+    ibusimcontext->event_window = window;
 }
 
 static void