Add support for seat unbinding

This required a bit of cleanup with the eis device handling.

Signed-off-by:	Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2021-07-21 10:22:09 +10:00
parent 3e66c87e81
commit 358a528478
8 changed files with 192 additions and 86 deletions

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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

View file

@ -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();

View file

@ -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);