Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
cb0f0f8
Enable non-resizable windows (SDL2 only)
falbrechtskirchinger Jul 10, 2023
367cf72
Implement full support for borderless windows
Flamefire Feb 15, 2026
9cb7dc5
Make `CHECK_SDL` a function
Flamefire Feb 15, 2026
e1d32a6
Make setting member naming consistent
Flamefire Feb 21, 2026
54c5272
Disallow comparison of Bitfields
Flamefire Feb 21, 2026
790875a
Allow opening (advanced) ingame settings with F10
Flamefire Feb 22, 2026
0d12cb5
Refactor control creation of dskOptions
Flamefire Feb 22, 2026
0ecdccb
Fix check for GUI scaling support in AUTO mode
Flamefire Feb 25, 2026
8f2261f
Translate docstrings in VideoWinAPI
Flamefire Feb 25, 2026
2ccc33a
Add extra option for locking Window size and make "Borderless Window"…
Flamefire Feb 25, 2026
9819617
Pass `VideoMode` by value
Flamefire Feb 25, 2026
b100f04
Fix parameter name
Flamefire Feb 25, 2026
7161abd
Return vector from `ListVideoModes` instead of output param
Flamefire Feb 26, 2026
82971d4
Add fallback to makeUnique for non-orderable elements
Flamefire Feb 26, 2026
ae61003
Add option to change text of a combobox item
Flamefire Feb 26, 2026
e717b2f
Add adaptive controls for changing window size
Flamefire Feb 26, 2026
328f706
Filter small video modes earlier
Flamefire Feb 26, 2026
1da2910
Add constant for minimum window size
Flamefire Feb 26, 2026
732bb05
Fix WinAPI glitch on first window resize: Window moves to background
Flamefire Feb 26, 2026
352b67c
Fix centering window in SDL2
Flamefire Feb 26, 2026
e10c266
Fix positioning of FPS display for unscaled desktops
Flamefire Feb 26, 2026
66ade2a
Fix misplaced buttons in game interface for very small windows
Flamefire Feb 26, 2026
81d8e73
Explicitly instantiate `Window::Scale`
Flamefire Feb 27, 2026
508cfd8
Translate and update docstrings of Window class
Flamefire Feb 27, 2026
1f32161
Store Window controls as `unique_ptr`
Flamefire Feb 27, 2026
23e1c02
Use CHECK_SDL to check success
Flamefire Apr 19, 2026
e5e96d4
WinAPI: Ensure window is restored when resize failed
Flamefire Apr 19, 2026
801b1fb
Extract constants for lower buttons in dskGameInterface
Flamefire Apr 19, 2026
c334dfa
Add enum for SubmitDebugData
Flamefire Apr 19, 2026
903b36b
Format defaultWindowSizes as list
Flamefire Apr 19, 2026
c1b57d6
Make `VideoMode` sortable and return as `std::set`
Flamefire Apr 19, 2026
0234d44
Sort `VideoMode` by (width,height)-tuple only
Flamefire Apr 19, 2026
24bd636
Add comment on old format
Flamefire Apr 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion data/RTTR/texte/de/keyboardlayout.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ F1:................... (Spiel laden)
F2:................... Spiel speichern
F8:................... Tastaturbelegung anzeigen
F9:................... ReadMe-Datei anzeigen
F10:.................. Einstellungen (UI, ...)
F11:.................. Musik-Spieler
F12:.................. Kontrollfenster

Expand All @@ -47,6 +48,6 @@ P:.................... Pause/Fortsetzen (Auch nach GF Sprung)
1-7:.................. Spielerwechsel

------------------------------------------------------------------------
https://www.siedler25.org Copyright (C) 2005-2022 Settlers Freaks
https://www.siedler25.org Copyright (C) 2005-2026 Settlers Freaks
------------------------------------------------------------------------

3 changes: 2 additions & 1 deletion data/RTTR/texte/keyboardlayout.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ F1:................... (Load game)
F2:................... Save game
F8:................... Readme "Keyboard layout"
F9:................... Readme
F10:.................. Settings (UI, ...)
F11:.................. Musicplayer
F12:.................. Options window

Expand All @@ -46,5 +47,5 @@ J:.................... Go to specific GF
P:.................... Pause/Resume (also after GF jump)
1-7:.................. Change to other player
------------------------------------------------------------------------
https://www.siedler25.org Copyright (C) 2005-2022 Settlers Freaks
https://www.siedler25.org Copyright (C) 2005-2026 Settlers Freaks
------------------------------------------------------------------------
180 changes: 119 additions & 61 deletions extras/videoDrivers/SDL2/VideoSDL2.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// Copyright (C) 2005 - 2025 Settlers Freaks (sf-team at siedler25.org)
// Copyright (C) 2005 - 2026 Settlers Freaks (sf-team at siedler25.org)
//
// SPDX-License-Identifier: GPL-2.0-or-later

#include "VideoSDL2.h"
#include "RTTR_Assert.h"
#include "driver/Interface.h"
#include "driver/VideoDriverLoaderInterface.h"
#include "driver/VideoInterface.h"
Expand Down Expand Up @@ -31,17 +32,18 @@
# include <gl4esinit.h>
#endif

#define CHECK_SDL(call) \
([&]() -> bool { \
if((call) < 0) \
{ \
PrintError(SDL_GetError()); \
return false; \
} \
return true; \
})()

namespace {

/// Check that the (SDL) call returns success or print the error
/// Can be used in conditions: if(CHECK_SDL(SDL_Foo()))
bool CHECK_SDL(int sdlResult)
{
if(sdlResult >= 0)
return true;
VideoSDL2::PrintError();
return false;
}

template<typename T>
struct SDLMemoryDeleter
{
Expand Down Expand Up @@ -100,13 +102,9 @@ bool VideoSDL2::Initialize()
rttr::ScopedLeakDisabler _;
// Do not emulate mouse events using touch
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
{
PrintError(SDL_GetError());
return false;
}
if(CHECK_SDL(SDL_InitSubSystem(SDL_INIT_VIDEO)))
initialized = true;

initialized = true;
return initialized;
}

Expand All @@ -132,7 +130,16 @@ void VideoSDL2::UpdateCurrentSizes()
SetNewSize(VideoMode(w, h), Extent(w2, h2));
}

bool VideoSDL2::CreateScreen(const std::string& title, const VideoMode& size, bool fullscreen)
static VideoMode getDesktopSize(SDL_Window* window, VideoMode fallback)
{
const int display = window ? std::max(0, SDL_GetWindowDisplayIndex(window)) : 0;
SDL_DisplayMode dskSize;
if(CHECK_SDL(SDL_GetDesktopDisplayMode(display, &dskSize)))
return VideoMode(dskSize.w, dskSize.h);
return fallback;
}

bool VideoSDL2::CreateScreen(const std::string& title, const VideoMode size, DisplayMode displayMode)
{
if(!initialized)
return false;
Expand All @@ -155,34 +162,45 @@ bool VideoSDL2::CreateScreen(const std::string& title, const VideoMode& size, bo
CHECK_SDL(SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8));
CHECK_SDL(SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1));

int wndPos = SDL_WINDOWPOS_CENTERED;

const auto requestedSize = fullscreen ? FindClosestVideoMode(size) : size;
unsigned commonFlags = SDL_WINDOW_OPENGL;
const int wndPos = SDL_WINDOWPOS_CENTERED;
const unsigned commonFlags = SDL_WINDOW_OPENGL;
// TODO: Fix GUI scaling with High DPI support enabled.
// See https://github.com/Return-To-The-Roots/s25client/issues/1621
// commonFlags |= SDL_WINDOW_ALLOW_HIGHDPI;

window = SDL_CreateWindow(title.c_str(), wndPos, wndPos, requestedSize.width, requestedSize.height,
commonFlags | (fullscreen ? SDL_WINDOW_FULLSCREEN : SDL_WINDOW_RESIZABLE));

// Fallback to non-fullscreen
if(!window && fullscreen)
unsigned windowTypeFlag = 0;
auto requestedSize = size;
if(displayMode == DisplayMode::Fullscreen)
{
window = SDL_CreateWindow(title.c_str(), wndPos, wndPos, requestedSize.width, requestedSize.height,
commonFlags | SDL_WINDOW_RESIZABLE);
}
windowTypeFlag = SDL_WINDOW_FULLSCREEN;
requestedSize = FindClosestVideoMode(size);
} else if(displayMode == DisplayMode::BorderlessWindow)
{
windowTypeFlag = SDL_WINDOW_BORDERLESS;
requestedSize = getDesktopSize(nullptr, size);
} else if(displayMode.resizeable)
windowTypeFlag = SDL_WINDOW_RESIZABLE;

window = SDL_CreateWindow(title.c_str(), wndPos, wndPos, requestedSize.width, requestedSize.height,
commonFlags | windowTypeFlag);

if(!window)
{
PrintError(SDL_GetError());
PrintError();
// Fallback to borderless fullscreen if unable to set resolution
if(displayMode == DisplayMode::Fullscreen)
return CreateScreen(title, size, DisplayMode::BorderlessWindow);
// No borderless -> Resizable window as last fallback to at least show something
if(displayMode == DisplayMode::BorderlessWindow)
return CreateScreen(title, size, DisplayMode::Windowed);
PrintError();
return false;
}

