xwayland: Fallback to plain XTEST if EI does not work

With optional EI support in Xwayland, we would route XTEST events to EI
so that they get actually emulated in the Wayland compositor.

However, this implies that EI is actually supported in various places,
including the Wayland compositor of course. If, for whatever reason, we
fail to use EI, the actual XTEST events will be dropped.

That might be seen as a regression, as previously those would go through
the usual X11 processing of events and might have worked with X11 native
clients.

So, to keep backward compatibility, fallback to the plain old XTEST
method if EI is not available or not usable.

Signed-off-by: Olivier Fourdan <ofourdan@redhat.com>
This commit is contained in:
Olivier Fourdan 2023-06-20 16:17:36 +02:00
parent a133334270
commit befef003d4
3 changed files with 99 additions and 10 deletions

View File

@ -3505,5 +3505,8 @@ InitInput(int argc, char *argv[])
void
CloseInput(void)
{
#ifdef XWL_HAS_EI
xwayland_restore_xtest();
#endif
mieqFini();
}

View File

@ -47,8 +47,14 @@
static struct xorg_list clients_for_reuse;
static DevPrivateKeyRec xwl_ei_private_key;
static DevPrivateKeyRec xwl_device_data_private_key;
struct xwl_device_data {
DeviceSendEventsProc sendEventsProc;
};
struct xwl_emulated_event {
DeviceIntPtr dev;
int type;
int detail;
int flags;
@ -82,6 +88,13 @@ struct xwl_ei_client {
};
static void xwl_handle_ei_event(int fd, int ready, void *data);
static bool xwl_dequeue_emulated_events(struct xwl_ei_client *xwl_ei_client);
static struct xwl_device_data *
xwl_device_data_get(DeviceIntPtr dev)
{
return dixLookupPrivate(&dev->devPrivates, &xwl_device_data_private_key);
}
static struct xwl_ei_client *
get_xwl_ei_client(ClientPtr client)
@ -90,7 +103,7 @@ get_xwl_ei_client(ClientPtr client)
}
static void
xwl_queue_emulated_event(struct xwl_ei_client *xwl_ei_client,
xwl_queue_emulated_event(struct xwl_ei_client *xwl_ei_client, DeviceIntPtr dev,
int type, int detail, int flags, const ValuatorMask *mask)
{
struct xwl_emulated_event *xwl_emulated_event;
@ -101,6 +114,7 @@ xwl_queue_emulated_event(struct xwl_ei_client *xwl_ei_client,
return;
}
xwl_emulated_event->dev = dev;
xwl_emulated_event->type = type;
xwl_emulated_event->detail = detail;
xwl_emulated_event->flags = flags;
@ -252,6 +266,7 @@ xwl_handle_oeffis_event(int fd, int ready, void *data)
case OEFFIS_EVENT_DISCONNECTED:
debug_ei("OEFFIS disconnected: %s\n",
oeffis_get_error_message(oeffis));
xwl_dequeue_emulated_events(xwl_ei_client);
free_ei(xwl_ei_client);
done = true;
break;
@ -604,6 +619,19 @@ reuse_client(ClientPtr client)
return NULL;
}
static void
xwayland_xtest_fallback(DeviceIntPtr dev,
int type, int detail, int flags, const ValuatorMask *mask)
{
struct xwl_device_data *xwl_device_data = xwl_device_data_get(dev);
if (xwl_device_data->sendEventsProc != NULL) {
debug_ei("EI failed, using XTEST as fallback for sending events\n");
(xwl_device_data->sendEventsProc)(dev, type, detail, flags, mask);
}
}
static void
xwayland_xtest_send_events(DeviceIntPtr dev,
int type, int detail, int flags, const ValuatorMask *mask)
@ -621,8 +649,10 @@ xwayland_xtest_send_events(DeviceIntPtr dev,
}
if (!xwl_ei_client) {
if (!(xwl_ei_client = setup_ei(client)))
if (!(xwl_ei_client = setup_ei(client))) {
xwayland_xtest_fallback(dev, type, detail, flags, mask);
return;
}
}
dixSetPrivate(&client->devPrivates, &xwl_ei_private_key, xwl_ei_client);
@ -650,7 +680,7 @@ xwayland_xtest_send_events(DeviceIntPtr dev,
}
else {
debug_ei("Not yet connected to EIS, queueing events\n");
xwl_queue_emulated_event(xwl_ei_client, type, detail, flags, mask);
xwl_queue_emulated_event(xwl_ei_client, dev, type, detail, flags, mask);
}
}
@ -659,14 +689,22 @@ static bool
xwl_dequeue_emulated_events(struct xwl_ei_client *xwl_ei_client)
{
struct xwl_emulated_event *xwl_emulated_event, *next_xwl_emulated_event;
bool sent;
xorg_list_for_each_entry_safe(xwl_emulated_event, next_xwl_emulated_event,
&xwl_ei_client->pending_emulated_events, link) {
if (!xwl_send_event_to_ei(xwl_ei_client,
xwl_emulated_event->type,
xwl_emulated_event->detail,
xwl_emulated_event->flags, &xwl_emulated_event->mask))
return false;
sent = xwl_send_event_to_ei(xwl_ei_client,
xwl_emulated_event->type,
xwl_emulated_event->detail,
xwl_emulated_event->flags,
&xwl_emulated_event->mask);
if (!sent)
xwayland_xtest_fallback(xwl_emulated_event->dev,
xwl_emulated_event->type,
xwl_emulated_event->detail,
xwl_emulated_event->flags,
&xwl_emulated_event->mask);
xorg_list_del(&xwl_emulated_event->link);
free(xwl_emulated_event);
}
@ -825,9 +863,45 @@ xwayland_ei_init(void)
return FALSE;
}
if (!dixRegisterPrivateKey(&xwl_device_data_private_key, PRIVATE_DEVICE,
sizeof(struct xwl_device_data))) {
ErrorF("Failed to register private key for XTEST override\n");
return FALSE;
}
return TRUE;
}
static void
xwayland_override_events_proc(DeviceIntPtr dev)
{
struct xwl_device_data *xwl_device_data = xwl_device_data_get(dev);
if (xwl_device_data->sendEventsProc != NULL)
return;
/* Save original sendEventsProc handler in case */
xwl_device_data->sendEventsProc = dev->sendEventsProc;
/* Set up our own sendEventsProc to forward events to EI */
debug_ei("Overriding XTEST for %s\n", dev->name);
dev->sendEventsProc = xwayland_xtest_send_events;
}
static void
xwayland_restore_events_proc(DeviceIntPtr dev)
{
struct xwl_device_data *xwl_device_data = xwl_device_data_get(dev);
if (xwl_device_data->sendEventsProc == NULL)
return;
/* Restore original sendEventsProc handler */
debug_ei("Restoring XTEST for %s\n", dev->name);
dev->sendEventsProc = xwl_device_data->sendEventsProc;
xwl_device_data->sendEventsProc = NULL;
}
void
xwayland_override_xtest(void)
{
@ -835,8 +909,19 @@ xwayland_override_xtest(void)
nt_list_for_each_entry(d, inputInfo.devices, next) {
if (IsXTestDevice(d, NULL)) {
debug_ei("Overriding XTest for %s\n", d->name);
d->sendEventsProc = xwayland_xtest_send_events;
xwayland_override_events_proc(d);
}
}
}
void
xwayland_restore_xtest(void)
{
DeviceIntPtr d;
nt_list_for_each_entry(d, inputInfo.devices, next) {
if (IsXTestDevice(d, NULL)) {
xwayland_restore_events_proc(d);
}
}
}

View File

@ -30,5 +30,6 @@
Bool xwayland_ei_init(void);
void xwayland_override_xtest(void);
void xwayland_restore_xtest(void);
#endif