libweston: Implement pointer timestamps for input_timestamps_unstable_v1
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 <alexandros.frantzis@collabora.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
This commit is contained in:
parent
2b44248f60
commit
db907b7188
@ -391,6 +391,8 @@ struct weston_pointer {
|
|||||||
uint32_t button_count;
|
uint32_t button_count;
|
||||||
|
|
||||||
struct wl_listener output_destroy_listener;
|
struct wl_listener output_destroy_listener;
|
||||||
|
|
||||||
|
struct wl_list timestamps_list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -226,6 +226,8 @@ unbind_pointer_client_resource(struct wl_resource *resource)
|
|||||||
pointer_client = weston_pointer_get_pointer_client(pointer,
|
pointer_client = weston_pointer_get_pointer_client(pointer,
|
||||||
client);
|
client);
|
||||||
assert(pointer_client);
|
assert(pointer_client);
|
||||||
|
remove_input_resource_from_timestamps(resource,
|
||||||
|
&pointer->timestamps_list);
|
||||||
weston_pointer_cleanup_pointer_client(pointer, pointer_client);
|
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;
|
resource_list = &pointer->focus_client->pointer_resources;
|
||||||
msecs = timespec_to_msec(time);
|
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_pointer_send_motion(resource, msecs, sx, sy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WL_EXPORT void
|
WL_EXPORT void
|
||||||
@ -528,8 +534,12 @@ weston_pointer_send_button(struct weston_pointer *pointer,
|
|||||||
resource_list = &pointer->focus_client->pointer_resources;
|
resource_list = &pointer->focus_client->pointer_resources;
|
||||||
serial = wl_display_next_serial(display);
|
serial = wl_display_next_serial(display);
|
||||||
msecs = timespec_to_msec(time);
|
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);
|
wl_pointer_send_button(resource, serial, msecs, button, state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -586,14 +596,21 @@ weston_pointer_send_axis(struct weston_pointer *pointer,
|
|||||||
wl_pointer_send_axis_discrete(resource, event->axis,
|
wl_pointer_send_axis_discrete(resource, event->axis,
|
||||||
event->discrete);
|
event->discrete);
|
||||||
|
|
||||||
if (event->value)
|
if (event->value) {
|
||||||
|
send_timestamps_for_input_resource(resource,
|
||||||
|
&pointer->timestamps_list,
|
||||||
|
time);
|
||||||
wl_pointer_send_axis(resource, msecs,
|
wl_pointer_send_axis(resource, msecs,
|
||||||
event->axis,
|
event->axis,
|
||||||
wl_fixed_from_double(event->value));
|
wl_fixed_from_double(event->value));
|
||||||
else if (wl_resource_get_version(resource) >=
|
} else if (wl_resource_get_version(resource) >=
|
||||||
WL_POINTER_AXIS_STOP_SINCE_VERSION)
|
WL_POINTER_AXIS_STOP_SINCE_VERSION) {
|
||||||
|
send_timestamps_for_input_resource(resource,
|
||||||
|
&pointer->timestamps_list,
|
||||||
|
time);
|
||||||
wl_pointer_send_axis_stop(resource, msecs,
|
wl_pointer_send_axis_stop(resource, msecs,
|
||||||
event->axis);
|
event->axis);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1128,6 +1145,7 @@ weston_pointer_create(struct weston_seat *seat)
|
|||||||
wl_signal_init(&pointer->focus_signal);
|
wl_signal_init(&pointer->focus_signal);
|
||||||
wl_list_init(&pointer->focus_view_listener.link);
|
wl_list_init(&pointer->focus_view_listener.link);
|
||||||
wl_signal_init(&pointer->destroy_signal);
|
wl_signal_init(&pointer->destroy_signal);
|
||||||
|
wl_list_init(&pointer->timestamps_list);
|
||||||
|
|
||||||
pointer->sprite_destroy_listener.notify = pointer_handle_sprite_destroy;
|
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_resource_listener.link);
|
||||||
wl_list_remove(&pointer->focus_view_listener.link);
|
wl_list_remove(&pointer->focus_view_listener.link);
|
||||||
wl_list_remove(&pointer->output_destroy_listener.link);
|
wl_list_remove(&pointer->output_destroy_listener.link);
|
||||||
|
wl_list_remove(&pointer->timestamps_list);
|
||||||
free(pointer);
|
free(pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4681,7 +4700,29 @@ input_timestamps_manager_get_pointer_timestamps(struct wl_client *client,
|
|||||||
uint32_t id,
|
uint32_t id,
|
||||||
struct wl_resource *pointer_resource)
|
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
|
static void
|
||||||
|
@ -28,12 +28,14 @@
|
|||||||
|
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
|
|
||||||
|
#include "input-timestamps-helper.h"
|
||||||
#include "shared/timespec-util.h"
|
#include "shared/timespec-util.h"
|
||||||
#include "weston-test-client-helper.h"
|
#include "weston-test-client-helper.h"
|
||||||
|
|
||||||
static const struct timespec t0 = { .tv_sec = 0, .tv_nsec = 100000000 };
|
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 t1 = { .tv_sec = 1, .tv_nsec = 1000001 };
|
||||||
static const struct timespec t2 = { .tv_sec = 2, .tv_nsec = 2000001 };
|
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
|
static void
|
||||||
send_motion(struct client *client, const struct timespec *time, int x, int y)
|
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,
|
struct client *client = create_client_with_pointer_focus(100, 100,
|
||||||
100, 100);
|
100, 100);
|
||||||
struct pointer *pointer = client->input->pointer;
|
struct pointer *pointer = client->input->pointer;
|
||||||
|
struct input_timestamps *input_ts =
|
||||||
|
input_timestamps_create_for_pointer(client);
|
||||||
|
|
||||||
send_motion(client, &t1, 150, 150);
|
send_motion(client, &t1, 150, 150);
|
||||||
assert(pointer->x == 50);
|
assert(pointer->x == 50);
|
||||||
assert(pointer->y == 50);
|
assert(pointer->y == 50);
|
||||||
assert(pointer->motion_time_msec == timespec_to_msec(&t1));
|
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)
|
TEST(pointer_button_events)
|
||||||
@ -353,6 +360,8 @@ TEST(pointer_button_events)
|
|||||||
struct client *client = create_client_with_pointer_focus(100, 100,
|
struct client *client = create_client_with_pointer_focus(100, 100,
|
||||||
100, 100);
|
100, 100);
|
||||||
struct pointer *pointer = client->input->pointer;
|
struct pointer *pointer = client->input->pointer;
|
||||||
|
struct input_timestamps *input_ts =
|
||||||
|
input_timestamps_create_for_pointer(client);
|
||||||
|
|
||||||
assert(pointer->button == 0);
|
assert(pointer->button == 0);
|
||||||
assert(pointer->state == 0);
|
assert(pointer->state == 0);
|
||||||
@ -361,11 +370,15 @@ TEST(pointer_button_events)
|
|||||||
assert(pointer->button == BTN_LEFT);
|
assert(pointer->button == BTN_LEFT);
|
||||||
assert(pointer->state == WL_POINTER_BUTTON_STATE_PRESSED);
|
assert(pointer->state == WL_POINTER_BUTTON_STATE_PRESSED);
|
||||||
assert(pointer->button_time_msec == timespec_to_msec(&t1));
|
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);
|
send_button(client, &t2, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
|
||||||
assert(pointer->button == BTN_LEFT);
|
assert(pointer->button == BTN_LEFT);
|
||||||
assert(pointer->state == WL_POINTER_BUTTON_STATE_RELEASED);
|
assert(pointer->state == WL_POINTER_BUTTON_STATE_RELEASED);
|
||||||
assert(pointer->button_time_msec == timespec_to_msec(&t2));
|
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)
|
TEST(pointer_axis_events)
|
||||||
@ -373,13 +386,70 @@ TEST(pointer_axis_events)
|
|||||||
struct client *client = create_client_with_pointer_focus(100, 100,
|
struct client *client = create_client_with_pointer_focus(100, 100,
|
||||||
100, 100);
|
100, 100);
|
||||||
struct pointer *pointer = client->input->pointer;
|
struct pointer *pointer = client->input->pointer;
|
||||||
|
struct input_timestamps *input_ts =
|
||||||
|
input_timestamps_create_for_pointer(client);
|
||||||
|
|
||||||
send_axis(client, &t1, 1, 1.0);
|
send_axis(client, &t1, 1, 1.0);
|
||||||
assert(pointer->axis == 1);
|
assert(pointer->axis == 1);
|
||||||
assert(pointer->axis_value == 1.0);
|
assert(pointer->axis_value == 1.0);
|
||||||
assert(pointer->axis_time_msec == timespec_to_msec(&t1));
|
assert(pointer->axis_time_msec == timespec_to_msec(&t1));
|
||||||
|
assert(timespec_eq(&pointer->axis_time_timespec, &t1));
|
||||||
|
|
||||||
send_axis(client, &t2, 2, 0.0);
|
send_axis(client, &t2, 2, 0.0);
|
||||||
assert(pointer->axis == 2);
|
assert(pointer->axis == 2);
|
||||||
assert(pointer->axis_stop_time_msec == timespec_to_msec(&t2));
|
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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user