Skip to content

Commit 86e9ffa

Browse files
committed
Add extra option for locking Window size and make "Borderless Window" always fullscreen
"Borderless window" usually means "fake fullscreen" mode. So separate it from the resizable-flag.
1 parent 6ecf437 commit 86e9ffa

10 files changed

Lines changed: 209 additions & 128 deletions

File tree

extras/videoDrivers/SDL2/VideoSDL2.cpp

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,14 @@ void VideoSDL2::UpdateCurrentSizes()
134134
SetNewSize(VideoMode(w, h), Extent(w2, h2));
135135
}
136136

137+
static VideoMode getDesktopSize(VideoMode fallback)
138+
{
139+
SDL_DisplayMode dskSize;
140+
if(CHECK_SDL(SDL_GetDesktopDisplayMode(0, &dskSize)))
141+
return VideoMode(dskSize.w, dskSize.h);
142+
return fallback;
143+
}
144+
137145
bool VideoSDL2::CreateScreen(const std::string& title, const VideoMode& size, DisplayMode displayMode)
138146
{
139147
if(!initialized)
@@ -158,53 +166,44 @@ bool VideoSDL2::CreateScreen(const std::string& title, const VideoMode& size, Di
158166
CHECK_SDL(SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1));
159167

160168
const int wndPos = SDL_WINDOWPOS_CENTERED;
161-
const auto fullscreen = displayMode == DisplayMode::Fullscreen;
162-
const auto requestedSize = fullscreen ? FindClosestVideoMode(size) : size;
163169
const unsigned commonFlags = SDL_WINDOW_OPENGL;
164170
// TODO: Fix GUI scaling with High DPI support enabled.
165171
// See https://github.com/Return-To-The-Roots/s25client/issues/1621
166172
// commonFlags |= SDL_WINDOW_ALLOW_HIGHDPI;
167173

168-
const unsigned windowTypeFlag =
169-
fullscreen ? SDL_WINDOW_FULLSCREEN :
170-
(displayMode == DisplayMode::BorderlessWindow ? SDL_WINDOW_BORDERLESS : SDL_WINDOW_RESIZABLE);
174+
unsigned windowTypeFlag = 0;
175+
auto requestedSize = size;
176+
if(displayMode == DisplayMode::Fullscreen)
177+
{
178+
windowTypeFlag = SDL_WINDOW_FULLSCREEN;
179+
requestedSize = FindClosestVideoMode(size);
180+
} else if(displayMode == DisplayMode::BorderlessWindow)
181+
{
182+
windowTypeFlag = SDL_WINDOW_BORDERLESS;
183+
requestedSize = getDesktopSize(size);
184+
} else if(displayMode.resizeable)
185+
windowTypeFlag = SDL_WINDOW_RESIZABLE;
171186

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

175190
if(!window)
176191
{
177192
PrintError();
178-
// Fallback to borderless fullscreen
179-
if(fullscreen)
180-
{
181-
SDL_DisplayMode dskSize;
182-
if(!CHECK_SDL(SDL_GetDesktopDisplayMode(0, &dskSize)))
183-
{
184-
dskSize.w = size.width;
185-
dskSize.h = size.height;
186-
}
187-
window = SDL_CreateWindow(title.c_str(), wndPos, wndPos, dskSize.w, dskSize.h,
188-
commonFlags | SDL_WINDOW_BORDERLESS);
189-
}
190-
// No borderless -> Resizable
191-
if(!window)
192-
{
193-
window = SDL_CreateWindow(title.c_str(), wndPos, wndPos, size.width, size.height,
194-
commonFlags | SDL_WINDOW_RESIZABLE);
195-
}
196-
}
197-
198-
if(!window)
199-
{
193+
// Fallback to borderless fullscreen if unable to set resolution
194+
if(displayMode == DisplayMode::Fullscreen)
195+
return CreateScreen(title, size, DisplayMode::BorderlessWindow);
196+
// No borderless -> Resizable window as last fallback to at least show something
197+
if(displayMode == DisplayMode::BorderlessWindow)
198+
return CreateScreen(title, size, DisplayMode::Windowed);
200199
PrintError();
201200
return false;
202201
}
203202

204203
UpdateCurrentDisplayMode();
205204
UpdateCurrentSizes();
206205

207-
if(displayMode_ != DisplayMode::Fullscreen)
206+
if(displayMode != DisplayMode::Fullscreen)
208207
MoveWindowToCenter();
209208

210209
SDL_Surface* iconSurf =
@@ -229,7 +228,7 @@ bool VideoSDL2::CreateScreen(const std::string& title, const VideoMode& size, Di
229228
return true;
230229
}
231230

232-
bool VideoSDL2::ResizeScreen(const VideoMode& newSize, DisplayMode displayMode)
231+
bool VideoSDL2::ResizeScreen(const VideoMode& reqSize, DisplayMode displayMode)
233232
{
234233
if(!initialized)
235234
return false;
@@ -245,13 +244,15 @@ bool VideoSDL2::ResizeScreen(const VideoMode& newSize, DisplayMode displayMode)
245244
displayMode = DisplayMode::BorderlessWindow;
246245
}
247246
}
248-
SDL_SetWindowResizable(window, static_cast<SDL_bool>(displayMode == DisplayMode::Windowed));
249-
SDL_SetWindowBordered(window, static_cast<SDL_bool>(displayMode != DisplayMode::BorderlessWindow));
247+
SDL_SetWindowResizable(window,
248+
static_cast<SDL_bool>(displayMode == DisplayMode::Windowed && displayMode.resizeable));
249+
SDL_SetWindowBordered(window, static_cast<SDL_bool>(displayMode == DisplayMode::Windowed));
250250

