diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index b38ef441db..e828dc9f69 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -685,8 +685,16 @@ static void pointer_dispatch_absolute_motion(SDL_WaylandSeat *seat) SDL_Window *window = window_data ? window_data->sdlwindow : NULL; if (window_data) { - const float sx = (float)(wl_fixed_to_double(seat->pointer.pending_frame.absolute.sx) * window_data->pointer_scale.x); - const float sy = (float)(wl_fixed_to_double(seat->pointer.pending_frame.absolute.sy) * window_data->pointer_scale.y); + double sx = wl_fixed_to_double(seat->pointer.pending_frame.absolute.sx); + double sy = wl_fixed_to_double(seat->pointer.pending_frame.absolute.sy); + + if (seat->pointer.focus_surface == window_data->mask.surface) { + sx += (double)window_data->mask.offset_x; + sy += (double)window_data->mask.offset_y; + } + + sx *= window_data->pointer_scale.x; + sy *= window_data->pointer_scale.y; SDL_SendMouseMotion(seat->pointer.pending_frame.timestamp_ns, window_data->sdlwindow, seat->pointer.sdl_id, false, sx, sy); seat->pointer.last_motion.x = (int)SDL_floorf(sx); @@ -816,6 +824,7 @@ static void pointer_dispatch_enter(SDL_WaylandSeat *seat) } seat->pointer.focus = window; + seat->pointer.focus_surface = seat->pointer.pending_frame.enter_surface; ++window->pointer_focus_count; SDL_SetMouseFocus(window->sdlwindow); @@ -874,6 +883,7 @@ static void pointer_dispatch_leave(SDL_WaylandSeat *seat, bool update_pointer) window->sdlwindow->flags &= ~SDL_WINDOW_MOUSE_CAPTURE; seat->pointer.focus = NULL; + seat->pointer.focus_surface = NULL; for (Uint8 i = 1; seat->pointer.buttons_pressed; ++i) { if (seat->pointer.buttons_pressed & SDL_BUTTON_MASK(i)) { SDL_SendMouseButton(0, window->sdlwindow, seat->pointer.sdl_id, i, false); @@ -1283,12 +1293,24 @@ static void pointer_handle_frame(void *data, struct wl_pointer *pointer) if (seat->pointer.pending_frame.enter_surface) { if (seat->pointer.pending_frame.leave_surface) { - // Leaving the previous surface before entering a new surface. - pointer_dispatch_leave(seat, false); - seat->pointer.pending_frame.leave_surface = NULL; + SDL_WindowData *window_data = seat->pointer.focus; + SDL_WindowData *new_focus = Wayland_GetWindowDataForOwnedSurface(seat->pointer.pending_frame.enter_surface); + + if (window_data && (window_data->sdlwindow->flags & SDL_WINDOW_MOUSE_CAPTURE) && window_data == new_focus) { + // The mouse is captured and moving between owned window surfaces. Just change the focused surface. + seat->pointer.focus_surface = seat->pointer.pending_frame.enter_surface; + seat->pointer.pending_frame.enter_surface = NULL; + seat->pointer.pending_frame.leave_surface = NULL; + } else { + // Leaving the previous surface before entering a new surface. + pointer_dispatch_leave(seat, false); + seat->pointer.pending_frame.leave_surface = NULL; + } } - pointer_dispatch_enter(seat); + if (seat->pointer.pending_frame.enter_surface) { + pointer_dispatch_enter(seat); + } } if (seat->pointer.pending_frame.have_absolute) { diff --git a/src/video/wayland/SDL_waylandevents_c.h b/src/video/wayland/SDL_waylandevents_c.h index 1a597a35f8..9e3d573b6c 100644 --- a/src/video/wayland/SDL_waylandevents_c.h +++ b/src/video/wayland/SDL_waylandevents_c.h @@ -189,6 +189,7 @@ typedef struct SDL_WaylandSeat struct zwp_pointer_gesture_pinch_v1 *gesture_pinch; SDL_WindowData *focus; + struct wl_surface *focus_surface; // According to the spec, a seat can only have one active gesture of any type at a time. SDL_WindowData *gesture_focus;