diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index d444af0bd0..b16f04529a 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -107,13 +107,14 @@ struct SDL_Window int last_pixel_w, last_pixel_h; Uint32 flags; SDL_bool fullscreen_exclusive; /* The window is currently fullscreen exclusive */ - SDL_bool last_fullscreen_exclusive; /* The last fullscreen_exclusive setting */ + SDL_DisplayID last_fullscreen_exclusive_display; /* The last fullscreen_exclusive display */ SDL_DisplayID last_displayID; /* Stored position and size for windowed mode */ SDL_Rect windowed; - SDL_DisplayMode fullscreen_mode; + SDL_DisplayMode requested_fullscreen_mode; + SDL_DisplayMode current_fullscreen_mode; float opacity; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index e2e2673afa..a1a60a939f 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -1264,7 +1264,7 @@ SDL_DisplayID SDL_GetDisplayForWindow(SDL_Window *window) /* An explicit fullscreen display overrides all */ if (window->flags & SDL_WINDOW_FULLSCREEN) { - displayID = window->fullscreen_mode.displayID; + displayID = window->current_fullscreen_mode.displayID; } if (!displayID && _this->GetDisplayForWindow) { @@ -1311,11 +1311,12 @@ void SDL_CheckWindowDisplayChanged(SDL_Window *window) SDL_VideoDisplay *new_display = &_this->displays[display_index]; /* The window was moved to a different display */ - if (new_display->fullscreen_window != NULL) { - /* Uh oh, there's already a fullscreen window here */ - } else { - new_display->fullscreen_window = window; + if (new_display->fullscreen_window && + new_display->fullscreen_window != window) { + /* Uh oh, there's already a fullscreen window here; minimize it */ + SDL_MinimizeWindow(new_display->fullscreen_window); } + new_display->fullscreen_window = window; display->fullscreen_window = NULL; } } @@ -1343,7 +1344,7 @@ static void SDL_RestoreMousePosition(SDL_Window *window) static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen) { - SDL_VideoDisplay *display; + SDL_VideoDisplay *display = NULL; SDL_DisplayMode *mode = NULL; CHECK_WINDOW_MAGIC(window, -1); @@ -1369,17 +1370,17 @@ static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen) do nothing, or else we may trigger an ugly double-transition */ if (SDL_strcmp(_this->name, "cocoa") == 0) { /* don't do this for X11, etc */ - if (window->is_destroying && !window->last_fullscreen_exclusive) { + if (window->is_destroying && !window->last_fullscreen_exclusive_display) { window->fullscreen_exclusive = SDL_FALSE; goto done; } /* If we're switching between a fullscreen Space and exclusive fullscreen, we need to get back to normal first. */ - if (fullscreen && !window->last_fullscreen_exclusive && window->fullscreen_exclusive) { + if (fullscreen && !window->last_fullscreen_exclusive_display && window->fullscreen_exclusive) { if (!Cocoa_SetWindowFullscreenSpace(window, SDL_FALSE)) { goto error; } - } else if (fullscreen && window->last_fullscreen_exclusive && !window->fullscreen_exclusive) { + } else if (fullscreen && window->last_fullscreen_exclusive_display && !window->fullscreen_exclusive) { display = SDL_GetVideoDisplayForWindow(window); SDL_SetDisplayModeForDisplay(display, NULL); if (_this->SetWindowFullscreen) { @@ -1421,12 +1422,12 @@ static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen) #endif /* Restore the video mode on other displays if needed */ - if (window->last_fullscreen_exclusive) { + if (window->last_fullscreen_exclusive_display) { int i; for (i = 0; i < _this->num_displays; ++i) { SDL_VideoDisplay *other = &_this->displays[i]; - if (display != other && other->fullscreen_window == window) { + if (display != other && other->id == window->last_fullscreen_exclusive_display) { SDL_SetDisplayModeForDisplay(other, NULL); } } @@ -1501,7 +1502,7 @@ static int SDL_UpdateFullscreenMode(SDL_Window *window, SDL_bool fullscreen) } done: - window->last_fullscreen_exclusive = window->fullscreen_exclusive; + window->last_fullscreen_exclusive_display = display && window->fullscreen_exclusive ? display->id : 0; return 0; error: @@ -1523,13 +1524,16 @@ int SDL_SetWindowFullscreenMode(SDL_Window *window, const SDL_DisplayMode *mode) } /* Save the mode so we can look up the closest match later */ - SDL_memcpy(&window->fullscreen_mode, mode, sizeof(window->fullscreen_mode)); + SDL_memcpy(&window->requested_fullscreen_mode, mode, sizeof(window->requested_fullscreen_mode)); } else { - SDL_zero(window->fullscreen_mode); + SDL_zero(window->requested_fullscreen_mode); } - if (SDL_WINDOW_FULLSCREEN_VISIBLE(window)) { - SDL_UpdateFullscreenMode(window, SDL_TRUE); + if (window->flags & SDL_WINDOW_FULLSCREEN) { + SDL_memcpy(&window->current_fullscreen_mode, &window->requested_fullscreen_mode, sizeof(window->current_fullscreen_mode)); + if (SDL_WINDOW_FULLSCREEN_VISIBLE(window)) { + SDL_UpdateFullscreenMode(window, SDL_TRUE); + } } return 0; @@ -1539,7 +1543,11 @@ const SDL_DisplayMode *SDL_GetWindowFullscreenMode(SDL_Window *window) { CHECK_WINDOW_MAGIC(window, NULL); - return SDL_GetFullscreenModeMatch(&window->fullscreen_mode); + if (window->flags & SDL_WINDOW_FULLSCREEN) { + return SDL_GetFullscreenModeMatch(&window->current_fullscreen_mode); + } else { + return SDL_GetFullscreenModeMatch(&window->requested_fullscreen_mode); + } } void *SDL_GetWindowICCProfile(SDL_Window *window, size_t *size) @@ -2613,6 +2621,7 @@ int SDL_RestoreWindow(SDL_Window *window) int SDL_SetWindowFullscreen(SDL_Window *window, SDL_bool fullscreen) { + int ret = 0; Uint32 flags = fullscreen ? SDL_WINDOW_FULLSCREEN : 0; CHECK_WINDOW_MAGIC(window, -1); @@ -2624,7 +2633,19 @@ int SDL_SetWindowFullscreen(SDL_Window *window, SDL_bool fullscreen) /* Clear the previous flags and OR in the new ones */ window->flags = (window->flags & ~SDL_WINDOW_FULLSCREEN) | flags; - return SDL_UpdateFullscreenMode(window, SDL_WINDOW_FULLSCREEN_VISIBLE(window)); + if (fullscreen) { + /* Set the current fullscreen mode to the desired mode */ + SDL_memcpy(&window->current_fullscreen_mode, &window->requested_fullscreen_mode, sizeof(window->current_fullscreen_mode)); + } + + ret = SDL_UpdateFullscreenMode(window, SDL_WINDOW_FULLSCREEN_VISIBLE(window)); + + if (!fullscreen || ret != 0) { + /* Clear the current fullscreen mode. */ + SDL_zero(window->current_fullscreen_mode); + } + + return ret; } static SDL_Surface *SDL_CreateWindowFramebuffer(SDL_Window *window) @@ -2983,30 +3004,21 @@ void SDL_OnWindowHidden(SDL_Window *window) void SDL_OnWindowDisplayChanged(SDL_Window *window) { if (window->flags & SDL_WINDOW_FULLSCREEN) { - SDL_Rect rect; + SDL_DisplayID displayID = SDL_GetDisplayForWindowPosition(window); + const SDL_DisplayMode *new_mode = NULL; - if (SDL_WINDOW_FULLSCREEN_VISIBLE(window) && window->fullscreen_exclusive) { - SDL_UpdateFullscreenMode(window, SDL_TRUE); + if (window->current_fullscreen_mode.pixel_w != 0 || window->current_fullscreen_mode.pixel_h != 0) { + new_mode = SDL_GetClosestFullscreenDisplayMode(displayID, window->current_fullscreen_mode.pixel_w, window->current_fullscreen_mode.pixel_h, window->current_fullscreen_mode.refresh_rate); } - /* - * If mode switching is being emulated, the display bounds don't necessarily reflect the - * emulated mode dimensions since the window is just being scaled. - */ - if (!ModeSwitchingEmulated(_this) && - SDL_GetDisplayBounds(SDL_GetDisplayForWindow(window), &rect) == 0) { - int old_w = window->w; - int old_h = window->h; - window->x = rect.x; - window->y = rect.y; - window->w = rect.w; - window->h = rect.h; - if (_this->SetWindowSize) { - _this->SetWindowSize(_this, window); - } - if (window->w != old_w || window->h != old_h) { - SDL_OnWindowResized(window); - } + if (new_mode) { + SDL_memcpy(&window->current_fullscreen_mode, new_mode, sizeof(window->current_fullscreen_mode)); + } else { + SDL_zero(window->current_fullscreen_mode); + } + + if (SDL_WINDOW_FULLSCREEN_VISIBLE(window)) { + SDL_UpdateFullscreenMode(window, SDL_TRUE); } } diff --git a/src/video/cocoa/SDL_cocoawindow.m b/src/video/cocoa/SDL_cocoawindow.m index 1b7cdd12e5..6cd9af61a6 100644 --- a/src/video/cocoa/SDL_cocoawindow.m +++ b/src/video/cocoa/SDL_cocoawindow.m @@ -570,7 +570,7 @@ static void Cocoa_UpdateClipCursor(SDL_Window *window) return NO; /* Spaces are forcibly disabled. */ } else if (state && window->fullscreen_exclusive) { return NO; /* we only allow you to make a Space on fullscreen desktop windows. */ - } else if (!state && window->last_fullscreen_exclusive) { + } else if (!state && window->last_fullscreen_exclusive_display) { return NO; /* we only handle leaving the Space on windows that were previously fullscreen desktop. */ } else if (state == isFullscreenSpace) { return YES; /* already there. */ diff --git a/src/video/kmsdrm/SDL_kmsdrmvulkan.c b/src/video/kmsdrm/SDL_kmsdrmvulkan.c index 889e72c548..da524de4c4 100644 --- a/src/video/kmsdrm/SDL_kmsdrmvulkan.c +++ b/src/video/kmsdrm/SDL_kmsdrmvulkan.c @@ -371,7 +371,7 @@ SDL_bool KMSDRM_Vulkan_CreateSurface(_THIS, new_mode_parameters.visibleRegion.height = window->h; /* SDL (and DRM, if we look at drmModeModeInfo vrefresh) uses plain integer Hz for display mode refresh rate, but Vulkan expects higher precision. */ - new_mode_parameters.refreshRate = window->fullscreen_mode.refresh_rate * 1000; + new_mode_parameters.refreshRate = window->current_fullscreen_mode.refresh_rate * 1000; SDL_zero(display_mode_create_info); display_mode_create_info.sType = VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR; diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c index 18038061b5..d706303053 100644 --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -957,10 +957,10 @@ static int Wayland_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, SDL_Rect * if (display->fullscreen_window && display->fullscreen_window->fullscreen_exclusive && display->fullscreen_window == SDL_GetFocusWindow() && - display->fullscreen_window->fullscreen_mode.screen_w != 0 && - display->fullscreen_window->fullscreen_mode.screen_h != 0) { - rect->w = display->fullscreen_window->fullscreen_mode.screen_w; - rect->h = display->fullscreen_window->fullscreen_mode.screen_h; + display->fullscreen_window->current_fullscreen_mode.screen_w != 0 && + display->fullscreen_window->current_fullscreen_mode.screen_h != 0) { + rect->w = display->fullscreen_window->current_fullscreen_mode.screen_w; + rect->h = display->fullscreen_window->current_fullscreen_mode.screen_h; } else { rect->w = display->current_mode->screen_w; rect->h = display->current_mode->screen_h; diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 1b98e7c8f8..f77feb7ecd 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -56,7 +56,7 @@ SDL_FORCE_INLINE SDL_bool FloatEqual(float a, float b) static SDL_bool SurfaceScaleIsFractional(SDL_Window *window) { SDL_WindowData *data = window->driverdata; - const float scale_value = !(window->fullscreen_exclusive) ? data->windowed_scale_factor : window->fullscreen_mode.display_scale; + const float scale_value = !(window->fullscreen_exclusive) ? data->windowed_scale_factor : window->current_fullscreen_mode.display_scale; return !FloatEqual(SDL_roundf(scale_value), scale_value); } @@ -77,7 +77,7 @@ static SDL_bool WindowNeedsViewport(SDL_Window *window) if (SurfaceScaleIsFractional(window)) { return SDL_TRUE; } else if (window->fullscreen_exclusive) { - if (window->fullscreen_mode.screen_w != output_width || window->fullscreen_mode.screen_h != output_height) { + if (window->current_fullscreen_mode.screen_w != output_width || window->current_fullscreen_mode.screen_h != output_height) { return SDL_TRUE; } } @@ -93,8 +93,8 @@ static void GetBufferSize(SDL_Window *window, int *width, int *height) int buf_height; if (window->fullscreen_exclusive) { - buf_width = window->fullscreen_mode.pixel_w; - buf_height = window->fullscreen_mode.pixel_h; + buf_width = window->current_fullscreen_mode.pixel_w; + buf_height = window->current_fullscreen_mode.pixel_h; } else { /* Round fractional backbuffer sizes halfway away from zero. */ buf_width = (int)SDL_lroundf((float)data->requested_window_width * data->windowed_scale_factor); @@ -160,8 +160,8 @@ static void ConfigureWindowGeometry(SDL_Window *window) /* If the compositor supplied fullscreen dimensions, use them, otherwise fall back to the display dimensions. */ const int output_width = data->requested_window_width ? data->requested_window_width : output->screen_width; const int output_height = data->requested_window_height ? data->requested_window_height : output->screen_height; - window_width = window->fullscreen_mode.screen_w; - window_height = window->fullscreen_mode.screen_h; + window_width = window->current_fullscreen_mode.screen_w; + window_height = window->current_fullscreen_mode.screen_h; window_size_changed = window_width != window->w || window_height != window->h || data->wl_window_width != output_width || data->wl_window_height != output_height; @@ -178,10 +178,10 @@ static void ConfigureWindowGeometry(SDL_Window *window) } else { /* Always use the mode dimensions for integer scaling. */ UnsetDrawSurfaceViewport(window); - wl_surface_set_buffer_scale(data->surface, (int32_t)window->fullscreen_mode.display_scale); + wl_surface_set_buffer_scale(data->surface, (int32_t)window->current_fullscreen_mode.display_scale); - data->wl_window_width = window->fullscreen_mode.screen_w; - data->wl_window_height = window->fullscreen_mode.screen_h; + data->wl_window_width = window->current_fullscreen_mode.screen_w; + data->wl_window_height = window->current_fullscreen_mode.screen_h; } data->pointer_scale_x = (float)window_width / (float)data->wl_window_width; @@ -554,7 +554,7 @@ static void handle_configure_xdg_toplevel(void *data, * place the fullscreen window is unknown. */ if (window->fullscreen_exclusive && !wind->fullscreen_was_positioned) { - SDL_VideoDisplay *disp = SDL_GetVideoDisplay(window->fullscreen_mode.displayID); + SDL_VideoDisplay *disp = SDL_GetVideoDisplay(window->current_fullscreen_mode.displayID); if (disp) { wind->fullscreen_was_positioned = SDL_TRUE; xdg_toplevel_set_fullscreen(xdg_toplevel, disp->driverdata->output); @@ -768,7 +768,7 @@ static void decoration_frame_configure(struct libdecor_frame *frame, * place the fullscreen window is unknown. */ if (window->fullscreen_exclusive && !wind->fullscreen_was_positioned) { - SDL_VideoDisplay *disp = SDL_GetVideoDisplay(window->fullscreen_mode.displayID); + SDL_VideoDisplay *disp = SDL_GetVideoDisplay(window->current_fullscreen_mode.displayID); if (disp) { wind->fullscreen_was_positioned = SDL_TRUE; libdecor_frame_set_fullscreen(frame, disp->driverdata->output);