core: Add minimal handling of touch events
Currently touch events are ignored in the core event handler, and hence dealt with within GDK. If those touch events were emulating pointer events, GDK would attempt to convert back those events to pointer events as the frame GdkWindow doesn't have the GDK_TOUCH_MASK set. This results in XI_TouchBegin events being initially processed by GDK, converted to button events, and triggering a grab op that subverts touch events into pointer events, so the touch is never ever seen again by GDK. This leaves GDK in an inconsistent internal state wrt pointer grabs, so future pointer-emulating touches will refer to the same window forever. Fix this by handling touch events minimally, just enough to convert XI_TouchBegin to GDK_BUTTON_PRESS within mutter, so GDK is bypassed for every touch event just like it is for pointer events. This, and the XIGrabDevice() that keeps coercing pointer events when the grab operation starts, are enough to fix window drag and drop on touch devices. https://bugzilla.gnome.org/show_bug.cgi?id=723552
This commit is contained in:
parent
4880ee9bb6
commit
991c85f6a0
@ -1815,6 +1815,9 @@ get_input_event (MetaDisplay *display,
|
||||
|
||||
switch (input_event->evtype)
|
||||
{
|
||||
case XI_TouchBegin:
|
||||
case XI_TouchUpdate:
|
||||
case XI_TouchEnd:
|
||||
case XI_Motion:
|
||||
case XI_ButtonPress:
|
||||
case XI_ButtonRelease:
|
||||
@ -2293,6 +2296,7 @@ event_callback (XEvent *event,
|
||||
{
|
||||
XIDeviceEvent *device_event = (XIDeviceEvent *) input_event;
|
||||
XIEnterEvent *enter_event = (XIEnterEvent *) input_event;
|
||||
gint button = 0;
|
||||
|
||||
if (window && !window->override_redirect &&
|
||||
((input_event->evtype == XI_KeyPress) || (input_event->evtype == XI_ButtonPress)))
|
||||
@ -2328,20 +2332,33 @@ event_callback (XEvent *event,
|
||||
if (meta_display_process_key_event (display, window, (XIDeviceEvent *) input_event))
|
||||
filter_out_event = bypass_compositor = TRUE;
|
||||
break;
|
||||
case XI_TouchBegin:
|
||||
/* Filter out non-pointer-emulating touches */
|
||||
if ((((XIDeviceEvent *) input_event)->flags & XITouchEmulatingPointer) == 0)
|
||||
break;
|
||||
|
||||
/* Fall through */
|
||||
case XI_ButtonPress:
|
||||
if (display->grab_op == META_GRAB_OP_COMPOSITOR)
|
||||
break;
|
||||
|
||||
display->overlay_key_only_pressed = FALSE;
|
||||
|
||||
if (device_event->detail == 4 || device_event->detail == 5)
|
||||
/* Scrollwheel event, do nothing and deliver event to compositor below */
|
||||
break;
|
||||
if (input_event->evtype == XI_ButtonPress)
|
||||
{
|
||||
if (device_event->detail == 4 || device_event->detail == 5)
|
||||
/* Scrollwheel event, do nothing and deliver event to compositor below */
|
||||
break;
|
||||
else
|
||||
button = device_event->detail;
|
||||
}
|
||||
else if (input_event->evtype == XI_TouchBegin)
|
||||
button = 1;
|
||||
|
||||
if ((window &&
|
||||
meta_grab_op_is_mouse (display->grab_op) &&
|
||||
(device_event->mods.effective & display->window_grab_modifiers) &&
|
||||
display->grab_button != device_event->detail &&
|
||||
display->grab_button != button &&
|
||||
display->grab_window == window) ||
|
||||
grab_op_is_keyboard (display->grab_op))
|
||||
{
|
||||
@ -2371,8 +2388,7 @@ event_callback (XEvent *event,
|
||||
*/
|
||||
unmodified = (device_event->mods.effective & grab_mask) == 0;
|
||||
|
||||
if (unmodified ||
|
||||
device_event->detail == 1)
|
||||
if (unmodified || button == 1)
|
||||
{
|
||||
/* don't focus if frame received, will be lowered in
|
||||
* frames.c or special-cased if the click was on a
|
||||
@ -2393,7 +2409,7 @@ event_callback (XEvent *event,
|
||||
{
|
||||
meta_topic (META_DEBUG_FOCUS,
|
||||
"Focusing %s due to unmodified button %u press (display.c)\n",
|
||||
window->desc, device_event->detail);
|
||||
window->desc, button);
|
||||
meta_window_focus (window, device_event->time);
|
||||
}
|
||||
else
|
||||
@ -2409,7 +2425,7 @@ event_callback (XEvent *event,
|
||||
if (!unmodified)
|
||||
begin_move = TRUE;
|
||||
}
|
||||
else if (!unmodified && device_event->detail == meta_prefs_get_mouse_button_resize())
|
||||
else if (!unmodified && button == meta_prefs_get_mouse_button_resize())
|
||||
{
|
||||
if (window->has_resize_func)
|
||||
{
|
||||
@ -2451,21 +2467,21 @@ event_callback (XEvent *event,
|
||||
op,
|
||||
TRUE,
|
||||
FALSE,
|
||||
device_event->detail,
|
||||
button,
|
||||
0,
|
||||
device_event->time,
|
||||
device_event->root_x,
|
||||
device_event->root_y);
|
||||
}
|
||||
}
|
||||
else if (device_event->detail == meta_prefs_get_mouse_button_menu())
|
||||
else if (button == meta_prefs_get_mouse_button_menu())
|
||||
{
|
||||
if (meta_prefs_get_raise_on_click ())
|
||||
meta_window_raise (window);
|
||||
meta_window_show_menu (window,
|
||||
device_event->root_x,
|
||||
device_event->root_y,
|
||||
device_event->detail,
|
||||
button,
|
||||
device_event->time);
|
||||
}
|
||||
|
||||
@ -2490,7 +2506,7 @@ event_callback (XEvent *event,
|
||||
META_GRAB_OP_MOVING,
|
||||
TRUE,
|
||||
FALSE,
|
||||
device_event->detail,
|
||||
button,
|
||||
0,
|
||||
device_event->time,
|
||||
device_event->root_x,
|
||||
@ -2640,6 +2656,18 @@ event_callback (XEvent *event,
|
||||
filter_out_event = bypass_compositor = TRUE;
|
||||
break;
|
||||
#endif /* HAVE_XI23 */
|
||||
case XI_TouchUpdate:
|
||||
case XI_TouchEnd:
|
||||
/* Filter out non-pointer-emulating touches */
|
||||
if ((((XIDeviceEvent *) input_event)->flags & XITouchEmulatingPointer) == 0)
|
||||
break;
|
||||
|
||||
/* Currently unhandled, if any grab_op is started through XI_TouchBegin,
|
||||
* the XIGrabDevice() evmask drops touch events, so only emulated
|
||||
* XI_Motions and XI_ButtonRelease will follow.
|
||||
*/
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -3115,6 +3143,9 @@ event_get_modified_window (MetaDisplay *display,
|
||||
case XI_ButtonRelease:
|
||||
case XI_KeyPress:
|
||||
case XI_KeyRelease:
|
||||
case XI_TouchBegin:
|
||||
case XI_TouchUpdate:
|
||||
case XI_TouchEnd:
|
||||
return ((XIDeviceEvent *) input_event)->event;
|
||||
case XI_FocusIn:
|
||||
case XI_FocusOut:
|
||||
@ -3401,6 +3432,15 @@ meta_spew_xi2_event (MetaDisplay *display,
|
||||
case XI_Leave:
|
||||
name = "XI_Leave";
|
||||
break;
|
||||
case XI_TouchBegin:
|
||||
name = "XI_TouchBegin";
|
||||
break;
|
||||
case XI_TouchUpdate:
|
||||
name = "XI_TouchUpdate";
|
||||
break;
|
||||
case XI_TouchEnd:
|
||||
name = "XI_TouchEnd";
|
||||
break;
|
||||
#ifdef HAVE_XI23
|
||||
case XI_BarrierHit:
|
||||
name = "XI_BarrierHit";
|
||||
@ -3458,6 +3498,18 @@ meta_spew_xi2_event (MetaDisplay *display,
|
||||
enter_event->root_x,
|
||||
enter_event->root_y);
|
||||
break;
|
||||
case XI_TouchBegin:
|
||||
case XI_TouchUpdate:
|
||||
case XI_TouchEnd:
|
||||
extra = g_strdup_printf ("win: 0x%lx root: 0x%lx touch sequence: %d x: %g y: %g state: 0x%x flags: 0x%x",
|
||||
device_event->event,
|
||||
device_event->root,
|
||||
device_event->detail,
|
||||
device_event->root_x,
|
||||
device_event->root_y,
|
||||
device_event->mods.effective,
|
||||
device_event->flags);
|
||||
break;
|
||||
}
|
||||
|
||||
*name_p = name;
|
||||
|
18
src/ui/ui.c
18
src/ui/ui.c
@ -123,6 +123,7 @@ maybe_redirect_mouse_event (XEvent *xevent)
|
||||
|
||||
switch (xev->evtype)
|
||||
{
|
||||
case XI_TouchBegin:
|
||||
case XI_ButtonPress:
|
||||
case XI_ButtonRelease:
|
||||
case XI_Motion:
|
||||
@ -159,20 +160,27 @@ maybe_redirect_mouse_event (XEvent *xevent)
|
||||
|
||||
switch (xev->evtype)
|
||||
{
|
||||
case XI_TouchBegin:
|
||||
case XI_ButtonPress:
|
||||
case XI_ButtonRelease:
|
||||
if (xev_d->evtype == XI_ButtonPress)
|
||||
if (xev_d->evtype == XI_ButtonPress || xev_d->evtype == XI_TouchBegin)
|
||||
{
|
||||
GtkSettings *settings = gtk_settings_get_default ();
|
||||
int double_click_time;
|
||||
int double_click_distance;
|
||||
int button;
|
||||
|
||||
g_object_get (settings,
|
||||
"gtk-double-click-time", &double_click_time,
|
||||
"gtk-double-click-distance", &double_click_distance,
|
||||
NULL);
|
||||
|
||||
if (xev_d->detail == ui->button_click_number &&
|
||||
if (xev->evtype == XI_TouchBegin)
|
||||
button = 1;
|
||||
else
|
||||
button = xev_d->detail;
|
||||
|
||||
if (button == ui->button_click_number &&
|
||||
xev_d->event == ui->button_click_window &&
|
||||
xev_d->time < ui->button_click_time + double_click_time &&
|
||||
ABS (xev_d->event_x - ui->button_click_x) <= double_click_distance &&
|
||||
@ -185,20 +193,22 @@ maybe_redirect_mouse_event (XEvent *xevent)
|
||||
else
|
||||
{
|
||||
gevent = gdk_event_new (GDK_BUTTON_PRESS);
|
||||
ui->button_click_number = xev_d->detail;
|
||||
ui->button_click_number = button;
|
||||
ui->button_click_window = xev_d->event;
|
||||
ui->button_click_time = xev_d->time;
|
||||
ui->button_click_x = xev_d->event_x;
|
||||
ui->button_click_y = xev_d->event_y;
|
||||
}
|
||||
|
||||
gevent->button.button = button;
|
||||
}
|
||||
else
|
||||
{
|
||||
gevent = gdk_event_new (GDK_BUTTON_RELEASE);
|
||||
gevent->button.button = xev_d->detail;
|
||||
}
|
||||
|
||||
gevent->button.window = g_object_ref (gdk_window);
|
||||
gevent->button.button = xev_d->detail;
|
||||
gevent->button.time = xev_d->time;
|
||||
gevent->button.x = xev_d->event_x;
|
||||
gevent->button.y = xev_d->event_y;
|
||||
|
Loading…
Reference in New Issue
Block a user