• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Return-To-The-Roots / s25client / 22797872430

07 Mar 2026 11:05AM UTC coverage: 50.156% (-0.2%) from 50.327%
22797872430

Pull #1890

github

web-flow
Merge 4597ccbf9 into d2a3730c9
Pull Request #1890: Add support for borderless Windows

155 of 626 new or added lines in 44 files covered. (24.76%)

26 existing lines in 9 files now uncovered.

23041 of 45939 relevant lines covered (50.16%)

44513.07 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

7.69
/extras/videoDrivers/SDL2/VideoSDL2.cpp
1
// Copyright (C) 2005 - 2026 Settlers Freaks (sf-team at siedler25.org)
2
//
3
// SPDX-License-Identifier: GPL-2.0-or-later
4

5
#include "VideoSDL2.h"
6
#include "RTTR_Assert.h"
7
#include "driver/Interface.h"
8
#include "driver/VideoDriverLoaderInterface.h"
9
#include "driver/VideoInterface.h"
10
#include "enum_cast.hpp"
11
#include "helpers/LSANUtils.h"
12
#include "helpers/containerUtils.h"
13
#include "icon.h"
14
#include "openglCfg.hpp"
15
#include <s25util/utf8.h>
16
#include <boost/nowide/iostream.hpp>
17
#include <SDL.h>
18
#include <SDL_hints.h>
19
#include <SDL_video.h>
20
#include <algorithm>
21
#include <memory>
22

23
#ifdef _WIN32
24
#    include <boost/nowide/convert.hpp>
25
#    ifndef WIN32_LEAN_AND_MEAN
26
#        define WIN32_LEAN_AND_MEAN
27
#    endif
28
#    include <windows.h> // Avoid "Windows headers require the default packing option" due to SDL2
29
#    include <SDL_syswm.h>
30
#endif // _WIN32
31
#if RTTR_OGL_GL4ES
32
#    include <gl4esinit.h>
33
#endif
34

35
namespace {
36

37
/// Check that the (SDL) call returns success or print the error
38
/// Can be used in conditions: if(CHECK_SDL(SDL_Foo()))
NEW
39
bool CHECK_SDL(int sdlResult)
×
40
{
NEW
41
    if(sdlResult >= 0)
×
NEW
42
        return true;
×
NEW
43
    VideoSDL2::PrintError();
×
NEW
44
    return false;
×
45
}
46

47
template<typename T>
48
struct SDLMemoryDeleter
49
{
50
    void operator()(T* p) const { SDL_free(p); }
×
51
};
52

53
template<typename T>
54
using SDL_memory = std::unique_ptr<T, SDLMemoryDeleter<T>>;
55

56
void setSpecialKeys(KeyEvent& ke, const SDL_Keymod mod)
×
57
{
58
    ke.ctrl = (mod & KMOD_CTRL);
×
59
    ke.shift = (mod & KMOD_SHIFT);
×
60
    ke.alt = (mod & KMOD_ALT);
×
61
}
×
62
void setSpecialKeys(KeyEvent& ke)
×
63
{
64
    setSpecialKeys(ke, SDL_GetModState());
×
65
}
×
66
} // namespace
67

68
IVideoDriver* CreateVideoInstance(VideoDriverLoaderInterface* CallBack)
1✔
69
{
70
    return new VideoSDL2(CallBack);
1✔
71
}
72

73
void FreeVideoInstance(IVideoDriver* driver)
1✔
74
{
75
    delete driver;
1✔
76
}
1✔
77

78
const char* GetDriverName()
5✔
79
{
80
#if RTTR_OGL_GL4ES
81
    return "(SDL2) OpenGL-ES gl4es via SDL2-Library";
82
#else
83
    return "(SDL2) OpenGL via SDL2-Library";
5✔
84
#endif
85
}
86

87
VideoSDL2::VideoSDL2(VideoDriverLoaderInterface* CallBack) : VideoDriver(CallBack), window(nullptr), context(nullptr) {}
1✔
88

89
VideoSDL2::~VideoSDL2()
2✔
90
{
91
    CleanUp();
1✔
92
}
2✔
93

