[uim-commit] r2997 - trunk/gtk

ekato at freedesktop.org ekato at freedesktop.org
Thu Jan 26 07:38:18 PST 2006


Author: ekato
Date: 2006-01-26 07:38:13 -0800 (Thu, 26 Jan 2006)
New Revision: 2997

Modified:
   trunk/gtk/gtk-im-uim.c
Log:
* gtk/gtk-im-uim.c : Disable snooper by default.  Instead, bind
  key event at the toplevel widget.
(cur_toplevel) : New static variable for IM_UIM_USE_TOPLEVEL.
(cur_key_press_handler_id) : Ditto.
(cur_key_release_handler_id) : Ditto.
(_IMUIMContext) : Remove unused toplevel member.  Add widget,
  in_toplevel, and event_rec for IM_UIM_USE_TOPLEVEL.
(focus_in) : Connect to key-press and key-release event of
  toplevel widget if IM_UIM_USE_TOPLEVEL.
(focus_out) : Remove key handler for toplevel.
(update_in_toplevel) : New.  Update in_toplevel if define
  IM_UIM_USE_TOPLEVEL.
(widget_for_window) : New.  Get top level widget for gdkwindow.
(on_client_widget_hierarchy_changed) : New.  Call
  update_in_toplevel().
(update_client_widget) : New for IM_UIM_USE_TOPLEVEL.
(set_client_window) : Call update_client_window() if define
  IM_UIM_USE_TOPLEVEL.
(im_uim_init) : Initialize variables for IM_UIM_USE_TOPLEVEL.
(handle_key_on_toplevel) : New.


Modified: trunk/gtk/gtk-im-uim.c
===================================================================
--- trunk/gtk/gtk-im-uim.c	2006-01-26 08:31:23 UTC (rev 2996)
+++ trunk/gtk/gtk-im-uim.c	2006-01-26 15:38:13 UTC (rev 2997)
@@ -57,6 +57,9 @@
 #include "caret-state-indicator.h"
 #include "key-util-gtk.h"
 
+#define IM_UIM_USE_SNOOPER	0
+#define IM_UIM_USE_TOPLEVEL	1
+
 /* exported symbols */
 GtkIMContext *im_module_create(const gchar *context_id);
 void im_module_list(const GtkIMContextInfo ***contexts, int *n_contexts);
@@ -68,7 +71,13 @@
 
 static int im_uim_fd = -1;
 static unsigned int read_tag;
+#if IM_UIM_USE_SNOOPER
 static guint snooper_id;
+#elif IM_UIM_USE_TOPLEVEL
+static GtkWidget *cur_toplevel;
+gulong cur_key_press_handler_id;
+gulong cur_key_release_handler_id;
+#endif
 
 struct preedit_segment {
   int attr;
@@ -87,7 +96,7 @@
 
   GtkWidget *menu;
   GdkWindow *win;
-  GdkWindow *toplevel;
+
   GtkWidget *caret_state_indicator;
   GdkRectangle preedit_pos;
 
@@ -95,13 +104,21 @@
   GtkWidget *preedit_window;
   gulong preedit_handler_id;
 
+#if IM_UIM_USE_TOPLEVEL
+  GtkWidget *widget;
+  gboolean in_toplevel;
+  GdkEventKey event_rec;
+#endif
+
   struct _IMUIMContext *prev, *next;
 } IMUIMContext;
 
 static IMUIMContext context_list;
 static IMUIMContext *focused_context = NULL;
 static gboolean disable_focused_context = FALSE;
+#if IM_UIM_USE_SNOOPER
 static gboolean snooper_installed = FALSE;
+#endif
 
 static GObjectClass *parent_class;
 
@@ -123,7 +140,11 @@
 
 static void im_uim_parse_helper_str(const char *str);
 static gboolean get_user_defined_color(PangoColor *color, const gchar *uim_symbol);
+#if IM_UIM_USE_SNOOPER
 static gboolean uim_key_snoop(GtkWidget *grab_widget, GdkEventKey *key, gpointer data);
