[PATCH weston v3 4/6] libweston: Implement keyboard timestamps for input_timestamps_unstable_v1

Alexandros Frantzis alexandros.frantzis at collabora.com
Tue Feb 20 12:05:50 UTC 2018


Implement the zwp_input_timestamps_manager_v1.get_keyboard_timestamps
request to subscribe to timestamp events for wl_keyboard resources.
Ensure that the request handling code can gracefully handle inert
keyboard resources.

This commit introduces a few internal helper functions which will also
be useful in the implementation of the remaining
zwp_input_timestamps_manager_v1 requests.

Signed-off-by: Alexandros Frantzis <alexandros.frantzis at collabora.com>
---
Changes in v3:
 - In keyboard_timestamps_stop_after_client_releases_wl_keyboard test
   check for changes to keyboard->input_timestamp instead of
   keyboard->key_time_timespec.

Changes in v2:
 - Merge helper functions from v1 3/6 commit in this one to avoid
   warnings in 3/6 commit.
 - Remove the head of timestamps_list in weston_keyboard_destroy.
 - Gracefully handle inert keyboard resources in destroy_keyboard_resource
   and input_timestamps_manager_get_keyboard_timestamps.

 libweston/compositor.h |  2 ++
 libweston/input.c      | 95 ++++++++++++++++++++++++++++++++++++++++++++++++--
 tests/keyboard-test.c  | 51 +++++++++++++++++++++++++++
 3 files changed, 145 insertions(+), 3 deletions(-)

diff --git a/libweston/compositor.h b/libweston/compositor.h
index ca1acc60..1566677f 100644
--- a/libweston/compositor.h
+++ b/libweston/compositor.h
@@ -605,6 +605,8 @@ struct weston_keyboard {
 		enum weston_led leds;
 	} xkb_state;
 	struct xkb_keymap *pending_keymap;
+
+	struct wl_list timestamps_list;
 };
 
 struct weston_seat {
diff --git a/libweston/input.c b/libweston/input.c
index 2e8bd088..8028ec20 100644
--- a/libweston/input.c
+++ b/libweston/input.c
@@ -87,6 +87,42 @@ region_init_infinite(pixman_region32_t *region)
 				  UINT32_MAX, UINT32_MAX);
 }
 
+static void
+send_timestamp(struct wl_resource *resource,
+	       const struct timespec *time)
+{
+	uint32_t tv_sec_hi, tv_sec_lo, tv_nsec;
+
+	timespec_to_proto(time, &tv_sec_hi, &tv_sec_lo, &tv_nsec);
+	zwp_input_timestamps_v1_send_timestamp(resource, tv_sec_hi, tv_sec_lo,
+					       tv_nsec);
+}
+
+static void
+send_timestamps_for_input_resource(struct wl_resource *input_resource,
+				   struct wl_list *list,
+				   const struct timespec *time)
+{
+	struct wl_resource *resource;
+
+	wl_resource_for_each(resource, list) {
+		if (wl_resource_get_user_data(resource) == input_resource)
+			send_timestamp(resource, time);
+	}
+}
+
+static void
+remove_input_resource_from_timestamps(struct wl_resource *input_resource,
+				      struct wl_list *list)
+{
+	struct wl_resource *resource;
+
+	wl_resource_for_each(resource, list) {
+		if (wl_resource_get_user_data(resource) == input_resource)
+			wl_resource_set_user_data(resource, NULL);
+	}
+}
+
 static struct weston_pointer_client *
 weston_pointer_client_create(struct wl_client *client)
 {
@@ -884,8 +920,12 @@ weston_keyboard_send_key(struct weston_keyboard *keyboard,
 	resource_list = &keyboard->focus_resource_list;
 	serial = wl_display_next_serial(display);
 	msecs = timespec_to_msec(time);
-	wl_resource_for_each(resource, resource_list)
+	wl_resource_for_each(resource, resource_list) {
+		send_timestamps_for_input_resource(resource,
+						   &keyboard->timestamps_list,
+						   time);
 		wl_keyboard_send_key(resource, serial, msecs, key, state);
+	}
 };
 
 static void
@@ -1157,6 +1197,7 @@ weston_keyboard_create(void)
 	keyboard->default_grab.keyboard = keyboard;
 	keyboard->grab = &keyboard->default_grab;
 	wl_signal_init(&keyboard->focus_signal);
+	wl_list_init(&keyboard->timestamps_list);
 
 	return keyboard;
 }
@@ -1187,6 +1228,7 @@ weston_keyboard_destroy(struct weston_keyboard *keyboard)
 
 	wl_array_release(&keyboard->keys);
 	wl_list_remove(&keyboard->focus_resource_listener.link);
+	wl_list_remove(&keyboard->timestamps_list);
 	free(keyboard);
 }
 
@@ -2467,6 +2509,19 @@ seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
 	}
 }
 
+static void
+destroy_keyboard_resource(struct wl_resource *resource)
+{
+	struct weston_keyboard *keyboard = wl_resource_get_user_data(resource);
+
+	wl_list_remove(wl_resource_get_link(resource));
+
+	if (keyboard) {
+		remove_input_resource_from_timestamps(resource,
+						      &keyboard->timestamps_list);
+	}
+}
+
 static void
 keyboard_release(struct wl_client *client, struct wl_resource *resource)
 {
@@ -2524,7 +2579,7 @@ seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
 
 	wl_list_init(wl_resource_get_link(cr));
 	wl_resource_set_implementation(cr, &keyboard_interface,
-				       keyboard, unbind_resource);
+				       keyboard, destroy_keyboard_resource);
 
 	/* If we don't have a keyboard_state, the resource is inert, so there
 	 * is nothing more to set up */
