Skip to content

Commit a1332d7

Browse files
committed
wayland: Cleanup timestamp handling
Better handle some very rare, but possible edge cases if the system has been running for many days.
1 parent b5ed0d0 commit a1332d7

File tree

1 file changed

+44
-48
lines changed

1 file changed

+44
-48
lines changed

src/video/wayland/SDL_waylandevents.c

+44-48
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ static void Wayland_GetScaledMouseRect(SDL_Window *window, SDL_Rect *scaled_rect
179179
scaled_rect->h = (int)SDL_ceil(window->mouse_rect.h / window_data->pointer_scale.y);
180180
}
181181

182-
static Uint64 Wayland_GetEventTimestamp(Uint64 nsTimestamp)
182+
static Uint64 Wayland_AdjustEventTimestampBase(Uint64 nsTimestamp)
183183
{
184184
static Uint64 timestamp_offset = 0;
185185
const Uint64 now = SDL_GetTicksNS();
@@ -197,16 +197,9 @@ static Uint64 Wayland_GetEventTimestamp(Uint64 nsTimestamp)
197197
return nsTimestamp;
198198
}
199199

200-
static void input_timestamp_listener(void *data, struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1,
201-
uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec)
202-
{
203-
*((Uint64 *)data) = ((((Uint64)tv_sec_hi << 32) | (Uint64)tv_sec_lo) * SDL_NS_PER_SECOND) + tv_nsec;
204-
}
205-
206-
static const struct zwp_input_timestamps_v1_listener timestamp_listener = {
207-
input_timestamp_listener
208-
};
209-
200+
/* This should only be called with 32-bit millisecond timestamps received in Wayland events!
201+
* No synthetic or high-res timestamps, as they can corrupt the rollover offset!
202+
*/
210203
static Uint64 Wayland_EventTimestampMSToNS(Uint32 wl_timestamp_ms)
211204
{
212205
static Uint64 timestamp_offset = 0;
@@ -222,38 +215,38 @@ static Uint64 Wayland_EventTimestampMSToNS(Uint32 wl_timestamp_ms)
222215
return SDL_MS_TO_NS(wl_timestamp_ms) + timestamp_offset;
223216
}
224217

225-
static Uint64 Wayland_GetKeyboardTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
226-
{
227-
if (wl_timestamp_ms) {
228-
return Wayland_GetEventTimestamp(seat->keyboard.highres_timestamp_ns ? seat->keyboard.highres_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms));
229-
}
230-
231-
return 0;
232-
}
218+
/* Even if high-res timestamps are available, the millisecond timestamps are still processed
219+
* to accumulate the rollover offset if needed later.
220+
*/
233221

234222
static Uint64 Wayland_GetKeyboardTimestampRaw(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
235223
{
236-
return seat->keyboard.highres_timestamp_ns ? seat->keyboard.highres_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms);
224+
const Uint64 adjustedTimestampMS = Wayland_EventTimestampMSToNS(wl_timestamp_ms);
225+
return seat->keyboard.timestamps ? seat->keyboard.highres_timestamp_ns : adjustedTimestampMS;
237226
}
238227

239228
static Uint64 Wayland_GetPointerTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
240229
{
241-
if (wl_timestamp_ms) {
242-
return Wayland_GetEventTimestamp(seat->pointer.highres_timestamp_ns ? seat->pointer.highres_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms));
243-
}
244-
245-
return 0;
230+
const Uint64 adjustedTimestampMS = Wayland_EventTimestampMSToNS(wl_timestamp_ms);
231+
return Wayland_AdjustEventTimestampBase(seat->pointer.timestamps ? seat->pointer.highres_timestamp_ns : adjustedTimestampMS);
246232
}
247233

248234
Uint64 Wayland_GetTouchTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms)
249235
{
250-
if (wl_timestamp_ms) {
251-
return Wayland_GetEventTimestamp(seat->touch.highres_timestamp_ns ? seat->touch.highres_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms));
252-
}
236+
const Uint64 adjustedTimestampMS = Wayland_EventTimestampMSToNS(wl_timestamp_ms);
237+
return Wayland_AdjustEventTimestampBase(seat->touch.timestamps ? seat->touch.highres_timestamp_ns : adjustedTimestampMS);
238+
}
253239

254-
return 0;
240+
static void input_timestamp_listener(void *data, struct zwp_input_timestamps_v1 *zwp_input_timestamps_v1,
241+
uint32_t tv_sec_hi, uint32_t tv_sec_lo, uint32_t tv_nsec)
242+
{
243+
*((Uint64 *)data) = ((((Uint64)tv_sec_hi << 32) | (Uint64)tv_sec_lo) * SDL_NS_PER_SECOND) + tv_nsec;
255244
}
256245

