Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/gtk+/ChangeLog,v
retrieving revision 1.6286.2.213
diff -u -p -r1.6286.2.213 ChangeLog
--- ChangeLog	3 May 2005 01:51:41 -0000	1.6286.2.213
+++ ChangeLog	4 May 2005 20:59:25 -0000
@@ -1,3 +1,9 @@
+2005-05-04  Owen Taylor  <otaylor@redhat.com>
+
+	* gdk/x11/gdkevents-x11.c gdk/x11/gdkwindow-x11.h: Fix a bug
+	in focus tracking when we move between has_pointer_focus and 
+	has_focus_window directly.
+
 2005-05-02  Federico Mena Quintero  <federico@ximian.com>
 
 	* tests/testfilechooser.c: Oops, remove mtrace() stuff.
Index: gdk/x11/gdkevents-x11.c
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkevents-x11.c,v
retrieving revision 1.144.2.2
diff -u -p -r1.144.2.2 gdkevents-x11.c
--- gdk/x11/gdkevents-x11.c	16 Mar 2005 03:25:09 -0000	1.144.2.2
+++ gdk/x11/gdkevents-x11.c	4 May 2005 20:59:25 -0000
@@ -1218,16 +1218,19 @@ gdk_event_translate (GdkDisplay *display
         }
       
       /* Handle focusing (in the case where no window manager is running */
-      if (toplevel &&
-	  xevent->xcrossing.detail != NotifyInferior &&
-	  xevent->xcrossing.focus && !toplevel->has_focus_window)
+      if (toplevel && xevent->xcrossing.detail != NotifyInferior)
 	{
-	  gboolean had_focus = HAS_FOCUS (toplevel);
-
-	  toplevel->has_pointer_focus = TRUE;
+	  toplevel->has_pointer = TRUE;
 
-	  if (HAS_FOCUS (toplevel) != had_focus)
-	    generate_focus_event (window, TRUE);
+	  if (xevent->xcrossing.focus && !toplevel->has_focus_window)
+	    {
+	      gboolean had_focus = HAS_FOCUS (toplevel);
+	      
+	      toplevel->has_pointer_focus = TRUE;
+	      
+	      if (HAS_FOCUS (toplevel) != had_focus)
+		generate_focus_event (window, TRUE);
+	    }
 	}
 
       /* Tell XInput stuff about it if appropriate */
@@ -1312,16 +1315,19 @@ gdk_event_translate (GdkDisplay *display
         }
       
       /* Handle focusing (in the case where no window manager is running */
-      if (toplevel &&
-	  xevent->xcrossing.detail != NotifyInferior &&
-	  xevent->xcrossing.focus && !toplevel->has_focus_window)
+      if (toplevel && xevent->xcrossing.detail != NotifyInferior)
 	{
-	  gboolean had_focus = HAS_FOCUS (toplevel);
-	  
-	  toplevel->has_pointer_focus = FALSE;
-	  
-	  if (HAS_FOCUS (toplevel) != had_focus)
-	    generate_focus_event (window, FALSE);
+	  toplevel->has_pointer = FALSE;
+
+	  if (xevent->xcrossing.focus && !toplevel->has_focus_window)
+	    {
+	      gboolean had_focus = HAS_FOCUS (toplevel);
+	      
+	      toplevel->has_pointer_focus = FALSE;
+	      
+	      if (HAS_FOCUS (toplevel) != had_focus)
+		generate_focus_event (window, FALSE);
+	    }
 	}
 
       event->crossing.type = GDK_LEAVE_NOTIFY;
@@ -1404,8 +1410,19 @@ gdk_event_translate (GdkDisplay *display
 	  switch (xevent->xfocus.detail)
 	    {
 	    case NotifyAncestor:
-	    case NotifyNonlinear:
 	    case NotifyVirtual:
+	      /* When the focus moves from an ancestor of the window to
+	       * the window or a descendent of the window, *and* the
+	       * pointer is inside the window, then we were previously
+	       * receiving keystroke events in the has_pointer_focus
+	       * case and are now receiving them in the
+	       * has_focus_window case.
+	       */
+	      if (toplevel->has_pointer)
+		toplevel->has_pointer_focus = FALSE;
+	      
+	      /* fall through */
+	    case NotifyNonlinear:
 	    case NotifyNonlinearVirtual:
 	      toplevel->has_focus_window = TRUE;
 	      /* We pretend that the focus moves to the grab
@@ -1447,8 +1464,19 @@ gdk_event_translate (GdkDisplay *display
 	  switch (xevent->xfocus.detail)
 	    {
 	    case NotifyAncestor:
-	    case NotifyNonlinear:
 	    case NotifyVirtual:
+	      /* When the focus moves from the window or a descendent
+	       * of the window to an ancestor of the window, *and* the
+	       * pointer is inside the window, then we were previously
+	       * receiving keystroke events in the has_focus_window
+	       * case and are now receiving them in the
+	       * has_pointer_focus case.
+	       */
+	      if (toplevel->has_pointer)
+		toplevel->has_pointer_focus = TRUE;
+
+	      /* fall through */
+	    case NotifyNonlinear:
 	    case NotifyNonlinearVirtual:
 	      toplevel->has_focus_window = FALSE;
 	      if (xevent->xfocus.mode != NotifyWhileGrabbed)
Index: gdk/x11/gdkwindow-x11.h
===================================================================
RCS file: /cvs/gnome/gtk+/gdk/x11/gdkwindow-x11.h,v
retrieving revision 1.18
diff -u -p -r1.18 gdkwindow-x11.h
--- gdk/x11/gdkwindow-x11.h	18 Oct 2004 21:02:37 -0000	1.18
+++ gdk/x11/gdkwindow-x11.h	4 May 2005 20:59:25 -0000
@@ -96,9 +96,14 @@ struct _GdkToplevelX11
    */
   guint has_focus : 1;
 
-  /* Set if !window->has_focus_window, but events are being sent to the
-   * window because the pointer is in it. (Typically, no window
-   * manager is running.
+  /* Set if the pointer is inside this window. (This is needed for
+   * for focus tracking)
+   */
+  guint has_pointer : 1;
+  
+  /* Set if the window is a descendent of the focus window and the pointer is
+   * inside it. (This is the case where the window will receive keystroke
+   * events even window->has_focus_window is FALSE)
    */
   guint has_pointer_focus : 1;
 