isFullscreen_ = (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) != 0;
UpdateCurrentDisplayMode();
UpdateCurrentSizes();

if(!isFullscreen_)
if(displayMode != DisplayMode::Fullscreen)
MoveWindowToCenter();

SDL_Surface* iconSurf =
Expand All @@ -192,7 +210,7 @@ bool VideoSDL2::CreateScreen(const std::string& title, const VideoMode& size, bo
SDL_SetWindowIcon(window, iconSurf);
SDL_FreeSurface(iconSurf);
} else
PrintError(SDL_GetError());
PrintError();

context = SDL_GL_CreateContext(window);

Expand All @@ -207,50 +225,67 @@ bool VideoSDL2::CreateScreen(const std::string& title, const VideoMode& size, bo
return true;
}

bool VideoSDL2::ResizeScreen(const VideoMode& newSize, bool fullscreen)
bool VideoSDL2::ResizeScreen(VideoMode newSize, DisplayMode displayMode)
{
if(!initialized)
return false;

if(isFullscreen_ != fullscreen)
bool centerWindow = false;

if(displayMode_ != displayMode)
{
SDL_SetWindowFullscreen(window, fullscreen ? SDL_WINDOW_FULLSCREEN : 0);
isFullscreen_ = (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) != 0;
if(!isFullscreen_)
if(displayMode_ == DisplayMode::Fullscreen || displayMode == DisplayMode::Fullscreen)
{
SDL_SetWindowResizable(window, SDL_TRUE);
MoveWindowToCenter();
if(!CHECK_SDL(
SDL_SetWindowFullscreen(window, (displayMode == DisplayMode::Fullscreen) ? SDL_WINDOW_FULLSCREEN : 0)))
{
if(displayMode == DisplayMode::Fullscreen)
displayMode = DisplayMode::BorderlessWindow;
}
}
}
SDL_SetWindowResizable(window,
static_cast<SDL_bool>(displayMode == DisplayMode::Windowed && displayMode.resizeable));
SDL_SetWindowBordered(window, static_cast<SDL_bool>(displayMode == DisplayMode::Windowed));

UpdateCurrentDisplayMode();
centerWindow = true;
}
if(displayMode_ == DisplayMode::BorderlessWindow)
newSize = getDesktopSize(nullptr, newSize);
if(newSize != GetWindowSize())
{
if(isFullscreen_)
if(displayMode_ == DisplayMode::Fullscreen)
{
auto const targetMode = FindClosestVideoMode(newSize);
SDL_DisplayMode target;
target.w = targetMode.width;
target.h = targetMode.height;
target.format = 0; // don't care
target.refresh_rate = 0; // don't care
target.driverdata = nullptr; // initialize to 0
target.format = 0; // don't care
target.refresh_rate = 0; // don't care
target.driverdata = nullptr;
// Explicitly change the window size to avoid a bug with SDL reporting the wrong size until alt+tab
SDL_SetWindowSize(window, target.w, target.h);
if(SDL_SetWindowDisplayMode(window, &target) < 0)
{
PrintError(SDL_GetError());
if(!CHECK_SDL(SDL_SetWindowDisplayMode(window, &target)))
return false;
}
} else
{
SDL_SetWindowSize(window, newSize.width, newSize.height);
centerWindow = true;
}
UpdateCurrentSizes();
}
if(centerWindow)
MoveWindowToCenter();

return true;
}

void VideoSDL2::PrintError(const std::string& msg) const
void VideoSDL2::PrintError()
{
PrintError(SDL_GetError());
}

void VideoSDL2::PrintError(const std::string& msg)
{
boost::nowide::cerr << msg << std::endl;
}
Expand Down Expand Up @@ -308,7 +343,7 @@ bool VideoSDL2::MessageLoop()
{
case SDL_WINDOWEVENT_RESIZED:
{
isFullscreen_ = (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) != 0;
UpdateCurrentDisplayMode();
VideoMode newSize(ev.window.data1, ev.window.data2);
if(newSize != GetWindowSize())
{
Expand Down Expand Up @@ -508,23 +543,25 @@ unsigned long VideoSDL2::GetTickCount() const
return SDL_GetTicks();
}

void VideoSDL2::ListVideoModes(std::vector<VideoMode>& video_modes) const
std::vector<VideoMode> VideoSDL2::ListVideoModes() const
{
int display = SDL_GetWindowDisplayIndex(window);
if(display < 0)
display = 0;
std::vector<VideoMode> video_modes;
for(int i = SDL_GetNumDisplayModes(display) - 1; i >= 0; --i)
{
SDL_DisplayMode mode;
if(SDL_GetDisplayMode(display, i, &mode) != 0)
PrintError(SDL_GetError());
PrintError();
else
{
VideoMode vm(mode.w, mode.h);
if(!helpers::contains(video_modes, vm))
video_modes.push_back(vm);
}
}
return video_modes;
}

OpenGL_Loader_Proc VideoSDL2::GetLoaderFunction() const
Expand Down Expand Up @@ -565,17 +602,38 @@ void* VideoSDL2::GetMapPointer() const

void VideoSDL2::MoveWindowToCenter()
{
SDL_PumpEvents(); // Let window system run update events/initialization
const int display = window ? std::max(0, SDL_GetWindowDisplayIndex(window)) : 0;

SDL_Rect usableBounds;
CHECK_SDL(SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(window), &usableBounds));
CHECK_SDL(SDL_GetDisplayUsableBounds(display, &usableBounds));
int top, left, bottom, right;
if(CHECK_SDL(SDL_GetWindowBordersSize(window, &top, &left, &bottom, &right)) != 0)
if(!CHECK_SDL(SDL_GetWindowBordersSize(window, &top, &left, &bottom, &right)))
top = left = bottom = right = 0;
usableBounds.w -= left + right;
usableBounds.h -= top + bottom;
if(usableBounds.w < GetWindowSize().width || usableBounds.h < GetWindowSize().height)
auto wndOuterSize = GetWindowSize();
wndOuterSize.width += left + right;
wndOuterSize.height += top + bottom;
if(usableBounds.w < wndOuterSize.width || usableBounds.h < wndOuterSize.height)
{
SDL_SetWindowSize(window, usableBounds.w, usableBounds.h);
SDL_SetWindowSize(window, usableBounds.w - left - right, usableBounds.h - top - bottom);
UpdateCurrentSizes();
wndOuterSize.width = usableBounds.w;
wndOuterSize.height = usableBounds.h;
}
SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
const int x = usableBounds.x + (usableBounds.w - wndOuterSize.width) / 2 + left;
const int y = usableBounds.y + (usableBounds.h - wndOuterSize.height) / 2 + top;
SDL_SetWindowPosition(window, x, y);
}

void VideoSDL2::UpdateCurrentDisplayMode()
{
RTTR_Assert(window);
const auto flags = SDL_GetWindowFlags(window);
if(flags & SDL_WINDOW_FULLSCREEN)
displayMode_ = DisplayMode::Fullscreen;
else if((flags & SDL_WINDOW_BORDERLESS) != 0)
displayMode_ = DisplayMode::BorderlessWindow;
else
displayMode_ = DisplayMode::Windowed;
displayMode_.resizeable = (flags & SDL_WINDOW_RESIZABLE) != 0;
}
15 changes: 9 additions & 6 deletions extras/videoDrivers/SDL2/VideoSDL2.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2005 - 2021 Settlers Freaks (sf-team at siedler25.org)
// Copyright (C) 2005 - 2026 Settlers Freaks (sf-team at siedler25.org)
//
// SPDX-License-Identifier: GPL-2.0-or-later

Expand All @@ -24,8 +24,8 @@ class VideoSDL2 final : public VideoDriver

bool Initialize() override;

bool CreateScreen(const std::string& title, const VideoMode& size, bool fullscreen) override;
bool ResizeScreen(const VideoMode& newSize, bool fullscreen) override;
bool CreateScreen(const std::string& title, VideoMode size, DisplayMode displayMode) override;
bool ResizeScreen(VideoMode newSize, DisplayMode displayMode) override;

void DestroyScreen() override;

Expand All @@ -41,8 +41,8 @@ class VideoSDL2 final : public VideoDriver

OpenGL_Loader_Proc GetLoaderFunction() const override;

/// Add supported video modes
void ListVideoModes(std::vector<VideoMode>& video_modes) const override;
/// Get supported video modes
std::vector<VideoMode> ListVideoModes() const override;

/// Set mouse position
void SetMousePos(Position pos) override;
Expand All @@ -53,11 +53,14 @@ class VideoSDL2 final : public VideoDriver
/// Get (device-dependent!) window pointer, HWND in Windows
void* GetMapPointer() const override;

static void PrintError();
static void PrintError(const std::string& msg);

private:
void PrintError(const std::string& msg) const;
void HandlePaste();
void UpdateCurrentSizes();
void MoveWindowToCenter();
void UpdateCurrentDisplayMode();

SDL_Window* window;
SDL_GLContext context;
Expand Down
Loading
Loading