251251
UpdateCurrentDisplayMode();
252252
if(displayMode_ != DisplayMode::Fullscreen)
253253
MoveWindowToCenter();
254254
}
255+
const VideoMode newSize = displayMode_ == DisplayMode::BorderlessWindow ? getDesktopSize(reqSize) : reqSize;
255256
if(newSize != GetWindowSize())
256257
{
257258
if(displayMode_ == DisplayMode::Fullscreen)
@@ -260,9 +261,9 @@ bool VideoSDL2::ResizeScreen(const VideoMode& newSize, DisplayMode displayMode)
260261
SDL_DisplayMode target;
261262
target.w = targetMode.width;
262263
target.h = targetMode.height;
263-
target.format = 0; // don't care
264-
target.refresh_rate = 0; // don't care
265-
target.driverdata = nullptr; // initialize to 0
264+
target.format = 0; // don't care
265+
target.refresh_rate = 0; // don't care
266+
target.driverdata = nullptr;
266267
// Explicitly change the window size to avoid a bug with SDL reporting the wrong size until alt+tab
267268
SDL_SetWindowSize(window, target.w, target.h);
268269
if(!CHECK_SDL(SDL_SetWindowDisplayMode(window, &target)))
@@ -598,7 +599,7 @@ void VideoSDL2::MoveWindowToCenter()
598599
SDL_Rect usableBounds;
599600
CHECK_SDL(SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(window), &usableBounds));
600601
int top, left, bottom, right;
601-
if(CHECK_SDL(SDL_GetWindowBordersSize(window, &top, &left, &bottom, &right)) != 0)
602+
if(!CHECK_SDL(SDL_GetWindowBordersSize(window, &top, &left, &bottom, &right)))
602603
top = left = bottom = right = 0;
603604
usableBounds.w -= left + right;
604605
usableBounds.h -= top + bottom;
@@ -620,4 +621,5 @@ void VideoSDL2::UpdateCurrentDisplayMode()
620621
displayMode_ = DisplayMode::BorderlessWindow;
621622
else
622623
displayMode_ = DisplayMode::Windowed;
624+
displayMode_.resizeable = (flags & SDL_WINDOW_RESIZABLE) != 0;
623625
}

