evdev_set_device_group(struct evdev_device *device,
struct udev_device *udev_device)
{
+ struct libinput *libinput = device->base.seat->libinput;
struct libinput_device_group *group = NULL;
const char *udev_group;
udev_group = udev_device_get_property_value(udev_device,
"LIBINPUT_DEVICE_GROUP");
- if (udev_group) {
- struct libinput_device *d;
-
- list_for_each(d, &device->base.seat->devices_list, link) {
- const char *identifier = d->group->identifier;
-
- if (identifier &&
- strcmp(identifier, udev_group) == 0) {
- group = d->group;
- break;
- }
- }
- }
+ if (udev_group)
+ group = libinput_device_group_find_group(libinput, udev_group);
if (!group) {
- group = libinput_device_group_create(udev_group);
+ group = libinput_device_group_create(libinput, udev_group);
if (!group)
return 1;
libinput_device_set_device_group(&device->base, group);
enum libinput_log_priority log_priority;
void *user_data;
int refcount;
+
+ struct list device_group_list;
};
typedef void (*libinput_seat_destroy_func) (struct libinput_seat *seat);
int refcount;
void *user_data;
char *identifier; /* unique identifier or NULL for singletons */
+
+ struct list link;
};
struct libinput_device {
struct libinput_seat *seat);
struct libinput_device_group *
-libinput_device_group_create(const char *identifier);
+libinput_device_group_create(struct libinput *libinput,
+ const char *identifier);
+
+struct libinput_device_group *
+libinput_device_group_find_group(struct libinput *libinput,
+ const char *identifier);
void
libinput_device_set_device_group(struct libinput_device *device,
libinput->log_handler = log_handler;
}
+static void
+libinput_device_group_destroy(struct libinput_device_group *group);
+
static void
libinput_post_event(struct libinput *libinput,
struct libinput_event *event);
libinput->refcount = 1;
list_init(&libinput->source_destroy_list);
list_init(&libinput->seat_list);
+ list_init(&libinput->device_group_list);
if (libinput_timer_subsys_init(libinput) != 0) {
free(libinput->events);
struct libinput_event *event;
struct libinput_device *device, *next_device;
struct libinput_seat *seat, *next_seat;
+ struct libinput_device_group *group, *next_group;
if (libinput == NULL)
return NULL;
libinput_seat_destroy(seat);
}
+ list_for_each_safe(group,
+ next_group,
+ &libinput->device_group_list,
+ link) {
+ libinput_device_group_destroy(group);
+ }
+
libinput_timer_subsys_destroy(libinput);
libinput_drop_destroyed_sources(libinput);
close(libinput->epoll_fd);
}
struct libinput_device_group *
-libinput_device_group_create(const char *identifier)
+libinput_device_group_create(struct libinput *libinput,
+ const char *identifier)
{
struct libinput_device_group *group;
group->identifier = strdup(identifier);
if (!group->identifier) {
free(group);
- group = NULL;
+ return NULL;
}
}
+ list_init(&group->link);
+ list_insert(&libinput->device_group_list, &group->link);
+
return group;
}
+struct libinput_device_group *
+libinput_device_group_find_group(struct libinput *libinput,
+ const char *identifier)
+{
+ struct libinput_device_group *g = NULL;
+
+ list_for_each(g, &libinput->device_group_list, link) {
+ if (identifier && g->identifier &&
+ streq(g->identifier, identifier)) {
+ return g;
+ }
+ }
+
+ return g;
+}
+
void
libinput_device_set_device_group(struct libinput_device *device,
struct libinput_device_group *group)
static void
libinput_device_group_destroy(struct libinput_device_group *group)
{
+ list_remove(&group->link);
free(group->identifier);
free(group);
}
}
END_TEST
+static int open_restricted(const char *path, int flags, void *data)
+{
+ int fd;
+ fd = open(path, flags);
+ return fd < 0 ? -errno : fd;
+}
+static void close_restricted(int fd, void *data)
+{
+ close(fd);
+}
+
+const struct libinput_interface simple_interface = {
+ .open_restricted = open_restricted,
+ .close_restricted = close_restricted,
+};
+
START_TEST(device_group_get)
{
struct litest_device *dev = litest_current_device();
}
END_TEST
+START_TEST(device_group_leak)
+{
+ struct libinput *li;
+ struct libinput_device *device;
+ struct libevdev_uinput *uinput;
+ struct libinput_device_group *group;
+
+ uinput = litest_create_uinput_device("test device", NULL,
+ EV_KEY, BTN_LEFT,
+ EV_KEY, BTN_RIGHT,
+ EV_REL, REL_X,
+ EV_REL, REL_Y,
+ -1);
+
+ li = libinput_path_create_context(&simple_interface, NULL);
+ device = libinput_path_add_device(li,
+ libevdev_uinput_get_devnode(uinput));
+
+ group = libinput_device_get_device_group(device);
+ libinput_device_group_ref(group);
+
+ libinput_path_remove_device(device);
+
+ libevdev_uinput_destroy(uinput);
+ libinput_unref(li);
+
+ /* the device group leaks, check valgrind */
+}
+END_TEST
+
START_TEST(abs_device_no_absx)
{
struct libevdev_uinput *uinput;
litest_add("device:group", device_group_get, LITEST_ANY, LITEST_ANY);
litest_add_no_device("device:group", device_group_ref);
+ litest_add_no_device("device:group", device_group_leak);
litest_add_no_device("device:invalid devices", abs_device_no_absx);
litest_add_no_device("device:invalid devices", abs_device_no_absy);