[gtk+/multitouch: 45/121] gdk: Generate crossing events around touch devices' press/release
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/multitouch: 45/121] gdk: Generate crossing events around touch devices' press/release
- Date: Thu, 12 Jan 2012 14:20:53 +0000 (UTC)
commit fe3b7ce426c72591f344903810b07b26b3dda80c
Author: Carlos Garnacho <carlosg gnome org>
Date: Sat Dec 3 15:11:08 2011 +0100
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_PRESS/RELEASE are handled, and those are sent
around button press/release. 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.
gdk/gdkdisplay.c | 28 ++++++++++++-----
gdk/gdkdisplayprivate.h | 1 +
gdk/gdkevents.h | 14 ++++++++-
gdk/gdkwindow.c | 75 +++++++++++++++++++++++++++++++++++++++++++++--
4 files changed, 105 insertions(+), 13 deletions(-)
---
diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c
index 702f6b4..48a556c 100644
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@ -897,15 +897,25 @@ 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_TOUCH)
+ 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,
diff --git a/gdk/gdkdisplayprivate.h b/gdk/gdkdisplayprivate.h
index 8084332..d73449e 100644
--- a/gdk/gdkdisplayprivate.h
+++ b/gdk/gdkdisplayprivate.h
@@ -76,6 +76,7 @@ typedef struct
guint32 state;
guint32 button;
GdkDevice *last_slave;
+ guint need_touch_press_enter : 1;
} GdkPointerWindowInfo;
typedef struct
diff --git a/gdk/gdkevents.h b/gdk/gdkevents.h
index d8a1f76..33cd8b0 100644
--- a/gdk/gdkevents.h
+++ b/gdk/gdkevents.h
@@ -354,6 +354,15 @@ 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_STATE_CHANGED: crossing because a GTK+ widget changed
+ * state (e.g. sensitivity).
+ * @GDK_CROSSING_TOUCH_PRESS: crossing because a touch device was pressed,
+ * this event is synthetic as the pointer might have not left the window.
+ * @GDK_CROSSING_TOUCH_RELEASE: crossing because a touch device was released.
+ * 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.
*/
@@ -364,7 +373,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_PRESS,
+ GDK_CROSSING_TOUCH_RELEASE,
+ GDK_CROSSING_DEVICE_SWITCH
} GdkCrossingMode;
/**
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index de6e4b6..2aabcfd 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -8335,9 +8335,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)
@@ -8350,7 +8352,13 @@ send_crossing_event (GdkDisplay *display,
else
window_event_mask = window->event_mask;
- if (type == GDK_LEAVE_NOTIFY)
+ if (pointer_info->need_touch_press_enter &&
+ mode != GDK_CROSSING_TOUCH_PRESS &&
+ mode != GDK_CROSSING_TOUCH_RELEASE)
+ {
+ 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);
@@ -9174,7 +9182,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);
@@ -9194,6 +9202,13 @@ 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_TOUCH)
+ {
+ 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
@@ -9317,6 +9332,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 &&
@@ -9375,6 +9402,7 @@ proxy_button_event (GdkEvent *source_event,
GdkWindow *pointer_window;
GdkWindow *parent;
GdkEvent *event;
+ GdkPointerWindowInfo *pointer_info;
guint state;
guint32 time_;
GdkEventType type;
@@ -9394,6 +9422,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 &&
@@ -9446,6 +9475,30 @@ 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_TOUCH)
+ mode = GDK_CROSSING_TOUCH_PRESS;
+ 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)
@@ -9466,7 +9519,23 @@ 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_TOUCH)
+ {
+ /* 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_RELEASE,
+ toplevel_x, toplevel_y,
+ state, time_, NULL,
+ serial, FALSE);
+ }
return TRUE;
case GDK_SCROLL:
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]