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)
This commit is contained in:
Alexander Larsson 2009-07-09 16:48:22 +02:00
parent 8031432c09
commit 9044ec9bb9
4 changed files with 138 additions and 78 deletions

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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);