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