[gtk+] Correctly set enter/leave events as detail=nonlinear



commit 9044ec9bb9b1d08bd6674f17c7ea25fdbe3ac1ab
Author: Alexander Larsson <alexl redhat com>
Date:   Thu Jul 9 16:48:22 2009 +0200

    Correctly set enter/leave events as detail=nonlinear
    
    If we get a nonlinear enter/leave notify on the toplevel we need
    to set nonlinear in all the events we send, even if the in-toplevel
    tree is linear.
    
    This fixes combobox menus popping down immediately when you click
    (not hold). (bug #587559)

 gdk/gdkdisplay.c   |   56 ++++++++++++++++----------------
 gdk/gdkinternals.h |   19 ++++++-----
 gdk/gdkwindow.c    |   91 ++++++++++++++++++++++++++++-----------------------
 gtk/gtkmenu.c      |   50 ++++++++++++++++++++++++++++
 4 files changed, 138 insertions(+), 78 deletions(-)
---
diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c
index d599ba7..399d193 100644
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@ -856,26 +856,26 @@ synthesize_crossing_events (GdkDisplay *display,
       gdk_window_get_pointer (dest_toplevel,
 			      &x, &y, &state);
       _gdk_synthesize_crossing_events (display,
-				      src_window,
-				      dest_window,
-				      crossing_mode,
-				      x, y, state,
-				      time,
-				      NULL,
-				      serial);
+				       src_window,
+				       dest_window,
+				       crossing_mode,
+				       x, y, state,
+				       time,
+				       NULL,
+				       serial, FALSE);
     }
   else if (dest_toplevel == NULL)
     {
       gdk_window_get_pointer (src_toplevel,
 			      &x, &y, &state);
       _gdk_synthesize_crossing_events (display,
-				      src_window,
-				      NULL,
-				      crossing_mode,
-				      x, y, state,
-				      time,
-				      NULL,
-				      serial);
+				       src_window,
+				       NULL,
+				       crossing_mode,
+				       x, y, state,
+				       time,
+				       NULL,
+				       serial, FALSE);
     }
   else
     {
@@ -883,23 +883,23 @@ synthesize_crossing_events (GdkDisplay *display,
       gdk_window_get_pointer (src_toplevel,
 			      &x, &y, &state);
       _gdk_synthesize_crossing_events (display,
-				      src_window,
-				      NULL,
-				      crossing_mode,
-				      x, y, state,
-				      time,
-				      NULL,
-				      serial);
+				       src_window,
+				       NULL,
+				       crossing_mode,
+				       x, y, state,
+				       time,
+				       NULL,
+				       serial, FALSE);
       gdk_window_get_pointer (dest_toplevel,
 			      &x, &y, &state);
       _gdk_synthesize_crossing_events (display,
-				      NULL,
-				      dest_window,
-				      crossing_mode,
-				      x, y, state,
-				      time,
-				      NULL,
-				      serial);
+				       NULL,
+				       dest_window,
+				       crossing_mode,
+				       x, y, state,
+				       time,
+				       NULL,
+				       serial, FALSE);
     }
 }
 
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index c984386..6d1a4d0 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -628,15 +628,16 @@ GdkEvent * _gdk_make_event (GdkWindow    *window,
 			    gboolean      before_event);
 
 void _gdk_synthesize_crossing_events (GdkDisplay                 *display,
-				     GdkWindow                  *src,
-				     GdkWindow                  *dest,
-				     GdkCrossingMode             mode,
-				     gint                        toplevel_x,
-				     gint                        toplevel_y,
-				     GdkModifierType             mask,
-				     guint32                     time_,
-				     GdkEvent                   *event_in_queue,
-				     gulong                      serial);
+				      GdkWindow                  *src,
+				      GdkWindow                  *dest,
+				      GdkCrossingMode             mode,
+				      gint                        toplevel_x,
+				      gint                        toplevel_y,
+				      GdkModifierType             mask,
+				      guint32                     time_,
+				      GdkEvent                   *event_in_queue,
+				      gulong                      serial,
+				      gboolean                    non_linear);
 void _gdk_display_set_window_under_pointer (GdkDisplay *display,
 					    GdkWindow *window);
 
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index bd253c7..dd7df89 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -8494,20 +8494,20 @@ send_crossing_event (GdkDisplay                 *display,
  */
 void
 _gdk_synthesize_crossing_events (GdkDisplay                 *display,
-				GdkWindow                  *src,
-				GdkWindow                  *dest,
-				GdkCrossingMode             mode,
-				gint                        toplevel_x,
-				gint                        toplevel_y,
-				GdkModifierType             mask,
-				guint32                     time_,
-				GdkEvent                   *event_in_queue,
-				gulong                      serial)
+				 GdkWindow                  *src,
+				 GdkWindow                  *dest,
+				 GdkCrossingMode             mode,
+				 gint                        toplevel_x,
+				 gint                        toplevel_y,
+				 GdkModifierType             mask,
+				 guint32                     time_,
+				 GdkEvent                   *event_in_queue,
+				 gulong                      serial,
+				 gboolean                    non_linear)
 {
   GdkWindowObject *c;
   GdkWindowObject *win, *last, *next;
   GList *path, *list;
-  gboolean non_linear;
   GdkWindowObject *a;
   GdkWindowObject *b;
   GdkWindowObject *toplevel;
@@ -8522,7 +8522,7 @@ _gdk_synthesize_crossing_events (GdkDisplay                 *display,
 
   c = find_common_ancestor (a, b);
 
-  non_linear = (c != a) && (c != b);
+  non_linear |= (c != a) && (c != b);
 
   if (a) /* There might not be a source (i.e. if no previous pointer_in_window) */
     {
@@ -8821,15 +8821,16 @@ do_synthesize_crossing_event (gpointer data)
 	  display->pointer_info.window_under_pointer)
 	{
 	  _gdk_synthesize_crossing_events (display,
-					  display->pointer_info.window_under_pointer,
-					  new_window_under_pointer,
-					  GDK_CROSSING_NORMAL,
-					  display->pointer_info.toplevel_x,
-					  display->pointer_info.toplevel_y,
-					  display->pointer_info.state,
-					  GDK_CURRENT_TIME,
-					  NULL,
-					  serial);
+					   display->pointer_info.window_under_pointer,
+					   new_window_under_pointer,
+					   GDK_CROSSING_NORMAL,
+					   display->pointer_info.toplevel_x,
+					   display->pointer_info.toplevel_y,
+					   display->pointer_info.state,
+					   GDK_CURRENT_TIME,
+					   NULL,
+					   serial,
+					   FALSE);
 	  _gdk_display_set_window_under_pointer (display, new_window_under_pointer);
 	}
     }