94
const char* VideoSDL2::GetName() const
2✔
95
{
96
    return GetDriverName();
2✔
97
}
98

99
bool VideoSDL2::Initialize()
1✔
100
{
101
    initialized = false;
1✔
102
    rttr::ScopedLeakDisabler _;
1✔
103
    // Do not emulate mouse events using touch
104
    SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
1✔
105
    if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
1✔
106
    {
NEW
107
        PrintError();
×
108
        return false;
×
109
    }
110

111
    initialized = true;
1✔
112
    return initialized;
1✔
113
}
114

115
void VideoSDL2::CleanUp()
1✔
116
{
117
    if(!initialized)
1✔
118
        return;
×
119

120
    if(context)
1✔
121
        SDL_GL_DeleteContext(context);
×
122
    if(window)
1✔
123
        SDL_DestroyWindow(window);
×
124
    SDL_QuitSubSystem(SDL_INIT_VIDEO);
1✔
125
    SDL_Quit();
1✔
126
    initialized = false;
1✔
127
}
128

129
void VideoSDL2::UpdateCurrentSizes()
×
130
{
131
    int w, h, w2, h2;
132
    SDL_GetWindowSize(window, &w, &h);
×
133
    SDL_GL_GetDrawableSize(window, &w2, &h2);
×
134
    SetNewSize(VideoMode(w, h), Extent(w2, h2));
×
135
}
×
136

NEW
137
static VideoMode getDesktopSize(SDL_Window* window, VideoMode fallback)
×
138
{
NEW
139
    const int display = window ? std::max(0, SDL_GetWindowDisplayIndex(window)) : 0;
×
140
    SDL_DisplayMode dskSize;
NEW
141
    if(CHECK_SDL(SDL_GetDesktopDisplayMode(display, &dskSize)))
×
NEW
142
        return VideoMode(dskSize.w, dskSize.h);
×
NEW
143
    return fallback;
×
144
}
145

NEW
146
bool VideoSDL2::CreateScreen(const std::string& title, const VideoMode size, DisplayMode displayMode)
×
147
{
148
    if(!initialized)
×
149
        return false;
×
150

151
    // GL-Attributes
152
    CHECK_SDL(SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, RTTR_OGL_MAJOR));
×
153
    CHECK_SDL(SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, RTTR_OGL_MINOR));
×
154
    SDL_GLprofile profile;
155
    if(RTTR_OGL_ES || RTTR_OGL_GL4ES)
156
        profile = SDL_GL_CONTEXT_PROFILE_ES;
157
    else if(RTTR_OGL_COMPAT)
158
        profile = SDL_GL_CONTEXT_PROFILE_COMPATIBILITY;
×
159
    else
160
        profile = SDL_GL_CONTEXT_PROFILE_CORE;
161

162
    CHECK_SDL(SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, profile));
×
163

164
    CHECK_SDL(SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8));
×
165
    CHECK_SDL(SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8));
×
166
    CHECK_SDL(SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8));
×
167
    CHECK_SDL(SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1));
×
168

NEW
169
    const int wndPos = SDL_WINDOWPOS_CENTERED;
×
NEW
170
    const unsigned commonFlags = SDL_WINDOW_OPENGL;
×
171
    // TODO: Fix GUI scaling with High DPI support enabled.
172
    // See https://github.com/Return-To-The-Roots/s25client/issues/1621
173
    // commonFlags |= SDL_WINDOW_ALLOW_HIGHDPI;
174

NEW
175
    unsigned windowTypeFlag = 0;
×
NEW
176
    auto requestedSize = size;
×
NEW
177
    if(displayMode == DisplayMode::Fullscreen)
×
178
    {
NEW
179
        windowTypeFlag = SDL_WINDOW_FULLSCREEN;
×
NEW
180
        requestedSize = FindClosestVideoMode(size);
×
NEW
181
    } else if(displayMode == DisplayMode::BorderlessWindow)
×
182
    {
NEW
183
        windowTypeFlag = SDL_WINDOW_BORDERLESS;
×
NEW
184
        requestedSize = getDesktopSize(nullptr, size);
×
NEW
185
    } else if(displayMode.resizeable)
