SDL_windowsvideo.c (14642B)
1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2020 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 #if SDL_VIDEO_DRIVER_WINDOWS 24 25 #include "SDL_main.h" 26 #include "SDL_video.h" 27 #include "SDL_hints.h" 28 #include "SDL_mouse.h" 29 #include "SDL_system.h" 30 #include "../SDL_sysvideo.h" 31 #include "../SDL_pixels_c.h" 32 33 #include "SDL_windowsvideo.h" 34 #include "SDL_windowsframebuffer.h" 35 #include "SDL_windowsshape.h" 36 #include "SDL_windowsvulkan.h" 37 38 /* Initialization/Query functions */ 39 static int WIN_VideoInit(_THIS); 40 static void WIN_VideoQuit(_THIS); 41 42 /* Hints */ 43 SDL_bool g_WindowsEnableMessageLoop = SDL_TRUE; 44 SDL_bool g_WindowFrameUsableWhileCursorHidden = SDL_TRUE; 45 46 static void SDLCALL 47 UpdateWindowsEnableMessageLoop(void *userdata, const char *name, const char *oldValue, const char *newValue) 48 { 49 if (newValue && *newValue == '0') { 50 g_WindowsEnableMessageLoop = SDL_FALSE; 51 } else { 52 g_WindowsEnableMessageLoop = SDL_TRUE; 53 } 54 } 55 56 static void SDLCALL 57 UpdateWindowFrameUsableWhileCursorHidden(void *userdata, const char *name, const char *oldValue, const char *newValue) 58 { 59 if (newValue && *newValue == '0') { 60 g_WindowFrameUsableWhileCursorHidden = SDL_FALSE; 61 } else { 62 g_WindowFrameUsableWhileCursorHidden = SDL_TRUE; 63 } 64 } 65 66 static void WIN_SuspendScreenSaver(_THIS) 67 { 68 if (_this->suspend_screensaver) { 69 SetThreadExecutionState(ES_CONTINUOUS | ES_DISPLAY_REQUIRED); 70 } else { 71 SetThreadExecutionState(ES_CONTINUOUS); 72 } 73 } 74 75 76 /* Windows driver bootstrap functions */ 77 78 static void 79 WIN_DeleteDevice(SDL_VideoDevice * device) 80 { 81 SDL_VideoData *data = (SDL_VideoData *) device->driverdata; 82 83 SDL_UnregisterApp(); 84 if (data->userDLL) { 85 SDL_UnloadObject(data->userDLL); 86 } 87 if (data->shcoreDLL) { 88 SDL_UnloadObject(data->shcoreDLL); 89 } 90 91 SDL_free(device->driverdata); 92 SDL_free(device); 93 } 94 95 static SDL_VideoDevice * 96 WIN_CreateDevice(int devindex) 97 { 98 SDL_VideoDevice *device; 99 SDL_VideoData *data; 100 101 SDL_RegisterApp(NULL, 0, NULL); 102 103 /* Initialize all variables that we clean on shutdown */ 104 device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice)); 105 if (device) { 106 data = (struct SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData)); 107 } else { 108 data = NULL; 109 } 110 if (!data) { 111 SDL_free(device); 112 SDL_OutOfMemory(); 113 return NULL; 114 } 115 device->driverdata = data; 116 117 data->userDLL = SDL_LoadObject("USER32.DLL"); 118 if (data->userDLL) { 119 data->CloseTouchInputHandle = (BOOL (WINAPI *)(HTOUCHINPUT)) SDL_LoadFunction(data->userDLL, "CloseTouchInputHandle"); 120 data->GetTouchInputInfo = (BOOL (WINAPI *)(HTOUCHINPUT, UINT, PTOUCHINPUT, int)) SDL_LoadFunction(data->userDLL, "GetTouchInputInfo"); 121 data->RegisterTouchWindow = (BOOL (WINAPI *)(HWND, ULONG)) SDL_LoadFunction(data->userDLL, "RegisterTouchWindow"); 122 } else { 123 SDL_ClearError(); 124 } 125 126 data->shcoreDLL = SDL_LoadObject("SHCORE.DLL"); 127 if (data->shcoreDLL) { 128 data->GetDpiForMonitor = (HRESULT (WINAPI *)(HMONITOR, MONITOR_DPI_TYPE, UINT *, UINT *)) SDL_LoadFunction(data->shcoreDLL, "GetDpiForMonitor"); 129 } else { 130 SDL_ClearError(); 131 } 132 133 /* Set the function pointers */ 134 device->VideoInit = WIN_VideoInit; 135 device->VideoQuit = WIN_VideoQuit; 136 device->GetDisplayBounds = WIN_GetDisplayBounds; 137 device->GetDisplayUsableBounds = WIN_GetDisplayUsableBounds; 138 device->GetDisplayDPI = WIN_GetDisplayDPI; 139 device->GetDisplayModes = WIN_GetDisplayModes; 140 device->SetDisplayMode = WIN_SetDisplayMode; 141 device->PumpEvents = WIN_PumpEvents; 142 device->SuspendScreenSaver = WIN_SuspendScreenSaver; 143 144 device->CreateSDLWindow = WIN_CreateWindow; 145 device->CreateSDLWindowFrom = WIN_CreateWindowFrom; 146 device->SetWindowTitle = WIN_SetWindowTitle; 147 device->SetWindowIcon = WIN_SetWindowIcon; 148 device->SetWindowPosition = WIN_SetWindowPosition; 149 device->SetWindowSize = WIN_SetWindowSize; 150 device->GetWindowBordersSize = WIN_GetWindowBordersSize; 151 device->SetWindowOpacity = WIN_SetWindowOpacity; 152 device->ShowWindow = WIN_ShowWindow; 153 device->HideWindow = WIN_HideWindow; 154 device->RaiseWindow = WIN_RaiseWindow; 155 device->MaximizeWindow = WIN_MaximizeWindow; 156 device->MinimizeWindow = WIN_MinimizeWindow; 157 device->RestoreWindow = WIN_RestoreWindow; 158 device->SetWindowBordered = WIN_SetWindowBordered; 159 device->SetWindowResizable = WIN_SetWindowResizable; 160 device->SetWindowFullscreen = WIN_SetWindowFullscreen; 161 device->SetWindowGammaRamp = WIN_SetWindowGammaRamp; 162 device->GetWindowGammaRamp = WIN_GetWindowGammaRamp; 163 device->SetWindowGrab = WIN_SetWindowGrab; 164 device->DestroyWindow = WIN_DestroyWindow; 165 device->GetWindowWMInfo = WIN_GetWindowWMInfo; 166 device->CreateWindowFramebuffer = WIN_CreateWindowFramebuffer; 167 device->UpdateWindowFramebuffer = WIN_UpdateWindowFramebuffer; 168 device->DestroyWindowFramebuffer = WIN_DestroyWindowFramebuffer; 169 device->OnWindowEnter = WIN_OnWindowEnter; 170 device->SetWindowHitTest = WIN_SetWindowHitTest; 171 device->AcceptDragAndDrop = WIN_AcceptDragAndDrop; 172 173 device->shape_driver.CreateShaper = Win32_CreateShaper; 174 device->shape_driver.SetWindowShape = Win32_SetWindowShape; 175 device->shape_driver.ResizeWindowShape = Win32_ResizeWindowShape; 176 177 #if SDL_VIDEO_OPENGL_WGL 178 device->GL_LoadLibrary = WIN_GL_LoadLibrary; 179 device->GL_GetProcAddress = WIN_GL_GetProcAddress; 180 device->GL_UnloadLibrary = WIN_GL_UnloadLibrary; 181 device->GL_CreateContext = WIN_GL_CreateContext; 182 device->GL_MakeCurrent = WIN_GL_MakeCurrent; 183 device->GL_SetSwapInterval = WIN_GL_SetSwapInterval; 184 device->GL_GetSwapInterval = WIN_GL_GetSwapInterval; 185 device->GL_SwapWindow = WIN_GL_SwapWindow; 186 device->GL_DeleteContext = WIN_GL_DeleteContext; 187 #elif SDL_VIDEO_OPENGL_EGL 188 /* Use EGL based functions */ 189 device->GL_LoadLibrary = WIN_GLES_LoadLibrary; 190 device->GL_GetProcAddress = WIN_GLES_GetProcAddress; 191 device->GL_UnloadLibrary = WIN_GLES_UnloadLibrary; 192 device->GL_CreateContext = WIN_GLES_CreateContext; 193 device->GL_MakeCurrent = WIN_GLES_MakeCurrent; 194 device->GL_SetSwapInterval = WIN_GLES_SetSwapInterval; 195 device->GL_GetSwapInterval = WIN_GLES_GetSwapInterval; 196 device->GL_SwapWindow = WIN_GLES_SwapWindow; 197 device->GL_DeleteContext = WIN_GLES_DeleteContext; 198 #endif 199 #if SDL_VIDEO_VULKAN 200 device->Vulkan_LoadLibrary = WIN_Vulkan_LoadLibrary; 201 device->Vulkan_UnloadLibrary = WIN_Vulkan_UnloadLibrary; 202 device->Vulkan_GetInstanceExtensions = WIN_Vulkan_GetInstanceExtensions; 203 device->Vulkan_CreateSurface = WIN_Vulkan_CreateSurface; 204 #endif 205 206 device->StartTextInput = WIN_StartTextInput; 207 device->StopTextInput = WIN_StopTextInput; 208 device->SetTextInputRect = WIN_SetTextInputRect; 209 210 device->SetClipboardText = WIN_SetClipboardText; 211 device->GetClipboardText = WIN_GetClipboardText; 212 device->HasClipboardText = WIN_HasClipboardText; 213 214 device->free = WIN_DeleteDevice; 215 216 return device; 217 } 218 219 220 VideoBootStrap WINDOWS_bootstrap = { 221 "windows", "SDL Windows video driver", WIN_CreateDevice 222 }; 223 224 int 225 WIN_VideoInit(_THIS) 226 { 227 if (WIN_InitModes(_this) < 0) { 228 return -1; 229 } 230 231 WIN_InitKeyboard(_this); 232 WIN_InitMouse(_this); 233 234 SDL_AddHintCallback(SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, UpdateWindowsEnableMessageLoop, NULL); 235 SDL_AddHintCallback(SDL_HINT_WINDOW_FRAME_USABLE_WHILE_CURSOR_HIDDEN, UpdateWindowFrameUsableWhileCursorHidden, NULL); 236 237 return 0; 238 } 239 240 void 241 WIN_VideoQuit(_THIS) 242 { 243 WIN_QuitModes(_this); 244 WIN_QuitKeyboard(_this); 245 WIN_QuitMouse(_this); 246 } 247 248 249 #define D3D_DEBUG_INFO 250 #include <d3d9.h> 251 252 SDL_bool 253 D3D_LoadDLL(void **pD3DDLL, IDirect3D9 **pDirect3D9Interface) 254 { 255 *pD3DDLL = SDL_LoadObject("D3D9.DLL"); 256 if (*pD3DDLL) { 257 typedef IDirect3D9 *(WINAPI *Direct3DCreate9_t) (UINT SDKVersion); 258 Direct3DCreate9_t Direct3DCreate9Func; 259 260 #ifdef USE_D3D9EX 261 typedef HRESULT (WINAPI *Direct3DCreate9Ex_t)(UINT SDKVersion, IDirect3D9Ex **ppD3D); 262 Direct3DCreate9Ex_t Direct3DCreate9ExFunc; 263 264 Direct3DCreate9ExFunc = (Direct3DCreate9Ex_t)SDL_LoadFunction(*pD3DDLL, "Direct3DCreate9Ex"); 265 if (Direct3DCreate9ExFunc) { 266 IDirect3D9Ex *pDirect3D9ExInterface; 267 HRESULT hr = Direct3DCreate9ExFunc(D3D_SDK_VERSION, &pDirect3D9ExInterface); 268 if (SUCCEEDED(hr)) { 269 const GUID IDirect3D9_GUID = { 0x81bdcbca, 0x64d4, 0x426d, { 0xae, 0x8d, 0xad, 0x1, 0x47, 0xf4, 0x27, 0x5c } }; 270 hr = IDirect3D9Ex_QueryInterface(pDirect3D9ExInterface, &IDirect3D9_GUID, (void**)pDirect3D9Interface); 271 IDirect3D9Ex_Release(pDirect3D9ExInterface); 272 if (SUCCEEDED(hr)) { 273 return SDL_TRUE; 274 } 275 } 276 } 277 #endif /* USE_D3D9EX */ 278 279 Direct3DCreate9Func = (Direct3DCreate9_t)SDL_LoadFunction(*pD3DDLL, "Direct3DCreate9"); 280 if (Direct3DCreate9Func) { 281 *pDirect3D9Interface = Direct3DCreate9Func(D3D_SDK_VERSION); 282 if (*pDirect3D9Interface) { 283 return SDL_TRUE; 284 } 285 } 286 287 SDL_UnloadObject(*pD3DDLL); 288 *pD3DDLL = NULL; 289 } 290 *pDirect3D9Interface = NULL; 291 return SDL_FALSE; 292 } 293 294 295 int 296 SDL_Direct3D9GetAdapterIndex(int displayIndex) 297 { 298 void *pD3DDLL; 299 IDirect3D9 *pD3D; 300 if (!D3D_LoadDLL(&pD3DDLL, &pD3D)) { 301 SDL_SetError("Unable to create Direct3D interface"); 302 return D3DADAPTER_DEFAULT; 303 } else { 304 SDL_DisplayData *pData = (SDL_DisplayData *)SDL_GetDisplayDriverData(displayIndex); 305 int adapterIndex = D3DADAPTER_DEFAULT; 306 307 if (!pData) { 308 SDL_SetError("Invalid display index"); 309 adapterIndex = -1; /* make sure we return something invalid */ 310 } else { 311 char *displayName = WIN_StringToUTF8(pData->DeviceName); 312 unsigned int count = IDirect3D9_GetAdapterCount(pD3D); 313 unsigned int i; 314 for (i=0; i<count; i++) { 315 D3DADAPTER_IDENTIFIER9 id; 316 IDirect3D9_GetAdapterIdentifier(pD3D, i, 0, &id); 317 318 if (SDL_strcmp(id.DeviceName, displayName) == 0) { 319 adapterIndex = i; 320 break; 321 } 322 } 323 SDL_free(displayName); 324 } 325 326 /* free up the D3D stuff we inited */ 327 IDirect3D9_Release(pD3D); 328 SDL_UnloadObject(pD3DDLL); 329 330 return adapterIndex; 331 } 332 } 333 334 #if HAVE_DXGI_H 335 #define CINTERFACE 336 #define COBJMACROS 337 #include <dxgi.h> 338 339 static SDL_bool 340 DXGI_LoadDLL(void **pDXGIDLL, IDXGIFactory **pDXGIFactory) 341 { 342 *pDXGIDLL = SDL_LoadObject("DXGI.DLL"); 343 if (*pDXGIDLL) { 344 HRESULT (WINAPI *CreateDXGI)(REFIID riid, void **ppFactory); 345 346 CreateDXGI = 347 (HRESULT (WINAPI *) (REFIID, void**)) SDL_LoadFunction(*pDXGIDLL, 348 "CreateDXGIFactory"); 349 if (CreateDXGI) { 350 GUID dxgiGUID = {0x7b7166ec,0x21c7,0x44ae,{0xb2,0x1a,0xc9,0xae,0x32,0x1a,0xe3,0x69}}; 351 if (!SUCCEEDED(CreateDXGI(&dxgiGUID, (void**)pDXGIFactory))) { 352 *pDXGIFactory = NULL; 353 } 354 } 355 if (!*pDXGIFactory) { 356 SDL_UnloadObject(*pDXGIDLL); 357 *pDXGIDLL = NULL; 358 return SDL_FALSE; 359 } 360 361 return SDL_TRUE; 362 } else { 363 *pDXGIFactory = NULL; 364 return SDL_FALSE; 365 } 366 } 367 #endif 368 369 370 SDL_bool 371 SDL_DXGIGetOutputInfo(int displayIndex, int *adapterIndex, int *outputIndex) 372 { 373 #if !HAVE_DXGI_H 374 if (adapterIndex) *adapterIndex = -1; 375 if (outputIndex) *outputIndex = -1; 376 SDL_SetError("SDL was compiled without DXGI support due to missing dxgi.h header"); 377 return SDL_FALSE; 378 #else 379 SDL_DisplayData *pData = (SDL_DisplayData *)SDL_GetDisplayDriverData(displayIndex); 380 void *pDXGIDLL; 381 char *displayName; 382 int nAdapter, nOutput; 383 IDXGIFactory *pDXGIFactory = NULL; 384 IDXGIAdapter *pDXGIAdapter; 385 IDXGIOutput* pDXGIOutput; 386 387 if (!adapterIndex) { 388 SDL_InvalidParamError("adapterIndex"); 389 return SDL_FALSE; 390 } 391 392 if (!outputIndex) { 393 SDL_InvalidParamError("outputIndex"); 394 return SDL_FALSE; 395 } 396 397 *adapterIndex = -1; 398 *outputIndex = -1; 399 400 if (!pData) { 401 SDL_SetError("Invalid display index"); 402 return SDL_FALSE; 403 } 404 405 if (!DXGI_LoadDLL(&pDXGIDLL, &pDXGIFactory)) { 406 SDL_SetError("Unable to create DXGI interface"); 407 return SDL_FALSE; 408 } 409 410 displayName = WIN_StringToUTF8(pData->DeviceName); 411 nAdapter = 0; 412 while (*adapterIndex == -1 && SUCCEEDED(IDXGIFactory_EnumAdapters(pDXGIFactory, nAdapter, &pDXGIAdapter))) { 413 nOutput = 0; 414 while (*adapterIndex == -1 && SUCCEEDED(IDXGIAdapter_EnumOutputs(pDXGIAdapter, nOutput, &pDXGIOutput))) { 415 DXGI_OUTPUT_DESC outputDesc; 416 if (SUCCEEDED(IDXGIOutput_GetDesc(pDXGIOutput, &outputDesc))) { 417 char *outputName = WIN_StringToUTF8(outputDesc.DeviceName); 418 if (SDL_strcmp(outputName, displayName) == 0) { 419 *adapterIndex = nAdapter; 420 *outputIndex = nOutput; 421 } 422 SDL_free(outputName); 423 } 424 IDXGIOutput_Release(pDXGIOutput); 425 nOutput++; 426 } 427 IDXGIAdapter_Release(pDXGIAdapter); 428 nAdapter++; 429 } 430 SDL_free(displayName); 431 432 /* free up the DXGI factory */ 433 IDXGIFactory_Release(pDXGIFactory); 434 SDL_UnloadObject(pDXGIDLL); 435 436 if (*adapterIndex == -1) { 437 return SDL_FALSE; 438 } else { 439 return SDL_TRUE; 440 } 441 #endif 442 } 443 444 #endif /* SDL_VIDEO_DRIVER_WINDOWS */ 445 446 /* vim: set ts=4 sw=4 expandtab: */