diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 005ae7406f..1369cef0c5 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -494,6 +494,58 @@ static void FlushFullscreenEvents(SDL_Window *window) } } +/* While we can't get window position from the compositor, we do at least know + * what monitor we're on, so let's send move events that put the window at the + * center of the whatever display the wl_surface_listener events give us. + */ +static void Wayland_move_window(SDL_Window *window) +{ + SDL_WindowData *wind = window->driverdata; + SDL_DisplayData *display = wind->outputs[wind->num_outputs - 1]; + SDL_DisplayID *displays; + + displays = SDL_GetDisplays(NULL); + if (displays) { + for (int i = 0; displays[i]; ++i) { + if (SDL_GetDisplayDriverData(displays[i]) == display) { + /* We want to send a very very specific combination here: + * + * 1. A coordinate that tells the application what display we're on + * 2. Exactly (0, 0) + * + * Part 1 is useful information but is also really important for + * ensuring we end up on the right display for fullscreen, while + * part 2 is important because numerous applications use a specific + * combination of GetWindowPosition and GetGlobalMouseState, and of + * course neither are supported by Wayland. Since global mouse will + * fall back to just GetMouseState, we need the window position to + * be zero so the cursor math works without it going off in some + * random direction. See UE5 Editor for a notable example of this! + * + * This may be an issue some day if we're ever able to implement + * SDL_GetDisplayUsableBounds! + * + * -flibit + */ + + if (wind->last_displayID != displays[i]) { + wind->last_displayID = displays[i]; + if (wind->shell_surface_type != WAYLAND_SURFACE_XDG_POPUP) { + /* Need to catch up on fullscreen state here, as the video core may try to update + * the fullscreen window, which on Wayland involves a set fullscreen call, which + * can overwrite older pending state. + */ + FlushFullscreenEvents(window); + SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, display->x, display->y); + } + } + break; + } + } + SDL_free(displays); + } +} + static void SetFullscreen(SDL_Window *window, struct wl_output *output) { SDL_WindowData *wind = window->driverdata; @@ -567,6 +619,11 @@ static void UpdateWindowFullscreen(SDL_Window *window, SDL_bool fullscreen) SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_LEAVE_FULLSCREEN, 0, 0); SDL_UpdateFullscreenMode(window, SDL_FALSE, SDL_FALSE); wind->fullscreen_was_positioned = SDL_FALSE; + + /* Send a move event, in case it was deferred while the fullscreen window was moving and + * on multiple outputs. + */ + Wayland_move_window(window); } } } @@ -1249,68 +1306,12 @@ static void Wayland_MaybeUpdateScaleFactor(SDL_WindowData *window) Wayland_HandlePreferredScaleChanged(window, factor); } -/* While we can't get window position from the compositor, we do at least know - * what monitor we're on, so let's send move events that put the window at the - * center of the whatever display the wl_surface_listener events give us. - */ -static void Wayland_move_window(SDL_Window *window, SDL_DisplayData *driverdata) -{ - SDL_WindowData *wind = window->driverdata; - SDL_DisplayID *displays; - int i; - - displays = SDL_GetDisplays(NULL); - if (displays) { - for (i = 0; displays[i]; ++i) { - if (SDL_GetDisplayDriverData(displays[i]) == driverdata) { - /* We want to send a very very specific combination here: - * - * 1. A coordinate that tells the application what display we're on - * 2. Exactly (0, 0) - * - * Part 1 is useful information but is also really important for - * ensuring we end up on the right display for fullscreen, while - * part 2 is important because numerous applications use a specific - * combination of GetWindowPosition and GetGlobalMouseState, and of - * course neither are supported by Wayland. Since global mouse will - * fall back to just GetMouseState, we need the window position to - * be zero so the cursor math works without it going off in some - * random direction. See UE5 Editor for a notable example of this! - * - * This may be an issue some day if we're ever able to implement - * SDL_GetDisplayUsableBounds! - * - * -flibit - */ - SDL_Rect bounds; - - wind->last_displayID = displays[i]; - if (wind->shell_surface_type != WAYLAND_SURFACE_XDG_POPUP) { - /* Need to catch up on fullscreen state here, as the video core may try to update - * the fullscreen window, which on Wayland involves a set fullscreen call, which - * can overwrite older pending state. - */ - FlushFullscreenEvents(window); - - SDL_GetDisplayBounds(wind->last_displayID, &bounds); - SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, bounds.x, bounds.y); - } - break; - } - } - SDL_free(displays); - } -} - void Wayland_RemoveOutputFromWindow(SDL_WindowData *window, SDL_DisplayData *display_data) { - SDL_bool send_move_event = SDL_FALSE; - for (int i = 0; i < window->num_outputs; i++) { if (window->outputs[i] == display_data) { /* remove this one */ if (i == (window->num_outputs - 1)) { window->outputs[i] = NULL; - send_move_event = SDL_TRUE; } else { SDL_memmove(&window->outputs[i], &window->outputs[i + 1], @@ -1324,12 +1325,10 @@ void Wayland_RemoveOutputFromWindow(SDL_WindowData *window, SDL_DisplayData *dis if (window->num_outputs == 0) { SDL_free(window->outputs); window->outputs = NULL; - } else if (send_move_event) { - Wayland_move_window(window->sdlwindow, - window->outputs[window->num_outputs - 1]); + } else if (!window->is_fullscreen || window->num_outputs == 1) { + Wayland_move_window(window->sdlwindow); + Wayland_MaybeUpdateScaleFactor(window); } - - Wayland_MaybeUpdateScaleFactor(window); } static void handle_surface_enter(void *data, struct wl_surface *surface, struct wl_output *output) @@ -1351,8 +1350,10 @@ static void handle_surface_enter(void *data, struct wl_surface *surface, struct window->outputs[window->num_outputs++] = driverdata; /* Update the scale factor after the move so that fullscreen outputs are updated. */ - Wayland_move_window(window->sdlwindow, driverdata); - Wayland_MaybeUpdateScaleFactor(window); + if (!window->is_fullscreen || window->num_outputs == 1) { + Wayland_move_window(window->sdlwindow); + Wayland_MaybeUpdateScaleFactor(window); + } } static void handle_surface_leave(void *data, struct wl_surface *surface, struct wl_output *output)