From 358a528478f53f3685d205957ca049fa2c6fa81b Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Wed, 21 Jul 2021 10:22:09 +1000 Subject: [PATCH] Add support for seat unbinding This required a bit of cleanup with the eis device handling. Signed-off-by: Peter Hutterer --- src/libeis-client.c | 4 +- src/libeis-device.c | 36 ++--------- src/libeis-private.h | 4 -- src/libeis-seat.c | 25 -------- test/eierpecken.c | 46 +++++++++----- test/eierpecken.h | 18 ++++-- test/test-ei.c | 141 +++++++++++++++++++++++++++++++++++++++++++ test/test-eis.c | 4 +- 8 files changed, 192 insertions(+), 86 deletions(-) diff --git a/src/libeis-client.c b/src/libeis-client.c index fe246be..a6bd501 100644 --- a/src/libeis-client.c +++ b/src/libeis-client.c @@ -155,7 +155,7 @@ eis_client_disconnect(struct eis_client *client) { struct eis_seat *s, *tmp; list_for_each_safe(s, tmp, &client->seats, link) { - eis_seat_disconnect(s); + eis_seat_remove(s); } } eis_queue_disconnect_event(client); @@ -210,7 +210,7 @@ client_seat_unbind(struct eis_client *client, uint32_t seatid) list_for_each(seat, &client->seats, link) { if (seat->id == seatid) { - /* FIXME */ + eis_queue_seat_unbind_event(seat); return 0; } } diff --git a/src/libeis-device.c b/src/libeis-device.c index 8a6e35b..c2377ef 100644 --- a/src/libeis-device.c +++ b/src/libeis-device.c @@ -238,7 +238,10 @@ eis_device_add(struct eis_device *device) _public_ void eis_device_remove(struct eis_device *device) { - device->state = EIS_DEVICE_STATE_REMOVED_BY_SERVER ; + if (device->state == EIS_DEVICE_STATE_DEAD) + return; + + device->state = EIS_DEVICE_STATE_DEAD; eis_client_remove_device(eis_device_get_client(device), device); list_remove(&device->link); eis_device_unref(device); @@ -448,33 +451,6 @@ eis_device_touch(struct eis_device *device, uint32_t touchid, return 0; } -#if 0 /* FIXME: needs to move to eis_device_remove */ -_public_ void -eis_device_disconnect(struct eis_device *device) -{ - switch (device->state) { - case EIS_DEVICE_STATE_DEAD: - case EIS_DEVICE_STATE_REMOVED_BY_SERVER: - break; - /* server is the first to drop the device. Notify the client but the - * local event comes when the client acks it */ - case EIS_DEVICE_STATE_NEW: - case EIS_DEVICE_STATE_SUSPENDED: - case EIS_DEVICE_STATE_RESUMED: - device->state = EIS_DEVICE_STATE_REMOVED_BY_SERVER; - eis_client_disconnect_device(eis_device_get_client(device), device); - break; - /* device was already removed by the client, so it's properly gone - * now */ - case EIS_DEVICE_STATE_CLOSED_BY_CLIENT: - device->state = EIS_DEVICE_STATE_DEAD; - list_remove(&device->link); - eis_device_unref(device); - break; - } -} -#endif - void eis_device_closed_by_client(struct eis_device *device) { @@ -483,15 +459,11 @@ eis_device_closed_by_client(struct eis_device *device) case EIS_DEVICE_STATE_CLOSED_BY_CLIENT: /* libei bug, ignore */ break; - case EIS_DEVICE_STATE_REMOVED_BY_SERVER: - /* FIXME: Late arrival after eis_device_removed? */ - break; case EIS_DEVICE_STATE_NEW: case EIS_DEVICE_STATE_SUSPENDED: case EIS_DEVICE_STATE_RESUMED: eis_queue_device_closed_event(device); device->state = EIS_DEVICE_STATE_CLOSED_BY_CLIENT; - eis_client_remove_device(eis_device_get_client(device), device); break; } } diff --git a/src/libeis-private.h b/src/libeis-private.h index 640bfae..dfea0e6 100644 --- a/src/libeis-private.h +++ b/src/libeis-private.h @@ -106,7 +106,6 @@ enum eis_device_state { EIS_DEVICE_STATE_SUSPENDED, EIS_DEVICE_STATE_RESUMED, EIS_DEVICE_STATE_CLOSED_BY_CLIENT, - EIS_DEVICE_STATE_REMOVED_BY_SERVER, EIS_DEVICE_STATE_DEAD, }; @@ -206,9 +205,6 @@ eis_client_suspend_device(struct eis_client *client, void eis_seat_bind(struct eis_seat *seat, uint32_t cap); -void -eis_seat_disconnect(struct eis_seat *seat); - void eis_device_set_pointer_range(struct eis_device *device, uint32_t w, uint32_t h); diff --git a/src/libeis-seat.c b/src/libeis-seat.c index cae3d74..9b375d9 100644 --- a/src/libeis-seat.c +++ b/src/libeis-seat.c @@ -113,15 +113,6 @@ eis_seat_remove(struct eis_seat *seat) return; } - /* We have a problem here: the server controls the seat but - * we wait for the client to acknowledge device removal. so we can't - * actually remove the seat until all devices within are gone. - * - * So we disconnect the device (sending a message to the client) - * and mark the seat as removed. When the messages for the - * removed devices come in from the client, we can remove the seat - * for real. - */ struct eis_device *d, *tmp; list_for_each_safe(d, tmp, &seat->devices, link) { eis_device_remove(d); @@ -129,22 +120,6 @@ eis_seat_remove(struct eis_seat *seat) eis_client_remove_seat(eis_seat_get_client(seat), seat); seat->state = EIS_SEAT_STATE_REMOVED; -} - -void -eis_seat_disconnect(struct eis_seat *seat) -{ - /* First, remove the seat as if the caller did it */ - eis_seat_remove(seat); - - /* Now process all devices as if the client had sent us the - * device removed event. */ - struct eis_device *d, *tmp; - list_for_each_safe(d, tmp, &seat->devices, link) { - eis_device_closed_by_client(d); - } - - seat->state = EIS_SEAT_STATE_DEAD; list_remove(&seat->link); eis_seat_unref(seat); } diff --git a/test/eierpecken.c b/test/eierpecken.c index 4a88699..50e604c 100644 --- a/test/eierpecken.c +++ b/test/eierpecken.c @@ -334,8 +334,9 @@ peck_enable_eis_behavior(struct peck *peck, enum peck_eis_behavior behavior) case PECK_EIS_BEHAVIOR_ACCEPT_ALL: peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT); - peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_BIND_SEAT); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_HANDLE_BIND_SEAT); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_RESUME_DEVICE); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_HANDLE_CLOSE_DEVICE); break; case PECK_EIS_BEHAVIOR_ADD_DEVICES: peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_POINTER); @@ -347,16 +348,9 @@ peck_enable_eis_behavior(struct peck *peck, enum peck_eis_behavior behavior) flag_clear(peck->eis_behavior, behavior - 1); flag_set(peck->eis_behavior, behavior); break; - case PECK_EIS_BEHAVIOR_ACCEPT_UNBIND_SEAT: - case PECK_EIS_BEHAVIOR_ACCEPT_BIND_SEAT: - flag_clear(peck->eis_behavior, behavior + 1); - flag_set(peck->eis_behavior, behavior); - break; - case PECK_EIS_BEHAVIOR_REJECT_UNBIND_SEAT: - case PECK_EIS_BEHAVIOR_REJECT_BIND_SEAT: - flag_clear(peck->eis_behavior, behavior - 1); - flag_set(peck->eis_behavior, behavior); - break; + case PECK_EIS_BEHAVIOR_HANDLE_BIND_SEAT: + case PECK_EIS_BEHAVIOR_HANDLE_UNBIND_SEAT: + case PECK_EIS_BEHAVIOR_HANDLE_CLOSE_DEVICE: case PECK_EIS_BEHAVIOR_ADD_POINTER: case PECK_EIS_BEHAVIOR_ADD_POINTER_ABSOLUTE: case PECK_EIS_BEHAVIOR_ADD_KEYBOARD: @@ -556,9 +550,22 @@ peck_handle_eis_seat_bind(struct peck *peck, struct eis_event *e) static inline void peck_handle_eis_seat_unbind(struct peck *peck, struct eis_seat *seat) { - /* FIXME */ + eis_seat_remove(seat); } +static inline void +peck_eis_device_remove(struct peck *peck, struct eis_device *device) +{ + eis_device_remove(device); + if (device == peck->eis_pointer) + peck->eis_pointer = eis_device_unref(device); + if (device == peck->eis_abs) + peck->eis_abs = eis_device_unref(device); + if (device == peck->eis_keyboard) + peck->eis_keyboard = eis_device_unref(device); + if (device == peck->eis_touch) + peck->eis_touch = eis_device_unref(device); +} bool _peck_dispatch_eis(struct peck *peck, int lineno) @@ -585,15 +592,19 @@ _peck_dispatch_eis(struct peck *peck, int lineno) process_event = tristate_yes; break; case EIS_EVENT_SEAT_BIND: - if (flag_is_set(peck->eis_behavior, PECK_EIS_BEHAVIOR_ACCEPT_BIND_SEAT) || - flag_is_set(peck->eis_behavior, PECK_EIS_BEHAVIOR_REJECT_BIND_SEAT)) + if (flag_is_set(peck->eis_behavior, PECK_EIS_BEHAVIOR_HANDLE_BIND_SEAT)) process_event = tristate_yes; else process_event = tristate_no; break; case EIS_EVENT_SEAT_UNBIND: - if (flag_is_set(peck->eis_behavior, PECK_EIS_BEHAVIOR_ACCEPT_UNBIND_SEAT) || - flag_is_set(peck->eis_behavior, PECK_EIS_BEHAVIOR_REJECT_UNBIND_SEAT)) + if (flag_is_set(peck->eis_behavior, PECK_EIS_BEHAVIOR_HANDLE_UNBIND_SEAT)) + process_event = tristate_yes; + else + process_event = tristate_no; + break; + case EIS_EVENT_DEVICE_CLOSED: + if (flag_is_set(peck->eis_behavior, PECK_EIS_BEHAVIOR_HANDLE_CLOSE_DEVICE)) process_event = tristate_yes; else process_event = tristate_no; @@ -631,6 +642,9 @@ _peck_dispatch_eis(struct peck *peck, int lineno) case EIS_EVENT_SEAT_UNBIND: peck_handle_eis_seat_unbind(peck, eis_event_get_seat(e)); break; + case EIS_EVENT_DEVICE_CLOSED: + peck_eis_device_remove(peck, eis_event_get_device(e)); + break; default: break; } diff --git a/test/eierpecken.h b/test/eierpecken.h index 06b8c16..32ca980 100644 --- a/test/eierpecken.h +++ b/test/eierpecken.h @@ -65,12 +65,20 @@ enum peck_eis_behavior { PECK_EIS_BEHAVIOR_NO_DEFAULT_SEAT, /** - * Accept or reject bind/unbind seat requests + * Handle the bind seat request */ - PECK_EIS_BEHAVIOR_ACCEPT_BIND_SEAT, - PECK_EIS_BEHAVIOR_REJECT_BIND_SEAT, - PECK_EIS_BEHAVIOR_ACCEPT_UNBIND_SEAT, - PECK_EIS_BEHAVIOR_REJECT_UNBIND_SEAT, + PECK_EIS_BEHAVIOR_HANDLE_BIND_SEAT, + + /** + * Handle the seat unbind request + */ + PECK_EIS_BEHAVIOR_HANDLE_UNBIND_SEAT, + + /** + * Handle the device close. This behavior is enabled as part of + * PECK_EIS_BEHAVIOR_ACCEPT_ALL. + */ + PECK_EIS_BEHAVIOR_HANDLE_CLOSE_DEVICE, /** * Create default devices diff --git a/test/test-ei.c b/test/test-ei.c index e909d7c..248e1ae 100644 --- a/test/test-ei.c +++ b/test/test-ei.c @@ -446,6 +446,147 @@ MUNIT_TEST(test_ei_disconnect_after_unbind_after_received) return MUNIT_OK; } +MUNIT_TEST(test_ei_seat_bind_unbind) +{ + _unref_(peck) *peck = peck_new(); + _unref_(ei_seat) *seat = NULL; + _unref_(ei_device) *dev1 = NULL; + _unref_(ei_device) *dev2 = NULL; + + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_POINTER); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_KEYBOARD); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_HANDLE_UNBIND_SEAT); + peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE); + peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT); + peck_dispatch_until_stable(peck); + + with_client(peck) { + _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED); + seat = ei_seat_ref(ei_event_get_seat(event)); + ei_seat_bind(seat); + } + + /* server has the Bind event now and creates devices */ + peck_dispatch_until_stable(peck); + + with_client(peck) { + _unref_(ei_event) *e1 = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); + _unref_(ei_event) *discard1 = peck_ei_next_event(ei, EI_EVENT_DEVICE_RESUMED); + _unref_(ei_event) *e2 = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); + _unref_(ei_event) *discard2 = peck_ei_next_event(ei, EI_EVENT_DEVICE_RESUMED); + + dev1 = ei_device_ref(ei_event_get_device(e1)); + dev2 = ei_device_ref(ei_event_get_device(e2)); + + ei_seat_unbind(seat); + } + + /* Dispatch, server is aware of the ei_seat_unbind() */ + peck_dispatch_until_stable(peck); + + with_client(peck) { + _unref_(ei_event) *e1 = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); + _unref_(ei_event) *e2 = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); + + struct ei_device *d1 = ei_event_get_device(e1); + struct ei_device *d2 = ei_event_get_device(e2); + + munit_assert(d1 != d2); + munit_assert(d1 == dev1 || d1 == dev2); + munit_assert(d2 == dev1 || d2 == dev2); + + _unref_(ei_event) *eseat = peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED); + struct ei_seat *s = ei_event_get_seat(eseat); + munit_assert_ptr_equal(s, seat); + } + + return MUNIT_OK; +} + +MUNIT_TEST(test_ei_seat_bind_unbind_noref) +{ + _unref_(peck) *peck = peck_new(); + struct ei_seat *seat = NULL; + + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_POINTER); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_KEYBOARD); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_HANDLE_UNBIND_SEAT); + peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE); + peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT); + peck_dispatch_until_stable(peck); + + with_client(peck) { + _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED); + seat = ei_seat_ref(ei_event_get_seat(event)); + ei_seat_bind(seat); + } + + /* server has the Bind event now and creates devices */ + peck_dispatch_until_stable(peck); + + with_client(peck) { + _unref_(ei_event) *e1 = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); + _unref_(ei_event) *discard1 = peck_ei_next_event(ei, EI_EVENT_DEVICE_RESUMED); + _unref_(ei_event) *e2 = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); + _unref_(ei_event) *discard2 = peck_ei_next_event(ei, EI_EVENT_DEVICE_RESUMED); + + /* Drop our ref before unbinding. This is technically wrong - + * must not use seat after unref, but we know there's at least + * one ref inside libei for this seat, so this tests ensures + * we don't rely on a caller ref to keep everything alive. */ + ei_seat_unref(seat); + ei_seat_unbind(seat); + } + + /* Dispatch, server is aware of the ei_seat_unbind() */ + peck_dispatch_until_stable(peck); + + with_client(peck) { + _unref_(ei_event) *e1 = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); + _unref_(ei_event) *e2 = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); + _unref_(ei_event) *eseat = peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED); + } + + return MUNIT_OK; +} + +MUNIT_TEST(test_ei_seat_bind_unbind_immediately) +{ + _unref_(peck) *peck = peck_new(); + struct ei_seat *seat = NULL; + + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_POINTER); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_KEYBOARD); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_HANDLE_UNBIND_SEAT); + peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_NONE); + peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNECT); + peck_dispatch_until_stable(peck); + + with_client(peck) { + _unref_(ei_event) *event = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED); + seat = ei_event_get_seat(event); + ei_seat_bind(seat); + ei_seat_unbind(seat); + } + + peck_dispatch_until_stable(peck); + + with_client(peck) { + _unref_(ei_event) *e1 = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); + _unref_(ei_event) *e2 = peck_ei_next_event(ei, EI_EVENT_DEVICE_RESUMED); + _unref_(ei_event) *e3 = peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED); + _unref_(ei_event) *e4 = peck_ei_next_event(ei, EI_EVENT_DEVICE_RESUMED); + _unref_(ei_event) *e5 = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); + _unref_(ei_event) *e6 = peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED); + _unref_(ei_event) *e7 = peck_ei_next_event(ei, EI_EVENT_SEAT_REMOVED); + } + + return MUNIT_OK; +} + MUNIT_TEST(test_ei_device_basics) { _unref_(peck) *peck = peck_new(); diff --git a/test/test-eis.c b/test/test-eis.c index 3dfee94..188d70e 100644 --- a/test/test-eis.c +++ b/test/test-eis.c @@ -187,7 +187,7 @@ MUNIT_TEST(eistest_device_resume_suspend_twice) peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT); - peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_BIND_SEAT); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_HANDLE_BIND_SEAT); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_POINTER); peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_HANDLE_ADDED); peck_dispatch_until_stable(peck); @@ -237,7 +237,7 @@ MUNIT_TEST(eistest_device_ignore_suspended_device) peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_DEFAULT_SEAT); - peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_BIND_SEAT); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_HANDLE_BIND_SEAT); peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_POINTER); peck_dispatch_until_stable(peck);