×
NEW
186
        windowTypeFlag = SDL_WINDOW_RESIZABLE;
×
187

NEW
188
    window = SDL_CreateWindow(title.c_str(), wndPos, wndPos, requestedSize.width, requestedSize.height,
×
189
                              commonFlags | windowTypeFlag);
190

191
    if(!window)
×
192
    {
NEW
193
        PrintError();
×
194
        // Fallback to borderless fullscreen if unable to set resolution
NEW
195
        if(displayMode == DisplayMode::Fullscreen)
×
NEW
196
            return CreateScreen(title, size, DisplayMode::BorderlessWindow);
×
197
        // No borderless -> Resizable window as last fallback to at least show something
NEW
198
        if(displayMode == DisplayMode::BorderlessWindow)
×
NEW
199
            return CreateScreen(title, size, DisplayMode::Windowed);
×
NEW
200
        PrintError();
×
UNCOV
201
        return false;
×
202
    }
203

NEW
204
    UpdateCurrentDisplayMode();
×
205
    UpdateCurrentSizes();
×
206

NEW
207
    if(displayMode != DisplayMode::Fullscreen)
×
208
        MoveWindowToCenter();
×
209

210
    SDL_Surface* iconSurf =
211
      SDL_CreateRGBSurfaceFrom(image.data(), 48, 48, 32, 48 * 4, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
×
212
    if(iconSurf)
×
213
    {
214
        SDL_SetWindowIcon(window, iconSurf);
×
215
        SDL_FreeSurface(iconSurf);
×
216
    } else
NEW
217
        PrintError();
×
218

219
    context = SDL_GL_CreateContext(window);
×
220

221
#ifdef _WIN32
222
    SetWindowTextW(GetConsoleWindow(), boost::nowide::widen(title).c_str());
223
#endif
224

225
    std::fill(keyboard.begin(), keyboard.end(), false);
×
226

227
    SDL_ShowCursor(0);
×
228

229
    return true;
×
230
}
231

NEW
232
bool VideoSDL2::ResizeScreen(VideoMode newSize, DisplayMode displayMode)
×
233
{
234
    if(!initialized)
×
235
        return false;
×
236

NEW
237
    bool centerWindow = false;
×
238

NEW
239
    if(displayMode_ != displayMode)
×
240
    {
NEW
241
        if(displayMode_ == DisplayMode::Fullscreen || displayMode == DisplayMode::Fullscreen)
×
242
        {
NEW
243
            if(!CHECK_SDL(
×
NEW
244
                 SDL_SetWindowFullscreen(window, (displayMode == DisplayMode::Fullscreen) ? SDL_WINDOW_FULLSCREEN : 0)))
×
245
            {
NEW
246
                if(displayMode == DisplayMode::Fullscreen)
×
NEW
247
                    displayMode = DisplayMode::BorderlessWindow;
×
248
            }
249
        }
NEW
250
        SDL_SetWindowResizable(window,
×
NEW
251
                               static_cast<SDL_bool>(displayMode == DisplayMode::Windowed && displayMode.resizeable));
×
NEW
252
        SDL_SetWindowBordered(window, static_cast<SDL_bool>(displayMode == DisplayMode::Windowed));
×
253

NEW
254
        UpdateCurrentDisplayMode();
×
NEW
255
        centerWindow = true;
×
256
    }
NEW
257
    if(displayMode_ == DisplayMode::BorderlessWindow)
×
NEW
258
        newSize = getDesktopSize(nullptr, newSize);
×
UNCOV
259
    if(newSize != GetWindowSize())
×
260
    {
NEW
261
        if(displayMode_ == DisplayMode::Fullscreen)
×
262
        {
263
            auto const targetMode = FindClosestVideoMode(newSize);
×
264
            SDL_DisplayMode target;
265
            target.w = targetMode.width;
×
266
            target.h = targetMode.height;
×
NEW
267
            target.format = 0;       // don't care
×
NEW
268
            target.refresh_rate = 0; // don't care
×
NEW
269
            target.driverdata = nullptr;
×
270
            // Explicitly change the window size to avoid a bug with SDL reporting the wrong size until alt+tab
271
            SDL_SetWindowSize(window, target.w, target.h);
×
NEW
272
            if(!CHECK_SDL(SDL_SetWindowDisplayMode(window, &target)))
×
UNCOV
273
                return false;
×
274
        } else
275
        {
276
            SDL_SetWindowSize(window, newSize.width, newSize.height);
×
NEW
277
            centerWindow = true;
×
278
        }
279
        UpdateCurrentSizes();
×
280
    }
NEW
281
    if(centerWindow)
×
NEW
282
        MoveWindowToCenter();
×
283

UNCOV
284
    return true;
×
285
}
286

