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.
This commit is contained in:
committed by
Matthias Clasen
parent
edebccd1ad
commit
4ff34b7ca3
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -8333,9 +8333,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)
|
||||
@@ -8348,7 +8350,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);
|
||||
@@ -9172,7 +9181,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);
|
||||
@@ -9192,6 +9201,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
|
||||
@@ -9315,6 +9333,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 &&
|
||||
@@ -9373,6 +9403,7 @@ proxy_button_event (GdkEvent *source_event,
|
||||
GdkWindow *pointer_window;
|
||||
GdkWindow *parent;
|
||||
GdkEvent *event;
|
||||
GdkPointerWindowInfo *pointer_info;
|
||||
guint state;
|
||||
guint32 time_;
|
||||
GdkEventType type;
|
||||
@@ -9392,6 +9423,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 &&
|
||||
@@ -9444,6 +9476,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)
|
||||
@@ -9464,7 +9521,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:
|
||||
|
||||
Reference in New Issue
Block a user