Commit 8689921b authored by Carlos Garnacho's avatar Carlos Garnacho Committed by Matthias Clasen

gdk: Generate crossing events around touch devices' press/release

Anytime a touch device interacts, the crossing events generation
will change to a touch mode where only events with mode
GDK_CROSSING_TOUCH_BEGIN/END are handled, and those are sent
around touch begin/end. Those are virtual as the master
device may still stay on the window.

Whenever there is a switch of slave device (the user starts
using another non-touch device), a crossing event with mode
GDK_CROSSING_DEVICE_SWITCH may generated if needed, and the normal
crossing event handling is resumed.
parent 9f4bfff1
......@@ -895,15 +895,26 @@ switch_to_pointer_grab (GdkDisplay *display,
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,
......
......@@ -74,6 +74,7 @@ typedef struct
guint32 state;
guint32 button;
GdkDevice *last_slave;
guint need_touch_press_enter : 1;
} GdkPointerWindowInfo;
typedef struct
......
......@@ -399,6 +399,13 @@ typedef enum
* @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.
*/
......@@ -409,7 +416,10 @@ typedef enum
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;
/**
......
......@@ -8337,9 +8337,11 @@ send_crossing_event (GdkDisplay *display,
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)
......@@ -8352,7 +8354,14 @@ send_crossing_event (GdkDisplay *display,
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);
......@@ -9176,7 +9185,7 @@ proxy_pointer_event (GdkDisplay *display,
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);
......@@ -9196,6 +9205,15 @@ proxy_pointer_event (GdkDisplay *display,
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
......@@ -9319,6 +9337,18 @@ proxy_pointer_event (GdkDisplay *display,
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 &&
......@@ -9377,6 +9407,7 @@ proxy_button_event (GdkEvent *source_event,
GdkWindow *pointer_window;
GdkWindow *parent;
GdkEvent *event;
GdkPointerWindowInfo *pointer_info;
guint state;
guint32 time_;
GdkEventType type;
......@@ -9396,6 +9427,7 @@ proxy_button_event (GdkEvent *source_event,
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 &&
......@@ -9448,6 +9480,31 @@ proxy_button_event (GdkEvent *source_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)
......@@ -9468,7 +9525,24 @@ proxy_button_event (GdkEvent *source_event,
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:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment