diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index 098d26e1ff..7f0f5f01cf 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -179,7 +179,7 @@ static void Wayland_GetScaledMouseRect(SDL_Window *window, SDL_Rect *scaled_rect scaled_rect->h = (int)SDL_ceil(window->mouse_rect.h / window_data->pointer_scale.y); } -static Uint64 Wayland_GetEventTimestamp(Uint64 nsTimestamp) +static Uint64 Wayland_AdjustEventTimestampBase(Uint64 nsTimestamp) { static Uint64 timestamp_offset = 0; const Uint64 now = SDL_GetTicksNS(); @@ -197,16 +197,9 @@ static Uint64 Wayland_GetEventTimestamp(Uint64 nsTimestamp) return nsTimestamp; } -static void 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 = { - input_timestamp_listener -}; - +/* This should only be called with 32-bit millisecond timestamps received in Wayland events! + * No synthetic or high-res timestamps, as they can corrupt the rollover offset! + */ static Uint64 Wayland_EventTimestampMSToNS(Uint32 wl_timestamp_ms) { static Uint64 timestamp_offset = 0; @@ -222,38 +215,38 @@ static Uint64 Wayland_EventTimestampMSToNS(Uint32 wl_timestamp_ms) return SDL_MS_TO_NS(wl_timestamp_ms) + timestamp_offset; } -static Uint64 Wayland_GetKeyboardTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms) -{ - if (wl_timestamp_ms) { - return Wayland_GetEventTimestamp(seat->keyboard.highres_timestamp_ns ? seat->keyboard.highres_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms)); - } - - return 0; -} +/* Even if high-res timestamps are available, the millisecond timestamps are still processed + * to accumulate the rollover offset if needed later. + */ static Uint64 Wayland_GetKeyboardTimestampRaw(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms) { - return seat->keyboard.highres_timestamp_ns ? seat->keyboard.highres_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms); + const Uint64 adjustedTimestampMS = Wayland_EventTimestampMSToNS(wl_timestamp_ms); + return seat->keyboard.timestamps ? seat->keyboard.highres_timestamp_ns : adjustedTimestampMS; } static Uint64 Wayland_GetPointerTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms) { - if (wl_timestamp_ms) { - return Wayland_GetEventTimestamp(seat->pointer.highres_timestamp_ns ? seat->pointer.highres_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms)); - } - - return 0; + const Uint64 adjustedTimestampMS = Wayland_EventTimestampMSToNS(wl_timestamp_ms); + return Wayland_AdjustEventTimestampBase(seat->pointer.timestamps ? seat->pointer.highres_timestamp_ns : adjustedTimestampMS); } Uint64 Wayland_GetTouchTimestamp(SDL_WaylandSeat *seat, Uint32 wl_timestamp_ms) { - if (wl_timestamp_ms) { - return Wayland_GetEventTimestamp(seat->touch.highres_timestamp_ns ? seat->touch.highres_timestamp_ns : Wayland_EventTimestampMSToNS(wl_timestamp_ms)); - } - - return 0; + const Uint64 adjustedTimestampMS = Wayland_EventTimestampMSToNS(wl_timestamp_ms); + return Wayland_AdjustEventTimestampBase(seat->touch.timestamps ? seat->touch.highres_timestamp_ns : adjustedTimestampMS); } +static void 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 = { + input_timestamp_listener +}; + static void Wayland_SeatRegisterInputTimestampListeners(SDL_WaylandSeat *seat) { if (seat->display->input_timestamps_manager) { @@ -308,7 +301,7 @@ static bool keyboard_repeat_handle(SDL_WaylandKeyboardRepeat *repeat_info, Uint6 while (elapsed >= repeat_info->next_repeat_ns) { if (repeat_info->scancode != SDL_SCANCODE_UNKNOWN) { const Uint64 timestamp = repeat_info->wl_press_time_ns + repeat_info->next_repeat_ns; - SDL_SendKeyboardKeyIgnoreModifiers(Wayland_GetEventTimestamp(timestamp), repeat_info->keyboard_id, repeat_info->key, repeat_info->scancode, true); + SDL_SendKeyboardKeyIgnoreModifiers(Wayland_AdjustEventTimestampBase(timestamp), repeat_info->keyboard_id, repeat_info->key, repeat_info->scancode, true); } if (repeat_info->text[0]) { SDL_SendKeyboardText(repeat_info->text); @@ -574,17 +567,15 @@ void Wayland_PumpEvents(SDL_VideoDevice *_this) } } -static void pointer_handle_motion(void *data, struct wl_pointer *pointer, - uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w) +static void pointer_handle_motion_common(SDL_WaylandSeat *seat, Uint64 nsTimestamp, wl_fixed_t sx_w, wl_fixed_t sy_w) { - SDL_WaylandSeat *seat = data; SDL_WindowData *window_data = seat->pointer.focus; SDL_Window *window = window_data ? window_data->sdlwindow : NULL; if (window_data) { const float sx = (float)(wl_fixed_to_double(sx_w) * window_data->pointer_scale.x); const float sy = (float)(wl_fixed_to_double(sy_w) * window_data->pointer_scale.y); - SDL_SendMouseMotion(Wayland_GetPointerTimestamp(seat, time), window_data->sdlwindow, seat->pointer.sdl_id, false, sx, sy); + SDL_SendMouseMotion(nsTimestamp, window_data->sdlwindow, seat->pointer.sdl_id, false, sx, sy); seat->pointer.last_motion.x = (int)SDL_floorf(sx); seat->pointer.last_motion.y = (int)SDL_floorf(sy); @@ -678,6 +669,13 @@ static void pointer_handle_motion(void *data, struct wl_pointer *pointer, } } +static void pointer_handle_motion(void *data, struct wl_pointer *pointer, + uint32_t time, wl_fixed_t sx_w, wl_fixed_t sy_w) +{ + SDL_WaylandSeat *seat = (SDL_WaylandSeat *)data; + pointer_handle_motion_common(seat, Wayland_GetPointerTimestamp(seat, time), sx_w, sy_w); +} + static void pointer_handle_enter(void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, 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, * FIXME: This causes a movement event with an anomalous timestamp when * the cursor enters the window. */ - pointer_handle_motion(data, pointer, 0, sx_w, sy_w); + pointer_handle_motion_common(seat, 0, sx_w, sy_w); // Update the pointer grab state. Wayland_SeatUpdatePointerGrab(seat); @@ -845,11 +843,10 @@ static bool Wayland_ProcessHitTest(SDL_WaylandSeat *seat, Uint32 serial) } static void pointer_handle_button_common(SDL_WaylandSeat *seat, uint32_t serial, - uint32_t time, uint32_t button, uint32_t state_w) + Uint64 nsTimestamp, uint32_t button, uint32_t state_w) { SDL_WindowData *window = seat->pointer.focus; enum wl_pointer_button_state state = state_w; - Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time); Uint8 sdl_button; const bool down = (state != 0); @@ -913,7 +910,7 @@ static void pointer_handle_button_common(SDL_WaylandSeat *seat, uint32_t serial, } if (!ignore_click) { - SDL_SendMouseButton(timestamp, window->sdlwindow, seat->pointer.sdl_id, sdl_button, down); + SDL_SendMouseButton(nsTimestamp, window->sdlwindow, seat->pointer.sdl_id, sdl_button, down); } } } @@ -922,15 +919,13 @@ static void pointer_handle_button(void *data, struct wl_pointer *pointer, uint32 uint32_t time, uint32_t button, uint32_t state_w) { SDL_WaylandSeat *seat = data; - - pointer_handle_button_common(seat, serial, time, button, state_w); + pointer_handle_button_common(seat, serial, Wayland_GetPointerTimestamp(seat, time), button, state_w); } static void pointer_handle_axis_common_v1(SDL_WaylandSeat *seat, - uint32_t time, uint32_t axis, wl_fixed_t value) + Uint64 nsTimestamp, uint32_t axis, wl_fixed_t value) { SDL_WindowData *window = seat->pointer.focus; - const Uint64 timestamp = Wayland_GetPointerTimestamp(seat, time); const enum wl_pointer_axis a = axis; if (seat->pointer.focus) { @@ -952,7 +947,7 @@ static void pointer_handle_axis_common_v1(SDL_WaylandSeat *seat, x /= WAYLAND_WHEEL_AXIS_UNIT; y /= WAYLAND_WHEEL_AXIS_UNIT; - SDL_SendMouseWheel(timestamp, window->sdlwindow, seat->pointer.sdl_id, x, y, SDL_MOUSEWHEEL_NORMAL); + SDL_SendMouseWheel(nsTimestamp, window->sdlwindow, seat->pointer.sdl_id, x, y, SDL_MOUSEWHEEL_NORMAL); } } @@ -1033,12 +1028,13 @@ static void pointer_handle_axis(void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value) { SDL_WaylandSeat *seat = data; + const Uint64 nsTimestamp = Wayland_GetPointerTimestamp(seat, time); if (wl_seat_get_version(seat->wl_seat) >= WL_POINTER_FRAME_SINCE_VERSION) { - seat->pointer.current_axis_info.timestamp_ns = Wayland_GetPointerTimestamp(seat, time); + seat->pointer.current_axis_info.timestamp_ns = nsTimestamp; pointer_handle_axis_common(seat, AXIS_EVENT_CONTINUOUS, axis, value); } else { - pointer_handle_axis_common_v1(seat, time, axis, value); + pointer_handle_axis_common_v1(seat, nsTimestamp, axis, value); } } @@ -1166,7 +1162,7 @@ static void relative_pointer_handle_relative_motion(void *data, SDL_Mouse *mouse = SDL_GetMouse(); // Relative pointer event times are in microsecond granularity. - const Uint64 timestamp = Wayland_GetEventTimestamp(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo)); + const Uint64 timestamp = Wayland_AdjustEventTimestampBase(SDL_US_TO_NS(((Uint64)time_hi << 32) | (Uint64)time_lo)); double dx; double dy; @@ -2022,7 +2018,7 @@ static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard, const SDL_Scancode scancode = Wayland_GetScancodeForKey(seat, key); Wayland_HandleModifierKeys(seat, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED); - Uint64 timestamp = Wayland_GetKeyboardTimestamp(seat, time); + Uint64 timestamp = Wayland_AdjustEventTimestampBase(timestamp_raw_ns); SDL_SendKeyboardKeyIgnoreModifiers(timestamp, seat->keyboard.sdl_id, key, scancode, state == WL_KEYBOARD_KEY_STATE_PRESSED); @@ -3243,7 +3239,7 @@ static void tablet_tool_handle_frame(void *data, struct zwp_tablet_tool_v2 *tool return; // Not a pen we report on. } - const Uint64 timestamp = Wayland_GetEventTimestamp(Wayland_EventTimestampMSToNS(time)); + const Uint64 timestamp = Wayland_AdjustEventTimestampBase(Wayland_EventTimestampMSToNS(time)); const SDL_PenID instance_id = sdltool->instance_id; SDL_Window *window = sdltool->tool_focus;