With this patch, a user can keep a reference to a libinput_seat instance, which will cause the seat to never be unlinked from the libinput context nor destroyed.
Previously, a when the last device of a seat was removed, the seat was unlinked and if a new device was discovered with a previously empty seat a new seat instance would always be created, meaning two potential seat instances with identical physical and logical seat name pairs. Signed-off-by: Jonas Ådahl <jad...@gmail.com> --- src/libinput.c | 1 + src/libinput.h | 5 +++ src/path.c | 14 +++++++-- src/path.h | 9 +++--- src/udev-seat.c | 9 ------ test/path.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/udev.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 193 insertions(+), 16 deletions(-) diff --git a/src/libinput.c b/src/libinput.c index cfce2c5..cc84fb5 100644 --- a/src/libinput.c +++ b/src/libinput.c @@ -508,6 +508,7 @@ libinput_seat_init(struct libinput_seat *seat, seat->logical_name = strdup(logical_name); seat->destroy = destroy; list_init(&seat->devices_list); + list_insert(&libinput->seat_list, &seat->link); } LIBINPUT_EXPORT void diff --git a/src/libinput.h b/src/libinput.h index 9cd9d5b..4a481d2 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -1023,6 +1023,11 @@ libinput_device_get_output_name(struct libinput_device *device); * * Get the seat associated with this input device. * + * A seat can be uniquely identified by the physical and logical seat name. + * There will ever be only one seat instance with a given physical and logical + * seat name pair at any given time, but if no external reference is kept, it + * may be destroyed if no device belonging to it is left. + * * @param device A previously obtained device * @return The seat this input device belongs to */ diff --git a/src/path.c b/src/path.c index 2893ad4..4e2cf1f 100644 --- a/src/path.c +++ b/src/path.c @@ -68,7 +68,6 @@ path_seat_create(struct path_input *input, libinput_seat_init(&seat->base, &input->base, seat_name, seat_logical_name, path_seat_destroy); - list_insert(&input->base.seat_list, &seat->base.link); return seat; } @@ -142,13 +141,22 @@ path_input_enable(struct libinput *libinput) return -1; } - seat = path_seat_create(input, seat_name, seat_logical_name); + if (!input->seat) { + input->seat = path_seat_create(input, + seat_name, + seat_logical_name); + if (!input->seat) { + close_restricted(libinput, fd); + log_info("could not create seat '%s'.\n", seat_name); + return -1; + } + } + seat = input->seat; free(seat_name); free(seat_logical_name); device = evdev_device_create(&seat->base, devnode, sysname, fd); free(sysname); - libinput_seat_unref(&seat->base); if (device == EVDEV_UNHANDLED_DEVICE) { close_restricted(libinput, fd); diff --git a/src/path.h b/src/path.h index b840acf..12bbfb8 100644 --- a/src/path.h +++ b/src/path.h @@ -26,16 +26,17 @@ #include "config.h" #include "libinput-private.h" +struct path_seat { + struct libinput_seat base; +}; + struct path_input { struct libinput base; char *path; + struct path_seat *seat; struct evdev_device *device; }; -struct path_seat { - struct libinput_seat base; -}; - int path_input_process_event(struct libinput_event); #endif diff --git a/src/udev-seat.c b/src/udev-seat.c index 5936511..161b294 100644 --- a/src/udev-seat.c +++ b/src/udev-seat.c @@ -221,14 +221,6 @@ udev_input_remove_devices(struct udev_input *input) &seat->base.devices_list, base.link) { close_restricted(&input->base, device->fd); evdev_device_remove(device); - if (list_empty(&seat->base.devices_list)) { - /* if the seat may be referenced by the - client, so make sure it's dropped from - the seat list now, to be freed whenever - * the device is removed */ - list_remove(&seat->base.link); - list_init(&seat->base.link); - } } libinput_seat_unref(&seat->base); } @@ -329,7 +321,6 @@ udev_seat_create(struct udev_input *input, libinput_seat_init(&seat->base, &input->base, device_seat, seat_name, udev_seat_destroy); - list_insert(&input->base.seat_list, &seat->base.link); return seat; } diff --git a/test/path.c b/test/path.c index 24f647f..8374582 100644 --- a/test/path.c +++ b/test/path.c @@ -334,6 +334,98 @@ START_TEST(path_double_resume) } END_TEST +START_TEST(path_seat_recycle) +{ + struct libinput *li; + struct libevdev *evdev; + struct libevdev_uinput *uinput; + int rc; + void *userdata = &rc; + struct libinput_event *ev; + struct libinput_device *device; + struct libinput_seat *saved_seat = NULL; + struct libinput_seat *seat; + int data = 0; + int found = 0; + void *user_data; + + evdev = libevdev_new(); + ck_assert(evdev != NULL); + + libevdev_set_name(evdev, "test device"); + libevdev_enable_event_code(evdev, EV_KEY, BTN_LEFT, NULL); + libevdev_enable_event_code(evdev, EV_KEY, BTN_RIGHT, NULL); + libevdev_enable_event_code(evdev, EV_REL, REL_X, NULL); + libevdev_enable_event_code(evdev, EV_REL, REL_Y, NULL); + + rc = libevdev_uinput_create_from_device(evdev, + LIBEVDEV_UINPUT_OPEN_MANAGED, + &uinput); + ck_assert_int_eq(rc, 0); + libevdev_free(evdev); + + li = libinput_create_from_path(&simple_interface, userdata, + libevdev_uinput_get_devnode(uinput)); + ck_assert(li != NULL); + + libinput_dispatch(li); + while ((ev = libinput_get_event(li))) { + switch (libinput_event_get_type(ev)) { + case LIBINPUT_EVENT_DEVICE_ADDED: + if (saved_seat) + break; + + device = libinput_event_get_device(ev); + ck_assert(device != NULL); + saved_seat = libinput_device_get_seat(device); + libinput_seat_set_user_data(saved_seat, &data); + libinput_seat_ref(saved_seat); + break; + default: + break; + } + + libinput_event_destroy(ev); + } + + ck_assert(saved_seat != NULL); + + libinput_suspend(li); + + libinput_dispatch(li); + while ((ev = libinput_get_event(li))) + libinput_event_destroy(ev); + + libinput_resume(li); + + libinput_dispatch(li); + while ((ev = libinput_get_event(li))) { + switch (libinput_event_get_type(ev)) { + case LIBINPUT_EVENT_DEVICE_ADDED: + device = libinput_event_get_device(ev); + ck_assert(device != NULL); + + seat = libinput_device_get_seat(device); + user_data = libinput_seat_get_user_data(seat); + if (user_data == &data) { + found = 1; + ck_assert(seat == saved_seat); + } + break; + default: + break; + } + + libinput_event_destroy(ev); + } + + ck_assert(found == 1); + + libinput_destroy(li); +} +END_TEST + + int main (int argc, char **argv) { litest_add("path:create", path_create_NULL, LITEST_ANY, LITEST_ANY); @@ -345,6 +437,8 @@ int main (int argc, char **argv) { litest_add("path:seat events", path_added_seat, LITEST_ANY, LITEST_ANY); litest_add("path:device events", path_added_device, LITEST_ANY, LITEST_ANY); litest_add("path:device events", path_device_sysname, LITEST_ANY, LITEST_ANY); + litest_add("path:seat", path_seat_recycle, + LITEST_DISABLE_DEVICE, LITEST_DISABLE_DEVICE); return litest_run(argc, argv); } diff --git a/test/udev.c b/test/udev.c index 235d10e..29f87db 100644 --- a/test/udev.c +++ b/test/udev.c @@ -327,6 +327,82 @@ START_TEST(udev_device_sysname) } END_TEST +START_TEST(udev_seat_recycle) +{ + struct udev *udev; + struct libinput *li; + struct libinput_event *ev; + struct libinput_device *device; + struct libinput_seat *saved_seat = NULL; + struct libinput_seat *seat; + int data = 0; + int found = 0; + void *user_data; + + udev = udev_new(); + ck_assert(udev != NULL); + + li = libinput_create_from_udev(&simple_interface, NULL, udev, "seat0"); + ck_assert(li != NULL); + + libinput_dispatch(li); + while ((ev = libinput_get_event(li))) { + switch (libinput_event_get_type(ev)) { + case LIBINPUT_EVENT_DEVICE_ADDED: + if (saved_seat) + break; + + device = libinput_event_get_device(ev); + ck_assert(device != NULL); + saved_seat = libinput_device_get_seat(device); + libinput_seat_set_user_data(saved_seat, &data); + libinput_seat_ref(saved_seat); + break; + default: + break; + } + + libinput_event_destroy(ev); + } + + ck_assert(saved_seat != NULL); + + libinput_suspend(li); + + libinput_dispatch(li); + while ((ev = libinput_get_event(li))) + libinput_event_destroy(ev); + + libinput_resume(li); + + libinput_dispatch(li); + while ((ev = libinput_get_event(li))) { + switch (libinput_event_get_type(ev)) { + case LIBINPUT_EVENT_DEVICE_ADDED: + device = libinput_event_get_device(ev); + ck_assert(device != NULL); + + seat = libinput_device_get_seat(device); + user_data = libinput_seat_get_user_data(seat); + if (user_data == &data) { + found = 1; + ck_assert(seat == saved_seat); + } + break; + default: + break; + } + + libinput_event_destroy(ev); + } + + ck_assert(found == 1); + + libinput_destroy(li); + udev_unref(udev); +} +END_TEST + int main (int argc, char **argv) { litest_add_no_device("udev:create", udev_create_NULL); @@ -339,6 +415,7 @@ int main (int argc, char **argv) { litest_add("udev:suspend", udev_double_resume, LITEST_ANY, LITEST_ANY); litest_add("udev:suspend", udev_suspend_resume, LITEST_ANY, LITEST_ANY); litest_add("udev:device events", udev_device_sysname, LITEST_ANY, LITEST_ANY); + litest_add("udev:seat", udev_seat_recycle, LITEST_ANY, LITEST_ANY); return litest_run(argc, argv); } -- 1.8.3.2 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel