|
|
3c14d2 |
From 9eeb657cd98eeb198e50130b4081b2b34b1d7469 Mon Sep 17 00:00:00 2001
|
|
|
3c14d2 |
From: Carlos Garnacho <carlosg@gnome.org>
|
|
|
3c14d2 |
Date: Tue, 11 Feb 2014 19:24:12 +0100
|
|
|
3c14d2 |
Subject: [PATCH] core: Add minimal handling of touch events
|
|
|
3c14d2 |
|
|
|
3c14d2 |
Currently touch events are ignored in the core event handler,
|
|
|
3c14d2 |
and hence dealt with within GDK. If those touch events were
|
|
|
3c14d2 |
emulating pointer events, GDK would attempt to convert back
|
|
|
3c14d2 |
those events to pointer events as the frame GdkWindow doesn't
|
|
|
3c14d2 |
have the GDK_TOUCH_MASK set.
|
|
|
3c14d2 |
|
|
|
3c14d2 |
This results in XI_TouchBegin events being initially processed
|
|
|
3c14d2 |
by GDK, converted to button events, and triggering a grab op
|
|
|
3c14d2 |
that subverts touch events into pointer events, so the touch
|
|
|
3c14d2 |
is never ever seen again by GDK. This leaves GDK in an
|
|
|
3c14d2 |
inconsistent internal state wrt pointer grabs, so future
|
|
|
3c14d2 |
pointer-emulating touches will refer to the same window forever.
|
|
|
3c14d2 |
|
|
|
3c14d2 |
Fix this by handling touch events minimally, just enough to
|
|
|
3c14d2 |
convert XI_TouchBegin to GDK_BUTTON_PRESS within mutter, so GDK
|
|
|
3c14d2 |
is bypassed for every touch event just like it is for pointer
|
|
|
3c14d2 |
events. This, and the XIGrabDevice() that keeps coercing pointer
|
|
|
3c14d2 |
events when the grab operation starts, are enough to fix window
|
|
|
3c14d2 |
drag and drop on touch devices.
|
|
|
3c14d2 |
---
|
|
|
3c14d2 |
src/core/display.c | 51 +++++++++++++++++++++++++++++++++++++++------------
|
|
|
3c14d2 |
src/ui/ui.c | 18 ++++++++++++++----
|
|
|
3c14d2 |
2 files changed, 53 insertions(+), 16 deletions(-)
|
|
|
3c14d2 |
|
|
|
3c14d2 |
diff --git a/src/core/display.c b/src/core/display.c
|
|
|
3c14d2 |
index d611314..435d9d9 100644
|
|
|
3c14d2 |
--- a/src/core/display.c
|
|
|
3c14d2 |
+++ b/src/core/display.c
|
|
|
3c14d2 |
@@ -1838,6 +1838,9 @@ get_input_event (MetaDisplay *display,
|
|
|
3c14d2 |
|
|
|
3c14d2 |
switch (input_event->evtype)
|
|
|
3c14d2 |
{
|
|
|
3c14d2 |
+ case XI_TouchBegin:
|
|
|
3c14d2 |
+ case XI_TouchUpdate:
|
|
|
3c14d2 |
+ case XI_TouchEnd:
|
|
|
3c14d2 |
case XI_Motion:
|
|
|
3c14d2 |
case XI_ButtonPress:
|
|
|
3c14d2 |
case XI_ButtonRelease:
|
|
|
3c14d2 |
@@ -2041,6 +2044,7 @@ event_callback (XEvent *event,
|
|
|
3c14d2 |
{
|
|
|
3c14d2 |
XIDeviceEvent *device_event = (XIDeviceEvent *) input_event;
|
|
|
3c14d2 |
XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
|
|
|
3c14d2 |
+ gint button = 0;
|
|
|
3c14d2 |
|
|
|
3c14d2 |
if (window && !window->override_redirect &&
|
|
|
3c14d2 |
((input_event->type == XI_KeyPress) || (input_event->type == XI_ButtonPress)))
|
|
|
3c14d2 |
@@ -2076,19 +2080,32 @@ event_callback (XEvent *event,
|
|
|
3c14d2 |
if (meta_display_process_key_event (display, window, (XIDeviceEvent *) input_event))
|
|
|
3c14d2 |
filter_out_event = bypass_compositor = TRUE;
|
|
|
3c14d2 |
break;
|
|
|
3c14d2 |
+ case XI_TouchBegin:
|
|
|
3c14d2 |
+ /* Filter out non-pointer-emulating touches */
|
|
|
3c14d2 |
+ if ((((XIDeviceEvent *) input_event)->flags & XITouchEmulatingPointer) == 0)
|
|
|
3c14d2 |
+ break;
|
|
|
3c14d2 |
+
|
|
|
3c14d2 |
+ /* Fall through */
|
|
|
3c14d2 |
case XI_ButtonPress:
|
|
|
3c14d2 |
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
|
|
3c14d2 |
break;
|
|
|
3c14d2 |
|
|
|
3c14d2 |
display->overlay_key_only_pressed = FALSE;
|
|
|
3c14d2 |
|
|
|
3c14d2 |
- if (device_event->detail == 4 || device_event->detail == 5)
|
|
|
3c14d2 |
- /* Scrollwheel event, do nothing and deliver event to compositor below */
|
|
|
3c14d2 |
- break;
|
|
|
3c14d2 |
+ if (input_event->evtype == XI_ButtonPress)
|
|
|
3c14d2 |
+ {
|
|
|
3c14d2 |
+ if (device_event->detail == 4 || device_event->detail == 5)
|
|
|
3c14d2 |
+ /* Scrollwheel event, do nothing and deliver event to compositor below */
|
|
|
3c14d2 |
+ break;
|
|
|
3c14d2 |
+ else
|
|
|
3c14d2 |
+ button = device_event->detail;
|
|
|
3c14d2 |
+ }
|
|
|
3c14d2 |
+ else if (input_event->evtype == XI_TouchBegin)
|
|
|
3c14d2 |
+ button = 1;
|
|
|
3c14d2 |
|
|
|
3c14d2 |
if ((window &&
|
|
|
3c14d2 |
meta_grab_op_is_mouse (display->grab_op) &&
|
|
|
3c14d2 |
- display->grab_button != device_event->detail &&
|
|
|
3c14d2 |
+ display->grab_button != button &&
|
|
|
3c14d2 |
display->grab_window == window) ||
|
|
|
3c14d2 |
grab_op_is_keyboard (display->grab_op))
|
|
|
3c14d2 |
{
|
|
|
3c14d2 |
@@ -2130,8 +2147,7 @@ event_callback (XEvent *event,
|
|
|
3c14d2 |
*/
|
|
|
3c14d2 |
unmodified = (device_event->mods.effective & grab_mask) == 0;
|
|
|
3c14d2 |
|
|
|
3c14d2 |
- if (unmodified ||
|
|
|
3c14d2 |
- device_event->detail == 1)
|
|
|
3c14d2 |
+ if (unmodified || button == 1)
|
|
|
3c14d2 |
{
|
|
|
3c14d2 |
/* don't focus if frame received, will be lowered in
|
|
|
3c14d2 |
* frames.c or special-cased if the click was on a
|
|
|
3c14d2 |
@@ -2152,7 +2168,7 @@ event_callback (XEvent *event,
|
|
|
3c14d2 |
{
|
|
|
3c14d2 |
meta_topic (META_DEBUG_FOCUS,
|
|
|
3c14d2 |
"Focusing %s due to unmodified button %u press (display.c)\n",
|
|
|
3c14d2 |
- window->desc, device_event->detail);
|
|
|
3c14d2 |
+ window->desc, button);
|
|
|
3c14d2 |
meta_window_focus (window, device_event->time);
|
|
|
3c14d2 |
}
|
|
|
3c14d2 |
else
|
|
|
3c14d2 |
@@ -2168,7 +2184,7 @@ event_callback (XEvent *event,
|
|
|
3c14d2 |
if (!unmodified)
|
|
|
3c14d2 |
begin_move = TRUE;
|
|
|
3c14d2 |
}
|
|
|
3c14d2 |
- else if (!unmodified && device_event->detail == meta_prefs_get_mouse_button_resize())
|
|
|
3c14d2 |
+ else if (!unmodified && button == meta_prefs_get_mouse_button_resize())
|
|
|
3c14d2 |
{
|
|
|
3c14d2 |
if (window->has_resize_func)
|
|
|
3c14d2 |
{
|
|
|
3c14d2 |
@@ -2210,21 +2226,21 @@ event_callback (XEvent *event,
|
|
|
3c14d2 |
op,
|
|
|
3c14d2 |
TRUE,
|
|
|
3c14d2 |
FALSE,
|
|
|
3c14d2 |
- device_event->detail,
|
|
|
3c14d2 |
+ button,
|
|
|
3c14d2 |
0,
|
|
|
3c14d2 |
device_event->time,
|
|
|
3c14d2 |
device_event->root_x,
|
|
|
3c14d2 |
device_event->root_y);
|
|
|
3c14d2 |
}
|
|
|
3c14d2 |
}
|
|
|
3c14d2 |
- else if (device_event->detail == meta_prefs_get_mouse_button_menu())
|
|
|
3c14d2 |
+ else if (button == meta_prefs_get_mouse_button_menu())
|
|
|
3c14d2 |
{
|
|
|
3c14d2 |
if (meta_prefs_get_raise_on_click ())
|
|
|
3c14d2 |
meta_window_raise (window);
|
|
|
3c14d2 |
meta_window_show_menu (window,
|
|
|
3c14d2 |
device_event->root_x,
|
|
|
3c14d2 |
device_event->root_y,
|
|
|
3c14d2 |
- device_event->detail,
|
|
|
3c14d2 |
+ button,
|
|
|
3c14d2 |
device_event->time);
|
|
|
3c14d2 |
}
|
|
|
3c14d2 |
|
|
|
3c14d2 |
@@ -2267,7 +2283,7 @@ event_callback (XEvent *event,
|
|
|
3c14d2 |
META_GRAB_OP_MOVING,
|
|
|
3c14d2 |
TRUE,
|
|
|
3c14d2 |
FALSE,
|
|
|
3c14d2 |
- device_event->detail,
|
|
|
3c14d2 |
+ button,
|
|
|
3c14d2 |
0,
|
|
|
3c14d2 |
device_event->time,
|
|
|
3c14d2 |
device_event->root_x,
|
|
|
3c14d2 |
@@ -2438,6 +2454,14 @@ event_callback (XEvent *event,
|
|
|
3c14d2 |
filter_out_event = bypass_compositor = TRUE;
|
|
|
3c14d2 |
break;
|
|
|
3c14d2 |
#endif /* HAVE_XI23 */
|
|
|
3c14d2 |
+ case XI_TouchUpdate:
|
|
|
3c14d2 |
+ case XI_TouchEnd:
|
|
|
3c14d2 |
+ /* Currently unhandled, if any grab_op is started through XI_TouchBegin,
|
|
|
3c14d2 |
+ * the XIGrabDevice() evmask drops touch events, so only emulated
|
|
|
3c14d2 |
+ * XI_Motions and XI_ButtonRelease will follow.
|
|
|
3c14d2 |
+ */
|
|
|
3c14d2 |
+ filter_out_event = TRUE;
|
|
|
3c14d2 |
+ break;
|
|
|
3c14d2 |
}
|
|
|
3c14d2 |
}
|
|
|
3c14d2 |
else
|
|
|
3c14d2 |
@@ -2963,6 +2987,9 @@ event_get_modified_window (MetaDisplay *display,
|
|
|
3c14d2 |
case XI_ButtonRelease:
|
|
|
3c14d2 |
case XI_KeyPress:
|
|
|
3c14d2 |
case XI_KeyRelease:
|
|
|
3c14d2 |
+ case XI_TouchBegin:
|
|
|
3c14d2 |
+ case XI_TouchUpdate:
|
|
|
3c14d2 |
+ case XI_TouchEnd:
|
|
|
3c14d2 |
return ((XIDeviceEvent *) input_event)->event;
|
|
|
3c14d2 |
case XI_FocusIn:
|
|
|
3c14d2 |
case XI_FocusOut:
|
|
|
3c14d2 |
diff --git a/src/ui/ui.c b/src/ui/ui.c
|
|
|
3c14d2 |
index af28263..582fdce 100644
|
|
|
3c14d2 |
--- a/src/ui/ui.c
|
|
|
3c14d2 |
+++ b/src/ui/ui.c
|
|
|
3c14d2 |
@@ -126,6 +126,7 @@ maybe_redirect_mouse_event (XEvent *xevent)
|
|
|
3c14d2 |
|
|
|
3c14d2 |
switch (xev->evtype)
|
|
|
3c14d2 |
{
|
|
|
3c14d2 |
+ case XI_TouchBegin:
|
|
|
3c14d2 |
case XI_ButtonPress:
|
|
|
3c14d2 |
case XI_ButtonRelease:
|
|
|
3c14d2 |
case XI_Motion:
|
|
|
3c14d2 |
@@ -162,20 +163,27 @@ maybe_redirect_mouse_event (XEvent *xevent)
|
|
|
3c14d2 |
|
|
|
3c14d2 |
switch (xev->evtype)
|
|
|
3c14d2 |
{
|
|
|
3c14d2 |
+ case XI_TouchBegin:
|
|
|
3c14d2 |
case XI_ButtonPress:
|
|
|
3c14d2 |
case XI_ButtonRelease:
|
|
|
3c14d2 |
- if (xev_d->evtype == XI_ButtonPress)
|
|
|
3c14d2 |
+ if (xev_d->evtype == XI_ButtonPress || xev_d->evtype == XI_TouchBegin)
|
|
|
3c14d2 |
{
|
|
|
3c14d2 |
GtkSettings *settings = gtk_settings_get_default ();
|
|
|
3c14d2 |
int double_click_time;
|
|
|
3c14d2 |
int double_click_distance;
|
|
|
3c14d2 |
+ int button;
|
|
|
3c14d2 |
|
|
|
3c14d2 |
g_object_get (settings,
|
|
|
3c14d2 |
"gtk-double-click-time", &double_click_time,
|
|
|
3c14d2 |
"gtk-double-click-distance", &double_click_distance,
|
|
|
3c14d2 |
NULL);
|
|
|
3c14d2 |
|
|
|
3c14d2 |
- if (xev_d->detail == ui->button_click_number &&
|
|
|
3c14d2 |
+ if (xev->evtype == XI_TouchBegin)
|
|
|
3c14d2 |
+ button = 1;
|
|
|
3c14d2 |
+ else
|
|
|
3c14d2 |
+ button = xev_d->detail;
|
|
|
3c14d2 |
+
|
|
|
3c14d2 |
+ if (button == ui->button_click_number &&
|
|
|
3c14d2 |
xev_d->event == ui->button_click_window &&
|
|
|
3c14d2 |
xev_d->time < ui->button_click_time + double_click_time &&
|
|
|
3c14d2 |
ABS (xev_d->event_x - ui->button_click_x) <= double_click_distance &&
|
|
|
3c14d2 |
@@ -188,20 +196,22 @@ maybe_redirect_mouse_event (XEvent *xevent)
|
|
|
3c14d2 |
else
|
|
|
3c14d2 |
{
|
|
|
3c14d2 |
gevent = gdk_event_new (GDK_BUTTON_PRESS);
|
|
|
3c14d2 |
- ui->button_click_number = xev_d->detail;
|
|
|
3c14d2 |
+ ui->button_click_number = button;
|
|
|
3c14d2 |
ui->button_click_window = xev_d->event;
|
|
|
3c14d2 |
ui->button_click_time = xev_d->time;
|
|
|
3c14d2 |
ui->button_click_x = xev_d->event_x;
|
|
|
3c14d2 |
ui->button_click_y = xev_d->event_y;
|
|
|
3c14d2 |
}
|
|
|
3c14d2 |
+
|
|
|
3c14d2 |
+ gevent->button.button = button;
|
|
|
3c14d2 |
}
|
|
|
3c14d2 |
else
|
|
|
3c14d2 |
{
|
|
|
3c14d2 |
gevent = gdk_event_new (GDK_BUTTON_RELEASE);
|
|
|
3c14d2 |
+ gevent->button.button = xev_d->detail;
|
|
|
3c14d2 |
}
|
|
|
3c14d2 |
|
|
|
3c14d2 |
gevent->button.window = g_object_ref (gdk_window);
|
|
|
3c14d2 |
- gevent->button.button = xev_d->detail;
|
|
|
3c14d2 |
gevent->button.time = xev_d->time;
|
|
|
3c14d2 |
gevent->button.x = xev_d->event_x;
|
|
|
3c14d2 |
gevent->button.y = xev_d->event_y;
|
|
|
3c14d2 |
--
|
|
|
3c14d2 |
1.8.5.3
|
|
|
3c14d2 |
|