extras/videoDrivers/WinAPI/WinAPI.cpp

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,12 @@ bool VideoWinAPI::ResizeScreen(const VideoMode& newSize, DisplayMode displayMode
133133
SetWindowLongPtr(screen, GWL_EXSTYLE, exStyle);
134134
displayMode_ = displayMode;
135135

136-
const RECT wRect = CalculateWindowRect(displayMode, windowSize);
136+
const auto [wndArea, adjustedSize] = CalculateWindowRect(displayMode, windowSize);
137137

138-
// Sett size and position
138+
// Set size and position
139139
UINT flags = SWP_SHOWWINDOW | SWP_DRAWFRAME | SWP_FRAMECHANGED;
140-
SetWindowPos(screen, HWND_TOP, wRect.left, wRect.top, wRect.right - wRect.left, wRect.bottom - wRect.top, flags);
141-
SetNewSize(windowSize, Extent(windowSize.width, windowSize.height));
140+
SetWindowPos(screen, HWND_TOP, wndArea.left, wndArea.top, wndArea.getSize().x, wndArea.getSize().y, flags);
141+
SetNewSize(adjustedSize, Extent(adjustedSize.width, adjustedSize.height));
142142

143143
ShowWindow(screen, SW_SHOW);
144144
SetForegroundWindow(screen);
@@ -160,37 +160,49 @@ std::pair<DWORD, DWORD> VideoWinAPI::GetStyleFlags(const DisplayMode mode) const
160160
{
161161
result.first |= WS_OVERLAPPEDWINDOW;
162162
result.second |= WS_EX_WINDOWEDGE;
163+
if(!mode.resizeable)
164+
result.first &= ~WS_THICKFRAME;
163165
}
164166
return result;
165167
}
166168
}
167169

168-
RECT VideoWinAPI::CalculateWindowRect(const DisplayMode mode, VideoMode size) const
170+
std::pair<Rect, VideoMode> VideoWinAPI::CalculateWindowRect(const DisplayMode mode, VideoMode requestedSize) const
169171
{
170-
RECT wRect;
171-
if(mode == DisplayMode::Fullscreen)
172-
{
173-
wRect.left = 0;
174-
wRect.top = 0;
175-
} else
172+
switch(mode.type)
176173
{
177-
RECT workArea;
178-
SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
179-
const unsigned waWidth = workArea.right - workArea.left;
180-
const unsigned waHeight = workArea.bottom - workArea.top;
181-
size.width = std::min<uint16_t>(size.width, waWidth);
182-
size.height = std::min<uint16_t>(size.height, waHeight);
183-
wRect.left = (waWidth - size.width) / 2;
184-
wRect.top = (waHeight - size.height) / 2;
174+
case DisplayMode::Fullscreen:
175+
{
176+
const auto size = FindClosestVideoMode(requestedSize);
177+
return std::make_pair(Rect(Position::all(0), size.width, size.height), size);
178+
};
179+
case DisplayMode::BorderlessWindow:
180+
{
181+
const auto size = getDesktopSize(requestedSize);
182+
return std::make_pair(Rect(Position::all(0), size.width, size.height), size);
183+
}
184+
case DisplayMode::Windowed:
185+
{
186+
RECT workArea;
187+
SystemParametersInfo(SPI_GETWORKAREA, 0, &workArea, 0);
188+
const unsigned waWidth = workArea.right - workArea.left;
189+
const unsigned waHeight = workArea.bottom - workArea.top;
190+
const VideoMode size(std::min<uint16_t>(requestedSize.width, waWidth),
191+
std::min<uint16_t>(requestedSize.height, waHeight));
192+
RECT wRect;
193+
wRect.left = (waWidth - size.width) / 2;
194+
wRect.top = (waHeight - size.height) / 2;
195+
wRect.right = wRect.left + size.width;
196+
wRect.bottom = wRect.top + size.height;
197+
// Calculate real right/bottom based on the window style
198+
const auto [style, exStyle] = GetStyleFlags(mode);
199+
AdjustWindowRectEx(&wRect, style, false, exStyle);
200+
return std::make_pair(Rect(wRect.left, wRect.top, wRect.right - wRect.left, wRect.bottom - wRect.top),
201+
size);
202+
}
185203
}
186-
wRect.right = wRect.left + size.width;
187-
wRect.bottom = wRect.top + size.height;
188204

189-
const auto [style, exStyle] = GetStyleFlags(mode);
190-
// Calculate real right/bottom based on the window style
191-
AdjustWindowRectEx(&wRect, style, false, exStyle);
192-
193-
return wRect;
205+
BOOST_UNREACHABLE_RETURN(std::make_pair(RECT{0, 0, requestedSize.width, requestedSize.height}, requestedSize));
194206
}
195207

