mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-01-09 14:30:18 +01:00
libei: immediately remove devices added for a removed seat
Once the SEAT_REMOVED event has been processed, adding new devices is pointless. But we do promise a DEVICE_REMOVED event for any device added with ei_device_add(), so let's immediately queue an event and mark the device as dead. Since the SEAT_REMOVED event may still be pending in the queue (i.e. not yet read by the client), we need to prepend the event to the queue. Note that client that immediately add a device when a device is removed will cause an infinite loop. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
f068ddf2a8
commit
c317de742b
5 changed files with 168 additions and 0 deletions
|
|
@ -310,8 +310,21 @@ ei_device_set_keymap(struct ei_device *device,
|
|||
_public_ void
|
||||
ei_device_add(struct ei_device *device)
|
||||
{
|
||||
struct ei_seat *seat = ei_device_get_seat(device);
|
||||
|
||||
switch (device->state) {
|
||||
case EI_DEVICE_STATE_NEW:
|
||||
/* If the caller tries to add a device to a seat that has
|
||||
* been removed, immediately drop that device. But since our
|
||||
* SEAT_REMOVED event may still be in the queue, prepend the
|
||||
* device to the rest of the queue.
|
||||
*/
|
||||
if (seat->state == EI_SEAT_STATE_REMOVED) {
|
||||
ei_insert_device_removed_event(device);
|
||||
ei_device_set_state(device, EI_DEVICE_STATE_DEAD);
|
||||
ei_device_unref(device);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case EI_DEVICE_STATE_REMOVED_FROM_CLIENT:
|
||||
case EI_DEVICE_STATE_REMOVED_FROM_SERVER:
|
||||
|
|
|
|||
|
|
@ -183,6 +183,9 @@ ei_send_remove_device(struct ei_device *device);
|
|||
void
|
||||
ei_queue_device_removed_event(struct ei_device *device);
|
||||
|
||||
void
|
||||
ei_insert_device_removed_event(struct ei_device *device);
|
||||
|
||||
void
|
||||
ei_queue_seat_removed_event(struct ei_seat *seat);
|
||||
|
||||
|
|
|
|||
28
src/libei.c
28
src/libei.c
|
|
@ -189,6 +189,16 @@ queue_event(struct ei *ei, struct ei_event *event)
|
|||
list_append(&ei->event_queue, &event->link);
|
||||
}
|
||||
|
||||
static void
|
||||
insert_event(struct ei *ei, struct ei_event *event)
|
||||
{
|
||||
log_debug(ei, "inserting event type %s (%d)\n",
|
||||
ei_event_type_to_string(event->type), event->type);
|
||||
|
||||
list_insert(&ei->event_queue, &event->link);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
queue_connect_event(struct ei *ei)
|
||||
{
|
||||
|
|
@ -261,6 +271,18 @@ queue_device_removed_event(struct ei_device *device)
|
|||
queue_event(ei, e);
|
||||
}
|
||||
|
||||
static void
|
||||
insert_device_removed_event(struct ei_device *device)
|
||||
{
|
||||
struct ei *ei= ei_device_get_context(device);
|
||||
|
||||
struct ei_event *e = ei_event_create(&ei->object);
|
||||
e->type = EI_EVENT_DEVICE_REMOVED;
|
||||
e->device = ei_device_ref(device);
|
||||
|
||||
insert_event(ei, e);
|
||||
}
|
||||
|
||||
static void
|
||||
queue_suspended_event(struct ei_device *device)
|
||||
{
|
||||
|
|
@ -529,6 +551,12 @@ ei_queue_device_removed_event(struct ei_device *device)
|
|||
queue_device_removed_event(device);
|
||||
}
|
||||
|
||||
void
|
||||
ei_insert_device_removed_event(struct ei_device *device)
|
||||
{
|
||||
insert_device_removed_event(device);
|
||||
}
|
||||
|
||||
static int
|
||||
handle_msg_device_removed(struct ei *ei, uint32_t deviceid)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -788,6 +788,10 @@ ei_device_keyboard_configure_keymap(struct ei_device *device,
|
|||
*
|
||||
* A client may not send events through this device until it has been added
|
||||
* by the server.
|
||||
*
|
||||
* Devices should only be added once all events from ei_get_event() have
|
||||
* been processed. It is considered a client bug to add a device to a seat
|
||||
* after the SEAT_REMOVED has been received by libei.
|
||||
*/
|
||||
void
|
||||
ei_device_add(struct ei_device *device);
|
||||
|
|
|
|||
120
test/test-ei.c
120
test/test-ei.c
|
|
@ -840,6 +840,126 @@ MUNIT_TEST(test_ei_device_add_zero_caps)
|
|||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
MUNIT_TEST(test_ei_device_add_after_seat_remove)
|
||||
{
|
||||
_unref_(peck) *peck = peck_new();
|
||||
|
||||
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
|
||||
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_HANDLE_ADDED);
|
||||
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_HANDLE_RESUMED);
|
||||
peck_dispatch_until_stable(peck);
|
||||
|
||||
with_client(peck) {
|
||||
struct ei_seat *seat = peck_ei_get_default_seat(peck);
|
||||
_unref_(ei_device) *device = ei_device_new(seat);
|
||||
|
||||
ei_device_configure_name(device, __func__);
|
||||
ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
|
||||
ei_device_add(device);
|
||||
}
|
||||
|
||||
peck_dispatch_until_stable(peck);
|
||||
|
||||
with_server(peck) {
|
||||
struct eis_seat *seat = peck_eis_get_default_seat(peck);
|
||||
eis_seat_remove(seat);
|
||||
}
|
||||
|
||||
/* Seat was removed by server but we don't know this yet, let's add
|
||||
* a device */
|
||||
with_client(peck) {
|
||||
struct ei_seat *seat = peck_ei_get_default_seat(peck);
|
||||
_unref_(ei_device) *device = ei_device_new(seat);
|
||||
ei_device_configure_name(device, __func__);
|
||||
ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
|
||||
ei_device_add(device);
|
||||
}
|
||||
|
||||
peck_dispatch_until_stable(peck);
|
||||
|
||||
/* Now add a device while the SEAT_REMOVED event is pending */
|
||||
with_client(peck) {
|
||||
/* The original device */
|
||||
_unref_(ei_event) *removed1 =
|
||||
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
|
||||
|
||||
/* The device added before we knew about seat removal */
|
||||
_unref_(ei_event) *removed2 =
|
||||
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
|
||||
|
||||
struct ei_seat *seat = peck_ei_get_default_seat(peck);
|
||||
_unref_(ei_device) *device = ei_device_new(seat);
|
||||
ei_device_configure_name(device, __func__);
|
||||
ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
|
||||
ei_device_add(device);
|
||||
|
||||
/* The device added just above */
|
||||
_unref_(ei_event) *removed3 =
|
||||
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
|
||||
|
||||
_unref_(ei_event) *seat_removed =
|
||||
peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED);
|
||||
}
|
||||
|
||||
/* Now add a device when the seat had already been removed */
|
||||
with_client(peck) {
|
||||
struct ei_seat *seat = peck_ei_get_default_seat(peck);
|
||||
_unref_(ei_device) *device = ei_device_new(seat);
|
||||
ei_device_configure_name(device, __func__);
|
||||
ei_device_configure_capability(device, EI_DEVICE_CAP_POINTER);
|
||||
ei_device_add(device);
|
||||
|
||||
_unref_(ei_event) *removed =
|
||||
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
|
||||
}
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
MUNIT_TEST(test_ei_device_add_after_disconnect)
|
||||
{
|
||||
_unref_(peck) *peck = peck_new();
|
||||
|
||||
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL);
|
||||
peck_dispatch_until_stable(peck);
|
||||
|
||||
with_server(peck) {
|
||||
struct eis_client *client = peck_eis_get_default_client(peck);
|
||||
eis_client_disconnect(client);
|
||||
}
|
||||
|
||||
peck_dispatch_until_stable(peck);
|
||||
|
||||
with_client(peck) {
|
||||
struct ei_seat *seat = peck_ei_get_default_seat(peck);
|
||||
_unref_(ei_device) *d1 = ei_device_new(seat);
|
||||
|
||||
ei_device_configure_name(d1, __func__);
|
||||
ei_device_configure_capability(d1, EI_DEVICE_CAP_POINTER);
|
||||
ei_device_add(d1);
|
||||
|
||||
_unref_(ei_event) *removed1 =
|
||||
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
|
||||
|
||||
_unref_(ei_event) *seat_removed =
|
||||
peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED);
|
||||
|
||||
_unref_(ei_device) *d2 = ei_device_new(seat);
|
||||
|
||||
ei_device_configure_name(d2, __func__);
|
||||
ei_device_configure_capability(d2, EI_DEVICE_CAP_POINTER);
|
||||
ei_device_add(d2);
|
||||
|
||||
_unref_(ei_event) *removed2 =
|
||||
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
|
||||
|
||||
_unref_(ei_event) *disconnect =
|
||||
peck_ei_next_event(ei, EI_EVENT_DISCONNECT);
|
||||
}
|
||||
|
||||
return MUNIT_OK;
|
||||
}
|
||||
|
||||
MUNIT_TEST(test_ei_device_pointer_rel)
|
||||
{
|
||||
_unref_(peck) *peck = peck_new();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue