gdk: Drop generation of synthesized crossing events on grabs

GDK just needs to care about toplevels nowadays, which means these events
are already delivered from the windowing. We don't need to generate
intra-window crossing events ourselves.
This commit is contained in:
Carlos Garnacho 2017-09-15 18:31:18 +02:00
parent a9988e18b0
commit 3e1f672170
2 changed files with 1 additions and 466 deletions

View File

@ -806,97 +806,6 @@ _gdk_display_end_touch_grab (GdkDisplay *display,
return FALSE;
}
/* _gdk_synthesize_crossing_events only works inside one toplevel.
This function splits things into two calls if needed, converting the
coordinates to the right toplevel */
static void
synthesize_crossing_events (GdkDisplay *display,
GdkDevice *device,
GdkDevice *source_device,
GdkWindow *src_window,
GdkWindow *dest_window,
GdkCrossingMode crossing_mode,
guint32 time,
gulong serial)
{
GdkWindow *src_toplevel, *dest_toplevel;
GdkModifierType state;
double x, y;
if (src_window)
src_toplevel = gdk_window_get_toplevel (src_window);
else
src_toplevel = NULL;
if (dest_window)
dest_toplevel = gdk_window_get_toplevel (dest_window);
else
dest_toplevel = NULL;
if (src_toplevel == NULL && dest_toplevel == NULL)
return;
if (src_toplevel == NULL ||
src_toplevel == dest_toplevel)
{
/* Same toplevels */
gdk_window_get_device_position_double (dest_toplevel,
device,
&x, &y, &state);
_gdk_synthesize_crossing_events (display,
src_window,
dest_window,
device, source_device,
crossing_mode,
x, y, state,
time,
NULL,
serial, FALSE);
}
else if (dest_toplevel == NULL)
{
gdk_window_get_device_position_double (src_toplevel,
device,
&x, &y, &state);
_gdk_synthesize_crossing_events (display,
src_window,
NULL,
device, source_device,
crossing_mode,
x, y, state,
time,
NULL,
serial, FALSE);
}
else
{
/* Different toplevels */
gdk_window_get_device_position_double (src_toplevel,
device,
&x, &y, &state);
_gdk_synthesize_crossing_events (display,
src_window,
NULL,
device, source_device,
crossing_mode,
x, y, state,
time,
NULL,
serial, FALSE);
gdk_window_get_device_position_double (dest_toplevel,
device,
&x, &y, &state);
_gdk_synthesize_crossing_events (display,
NULL,
dest_window,
device, source_device,
crossing_mode,
x, y, state,
time,
NULL,
serial, FALSE);
}
}
static GdkWindow *
get_current_toplevel (GdkDisplay *display,
GdkDevice *device,
@ -932,7 +841,7 @@ switch_to_pointer_grab (GdkDisplay *display,
guint32 time,
gulong serial)
{
GdkWindow *src_window, *pointer_window, *new_toplevel;
GdkWindow *pointer_window, *new_toplevel;
GdkPointerWindowInfo *info;
GList *old_grabs;
GdkModifierType state;
@ -946,26 +855,8 @@ switch_to_pointer_grab (GdkDisplay *display,
if (grab)
{
/* New grab is in effect */
/* We need to generate crossing events for the grab.
* However, there are never any crossing events for implicit grabs
* TODO: ... Actually, this could happen if the pointer window
* doesn't have button mask so a parent gets the event...
*/
if (!grab->implicit)
{
/* We send GRAB crossing events from the window under the pointer to the
grab window. Except if there is an old grab then we start from that */
if (last_grab)
src_window = last_grab->window;
else
src_window = info->window_under_pointer;
if (src_window != grab->window)
synthesize_crossing_events (display, device, source_device,
src_window, grab->window,
GDK_CROSSING_GRAB, time, serial);
/* !owner_event Grabbing a window that we're not inside, current status is
now NULL (i.e. outside grabbed window) */
if (!grab->owner_events && info->window_under_pointer != grab->window)
@ -1029,12 +920,6 @@ switch_to_pointer_grab (GdkDisplay *display,
NULL, NULL);
}
if (!info->need_touch_press_enter &&
pointer_window != last_grab->window)
synthesize_crossing_events (display, device, source_device,
last_grab->window, pointer_window,
GDK_CROSSING_UNGRAB, time, serial);
/* We're now ungrabbed, update the window_under_pointer */
_gdk_display_set_window_under_pointer (display, device, pointer_window);
}

View File

@ -5466,37 +5466,6 @@ point_in_input_window (GdkWindow *window,
return FALSE;
}
static void
convert_toplevel_coords_to_window (GdkWindow *window,
gdouble toplevel_x,
gdouble toplevel_y,
gdouble *window_x,
gdouble *window_y)
{
GdkWindow *parent;
gdouble x, y;
GList *children, *l;
x = toplevel_x;
y = toplevel_y;
children = NULL;
while ((parent = window->parent) != NULL &&
(parent->window_type != GDK_WINDOW_ROOT))
{
children = g_list_prepend (children, window);
window = parent;
}
for (l = children; l != NULL; l = l->next)
gdk_window_coords_from_parent (l->data, x, y, &x, &y);
g_list_free (children);
*window_x = x;
*window_y = y;
}
GdkWindow *
_gdk_window_find_child_at (GdkWindow *window,
double x,
@ -5670,43 +5639,6 @@ gdk_window_get_support_multidevice (GdkWindow *window)
/* send motion events if the right buttons are down */
static GdkWindow *
find_common_ancestor (GdkWindow *win1,
GdkWindow *win2)
{
GdkWindow *tmp;
GList *path1 = NULL, *path2 = NULL;
GList *list1, *list2;
tmp = win1;
while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
{
path1 = g_list_prepend (path1, tmp);
tmp = tmp->parent;
}
tmp = win2;
while (tmp != NULL && tmp->window_type != GDK_WINDOW_ROOT)
{
path2 = g_list_prepend (path2, tmp);
tmp = tmp->parent;
}
list1 = path1;
list2 = path2;
tmp = NULL;
while (list1 && list2 && (list1->data == list2->data))
{
tmp = list1->data;
list1 = list1->next;
list2 = list2->next;
}
g_list_free (path1);
g_list_free (path2);
return tmp;
}
GdkEvent *
_gdk_make_event (GdkWindow *window,
GdkEventType type,
@ -5827,288 +5759,6 @@ _gdk_make_event (GdkWindow *window,
return event;
}
static void
send_crossing_event (GdkDisplay *display,
GdkWindow *toplevel,
GdkWindow *window,
GdkEventType type,
GdkCrossingMode mode,
GdkNotifyType notify_type,
GdkWindow *subwindow,
GdkDevice *device,
GdkDevice *source_device,
gdouble toplevel_x,
gdouble toplevel_y,
GdkModifierType mask,
guint32 time_,
GdkEvent *event_in_queue,
gulong serial)
{
GdkEvent *event;
guint32 window_event_mask, type_event_mask;
GdkDeviceGrabInfo *grab;
GdkTouchGrabInfo *touch_grab = NULL;
GdkPointerWindowInfo *pointer_info;
gboolean block_event = FALSE;
GdkEventSequence *sequence;
grab = _gdk_display_has_device_grab (display, device, serial);
pointer_info = _gdk_display_get_pointer_info (display, device);
sequence = gdk_event_get_event_sequence (event_in_queue);
if (sequence)
touch_grab = _gdk_display_has_touch_grab (display, device, sequence, serial);
if (touch_grab)
{
if (window != touch_grab->window)
return;
window_event_mask = touch_grab->event_mask;
}
else if (grab != NULL &&
!grab->owner_events)
{
/* !owner_event => only report events wrt grab window, ignore rest */
if ((GdkWindow *)window != grab->window)
return;
window_event_mask = grab->event_mask;
}
else
window_event_mask = window->event_mask;
if (type == GDK_ENTER_NOTIFY &&
(pointer_info->need_touch_press_enter ||
(source_device &&
gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN)) &&
mode != GDK_CROSSING_TOUCH_BEGIN &&
mode != GDK_CROSSING_TOUCH_END)
{
pointer_info->need_touch_press_enter = TRUE;
block_event = TRUE;
}
else if (type == GDK_LEAVE_NOTIFY)
{
type_event_mask = GDK_LEAVE_NOTIFY_MASK;
window->devices_inside = g_list_remove (window->devices_inside, device);
if (!window->support_multidevice && window->devices_inside)
{
/* Block leave events unless it's the last pointer */
block_event = TRUE;
}
}
else
{
type_event_mask = GDK_ENTER_NOTIFY_MASK;
if (!window->support_multidevice && window->devices_inside)
{
/* Only emit enter events for the first device */
block_event = TRUE;
}
if (gdk_device_get_device_type (device) == GDK_DEVICE_TYPE_MASTER &&
gdk_device_get_mode (device) != GDK_MODE_DISABLED &&
!g_list_find (window->devices_inside, device))
window->devices_inside = g_list_prepend (window->devices_inside, device);
}
if (block_event)
return;
if (window_event_mask & type_event_mask)
{
event = _gdk_make_event ((GdkWindow *)window, type, event_in_queue, TRUE);
gdk_event_set_device (event, device);
gdk_event_set_seat (event, gdk_device_get_seat (device));
if (source_device)
gdk_event_set_source_device (event, source_device);
event->crossing.time = time_;
event->crossing.subwindow = subwindow;
if (subwindow)
g_object_ref (subwindow);
convert_toplevel_coords_to_window ((GdkWindow *)window,
toplevel_x, toplevel_y,
&event->crossing.x, &event->crossing.y);
event->crossing.x_root = toplevel_x + toplevel->x;
event->crossing.y_root = toplevel_y + toplevel->y;
event->crossing.mode = mode;
event->crossing.detail = notify_type;
event->crossing.focus = FALSE;
event->crossing.state = mask;
}
}
/* The coordinates are in the toplevel window that src/dest are in.
* src and dest are always (if != NULL) in the same toplevel, as
* we get a leave-notify and set the window_under_pointer to null
* before crossing to another toplevel.
*/
void
_gdk_synthesize_crossing_events (GdkDisplay *display,
GdkWindow *src,
GdkWindow *dest,
GdkDevice *device,
GdkDevice *source_device,
GdkCrossingMode mode,
double toplevel_x,
double toplevel_y,
GdkModifierType mask,
guint32 time_,
GdkEvent *event_in_queue,
gulong serial,
gboolean non_linear)
{
GdkWindow *c;
GdkWindow *win, *last, *next;
GList *path, *list;
GdkWindow *a;
GdkWindow *b;
GdkWindow *toplevel;
GdkNotifyType notify_type;
/* TODO: Don't send events to toplevel, as we get those from the windowing system */
a = (src && GDK_IS_WINDOW (src)) ? src : NULL;
b = (dest && GDK_IS_WINDOW (dest)) ? dest : NULL;
if (src == dest)
return; /* No crossings generated between src and dest */
if (gdk_device_get_device_type (device) != GDK_DEVICE_TYPE_MASTER)
{
if (a && gdk_window_get_device_events (src, device) == 0)
a = NULL;
if (b && gdk_window_get_device_events (dest, device) == 0)
b = NULL;
}
if (!a && !b)
return;
c = find_common_ancestor (a, b);
non_linear |= (c != a) && (c != b);
if (a) /* There might not be a source (i.e. if no previous pointer_in_window) */
{
toplevel = gdk_window_get_toplevel (a);
/* Traverse up from a to (excluding) c sending leave events */
if (non_linear)
notify_type = GDK_NOTIFY_NONLINEAR;
else if (c == a)
notify_type = GDK_NOTIFY_INFERIOR;
else
notify_type = GDK_NOTIFY_ANCESTOR;
send_crossing_event (display, toplevel,
a, GDK_LEAVE_NOTIFY,
mode,
notify_type,
NULL, device, source_device,
toplevel_x, toplevel_y,
mask, time_,
event_in_queue,
serial);
if (c != a)
{
if (non_linear)
notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
else
notify_type = GDK_NOTIFY_VIRTUAL;
last = a;
win = a->parent;
while (win != c && win->window_type != GDK_WINDOW_ROOT)
{
send_crossing_event (display, toplevel,
win, GDK_LEAVE_NOTIFY,
mode,
notify_type,
(GdkWindow *)last,
device, source_device,
toplevel_x, toplevel_y,
mask, time_,
event_in_queue,
serial);
last = win;
win = win->parent;
}
}
}
if (b) /* Might not be a dest, e.g. if we're moving out of the window */
{
toplevel = gdk_window_get_toplevel ((GdkWindow *)b);
/* Traverse down from c to b */
if (c != b)
{
path = NULL;
win = b->parent;
while (win != c && win->window_type != GDK_WINDOW_ROOT)
{
path = g_list_prepend (path, win);
win = win->parent;
}
if (non_linear)
notify_type = GDK_NOTIFY_NONLINEAR_VIRTUAL;
else
notify_type = GDK_NOTIFY_VIRTUAL;
list = path;
while (list)
{
win = list->data;
list = list->next;
if (list)
next = list->data;
else
next = b;
send_crossing_event (display, toplevel,
win, GDK_ENTER_NOTIFY,
mode,
notify_type,
(GdkWindow *)next,
device, source_device,
toplevel_x, toplevel_y,
mask, time_,
event_in_queue,
serial);
}
g_list_free (path);
}
if (non_linear)
notify_type = GDK_NOTIFY_NONLINEAR;
else if (c == a)
notify_type = GDK_NOTIFY_ANCESTOR;
else
notify_type = GDK_NOTIFY_INFERIOR;
send_crossing_event (display, toplevel,
b, GDK_ENTER_NOTIFY,
mode,
notify_type,
NULL,
device, source_device,
toplevel_x, toplevel_y,
mask, time_,
event_in_queue,
serial);
}
}
void
_gdk_display_set_window_under_pointer (GdkDisplay *display,
GdkDevice *device,