From d7157847343a6a37b2cd77be2e8e3ed22c5aee92 Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Tue, 20 Feb 2018 14:07:03 +0200 Subject: [PATCH] libweston: Implement touch timestamps for input_timestamps_unstable_v1 Implement the zwp_input_timestamps_manager_v1.get_touch_timestamps request to subscribe to timestamp events for wl_touch resources. Ensure that the request handling code can gracefully handle inert touch resources. Signed-off-by: Alexandros Frantzis Reviewed-by: Pekka Paalanen --- libweston/compositor.h | 2 ++ libweston/input.c | 61 +++++++++++++++++++++++++++++++++++++----- tests/touch-test.c | 52 +++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 7 deletions(-) diff --git a/libweston/compositor.h b/libweston/compositor.h index 78d2668e..010f1fa8 100644 --- a/libweston/compositor.h +++ b/libweston/compositor.h @@ -415,6 +415,8 @@ struct weston_touch { wl_fixed_t grab_x, grab_y; uint32_t grab_serial; struct timespec grab_time; + + struct wl_list timestamps_list; }; void diff --git a/libweston/input.c b/libweston/input.c index 632c9c3c..3f616941 100644 --- a/libweston/input.c +++ b/libweston/input.c @@ -758,10 +758,14 @@ weston_touch_send_down(struct weston_touch *touch, const struct timespec *time, resource_list = &touch->focus_resource_list; serial = wl_display_next_serial(display); msecs = timespec_to_msec(time); - wl_resource_for_each(resource, resource_list) - wl_touch_send_down(resource, serial, msecs, - touch->focus->surface->resource, - touch_id, sx, sy); + wl_resource_for_each(resource, resource_list) { + send_timestamps_for_input_resource(resource, + &touch->timestamps_list, + time); + wl_touch_send_down(resource, serial, msecs, + touch->focus->surface->resource, + touch_id, sx, sy); + } } static void @@ -798,8 +802,12 @@ weston_touch_send_up(struct weston_touch *touch, const struct timespec *time, resource_list = &touch->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, + &touch->timestamps_list, + time); wl_touch_send_up(resource, serial, msecs, touch_id); + } } static void @@ -839,6 +847,9 @@ weston_touch_send_motion(struct weston_touch *touch, resource_list = &touch->focus_resource_list; msecs = timespec_to_msec(time); wl_resource_for_each(resource, resource_list) { + send_timestamps_for_input_resource(resource, + &touch->timestamps_list, + time); wl_touch_send_motion(resource, msecs, touch_id, sx, sy); } @@ -1276,6 +1287,7 @@ weston_touch_create(void) touch->default_grab.touch = touch; touch->grab = &touch->default_grab; wl_signal_init(&touch->focus_signal); + wl_list_init(&touch->timestamps_list); return touch; } @@ -1297,6 +1309,7 @@ weston_touch_destroy(struct weston_touch *touch) wl_list_remove(&touch->focus_resource_list); wl_list_remove(&touch->focus_view_listener.link); wl_list_remove(&touch->focus_resource_listener.link); + wl_list_remove(&touch->timestamps_list); free(touch); } @@ -2647,6 +2660,19 @@ seat_get_keyboard(struct wl_client *client, struct wl_resource *resource, } } +static void +destroy_touch_resource(struct wl_resource *resource) +{ + struct weston_touch *touch = wl_resource_get_user_data(resource); + + wl_list_remove(wl_resource_get_link(resource)); + + if (touch) { + remove_input_resource_from_timestamps(resource, + &touch->timestamps_list); + } +} + static void touch_release(struct wl_client *client, struct wl_resource *resource) { @@ -2682,7 +2708,7 @@ seat_get_touch(struct wl_client *client, struct wl_resource *resource, wl_list_init(wl_resource_get_link(cr)); wl_resource_set_implementation(cr, &touch_interface, - touch, unbind_resource); + touch, destroy_touch_resource); /* If we don't have a touch_state, the resource is inert, so there * is nothing more to set up */ @@ -4731,7 +4757,28 @@ input_timestamps_manager_get_touch_timestamps(struct wl_client *client, uint32_t id, struct wl_resource *touch_resource) { - wl_client_post_no_memory(client); + struct weston_touch *touch = wl_resource_get_user_data(touch_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 (touch) { + wl_list_insert(&touch->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, + touch_resource, + unbind_resource); } static const struct zwp_input_timestamps_manager_v1_interface diff --git a/tests/touch-test.c b/tests/touch-test.c index 9635257f..baf5bc58 100644 --- a/tests/touch-test.c +++ b/tests/touch-test.c @@ -27,6 +27,7 @@ #include +#include "input-timestamps-helper.h" #include "shared/timespec-util.h" #include "weston-test-client-helper.h" #include "wayland-server-protocol.h" @@ -34,6 +35,7 @@ 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 t3 = { .tv_sec = 3, .tv_nsec = 3000001 }; +static const struct timespec t_other = { .tv_sec = 123, .tv_nsec = 456 }; static struct client * create_touch_test_client(void) @@ -59,13 +61,63 @@ TEST(touch_events) { struct client *client = create_touch_test_client(); struct touch *touch = client->input->touch; + struct input_timestamps *input_ts = + input_timestamps_create_for_touch(client); send_touch(client, &t1, WL_TOUCH_DOWN); assert(touch->down_time_msec == timespec_to_msec(&t1)); + assert(timespec_eq(&touch->down_time_timespec, &t1)); send_touch(client, &t2, WL_TOUCH_MOTION); assert(touch->motion_time_msec == timespec_to_msec(&t2)); + assert(timespec_eq(&touch->motion_time_timespec, &t2)); send_touch(client, &t3, WL_TOUCH_UP); assert(touch->up_time_msec == timespec_to_msec(&t3)); + assert(timespec_eq(&touch->up_time_timespec, &t3)); + + input_timestamps_destroy(input_ts); +} + +TEST(touch_timestamps_stop_after_input_timestamps_object_is_destroyed) +{ + struct client *client = create_touch_test_client(); + struct touch *touch = client->input->touch; + struct input_timestamps *input_ts = + input_timestamps_create_for_touch(client); + + send_touch(client, &t1, WL_TOUCH_DOWN); + assert(touch->down_time_msec == timespec_to_msec(&t1)); + assert(timespec_eq(&touch->down_time_timespec, &t1)); + + input_timestamps_destroy(input_ts); + + send_touch(client, &t2, WL_TOUCH_UP); + assert(touch->up_time_msec == timespec_to_msec(&t2)); + assert(timespec_is_zero(&touch->up_time_timespec)); +} + +TEST(touch_timestamps_stop_after_client_releases_wl_touch) +{ + struct client *client = create_touch_test_client(); + struct touch *touch = client->input->touch; + struct input_timestamps *input_ts = + input_timestamps_create_for_touch(client); + + send_touch(client, &t1, WL_TOUCH_DOWN); + assert(touch->down_time_msec == timespec_to_msec(&t1)); + assert(timespec_eq(&touch->down_time_timespec, &t1)); + + wl_touch_release(client->input->touch->wl_touch); + + /* 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. */ + touch->input_timestamp = t_other; + send_touch(client, &t2, WL_TOUCH_UP); + assert(timespec_eq(&touch->input_timestamp, &t_other)); + + input_timestamps_destroy(input_ts); }