196208
bool VideoWinAPI::RegisterAndCreateWindow(const std::string& title, const VideoMode& wndSize, DisplayMode displayMode)
@@ -215,19 +227,16 @@ bool VideoWinAPI::RegisterAndCreateWindow(const std::string& title, const VideoM
215227
return false;
216228

217229
// Create window
218-
const auto reqWindowSize = (displayMode == DisplayMode::Fullscreen) ? FindClosestVideoMode(wndSize) : wndSize;
219-
const RECT wRect = CalculateWindowRect(displayMode, reqWindowSize);
220-
const VideoMode adjWindowSize(static_cast<unsigned short>(wRect.right - wRect.left),
221-
static_cast<unsigned short>(wRect.bottom - wRect.top));
230+
const auto [wndArea, adjustedSize] = CalculateWindowRect(displayMode, wndSize);
222231
const auto [style, exStyle] = GetStyleFlags(displayMode);
223232
screen =
224-
CreateWindowExW(exStyle, windowClassName.c_str(), wTitle.c_str(), style, wRect.left, wRect.top,
225-
adjWindowSize.width, adjWindowSize.height, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
233+
CreateWindowExW(exStyle, windowClassName.c_str(), wTitle.c_str(), style, wndArea.left, wndArea.top,
234+
wndArea.getSize().x, wndArea.getSize().y, nullptr, nullptr, GetModuleHandle(nullptr), nullptr);
226235

227236
if(screen == nullptr)
228237
return false;
229238

230-
SetNewSize(adjWindowSize, Extent(adjWindowSize.width, adjWindowSize.height));
239+
SetNewSize(adjustedSize, Extent(adjustedSize.width, adjustedSize.height));
231240

232241
SetClipboardViewer(screen);
233242

@@ -312,6 +321,24 @@ bool VideoWinAPI::MakeFullscreen(const VideoMode& resolution)
312321
return true;
313322
}
314323

324+
VideoMode VideoWinAPI::getDesktopSize(const VideoMode fallback) const
325+
{
326+
HMONITOR monitor;
327+
if(screen)
328+
monitor = MonitorFromWindow(screen, MONITOR_DEFAULTTONEAREST);
329+
else
330+
monitor = MonitorFromPoint(POINT{0, 0}, MONITOR_DEFAULTTOPRIMARY);
331+
332+
MONITORINFO mi{};
333+
mi.cbSize = sizeof(mi);
334+
if(GetMonitorInfo(monitor, &mi) == TRUE)
335+
{
336+
return VideoMode(static_cast<unsigned short>(mi.rcMonitor.right - mi.rcMonitor.left),
337+
static_cast<unsigned short>(mi.rcMonitor.bottom - mi.rcMonitor.top));
338+
} else
339+
return fallback;
340+
}
341+
315342
void VideoWinAPI::DestroyScreen()
316343
{
317344
EndDialog(screen, 0);

extras/videoDrivers/WinAPI/WinAPI.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#ifndef WIN32_LEAN_AND_MEAN
99
# define WIN32_LEAN_AND_MEAN
1010
#endif
11+
#include "Point.h"
12+
#include "Rect.h"
1113
#include <windows.h>
1214
#include <string>
1315
#include <utility>
@@ -65,11 +67,13 @@ class VideoWinAPI final : public VideoDriver
6567
private:
6668
/// Get style and extended style flags
6769
std::pair<DWORD, DWORD> GetStyleFlags(DisplayMode mode) const;
68-
/// Calculate the rect for the window of the requested size
69-
RECT CalculateWindowRect(DisplayMode mode, VideoMode size) const;
70+
/// Calculate the rect for the window of the requested size at the display mode
71+
/// Returns the final rect (position&size) for the window and the possibly adjusted size of the render region
72+
std::pair<Rect, VideoMode> CalculateWindowRect(DisplayMode mode, VideoMode requestedSize) const;
7073
bool RegisterAndCreateWindow(const std::string& title, const VideoMode& wndSize, DisplayMode displayMode);
7174
bool InitOGL();
7275
static bool MakeFullscreen(const VideoMode& resolution);
76+
VideoMode getDesktopSize(VideoMode fallback) const;
7377

7478
/// Callback for pressed character keys
7579
void OnWMChar(unsigned c, bool disablepaste = false, LPARAM lParam = 0);
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
// Copyright (C) 2005 - 2021 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
#pragma once
66

7-
#define DRIVERAPIVERSION 7
7+
#define DRIVERAPIVERSION 8

libs/driver/include/driver/VideoMode.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,27 @@ struct VideoMode
1616
bool operator!=(const VideoMode& o) const { return !(*this == o); }
1717
};
1818

19-
enum class DisplayMode
19+
// Enum like type with extra flag
20+
struct DisplayMode
2021
{
21-
Windowed,
22-
Fullscreen,
23-
BorderlessWindow,
22+
enum Type
23+
{
24+
Windowed,
25+
Fullscreen,
26+
BorderlessWindow,
27+
} type = Windowed;
28+
bool resizeable = true;
29+
30+
constexpr DisplayMode() = default;
31+
constexpr DisplayMode(Type t) : type(t) {}
32+
constexpr explicit DisplayMode(unsigned t) : type(Type(t)) {}
33+
constexpr bool operator==(const Type& t) const { return type == t; }
34+
constexpr bool operator!=(const Type& t) const { return type != t; }
35+
constexpr bool operator==(const DisplayMode& o) const { return o.type == type && o.resizeable == resizeable; }
36+
constexpr bool operator!=(const DisplayMode& o) const { return !(o == *this); }
2437
};
25-
constexpr auto maxEnumValue(DisplayMode)
38+
39+
constexpr auto maxEnumValue(DisplayMode::Type)
2640
{
2741
return DisplayMode::BorderlessWindow;
2842
}

libs/s25main/Settings.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,13 +244,14 @@ void Settings::Load()
244244
video.fullscreenSize.width = iniVideo->getIntValue("fullscreen_width");
245245
video.fullscreenSize.height = iniVideo->getIntValue("fullscreen_height");
246246
const auto displayMode = iniVideo->getValue("displayMode", -1);
247-
if(displayMode >= 0 && static_cast<unsigned>(displayMode) <= helpers::MaxEnumValue_v<DisplayMode>)
247+
if(displayMode >= 0 && static_cast<unsigned>(displayMode) <= helpers::MaxEnumValue_v<DisplayMode::Type>)
248248
video.displayMode = DisplayMode(displayMode);
249249
else
250250
{
251251
video.displayMode =
252252
iniVideo->getValue("fullscreen", false) ? DisplayMode::Fullscreen : DisplayMode::Windowed;
253253
}
254+
video.displayMode.resizeable = !iniVideo->getValue("lock_window_size", false);
254255
video.framerate = iniVideo->getValue("framerate", 0);
255256
video.vbo = iniVideo->getBoolValue("vbo");
256257
video.sharedTextures = iniVideo->getBoolValue("shared_textures");
@@ -452,7 +453,8 @@ void Settings::Save()
452453
iniVideo->setValue("fullscreen_height", video.fullscreenSize.height);
453454
iniVideo->setValue("windowed_width", video.windowedSize.width);
454455
iniVideo->setValue("windowed_height", video.windowedSize.height);
455-
iniVideo->setValue("displayMode", rttr::enum_cast(video.displayMode));
456+
iniVideo->setValue("displayMode", rttr::enum_cast(video.displayMode.type));
457+
iniVideo->setValue("lock_window_size", !video.displayMode.resizeable);
456458
iniVideo->setValue("framerate", video.framerate);
457459
iniVideo->setValue("vbo", video.vbo);
458460
iniVideo->setValue("shared_textures", video.sharedTextures);

0 commit comments

Comments
 (0)