On Fri, Mar 23, 2018 at 02:00:52PM +0200, Pekka Paalanen wrote:
> From: Louis-Francis Ratté-Boulianne <l...@collabora.com>
> 
> Introduce weston_touch_device for libweston core to track individual
> touchscreen input devices. A weston_seat/weston_touch may be an
> aggregation of several physical touchscreen input devices. Separating
> the physical devices will be required for implementing touchscreen
> calibration. One can only calibrate one device at a time, and we want to
> make sure to handle the right one.
> 
> Both backends that support touch devices are updated to create
> weston_touch_devices. Wayland-backend provides touch devices that cannot
> be calibrated, because we have no access to raw touch coordinates from
> the device - calibration is the responsibility of the parent display
> server. Libinput backend provides touch devices that can be calibrated,
> hence implementing the set and get calibration hooks.
> 
> Backends need to maintain an output pointer in any case, so we have a
> get_output() hook instead of having to maintain an identical field in
> weston_touch_device. The same justification applies to
> get_calibration_head_name.
> 
> Also update the test plugin to manage weston_touch_device objects.
> 
> Co-developed by Louis-Francis and Pekka.

just a little nit: you're going to make the world an every so slightly
angrier place by choosing "calb" instead of "calib" or "cal" as shortcut for
"calibration" :)

I predict that almost everyone working on that code will mistype that the
first few times around.

Cheers,
   Peter

