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