diff --git a/src/backends/x11/meta-backend-x11.c b/src/backends/x11/meta-backend-x11.c index 0f5596e04..7fa90c10f 100644 --- a/src/backends/x11/meta-backend-x11.c +++ b/src/backends/x11/meta-backend-x11.c @@ -60,6 +60,10 @@ struct _MetaBackendX11Private XSyncAlarm user_active_alarm; XSyncCounter counter; + int current_touch_replay_sync_serial; + int pending_touch_replay_sync_serial; + Atom touch_replay_sync_atom; + int xinput_opcode; int xinput_event_base; int xinput_error_base; @@ -168,6 +172,26 @@ meta_backend_x11_translate_device_event (MetaBackendX11 *x11, backend_x11_class->translate_device_event (x11, device_event); } +static void +maybe_translate_touch_replay_pointer_event (MetaBackendX11 *x11, + XIDeviceEvent *device_event) +{ + MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); + + if (!device_event->send_event && + device_event->time != CurrentTime && + priv->current_touch_replay_sync_serial != + priv->pending_touch_replay_sync_serial && + XSERVER_TIME_IS_BEFORE (device_event->time, priv->latest_evtime)) + { + /* Emulated pointer events received after XIRejectTouch is received + * on a passive touch grab will contain older timestamps, update those + * so we dont get InvalidTime at grabs. + */ + device_event->time = priv->latest_evtime; + } +} + static void translate_device_event (MetaBackendX11 *x11, XIDeviceEvent *device_event) @@ -177,19 +201,7 @@ translate_device_event (MetaBackendX11 *x11, meta_backend_x11_translate_device_event (x11, device_event); if (!device_event->send_event && device_event->time != CurrentTime) - { - if (XSERVER_TIME_IS_BEFORE (device_event->time, priv->latest_evtime)) - { - /* Emulated pointer events received after XIRejectTouch is received - * on a passive touch grab will contain older timestamps, update those - * so we dont get InvalidTime at grabs. - */ - device_event->time = priv->latest_evtime; - } - - /* Update the internal latest evtime, for any possible later use */ - priv->latest_evtime = device_event->time; - } + priv->latest_evtime = device_event->time; } static void @@ -254,6 +266,9 @@ maybe_spoof_event_as_stage_event (MetaBackendX11 *x11, case XI_Motion: case XI_ButtonPress: case XI_ButtonRelease: + maybe_translate_touch_replay_pointer_event (x11, + (XIDeviceEvent *) input_event); + /* Intentional fall-through */ case XI_KeyPress: case XI_KeyRelease: case XI_TouchBegin: @@ -321,6 +336,17 @@ handle_host_xevent (MetaBackend *backend, MetaBackendX11Private *priv = meta_backend_x11_get_instance_private (x11); gboolean bypass_clutter = FALSE; + switch (event->type) + { + case ClientMessage: + if (event->xclient.window == meta_backend_x11_get_xwindow (x11) && + event->xclient.message_type == priv->touch_replay_sync_atom) + priv->current_touch_replay_sync_serial = event->xclient.data.l[0]; + break; + default: + break; + } + XGetEventData (priv->xdisplay, &event->xcookie); { @@ -528,6 +554,10 @@ meta_backend_x11_post_init (MetaBackend *backend) monitor_manager = meta_backend_get_monitor_manager (backend); g_signal_connect (monitor_manager, "monitors-changed-internal", G_CALLBACK (on_monitors_changed), backend); + + priv->touch_replay_sync_atom = XInternAtom (priv->xdisplay, + "_MUTTER_TOUCH_SEQUENCE_SYNC", + False); } static ClutterBackend * @@ -604,6 +634,21 @@ meta_backend_x11_finish_touch_sequence (MetaBackend *backend, META_VIRTUAL_CORE_POINTER_ID, clutter_x11_event_sequence_get_touch_detail (sequence), DefaultRootWindow (priv->xdisplay), event_mode); + + if (state == META_SEQUENCE_REJECTED) + { + XClientMessageEvent ev; + + ev = (XClientMessageEvent) { + .type = ClientMessage, + .window = meta_backend_x11_get_xwindow (x11), + .message_type = priv->touch_replay_sync_atom, + .format = 32, + .data.l[0] = ++priv->pending_touch_replay_sync_serial, + }; + XSendEvent (priv->xdisplay, meta_backend_x11_get_xwindow (x11), + False, 0, (XEvent *) &ev); + } } static void