if (grab == NULL) /* Ungrabbed, send events */
{
- pointer_window = NULL;
- if (new_toplevel)
- {
- /* Find (possibly virtual) child window */
- pointer_window =
- _gdk_window_find_descendant_at (new_toplevel,
- x, y,
- NULL, NULL);
- }
+ /* If the source device is a touch device, do not
+ * propagate any enter event yet, until one is
+ * synthesized when needed.
+ */
+ if (source_device &&
+ (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN ||
+ gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHPAD))
+ info->need_touch_press_enter = TRUE;
+
+ pointer_window = NULL;
+
+ if (new_toplevel &&
+ !info->need_touch_press_enter)
+ {
+ /* Find (possibly virtual) child window */
+ pointer_window =
+ _gdk_window_find_descendant_at (new_toplevel,
+ x, y,
+ NULL, NULL);
+ }
if (pointer_window != last_grab->window)
synthesize_crossing_events (display, device, source_device,
* @GDK_CROSSING_GTK_UNGRAB: crossing because a GTK+ grab is deactivated.
* @GDK_CROSSING_STATE_CHANGED: crossing because a GTK+ widget changed
* state (e.g. sensitivity).
+ * @GDK_CROSSING_TOUCH_BEGIN: crossing because a touch sequence has begun,
+ * this event is synthetic as the pointer might have not left the window.
+ * @GDK_CROSSING_TOUCH_END: crossing because a touch sequence has ended,
+ * this event is synthetic as the pointer might have not left the window.
+ * @GDK_CROSSING_DEVICE_SWITCH: crossing because of a device switch (i.e.
+ * a mouse taking control of the pointer after a touch device), this event
+ * is synthetic as the pointer didn't leave the window.
*
* Specifies the crossing mode for #GdkEventCrossing.
*/
GDK_CROSSING_UNGRAB,
GDK_CROSSING_GTK_GRAB,
GDK_CROSSING_GTK_UNGRAB,
- GDK_CROSSING_STATE_CHANGED
+ GDK_CROSSING_STATE_CHANGED,
+ GDK_CROSSING_TOUCH_BEGIN,
+ GDK_CROSSING_TOUCH_END,
+ GDK_CROSSING_DEVICE_SWITCH
} GdkCrossingMode;
/**
GdkEvent *event;
guint32 window_event_mask, type_event_mask;
GdkDeviceGrabInfo *grab;
+ GdkPointerWindowInfo *pointer_info;
gboolean block_event = FALSE;
grab = _gdk_display_has_device_grab (display, device, serial);
+ pointer_info = _gdk_display_get_pointer_info (display, device);
if (grab != NULL &&
!grab->owner_events)
else
window_event_mask = window->event_mask;
- if (type == GDK_LEAVE_NOTIFY)
+ if (type == GDK_ENTER_NOTIFY &&
+ pointer_info->need_touch_press_enter &&
+ mode != GDK_CROSSING_TOUCH_BEGIN &&
+ mode != GDK_CROSSING_TOUCH_END)
+ {
+ 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);
guint state;
gdouble toplevel_x, toplevel_y;
guint32 time_;
- gboolean non_linear;
+ gboolean non_linear, need_synthetic_enter = FALSE;
event_window = source_event->any.window;
gdk_event_get_coords (source_event, &toplevel_x, &toplevel_y);
source_event->crossing.detail == GDK_NOTIFY_NONLINEAR_VIRTUAL))
non_linear = TRUE;
+ if (pointer_info->need_touch_press_enter &&
+ gdk_device_get_source (pointer_info->last_slave) != GDK_SOURCE_TOUCHSCREEN &&
+ gdk_device_get_source (pointer_info->last_slave) != GDK_SOURCE_TOUCHPAD)
+
+ {
+ pointer_info->need_touch_press_enter = FALSE;
+ need_synthetic_enter = TRUE;
+ }
+
/* If we get crossing events with subwindow unexpectedly being NULL
that means there is a native subwindow that gdk doesn't know about.
We track these and forward them, with the correct virtual window
gdk_window_get_device_events (event_win, device) == 0)
return TRUE;
+ /* The last device to interact with the window was a touch device,
+ * which synthesized a leave notify event, so synthesize another enter
+ * notify to tell the pointer is on the window.
+ */
+ if (need_synthetic_enter)
+ _gdk_synthesize_crossing_events (display,
+ NULL, pointer_window,
+ device, source_device,
+ GDK_CROSSING_DEVICE_SWITCH,
+ toplevel_x, toplevel_y,
+ state, time_, NULL,
+ serial, FALSE);
is_hint = FALSE;
if (event_win &&
GdkWindow *pointer_window;
GdkWindow *parent;
GdkEvent *event;
+ GdkPointerWindowInfo *pointer_info;
guint state;
guint32 time_;
GdkEventType type;
toplevel_window = convert_native_coords_to_toplevel (event_window,
toplevel_x, toplevel_y,
&toplevel_x, &toplevel_y);
+ pointer_info = _gdk_display_get_pointer_info (display, device);
if (type == GDK_BUTTON_PRESS &&
!source_event->any.send_event &&
gdk_window_get_device_events (event_win, device) == 0)
return TRUE;
+ if (type == GDK_BUTTON_PRESS &&
+ pointer_info->need_touch_press_enter)
+ {
+ GdkCrossingMode mode;
+
+ /* The last device to interact with the window was a touch device,
+ * which synthesized a leave notify event, so synthesize another enter
+ * notify to tell the pointer is on the window.
+ */
+ if (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN ||
+ gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHPAD)
+ mode = GDK_CROSSING_TOUCH_BEGIN;
+ else
+ mode = GDK_CROSSING_DEVICE_SWITCH;
+
+ pointer_info->need_touch_press_enter = FALSE;
+ _gdk_synthesize_crossing_events (display,
+ NULL,
+ pointer_info->window_under_pointer,
+ device, source_device, mode,
+ toplevel_x, toplevel_y,
+ state, time_, source_event,
+ serial, FALSE);
+ }
+
event = _gdk_make_event (event_win, type, source_event, FALSE);
switch (type)
gdk_event_set_source_device (event, source_device);
if (type == GDK_BUTTON_PRESS)
- _gdk_event_button_generate (display, event);
+ _gdk_event_button_generate (display, event);
+ else if (type == GDK_BUTTON_RELEASE &&
+ pointer_window == pointer_info->window_under_pointer &&
+ (gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHSCREEN ||
+ gdk_device_get_source (source_device) == GDK_SOURCE_TOUCHPAD))
+ {
+ /* Synthesize a leave notify event
+ * whenever a touch device is released
+ */
+ pointer_info->need_touch_press_enter = TRUE;
+ _gdk_synthesize_crossing_events (display,
+ pointer_window, NULL,
+ device, source_device,
+ GDK_CROSSING_TOUCH_END,
+ toplevel_x, toplevel_y,
+ state, time_, NULL,
+ serial, FALSE);
+ }
return TRUE;
case GDK_SCROLL: