From 8cafde5ecc402f62a3fa1efe9c94b4f12ae6f4f4 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Sun, 4 Dec 2022 11:45:19 -0500 Subject: [PATCH] wayland: Add high-resolution event timestamp support Add the protocol for high-resolution timestamp events and subscribe to them if available. Event timestamps are now handled natively in nanoseconds as much as possible to avoid error-prone conversions. Variables have been appended with _ms or _ns where appropriate, to avoid ambiguity. --- src/video/wayland/SDL_waylandevents.c | 126 +++++++++++---- src/video/wayland/SDL_waylandevents_c.h | 27 ++-- src/video/wayland/SDL_waylandtouch.c | 11 +- src/video/wayland/SDL_waylandvideo.c | 11 ++ src/video/wayland/SDL_waylandvideo.h | 1 + .../input-timestamps-unstable-v1.xml | 145 ++++++++++++++++++ 6 files changed, 278 insertions(+), 43 deletions(-) create mode 100644 wayland-protocols/input-timestamps-unstable-v1.xml diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index f8a3781b7..a92fd6ea9 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -39,6 +39,7 @@ #include "text-input-unstable-v3-client-protocol.h" #include "tablet-unstable-v2-client-protocol.h" #include "primary-selection-unstable-v1-client-protocol.h" +#include "input-timestamps-unstable-v1-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -173,11 +174,10 @@ static struct wl_surface *touch_surface(SDL_TouchID id) return NULL; } -Uint64 Wayland_GetEventTimestamp(Uint32 wayland_timestamp) +Uint64 Wayland_GetEventTimestamp(Uint64 nsTimestamp) { - static Uint32 last; + static Uint64 last; static Uint64 timestamp_offset; - Uint64 nsTimestamp = SDL_MS_TO_NS(wayland_timestamp); const Uint64 now = SDL_GetTicksNS(); if (!nsTimestamp) { @@ -203,19 +203,71 @@ Uint64 Wayland_GetEventTimestamp(Uint32 wayland_timestamp) return nsTimestamp; } +static void Wayland_input_timestamp_listener(void *data, struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1, + uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec) +{ + *((Uint64 *)data) = ((((Uint64)tv_sec_hi << 32) | (Uint64)tv_sec_lo) * SDL_NS_PER_SECOND) + tv_nsec; +} + +static const struct zwp_input_timestamps_v1_listener timestamp_listener = { + Wayland_input_timestamp_listener +}; + +static Uint64 Wayland_GetKeyboardTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms) +{ + return Wayland_GetEventTimestamp(input->keyboard_timestamp_ns ? input->keyboard_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms)); +} + +static Uint64 Wayland_GetKeyboardTimestampRaw(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms) +{ + return input->keyboard_timestamp_ns ? input->keyboard_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms); +} + +static Uint64 Wayland_GetPointerTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms) +{ + return Wayland_GetEventTimestamp(input->pointer_timestamp_ns ? input->pointer_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms)); +} + +Uint64 Wayland_GetTouchTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms) +{ + return Wayland_GetEventTimestamp(input->touch_timestamp_ns ? input->touch_timestamp_ns : SDL_MS_TO_NS(wl_timestamp_ms)); +} + +void Wayland_RegisterTimestampListeners(struct SDL_WaylandInput *input) +{ + SDL_VideoData *viddata = input->display; + + if (viddata->input_timestamps_manager) { + if (input->keyboard && !input->keyboard_timestamps) { + input->keyboard_timestamps = zwp_input_timestamps_manager_v1_get_keyboard_timestamps(viddata->input_timestamps_manager, input->keyboard); + zwp_input_timestamps_v1_add_listener(input->keyboard_timestamps, ×tamp_listener, &input->keyboard_timestamp_ns); + } + + if (input->pointer && !input->pointer_timestamps) { + input->pointer_timestamps = zwp_input_timestamps_manager_v1_get_pointer_timestamps(viddata->input_timestamps_manager, input->pointer); + zwp_input_timestamps_v1_add_listener(input->pointer_timestamps, ×tamp_listener, &input->pointer_timestamp_ns); + } + + if (input->touch && !input->touch_timestamps) { + input->touch_timestamps = zwp_input_timestamps_manager_v1_get_touch_timestamps(viddata->input_timestamps_manager, input->touch); + zwp_input_timestamps_v1_add_listener(input->touch_timestamps, ×tamp_listener, &input->touch_timestamp_ns); + } + } +} + /* Returns SDL_TRUE if a key repeat event was due */ -static SDL_bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, uint32_t elapsed) +static SDL_bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint64 elapsed) { SDL_bool ret = SDL_FALSE; - while ((elapsed - repeat_info->next_repeat_ms) < 0x80000000U) { + while (elapsed >= repeat_info->next_repeat_ns) { if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) { - const Uint32 timestamp = repeat_info->wl_press_time + repeat_info->next_repeat_ms; + const Uint64 timestamp = repeat_info->wl_press_time_ns + repeat_info->next_repeat_ns; SDL_SendKeyboardKey(Wayland_GetEventTimestamp(timestamp), SDL_PRESSED, repeat_info->scancode); } if (repeat_info->text[0]) { SDL_SendKeyboardText(repeat_info->text); } - repeat_info->next_repeat_ms += 1000 / repeat_info->repeat_rate; + repeat_info->next_repeat_ns += SDL_NS_PER_SECOND / (Uint64)repeat_info->repeat_rate; ret = SDL_TRUE; } return ret; @@ -229,7 +281,7 @@ static void keyboard_repeat_clear(SDL_WaylandKeyboardRepeat *repeat_info) repeat_info->is_key_down = SDL_FALSE; } -static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, uint32_t key, uint32_t wl_press_time, +static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, uint32_t key, Uint64 wl_press_time_ns, uint32_t scancode, SDL_bool has_text, char text[8]) { if (!repeat_info->is_initialized || !repeat_info->repeat_rate) { @@ -237,9 +289,9 @@ static void keyboard_repeat_set(SDL_WaylandKeyboardRepeat *repeat_info, uint32_t } repeat_info->is_key_down = SDL_TRUE; repeat_info->key = key; - repeat_info->wl_press_time = wl_press_time; - repeat_info->sdl_press_time = SDL_GetTicks(); - repeat_info->next_repeat_ms = repeat_info->repeat_delay; + repeat_info->wl_press_time_ns = wl_press_time_ns; + repeat_info->sdl_press_time_ns = SDL_GetTicksNS(); + repeat_info->next_repeat_ns = SDL_MS_TO_NS(repeat_info->repeat_delay_ms); repeat_info->scancode = scancode; if (has_text) { SDL_memcpy(repeat_info->text, text, 8); @@ -317,16 +369,16 @@ int Wayland_WaitEventTimeout(_THIS, Sint64 timeoutNS) /* If key repeat is active, we'll need to cap our maximum wait time to handle repeats */ if (input && keyboard_repeat_is_set(&input->keyboard_repeat)) { - uint32_t elapsed = (uint32_t)(SDL_GetTicks() - input->keyboard_repeat.sdl_press_time); + const Uint64 elapsed = SDL_GetTicksNS() - input->keyboard_repeat.sdl_press_time_ns; if (keyboard_repeat_handle(&input->keyboard_repeat, elapsed)) { /* A repeat key event was already due */ return 1; } else { - uint32_t next_repeat_wait_time = (input->keyboard_repeat.next_repeat_ms - elapsed) + 1; + const Uint64 next_repeat_wait_time = (input->keyboard_repeat.next_repeat_ns - elapsed) + 1; if (timeoutNS >= 0) { - timeoutNS = SDL_min(timeoutNS, SDL_MS_TO_NS(next_repeat_wait_time)); + timeoutNS = SDL_min(timeoutNS, next_repeat_wait_time); } else { - timeoutNS = SDL_MS_TO_NS(next_repeat_wait_time); + timeoutNS = next_repeat_wait_time; } key_repeat_active = SDL_TRUE; } @@ -347,7 +399,7 @@ int Wayland_WaitEventTimeout(_THIS, Sint64 timeoutNS) /* If key repeat is active, we might have woken up to generate a key event */ if (key_repeat_active) { - uint32_t elapsed = (uint32_t)(SDL_GetTicks() - input->keyboard_repeat.sdl_press_time); + const Uint64 elapsed = SDL_GetTicksNS() - input->keyboard_repeat.sdl_press_time_ns; if (keyboard_repeat_handle(&input->keyboard_repeat, elapsed)) { return 1; } @@ -406,7 +458,7 @@ void Wayland_PumpEvents(_THIS) err = WAYLAND_wl_display_dispatch_pending(d->display); if (input && keyboard_repeat_is_set(&input->keyboard_repeat)) { - uint32_t elapsed = (uint32_t)(SDL_GetTicks() - input->keyboard_repeat.sdl_press_time); + const Uint64 elapsed = SDL_GetTicksNS() - input->keyboard_repeat.sdl_press_time_ns; keyboard_repeat_handle(&input->keyboard_repeat, elapsed); } @@ -440,7 +492,7 @@ static void pointer_handle_motion(void *data, struct wl_pointer *pointer, const float sy_f = (float)wl_fixed_to_double(sy_w); const int sx = (int)SDL_floorf(sx_f * window->pointer_scale_x); const int sy = (int)SDL_floorf(sy_f * window->pointer_scale_y); - SDL_SendMouseMotion(Wayland_GetEventTimestamp(time), window->sdlwindow, 0, 0, sx, sy); + SDL_SendMouseMotion(Wayland_GetPointerTimestamp(input, time), window->sdlwindow, 0, 0, sx, sy); } } @@ -634,7 +686,7 @@ static void pointer_handle_button_common(struct SDL_WaylandInput *input, uint32_ Wayland_data_device_set_serial(input->data_device, serial); Wayland_primary_selection_device_set_serial(input->primary_selection_device, serial); - SDL_SendMouseButton(Wayland_GetEventTimestamp(time), window->sdlwindow, 0, + SDL_SendMouseButton(Wayland_GetPointerTimestamp(input, time), window->sdlwindow, 0, state ? SDL_PRESSED : SDL_RELEASED, sdl_button); } } @@ -671,7 +723,7 @@ static void pointer_handle_axis_common_v1(struct SDL_WaylandInput *input, x /= WAYLAND_WHEEL_AXIS_UNIT; y /= WAYLAND_WHEEL_AXIS_UNIT; - SDL_SendMouseWheel(Wayland_GetEventTimestamp(time), window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL); + SDL_SendMouseWheel(Wayland_GetPointerTimestamp(input, time), window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL); } } @@ -754,7 +806,7 @@ static void pointer_handle_axis(void *data, struct wl_pointer *pointer, struct SDL_WaylandInput *input = data; if (wl_seat_get_version(input->seat) >= 5) { - input->pointer_curr_axis_info.timestamp = time; + input->pointer_curr_axis_info.timestamp_ns = Wayland_GetPointerTimestamp(input, time); pointer_handle_axis_common(input, AXIS_EVENT_CONTINUOUS, axis, value); } else { pointer_handle_axis_common_v1(input, time, axis, value); @@ -801,7 +853,7 @@ static void pointer_handle_frame(void *data, struct wl_pointer *pointer) SDL_memset(&input->pointer_curr_axis_info, 0, sizeof input->pointer_curr_axis_info); if (x != 0.0f || y != 0.0f) { - SDL_SendMouseWheel(Wayland_GetEventTimestamp(input->pointer_curr_axis_info.timestamp), + SDL_SendMouseWheel(input->pointer_curr_axis_info.timestamp_ns, window->sdlwindow, 0, x, y, SDL_MOUSEWHEEL_NORMAL); } } @@ -851,6 +903,7 @@ static void touch_handler_down(void *data, struct wl_touch *touch, uint32_t seri uint32_t timestamp, struct wl_surface *surface, int id, wl_fixed_t fx, wl_fixed_t fy) { + struct SDL_WaylandInput *input = (struct SDL_WaylandInput *)data; SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(surface); const double dblx = wl_fixed_to_double(fx) * window_data->pointer_scale_x; const double dbly = wl_fixed_to_double(fy) * window_data->pointer_scale_y; @@ -859,13 +912,14 @@ static void touch_handler_down(void *data, struct wl_touch *touch, uint32_t seri touch_add(id, x, y, surface); - SDL_SendTouch(Wayland_GetEventTimestamp(timestamp), (SDL_TouchID)(intptr_t)touch, + SDL_SendTouch(Wayland_GetTouchTimestamp(input, timestamp), (SDL_TouchID)(intptr_t)touch, (SDL_FingerID)id, window_data->sdlwindow, SDL_TRUE, x, y, 1.0f); } static void touch_handler_up(void *data, struct wl_touch *touch, uint32_t serial, uint32_t timestamp, int id) { + struct SDL_WaylandInput *input = (struct SDL_WaylandInput *)data; float x = 0, y = 0; struct wl_surface *surface = NULL; SDL_Window *window = NULL; @@ -877,13 +931,14 @@ static void touch_handler_up(void *data, struct wl_touch *touch, uint32_t serial window = window_data->sdlwindow; } - SDL_SendTouch(Wayland_GetEventTimestamp(timestamp), (SDL_TouchID)(intptr_t)touch, + SDL_SendTouch(Wayland_GetTouchTimestamp(input, timestamp), (SDL_TouchID)(intptr_t)touch, (SDL_FingerID)id, window, SDL_FALSE, x, y, 0.0f); } static void touch_handler_motion(void *data, struct wl_touch *touch, uint32_t timestamp, int id, wl_fixed_t fx, wl_fixed_t fy) { + struct SDL_WaylandInput *input = (struct SDL_WaylandInput *)data; SDL_WindowData *window_data = (SDL_WindowData *)wl_surface_get_user_data(touch_surface(id)); const double dblx = wl_fixed_to_double(fx) * window_data->pointer_scale_x; const double dbly = wl_fixed_to_double(fy) * window_data->pointer_scale_y; @@ -891,7 +946,7 @@ static void touch_handler_motion(void *data, struct wl_touch *touch, uint32_t ti const float y = dbly / window_data->sdlwindow->h; touch_update(id, x, y); - SDL_SendTouchMotion(Wayland_GetEventTimestamp(timestamp), (SDL_TouchID)(intptr_t)touch, + SDL_SendTouchMotion(Wayland_GetPointerTimestamp(input, timestamp), (SDL_TouchID)(intptr_t)touch, (SDL_FingerID)id, window_data->sdlwindow, x, y, 1.0f); } @@ -1237,6 +1292,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, char text[8]; SDL_bool has_text = SDL_FALSE; SDL_bool handled_by_ime = SDL_FALSE; + const Uint64 timestamp_raw_ns = Wayland_GetKeyboardTimestampRaw(input, time); if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { has_text = keyboard_input_get_text(text, input, key, SDL_PRESSED, &handled_by_ime); @@ -1247,7 +1303,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, * Using SDL_GetTicks would be wrong, as it would report when the release event is processed, * which may be off if the application hasn't pumped events for a while. */ - keyboard_repeat_handle(&input->keyboard_repeat, time - input->keyboard_repeat.wl_press_time); + keyboard_repeat_handle(&input->keyboard_repeat, timestamp_raw_ns - input->keyboard_repeat.wl_press_time_ns); keyboard_repeat_clear(&input->keyboard_repeat); } keyboard_input_get_text(text, input, key, SDL_RELEASED, &handled_by_ime); @@ -1255,7 +1311,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, if (!handled_by_ime) { scancode = Wayland_get_scancode_from_key(input, key + 8); - SDL_SendKeyboardKey(Wayland_GetEventTimestamp(time), state == WL_KEYBOARD_KEY_STATE_PRESSED ? SDL_PRESSED : SDL_RELEASED, scancode); + SDL_SendKeyboardKey(Wayland_GetKeyboardTimestamp(input, time), state == WL_KEYBOARD_KEY_STATE_PRESSED ? SDL_PRESSED : SDL_RELEASED, scancode); } if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { @@ -1267,7 +1323,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, } } if (input->xkb.keymap && WAYLAND_xkb_keymap_key_repeats(input->xkb.keymap, key + 8)) { - keyboard_repeat_set(&input->keyboard_repeat, key, time, scancode, has_text, text); + keyboard_repeat_set(&input->keyboard_repeat, key, timestamp_raw_ns, scancode, has_text, text); } } } @@ -1325,7 +1381,7 @@ static void keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keybo { struct SDL_WaylandInput *input = data; input->keyboard_repeat.repeat_rate = SDL_clamp(rate, 0, 1000); - input->keyboard_repeat.repeat_delay = delay; + input->keyboard_repeat.repeat_delay_ms = delay; input->keyboard_repeat.is_initialized = SDL_TRUE; } @@ -1377,6 +1433,8 @@ static void seat_handle_capabilities(void *data, struct wl_seat *seat, wl_keyboard_destroy(input->keyboard); input->keyboard = NULL; } + + Wayland_RegisterTimestampListeners(input); } static void seat_handle_name(void *data, struct wl_seat *wl_seat, const char *name) @@ -2396,6 +2454,16 @@ void Wayland_display_destroy_input(SDL_VideoData *d) return; } + if (input->keyboard_timestamps) { + zwp_input_timestamps_v1_destroy(input->keyboard_timestamps); + } + if (input->pointer_timestamps) { + zwp_input_timestamps_v1_destroy(input->pointer_timestamps); + } + if (input->touch_timestamps) { + zwp_input_timestamps_v1_destroy(input->touch_timestamps); + } + if (input->data_device != NULL) { Wayland_data_device_clear_selection(input->data_device); if (input->data_device->selection_offer != NULL) { diff --git a/src/video/wayland/SDL_waylandevents_c.h b/src/video/wayland/SDL_waylandevents_c.h index 904bb56fb..fee4c854b 100644 --- a/src/video/wayland/SDL_waylandevents_c.h +++ b/src/video/wayland/SDL_waylandevents_c.h @@ -68,16 +68,15 @@ struct SDL_WaylandTabletInput typedef struct { - // repeat_rate in range of [1, 1000] - int32_t repeat_rate; - int32_t repeat_delay; + int32_t repeat_rate; /* Repeat rate in range of [1, 1000] character(s) per second */ + int32_t repeat_delay_ms; /* Time to first repeat event in milliseconds */ SDL_bool is_initialized; SDL_bool is_key_down; uint32_t key; - uint32_t wl_press_time; // Key press time as reported by the Wayland API - Uint64 sdl_press_time; // Key press time expressed in SDL ticks - uint32_t next_repeat_ms; + Uint64 wl_press_time_ns; /* Key press time as reported by the Wayland API */ + Uint64 sdl_press_time_ns; /* Key press time expressed in SDL ticks */ + Uint64 next_repeat_ns; /* Next repeat event in nanoseconds */ uint32_t scancode; char text[8]; } SDL_WaylandKeyboardRepeat; @@ -93,10 +92,18 @@ struct SDL_WaylandInput SDL_WaylandPrimarySelectionDevice *primary_selection_device; SDL_WaylandTextInput *text_input; struct zwp_relative_pointer_v1 *relative_pointer; + struct zwp_input_timestamps_v1 *keyboard_timestamps; + struct zwp_input_timestamps_v1 *pointer_timestamps; + struct zwp_input_timestamps_v1 *touch_timestamps; SDL_WindowData *pointer_focus; SDL_WindowData *keyboard_focus; uint32_t pointer_enter_serial; + /* High-resolution event timestamps */ + Uint64 keyboard_timestamp_ns; + Uint64 pointer_timestamp_ns; + Uint64 touch_timestamp_ns; + /* Last motion location */ wl_fixed_t sx_w; wl_fixed_t sy_w; @@ -134,8 +141,8 @@ struct SDL_WaylandInput enum SDL_WaylandAxisEvent y_axis_type; float y; - /* Event timestamp in milliseconds */ - Uint32 timestamp; + /* Event timestamp in nanoseconds */ + Uint64 timestamp_ns; } pointer_curr_axis_info; SDL_WaylandKeyboardRepeat keyboard_repeat; @@ -149,7 +156,7 @@ struct SDL_WaylandInput SDL_bool keyboard_is_virtual; }; -extern Uint64 Wayland_GetEventTimestamp(Uint32 wayland_timestamp); +extern Uint64 Wayland_GetTouchTimestamp(struct SDL_WaylandInput *input, Uint32 wl_timestamp_ms); extern void Wayland_PumpEvents(_THIS); extern void Wayland_SendWakeupEvent(_THIS, SDL_Window *window); @@ -180,6 +187,8 @@ extern int Wayland_input_ungrab_keyboard(SDL_Window *window); extern void Wayland_input_add_tablet(struct SDL_WaylandInput *input, struct SDL_WaylandTabletManager *tablet_manager); extern void Wayland_input_destroy_tablet(struct SDL_WaylandInput *input); +extern void Wayland_RegisterTimestampListeners(struct SDL_WaylandInput *input); + #endif /* SDL_waylandevents_h_ */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/wayland/SDL_waylandtouch.c b/src/video/wayland/SDL_waylandtouch.c index 7f946ed1a..17d17baf9 100644 --- a/src/video/wayland/SDL_waylandtouch.c +++ b/src/video/wayland/SDL_waylandtouch.c @@ -71,6 +71,8 @@ static void touch_handle_touch(void *data, * (src/compositor/wayland_wrapper/qwltouch.cpp) **/ + SDL_VideoData *viddata = (SDL_VideoData *)data; + float FIXED_TO_FLOAT = 1. / 10000.; float xf = FIXED_TO_FLOAT * normalized_x; float yf = FIXED_TO_FLOAT * normalized_y; @@ -105,13 +107,12 @@ static void touch_handle_touch(void *data, switch (touchState) { case QtWaylandTouchPointPressed: case QtWaylandTouchPointReleased: - SDL_SendTouch(Wayland_GetEventTimestamp(time), deviceId, (SDL_FingerID)id, window, - (touchState == QtWaylandTouchPointPressed) ? SDL_TRUE : SDL_FALSE, - xf, yf, pressuref); + SDL_SendTouch(Wayland_GetTouchTimestamp(viddata->input, time), deviceId, (SDL_FingerID)id, + window, (touchState == QtWaylandTouchPointPressed) ? SDL_TRUE : SDL_FALSE, xf, yf, pressuref); break; case QtWaylandTouchPointMoved: - SDL_SendTouchMotion(Wayland_GetEventTimestamp(time), deviceId, (SDL_FingerID)id, window, - xf, yf, pressuref); + SDL_SendTouchMotion(Wayland_GetTouchTimestamp(viddata->input, time), deviceId, (SDL_FingerID)id, + window, xf, yf, pressuref); break; default: /* Should not happen */ diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index 47b909cd8..870a7f17f 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -53,6 +53,7 @@ #include "viewporter-client-protocol.h" #include "primary-selection-unstable-v1-client-protocol.h" #include "fractional-scale-v1-client-protocol.h" +#include "input-timestamps-unstable-v1-client-protocol.h" #ifdef HAVE_LIBDECOR_H #include @@ -849,6 +850,11 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint d->viewporter = wl_registry_bind(d->registry, id, &wp_viewporter_interface, 1); } else if (SDL_strcmp(interface, "wp_fractional_scale_manager_v1") == 0) { d->fractional_scale_manager = wl_registry_bind(d->registry, id, &wp_fractional_scale_manager_v1_interface, 1); + } else if (SDL_strcmp(interface, "zwp_input_timestamps_manager_v1") == 0) { + d->input_timestamps_manager = wl_registry_bind(d->registry, id, &zwp_input_timestamps_manager_v1_interface, 1); + if (d->input) { + Wayland_RegisterTimestampListeners(d->input); + } #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH } else if (SDL_strcmp(interface, "qt_touch_extension") == 0) { Wayland_touch_create(d, id); @@ -1099,6 +1105,11 @@ static void Wayland_VideoCleanup(_THIS) data->fractional_scale_manager = NULL; } + if (data->input_timestamps_manager) { + zwp_input_timestamps_manager_v1_destroy(data->input_timestamps_manager); + data->input_timestamps_manager = NULL; + } + if (data->compositor) { wl_compositor_destroy(data->compositor); data->compositor = NULL; diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h index b8aed7ae9..cae968b8a 100644 --- a/src/video/wayland/SDL_waylandvideo.h +++ b/src/video/wayland/SDL_waylandvideo.h @@ -79,6 +79,7 @@ typedef struct struct zxdg_output_manager_v1 *xdg_output_manager; struct wp_viewporter *viewporter; struct wp_fractional_scale_manager_v1 *fractional_scale_manager; + struct zwp_input_timestamps_manager_v1 *input_timestamps_manager; EGLDisplay edpy; EGLContext context; diff --git a/wayland-protocols/input-timestamps-unstable-v1.xml b/wayland-protocols/input-timestamps-unstable-v1.xml new file mode 100644 index 000000000..7c5e08280 --- /dev/null +++ b/wayland-protocols/input-timestamps-unstable-v1.xml @@ -0,0 +1,145 @@ + + + + + Copyright © 2017 Collabora, Ltd. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol specifies a way for a client to request and receive + high-resolution timestamps for input events. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + + + + + A global interface used for requesting high-resolution timestamps + for input events. + + + + + Informs the server that the client will no longer be using this + protocol object. Existing objects created by this object are not + affected. + + + + + + Creates a new input timestamps object that represents a subscription + to high-resolution timestamp events for all wl_keyboard events that + carry a timestamp. + + If the associated wl_keyboard object is invalidated, either through + client action (e.g. release) or server-side changes, the input + timestamps object becomes inert and the client should destroy it + by calling zwp_input_timestamps_v1.destroy. + + + + + + + + Creates a new input timestamps object that represents a subscription + to high-resolution timestamp events for all wl_pointer events that + carry a timestamp. + + If the associated wl_pointer object is invalidated, either through + client action (e.g. release) or server-side changes, the input + timestamps object becomes inert and the client should destroy it + by calling zwp_input_timestamps_v1.destroy. + + + + + + + + Creates a new input timestamps object that represents a subscription + to high-resolution timestamp events for all wl_touch events that + carry a timestamp. + + If the associated wl_touch object becomes invalid, either through + client action (e.g. release) or server-side changes, the input + timestamps object becomes inert and the client should destroy it + by calling zwp_input_timestamps_v1.destroy. + + + + + + + + + Provides high-resolution timestamp events for a set of subscribed input + events. The set of subscribed input events is determined by the + zwp_input_timestamps_manager_v1 request used to create this object. + + + + + Informs the server that the client will no longer be using this + protocol object. After the server processes the request, no more + timestamp events will be emitted. + + + + + + The timestamp event is associated with the first subsequent input event + carrying a timestamp which belongs to the set of input events this + object is subscribed to. + + The timestamp provided by this event is a high-resolution version of + the timestamp argument of the associated input event. The provided + timestamp is in the same clock domain and is at least as accurate as + the associated input event timestamp. + + The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples, + each component being an unsigned 32-bit value. Whole seconds are in + tv_sec which is a 64-bit value combined from tv_sec_hi and tv_sec_lo, + and the additional fractional part in tv_nsec as nanoseconds. Hence, + for valid timestamps tv_nsec must be in [0, 999999999]. + + + + + + + +