libinput: use head names for output matching
authorPekka Paalanen <pekka.paalanen@collabora.co.uk>
Mon, 19 Mar 2018 12:55:41 +0000 (14:55 +0200)
committerPekka Paalanen <pekka.paalanen@collabora.co.uk>
Fri, 20 Apr 2018 12:27:54 +0000 (15:27 +0300)
Associating input devices with weston_outputs by the output name fails
when one output has several heads. We need to match against head names
instead of output names to be able to find all names.

This fixes touchscreen output association in shared-CRTC clone mode when
outputs or input devices appear or disappear.

Even though notify_output_create() is called only when new outputs
appear, the implementation is prepared to also remove output
associations. This will be handy in the future when this function will
handle also head detaching from an output that remains enabled.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
libweston/libinput-seat.c

index 953f620..3cece3a 100644 (file)
@@ -58,6 +58,27 @@ get_udev_seat(struct udev_input *input, struct libinput_device *device)
        return udev_seat_get_named(input, seat_name);
 }
 
+static struct weston_output *
+output_find_by_head_name(struct weston_compositor *compositor,
+                        const char *head_name)
+{
+       struct weston_output *output;
+       struct weston_head *head;
+
+       if (!head_name)
+               return NULL;
+
+       /* only enabled outputs */
+       wl_list_for_each(output, &compositor->output_list, link) {
+               wl_list_for_each(head, &output->head_list, output_link) {
+                       if (strcmp(head_name, head->name) == 0)
+                               return output;
+               }
+       }
+
+       return NULL;
+}
+
 static void
 device_added(struct udev_input *input, struct libinput_device *libinput_device)
 {
@@ -95,11 +116,10 @@ device_added(struct udev_input *input, struct libinput_device *libinput_device)
        output_name = libinput_device_get_output_name(libinput_device);
        if (output_name) {
                device->output_name = strdup(output_name);
-               wl_list_for_each(output, &c->output_list, link)
-                       if (output->name &&
-                           strcmp(output->name, device->output_name) == 0)
-                               evdev_device_set_output(device, output);
-       } else if (device->output == NULL && !wl_list_empty(&c->output_list)) {
+               output = output_find_by_head_name(c, output_name);
+               evdev_device_set_output(device, output);
+       } else if (!wl_list_empty(&c->output_list)) {
+               /* default assignment to an arbitrary output */
                output = container_of(c->output_list.next,
                                      struct weston_output, link);
                evdev_device_set_output(device, output);
@@ -363,15 +383,26 @@ notify_output_create(struct wl_listener *listener, void *data)
                                              output_create_listener);
        struct evdev_device *device;
        struct weston_output *output = data;
+       struct weston_output *found;
 
        wl_list_for_each(device, &seat->devices_list, link) {
-               if (device->output_name &&
-                   strcmp(output->name, device->output_name) == 0) {
-                       evdev_device_set_output(device, output);
+               /* If we find any input device without an associated output
+                * or an output name to associate with, just tie it with the
+                * output we got here - the default assingment.
+                */
+               if (!device->output_name) {
+                       if (!device->output)
+                               evdev_device_set_output(device, output);
+
+                       continue;
                }
 
-               if (device->output_name == NULL && device->output == NULL)
-                       evdev_device_set_output(device, output);
+               /* Update all devices' output associations, may they gain or
+                * lose it.
+                */
+               found = output_find_by_head_name(output->compositor,
+                                                device->output_name);
+               evdev_device_set_output(device, found);
        }
 }