[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