> 
> Signed-off-by: Louis-Francis Ratté-Boulianne <l...@collabora.com>
> Signed-off-by: Pekka Paalanen <pekka.paala...@collabora.co.uk>
> ---
>  libweston/compositor-wayland.c |  21 ++++++++
>  libweston/compositor.h         |  56 ++++++++++++++++++++
>  libweston/input.c              |  65 +++++++++++++++++++++++
>  libweston/libinput-device.c    | 116 
> ++++++++++++++++++++++++++++++++++++++++-
>  libweston/libinput-device.h    |   3 ++
>  tests/weston-test.c            |  38 ++++++++++++++
>  6 files changed, 298 insertions(+), 1 deletion(-)
> 
> diff --git a/libweston/compositor-wayland.c b/libweston/compositor-wayland.c
> index f186681c..9d5b3551 100644
> --- a/libweston/compositor-wayland.c
> +++ b/libweston/compositor-wayland.c
> @@ -198,6 +198,8 @@ struct wayland_input {
>               } cursor;
>       } parent;
>  
> +     struct weston_touch_device *touch_device;
> +
>       enum weston_key_state_update keyboard_state_update;
>       uint32_t key_serial;
>       uint32_t enter_serial;
> @@ -2246,6 +2248,22 @@ static const struct wl_touch_listener touch_listener = 
> {
>  };
>  
>  
> +static struct weston_touch_device *
> +create_touch_device(struct wayland_input *input)
> +{
> +     struct weston_touch_device *touch_device;
> +     char str[128];
> +
> +     /* manufacture a unique'ish name */
> +     snprintf(str, sizeof str, "wayland-touch[%u]",
> +              wl_proxy_get_id((struct wl_proxy *)input->parent.seat));
> +
> +     touch_device = weston_touch_create_touch_device(input->base.touch_state,
> +                                                     str, NULL, NULL);
> +
> +     return touch_device;
> +}
> +
>  static void
>  input_handle_capabilities(void *data, struct wl_seat *seat,
>                         enum wl_seat_capability caps)
> @@ -2287,7 +2305,10 @@ input_handle_capabilities(void *data, struct wl_seat 
> *seat,
>               wl_touch_add_listener(input->parent.touch,
>                                     &touch_listener, input);
>               weston_seat_init_touch(&input->base);
> +             input->touch_device = create_touch_device(input);
>       } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->parent.touch) {
> +             weston_touch_device_destroy(input->touch_device);
> +             input->touch_device = NULL;
>               if (input->seat_version >= WL_TOUCH_RELEASE_SINCE_VERSION)
>                       wl_touch_release(input->parent.touch);
>               else
> diff --git a/libweston/compositor.h b/libweston/compositor.h
> index 675ee68f..b08031ac 100644
> --- a/libweston/compositor.h
> +++ b/libweston/compositor.h
> @@ -453,10 +453,54 @@ struct weston_pointer {
>       struct wl_list timestamps_list;
>  };
>  
> +/** libinput style calibration matrix
> + *
> + * See https://wayland.freedesktop.org/libinput/doc/latest/absolute_axes.html
> + * and libinput_device_config_calibration_set_matrix().
> + */
> +struct weston_touch_device_matrix {
> +     float m[6];
> +};
> +
> +struct weston_touch_device;
> +
> +/** Operations for a calibratable touchscreen */
> +struct weston_touch_device_ops {
> +     /** Get the associated output if existing. */
> +     struct weston_output *(*get_output)(struct weston_touch_device *device);
> +
> +     /** Get the name of the associated head if existing. */
> +     const char *
> +     (*get_calibration_head_name)(struct weston_touch_device *device);
> +
> +     /** Retrieve the current calibration matrix. */
> +     void (*get_calibration)(struct weston_touch_device *device,
> +                             struct weston_touch_device_matrix *matrix);
> +
> +     /** Set a new calibration matrix. */
> +     void (*set_calibration)(struct weston_touch_device *device,
> +                             const struct weston_touch_device_matrix 
> *matrix);
> +};
> +
> +/** Represents a physical touchscreen input device */
> +struct weston_touch_device {
> +     char *devpath;                  /**< unique name */
>  
> +     struct weston_touch *aggregate; /**< weston_touch this is part of */
> +     struct wl_list link;            /**< in weston_touch::device_list */
> +     struct wl_signal destroy_signal;        /**< destroy notifier */
> +
> +     void *backend_data;             /**< backend-specific private */
> +
> +     const struct weston_touch_device_ops *ops;
> +};
> +
> +/** Represents a set of touchscreen devices aggregated under a seat */
>  struct weston_touch {
>       struct weston_seat *seat;
>  
> +     struct wl_list device_list;     /* struct weston_touch_device::link */
> +
>       struct wl_list resource_list;
>       struct wl_list focus_resource_list;
>       struct weston_view *focus;
> @@ -590,6 +634,18 @@ weston_touch_send_motion(struct weston_touch *touch,
>  void
>  weston_touch_send_frame(struct weston_touch *touch);
>  
> +struct weston_touch_device *
> +weston_touch_create_touch_device(struct weston_touch *touch,
> +                              const char *devpath,
> +                              void *backend_data,
> +                              const struct weston_touch_device_ops *ops);
> +
> +void
> +weston_touch_device_destroy(struct weston_touch_device *device);
> +
> +bool
> +weston_touch_device_can_calibrate(struct weston_touch_device *device);
> +
>  void
>  wl_data_device_set_keyboard_focus(struct weston_seat *seat);
>  
> diff --git a/libweston/input.c b/libweston/input.c
> index 3e91c266..feea9e72 100644
> --- a/libweston/input.c
> +++ b/libweston/input.c
> @@ -123,6 +123,68 @@ remove_input_resource_from_timestamps(struct wl_resource 
> *input_resource,
>       }
>  }
>  
> +/** Register a touchscreen input device
> + *
> + * \param touch The parent weston_touch that identifies the seat.
> + * \param devpath Unique device name.
> + * \param backend_data Backend private data if necessary.
> + * \param ops Calibration operations, or NULL for not able to run 
> calibration.
> + * \return New touch device, or NULL on failure.
> + */
> +WL_EXPORT struct weston_touch_device *
> +weston_touch_create_touch_device(struct weston_touch *touch,
> +                              const char *devpath,
> +                              void *backend_data,
> +                              const struct weston_touch_device_ops *ops)
> +{
> +     struct weston_touch_device *device;
> +
> +     assert(devpath);
> +     if (ops) {
> +             assert(ops->get_output);
> +             assert(ops->get_calibration_head_name);
> +             assert(ops->get_calibration);
> +             assert(ops->set_calibration);
> +     }
> +
> +     device = zalloc(sizeof *device);
> +     if (!device)
> +             return NULL;
> +
> +     wl_signal_init(&device->destroy_signal);
> +
> +     device->devpath = strdup(devpath);
> +     if (!device->devpath) {
> +             free(device);
> +             return NULL;
> +     }
> +
> +     device->backend_data = backend_data;
> +     device->ops = ops;
> +
> +     device->aggregate = touch;
> +     wl_list_insert(touch->device_list.prev, &device->link);
> +
> +     return device;
> +}
> +
> +/** Destroy the touch device. */
> +WL_EXPORT void
> +weston_touch_device_destroy(struct weston_touch_device *device)
> +{
> +     wl_list_remove(&device->link);
> +     wl_signal_emit(&device->destroy_signal, device);
> +     free(device->devpath);
> +     free(device);
> +}
> +
> +/** Is it possible to run calibration on this touch device? */
> +WL_EXPORT bool
> +weston_touch_device_can_calibrate(struct weston_touch_device *device)
> +{
> +     return !!device->ops;
> +}
> +
>  static struct weston_pointer_client *
>  weston_pointer_client_create(struct wl_client *client)
>  {
> @@ -1277,6 +1339,7 @@ weston_touch_create(void)
>       if (touch == NULL)
>               return NULL;
>  
> +     wl_list_init(&touch->device_list);
>       wl_list_init(&touch->resource_list);
>       wl_list_init(&touch->focus_resource_list);
>       wl_list_init(&touch->focus_view_listener.link);
> @@ -1297,6 +1360,8 @@ weston_touch_destroy(struct weston_touch *touch)
>  {
>       struct wl_resource *resource;
>  
> +     assert(wl_list_empty(&touch->device_list));
> +
>       wl_resource_for_each(resource, &touch->resource_list) {
>               wl_resource_set_user_data(resource, NULL);
>       }
> diff --git a/libweston/libinput-device.c b/libweston/libinput-device.c
> index e1738613..cb0bafe8 100644
> --- a/libweston/libinput-device.c
> +++ b/libweston/libinput-device.c
> @@ -296,6 +296,111 @@ handle_pointer_axis(struct libinput_device 
> *libinput_device,
>       return true;
>  }
>  
> +static struct weston_output *
> +touch_get_output(struct weston_touch_device *device)
> +{
> +     struct evdev_device *evdev_device = device->backend_data;
> +
> +     return evdev_device->output;
> +}
> +
> +static const char *
> +touch_get_calibration_head_name(struct weston_touch_device *device)
> +{
> +     struct evdev_device *evdev_device = device->backend_data;
> +     struct weston_output *output = evdev_device->output;
> +     struct weston_head *head;
> +
> +     if (!output)
> +             return NULL;
> +
> +     assert(output->enabled);
> +     if (evdev_device->output_name)
> +             return evdev_device->output_name;
> +
> +     /* No specific head was configured, so the association was made by
> +      * the default rule. Just grab whatever head's name.
> +      */
> +     wl_list_for_each(head, &output->head_list, output_link)
> +             return head->name;
> +
> +     assert(0);
> +     return NULL;
> +}
> +
> +static void
> +touch_get_calibration(struct weston_touch_device *device,
> +                   struct weston_touch_device_matrix *calb)
> +{
> +     struct evdev_device *evdev_device = device->backend_data;
> +
> +     libinput_device_config_calibration_get_matrix(evdev_device->device,
> +                                                   calb->m);
> +}
> +
> +static void
> +do_set_calibration(struct evdev_device *evdev_device,
> +                const struct weston_touch_device_matrix *calb)
> +{
> +     enum libinput_config_status status;
> +
> +     status = 
> libinput_device_config_calibration_set_matrix(evdev_device->device,
> +                                                            calb->m);
> +     if (status != LIBINPUT_CONFIG_STATUS_SUCCESS)
> +             weston_log("Failed to apply calibration.\n");
> +}
> +
> +static void
> +touch_set_calibration(struct weston_touch_device *device,
> +                   const struct weston_touch_device_matrix *calb)
> +{
> +     struct evdev_device *evdev_device = device->backend_data;
> +
> +     /* Stop output hotplug from reloading the WL_CALIBRATION values.
> +      * libinput will maintain the latest calibration for us.
> +      */
> +     evdev_device->override_wl_calibration = true;
> +
> +     do_set_calibration(evdev_device, calb);
> +}
> +
> +static const struct weston_touch_device_ops touch_calibration_ops = {
> +     .get_output = touch_get_output,
> +     .get_calibration_head_name = touch_get_calibration_head_name,
> +     .get_calibration = touch_get_calibration,
> +     .set_calibration = touch_set_calibration
> +};
> +
> +static struct weston_touch_device *
> +create_touch_device(struct evdev_device *device)
> +{
> +     const struct weston_touch_device_ops *ops = NULL;
> +     struct weston_touch_device *touch_device;
> +     struct udev_device *udev_device;
> +
> +     if (libinput_device_config_calibration_has_matrix(device->device))
> +             ops = &touch_calibration_ops;
> +
> +     udev_device = libinput_device_get_udev_device(device->device);
> +     if (!udev_device)
> +             return NULL;
> +
> +     touch_device = 
> weston_touch_create_touch_device(device->seat->touch_state,
> +                                     udev_device_get_devpath(udev_device),
> +                                     device, ops);
> +
> +     udev_device_unref(udev_device);
> +
> +     if (!touch_device)
> +             return NULL;
> +
> +     weston_log("Touchscreen - %s - %s\n",
> +                libinput_device_get_name(device->device),
> +                touch_device->devpath);
> +
> +     return touch_device;
> +}
> +
>  static void
>  handle_touch_with_coords(struct libinput_device *libinput_device,
>                        struct libinput_event_touch *touch_event,
> @@ -466,6 +571,12 @@ evdev_device_set_calibration(struct evdev_device *device)
>                                                         calibration) != 0)
>               return;
>  
> +     /* touch_set_calibration() has updated the values, do not load old
> +      * values from WL_CALIBRATION.
> +      */
> +     if (device->override_wl_calibration)
> +             return;
> +
>       if (!device->output) {
>               weston_log("input device %s has no enabled output associated "
>                          "(%s named), skipping calibration for now.\n",
> @@ -598,6 +709,7 @@ evdev_device_create(struct libinput_device 
> *libinput_device,
>                                          LIBINPUT_DEVICE_CAP_TOUCH)) {
>               weston_seat_init_touch(seat);
>               device->seat_caps |= EVDEV_SEAT_TOUCH;
> +             device->touch_device = create_touch_device(device);
>       }
>  
>       libinput_device_set_user_data(libinput_device, device);
> @@ -613,8 +725,10 @@ evdev_device_destroy(struct evdev_device *device)
>               weston_seat_release_pointer(device->seat);
>       if (device->seat_caps & EVDEV_SEAT_KEYBOARD)
>               weston_seat_release_keyboard(device->seat);
> -     if (device->seat_caps & EVDEV_SEAT_TOUCH)
> +     if (device->seat_caps & EVDEV_SEAT_TOUCH) {
> +             weston_touch_device_destroy(device->touch_device);
>               weston_seat_release_touch(device->seat);
> +     }
>  
>       if (device->output)
>               wl_list_remove(&device->output_destroy_listener.link);
> diff --git a/libweston/libinput-device.h b/libweston/libinput-device.h
> index 8e9f5608..6147a513 100644
> --- a/libweston/libinput-device.h
> +++ b/libweston/libinput-device.h
> @@ -31,6 +31,7 @@
>  #include <linux/input.h>
>  #include <wayland-util.h>
>  #include <libinput.h>
> +#include <stdbool.h>
>  
>  #include "compositor.h"
>  
> @@ -44,11 +45,13 @@ struct evdev_device {
>       struct weston_seat *seat;
>       enum evdev_device_seat_capability seat_caps;
>       struct libinput_device *device;
> +     struct weston_touch_device *touch_device;
>       struct wl_list link;
>       struct weston_output *output;
>       struct wl_listener output_destroy_listener;
>       char *output_name;
>       int fd;
> +     bool override_wl_calibration;
>  };
>  
>  void
> diff --git a/tests/weston-test.c b/tests/weston-test.c
> index ae08b02f..9662b67c 100644
> --- a/tests/weston-test.c
> +++ b/tests/weston-test.c
> @@ -45,11 +45,15 @@
>  #include "shared/helpers.h"
>  #include "shared/timespec-util.h"
>  
> +#define MAX_TOUCH_DEVICES 32
> +
>  struct weston_test {
>       struct weston_compositor *compositor;
>       struct weston_layer layer;
>       struct weston_process process;
>       struct weston_seat seat;
> +     struct weston_touch_device *touch_device[MAX_TOUCH_DEVICES];
> +     int nr_touch_devices;
>       bool is_seat_initialized;
>  };
>  
> @@ -77,6 +81,34 @@ test_client_sigchld(struct weston_process *process, int 
> status)
>       wl_display_terminate(test->compositor->wl_display);
>  }
>  
> +static void
> +touch_device_add(struct weston_test *test)
> +{
> +     char buf[128];
> +     int i = test->nr_touch_devices;
> +
> +     assert(i < MAX_TOUCH_DEVICES);
> +     assert(!test->touch_device[i]);
> +
> +     snprintf(buf, sizeof buf, "test-touch-device-%d", i);
> +
> +     test->touch_device[i] = weston_touch_create_touch_device(
> +                             test->seat.touch_state, buf, NULL, NULL);
> +     test->nr_touch_devices++;
> +}
> +
> +static void
> +touch_device_remove(struct weston_test *test)
> +{
> +     int i = test->nr_touch_devices - 1;
> +
> +     assert(i >= 0);
> +     assert(test->touch_device[i]);
> +     weston_touch_device_destroy(test->touch_device[i]);
> +     test->touch_device[i] = NULL;
> +     --test->nr_touch_devices;
> +}
> +
>  static int
>  test_seat_init(struct weston_test *test)
>  {
> @@ -92,6 +124,7 @@ test_seat_init(struct weston_test *test)
>       if (weston_seat_init_keyboard(&test->seat, NULL) < 0)
>               return -1;
>       weston_seat_init_touch(&test->seat);
> +     touch_device_add(test);
>  
>       return 0;
>  }
> @@ -99,6 +132,9 @@ test_seat_init(struct weston_test *test)
>  static void
>  test_seat_release(struct weston_test *test)
>  {
> +     while (test->nr_touch_devices > 0)
> +             touch_device_remove(test);
> +
>       assert(test->is_seat_initialized &&
>              "Trying to release already released test seat");
>       test->is_seat_initialized = false;
> @@ -281,6 +317,7 @@ device_release(struct wl_client *client,
>       } else if (strcmp(device, "keyboard") == 0) {
>               weston_seat_release_keyboard(seat);
>       } else if (strcmp(device, "touch") == 0) {
> +             touch_device_remove(test);
>               weston_seat_release_touch(seat);
>       } else if (strcmp(device, "seat") == 0) {
>               test_seat_release(test);
> @@ -302,6 +339,7 @@ device_add(struct wl_client *client,
>               weston_seat_init_keyboard(seat, NULL);
>       } else if (strcmp(device, "touch") == 0) {
>               weston_seat_init_touch(seat);
> +             touch_device_add(test);
>       } else if (strcmp(device, "seat") == 0) {
>               test_seat_init(test);
>       } else {
> -- 
> 2.16.1
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/wayland-devel
> 
_______________________________________________
wayland-devel mailing list
wayland-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to