NEW
287
void VideoSDL2::PrintError()
×
288
{
NEW
289
    PrintError(SDL_GetError());
×
NEW
290
}
×
291

NEW
292
void VideoSDL2::PrintError(const std::string& msg)
×
293
{
294
    boost::nowide::cerr << msg << std::endl;
×
295
}
×
296

297
void VideoSDL2::ShowErrorMessage(const std::string& title, const std::string& message)
×
298
{
299
    // window==nullptr is okay too ("no parent")
300
#ifdef __linux__
301
    // When using window, SDL will try to use a system tool like "zenity" which isn't always installed on every distro
302
    // so rttr will crash. But without a window it will use an x11 backend that should be available on x11 AND wayland
303
    // for compatibility reasons
304
    SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title.c_str(), message.c_str(), nullptr);
×
305
#else
306
    SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title.c_str(), message.c_str(), window);
307
#endif
308
}
×
309

310
void VideoSDL2::HandlePaste()
×
311
{
312
    if(!SDL_HasClipboardText())
×
313
        return;
×
314

315
    SDL_memory<char> text(SDL_GetClipboardText());
×
316
    if(!text || *text == '\0') // empty string indicates error
×
317
        PrintError(text ? SDL_GetError() : "Paste failed.");
×
318

319
    for(const char32_t c : s25util::utf8to32(text.get()))
×
320
        CallBack->Msg_KeyDown(KeyEvent(c));
×
321
}
322

323
void VideoSDL2::DestroyScreen()
×
324
{
325
    CleanUp();
×
326
}
×
327

328
bool VideoSDL2::SwapBuffers()
×
329
{
330
    SDL_GL_SwapWindow(window);
×
331
    return true;
×
332
}
333

