Atlas - SDL_windowsvideo.c

Home / ext / SDL / src / video / windows Lines: 1 | Size: 34644 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 40#include <shobjidl.h> 41 42#ifndef __ITaskbarList3_FWD_DEFINED__ 43typedef struct ITaskbarList3 ITaskbarList3; 44#endif 45 46#ifndef __ITaskbarList3_INTERFACE_DEFINED__ 47typedef enum TBPFLAG 48{ 49 TBPF_NOPROGRESS = 0x0, 50 TBPF_INDETERMINATE = 0x1, 51 TBPF_NORMAL = 0x2, 52 TBPF_ERROR = 0x4, 53 TBPF_PAUSED = 0x8 54} TBPFLAG; 55 56typedef enum THUMBBUTTONMASK 57{ 58 THB_BITMAP = 0x1, 59 THB_ICON = 0x2, 60 THB_TOOLTIP = 0x4, 61 THB_FLAGS = 0x8 62} THUMBBUTTONMASK; 63 64typedef enum THUMBBUTTONFLAGS 65{ 66 THBF_ENABLED = 0x0, 67 THBF_DISABLED = 0x1, 68 THBF_DISMISSONCLICK = 0x2, 69 THBF_NOBACKGROUND = 0x4, 70 THBF_HIDDEN = 0x8, 71 THBF_NONINTERACTIVE = 0x10 72} THUMBBUTTONFLAGS; 73 74#if defined(_MSC_VER) 75#pragma warning(disable: 4103) 76#endif 77#pragma pack(push, 8) 78typedef struct THUMBBUTTON 79{ 80 THUMBBUTTONMASK dwMask; 81 UINT iId; 82 UINT iBitmap; 83 HICON hIcon; 84 WCHAR szTip[260]; 85 THUMBBUTTONFLAGS dwFlags; 86} THUMBBUTTON; 87 88typedef struct THUMBBUTTON *LPTHUMBBUTTON; 89#pragma pack(pop) 90 91#ifndef HIMAGELIST 92struct _IMAGELIST; 93typedef struct _IMAGELIST *HIMAGELIST; 94#endif 95 96typedef struct ITaskbarList3Vtbl 97{ 98 HRESULT (__stdcall *QueryInterface)(ITaskbarList3 *This, REFIID riid, void **ppvObject); 99 ULONG (__stdcall *AddRef)(ITaskbarList3 *This); 100 ULONG (__stdcall *Release)(ITaskbarList3 *This); 101 HRESULT (__stdcall *HrInit)(ITaskbarList3 *This); 102 HRESULT (__stdcall *AddTab)(ITaskbarList3 *This, HWND hwnd); 103 HRESULT (__stdcall *DeleteTab)(ITaskbarList3 *This, HWND hwnd); 104 HRESULT (__stdcall *ActivateTab)(ITaskbarList3 *This, HWND hwnd); 105 HRESULT (__stdcall *SetActiveAlt)(ITaskbarList3 *This, HWND hwnd); 106 HRESULT (__stdcall *MarkFullscreenWindow)(ITaskbarList3 *This, HWND hwnd, BOOL fFullscreen); 107 HRESULT (__stdcall *SetProgressValue)(ITaskbarList3 *This, HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal); 108 HRESULT (__stdcall *SetProgressState)(ITaskbarList3 *This, HWND hwnd, TBPFLAG tbpFlags); 109 HRESULT (__stdcall *RegisterTab)(ITaskbarList3 *This, HWND hwndTab, HWND hwndMDI); 110 HRESULT (__stdcall *UnregisterTab)(ITaskbarList3 *This, HWND hwndTab); 111 HRESULT (__stdcall *SetTabOrder)(ITaskbarList3 *This, HWND hwndTab, HWND hwndInsertBefore); 112 HRESULT (__stdcall *SetTabActive)(ITaskbarList3 *This, HWND hwndTab, HWND hwndMDI, DWORD dwReserved); 113 HRESULT (__stdcall *ThumbBarAddButtons)(ITaskbarList3 *This, HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton); 114 HRESULT (__stdcall *ThumbBarUpdateButtons)(ITaskbarList3 *This, HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton); 115 HRESULT (__stdcall *ThumbBarSetImageList)(ITaskbarList3 *This, HWND hwnd, HIMAGELIST himl); 116 HRESULT (__stdcall *SetOverlayIcon)(ITaskbarList3 *This, HWND hwnd, HICON hIcon, LPCWSTR pszDescription); 117 HRESULT (__stdcall *SetThumbnailTooltip)(ITaskbarList3 *This, HWND hwnd, LPCWSTR pszTip); 118 HRESULT (__stdcall *SetThumbnailClip)(ITaskbarList3 *This, HWND hwnd, RECT *prcClip); 119} ITaskbarList3Vtbl; 120 121struct ITaskbarList3 122{ 123 ITaskbarList3Vtbl *lpVtbl; 124}; 125 126#endif // #ifndef __ITaskbarList3_INTERFACE_DEFINED__ 127 128#endif 129 130#ifdef SDL_GDK_TEXTINPUT 131#include "../gdk/SDL_gdktextinput.h" 132#endif 133 134// #define HIGHDPI_DEBUG 135 136// Initialization/Query functions 137static bool WIN_VideoInit(SDL_VideoDevice *_this); 138static void WIN_VideoQuit(SDL_VideoDevice *_this); 139 140// Hints 141bool g_WindowsEnableMessageLoop = true; 142bool g_WindowsEnableMenuMnemonics = false; 143bool g_WindowFrameUsableWhileCursorHidden = true; 144 145static void SDLCALL UpdateWindowsRawKeyboard(void *userdata, const char *name, const char *oldValue, const char *newValue) 146{ 147 SDL_VideoDevice *_this = (SDL_VideoDevice *)userdata; 148 bool enabled = SDL_GetStringBoolean(newValue, false); 149 WIN_SetRawKeyboardEnabled(_this, enabled); 150} 151 152static void SDLCALL UpdateWindowsRawKeyboardNoHotkeys(void *userdata, const char *name, const char *oldValue, const char *newValue) 153{ 154 SDL_VideoDevice *_this = (SDL_VideoDevice *)userdata; 155 bool enabled = SDL_GetStringBoolean(newValue, false); 156 WIN_SetRawKeyboardFlag_NoHotkeys(_this, enabled); 157} 158 159static void SDLCALL UpdateWindowsEnableMessageLoop(void *userdata, const char *name, const char *oldValue, const char *newValue) 160{ 161 g_WindowsEnableMessageLoop = SDL_GetStringBoolean(newValue, true); 162} 163 164static void SDLCALL UpdateWindowsEnableMenuMnemonics(void *userdata, const char *name, const char *oldValue, const char *newValue) 165{ 166 g_WindowsEnableMenuMnemonics = SDL_GetStringBoolean(newValue, false); 167} 168 169static void SDLCALL UpdateWindowFrameUsableWhileCursorHidden(void *userdata, const char *name, const char *oldValue, const char *newValue) 170{ 171 g_WindowFrameUsableWhileCursorHidden = SDL_GetStringBoolean(newValue, true); 172} 173 174#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 175static bool WIN_SuspendScreenSaver(SDL_VideoDevice *_this) 176{ 177 DWORD result; 178 if (_this->suspend_screensaver) { 179 result = SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED); 180 } else { 181 result = SetThreadExecutionState(ES_CONTINUOUS); 182 } 183 if (result == 0) { 184 SDL_SetError("SetThreadExecutionState() failed"); 185 return false; 186 } 187 return true; 188} 189#endif 190 191#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) 192extern void D3D12_XBOX_GetResolution(Uint32 *width, Uint32 *height); 193#endif 194 195// Windows driver bootstrap functions 196 197static void WIN_DeleteDevice(SDL_VideoDevice *device) 198{ 199 SDL_VideoData *data = device->internal; 200 201 SDL_UnregisterApp(); 202#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 203 if (data->userDLL) { 204 SDL_UnloadObject(data->userDLL); 205 } 206 if (data->shcoreDLL) { 207 SDL_UnloadObject(data->shcoreDLL); 208 } 209 if (data->dwmapiDLL) { 210 SDL_UnloadObject(data->dwmapiDLL); 211 } 212#endif 213#ifdef HAVE_DXGI_H 214 if (data->pDXGIFactory) { 215 IDXGIFactory_Release(data->pDXGIFactory); 216 } 217 if (data->dxgiDLL) { 218 SDL_UnloadObject(data->dxgiDLL); 219 } 220#endif 221 SDL_free(device->internal->rawinput); 222 SDL_free(device->internal); 223 SDL_free(device); 224} 225 226static SDL_VideoDevice *WIN_CreateDevice(void) 227{ 228 SDL_VideoDevice *device; 229 SDL_VideoData *data; 230 231 SDL_RegisterApp(NULL, 0, NULL); 232 233 // Initialize all variables that we clean on shutdown 234 device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice)); 235 if (device) { 236 data = (SDL_VideoData *)SDL_calloc(1, sizeof(SDL_VideoData)); 237 } else { 238 data = NULL; 239 } 240 if (!data) { 241 SDL_UnregisterApp(); 242 SDL_free(device); 243 return NULL; 244 } 245 device->internal = data; 246 device->system_theme = WIN_GetSystemTheme(); 247 248#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 249 data->userDLL = SDL_LoadObject("USER32.DLL"); 250 if (data->userDLL) { 251 /* *INDENT-OFF* */ // clang-format off 252 data->CloseTouchInputHandle = (BOOL (WINAPI *)(HTOUCHINPUT))SDL_LoadFunction(data->userDLL, "CloseTouchInputHandle"); 253 data->GetTouchInputInfo = (BOOL (WINAPI *)(HTOUCHINPUT, UINT, PTOUCHINPUT, int)) SDL_LoadFunction(data->userDLL, "GetTouchInputInfo"); 254 data->RegisterTouchWindow = (BOOL (WINAPI *)(HWND, ULONG))SDL_LoadFunction(data->userDLL, "RegisterTouchWindow"); 255 data->SetProcessDPIAware = (BOOL (WINAPI *)(void))SDL_LoadFunction(data->userDLL, "SetProcessDPIAware"); 256 data->SetProcessDpiAwarenessContext = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "SetProcessDpiAwarenessContext"); 257 data->SetThreadDpiAwarenessContext = (DPI_AWARENESS_CONTEXT (WINAPI *)(DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "SetThreadDpiAwarenessContext"); 258 data->GetThreadDpiAwarenessContext = (DPI_AWARENESS_CONTEXT (WINAPI *)(void))SDL_LoadFunction(data->userDLL, "GetThreadDpiAwarenessContext"); 259 data->GetAwarenessFromDpiAwarenessContext = (DPI_AWARENESS (WINAPI *)(DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "GetAwarenessFromDpiAwarenessContext"); 260 data->EnableNonClientDpiScaling = (BOOL (WINAPI *)(HWND))SDL_LoadFunction(data->userDLL, "EnableNonClientDpiScaling"); 261 data->AdjustWindowRectExForDpi = (BOOL (WINAPI *)(LPRECT, DWORD, BOOL, DWORD, UINT))SDL_LoadFunction(data->userDLL, "AdjustWindowRectExForDpi"); 262 data->GetDpiForWindow = (UINT (WINAPI *)(HWND))SDL_LoadFunction(data->userDLL, "GetDpiForWindow"); 263 data->AreDpiAwarenessContextsEqual = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT, DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "AreDpiAwarenessContextsEqual"); 264 data->IsValidDpiAwarenessContext = (BOOL (WINAPI *)(DPI_AWARENESS_CONTEXT))SDL_LoadFunction(data->userDLL, "IsValidDpiAwarenessContext"); 265 data->GetDisplayConfigBufferSizes = (LONG (WINAPI *)(UINT32,UINT32 *,UINT32 *))SDL_LoadFunction(data->userDLL, "GetDisplayConfigBufferSizes"); 266 data->QueryDisplayConfig = (LONG (WINAPI *)(UINT32,UINT32 *,DISPLAYCONFIG_PATH_INFO*,UINT32 *,DISPLAYCONFIG_MODE_INFO*,DISPLAYCONFIG_TOPOLOGY_ID*))SDL_LoadFunction(data->userDLL, "QueryDisplayConfig"); 267 data->DisplayConfigGetDeviceInfo = (LONG (WINAPI *)(DISPLAYCONFIG_DEVICE_INFO_HEADER*))SDL_LoadFunction(data->userDLL, "DisplayConfigGetDeviceInfo"); 268 data->GetPointerType = (BOOL (WINAPI *)(UINT32, POINTER_INPUT_TYPE *))SDL_LoadFunction(data->userDLL, "GetPointerType"); 269 data->GetPointerPenInfo = (BOOL (WINAPI *)(UINT32, POINTER_PEN_INFO *))SDL_LoadFunction(data->userDLL, "GetPointerPenInfo"); 270 data->GetPointerDeviceRects = (BOOL (WINAPI *)(HANDLE, RECT *, RECT *))SDL_LoadFunction(data->userDLL, "GetPointerDeviceRects"); 271 /* *INDENT-ON* */ // clang-format on 272 } else { 273 SDL_ClearError(); 274 } 275 276 data->shcoreDLL = SDL_LoadObject("SHCORE.DLL"); 277 if (data->shcoreDLL) { 278 /* *INDENT-OFF* */ // clang-format off 279 data->GetDpiForMonitor = (HRESULT (WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *))SDL_LoadFunction(data->shcoreDLL, "GetDpiForMonitor"); 280 data->SetProcessDpiAwareness = (HRESULT (WINAPI *)(PROCESS_DPI_AWARENESS))SDL_LoadFunction(data->shcoreDLL, "SetProcessDpiAwareness"); 281 /* *INDENT-ON* */ // clang-format on 282 } else { 283 SDL_ClearError(); 284 } 285 286 data->dwmapiDLL = SDL_LoadObject("DWMAPI.DLL"); 287 if (data->dwmapiDLL) { 288 /* *INDENT-OFF* */ // clang-format off 289 data->DwmFlush = (HRESULT (WINAPI *)(void))SDL_LoadFunction(data->dwmapiDLL, "DwmFlush"); 290 data->DwmEnableBlurBehindWindow = (HRESULT (WINAPI *)(HWND hwnd, const DWM_BLURBEHIND *pBlurBehind))SDL_LoadFunction(data->dwmapiDLL, "DwmEnableBlurBehindWindow"); 291 data->DwmSetWindowAttribute = (HRESULT (WINAPI *)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute))SDL_LoadFunction(data->dwmapiDLL, "DwmSetWindowAttribute"); 292 /* *INDENT-ON* */ // clang-format on 293 } else { 294 SDL_ClearError(); 295 } 296#endif // #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 297 298#ifdef HAVE_DXGI_H 299 data->dxgiDLL = SDL_LoadObject("DXGI.DLL"); 300 if (data->dxgiDLL) { 301 /* *INDENT-OFF* */ // clang-format off 302 typedef HRESULT (WINAPI *pfnCreateDXGI)(REFIID riid, void **ppFactory); 303 /* *INDENT-ON* */ // clang-format on 304 pfnCreateDXGI pCreateDXGI; 305 306 pCreateDXGI = (pfnCreateDXGI)SDL_LoadFunction(data->dxgiDLL, "CreateDXGIFactory"); 307 if (pCreateDXGI) { 308 GUID dxgiGUID = { 0x7b7166ec, 0x21c7, 0x44ae, { 0xb2, 0x1a, 0xc9, 0xae, 0x32, 0x1a, 0xe3, 0x69 } }; 309 pCreateDXGI(&dxgiGUID, (void **)&data->pDXGIFactory); 310 } 311 } 312#endif 313 314 // Set the function pointers 315 device->VideoInit = WIN_VideoInit; 316 device->VideoQuit = WIN_VideoQuit; 317#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 318 device->RefreshDisplays = WIN_RefreshDisplays; 319 device->GetDisplayBounds = WIN_GetDisplayBounds; 320 device->GetDisplayUsableBounds = WIN_GetDisplayUsableBounds; 321 device->GetDisplayModes = WIN_GetDisplayModes; 322 device->SetDisplayMode = WIN_SetDisplayMode; 323#endif 324 device->PumpEvents = WIN_PumpEvents; 325 device->WaitEventTimeout = WIN_WaitEventTimeout; 326#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 327 device->SendWakeupEvent = WIN_SendWakeupEvent; 328 device->SuspendScreenSaver = WIN_SuspendScreenSaver; 329#endif 330 331 device->CreateSDLWindow = WIN_CreateWindow; 332 device->SetWindowTitle = WIN_SetWindowTitle; 333 device->SetWindowIcon = WIN_SetWindowIcon; 334 device->SetWindowPosition = WIN_SetWindowPosition; 335 device->SetWindowSize = WIN_SetWindowSize; 336 device->GetWindowBordersSize = WIN_GetWindowBordersSize; 337 device->GetWindowSizeInPixels = WIN_GetWindowSizeInPixels; 338 device->SetWindowOpacity = WIN_SetWindowOpacity; 339 device->ShowWindow = WIN_ShowWindow; 340 device->HideWindow = WIN_HideWindow; 341 device->RaiseWindow = WIN_RaiseWindow; 342 device->MaximizeWindow = WIN_MaximizeWindow; 343 device->MinimizeWindow = WIN_MinimizeWindow; 344 device->RestoreWindow = WIN_RestoreWindow; 345 device->SetWindowBordered = WIN_SetWindowBordered; 346 device->SetWindowResizable = WIN_SetWindowResizable; 347 device->SetWindowAlwaysOnTop = WIN_SetWindowAlwaysOnTop; 348 device->SetWindowFullscreen = WIN_SetWindowFullscreen; 349 device->SetWindowParent = WIN_SetWindowParent; 350 device->SetWindowModal = WIN_SetWindowModal; 351#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 352 device->GetWindowICCProfile = WIN_GetWindowICCProfile; 353 device->SetWindowMouseRect = WIN_SetWindowMouseRect; 354 device->SetWindowMouseGrab = WIN_SetWindowMouseGrab; 355 device->SetWindowKeyboardGrab = WIN_SetWindowKeyboardGrab; 356#endif 357 device->DestroyWindow = WIN_DestroyWindow; 358#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 359 device->CreateWindowFramebuffer = WIN_CreateWindowFramebuffer; 360 device->UpdateWindowFramebuffer = WIN_UpdateWindowFramebuffer; 361 device->DestroyWindowFramebuffer = WIN_DestroyWindowFramebuffer; 362 device->OnWindowEnter = WIN_OnWindowEnter; 363 device->SetWindowHitTest = WIN_SetWindowHitTest; 364 device->AcceptDragAndDrop = WIN_AcceptDragAndDrop; 365 device->FlashWindow = WIN_FlashWindow; 366 device->ApplyWindowProgress = WIN_ApplyWindowProgress; 367 device->ShowWindowSystemMenu = WIN_ShowWindowSystemMenu; 368 device->SetWindowFocusable = WIN_SetWindowFocusable; 369 device->UpdateWindowShape = WIN_UpdateWindowShape; 370#endif 371 372#ifdef SDL_VIDEO_OPENGL_WGL 373 device->GL_LoadLibrary = WIN_GL_LoadLibrary; 374 device->GL_GetProcAddress = WIN_GL_GetProcAddress; 375 device->GL_UnloadLibrary = WIN_GL_UnloadLibrary; 376 device->GL_CreateContext = WIN_GL_CreateContext; 377 device->GL_MakeCurrent = WIN_GL_MakeCurrent; 378 device->GL_SetSwapInterval = WIN_GL_SetSwapInterval; 379 device->GL_GetSwapInterval = WIN_GL_GetSwapInterval; 380 device->GL_SwapWindow = WIN_GL_SwapWindow; 381 device->GL_DestroyContext = WIN_GL_DestroyContext; 382 device->GL_GetEGLSurface = NULL; 383#endif 384#ifdef SDL_VIDEO_OPENGL_EGL 385#ifdef SDL_VIDEO_OPENGL_WGL 386 if (SDL_GetHintBoolean(SDL_HINT_VIDEO_FORCE_EGL, false)) { 387#endif 388 // Use EGL based functions 389 device->GL_LoadLibrary = WIN_GLES_LoadLibrary; 390 device->GL_GetProcAddress = WIN_GLES_GetProcAddress; 391 device->GL_UnloadLibrary = WIN_GLES_UnloadLibrary; 392 device->GL_CreateContext = WIN_GLES_CreateContext; 393 device->GL_MakeCurrent = WIN_GLES_MakeCurrent; 394 device->GL_SetSwapInterval = WIN_GLES_SetSwapInterval; 395 device->GL_GetSwapInterval = WIN_GLES_GetSwapInterval; 396 device->GL_SwapWindow = WIN_GLES_SwapWindow; 397 device->GL_DestroyContext = WIN_GLES_DestroyContext; 398 device->GL_GetEGLSurface = WIN_GLES_GetEGLSurface; 399#ifdef SDL_VIDEO_OPENGL_WGL 400 } 401#endif 402#endif 403#ifdef SDL_VIDEO_VULKAN 404 device->Vulkan_LoadLibrary = WIN_Vulkan_LoadLibrary; 405 device->Vulkan_UnloadLibrary = WIN_Vulkan_UnloadLibrary; 406 device->Vulkan_GetInstanceExtensions = WIN_Vulkan_GetInstanceExtensions; 407 device->Vulkan_CreateSurface = WIN_Vulkan_CreateSurface; 408 device->Vulkan_DestroySurface = WIN_Vulkan_DestroySurface; 409 device->Vulkan_GetPresentationSupport = WIN_Vulkan_GetPresentationSupport; 410#endif 411 412#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 413 device->StartTextInput = WIN_StartTextInput; 414 device->StopTextInput = WIN_StopTextInput; 415 device->UpdateTextInputArea = WIN_UpdateTextInputArea; 416 device->ClearComposition = WIN_ClearComposition; 417 418 device->SetClipboardData = WIN_SetClipboardData; 419 device->GetClipboardData = WIN_GetClipboardData; 420 device->HasClipboardData = WIN_HasClipboardData; 421#endif 422 423#ifdef SDL_GDK_TEXTINPUT 424 GDK_EnsureHints(); 425 426 device->StartTextInput = GDK_StartTextInput; 427 device->StopTextInput = GDK_StopTextInput; 428 device->UpdateTextInputArea = GDK_UpdateTextInputArea; 429 device->ClearComposition = GDK_ClearComposition; 430 431 device->HasScreenKeyboardSupport = GDK_HasScreenKeyboardSupport; 432 device->ShowScreenKeyboard = GDK_ShowScreenKeyboard; 433 device->HideScreenKeyboard = GDK_HideScreenKeyboard; 434#endif 435 436 device->free = WIN_DeleteDevice; 437 438 device->device_caps = VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT | 439 VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS; 440 441 return device; 442} 443 444VideoBootStrap WINDOWS_bootstrap = { 445 "windows", "SDL Windows video driver", WIN_CreateDevice, 446 #if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 447 WIN_ShowMessageBox, 448 #else 449 NULL, 450 #endif 451 false 452}; 453 454static BOOL WIN_DeclareDPIAwareUnaware(SDL_VideoDevice *_this) 455{ 456#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 457 SDL_VideoData *data = _this->internal; 458 459 if (data->SetProcessDpiAwarenessContext) { 460 return data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE); 461 } else if (data->SetProcessDpiAwareness) { 462 // Windows 8.1 463 return SUCCEEDED(data->SetProcessDpiAwareness(PROCESS_DPI_UNAWARE)); 464 } 465#endif 466 return FALSE; 467} 468 469static BOOL WIN_DeclareDPIAwareSystem(SDL_VideoDevice *_this) 470{ 471#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 472 SDL_VideoData *data = _this->internal; 473 474 if (data->SetProcessDpiAwarenessContext) { 475 // Windows 10, version 1607 476 return data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE); 477 } else if (data->SetProcessDpiAwareness) { 478 // Windows 8.1 479 return SUCCEEDED(data->SetProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE)); 480 } else if (data->SetProcessDPIAware) { 481 // Windows Vista 482 return data->SetProcessDPIAware(); 483 } 484#endif 485 return FALSE; 486} 487 488static BOOL WIN_DeclareDPIAwarePerMonitor(SDL_VideoDevice *_this) 489{ 490#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 491 SDL_VideoData *data = _this->internal; 492 493 if (data->SetProcessDpiAwarenessContext) { 494 // Windows 10, version 1607 495 return data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE); 496 } else if (data->SetProcessDpiAwareness) { 497 // Windows 8.1 498 return SUCCEEDED(data->SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE)); 499 } else { 500 // Older OS: fall back to system DPI aware 501 return WIN_DeclareDPIAwareSystem(_this); 502 } 503#else 504 return FALSE; 505#endif 506} 507 508static BOOL WIN_DeclareDPIAwarePerMonitorV2(SDL_VideoDevice *_this) 509{ 510#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) 511 return FALSE; 512#else 513 SDL_VideoData *data = _this->internal; 514 515 // Declare DPI aware (may have been done in external code or a manifest, as well) 516 if (data->SetProcessDpiAwarenessContext) { 517 // Windows 10, version 1607 518 519 /* NOTE: SetThreadDpiAwarenessContext doesn't work here with OpenGL - the OpenGL contents 520 end up still getting OS scaled. (tested on Windows 10 21H1 19043.1348, NVIDIA 496.49) 521 522 NOTE: Enabling DPI awareness through Windows Explorer 523 (right click .exe -> Properties -> Compatibility -> High DPI Settings -> 524 check "Override high DPI Scaling behaviour", select Application) gives 525 a DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE context (at least on Windows 10 21H1), and 526 setting DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 will fail. 527 528 NOTE: Entering exclusive fullscreen in a DPI_AWARENESS_CONTEXT_UNAWARE process 529 appears to cause Windows to change the .exe manifest to DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE 530 on future launches. This means attempting to use DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 531 will fail in the future until you manually clear the "Override high DPI Scaling behaviour" 532 setting in Windows Explorer (tested on Windows 10 21H2). 533 */ 534 if (data->SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) { 535 return TRUE; 536 } else { 537 return WIN_DeclareDPIAwarePerMonitor(_this); 538 } 539 } else { 540 // Older OS: fall back to per-monitor (or system) 541 return WIN_DeclareDPIAwarePerMonitor(_this); 542 } 543#endif 544} 545 546#ifdef HIGHDPI_DEBUG 547static const char *WIN_GetDPIAwareness(SDL_VideoDevice *_this) 548{ 549 SDL_VideoData *data = _this->internal; 550 551 if (data->GetThreadDpiAwarenessContext && data->AreDpiAwarenessContextsEqual) { 552 DPI_AWARENESS_CONTEXT context = data->GetThreadDpiAwarenessContext(); 553 554 if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE)) { 555 return "unaware"; 556 } else if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_SYSTEM_AWARE)) { 557 return "system"; 558 } else if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE)) { 559 return "permonitor"; 560 } else if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) { 561 return "permonitorv2"; 562 } else if (data->AreDpiAwarenessContextsEqual(context, DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED)) { 563 return "unaware_gdiscaled"; 564 } 565 } 566 567 return ""; 568} 569#endif 570 571static void WIN_InitDPIAwareness(SDL_VideoDevice *_this) 572{ 573 const char *hint = SDL_GetHint("SDL_WINDOWS_DPI_AWARENESS"); 574 575 if (!hint || SDL_strcmp(hint, "permonitorv2") == 0) { 576 WIN_DeclareDPIAwarePerMonitorV2(_this); 577 } else if (SDL_strcmp(hint, "permonitor") == 0) { 578 WIN_DeclareDPIAwarePerMonitor(_this); 579 } else if (SDL_strcmp(hint, "system") == 0) { 580 WIN_DeclareDPIAwareSystem(_this); 581 } else if (SDL_strcmp(hint, "unaware") == 0) { 582 WIN_DeclareDPIAwareUnaware(_this); 583 } 584} 585 586static bool WIN_VideoInit(SDL_VideoDevice *_this) 587{ 588 SDL_VideoData *data = _this->internal; 589 HRESULT hr; 590 591 hr = WIN_CoInitialize(); 592 if (SUCCEEDED(hr)) { 593 data->coinitialized = true; 594 595#if !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 596 hr = OleInitialize(NULL); 597 if (SUCCEEDED(hr)) { 598 data->oleinitialized = true; 599 } else { 600 SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "OleInitialize() failed: 0x%.8x, using fallback drag-n-drop functionality", (unsigned int)hr); 601 } 602#endif // !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 603 } else { 604 SDL_LogInfo(SDL_LOG_CATEGORY_VIDEO, "CoInitialize() failed: 0x%.8x, using fallback drag-n-drop functionality", (unsigned int)hr); 605 } 606 607 WIN_InitDPIAwareness(_this); 608 609#ifdef HIGHDPI_DEBUG 610 SDL_Log("DPI awareness: %s", WIN_GetDPIAwareness(_this)); 611#endif 612 613 if (SDL_GetHintBoolean(SDL_HINT_WINDOWS_GAMEINPUT, false)) { 614 WIN_InitGameInput(_this); 615 } 616 617#if defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES) 618 // For Xbox, we just need to create the single display 619 { 620 SDL_DisplayMode mode; 621 622 SDL_zero(mode); 623 D3D12_XBOX_GetResolution(&mode.w, &mode.h); 624 mode.refresh_rate = 60.0f; 625 mode.format = SDL_PIXELFORMAT_ARGB8888; 626 627 SDL_AddBasicVideoDisplay(&mode); 628 } 629#else // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 630 if (!WIN_InitModes(_this)) { 631 return false; 632 } 633 634 WIN_InitKeyboard(_this); 635 WIN_InitMouse(_this); 636 WIN_InitDeviceNotification(); 637 if (!_this->internal->gameinput_context) { 638 WIN_CheckKeyboardAndMouseHotplug(_this, true); 639 } 640#endif 641 642 SDL_AddHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD, UpdateWindowsRawKeyboard, _this); 643 SDL_AddHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD_EXCLUDE_HOTKEYS, UpdateWindowsRawKeyboardNoHotkeys, _this); 644 SDL_AddHintCallback(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, UpdateWindowsEnableMessageLoop, NULL); 645 SDL_AddHintCallback(SDL_HINT_WINDOWS_ENABLE_MENU_MNEMONICS, UpdateWindowsEnableMenuMnemonics, NULL); 646 SDL_AddHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL); 647 648#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 649 data->_SDL_WAKEUP = RegisterWindowMessageA("_SDL_WAKEUP"); 650 data->WM_TASKBAR_BUTTON_CREATED = WIN_IsWindows7OrGreater() ? RegisterWindowMessageA("TaskbarButtonCreated") : 0; 651#endif 652 653 return true; 654} 655 656void WIN_VideoQuit(SDL_VideoDevice *_this) 657{ 658 SDL_VideoData *data = _this->internal; 659 660 SDL_RemoveHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD, UpdateWindowsRawKeyboard, _this); 661 SDL_RemoveHintCallback(SDL_HINT_WINDOWS_RAW_KEYBOARD_EXCLUDE_HOTKEYS, UpdateWindowsRawKeyboardNoHotkeys, _this); 662 SDL_RemoveHintCallback(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, UpdateWindowsEnableMessageLoop, NULL); 663 SDL_RemoveHintCallback(SDL_HINT_WINDOWS_ENABLE_MENU_MNEMONICS, UpdateWindowsEnableMenuMnemonics, NULL); 664 SDL_RemoveHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL); 665 666 WIN_SetRawMouseEnabled(_this, false); 667 WIN_SetRawKeyboardEnabled(_this, false); 668 WIN_QuitGameInput(_this); 669 670#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 671 WIN_QuitModes(_this); 672 WIN_QuitDeviceNotification(); 673 WIN_QuitKeyboard(_this); 674 WIN_QuitMouse(_this); 675 676 if (data->taskbar_list) { 677 data->taskbar_list->lpVtbl->Release(data->taskbar_list); 678 data->taskbar_list = NULL; 679 } 680 681 if (data->oleinitialized) { 682 OleUninitialize(); 683 data->oleinitialized = false; 684 } 685#endif // !(defined(SDL_PLATFORM_XBOXONE) || defined(SDL_PLATFORM_XBOXSERIES)) 686 687 if (data->coinitialized) { 688 WIN_CoUninitialize(); 689 data->coinitialized = false; 690 } 691} 692 693#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 694#define D3D_DEBUG_INFO 695#include <d3d9.h> 696 697#ifdef D3D_DEBUG_INFO 698#ifndef D3D_SDK_VERSION 699#define D3D_SDK_VERSION (32 | 0x80000000) 700#endif 701#ifndef D3D9b_SDK_VERSION 702#define D3D9b_SDK_VERSION (31 | 0x80000000) 703#endif 704#else // 705#ifndef D3D_SDK_VERSION 706#define D3D_SDK_VERSION 32 707#endif 708#ifndef D3D9b_SDK_VERSION 709#define D3D9b_SDK_VERSION 31 710#endif 711#endif 712 713bool D3D_LoadDLL(void **pD3DDLL, IDirect3D9 **pDirect3D9Interface) 714{ 715 *pD3DDLL = SDL_LoadObject("D3D9.DLL"); 716 if (*pD3DDLL) { 717 /* *INDENT-OFF* */ // clang-format off 718 typedef IDirect3D9 *(WINAPI *pfnDirect3DCreate9)(UINT SDKVersion); 719 typedef HRESULT (WINAPI *pfnDirect3DCreate9Ex)(UINT SDKVersion, IDirect3D9Ex **ppD3D); 720 /* *INDENT-ON* */ // clang-format on 721 pfnDirect3DCreate9 pDirect3DCreate9; 722 723 if (SDL_GetHintBoolean(SDL_HINT_WINDOWS_USE_D3D9EX, false)) { 724 pfnDirect3DCreate9Ex pDirect3DCreate9Ex; 725 726 pDirect3DCreate9Ex = (pfnDirect3DCreate9Ex)SDL_LoadFunction(*pD3DDLL, "Direct3DCreate9Ex"); 727 if (pDirect3DCreate9Ex) { 728 IDirect3D9Ex *pDirect3D9ExInterface; 729 HRESULT hr = pDirect3DCreate9Ex(D3D_SDK_VERSION, &pDirect3D9ExInterface); 730 if (SUCCEEDED(hr)) { 731 const GUID IDirect3D9_GUID = { 0x81bdcbca, 0x64d4, 0x426d, { 0xae, 0x8d, 0xad, 0x1, 0x47, 0xf4, 0x27, 0x5c } }; 732 hr = IDirect3D9Ex_QueryInterface(pDirect3D9ExInterface, &IDirect3D9_GUID, (void **)pDirect3D9Interface); 733 IDirect3D9Ex_Release(pDirect3D9ExInterface); 734 if (SUCCEEDED(hr)) { 735 return true; 736 } 737 } 738 } 739 } 740 741 pDirect3DCreate9 = (pfnDirect3DCreate9)SDL_LoadFunction(*pD3DDLL, "Direct3DCreate9"); 742 if (pDirect3DCreate9) { 743 *pDirect3D9Interface = pDirect3DCreate9(D3D_SDK_VERSION); 744 if (*pDirect3D9Interface) { 745 return true; 746 } 747 } 748 749 SDL_UnloadObject(*pD3DDLL); 750 *pD3DDLL = NULL; 751 } 752 *pDirect3D9Interface = NULL; 753 return false; 754} 755 756int SDL_GetDirect3D9AdapterIndex(SDL_DisplayID displayID) 757{ 758 void *pD3DDLL; 759 IDirect3D9 *pD3D; 760 if (!D3D_LoadDLL(&pD3DDLL, &pD3D)) { 761 SDL_SetError("Unable to create Direct3D interface"); 762 return -1; 763 } else { 764 SDL_DisplayData *pData = SDL_GetDisplayDriverData(displayID); 765 int adapterIndex = D3DADAPTER_DEFAULT; 766 767 if (!pData) { 768 SDL_SetError("Invalid display index"); 769 adapterIndex = -1; // make sure we return something invalid 770 } else { 771 char *displayName = WIN_StringToUTF8W(pData->DeviceName); 772 unsigned int count = IDirect3D9_GetAdapterCount(pD3D); 773 unsigned int i; 774 for (i = 0; i < count; i++) { 775 D3DADAPTER_IDENTIFIER9 id; 776 IDirect3D9_GetAdapterIdentifier(pD3D, i, 0, &id); 777 778 if (SDL_strcmp(id.DeviceName, displayName) == 0) { 779 adapterIndex = i; 780 break; 781 } 782 } 783 SDL_free(displayName); 784 } 785 786 // free up the D3D stuff we inited 787 IDirect3D9_Release(pD3D); 788 SDL_UnloadObject(pD3DDLL); 789 790 return adapterIndex; 791 } 792} 793#endif // !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 794 795bool SDL_GetDXGIOutputInfo(SDL_DisplayID displayID, int *adapterIndex, int *outputIndex) 796{ 797#ifndef HAVE_DXGI_H 798 if (adapterIndex) { 799 *adapterIndex = -1; 800 } 801 if (outputIndex) { 802 *outputIndex = -1; 803 } 804 return SDL_SetError("SDL was compiled without DXGI support due to missing dxgi.h header"); 805#else 806 const SDL_VideoDevice *videodevice = SDL_GetVideoDevice(); 807 const SDL_VideoData *videodata = videodevice ? videodevice->internal : NULL; 808 SDL_DisplayData *pData = SDL_GetDisplayDriverData(displayID); 809 int nAdapter, nOutput; 810 IDXGIAdapter *pDXGIAdapter; 811 IDXGIOutput *pDXGIOutput; 812 813 CHECK_PARAM(!adapterIndex) { 814 return SDL_InvalidParamError("adapterIndex"); 815 } 816 817 CHECK_PARAM(!outputIndex) { 818 return SDL_InvalidParamError("outputIndex"); 819 } 820 821 *adapterIndex = -1; 822 *outputIndex = -1; 823 824 if (!pData) { 825 return SDL_SetError("Invalid display index"); 826 } 827 828 if (!videodata || !videodata->pDXGIFactory) { 829 return SDL_SetError("Unable to create DXGI interface"); 830 } 831 832 nAdapter = 0; 833 while (*adapterIndex == -1 && SUCCEEDED(IDXGIFactory_EnumAdapters(videodata->pDXGIFactory, nAdapter, &pDXGIAdapter))) { 834 nOutput = 0; 835 while (*adapterIndex == -1 && SUCCEEDED(IDXGIAdapter_EnumOutputs(pDXGIAdapter, nOutput, &pDXGIOutput))) { 836 DXGI_OUTPUT_DESC outputDesc; 837 if (SUCCEEDED(IDXGIOutput_GetDesc(pDXGIOutput, &outputDesc))) { 838 if (SDL_wcscmp(outputDesc.DeviceName, pData->DeviceName) == 0) { 839 *adapterIndex = nAdapter; 840 *outputIndex = nOutput; 841 } 842 } 843 IDXGIOutput_Release(pDXGIOutput); 844 nOutput++; 845 } 846 IDXGIAdapter_Release(pDXGIAdapter); 847 nAdapter++; 848 } 849 850 if (*adapterIndex == -1) { 851 return SDL_SetError("Couldn't find matching adapter"); 852 } 853 return true; 854#endif 855} 856 857SDL_SystemTheme WIN_GetSystemTheme(void) 858{ 859 SDL_SystemTheme theme = SDL_SYSTEM_THEME_LIGHT; 860 HKEY hKey; 861 DWORD dwType = REG_DWORD; 862 DWORD value = ~0U; 863 DWORD length = sizeof(value); 864 865 // Technically this isn't the system theme, but it's the preference for applications 866 if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_READ, &hKey) == ERROR_SUCCESS) { 867 if (RegQueryValueExW(hKey, L"AppsUseLightTheme", 0, &dwType, (LPBYTE)&value, &length) == ERROR_SUCCESS) { 868 if (value == 0) { 869 theme = SDL_SYSTEM_THEME_DARK; 870 } 871 } 872 RegCloseKey(hKey); 873 } 874 return theme; 875} 876 877bool WIN_IsPerMonitorV2DPIAware(SDL_VideoDevice *_this) 878{ 879#if !defined(SDL_PLATFORM_XBOXONE) && !defined(SDL_PLATFORM_XBOXSERIES) 880 SDL_VideoData *data = _this->internal; 881 882 if (data->AreDpiAwarenessContextsEqual && data->GetThreadDpiAwarenessContext) { 883 // Windows 10, version 1607 884 return data->AreDpiAwarenessContextsEqual(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2, data->GetThreadDpiAwarenessContext()); 885 } 886#endif 887 return false; 888} 889 890#endif // SDL_VIDEO_DRIVER_WINDOWS 891
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.