video: Add a hint to disable auto mode switching if an exclusive fullscreen window moves between displays

The existing behavior helps clients that don't expect exclusive fullscreen windows to move by maintaining a consistent size and mode, however, some are aware that this can occur and want to handle mode selection themselves.

Add a hint to disable auto mode switching when an exclusive fullscreen window moves to accommodate this use case, and don't override fullscreen changes that may occur in an event watcher between the display changed event being posted and SDL running the display changed handler, as the mode switch may have already been handled there by the client.
This commit is contained in:
Frank Praznik
2025-03-14 11:50:25 -04:00
parent 58f6e9c278
commit 0bfe0497f3
4 changed files with 36 additions and 4 deletions

View File

@@ -188,6 +188,7 @@ bool SDL_SendWindowEvent(SDL_Window *window, SDL_EventType windowevent, int data
if (data1 == 0 || (SDL_DisplayID)data1 == window->last_displayID) {
return false;
}
window->update_fullscreen_on_display_changed = true;
window->last_displayID = (SDL_DisplayID)data1;
break;
case SDL_EVENT_WINDOW_OCCLUDED:

View File

@@ -103,6 +103,7 @@ struct SDL_Window
bool restore_on_show; // Child was hidden recursively by the parent, restore when shown.
bool last_position_pending; // This should NOT be cleared by the backend, as it is used for fullscreen positioning.
bool last_size_pending; // This should be cleared by the backend if the new size cannot be applied.
bool update_fullscreen_on_display_changed;
bool is_destroying;
bool is_dropping; // drag/drop in progress, expecting SDL_SendDropComplete().

View File

@@ -1854,6 +1854,7 @@ bool SDL_UpdateFullscreenMode(SDL_Window *window, SDL_FullscreenOp fullscreen, b
CHECK_WINDOW_MAGIC(window, false);
window->fullscreen_exclusive = false;
window->update_fullscreen_on_display_changed = false;
// If we are in the process of hiding don't go back to fullscreen
if (window->is_destroying || window->is_hiding) {
@@ -3940,16 +3941,26 @@ void SDL_OnWindowHidden(SDL_Window *window)
void SDL_OnWindowDisplayChanged(SDL_Window *window)
{
if (window->flags & SDL_WINDOW_FULLSCREEN) {
SDL_DisplayID displayID = SDL_GetDisplayForWindowPosition(window);
// Don't run this if a fullscreen change was made in an event watcher callback in response to a display changed event.
if (window->update_fullscreen_on_display_changed && (window->flags & SDL_WINDOW_FULLSCREEN)) {
const bool auto_mode_switch = SDL_GetHintBoolean(SDL_HINT_VIDEO_MATCH_EXCLUSIVE_MODE_ON_MOVE, true);
if (window->requested_fullscreen_mode.w != 0 || window->requested_fullscreen_mode.h != 0) {
if (auto_mode_switch && (window->requested_fullscreen_mode.w != 0 || window->requested_fullscreen_mode.h != 0)) {
SDL_DisplayID displayID = SDL_GetDisplayForWindowPosition(window);
bool include_high_density_modes = false;
if (window->requested_fullscreen_mode.pixel_density > 1.0f) {
include_high_density_modes = true;
}
SDL_GetClosestFullscreenDisplayMode(displayID, window->requested_fullscreen_mode.w, window->requested_fullscreen_mode.h, window->requested_fullscreen_mode.refresh_rate, include_high_density_modes, &window->current_fullscreen_mode);
const bool found_match = SDL_GetClosestFullscreenDisplayMode(displayID, window->requested_fullscreen_mode.w, window->requested_fullscreen_mode.h,
window->requested_fullscreen_mode.refresh_rate, include_high_density_modes, &window->current_fullscreen_mode);
// If a mode without matching dimensions was not found, just go to fullscreen desktop.
if (!found_match ||
window->requested_fullscreen_mode.w != window->current_fullscreen_mode.w ||
window->requested_fullscreen_mode.h != window->current_fullscreen_mode.h) {
SDL_zero(window->current_fullscreen_mode);
}
} else {
SDL_zero(window->current_fullscreen_mode);
}