1- // Copyright (C) 2005 - 2025 Settlers Freaks (sf-team at siedler25.org)
1+ // Copyright (C) 2005 - 2026 Settlers Freaks (sf-team at siedler25.org)
22//
33// SPDX-License-Identifier: GPL-2.0-or-later
44
55#include " VideoSDL2.h"
6+ #include " RTTR_Assert.h"
67#include " driver/Interface.h"
78#include " driver/VideoDriverLoaderInterface.h"
89#include " driver/VideoInterface.h"
3132# include < gl4esinit.h>
3233#endif
3334
34- #define CHECK_SDL (call ) \
35- ([&]() -> bool { \
36- if ((call) < 0 ) \
37- { \
38- PrintError (SDL_GetError ()); \
39- return false ; \
40- } \
41- return true ; \
42- })()
43-
4435namespace {
36+
37+ // / Check that the (SDL) call returns success or print the error
38+ // / Can be used in conditions: if(CHECK_SDL(SDL_Foo()))
39+ bool CHECK_SDL (int sdlResult)
40+ {
41+ if (sdlResult >= 0 )
42+ return true ;
43+ VideoSDL2::PrintError ();
44+ return false ;
45+ }
46+
4547template <typename T>
4648struct SDLMemoryDeleter
4749{
@@ -100,13 +102,9 @@ bool VideoSDL2::Initialize()
100102 rttr::ScopedLeakDisabler _;
101103 // Do not emulate mouse events using touch
102104 SDL_SetHint (SDL_HINT_TOUCH_MOUSE_EVENTS , " 0" );
103- if (SDL_InitSubSystem (SDL_INIT_VIDEO ) < 0 )
104- {
105- PrintError (SDL_GetError ());
106- return false ;
107- }
105+ if (CHECK_SDL (SDL_InitSubSystem (SDL_INIT_VIDEO )))
106+ initialized = true ;
108107
109- initialized = true ;
110108 return initialized;
111109}
112110
@@ -132,7 +130,16 @@ void VideoSDL2::UpdateCurrentSizes()
132130 SetNewSize (VideoMode (w, h), Extent (w2, h2));
133131}
134132
135- bool VideoSDL2::CreateScreen (const std::string& title, const VideoMode& size, bool fullscreen)
133+ static VideoMode getDesktopSize (SDL_Window* window, VideoMode fallback)
134+ {
135+ const int display = window ? std::max (0 , SDL_GetWindowDisplayIndex (window)) : 0 ;
136+ SDL_DisplayMode dskSize;
137+ if (CHECK_SDL (SDL_GetDesktopDisplayMode (display, &dskSize)))
138+ return VideoMode (dskSize.w , dskSize.h );
139+ return fallback;
140+ }
141+
142+ bool VideoSDL2::CreateScreen (const std::string& title, const VideoMode size, DisplayMode displayMode)
136143{
137144 if (!initialized)
138145 return false ;
@@ -155,34 +162,45 @@ bool VideoSDL2::CreateScreen(const std::string& title, const VideoMode& size, bo
155162 CHECK_SDL (SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE , 8 ));
156163 CHECK_SDL (SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER , 1 ));
157164
158- int wndPos = SDL_WINDOWPOS_CENTERED ;
159-
160- const auto requestedSize = fullscreen ? FindClosestVideoMode (size) : size;
161- unsigned commonFlags = SDL_WINDOW_OPENGL ;
165+ const int wndPos = SDL_WINDOWPOS_CENTERED ;
166+ const unsigned commonFlags = SDL_WINDOW_OPENGL ;
162167 // TODO: Fix GUI scaling with High DPI support enabled.
163168 // See https://github.com/Return-To-The-Roots/s25client/issues/1621
164169 // commonFlags |= SDL_WINDOW_ALLOW_HIGHDPI;
165170
166- window = SDL_CreateWindow (title.c_str (), wndPos, wndPos, requestedSize.width , requestedSize.height ,
167- commonFlags | (fullscreen ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE ));
168-
169- // Fallback to non-fullscreen
170- if (!window && fullscreen)
171+ unsigned windowTypeFlag = 0 ;
172+ auto requestedSize = size;
173+ if (displayMode == DisplayMode::Fullscreen)
171174 {
172- window = SDL_CreateWindow (title.c_str (), wndPos, wndPos, requestedSize.width , requestedSize.height ,
173- commonFlags | SDL_WINDOW_RESIZABLE );
174- }
175+ windowTypeFlag = SDL_WINDOW_FULLSCREEN ;
176+ requestedSize = FindClosestVideoMode (size);
177+ } else if (displayMode == DisplayMode::BorderlessWindow)
178+ {
179+ windowTypeFlag = SDL_WINDOW_BORDERLESS ;
180+ requestedSize = getDesktopSize (nullptr , size);
181+ } else if (displayMode.resizeable )
182+ windowTypeFlag = SDL_WINDOW_RESIZABLE ;
183+
184+ window = SDL_CreateWindow (title.c_str (), wndPos, wndPos, requestedSize.width , requestedSize.height ,
185+ commonFlags | windowTypeFlag);
175186
176187 if (!window)
177188 {
178- PrintError (SDL_GetError ());
189+ PrintError ();
190+ // Fallback to borderless fullscreen if unable to set resolution
191+ if (displayMode == DisplayMode::Fullscreen)
192+ return CreateScreen (title, size, DisplayMode::BorderlessWindow);
193+ // No borderless -> Resizable window as last fallback to at least show something
194+ if (displayMode == DisplayMode::BorderlessWindow)
195+ return CreateScreen (title, size, DisplayMode::Windowed);
196+ PrintError ();
179197 return false ;
180198 }
181199
182- isFullscreen_ = ( SDL_GetWindowFlags (window) & SDL_WINDOW_FULLSCREEN ) != 0 ;
200+ UpdateCurrentDisplayMode () ;
183201 UpdateCurrentSizes ();
184202
185- if (!isFullscreen_ )
203+ if (displayMode != DisplayMode::Fullscreen )
186204 MoveWindowToCenter ();
187205
188206 SDL_Surface* iconSurf =
@@ -192,7 +210,7 @@ bool VideoSDL2::CreateScreen(const std::string& title, const VideoMode& size, bo
192210 SDL_SetWindowIcon (window, iconSurf);
193211 SDL_FreeSurface (iconSurf);
194212 } else
195- PrintError (SDL_GetError () );
213+ PrintError ();
196214
197215 context = SDL_GL_CreateContext (window);
198216
@@ -207,50 +225,67 @@ bool VideoSDL2::CreateScreen(const std::string& title, const VideoMode& size, bo
207225 return true ;
208226}
209227
210- bool VideoSDL2::ResizeScreen (const VideoMode& newSize, bool fullscreen )
228+ bool VideoSDL2::ResizeScreen (VideoMode newSize, DisplayMode displayMode )
211229{
212230 if (!initialized)
213231 return false ;
214232
215- if (isFullscreen_ != fullscreen)
233+ bool centerWindow = false ;
234+
235+ if (displayMode_ != displayMode)
216236 {
217- SDL_SetWindowFullscreen (window, fullscreen ? SDL_WINDOW_FULLSCREEN : 0 );
218- isFullscreen_ = (SDL_GetWindowFlags (window) & SDL_WINDOW_FULLSCREEN ) != 0 ;
219- if (!isFullscreen_)
237+ if (displayMode_ == DisplayMode::Fullscreen || displayMode == DisplayMode::Fullscreen)
220238 {
221- SDL_SetWindowResizable (window, SDL_TRUE );
222- MoveWindowToCenter ();
239+ if (!CHECK_SDL (
240+ SDL_SetWindowFullscreen (window, (displayMode == DisplayMode::Fullscreen) ? SDL_WINDOW_FULLSCREEN : 0 )))
241+ {
242+ if (displayMode == DisplayMode::Fullscreen)
243+ displayMode = DisplayMode::BorderlessWindow;
244+ }
223245 }
224- }
246+ SDL_SetWindowResizable (window,
247+ static_cast <SDL_bool>(displayMode == DisplayMode::Windowed && displayMode.resizeable ));
248+ SDL_SetWindowBordered (window, static_cast <SDL_bool>(displayMode == DisplayMode::Windowed));
225249
250+ UpdateCurrentDisplayMode ();
251+ centerWindow = true ;
252+ }
253+ if (displayMode_ == DisplayMode::BorderlessWindow)
254+ newSize = getDesktopSize (nullptr , newSize);
226255 if (newSize != GetWindowSize ())
227256 {
228- if (isFullscreen_ )
257+ if (displayMode_ == DisplayMode::Fullscreen )
229258 {
230259 auto const targetMode = FindClosestVideoMode (newSize);
231260 SDL_DisplayMode target;
232261 target.w = targetMode.width ;
233262 target.h = targetMode.height ;
234- target.format = 0 ; // don't care
235- target.refresh_rate = 0 ; // don't care
236- target.driverdata = nullptr ; // initialize to 0
263+ target.format = 0 ; // don't care
264+ target.refresh_rate = 0 ; // don't care
265+ target.driverdata = nullptr ;
237266 // Explicitly change the window size to avoid a bug with SDL reporting the wrong size until alt+tab
238267 SDL_SetWindowSize (window, target.w , target.h );
239- if (SDL_SetWindowDisplayMode (window, &target) < 0 )
240- {
241- PrintError (SDL_GetError ());
268+ if (!CHECK_SDL (SDL_SetWindowDisplayMode (window, &target)))
242269 return false ;
243- }
244270 } else
245271 {
246272 SDL_SetWindowSize (window, newSize.width , newSize.height );
273+ centerWindow = true ;
247274 }
248275 UpdateCurrentSizes ();
249276 }
277+ if (centerWindow)
278+ MoveWindowToCenter ();
279+
250280 return true ;
251281}
252282
253- void VideoSDL2::PrintError (const std::string& msg) const
283+ void VideoSDL2::PrintError ()
284+ {
285+ PrintError (SDL_GetError ());
286+ }
287+
288+ void VideoSDL2::PrintError (const std::string& msg)
254289{
255290 boost::nowide::cerr << msg << std::endl;
256291}
@@ -308,7 +343,7 @@ bool VideoSDL2::MessageLoop()
308343 {
309344 case SDL_WINDOWEVENT_RESIZED :
310345 {
311- isFullscreen_ = ( SDL_GetWindowFlags (window) & SDL_WINDOW_FULLSCREEN ) != 0 ;
346+ UpdateCurrentDisplayMode () ;
312347 VideoMode newSize (ev.window .data1 , ev.window .data2 );
313348 if (newSize != GetWindowSize ())
314349 {
@@ -508,23 +543,25 @@ unsigned long VideoSDL2::GetTickCount() const
508543 return SDL_GetTicks ();
509544}
510545
511- void VideoSDL2::ListVideoModes ( std::vector<VideoMode>& video_modes ) const
546+ std::vector<VideoMode> VideoSDL2::ListVideoModes ( ) const
512547{
513548 int display = SDL_GetWindowDisplayIndex (window);
514549 if (display < 0 )
515550 display = 0 ;
551+ std::vector<VideoMode> video_modes;
516552 for (int i = SDL_GetNumDisplayModes (display) - 1 ; i >= 0 ; --i)
517553 {
518554 SDL_DisplayMode mode;
519555 if (SDL_GetDisplayMode (display, i, &mode) != 0 )
520- PrintError (SDL_GetError () );
556+ PrintError ();
521557 else
522558 {
523559 VideoMode vm (mode.w , mode.h );
524560 if (!helpers::contains (video_modes, vm))
525561 video_modes.push_back (vm);
526562 }
527563 }
564+ return video_modes;
528565}
529566
530567OpenGL_Loader_Proc VideoSDL2::GetLoaderFunction () const
@@ -565,17 +602,38 @@ void* VideoSDL2::GetMapPointer() const
565602
566603void VideoSDL2::MoveWindowToCenter ()
567604{
605+ SDL_PumpEvents (); // Let window system run update events/initialization
606+ const int display = window ? std::max (0 , SDL_GetWindowDisplayIndex (window)) : 0 ;
607+
568608 SDL_Rect usableBounds;
569- CHECK_SDL (SDL_GetDisplayUsableBounds (SDL_GetWindowDisplayIndex (window) , &usableBounds));
609+ CHECK_SDL (SDL_GetDisplayUsableBounds (display , &usableBounds));
570610 int top, left, bottom, right;
571- if (CHECK_SDL (SDL_GetWindowBordersSize (window, &top, &left, &bottom, &right)) != 0 )
611+ if (! CHECK_SDL (SDL_GetWindowBordersSize (window, &top, &left, &bottom, &right)))
572612 top = left = bottom = right = 0 ;
573- usableBounds.w -= left + right;
574- usableBounds.h -= top + bottom;
575- if (usableBounds.w < GetWindowSize ().width || usableBounds.h < GetWindowSize ().height )
613+ auto wndOuterSize = GetWindowSize ();
614+ wndOuterSize.width += left + right;
615+ wndOuterSize.height += top + bottom;
616+ if (usableBounds.w < wndOuterSize.width || usableBounds.h < wndOuterSize.height )
576617 {
577- SDL_SetWindowSize (window, usableBounds.w , usableBounds.h );
618+ SDL_SetWindowSize (window, usableBounds.w - left - right , usableBounds.h - top - bottom );
578619 UpdateCurrentSizes ();
620+ wndOuterSize.width = usableBounds.w ;
621+ wndOuterSize.height = usableBounds.h ;
579622 }
580- SDL_SetWindowPosition (window, SDL_WINDOWPOS_CENTERED , SDL_WINDOWPOS_CENTERED );
623+ const int x = usableBounds.x + (usableBounds.w - wndOuterSize.width ) / 2 + left;
624+ const int y = usableBounds.y + (usableBounds.h - wndOuterSize.height ) / 2 + top;
625+ SDL_SetWindowPosition (window, x, y);
626+ }
627+
628+ void VideoSDL2::UpdateCurrentDisplayMode ()
629+ {
630+ RTTR_Assert (window);
631+ const auto flags = SDL_GetWindowFlags (window);
632+ if (flags & SDL_WINDOW_FULLSCREEN )
633+ displayMode_ = DisplayMode::Fullscreen;
634+ else if ((flags & SDL_WINDOW_BORDERLESS ) != 0 )
635+ displayMode_ = DisplayMode::BorderlessWindow;
636+ else
637+ displayMode_ = DisplayMode::Windowed;
638+ displayMode_.resizeable = (flags & SDL_WINDOW_RESIZABLE ) != 0 ;
581639}
0 commit comments