From 62ae6f5edf3c4b71ebff4790fb393bae6a39f5f1 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 28 Nov 2024 15:38:06 +1000 Subject: [PATCH] ei: make ei_disconnect() public Previously the only way to disconnect from the EIS implementation was to call ei_unref() and release all resources. This makes it more difficult for shared cleanup code - clients already have code in place to deal with DEVICE_REMOVED, SEAT_REMOVED, etc. but that code has to be triggered manually before ei_unref() is called. OTOH where the server disconnects us, libei already unwound the state so we would artificially generate these removed events, allowing the client to clean up. Make life easier for client by allowing them to ei_disconnect() and get the benefits of our state unwinding. ei_disconnect() was already used internally to disconnect on any error so this merely makes this function public. Closes #67 Part-of: --- src/libei-private.h | 3 --- src/libei.c | 2 +- src/libei.h | 18 ++++++++++++++ test/test-ei.c | 60 +++++++++++++++++++++++++++++++++++++++------ 4 files changed, 71 insertions(+), 12 deletions(-) diff --git a/src/libei-private.h b/src/libei-private.h index 10133c9..02791a8 100644 --- a/src/libei-private.h +++ b/src/libei-private.h @@ -131,9 +131,6 @@ ei_get_interface(struct ei *ei); int ei_set_socket(struct ei *ei, int fd); -void -ei_disconnect(struct ei *ei); - struct ei * ei_get_context(struct ei *ei); diff --git a/src/libei.c b/src/libei.c index c80018b..286e062 100644 --- a/src/libei.c +++ b/src/libei.c @@ -580,7 +580,7 @@ ei_queue_touch_up_event(struct ei_device *device, uint32_t touchid) queue_event(ei_device_get_context(device), e); } -void +_public_ void ei_disconnect(struct ei *ei) { if (ei->state == EI_STATE_DISCONNECTED || diff --git a/src/libei.h b/src/libei.h index 8375de1..a9588dd 100644 --- a/src/libei.h +++ b/src/libei.h @@ -849,6 +849,24 @@ ei_peek_event(struct ei *ei); uint64_t ei_now(struct ei *ei); +/** + * Disconnect the current ei context from the EIS implementation. + * + * After a call to ei_disconnect(), ei_get_event() will return + * events to remove resources (e.g. seats and devices) as if they + * had been removed by the EIS implementation. The last event + * returned by ei_get_event() is @ref EI_EVENT_DISCONNECT after + * which the context should be considered inert and any + * remaining resources released with ei_unref(). + * + * This does not free the resources associated with the ei context, use + * ei_unref(). + * + * @since 1.4 + */ +void +ei_disconnect(struct ei *ei); + /** * @ingroup libei-seat * diff --git a/test/test-ei.c b/test/test-ei.c index 711e0d3..697011e 100644 --- a/test/test-ei.c +++ b/test/test-ei.c @@ -67,7 +67,7 @@ MUNIT_TEST(test_ei_disconnect_immediately) return MUNIT_OK; } -MUNIT_TEST(test_ei_disconnect_self_immediately) +MUNIT_TEST(test_ei_unref_self_immediately) { _unref_(peck) *peck = peck_new(); @@ -93,6 +93,30 @@ MUNIT_TEST(test_ei_disconnect_self_immediately) return MUNIT_OK; } +MUNIT_TEST(test_ei_disconnect_self_immediately) +{ + _unref_(peck) *peck = peck_new(); + + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE); + peck_dispatch_until_stable(peck); + + /* Disconnect before server processed CONNECT */ + with_client(peck) { + ei_disconnect(ei); + } + + peck_dispatch_until_stable(peck); + + /* Expect the client to get a disconnect event */ + with_server(peck) { + _unref_(eis_event) *connect = + peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT); + _unref_(eis_event) *disconnect = + peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT); + } + + return MUNIT_OK; +} MUNIT_TEST(test_ei_disconnect_after_connect) { @@ -130,7 +154,7 @@ MUNIT_TEST(test_ei_disconnect_after_connect) return MUNIT_OK; } -MUNIT_TEST(test_ei_disconnect_self_after_connect) +MUNIT_TEST(test_ei_unref_self_after_connect) { _unref_(peck) *peck = peck_new(); @@ -154,6 +178,29 @@ MUNIT_TEST(test_ei_disconnect_self_after_connect) return MUNIT_OK; } +MUNIT_TEST(test_ei_disconnect_self_after_connect) +{ + _unref_(peck) *peck = peck_new(); + + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_NONE); + peck_dispatch_until_stable(peck); + + with_client(peck) { + ei_disconnect(ei); + } + + peck_dispatch_until_stable(peck); + + with_server(peck) { + _unref_(eis_event) *connect = + peck_eis_next_event(eis, EIS_EVENT_CLIENT_CONNECT); + _unref_(eis_event) *disconnect = + peck_eis_next_event(eis, EIS_EVENT_CLIENT_DISCONNECT); + } + + return MUNIT_OK; +} + MUNIT_TEST(test_ei_disconnect_after_seat) { _unref_(peck) *peck = peck_new(); @@ -203,9 +250,8 @@ MUNIT_TEST(test_ei_disconnect_self_after_seat) peck_ei_next_event(ei, EI_EVENT_CONNECT); _unref_(ei_event) *seat = peck_ei_next_event(ei, EI_EVENT_SEAT_ADDED); - peck_drop_ei(peck); /* Disconnect from client */ - ei_unref(ei); + ei_disconnect(ei); /* There is no way to disconnect from the server without * destroying the context, so we don't care about the actual @@ -274,8 +320,7 @@ MUNIT_TEST(test_ei_disconnect_self_after_bind_before_received) struct ei_seat *seat = ei_event_get_seat(event); ei_seat_bind_capabilities(seat, EI_DEVICE_CAP_POINTER, NULL); /* Disconnect before the server can process the bind event */ - peck_drop_ei(peck); - ei_unref(ei); + ei_disconnect(ei); } peck_dispatch_eis(peck); @@ -354,8 +399,7 @@ MUNIT_TEST(test_ei_disconnect_self_after_bind_after_received) peck_dispatch_eis(peck); with_client(peck) { - peck_drop_ei(peck); - ei_unref(ei); + ei_disconnect(ei); } peck_dispatch_eis(peck);