[PATCH weston 12/25] input: introduce weston_touch_device
Peter Hutterer
peter.hutterer at who-t.net
Mon Apr 9 01:55:51 UTC 2018
On Fri, Mar 23, 2018 at 02:00:52PM +0200, Pekka Paalanen wrote:
> From: Louis-Francis Ratté-Boulianne <lfrb at 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 <lfrb at collabora.com>
> Signed-off-by: Pekka Paalanen <pekka.paalanen at 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 at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/wayland-devel
>
More information about the wayland-devel
mailing list