mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-05-24 22:09:54 +00:00
wayland: Handle captured pointer movements over a subsurface
Some compositors will send pointer enter/leave event while moving between surfaces that are part of the same window while mouse capture is active. Maintain window focus in this case, and adjust the coordinates relative to the content surface by the subsurface offset, if necessary.
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user