246+
static const struct zwp_input_timestamps_v1_listener timestamp_listener = {
247+
input_timestamp_listener
248+
};
249+
257250
static void Wayland_SeatRegisterInputTimestampListeners(SDL_WaylandSeat *seat)
258251
{
259252
if (seat->display->input_timestamps_manager) {
@@ -308,7 +301,7 @@ static bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint6
308301
while (elapsed >= repeat_info->next_repeat_ns) {
309302
if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) {
310303
const Uint64 timestamp = repeat_info->wl_press_time_ns + repeat_info->next_repeat_ns;
311-
SDL_SendKeyboardKeyIgnoreModifiers(Wayland_GetEventTimestamp(timestamp), repeat_info->keyboard_id, repeat_info->key, repeat_info->scancode, true);
304+
SDL_SendKeyboardKeyIgnoreModifiers(Wayland_AdjustEventTimestampBase(timestamp), repeat_info->keyboard_id, repeat_info->key, repeat_info->scancode, true);
312305
}
313306
if (repeat_info->text[0]) {
314307
SDL_SendKeyboardText(repeat_info->text);
@@ -574,17 +567,15 @@ void Wayland_PumpEvents(SDL_VideoDevice *_this)
574567
}
575568
}
576569

577-
static void pointer_handle_motion(void *data, struct wl_pointer *pointer,
578-
uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
570+
static void pointer_handle_motion_common(SDL_WaylandSeat *seat, Uint64 nsTimestamp, wl_fixed_t sx_w, wl_fixed_t sy_w)
579571
{
580-
SDL_WaylandSeat *seat = data;
581572
SDL_WindowData *window_data = seat->pointer.focus;
582573
SDL_Window *window = window_data ? window_data->sdlwindow : NULL;
583574

584575
if (window_data) {
585576
const float sx = (float)(wl_fixed_to_double(sx_w) * window_data->pointer_scale.x);
586577
const float sy = (float)(wl_fixed_to_double(sy_w) * window_data->pointer_scale.y);
587-
SDL_SendMouseMotion(Wayland_GetPointerTimestamp(seat, time), window_data->sdlwindow, seat->pointer.sdl_id, false, sx, sy);
578+
SDL_SendMouseMotion(nsTimestamp, window_data->sdlwindow, seat->pointer.sdl_id, false, sx, sy);
588579

589580
seat->pointer.last_motion.x = (int)SDL_floorf(sx);
590581
seat->pointer.last_motion.y = (int)SDL_floorf(sy);
@@ -678,6 +669,13 @@ static void pointer_handle_motion(void *data, struct wl_pointer *pointer,
678669
}
679670
}
680671

672+
static void pointer_handle_motion(void *data, struct wl_pointer *pointer,
673+
uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w)
674+
{
675+
SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data;
676+
pointer_handle_motion_common(seat, Wayland_GetPointerTimestamp(seat, time), sx_w, sy_w);
677+
}
678+
681679
static void pointer_handle_enter(void *data, struct wl_pointer *pointer,
682680
uint32_t serial, struct wl_surface *surface,
683681
wl_fixed_t sx_w, wl_fixed_t sy_w)
@@ -706,7 +704,7 @@ static void pointer_handle_enter(void *data, struct wl_pointer *pointer,
706704
* FIXME: This causes a movement event with an anomalous timestamp when
707705
* the cursor enters the window.
708706
*/
709-
pointer_handle_motion(data, pointer, 0, sx_w, sy_w);
707+
pointer_handle_motion_common(seat, 0, sx_w, sy_w);
710708

711709
// Update the pointer grab state.
712710
Wayland_SeatUpdatePointerGrab(seat);
@@ -845,11 +843,10 @@ static bool Wayland_ProcessHitTest(SDL_WaylandSeat *seat, Uint32 serial)
845843
}
846844

847845
static void pointer_handle_button_common(SDL_WaylandSeat *seat, uint32_t serial,
848-
uint32_t time, uint32_t button, uint32_t state_w)
846+
Uint64 nsTimestamp, uint32_t button, uint32_t state_w)
849847
{
850848
SDL_WindowData *window = seat->pointer.focus;
851849
enum wl_pointer_button_state state = state_w;
852-
Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time);
853850
Uint8 sdl_button;
854851
const bool down = (state != 0);
855852

@@ -913,7 +910,7 @@ static void pointer_handle_button_common(SDL_WaylandSeat *seat, uint32_t serial,
913910
}
914911

915912
if (!ignore_click) {
916-
SDL_SendMouseButton(timestamp, window->sdlwindow, seat->pointer.sdl_id, sdl_button, down);
913+
SDL_SendMouseButton(nsTimestamp, window->sdlwindow, seat->pointer.sdl_id, sdl_button, down);
917914
}
918915
}
919916
}
@@ -922,15 +919,13 @@ static void pointer_handle_button(void *data, struct wl_pointer *pointer, uint32
922919
uint32_t time, uint32_t button, uint32_t state_w)
923920
{
924921
SDL_WaylandSeat *seat = data;
925-
926-
pointer_handle_button_common(seat, serial, time, button, state_w);
922+
pointer_handle_button_common(seat, serial, Wayland_GetPointerTimestamp(seat, time), button, state_w);
927923
}
928924

