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