backends/x11: Emulate pointer motion while the pointer is off stage

Given X11 nature, the pointer "leaves" the stage anytime it wanders into
a client window, or any other areas that are not deemed part of the
stage input region.

Yet we want to stay correct in those situations, e.g. have the clutter
side reasonably in sync, picking and highlighting to work properly, etc.

In order to achieve that, emulate motion events on XI_RawMotion. These
are as much throttled as our pointer tracking for a11y, in order to avoid
too many XIQueryPointer sync calls. This emulation only kicks in anytime
that X11 notifies us that we are not "on" the stage.

This replaces some sync_pointer() calls in GNOME Shell code that are
there just to compensate for this trait of X11, e.g. in the message tray
code.

Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1659>
This commit is contained in:
Carlos Garnacho 2020-12-29 11:30:22 +01:00 committed by Marge Bot
parent 437f5d1c66
commit a5db9ee2d7

View File

@ -73,6 +73,7 @@ struct _MetaSeatX11
int opcode; int opcode;
guint has_touchscreens : 1; guint has_touchscreens : 1;
guint touch_mode : 1; guint touch_mode : 1;
guint has_pointer_focus : 1;
}; };
static GParamSpec *props[N_PROPS] = { 0 }; static GParamSpec *props[N_PROPS] = { 0 };
@ -871,6 +872,29 @@ translate_property_event (MetaSeatX11 *seat_x11,
} }
} }
static void
emulate_motion (MetaSeatX11 *seat_x11,
double x,
double y)
{
ClutterInputDevice *pointer;
ClutterEvent *event;
ClutterStage *stage;
pointer = clutter_seat_get_pointer (CLUTTER_SEAT (seat_x11));
stage = CLUTTER_STAGE (meta_backend_get_stage (meta_get_backend ()));
event = clutter_event_new (CLUTTER_MOTION);
clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_SYNTHETIC);
clutter_event_set_coords (event, x, y);
clutter_event_set_device (event, pointer);
clutter_event_set_source_device (event, NULL);
clutter_event_set_stage (event, stage);
clutter_event_put (event);
clutter_event_free (event);
}
static void static void
translate_raw_event (MetaSeatX11 *seat_x11, translate_raw_event (MetaSeatX11 *seat_x11,
XEvent *xevent) XEvent *xevent)
@ -890,9 +914,6 @@ translate_raw_event (MetaSeatX11 *seat_x11,
if (device == NULL) if (device == NULL)
return; return;
if (!_clutter_is_input_pointer_a11y_enabled (device))
return;
switch (cookie->evtype) switch (cookie->evtype)
{ {
case XI_RawMotion: case XI_RawMotion:
@ -906,7 +927,12 @@ translate_raw_event (MetaSeatX11 *seat_x11,
* so we need to explicitly query the pointer here... * so we need to explicitly query the pointer here...
*/ */
if (meta_input_device_x11_get_pointer_location (device, &x, &y)) if (meta_input_device_x11_get_pointer_location (device, &x, &y))
_clutter_input_pointer_a11y_on_motion_event (device, x, y); {
if (_clutter_is_input_pointer_a11y_enabled (device))
_clutter_input_pointer_a11y_on_motion_event (device, x, y);
if (!seat_x11->has_pointer_focus)
emulate_motion (seat_x11, x, y);
}
break; break;
case XI_RawButtonPress: case XI_RawButtonPress:
case XI_RawButtonRelease: case XI_RawButtonRelease:
@ -917,9 +943,12 @@ translate_raw_event (MetaSeatX11 *seat_x11,
meta_input_device_x11_get_device_id (device), meta_input_device_x11_get_device_id (device),
clutter_input_device_get_device_name (device), clutter_input_device_get_device_name (device),
xev->detail); xev->detail);
_clutter_input_pointer_a11y_on_button_event (device, if (_clutter_is_input_pointer_a11y_enabled (device))
xev->detail, {
(cookie->evtype == XI_RawButtonPress)); _clutter_input_pointer_a11y_on_button_event (device,
xev->detail,
(cookie->evtype == XI_RawButtonPress));
}
break; break;
} }
} }
@ -2291,6 +2320,9 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat,
event->crossing.time = xev->time; event->crossing.time = xev->time;
translate_coords (stage_x11, xev->event_x, xev->event_y, &event->crossing.x, &event->crossing.y); translate_coords (stage_x11, xev->event_x, xev->event_y, &event->crossing.x, &event->crossing.y);
if (xev->deviceid == seat->pointer_id)
seat->has_pointer_focus = TRUE;
} }
else else
{ {
@ -2302,6 +2334,9 @@ meta_seat_x11_translate_event (MetaSeatX11 *seat,
event->crossing.time = xev->time; event->crossing.time = xev->time;
translate_coords (stage_x11, xev->event_x, xev->event_y, &event->crossing.x, &event->crossing.y); translate_coords (stage_x11, xev->event_x, xev->event_y, &event->crossing.x, &event->crossing.y);
if (xev->deviceid == seat->pointer_id)
seat->has_pointer_focus = FALSE;
} }
meta_input_device_x11_reset_scroll_info (source_device); meta_input_device_x11_reset_scroll_info (source_device);