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