summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/video/windows/SDL_windowsvideo.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/SDL-3.2.8/src/video/windows/SDL_windowsvideo.c')
-rw-r--r--contrib/SDL-3.2.8/src/video/windows/SDL_windowsvideo.c773
1 files changed, 773 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/video/windows/SDL_windowsvideo.c b/contrib/SDL-3.2.8/src/video/windows/SDL_windowsvideo.c
new file mode 100644
index 0000000..04415b5
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/video/windows/SDL_windowsvideo.c
@@ -0,0 +1,773 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20*/
21#include "SDL_internal.h"
22
23#ifdef SDL_VIDEO_DRIVER_WINDOWS
24
25#ifdef SDL_VIDEO_VULKAN
26#include "../SDL_vulkan_internal.h"
27#endif
28#include "../SDL_sysvideo.h"
29#include "../SDL_pixels_c.h"
30#include "../../SDL_hints_c.h"
31#include "../../core/windows/SDL_hid.h"
32
33#include "SDL_windowsvideo.h"
34#include "SDL_windowsframebuffer.h"
35#include "SDL_windowsmessagebox.h"
36#include "SDL_windowsrawinput.h"
37#include "SDL_windowsvulkan.h"
38
39#ifdef SDL_GDK_TEXTINPUT
40#include "../gdk/SDL_gdktextinput.h"
41#endif
42
43// #define HIGHDPI_DEBUG
44
45// Initialization/Query functions
46static bool WIN_VideoInit(SDL_VideoDevice *_this);
47static void WIN_VideoQuit(SDL_VideoDevice *_this);
48
49// Hints
50bool g_WindowsEnableMessageLoop = true;
51bool g_WindowsEnableMenuMnemonics = false;
52bool g_WindowFrameUsableWhileCursorHidden = true;
53
54static void SDLCALL UpdateWindowsRawKeyboard(void *userdata, const char *name, const char *oldValue, const char *newValue)
55{
56 SDL_VideoDevice *_this = (SDL_VideoDevice *)userdata;
57 bool enabled = SDL_GetStringBoolean(newValue, false);
58 WIN_SetRawKeyboardEnabled(_this, enabled);
59}
60
61static void SDLCALL UpdateWindowsEnableMessageLoop(void *userdata, const char *name, const char *oldValue, const char *newValue)
62{
63 g_WindowsEnableMessageLoop = SDL_GetStringBoolean(newValue, true);
64}
65
66static void SDLCALL UpdateWindowsEnableMenuMnemonics(void *userdata, const char *name, const char *oldValue, const char *newValue)
67{
68 g_WindowsEnableMenuMnemonics = SDL_GetStringBoolean(newValue, false);
69}
70
71static void SDLCALL UpdateWindowFrameUsableWhileCursorHidden(void *userdata, const char *name, const char *oldValue, const char *newValue)
72{
73 g_WindowFrameUsableWhileCursorHidden = SDL_GetStringBoolean(newValue, true);
74}
75
76#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
77static bool WIN_SuspendScreenSaver(SDL_VideoDevice *_this)
78{
79 DWORD result;
80 if (_this->suspend_screensaver) {
81 result = SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED);
82 } else {
83 result = SetThreadExecutionState(ES_CONTINUOUS);
84 }
85 if (result == 0) {
86 SDL_SetError("SetThreadExecutionState() failed");
87 return false;
88 }
89 return true;
90}
91#endif
92
93#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
94extern void D3D12_XBOX_GetResolution(Uint32 *width, Uint32 *height);
95#endif
96
97// Windows driver bootstrap functions
98
99static void WIN_DeleteDevice(SDL_VideoDevice *device)
100{
101 SDL_VideoData *data = device->internal;
102
103 SDL_UnregisterApp();
104#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
105 if (data->userDLL) {
106 SDL_UnloadObject(data->userDLL);
107 }
108 if (data->shcoreDLL) {
109 SDL_UnloadObject(data->shcoreDLL);
110 }
111#endif
112#ifdef HAVE_DXGI_H
113 if (data->pDXGIFactory) {
114 IDXGIFactory_Release(data->pDXGIFactory);
115 }
116 if (data->dxgiDLL) {
117 SDL_UnloadObject(data->dxgiDLL);
118 }
119#endif
120 if (device->wakeup_lock) {
121 SDL_DestroyMutex(device->wakeup_lock);
122 }
123 SDL_free(device->internal->rawinput);
124 SDL_free(device->internal);
125 SDL_free(device);
126}
127
128static SDL_VideoDevice *WIN_CreateDevice(void)
129{
130 SDL_VideoDevice *device;
131 SDL_VideoData *data;
132
133 SDL_RegisterApp(NULL, 0, NULL);
134
135 // Initialize all variables that we clean on shutdown
136 device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
137 if (device) {
138 data = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData));
139 } else {
140 data = NULL;
141 }
142 if (!data) {
143 SDL_UnregisterApp();
144 SDL_free(device);
145 return NULL;
146 }
147 device->internal = data;
148 device->wakeup_lock = SDL_CreateMutex();
149 device->system_theme = WIN_GetSystemTheme();
150
151#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
152 data->userDLL = SDL_LoadObject("USER32.DLL");
153 if (data->userDLL) {
154 /* *INDENT-OFF* */ // clang-format off
155 data->CloseTouchInputHandle = (BOOL (WINAPI *)(HTOUCHINPUT))SDL_LoadFunction(data->userDLL, "CloseTouchInputHandle");
156 data->GetTouchInputInfo = (BOOL (WINAPI *)(HTOUCHINPUT, UINT, PTOUCHINPUT, int)) SDL_LoadFunction(data->userDLL, "GetTouchInputInfo");
157 data->RegisterTouchWindow = (BOOL (WINAPI *)(HWND, ULONG))SDL_LoadFunction(data->userDLL, "RegisterTouchWindow");
158 data->SetProcessDPIAware = (BOOL (WINAPI *)(void))SDL_LoadFunction(data->userDLL, "SetProcessDPIAware");
159 data->SetProcessDpiAwarenessContext = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "SetProcessDpiAwarenessContext");
160 data->SetThreadDpiAwarenessContext = (DPI_AWARENESS_CONTEXT (WINAPI *)(DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "SetThreadDpiAwarenessContext");
161 data->GetThreadDpiAwarenessContext = (DPI_AWARENESS_CONTEXT (WINAPI *)(void))SDL_LoadFunction(data->userDLL, "GetThreadDpiAwarenessContext");
162 data->GetAwarenessFromDpiAwarenessContext = (DPI_AWARENESS (WINAPI *)(DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "GetAwarenessFromDpiAwarenessContext");
163 data->EnableNonClientDpiScaling = (BOOL (WINAPI *)(HWND))SDL_LoadFunction(data->userDLL, "EnableNonClientDpiScaling");
164 data->AdjustWindowRectExForDpi = (BOOL (WINAPI *)(LPRECT, DWORD, BOOL, DWORD, UINT))SDL_LoadFunction(data->userDLL, "AdjustWindowRectExForDpi");
165 data->GetDpiForWindow = (UINT (WINAPI *)(HWND))SDL_LoadFunction(data->userDLL, "GetDpiForWindow");
166 data->AreDpiAwarenessContextsEqual = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "AreDpiAwarenessContextsEqual");
167 data->IsValidDpiAwarenessContext = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "IsValidDpiAwarenessContext");
168 data->GetDisplayConfigBufferSizes = (LONG (WINAPI *)(UINT32,UINT32*,UINT32* ))SDL_LoadFunction(data->userDLL, "GetDisplayConfigBufferSizes");
169 data->QueryDisplayConfig = (LONG (WINAPI *)(UINT32,UINT32*,DISPLAYCONFIG_PATH_INFO*,UINT32*,DISPLAYCONFIG_MODE_INFO*,DISPLAYCONFIG_TOPOLOGY_ID*))SDL_LoadFunction(data->userDLL, "QueryDisplayConfig");
170 data->DisplayConfigGetDeviceInfo = (LONG (WINAPI *)(DISPLAYCONFIG_DEVICE_INFO_HEADER*))SDL_LoadFunction(data->userDLL, "DisplayConfigGetDeviceInfo");
171 data->GetPointerType = (BOOL (WINAPI *)(UINT32, POINTER_INPUT_TYPE *))SDL_LoadFunction(data->userDLL, "GetPointerType");
172 data->GetPointerPenInfo = (BOOL (WINAPI *)(UINT32, POINTER_PEN_INFO *))SDL_LoadFunction(data->userDLL, "GetPointerPenInfo");
173 /* *INDENT-ON* */ // clang-format on
174 } else {
175 SDL_ClearError();
176 }
177
178 data->shcoreDLL = SDL_LoadObject("SHCORE.DLL");
179 if (data->shcoreDLL) {
180 /* *INDENT-OFF* */ // clang-format off
181 data->GetDpiForMonitor = (HRESULT (WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *))SDL_LoadFunction(data->shcoreDLL, "GetDpiForMonitor");
182 data->SetProcessDpiAwareness = (HRESULT (WINAPI *)(PROCESS_DPI_AWARENESS))SDL_LoadFunction(data->shcoreDLL, "SetProcessDpiAwareness");
183 /* *INDENT-ON* */ // clang-format on
184 } else {
185 SDL_ClearError();
186 }
187#endif // #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
188
189#ifdef HAVE_DXGI_H
190 data->dxgiDLL = SDL_LoadObject("DXGI.DLL");
191 if (data->dxgiDLL) {
192 /* *INDENT-OFF* */ // clang-format off
193 typedef HRESULT (WINAPI *CreateDXGI_t)(REFIID riid, void **ppFactory);
194 /* *INDENT-ON* */ // clang-format on
195 CreateDXGI_t CreateDXGI;
196
197 CreateDXGI = (CreateDXGI_t)SDL_LoadFunction(data->dxgiDLL, "CreateDXGIFactory");
198 if (CreateDXGI) {
199 GUID dxgiGUID = { 0x7b7166ec, 0x21c7, 0x44ae, { 0xb2, 0x1a, 0xc9, 0xae, 0x32, 0x1a, 0xe3, 0x69 } };
200 CreateDXGI(&dxgiGUID, (void **)&data->pDXGIFactory);
201 }
202 }
203#endif
204
205 // Set the function pointers
206 device->VideoInit = WIN_VideoInit;
207 device->VideoQuit = WIN_VideoQuit;
208#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
209 device->RefreshDisplays = WIN_RefreshDisplays;
210 device->GetDisplayBounds = WIN_GetDisplayBounds;
211 device->GetDisplayUsableBounds = WIN_GetDisplayUsableBounds;
212 device->GetDisplayModes = WIN_GetDisplayModes;
213 device->SetDisplayMode = WIN_SetDisplayMode;
214#endif
215 device->PumpEvents = WIN_PumpEvents;
216 device->WaitEventTimeout = WIN_WaitEventTimeout;
217#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
218 device->SendWakeupEvent = WIN_SendWakeupEvent;
219 device->SuspendScreenSaver = WIN_SuspendScreenSaver;
220#endif
221
222 device->CreateSDLWindow = WIN_CreateWindow;
223 device->SetWindowTitle = WIN_SetWindowTitle;
224 device->SetWindowIcon = WIN_SetWindowIcon;
225 device->SetWindowPosition = WIN_SetWindowPosition;
226 device->SetWindowSize = WIN_SetWindowSize;
227 device->GetWindowBordersSize = WIN_GetWindowBordersSize;
228 device->GetWindowSizeInPixels = WIN_GetWindowSizeInPixels;
229 device->SetWindowOpacity = WIN_SetWindowOpacity;
230 device->ShowWindow = WIN_ShowWindow;
231 device->HideWindow = WIN_HideWindow;
232 device->RaiseWindow = WIN_RaiseWindow;
233 device->MaximizeWindow = WIN_MaximizeWindow;
234 device->MinimizeWindow = WIN_MinimizeWindow;
235 device->RestoreWindow = WIN_RestoreWindow;
236 device->SetWindowBordered = WIN_SetWindowBordered;
237 device->SetWindowResizable = WIN_SetWindowResizable;
238 device->SetWindowAlwaysOnTop = WIN_SetWindowAlwaysOnTop;
239 device->SetWindowFullscreen = WIN_SetWindowFullscreen;
240 device->SetWindowParent = WIN_SetWindowParent;
241 device->SetWindowModal = WIN_SetWindowModal;
242#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
243 device->GetWindowICCProfile = WIN_GetWindowICCProfile;
244 device->SetWindowMouseRect = WIN_SetWindowMouseRect;
245 device->SetWindowMouseGrab = WIN_SetWindowMouseGrab;
246 device->SetWindowKeyboardGrab = WIN_SetWindowKeyboardGrab;
247#endif
248 device->DestroyWindow = WIN_DestroyWindow;
249#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
250 device->CreateWindowFramebuffer = WIN_CreateWindowFramebuffer;
251 device->UpdateWindowFramebuffer = WIN_UpdateWindowFramebuffer;
252 device->DestroyWindowFramebuffer = WIN_DestroyWindowFramebuffer;
253 device->OnWindowEnter = WIN_OnWindowEnter;
254 device->SetWindowHitTest = WIN_SetWindowHitTest;
255 device->AcceptDragAndDrop = WIN_AcceptDragAndDrop;
256 device->FlashWindow = WIN_FlashWindow;
257 device->ShowWindowSystemMenu = WIN_ShowWindowSystemMenu;
258 device->SetWindowFocusable = WIN_SetWindowFocusable;
259 device->UpdateWindowShape = WIN_UpdateWindowShape;
260#endif
261
262#ifdef SDL_VIDEO_OPENGL_WGL
263 device->GL_LoadLibrary = WIN_GL_LoadLibrary;
264 device->GL_GetProcAddress = WIN_GL_GetProcAddress;
265 device->GL_UnloadLibrary = WIN_GL_UnloadLibrary;
266 device->GL_CreateContext = WIN_GL_CreateContext;
267 device->GL_MakeCurrent = WIN_GL_MakeCurrent;
268 device->GL_SetSwapInterval = WIN_GL_SetSwapInterval;
269 device->GL_GetSwapInterval = WIN_GL_GetSwapInterval;
270 device->GL_SwapWindow = WIN_GL_SwapWindow;
271 device->GL_DestroyContext = WIN_GL_DestroyContext;
272 device->GL_GetEGLSurface = NULL;
273#endif
274#ifdef SDL_VIDEO_OPENGL_EGL
275#ifdef SDL_VIDEO_OPENGL_WGL
276 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, false)) {
277#endif
278 // Use EGL based functions
279 device->GL_LoadLibrary = WIN_GLES_LoadLibrary;
280 device->GL_GetProcAddress = WIN_GLES_GetProcAddress;
281 device->GL_UnloadLibrary = WIN_GLES_UnloadLibrary;
282 device->GL_CreateContext = WIN_GLES_CreateContext;
283 device->GL_MakeCurrent = WIN_GLES_MakeCurrent;
284 device->GL_SetSwapInterval = WIN_GLES_SetSwapInterval;
285 device->GL_GetSwapInterval = WIN_GLES_GetSwapInterval;
286 device->GL_SwapWindow = WIN_GLES_SwapWindow;
287 device->GL_DestroyContext = WIN_GLES_DestroyContext;
288 device->GL_GetEGLSurface = WIN_GLES_GetEGLSurface;
289#ifdef SDL_VIDEO_OPENGL_WGL
290 }
291#endif
292#endif
293#ifdef SDL_VIDEO_VULKAN
294 device->Vulkan_LoadLibrary = WIN_Vulkan_LoadLibrary;
295 device->Vulkan_UnloadLibrary = WIN_Vulkan_UnloadLibrary;
296 device->Vulkan_GetInstanceExtensions = WIN_Vulkan_GetInstanceExtensions;
297 device->Vulkan_CreateSurface = WIN_Vulkan_CreateSurface;
298 device->Vulkan_DestroySurface = WIN_Vulkan_DestroySurface;
299 device->Vulkan_GetPresentationSupport = WIN_Vulkan_GetPresentationSupport;
300#endif
301
302#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
303 device->StartTextInput = WIN_StartTextInput;
304 device->StopTextInput = WIN_StopTextInput;
305 device->UpdateTextInputArea = WIN_UpdateTextInputArea;
306 device->ClearComposition = WIN_ClearComposition;
307
308 device->SetClipboardData = WIN_SetClipboardData;
309 device->GetClipboardData = WIN_GetClipboardData;
310 device->HasClipboardData = WIN_HasClipboardData;
311#endif
312
313#ifdef SDL_GDK_TEXTINPUT
314 GDK_EnsureHints();
315
316 device->StartTextInput = GDK_StartTextInput;
317 device->StopTextInput = GDK_StopTextInput;
318 device->UpdateTextInputArea = GDK_UpdateTextInputArea;
319 device->ClearComposition = GDK_ClearComposition;
320
321 device->HasScreenKeyboardSupport = GDK_HasScreenKeyboardSupport;
322 device->ShowScreenKeyboard = GDK_ShowScreenKeyboard;
323 device->HideScreenKeyboard = GDK_HideScreenKeyboard;
324 device->IsScreenKeyboardShown = GDK_IsScreenKeyboardShown;
325#endif
326
327 device->free = WIN_DeleteDevice;
328
329 device->device_caps = VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT |
330 VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS;
331
332 return device;
333}
334
335VideoBootStrap WINDOWS_bootstrap = {
336 "windows", "SDL Windows video driver", WIN_CreateDevice,
337 #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
338 WIN_ShowMessageBox,
339 #else
340 NULL,
341 #endif
342 false
343};
344
345static BOOL WIN_DeclareDPIAwareUnaware(SDL_VideoDevice *_this)
346{
347#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
348 SDL_VideoData *data = _this->internal;
349
350 if (data->SetProcessDpiAwarenessContext) {
351 return data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
352 } else if (data->SetProcessDpiAwareness) {
353 // Windows 8.1
354 return SUCCEEDED(data->SetProcessDpiAwareness(PROCESS_DPI_UNAWARE));
355 }
356#endif
357 return FALSE;
358}
359
360static BOOL WIN_DeclareDPIAwareSystem(SDL_VideoDevice *_this)
361{
362#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
363 SDL_VideoData *data = _this->internal;
364
365 if (data->SetProcessDpiAwarenessContext) {
366 // Windows 10, version 1607
367 return data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);
368 } else if (data->SetProcessDpiAwareness) {
369 // Windows 8.1
370 return SUCCEEDED(data->SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE));
371 } else if (data->SetProcessDPIAware) {
372 // Windows Vista
373 return data->SetProcessDPIAware();
374 }
375#endif
376 return FALSE;
377}
378
379static BOOL WIN_DeclareDPIAwarePerMonitor(SDL_VideoDevice *_this)
380{
381#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
382 SDL_VideoData *data = _this->internal;
383
384 if (data->SetProcessDpiAwarenessContext) {
385 // Windows 10, version 1607
386 return data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
387 } else if (data->SetProcessDpiAwareness) {
388 // Windows 8.1
389 return SUCCEEDED(data->SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE));
390 } else {
391 // Older OS: fall back to system DPI aware
392 return WIN_DeclareDPIAwareSystem(_this);
393 }
394#else
395 return FALSE;
396#endif
397}
398
399static BOOL WIN_DeclareDPIAwarePerMonitorV2(SDL_VideoDevice *_this)
400{
401#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
402 return FALSE;
403#else
404 SDL_VideoData *data = _this->internal;
405
406 // Declare DPI aware (may have been done in external code or a manifest, as well)
407 if (data->SetProcessDpiAwarenessContext) {
408 // Windows 10, version 1607
409
410 /* NOTE: SetThreadDpiAwarenessContext doesn't work here with OpenGL - the OpenGL contents
411 end up still getting OS scaled. (tested on Windows 10 21H1 19043.1348, NVIDIA 496.49)
412
413 NOTE: Enabling DPI awareness through Windows Explorer
414 (right click .exe -> Properties -> Compatibility -> High DPI Settings ->
415 check "Override high DPI Scaling behaviour", select Application) gives
416 a DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE context (at least on Windows 10 21H1), and
417 setting DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 will fail.
418
419 NOTE: Entering exclusive fullscreen in a DPI_AWARENESS_CONTEXT_UNAWARE process
420 appears to cause Windows to change the .exe manifest to DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
421 on future launches. This means attempting to use DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
422 will fail in the future until you manually clear the "Override high DPI Scaling behaviour"
423 setting in Windows Explorer (tested on Windows 10 21H2).
424 */
425 if (data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
426 return TRUE;
427 } else {
428 return WIN_DeclareDPIAwarePerMonitor(_this);
429 }
430 } else {
431 // Older OS: fall back to per-monitor (or system)
432 return WIN_DeclareDPIAwarePerMonitor(_this);
433 }
434#endif
435}
436
437#ifdef HIGHDPI_DEBUG
438static const char *WIN_GetDPIAwareness(SDL_VideoDevice *_this)
439{
440 SDL_VideoData *data = _this->internal;
441
442 if (data->GetThreadDpiAwarenessContext && data->AreDpiAwarenessContextsEqual) {
443 DPI_AWARENESS_CONTEXT context = data->GetThreadDpiAwarenessContext();
444
445 if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE)) {
446 return "unaware";
447 } else if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)) {
448 return "system";
449 } else if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)) {
450 return "permonitor";
451 } else if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
452 return "permonitorv2";
453 } else if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED)) {
454 return "unaware_gdiscaled";
455 }
456 }
457
458 return "";
459}
460#endif
461
462static void WIN_InitDPIAwareness(SDL_VideoDevice *_this)
463{
464 const char *hint = SDL_GetHint("SDL_WINDOWS_DPI_AWARENESS");
465
466 if (!hint || SDL_strcmp(hint, "permonitorv2") == 0) {
467 WIN_DeclareDPIAwarePerMonitorV2(_this);
468 } else if (SDL_strcmp(hint, "permonitor") == 0) {
469 WIN_DeclareDPIAwarePerMonitor(_this);
470 } else if (SDL_strcmp(hint, "system") == 0) {
471 WIN_DeclareDPIAwareSystem(_this);
472 } else if (SDL_strcmp(hint, "unaware") == 0) {
473 WIN_DeclareDPIAwareUnaware(_this);
474 }
475}
476
477static bool WIN_VideoInit(SDL_VideoDevice *_this)
478{
479 SDL_VideoData *data = _this->internal;
480 HRESULT hr;
481
482 hr = WIN_CoInitialize();
483 if (SUCCEEDED(hr)) {
484 data->coinitialized = true;
485
486#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
487 hr = OleInitialize(NULL);
488 if (SUCCEEDED(hr)) {
489 data->oleinitialized = true;
490 } else {
491 SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "OleInitialize() failed: 0x%.8x, using fallback drag-n-drop functionality", (unsigned int)hr);
492 }
493#endif // !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
494 } else {
495 SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "CoInitialize() failed: 0x%.8x, using fallback drag-n-drop functionality", (unsigned int)hr);
496 }
497
498 WIN_InitDPIAwareness(_this);
499
500#ifdef HIGHDPI_DEBUG
501 SDL_Log("DPI awareness: %s", WIN_GetDPIAwareness(_this));
502#endif
503
504 if (SDL_GetHintBoolean(SDL_HINT_WINDOWS_GAMEINPUT, true)) {
505 WIN_InitGameInput(_this);
506 }
507
508#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)
509 // For Xbox, we just need to create the single display
510 {
511 SDL_DisplayMode mode;
512
513 SDL_zero(mode);
514 D3D12_XBOX_GetResolution(&mode.w, &mode.h);
515 mode.refresh_rate = 60.0f;
516 mode.format = SDL_PIXELFORMAT_ARGB8888;
517
518 SDL_AddBasicVideoDisplay(&mode);
519 }
520#else // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
521 if (!WIN_InitModes(_this)) {
522 return false;
523 }
524
525 WIN_InitKeyboard(_this);
526 WIN_InitMouse(_this);
527 WIN_InitDeviceNotification();
528 if (!_this->internal->gameinput_context) {
529 WIN_CheckKeyboardAndMouseHotplug(_this, true);
530 }
531#endif
532
533 SDL_AddHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD, UpdateWindowsRawKeyboard, _this);
534 SDL_AddHintCallback(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, UpdateWindowsEnableMessageLoop, NULL);
535 SDL_AddHintCallback(SDL_HINT_WINDOWS_ENABLE_MENU_MNEMONICS, UpdateWindowsEnableMenuMnemonics, NULL);
536 SDL_AddHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL);
537
538#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
539 data->_SDL_WAKEUP = RegisterWindowMessageA("_SDL_WAKEUP");
540#endif
541
542 return true;
543}
544
545void WIN_VideoQuit(SDL_VideoDevice *_this)
546{
547 SDL_VideoData *data = _this->internal;
548
549 SDL_RemoveHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD, UpdateWindowsRawKeyboard, _this);
550 SDL_RemoveHintCallback(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, UpdateWindowsEnableMessageLoop, NULL);
551 SDL_RemoveHintCallback(SDL_HINT_WINDOWS_ENABLE_MENU_MNEMONICS, UpdateWindowsEnableMenuMnemonics, NULL);
552 SDL_RemoveHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL);
553
554 WIN_SetRawMouseEnabled(_this, false);
555 WIN_SetRawKeyboardEnabled(_this, false);
556 WIN_QuitGameInput(_this);
557
558#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
559 WIN_QuitModes(_this);
560 WIN_QuitDeviceNotification();
561 WIN_QuitKeyboard(_this);
562 WIN_QuitMouse(_this);
563
564 if (data->oleinitialized) {
565 OleUninitialize();
566 data->oleinitialized = false;
567 }
568#endif // !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES))
569
570 if (data->coinitialized) {
571 WIN_CoUninitialize();
572 data->coinitialized = false;
573 }
574}
575
576#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
577#define D3D_DEBUG_INFO
578#include <d3d9.h>
579
580#ifdef D3D_DEBUG_INFO
581#ifndef D3D_SDK_VERSION
582#define D3D_SDK_VERSION (32 | 0x80000000)
583#endif
584#ifndef D3D9b_SDK_VERSION
585#define D3D9b_SDK_VERSION (31 | 0x80000000)
586#endif
587#else //
588#ifndef D3D_SDK_VERSION
589#define D3D_SDK_VERSION 32
590#endif
591#ifndef D3D9b_SDK_VERSION
592#define D3D9b_SDK_VERSION 31
593#endif
594#endif
595
596bool D3D_LoadDLL(void **pD3DDLL, IDirect3D9 **pDirect3D9Interface)
597{
598 *pD3DDLL = SDL_LoadObject("D3D9.DLL");
599 if (*pD3DDLL) {
600 /* *INDENT-OFF* */ // clang-format off
601 typedef IDirect3D9 *(WINAPI *Direct3DCreate9_t)(UINT SDKVersion);
602 typedef HRESULT (WINAPI* Direct3DCreate9Ex_t)(UINT SDKVersion, IDirect3D9Ex** ppD3D);
603 /* *INDENT-ON* */ // clang-format on
604 Direct3DCreate9_t Direct3DCreate9Func;
605
606 if (SDL_GetHintBoolean(SDL_HINT_WINDOWS_USE_D3D9EX, false)) {
607 Direct3DCreate9Ex_t Direct3DCreate9ExFunc;
608
609 Direct3DCreate9ExFunc = (Direct3DCreate9Ex_t)SDL_LoadFunction(*pD3DDLL, "Direct3DCreate9Ex");
610 if (Direct3DCreate9ExFunc) {
611 IDirect3D9Ex *pDirect3D9ExInterface;
612 HRESULT hr = Direct3DCreate9ExFunc(D3D_SDK_VERSION, &pDirect3D9ExInterface);
613 if (SUCCEEDED(hr)) {
614 const GUID IDirect3D9_GUID = { 0x81bdcbca, 0x64d4, 0x426d, { 0xae, 0x8d, 0xad, 0x1, 0x47, 0xf4, 0x27, 0x5c } };
615 hr = IDirect3D9Ex_QueryInterface(pDirect3D9ExInterface, &IDirect3D9_GUID, (void **)pDirect3D9Interface);
616 IDirect3D9Ex_Release(pDirect3D9ExInterface);
617 if (SUCCEEDED(hr)) {
618 return true;
619 }
620 }
621 }
622 }
623
624 Direct3DCreate9Func = (Direct3DCreate9_t)SDL_LoadFunction(*pD3DDLL, "Direct3DCreate9");
625 if (Direct3DCreate9Func) {
626 *pDirect3D9Interface = Direct3DCreate9Func(D3D_SDK_VERSION);
627 if (*pDirect3D9Interface) {
628 return true;
629 }
630 }
631
632 SDL_UnloadObject(*pD3DDLL);
633 *pD3DDLL = NULL;
634 }
635 *pDirect3D9Interface = NULL;
636 return false;
637}
638
639int SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID)
640{
641 void *pD3DDLL;
642 IDirect3D9 *pD3D;
643 if (!D3D_LoadDLL(&pD3DDLL, &pD3D)) {
644 SDL_SetError("Unable to create Direct3D interface");
645 return -1;
646 } else {
647 SDL_DisplayData *pData = SDL_GetDisplayDriverData(displayID);
648 int adapterIndex = D3DADAPTER_DEFAULT;
649
650 if (!pData) {
651 SDL_SetError("Invalid display index");
652 adapterIndex = -1; // make sure we return something invalid
653 } else {
654 char *displayName = WIN_StringToUTF8W(pData->DeviceName);
655 unsigned int count = IDirect3D9_GetAdapterCount(pD3D);
656 unsigned int i;
657 for (i = 0; i < count; i++) {
658 D3DADAPTER_IDENTIFIER9 id;
659 IDirect3D9_GetAdapterIdentifier(pD3D, i, 0, &id);
660
661 if (SDL_strcmp(id.DeviceName, displayName) == 0) {
662 adapterIndex = i;
663 break;
664 }
665 }
666 SDL_free(displayName);
667 }
668
669 // free up the D3D stuff we inited
670 IDirect3D9_Release(pD3D);
671 SDL_UnloadObject(pD3DDLL);
672
673 return adapterIndex;
674 }
675}
676#endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
677
678bool SDL_GetDXGIOutputInfo(SDL_DisplayID displayID, int *adapterIndex, int *outputIndex)
679{
680#ifndef HAVE_DXGI_H
681 if (adapterIndex) {
682 *adapterIndex = -1;
683 }
684 if (outputIndex) {
685 *outputIndex = -1;
686 }
687 return SDL_SetError("SDL was compiled without DXGI support due to missing dxgi.h header");
688#else
689 const SDL_VideoDevice *videodevice = SDL_GetVideoDevice();
690 const SDL_VideoData *videodata = videodevice ? videodevice->internal : NULL;
691 SDL_DisplayData *pData = SDL_GetDisplayDriverData(displayID);
692 int nAdapter, nOutput;
693 IDXGIAdapter *pDXGIAdapter;
694 IDXGIOutput *pDXGIOutput;
695
696 if (!adapterIndex) {
697 return SDL_InvalidParamError("adapterIndex");
698 }
699
700 if (!outputIndex) {
701 return SDL_InvalidParamError("outputIndex");
702 }
703
704 *adapterIndex = -1;
705 *outputIndex = -1;
706
707 if (!pData) {
708 return SDL_SetError("Invalid display index");
709 }
710
711 if (!videodata || !videodata->pDXGIFactory) {
712 return SDL_SetError("Unable to create DXGI interface");
713 }
714
715 nAdapter = 0;
716 while (*adapterIndex == -1 && SUCCEEDED(IDXGIFactory_EnumAdapters(videodata->pDXGIFactory, nAdapter, &pDXGIAdapter))) {
717 nOutput = 0;
718 while (*adapterIndex == -1 && SUCCEEDED(IDXGIAdapter_EnumOutputs(pDXGIAdapter, nOutput, &pDXGIOutput))) {
719 DXGI_OUTPUT_DESC outputDesc;
720 if (SUCCEEDED(IDXGIOutput_GetDesc(pDXGIOutput, &outputDesc))) {
721 if (SDL_wcscmp(outputDesc.DeviceName, pData->DeviceName) == 0) {
722 *adapterIndex = nAdapter;
723 *outputIndex = nOutput;
724 }
725 }
726 IDXGIOutput_Release(pDXGIOutput);
727 nOutput++;
728 }
729 IDXGIAdapter_Release(pDXGIAdapter);
730 nAdapter++;
731 }
732
733 if (*adapterIndex == -1) {
734 return SDL_SetError("Couldn't find matching adapter");
735 }
736 return true;
737#endif
738}
739
740SDL_SystemTheme WIN_GetSystemTheme(void)
741{
742 SDL_SystemTheme theme = SDL_SYSTEM_THEME_LIGHT;
743 HKEY hKey;
744 DWORD dwType = REG_DWORD;
745 DWORD value = ~0U;
746 DWORD length = sizeof(value);
747
748 // Technically this isn't the system theme, but it's the preference for applications
749 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
750 if (RegQueryValueExW(hKey, L"AppsUseLightTheme", 0, &dwType, (LPBYTE)&value, &length) == ERROR_SUCCESS) {
751 if (value == 0) {
752 theme = SDL_SYSTEM_THEME_DARK;
753 }
754 }
755 RegCloseKey(hKey);
756 }
757 return theme;
758}
759
760bool WIN_IsPerMonitorV2DPIAware(SDL_VideoDevice *_this)
761{
762#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES)
763 SDL_VideoData *data = _this->internal;
764
765 if (data->AreDpiAwarenessContextsEqual && data->GetThreadDpiAwarenessContext) {
766 // Windows 10, version 1607
767 return data->AreDpiAwarenessContextsEqual(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, data->GetThreadDpiAwarenessContext());
768 }
769#endif
770 return false;
771}
772
773#endif // SDL_VIDEO_DRIVER_WINDOWS