334
bool VideoSDL2::MessageLoop()
×
335
{
336
    SDL_Event ev;
337
    while(SDL_PollEvent(&ev))
×
338
    {
339
        switch(ev.type)
×
340
        {
341
            default: break;
×
342

343
            case SDL_QUIT: return false;
×
344
            case SDL_WINDOWEVENT:
×
345
            {
346
                switch(ev.window.event)
×
347
                {
348
                    case SDL_WINDOWEVENT_RESIZED:
×
349
                    {
NEW
350
                        UpdateCurrentDisplayMode();
×
351
                        VideoMode newSize(ev.window.data1, ev.window.data2);
×
352
                        if(newSize != GetWindowSize())
×
353
                        {
354
                            UpdateCurrentSizes();
×
355
                            CallBack->WindowResized();
×
356
                        }
357
                    }
358
                    break;
×
359
                }
360
            }
361
            break;
×
362

363
            case SDL_KEYDOWN:
×
364
            {
365
                KeyEvent ke;
×
366

367
                switch(ev.key.keysym.sym)
×
368
                {
369
                    default:
×
370
                    {
371
                        // Die 12 F-Tasten
372
                        if(ev.key.keysym.sym >= SDLK_F1 && ev.key.keysym.sym <= SDLK_F12)
×
373
                            ke.kt = static_cast<KeyType>(rttr::enum_cast(KeyType::F1) + ev.key.keysym.sym - SDLK_F1);
×
374
                    }
375
                    break;
×
376
                    case SDLK_RETURN: ke.kt = KeyType::Return; break;
×
377
                    case SDLK_SPACE: ke.kt = KeyType::Space; break;
×
378
                    case SDLK_LEFT: ke.kt = KeyType::Left; break;
×
379
                    case SDLK_RIGHT: ke.kt = KeyType::Right; break;
×
380
                    case SDLK_UP: ke.kt = KeyType::Up; break;
×
381
                    case SDLK_DOWN: ke.kt = KeyType::Down; break;
×
382
                    case SDLK_BACKSPACE: ke.kt = KeyType::Backspace; break;
×
383
                    case SDLK_DELETE: ke.kt = KeyType::Delete; break;
×
384
                    case SDLK_LSHIFT:
×
385
                    case SDLK_RSHIFT: ke.kt = KeyType::Shift; break;
×
386
                    case SDLK_TAB: ke.kt = KeyType::Tab; break;
×
387
                    case SDLK_HOME: ke.kt = KeyType::Home; break;
×
388
                    case SDLK_END: ke.kt = KeyType::End; break;
×
389
                    case SDLK_ESCAPE: ke.kt = KeyType::Escape; break;
×
390
                    case SDLK_PRINTSCREEN: ke.kt = KeyType::Print; break;
×
391
                    // case SDLK_BACKQUOTE: ev.key.keysym.scancode = '^'; break;
392
                    case SDLK_v:
×
393
                        if(SDL_GetModState() & KMOD_CTRL)
×
394
                        {
395
                            HandlePaste();
×
396
                            continue;
×
397
                        }
398
                        break;
×
399
                }
400

401
                setSpecialKeys(ke, SDL_Keymod(ev.key.keysym.mod));
×
402

403
                if(ke.kt != KeyType::Invalid)
×
404
                    CallBack->Msg_KeyDown(ke);
×
405
                else if(ke.alt || ke.ctrl)
×
406
                {
407
                    // Handle shortcuts (CTRL+x, ALT+y)
408
                    // but not possible combinations (ALT+0054)
409
                    const SDL_Keycode keycode = ev.key.keysym.sym;
×
410
                    if(keycode >= 'a' && keycode <= 'z')
×
411
                    {
412
                        ke.kt = KeyType::Char;
×
413
                        ke.c = static_cast<char32_t>(keycode);
×
414
                        CallBack->Msg_KeyDown(ke);
×
415
                    }
416
                }
417
            }
418
            break;
×
419
            case SDL_TEXTINPUT:
×
420
            {
421
                const std::u32string text = s25util::utf8to32(ev.text.text);
×
422
                KeyEvent ke(0);
×
423
                setSpecialKeys(ke);
×
424
                for(char32_t c : text)
×
425
                {
426
                    ke.c = c;
×
427
                    CallBack->Msg_KeyDown(ke);
×
428
                }
429
                break;
×
430
            }
431
            case SDL_MOUSEBUTTONDOWN:
×
432
                mouse_xy.pos = getGuiScale().screenToView(Position(ev.button.x, ev.button.y));
×
433

434
                switch(ev.button.button)
×
435
                {
436
                    case SDL_BUTTON_LEFT:
×
437
                        mouse_xy.ldown = true;
×
438
                        CallBack->Msg_LeftDown(mouse_xy);
×
439
                        break;
×
440

441
                    case SDL_BUTTON_RIGHT:
×
442
                        mouse_xy.rdown = true;
×
443
                        CallBack->Msg_RightDown(mouse_xy);
×
444
                        break;
×
445

446
                    case SDL_BUTTON_MIDDLE:
×
447
                        mouse_xy.mdown = true;
×
448
                        CallBack->Msg_MiddleDown(mouse_xy);
×
449
                        break;
×
450
                }
451
                break;
×
452
            case SDL_MOUSEBUTTONUP:
×
453
                mouse_xy.pos = getGuiScale().screenToView(Position(ev.button.x, ev.button.y));
×
454

455
                switch(ev.button.button)
×
456
                {
457
                    case SDL_BUTTON_LEFT:
×
458
                        mouse_xy.ldown = false;
×
459
                        CallBack->Msg_LeftUp(mouse_xy);
×
460
                        break;
×
461

462
                    case SDL_BUTTON_RIGHT:
×
463
                        mouse_xy.rdown = false;
×
464
                        CallBack->Msg_RightUp(mouse_xy);
×
465
                        break;
×
466

467
                    case SDL_BUTTON_MIDDLE:
×
468
                        mouse_xy.mdown = false;
×
469
                        CallBack->Msg_MiddleUp(mouse_xy);
×
470
                        break;
×
471
                }
472
                break;
×
473
            case SDL_MOUSEWHEEL:
×
474
            {
475
                int y = ev.wheel.y;
×
476
                if(ev.wheel.direction == SDL_MOUSEWHEEL_FLIPPED)
×
477
                    y = -y;
×
478
                if(y > 0)
×
479
                    CallBack->Msg_WheelUp(mouse_xy);
×
480
                else if(y < 0)
×
481
                    CallBack->Msg_WheelDown(mouse_xy);
×
482
            }
483
            break;
×
484
            case SDL_MOUSEMOTION:
×
485
            {
486
                const auto newPos = getGuiScale().screenToView(Position(ev.motion.x, ev.motion.y));
×
487
                // Avoid duplicate events especially when warping the mouse
488
                if(newPos != mouse_xy.pos)
×
489
                {
490
                    mouse_xy.pos = newPos;
×
491
                    CallBack->Msg_MouseMove(mouse_xy);
×
492
                }
493
            }
494
            break;
×
495
            case SDL_FINGERDOWN:
×
496
            {
497
                VideoMode wnSize = GetWindowSize();
×
498
                mouse_xy.pos = getGuiScale().screenToView(Position(static_cast<int>(ev.tfinger.x * wnSize.width),
×
499
                                                                   static_cast<int>(ev.tfinger.y * wnSize.height)));
×
500
                mouse_xy.ldown = true;
×
501
                mouse_xy.num_tfingers++;
×
502
                CallBack->Msg_LeftDown(mouse_xy);
×
503
                break;
×
504
            }
505
            case SDL_FINGERUP:
×
506
            {
507
                VideoMode wnSize = GetWindowSize();
×
508
                mouse_xy.pos = getGuiScale().screenToView(Position(static_cast<int>(ev.tfinger.x * wnSize.width),
×
509
                                                                   static_cast<int>(ev.tfinger.y * wnSize.height)));
×
510
                mouse_xy.ldown = false;
×
511
                CallBack->Msg_LeftUp(mouse_xy);
×
512
                mouse_xy.num_tfingers--; // Dirty way to count leftUp as touch event without extra isTouch bool
×
513
                break;
×
514
            }
515
            case SDL_FINGERMOTION:
×
516
            {
517
                VideoMode wnSize = GetWindowSize();
×
518
                const auto newPos = getGuiScale().screenToView(Position(
×
519
                  static_cast<int>(ev.tfinger.x * wnSize.width), static_cast<int>(ev.tfinger.y * wnSize.height)));
×
520

521
                if(newPos != mouse_xy.pos)
×
522
                {
523
                    mouse_xy.pos = newPos;
×
524
                    CallBack->Msg_MouseMove(mouse_xy);
×
525
                }
526
                break;
×
527
            }
528
            case SDL_MULTIGESTURE:
×
529
            {
530
                if(std::fabs(ev.mgesture.dDist) > 0.001)
×
531
                {
532
                    if(ev.mgesture.dDist > 0)
×
533
                        CallBack->Msg_WheelUp(mouse_xy);
×
534
                    else
535
                        CallBack->Msg_WheelDown(mouse_xy);
×
536
                }
537
                break;
×
538
            }
539
        }
540
    }
541

542
    return true;
×
543
}
544

