src/video/windows/SDL_windowsvideo.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 02 Aug 2018 16:03:47 -0400
changeset 12070 1d65571b57dd
parent 11872 e917e911dab6
child 12316 e9954c42ee01
permissions -rw-r--r--
Some drag'and'drop improvements.

First: disable d'n'd events by default; most apps don't need these at all, and
if an app doesn't explicitly handle these, each drop on the window will cause
a memory leak if the events are enabled. This follows the guidelines we have
for SDL_TEXTINPUT events already.

Second: when events are enabled or disabled, signal the video layer, as it
might be able to inform the OS, causing UI changes or optimizations (for
example, dropping a file icon on a Cocoa app that isn't accepting drops will
cause macOS to show a rejection animation instead of the drop operation just
vanishing into the ether, X11 might show a different cursor when dragging
onto an accepting window, etc).

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