@@ -8939,6 +8940,7 @@ proxy_pointer_event (GdkDisplay                 *display,
   guint state;
   gdouble toplevel_x, toplevel_y;
   guint32 time_;
+  gboolean non_linear;
 
   event_window = source_event->any.window;
   gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
@@ -8948,6 +8950,12 @@ proxy_pointer_event (GdkDisplay                 *display,
 						       toplevel_x, toplevel_y,
 						       &toplevel_x, &toplevel_y);
 
+  non_linear = FALSE;
+  if ((source_event->type == GDK_LEAVE_NOTIFY ||
+       source_event->type == GDK_ENTER_NOTIFY) &&
+      (source_event->crossing.detail == GDK_NOTIFY_NONLINEAR ||
+       source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))
+    non_linear = TRUE;
 
   /* If we get crossing events with subwindow unexpectedly being NULL
      that means there is a native subwindow that gdk doesn't know about.
@@ -8968,13 +8976,14 @@ proxy_pointer_event (GdkDisplay                 *display,
       /* Send leave events from window under pointer to event window
 	 that will get the subwindow == NULL window */
       _gdk_synthesize_crossing_events (display,
-				      display->pointer_info.window_under_pointer,
-				      event_window,
-				      source_event->crossing.mode,
-				      toplevel_x, toplevel_y,
-				      state, time_,
-				      source_event,
-				      serial);
+				       display->pointer_info.window_under_pointer,
+				       event_window,
+				       source_event->crossing.mode,
+				       toplevel_x, toplevel_y,
+				       state, time_,
+				       source_event,
+				       serial,
+				       non_linear);
 
       /* Send subwindow == NULL event */
       send_crossing_event (display,
@@ -9020,13 +9029,13 @@ proxy_pointer_event (GdkDisplay                 *display,
 
       /* Send enter events from event window to pointer_window */
       _gdk_synthesize_crossing_events (display,
-				      event_window,
-				      pointer_window,
-				      source_event->crossing.mode,
-				      toplevel_x, toplevel_y,
-				      state, time_,
-				      source_event,
-				      serial);
+				       event_window,
+				       pointer_window,
+				       source_event->crossing.mode,
+				       toplevel_x, toplevel_y,
+				       state, time_,
+				       source_event,
+				       serial, non_linear);
       _gdk_display_set_window_under_pointer (display, pointer_window);
       return TRUE;
     }