545
unsigned long VideoSDL2::GetTickCount() const
×
546
{
547
    return SDL_GetTicks();
×
548
}
549

NEW
550
std::vector<VideoMode> VideoSDL2::ListVideoModes() const
×
551
{
552
    int display = SDL_GetWindowDisplayIndex(window);
×
553
    if(display < 0)
×
554
        display = 0;
×
NEW
555
    std::vector<VideoMode> video_modes;
×
UNCOV
556
    for(int i = SDL_GetNumDisplayModes(display) - 1; i >= 0; --i)
×
557
    {
558
        SDL_DisplayMode mode;
559
        if(SDL_GetDisplayMode(display, i, &mode) != 0)
×
NEW
560
            PrintError();
×
561
        else
562
        {
563
            VideoMode vm(mode.w, mode.h);
×
564
            if(!helpers::contains(video_modes, vm))
×
565
                video_modes.push_back(vm);
×
566
        }
567
    }
NEW
568
    return video_modes;
×
569
}
570

571
OpenGL_Loader_Proc VideoSDL2::GetLoaderFunction() const
×
572
{
573
#if RTTR_OGL_GL4ES
574
    return gl4es_GetProcAddress;
575
#else
576
    return SDL_GL_GetProcAddress;
×
577
#endif
578
}
579