@@ -4570,6 +4625,18 @@ bind_pointer_constraints(struct wl_client *client, void *data,
 				       NULL, NULL);
 }
 
+static void
+input_timestamps_destroy(struct wl_client *client,
+			 struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static const struct zwp_input_timestamps_v1_interface
+				input_timestamps_interface = {
+	input_timestamps_destroy,
+};
+
 static void
 input_timestamps_manager_destroy(struct wl_client *client,
 				 struct wl_resource *resource)
@@ -4583,7 +4650,29 @@ input_timestamps_manager_get_keyboard_timestamps(struct wl_client *client,
 						 uint32_t id,
 						 struct wl_resource *keyboard_resource)
 {
-	wl_client_post_no_memory(client);
+	struct weston_keyboard *keyboard =
+		wl_resource_get_user_data(keyboard_resource);
+	struct wl_resource *input_ts;
+
+	input_ts = wl_resource_create(client,
+				      &zwp_input_timestamps_v1_interface,
+				      1, id);
+	if (!input_ts) {
+		wl_client_post_no_memory(client);
+		return;
+	}
+
+	if (keyboard) {
+		wl_list_insert(&keyboard->timestamps_list,
+			       wl_resource_get_link(input_ts));
+	} else {
+		wl_list_init(wl_resource_get_link(input_ts));
+	}
+
+	wl_resource_set_implementation(input_ts,
+				       &input_timestamps_interface,
+				       keyboard_resource,
+				       unbind_resource);
 }
 
 static void
diff --git a/tests/keyboard-test.c b/tests/keyboard-test.c
index 722bfd32..37ef83d0 100644
--- a/tests/keyboard-test.c
+++ b/tests/keyboard-test.c
@@ -27,11 +27,13 @@
 
 #include <stdint.h>
 
+#include "input-timestamps-helper.h"
 #include "shared/timespec-util.h"
 #include "weston-test-client-helper.h"
 
 static const struct timespec t1 = { .tv_sec = 1, .tv_nsec = 1000001 };
 static const struct timespec t2 = { .tv_sec = 2, .tv_nsec = 2000001 };
+static const struct timespec t_other = { .tv_sec = 123, .tv_nsec = 456 };
 
 static struct client *
 create_client_with_keyboard_focus(void)
@@ -97,10 +99,59 @@ TEST(keyboard_key_event_time)
 {
 	struct client *client = create_client_with_keyboard_focus();
 	struct keyboard *keyboard = client->input->keyboard;
+	struct input_timestamps *input_ts =
+		input_timestamps_create_for_keyboard(client);
 
 	send_key(client, &t1, 1, WL_KEYBOARD_KEY_STATE_PRESSED);
 	assert(keyboard->key_time_msec == timespec_to_msec(&t1));
+	assert(timespec_eq(&keyboard->key_time_timespec, &t1));
 
 	send_key(client, &t2, 1, WL_KEYBOARD_KEY_STATE_RELEASED);
 	assert(keyboard->key_time_msec == timespec_to_msec(&t2));
+	assert(timespec_eq(&keyboard->key_time_timespec, &t2));
+
+	input_timestamps_destroy(input_ts);
+}
+
+TEST(keyboard_timestamps_stop_after_input_timestamps_object_is_destroyed)
+{
+	struct client *client = create_client_with_keyboard_focus();
+	struct keyboard *keyboard = client->input->keyboard;
+	struct input_timestamps *input_ts =
+		input_timestamps_create_for_keyboard(client);
+
+	send_key(client, &t1, 1, WL_KEYBOARD_KEY_STATE_PRESSED);
+	assert(keyboard->key_time_msec == timespec_to_msec(&t1));
+	assert(timespec_eq(&keyboard->key_time_timespec, &t1));
+
+	input_timestamps_destroy(input_ts);
+
+	send_key(client, &t2, 1, WL_KEYBOARD_KEY_STATE_RELEASED);
+	assert(keyboard->key_time_msec == timespec_to_msec(&t2));
+	assert(timespec_is_zero(&keyboard->key_time_timespec));
+}
+
+TEST(keyboard_timestamps_stop_after_client_releases_wl_keyboard)
+{
+	struct client *client = create_client_with_keyboard_focus();
+	struct keyboard *keyboard = client->input->keyboard;
+	struct input_timestamps *input_ts =
+		input_timestamps_create_for_keyboard(client);
+
+	send_key(client, &t1, 1, WL_KEYBOARD_KEY_STATE_PRESSED);
+	assert(keyboard->key_time_msec == timespec_to_msec(&t1));
+	assert(timespec_eq(&keyboard->key_time_timespec, &t1));
+
+	wl_keyboard_release(client->input->keyboard->wl_keyboard);
+
+	/* Set input_timestamp to an arbitrary value (different from t1, t2
+	 * and 0) and check that it is not changed by sending the event.
+	 * This is preferred over just checking for 0, since 0 is used
+	 * internally for resetting the timestamp after handling an input
+	 * event and checking for it here may lead to false negatives. */
+	keyboard->input_timestamp = t_other;
+	send_key(client, &t2, 1, WL_KEYBOARD_KEY_STATE_RELEASED);
+	assert(timespec_eq(&keyboard->input_timestamp, &t_other));
+
+	input_timestamps_destroy(input_ts);
 }
-- 
2.14.1



More information about the wayland-devel mailing list