This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[gui][patch] filter out one set of window focus events


Hello,

I committed the attached patch to java-gui-branch.

We were receiving two sets of focus-in and focus-out events whenever a
top-level window gained or lost focus.  The two sets of events were
coming from the window manager.  When a top-level window becomes active,
the window manager first gives it the input focus by calling
XSetInputFocus.  Then the window manager sends the WM_TAKE_FOCUS client
message to the window.

The WM_TAKE_FOCUS message tells the client that it may transfer focus
from the top-level window to one of the sub-windows within the
top-level.  Usually GTK handles this message by transferring focus from
the top-level itself to its "default" widget -- that is, the widget that
will be activated when the user presses Enter.

The AWT has its own focus subsystem so we don't want GTK to handle
WM_TAKE_FOCUS, though we may want to handle it ourselves eventually.  In
the meantime this patch filters the message out completely.

Tom

2004-03-11  Thomas Fitzsimmons  <fitzsim@redhat.com>

	* jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c
	(window_wm_protocols_filter): New function.
	(window_focus_in_cb): Remove function.
	(window_focus_out_cb): Likewise.
	(window_focus_or_active_state_change_cb): New function.
	(create): Add filter that removes WM_TAKE_FOCUS client messages.
	(connectSignals): Don't attach handlers to focus-in-event or
	focus-out-event signals.  Handle notify signal.

Index: jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c,v
retrieving revision 1.24
diff -u -r1.24 gnu_java_awt_peer_gtk_GtkWindowPeer.c
--- jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c	29 Jan 2004 14:34:31 -0000	1.24
+++ jni/gtk-peer/gnu_java_awt_peer_gtk_GtkWindowPeer.c	11 Mar 2004 23:28:30 -0000
@@ -44,6 +44,12 @@
 #include <gdk/gdkx.h>
 #include <X11/Xatom.h>
 
+static int filter_added = 0;
+
+static GdkFilterReturn window_wm_protocols_filter (GdkXEvent *xev,
+                                                   GdkEvent  *event,
+                                                   gpointer   data);
+
 static void window_get_frame_extents (GtkWidget *window,
                                       int *top, int *left,
                                       int *bottom, int *right);
@@ -59,12 +65,9 @@
 static void window_destroy_cb (GtkWidget *widget, GdkEvent *event,
 			       jobject peer);
 static void window_show_cb (GtkWidget *widget, jobject peer);
-static gboolean window_focus_in_cb (GtkWidget * widget,
-				    GdkEventFocus *event,
-				    jobject peer);
-static gboolean window_focus_out_cb (GtkWidget * widget,
-				     GdkEventFocus *event,
-				     jobject peer);
+static void window_focus_or_active_state_change_cb (GtkWidget *widget,
+                                                    GParamSpec *pspec,
+                                                    jobject peer);
 static gboolean window_window_state_cb (GtkWidget *widget,
 					GdkEvent *event,
 					jobject peer);
@@ -147,6 +150,20 @@
   insets[2] = bottom;
   insets[3] = right;
 
+  /* We must filter out WM_TAKE_FOCUS messages.  Otherwise we get two
+     focus in events when a window becomes active and two focus out
+     events when a window becomes inactive. */
+  if (!filter_added)
+    {
+      GdkAtom wm_protocols_atom =
+        gdk_x11_xatom_to_atom (gdk_x11_get_xatom_by_name ("WM_PROTOCOLS"));
+
+      gdk_add_client_message_filter (wm_protocols_atom,
+                                     window_wm_protocols_filter,
+                                     NULL);
+      filter_added = 1;
+    }
+
   gdk_threads_leave ();
 
   (*env)->ReleaseIntArrayElements (env, jinsets, insets, 0);
@@ -251,11 +268,8 @@
   g_signal_connect (G_OBJECT (ptr), "show",
 		    G_CALLBACK (window_show_cb), *gref);
 
-  g_signal_connect (G_OBJECT (ptr), "focus-in-event",
-		    G_CALLBACK (window_focus_in_cb), *gref);
-
-  g_signal_connect (G_OBJECT (ptr), "focus-out-event",
-		    G_CALLBACK (window_focus_out_cb), *gref);
+  g_signal_connect (G_OBJECT (ptr), "notify",
+		    G_CALLBACK (window_focus_or_active_state_change_cb), *gref);
 
   g_signal_connect (G_OBJECT (ptr), "window-state-event",
 		    G_CALLBACK (window_window_state_cb), *gref);
@@ -661,40 +675,37 @@
 			      (jobject) NULL, (jint) 0);
 }
 
-static gboolean
-window_focus_in_cb (GtkWidget * widget __attribute__((unused)),
-		    GdkEventFocus *event __attribute__((unused)),
-		    jobject peer)
-{
-  /* FIXME: when hiding then showing, we get two sets of
-     (LOST_FOCUS/DEACTIVATED, ACTIVATED/GAINED_FOCUS) events. */
-  (*gdk_env)->CallVoidMethod (gdk_env, peer,
-			      postWindowEventID,
-			      (jint) AWT_WINDOW_ACTIVATED,
-			      (jobject) NULL, (jint) 0);
-
-  (*gdk_env)->CallVoidMethod (gdk_env, peer,
-			      postWindowEventID,
-			      (jint) AWT_WINDOW_GAINED_FOCUS,
-			      (jobject) NULL, (jint) 0);
-  return TRUE;
-}
-
-static gboolean
-window_focus_out_cb (GtkWidget * widget __attribute__((unused)),
-		     GdkEventFocus *event __attribute__((unused)),
-		     jobject peer)
+static void
+window_focus_or_active_state_change_cb (GtkWidget *widget,
+                                        GParamSpec *pspec,
+                                        jobject peer)
 {
-  (*gdk_env)->CallVoidMethod (gdk_env, peer,
-			      postWindowEventID,
-			      (jint) AWT_WINDOW_LOST_FOCUS,
-			      (jobject) NULL, (jint) 0);
-
-  (*gdk_env)->CallVoidMethod (gdk_env, peer,
-			      postWindowEventID,
-			      (jint) AWT_WINDOW_DEACTIVATED,
-			      (jobject) NULL, (jint) 0);
-  return TRUE;
+  if (!strcmp (g_param_spec_get_name (pspec), "is-active"))
+    {
+      if (GTK_WINDOW (widget)->is_active)
+        (*gdk_env)->CallVoidMethod (gdk_env, peer,
+                                    postWindowEventID,
+                                    (jint) AWT_WINDOW_GAINED_FOCUS,
+                                    (jobject) NULL, (jint) 0);
+      else
+        (*gdk_env)->CallVoidMethod (gdk_env, peer,
+                                    postWindowEventID,
+                                    (jint) AWT_WINDOW_DEACTIVATED,
+                                    (jobject) NULL, (jint) 0);
+    }
+  else if (!strcmp (g_param_spec_get_name (pspec), "has-toplevel-focus"))
+    {
+      if (GTK_WINDOW (widget)->has_toplevel_focus)
+        (*gdk_env)->CallVoidMethod (gdk_env, peer,
+                                    postWindowEventID,
+                                    (jint) AWT_WINDOW_ACTIVATED,
+                                    (jobject) NULL, (jint) 0);
+      else
+        (*gdk_env)->CallVoidMethod (gdk_env, peer,
+                                    postWindowEventID,
+                                    (jint) AWT_WINDOW_LOST_FOCUS,
+                                    (jobject) NULL, (jint) 0);
+    }
 }
 
 static gboolean
@@ -820,4 +831,17 @@
 				(jint) extents[1]); /* right */
 
   return FALSE;
+}
+
+static GdkFilterReturn
+window_wm_protocols_filter (GdkXEvent *xev,
+                            GdkEvent  *event __attribute__((unused)),
+                            gpointer data __attribute__((unused)))
+{
+  XEvent *xevent = (XEvent *)xev;
+
+  if ((Atom) xevent->xclient.data.l[0] == gdk_x11_get_xatom_by_name ("WM_TAKE_FOCUS"))
+    return GDK_FILTER_REMOVE;
+
+  return GDK_FILTER_CONTINUE;
 }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]