diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2014-01-29 15:57:53 +1000 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2014-02-10 11:23:35 +1000 |
commit | 6764e7e19a0b44e997707e6621974b1cc9c3d737 (patch) | |
tree | b789f844cbb2fb1bb2e43714ca7146ca2e9eebce /src/path.c | |
parent | f6e8160ce116fb58cb4aaf8dc5f8c3f59ea74d6d (diff) |
path: modify backend to allow for more than one device
The previous path backend created a libinput context attached to a single
device. This is insufficient when we need to use cross-device functionality.
One example of this cross-device functionality include disabling a touchpad
while the trackstick is in use (Lenovo T440 and related models).
This patch merely adds the infrastructure to support multiple devices for a
path backend. Follow-up patches add the function calls to add and remove
devices. This is needed by Xorg input drivers that still make use of the
server's device hotplug mechanisms but want to otherwise use libinput.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Diffstat (limited to 'src/path.c')
-rw-r--r-- | src/path.c | 122 |
1 files changed, 95 insertions, 27 deletions
@@ -39,11 +39,24 @@ static void path_input_disable(struct libinput *libinput) { struct path_input *input = (struct path_input*)libinput; - struct evdev_device *device = input->device; - - if (device) { - evdev_device_remove(device); - input->device = NULL; + struct path_seat *seat, *tmp; + struct evdev_device *device, *next; + + list_for_each_safe(seat, tmp, &input->base.seat_list, base.link) { + libinput_seat_ref(&seat->base); + 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); } } @@ -72,6 +85,22 @@ path_seat_create(struct path_input *input, return seat; } +static struct path_seat* +path_seat_get_named(struct path_input *input, + const char *seat_name_physical, + const char *seat_name_logical) +{ + struct path_seat *seat; + + list_for_each(seat, &input->base.seat_list, base.link) { + if (strcmp(seat->base.physical_name, seat_name_physical) == 0 && + strcmp(seat->base.logical_name, seat_name_logical) == 0) + return seat; + } + + return NULL; +} + static int path_get_udev_properties(const char *path, char **sysname, @@ -113,48 +142,64 @@ out: return rc; } -static int -path_input_enable(struct libinput *libinput) +static struct libinput_device * +path_device_enable(struct path_input *input, const char *devnode) { - struct path_input *input = (struct path_input*)libinput; struct path_seat *seat; - struct evdev_device *device; - const char *devnode = input->path; + struct evdev_device *device = NULL; char *sysname; char *seat_name, *seat_logical_name; - if (input->device) - return 0; - if (path_get_udev_properties(devnode, &sysname, &seat_name, &seat_logical_name) == -1) { log_info("failed to obtain sysname for device '%s'.\n", devnode); - return -1; + return NULL; } - seat = path_seat_create(input, seat_name, seat_logical_name); - free(seat_name); - free(seat_logical_name); + seat = path_seat_get_named(input, seat_name, seat_logical_name); - if (!seat) { - log_info("failed to create seat for device '%s'.\n", devnode); - free(sysname); - return -1; + if (seat) { + libinput_seat_ref(&seat->base); + } else { + seat = path_seat_create(input, seat_name, seat_logical_name); + if (!seat) { + log_info("failed to create seat for device '%s'.\n", devnode); + goto out; + } } device = evdev_device_create(&seat->base, devnode, sysname); - free(sysname); libinput_seat_unref(&seat->base); if (device == EVDEV_UNHANDLED_DEVICE) { + device = NULL; log_info("not using input device '%s'.\n", devnode); - return -1; + goto out; } else if (device == NULL) { log_info("failed to create input device '%s'.\n", devnode); - return -1; + goto out; } - input->device = device; +out: + free(sysname); + free(seat_name); + free(seat_logical_name); + + return device ? &device->base : NULL; +} + +static int +path_input_enable(struct libinput *libinput) +{ + struct path_input *input = (struct path_input*)libinput; + struct path_device *dev; + + list_for_each(dev, &input->path_list, link) { + if (path_device_enable(input, dev->path) == NULL) { + path_input_disable(libinput); + return -1; + } + } return 0; } @@ -163,7 +208,13 @@ static void path_input_destroy(struct libinput *input) { struct path_input *path_input = (struct path_input*)input; - free(path_input->path); + struct path_device *dev, *tmp; + + list_for_each_safe(dev, tmp, &path_input->path_list, link) { + free(dev->path); + free(dev); + } + } static const struct libinput_interface_backend interface_backend = { @@ -178,6 +229,7 @@ libinput_create_from_path(const struct libinput_interface *interface, const char *path) { struct path_input *input; + struct path_device *dev; if (!interface || !path) return NULL; @@ -186,13 +238,29 @@ libinput_create_from_path(const struct libinput_interface *interface, if (!input) return NULL; + dev = zalloc(sizeof *dev); + if (!dev) { + free(input); + return NULL; + } + if (libinput_init(&input->base, interface, &interface_backend, user_data) != 0) { free(input); + free(dev); + return NULL; + } + + list_init(&input->path_list); + + dev->path = strdup(path); + if (!dev->path) { + free(input); + free(dev); return NULL; } - input->path = strdup(path); + list_insert(&input->path_list, &dev->link); if (path_input_enable(&input->base) < 0) { libinput_destroy(&input->base); |