@@ -9038,13 +9047,13 @@ proxy_pointer_event (GdkDisplay                 *display,
 
       /* Different than last time, send crossing events */
       _gdk_synthesize_crossing_events (display,
-				      display->pointer_info.window_under_pointer,
-				      pointer_window,
-				      GDK_CROSSING_NORMAL,
-				      toplevel_x, toplevel_y,
-				      state, time_,
-				      source_event,
-				      serial);
+				       display->pointer_info.window_under_pointer,
+				       pointer_window,
+				       GDK_CROSSING_NORMAL,
+				       toplevel_x, toplevel_y,
+				       state, time_,
+				       source_event,
+				       serial, non_linear);
       _gdk_display_set_window_under_pointer (display, pointer_window);
     }
   else if (source_event->type == GDK_MOTION_NOTIFY)
diff --git a/gtk/gtkmenu.c b/gtk/gtkmenu.c
index 0fd5d3d..98aeb21 100644
--- a/gtk/gtkmenu.c
+++ b/gtk/gtkmenu.c
@@ -3792,6 +3792,47 @@ gtk_menu_handle_scrolling (GtkMenu *menu,
     }
 }
 
+static char *mode[] = {
+  "GDK_CROSSING_NORMAL",
+  "GDK_CROSSING_GRAB",
+  "GDK_CROSSING_UNGRAB",
+  "GDK_CROSSING_GTK_GRAB",
+  "GDK_CROSSING_GTK_UNGRAB",
+  "GDK_CROSSING_STATE_CHANGED",
+  NULL
+};
+
+static char *detail[] = {
+  "GDK_NOTIFY_ANCESTOR",
+  "GDK_NOTIFY_VIRTUAL",
+  "GDK_NOTIFY_INFERIOR",
+  "GDK_NOTIFY_NONLINEAR",
+  "GDK_NOTIFY_NONLINEAR_VIRTUAL",
+  "GDK_NOTIFY_UNKNOWN",
+  NULL
+};
+
+char *
+get_window_name (GtkWidget *widget, GdkWindow *window)
+{
+  GtkMenu *menu;
+  gpointer w;
+  menu = GTK_MENU (widget);
+  
+  if (window == widget->window)
+    return "widget->window";
+
+  if (window == menu->view_window)
+    return "menu->view_window";
+  
+  if (window == menu->bin_window)
+    return "menu->bin_window";
+
+  gdk_window_get_user_data (window, &w);
+  
+  return g_type_name_from_instance (w);
+}
+
 static gboolean
 gtk_menu_enter_notify (GtkWidget        *widget,
 		       GdkEventCrossing *event)
@@ -3804,6 +3845,10 @@ gtk_menu_enter_notify (GtkWidget        *widget,
       event->mode == GDK_CROSSING_STATE_CHANGED)
     return TRUE;
 
+  g_print ("menu ENTER notify for %s mode: %s, detail %s\n",
+	   get_window_name (widget, event->window),
+	   mode[event->mode], detail[event->detail]);
+  
   g_object_get (gtk_widget_get_settings (widget),
                 "gtk-touchscreen-mode", &touchscreen_mode,
                 NULL);
@@ -3846,6 +3891,7 @@ gtk_menu_enter_notify (GtkWidget        *widget,
 		   * far enough away from the enter point. (see
 		   * gtk_menu_motion_notify())
 		   */
+		  g_print ("user-enter, not pop-under\n");
 		  menu_shell->activate_time = 0;
 		}
 	    }
@@ -3880,6 +3926,10 @@ gtk_menu_leave_notify (GtkWidget        *widget,
       event->mode == GDK_CROSSING_STATE_CHANGED)
     return TRUE;
 
+  g_print ("menu LEAVE notify for %s mode: %s, detail %s\n",
+	   get_window_name (widget, event->window),
+	   mode[event->mode], detail[event->detail]);
+
   menu = GTK_MENU (widget);
   menu_shell = GTK_MENU_SHELL (widget); 
   



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]