[PATCH v2 libinput] Make it possible to have persistent libinput_seat instances

Peter Hutterer peter.hutterer at who-t.net
Sun Feb 9 17:40:55 PST 2014


From: Jonas Ådahl <jadahl at gmail.com>

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 <jadahl at gmail.com>
Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Changes to v1:
- rebased on top of my path add/remove devices patch, the changes to path
  and udev backends are now identical
- use litest_drain_events() instead of manual loop in tests
- destroy the uinput device when done with it, closes a leak in the test 

 src/libinput.c  |  1 +
 src/libinput.h  |  5 +++
 src/path.c      |  9 ------
 src/udev-seat.c |  9 ------
 test/path.c     | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 test/udev.c     | 75 ++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 177 insertions(+), 18 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 e87b2b7..2fd9638 100644
--- a/src/libinput.h
+++ b/src/libinput.h
@@ -1069,6 +1069,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 31a916a..1b929e8 100644
--- a/src/path.c
+++ b/src/path.c
@@ -49,14 +49,6 @@ path_disable_device(struct libinput *libinput,
 			continue;
 
 		evdev_device_remove(device);
-		if (list_empty(&seat->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->link);
-			list_init(&seat->link);
-		}
 		break;
 	}
 }
@@ -97,7 +89,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;
 }
diff --git a/src/udev-seat.c b/src/udev-seat.c
index 9b807be..e622de2 100644
--- a/src/udev-seat.c
+++ b/src/udev-seat.c
@@ -203,14 +203,6 @@ udev_input_remove_devices(struct udev_input *input)
 		list_for_each_safe(device, next,
 				   &seat->base.devices_list, base.link) {
 			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);
 	}
@@ -311,7 +303,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 59d3e5f..41ee5c6 100644
--- a/test/path.c
+++ b/test/path.c
@@ -778,6 +778,100 @@ START_TEST(path_add_device_suspend_resume_remove_device)
 }
 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_path_create_context(&simple_interface, userdata);
+	ck_assert(li != NULL);
+
+	device = libinput_path_add_device(li,
+					  libevdev_uinput_get_devnode(uinput));
+	ck_assert(device != 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);
+
+	litest_drain_events(li);
+
+	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);
+
+	libevdev_uinput_destroy(uinput);
+}
+END_TEST
+
 int main (int argc, char **argv) {
 
 	litest_add("path:create", path_create_NULL, LITEST_ANY, LITEST_ANY);
@@ -796,6 +890,8 @@ int main (int argc, char **argv) {
 	litest_add("path:device events", path_add_invalid_path, LITEST_ANY, LITEST_ANY);
 	litest_add("path:device events", path_remove_device, LITEST_ANY, LITEST_ANY);
 	litest_add("path:device events", path_double_remove_device, 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 ee25673..6af2cb0 100644
--- a/test/udev.c
+++ b/test/udev.c
@@ -327,6 +327,80 @@ 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_udev_create_for_seat(&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);
+
+	litest_drain_events(li);
+
+	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 +413,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.4.2



More information about the wayland-devel mailing list