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)
{
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
keyboard->default_grab.keyboard = keyboard;
keyboard->grab = &keyboard->default_grab;
wl_signal_init(&keyboard->focus_signal);
+ wl_list_init(&keyboard->timestamps_list);
return keyboard;
}
wl_array_release(&keyboard->keys);
wl_list_remove(&keyboard->focus_resource_listener.link);
+ wl_list_remove(&keyboard->timestamps_list);
free(keyboard);
}
}
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)
{
wl_resource_destroy(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 */
}
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)
{
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
#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)
{
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);
}