929925
static void pointer_handle_axis_common_v1(SDL_WaylandSeat *seat,
930-
uint32_t time, uint32_t axis, wl_fixed_t value)
926+
Uint64 nsTimestamp, uint32_t axis, wl_fixed_t value)
931927
{
932928
SDL_WindowData *window = seat->pointer.focus;
933-
const Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time);
934929
const enum wl_pointer_axis a = axis;
935930

936931
if (seat->pointer.focus) {
@@ -952,7 +947,7 @@ static void pointer_handle_axis_common_v1(SDL_WaylandSeat *seat,
952947
x /= WAYLAND_WHEEL_AXIS_UNIT;
953948
y /= WAYLAND_WHEEL_AXIS_UNIT;
954949

955-
SDL_SendMouseWheel(timestamp, window->sdlwindow, seat->pointer.sdl_id, x, y, SDL_MOUSEWHEEL_NORMAL);
950+
SDL_SendMouseWheel(nsTimestamp, window->sdlwindow, seat->pointer.sdl_id, x, y, SDL_MOUSEWHEEL_NORMAL);
956951
}
957952
}
958953

@@ -1033,12 +1028,13 @@ static void pointer_handle_axis(void *data, struct wl_pointer *pointer,
10331028
uint32_t time, uint32_t axis, wl_fixed_t value)
10341029
{
10351030
SDL_WaylandSeat *seat = data;
1031+
const Uint64 nsTimestamp = Wayland_GetPointerTimestamp(seat, time);
10361032

10371033
if (wl_seat_get_version(seat->wl_seat) >= WL_POINTER_FRAME_SINCE_VERSION) {
1038-
seat->pointer.current_axis_info.timestamp_ns = Wayland_GetPointerTimestamp(seat, time);
1034+
seat->pointer.current_axis_info.timestamp_ns = nsTimestamp;
10391035
pointer_handle_axis_common(seat, AXIS_EVENT_CONTINUOUS, axis, value);
10401036
} else {
1041-
pointer_handle_axis_common_v1(seat, time, axis, value);
1037+
pointer_handle_axis_common_v1(seat, nsTimestamp, axis, value);
10421038
}
10431039
}
10441040

@@ -1166,7 +1162,7 @@ static void relative_pointer_handle_relative_motion(void *data,
11661162
SDL_Mouse *mouse = SDL_GetMouse();
11671163

11681164
// Relative pointer event times are in microsecond granularity.
1169-
const Uint64 timestamp = Wayland_GetEventTimestamp(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo));
1165+
const Uint64 timestamp = Wayland_AdjustEventTimestampBase(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo));
11701166

11711167
double dx;
11721168
double dy;
@@ -2022,7 +2018,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
20222018

20232019
const SDL_Scancode scancode = Wayland_GetScancodeForKey(seat, key);
20242020
Wayland_HandleModifierKeys(seat, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
2025-
Uint64 timestamp = Wayland_GetKeyboardTimestamp(seat, time);
2021+
Uint64 timestamp = Wayland_AdjustEventTimestampBase(timestamp_raw_ns);
20262022

20272023
SDL_SendKeyboardKeyIgnoreModifiers(timestamp, seat->keyboard.sdl_id, key, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED);
20282024

@@ -3243,7 +3239,7 @@ static void tablet_tool_handle_frame(void *data, struct zwp_tablet_tool_v2 *tool
32433239
return; // Not a pen we report on.
32443240
}
32453241

3246-
const Uint64 timestamp = Wayland_GetEventTimestamp(Wayland_EventTimestampMSToNS(time));
3242+
const Uint64 timestamp = Wayland_AdjustEventTimestampBase(Wayland_EventTimestampMSToNS(time));
32473243
const SDL_PenID instance_id = sdltool->instance_id;
32483244
SDL_Window *window = sdltool->tool_focus;
32493245

0 commit comments

Comments
 (0)