+#elif IM_UIM_USE_TOPLEVEL
+static gboolean handle_key_on_toplevel(GtkWidget *widget, GdkEventKey *event, gpointer data);
+#endif
 
 static const GTypeInfo class_info = {
   sizeof(IMContextUIMClass),
@@ -235,15 +256,28 @@
 }
 
 /*
- * KEY EVENT HANDLER
+ * filter key event handler
+ * 
+ * uim uses key snooper or toplevel key event for IM.  So filter key
+ * event is just for fallbacks.
+ *
  */
 static gboolean
 filter_keypress(GtkIMContext *ic, GdkEventKey *key)
 {
   IMUIMContext *uic = IM_UIM_CONTEXT(ic);
 
-  /* Hack for combination of xchat + GTK+ 2.6 */
-  if (snooper_installed == FALSE) {
+#if IM_UIM_USE_SNOOPER
+  if (!snooper_installed) {
+#elif IM_UIM_USE_TOPLEVEL
+  /*
+   * Sometimes key events are emitted from other than top level
+   * widget, so check time of the event and hardware_keycode...
+   */
+  if (!cur_toplevel || ((key->time != uic->event_rec.time) && (key->hardware_keycode != key->hardware_keycode))) {
+#else
+  if (TRUE) {
+#endif
     int rv, kv, mod;
 
     im_uim_convert_keyevent(key, &kv, &mod);
@@ -258,7 +292,6 @@
 
     return TRUE;
   }
-  /* Hack for combination of xchat + GTK+ 2.6 */
 
   return gtk_im_context_filter_keypress(uic->slave, key);
 }
@@ -419,16 +452,29 @@
 {
   IMUIMContext *uic = IM_UIM_CONTEXT(ic);
   IMUIMContext *cc;
+#if IM_UIM_USE_TOPLEVEL
+  GtkWidget *toplevel;
+#endif
 
   focused_context = uic;
   disable_focused_context = FALSE;
 
-  /* XXX:Use of key snooper is not recommended way!! */
+#if IM_UIM_USE_SNOOPER
+  /* Using key snooper is not recommended */
   if (snooper_installed == FALSE) {
     snooper_id = gtk_key_snooper_install((GtkKeySnoopFunc)uim_key_snoop, NULL );
     snooper_installed = TRUE;
   }
+#elif IM_UIM_USE_TOPLEVEL
+  toplevel = gtk_widget_get_toplevel(uic->widget);
+  cur_toplevel = toplevel;
 
+  if (toplevel && GTK_WIDGET_TOPLEVEL(toplevel)) {
+    cur_key_press_handler_id = g_signal_connect(cur_toplevel, "key-press-event", G_CALLBACK(handle_key_on_toplevel), uic);
+    cur_key_release_handler_id = g_signal_connect(cur_toplevel, "key-release-event", G_CALLBACK(handle_key_on_toplevel), uic);
+  }
+#endif
+
   check_helper_connection();
 
   uim_helper_client_focus_in(uic->uc);
@@ -450,10 +496,18 @@
 {
   IMUIMContext *uic = IM_UIM_CONTEXT(ic);
 
+#if IM_UIM_USE_SNOOPER
   if (snooper_installed == TRUE) {
     gtk_key_snooper_remove(snooper_id);
     snooper_installed = FALSE;
   }
+#elif IM_UIM_USE_TOPLEVEL
+  if (cur_toplevel) {
+    g_signal_handler_disconnect(cur_toplevel, cur_key_press_handler_id);
+    g_signal_handler_disconnect(cur_toplevel, cur_key_release_handler_id);
+    cur_toplevel = NULL;
+  }
+#endif
 
   check_helper_connection();
   uim_helper_client_focus_out(uic->uc);
@@ -561,8 +615,59 @@
   return GDK_FILTER_CONTINUE;
 }
 
+#if IM_UIM_USE_TOPLEVEL
+static void
+update_in_toplevel(IMUIMContext *uic)
+{
+  if (uic->widget) {
+    GtkWidget *toplevel = gtk_widget_get_toplevel(uic->widget);
+    uic->in_toplevel = (toplevel && GTK_WIDGET_TOPLEVEL(toplevel));
+  } else {
+    uic->in_toplevel = FALSE;
+  }
+}
 
+static GtkWidget *
+widget_for_window (GdkWindow *window)
+{
+  while (window) {
+    gpointer user_data;
+    gdk_window_get_user_data (window, &user_data);
+    if (user_data)
+      return user_data;
+
+    window = gdk_window_get_parent (window);
+  }
+
+  return NULL;
+}
+
 static void
+on_client_widget_hierarchy_changed(GtkWidget *widget, GtkWidget *old_toplevel, IMUIMContext *uic)
+{
+  update_in_toplevel(uic);
+}
+
+static void
+update_client_widget(IMUIMContext *uic)
+{
+  GtkWidget *new_widget = widget_for_window(uic->win);
+  
+  if (new_widget != uic->widget) {
+    if (uic->widget)
+      g_signal_handlers_disconnect_by_func(uic->widget,
+		      (gpointer)on_client_widget_hierarchy_changed, uic);
+    uic->widget = new_widget;
+    if (uic->widget)
+      g_signal_connect(uic->widget, "hierarchy-changed",
+		      G_CALLBACK(on_client_widget_hierarchy_changed), uic);
+
+    update_in_toplevel(uic);
+  }
+}
+#endif /* IM_UIM_USE_TOPLEVEL */
+
+static void
 set_client_window(GtkIMContext *ic, GdkWindow *w)
 {
   IMUIMContext *uic = IM_UIM_CONTEXT(ic);
@@ -575,6 +680,9 @@
       g_object_unref(uic->win);
     uic->win = NULL;
   }
+#if IM_UIM_USE_TOPLEVEL
+  update_client_widget(uic);
+#endif
 }
 
 static void
@@ -589,6 +697,10 @@
 im_uim_init(IMUIMContext *uic)
 {
   uic->win = NULL;
+#if IM_UIM_USE_TOPLEVEL
+  uic->widget = NULL;
+  uic->in_toplevel = FALSE;
+#endif
   uic->menu = NULL;
   uic->caret_state_indicator = NULL;
   uic->pseg = NULL;
@@ -1070,7 +1182,8 @@
   g_source_remove(read_tag);
 }
 
-/* XXX:This is not a recommended way!! */
+#if IM_UIM_USE_SNOOPER
+/* snooper is not recommended! */
 static gboolean
 uim_key_snoop(GtkWidget *grab_widget, GdkEventKey *key, gpointer data)
 {
@@ -1091,7 +1204,45 @@
 
   return FALSE;
 }
+#endif
 
+#if IM_UIM_USE_TOPLEVEL
+static gboolean
+handle_key_on_toplevel(GtkWidget *widget, GdkEventKey *event, gpointer data)
+{
+  IMUIMContext *uic = data;
+  GtkWindow *window = GTK_WINDOW(widget);
+
+  if (focused_context == uic) {
+    int rv, kv, mod;
+
+    uic->event_rec.time = event->time;
+    uic->event_rec.hardware_keycode = event->hardware_keycode;
+
+    im_uim_convert_keyevent(event, &kv, &mod);
+
+    if (event->type == GDK_KEY_RELEASE)
+      rv = uim_release_key(focused_context->uc, kv, mod);
+    else
+      rv = uim_press_key(focused_context->uc, kv, mod);
+
+    if (rv)
+      return gtk_window_activate_key(window, event);
+#if 0
+    if (GTK_IS_TEXT_VIEW(uic->widget))
+      GTK_TEXT_VIEW(uic->widget)->need_im_reset = TRUE;
+    else if (GTK_IS_ENTRY(uic->widget)) {
+      if (GTK_ENTRY(uic->widget)->editable)
+	GTK_ENTRY(uic->widget)->need_im_reset = TRUE;
+    }
+#endif
+    return TRUE;
+  }
+
+  return FALSE;
+}
+#endif
+
 void
 im_module_init(GTypeModule *type_module)
 {
@@ -1104,9 +1255,11 @@
 					    "GtkIMContextUIM", &class_info, 0);
   uim_cand_win_gtk_register_type(type_module);
 
-  /* XXX:This is not recommended way!! */
+#if IM_UIM_USE_SNOOPER
+  /* Using snooper is not recommended! */
   snooper_id = gtk_key_snooper_install((GtkKeySnoopFunc)uim_key_snoop, NULL );
   snooper_installed = TRUE;
+#endif
 
   im_uim_init_modifier_keys();
 }
@@ -1117,6 +1270,8 @@
   if (im_uim_fd != -1)
     uim_helper_close_client_fd(im_uim_fd);
 
+#if IM_UIM_USE_SNOOPER
   gtk_key_snooper_remove(snooper_id);
+#endif
   uim_quit();
 }



More information about the uim-commit mailing list