Implement the zwp_input_timestamps_manager_v1.get_pointer_timestamps
request to subscribe to timestamp events for wl_pointer resources.
Ensure that the request handling code can gracefully handle inert
pointer resources.

Signed-off-by: Alexandros Frantzis <[email protected]>
---
Changes in v3:
 - In pointer_timestamps_stop_after_client_releases_wl_pointer test
   check for changes to pointer->input_timestamp instead of
   pointer->motion_time_timespec.

Changes in v2:
 - Remove the head of timestamps_list in weston_pointer_destroy.
 - Gracefully handle inert pointer resources in
   input_timestamps_manager_get_pointer_timestamps.

 libweston/compositor.h |  2 ++
 libweston/input.c      | 53 +++++++++++++++++++++++++++++++++-----
 tests/pointer-test.c   | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 119 insertions(+), 6 deletions(-)

diff --git a/libweston/compositor.h b/libweston/compositor.h
index 1566677f..78d2668e 100644
--- a/libweston/compositor.h
+++ b/libweston/compositor.h
@@ -391,6 +391,8 @@ struct weston_pointer {
        uint32_t button_count;
 
        struct wl_listener output_destroy_listener;
+
+       struct wl_list timestamps_list;
 };
 
 
diff --git a/libweston/input.c b/libweston/input.c
index 8028ec20..632c9c3c 100644
--- a/libweston/input.c
+++ b/libweston/input.c
@@ -226,6 +226,8 @@ unbind_pointer_client_resource(struct wl_resource *resource)
                pointer_client = weston_pointer_get_pointer_client(pointer,
                                                                   client);
                assert(pointer_client);
+               remove_input_resource_from_timestamps(resource,
+                                                     
&pointer->timestamps_list);
                weston_pointer_cleanup_pointer_client(pointer, pointer_client);
        }
 }
@@ -446,8 +448,12 @@ pointer_send_motion(struct weston_pointer *pointer,
 
        resource_list = &pointer->focus_client->pointer_resources;
        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,
+                                                   &pointer->timestamps_list,
+                                                   time);
                wl_pointer_send_motion(resource, msecs, sx, sy);
+       }
 }
 
 WL_EXPORT void
@@ -528,8 +534,12 @@ weston_pointer_send_button(struct weston_pointer *pointer,
        resource_list = &pointer->focus_client->pointer_resources;
        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,
+                                                   &pointer->timestamps_list,
+                                                   time);
                wl_pointer_send_button(resource, serial, msecs, button, state);
+       }
 }
 
 static void
@@ -586,14 +596,21 @@ weston_pointer_send_axis(struct weston_pointer *pointer,
                        wl_pointer_send_axis_discrete(resource, event->axis,
                                                      event->discrete);
 
-               if (event->value)
+               if (event->value) {
+                       send_timestamps_for_input_resource(resource,
+                                                          
&pointer->timestamps_list,
+                                                          time);
                        wl_pointer_send_axis(resource, msecs,
                                             event->axis,
                                             
wl_fixed_from_double(event->value));
-               else if (wl_resource_get_version(resource) >=
-                        WL_POINTER_AXIS_STOP_SINCE_VERSION)
+               } else if (wl_resource_get_version(resource) >=
+                        WL_POINTER_AXIS_STOP_SINCE_VERSION) {
+                       send_timestamps_for_input_resource(resource,
+                                                          
&pointer->timestamps_list,
+                                                          time);
                        wl_pointer_send_axis_stop(resource, msecs,
                                                  event->axis);
+               }
        }
 }
 
@@ -1128,6 +1145,7 @@ weston_pointer_create(struct weston_seat *seat)
        wl_signal_init(&pointer->focus_signal);
        wl_list_init(&pointer->focus_view_listener.link);
        wl_signal_init(&pointer->destroy_signal);
+       wl_list_init(&pointer->timestamps_list);
 
        pointer->sprite_destroy_listener.notify = pointer_handle_sprite_destroy;
 
@@ -1165,6 +1183,7 @@ weston_pointer_destroy(struct weston_pointer *pointer)
        wl_list_remove(&pointer->focus_resource_listener.link);
        wl_list_remove(&pointer->focus_view_listener.link);
        wl_list_remove(&pointer->output_destroy_listener.link);
+       wl_list_remove(&pointer->timestamps_list);
        free(pointer);
 }
 
@@ -4681,7 +4700,29 @@ input_timestamps_manager_get_pointer_timestamps(struct 
wl_client *client,
                                                uint32_t id,
                                                struct wl_resource 
*pointer_resource)
 {
-       wl_client_post_no_memory(client);
+       struct weston_pointer *pointer =
+               wl_resource_get_user_data(pointer_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 (pointer) {
+               wl_list_insert(&pointer->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,
+                                      pointer_resource,
+                                      unbind_resource);
 }
 
 static void
diff --git a/tests/pointer-test.c b/tests/pointer-test.c
index 4c438a22..eef52228 100644
--- a/tests/pointer-test.c
+++ b/tests/pointer-test.c
@@ -28,12 +28,14 @@
 
 #include <linux/input.h>
 
+#include "input-timestamps-helper.h"
 #include "shared/timespec-util.h"
 #include "weston-test-client-helper.h"
 
 static const struct timespec t0 = { .tv_sec = 0, .tv_nsec = 100000000 };
 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 void
 send_motion(struct client *client, const struct timespec *time, int x, int y)
@@ -341,11 +343,16 @@ TEST(pointer_motion_events)
        struct client *client = create_client_with_pointer_focus(100, 100,
                                                                 100, 100);
        struct pointer *pointer = client->input->pointer;
+       struct input_timestamps *input_ts =
+               input_timestamps_create_for_pointer(client);
 
        send_motion(client, &t1, 150, 150);
        assert(pointer->x == 50);
        assert(pointer->y == 50);
        assert(pointer->motion_time_msec == timespec_to_msec(&t1));
+       assert(timespec_eq(&pointer->motion_time_timespec, &t1));
+
+       input_timestamps_destroy(input_ts);
 }
 
 TEST(pointer_button_events)
@@ -353,6 +360,8 @@ TEST(pointer_button_events)
        struct client *client = create_client_with_pointer_focus(100, 100,
                                                                 100, 100);
        struct pointer *pointer = client->input->pointer;
+       struct input_timestamps *input_ts =
+               input_timestamps_create_for_pointer(client);
 
        assert(pointer->button == 0);
        assert(pointer->state == 0);
@@ -361,11 +370,15 @@ TEST(pointer_button_events)
        assert(pointer->button == BTN_LEFT);
        assert(pointer->state == WL_POINTER_BUTTON_STATE_PRESSED);
        assert(pointer->button_time_msec == timespec_to_msec(&t1));
+       assert(timespec_eq(&pointer->button_time_timespec, &t1));
 
        send_button(client, &t2, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
        assert(pointer->button == BTN_LEFT);
        assert(pointer->state == WL_POINTER_BUTTON_STATE_RELEASED);
        assert(pointer->button_time_msec == timespec_to_msec(&t2));
+       assert(timespec_eq(&pointer->button_time_timespec, &t2));
+
+       input_timestamps_destroy(input_ts);
 }
 
 TEST(pointer_axis_events)
@@ -373,13 +386,70 @@ TEST(pointer_axis_events)
        struct client *client = create_client_with_pointer_focus(100, 100,
                                                                 100, 100);
        struct pointer *pointer = client->input->pointer;
+       struct input_timestamps *input_ts =
+               input_timestamps_create_for_pointer(client);
 
        send_axis(client, &t1, 1, 1.0);
        assert(pointer->axis == 1);
        assert(pointer->axis_value == 1.0);
        assert(pointer->axis_time_msec == timespec_to_msec(&t1));
+       assert(timespec_eq(&pointer->axis_time_timespec, &t1));
 
        send_axis(client, &t2, 2, 0.0);
        assert(pointer->axis == 2);
        assert(pointer->axis_stop_time_msec == timespec_to_msec(&t2));
+       assert(timespec_eq(&pointer->axis_stop_time_timespec, &t2));
+
+       input_timestamps_destroy(input_ts);
+}
+
+TEST(pointer_timestamps_stop_after_input_timestamps_object_is_destroyed)
+{
+       struct client *client = create_client_with_pointer_focus(100, 100,
+                                                                100, 100);
+       struct pointer *pointer = client->input->pointer;
+       struct input_timestamps *input_ts =
+               input_timestamps_create_for_pointer(client);
+
+       send_button(client, &t1, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED);
+       assert(pointer->button == BTN_LEFT);
+       assert(pointer->state == WL_POINTER_BUTTON_STATE_PRESSED);
+       assert(pointer->button_time_msec == timespec_to_msec(&t1));
+       assert(timespec_eq(&pointer->button_time_timespec, &t1));
+
+       input_timestamps_destroy(input_ts);
+
+       send_button(client, &t2, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
+       assert(pointer->button == BTN_LEFT);
+       assert(pointer->state == WL_POINTER_BUTTON_STATE_RELEASED);
+       assert(pointer->button_time_msec == timespec_to_msec(&t2));
+       assert(timespec_is_zero(&pointer->button_time_timespec));
+}
+
+TEST(pointer_timestamps_stop_after_client_releases_wl_pointer)
+{
+       struct client *client = create_client_with_pointer_focus(100, 100,
+                                                                100, 100);
+       struct pointer *pointer = client->input->pointer;
+       struct input_timestamps *input_ts =
+               input_timestamps_create_for_pointer(client);
+
+       send_motion(client, &t1, 150, 150);
+       assert(pointer->x == 50);
+       assert(pointer->y == 50);
+       assert(pointer->motion_time_msec == timespec_to_msec(&t1));
+       assert(timespec_eq(&pointer->motion_time_timespec, &t1));
+
+       wl_pointer_release(client->input->pointer->wl_pointer);
+
+       /* 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. */
+       pointer->input_timestamp = t_other;
+       send_motion(client, &t2, 175, 175);
+       assert(timespec_eq(&pointer->input_timestamp, &t_other));
+
+       input_timestamps_destroy(input_ts);
 }
-- 
2.14.1

_______________________________________________
wayland-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to