580
void VideoSDL2::SetMousePos(Position pos)
×
581
{
582
    const auto screenPos = getGuiScale().viewToScreen(pos);
×
583
    mouse_xy.pos = pos;
×
584
    SDL_WarpMouseInWindow(window, screenPos.x, screenPos.y);
×
585
}
×
586

587
KeyEvent VideoSDL2::GetModKeyState() const
×
588
{
589
    KeyEvent ke;
×
590
    setSpecialKeys(ke);
×
591
    return ke;
×
592
}
593

594
void* VideoSDL2::GetMapPointer() const
×
595
{
596
#ifdef WIN32
597
    SDL_SysWMinfo wmInfo;
598
    SDL_VERSION(&wmInfo.version);
599
    SDL_GetWindowWMInfo(window, &wmInfo);
600
    // return (void*)wmInfo.info.win.window;
601
    return (void*)wmInfo.info.win.window;
602
#else
603
    return nullptr;
×
604
#endif
605
}
606

607
void VideoSDL2::MoveWindowToCenter()
×
608
{
NEW
609
    SDL_PumpEvents(); // Let window system run update events/initialization
×
NEW
610
    const int display = window ? std::max(0, SDL_GetWindowDisplayIndex(window)) : 0;
×
611

612
    SDL_Rect usableBounds;
NEW
613
    CHECK_SDL(SDL_GetDisplayUsableBounds(display, &usableBounds));
×
614
    int top, left, bottom, right;
NEW
615
    if(!CHECK_SDL(SDL_GetWindowBordersSize(window, &top, &left, &bottom, &right)))
×
616
        top = left = bottom = right = 0;
×
NEW
617
    auto wndOuterSize = GetWindowSize();
×
NEW
618
    wndOuterSize.width += left + right;
×
NEW
619
    wndOuterSize.height += top + bottom;
×
NEW
620
    if(usableBounds.w < wndOuterSize.width || usableBounds.h < wndOuterSize.height)
×
621
    {
NEW
622
        SDL_SetWindowSize(window, usableBounds.w - left - right, usableBounds.h - top - bottom);
×
623
        UpdateCurrentSizes();
×
NEW
624
        wndOuterSize.width = usableBounds.w;
×
NEW
625
        wndOuterSize.height = usableBounds.h;
×
626
    }
NEW
627
    const int x = usableBounds.x + (usableBounds.w - wndOuterSize.width) / 2 + left;
×
NEW
628
    const int y = usableBounds.y + (usableBounds.h - wndOuterSize.height) / 2 + top;
×
NEW
629
    SDL_SetWindowPosition(window, x, y);
×
NEW
630
}
×
631

NEW
632
void VideoSDL2::UpdateCurrentDisplayMode()
×
633
{
NEW
634
    RTTR_Assert(window);
×
NEW
635
    const auto flags = SDL_GetWindowFlags(window);
×
NEW
636
    if(flags & SDL_WINDOW_FULLSCREEN)
×
NEW
637
        displayMode_ = DisplayMode::Fullscreen;
×
NEW
638
    else if((flags & SDL_WINDOW_BORDERLESS) != 0)
×
NEW
639
        displayMode_ = DisplayMode::BorderlessWindow;
×
640
    else
NEW
641
        displayMode_ = DisplayMode::Windowed;
×
NEW
642
    displayMode_.resizeable = (flags & SDL_WINDOW_RESIZABLE) != 0;
×
UNCOV
643
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc