src/video/winrt/SDL_winrtvideo.cpp
author David Ludwig <dludwig@pobox.com>
Tue, 22 Dec 2015 00:58:47 -0500
changeset 9964 bcb6bd590d03
parent 9952 54b2eeb48c7d
child 9993 e05d46c27ce3
permissions -rw-r--r--
WinRT: Fixed bug 3210, "alt-tab doesn't work correctly with full-screened, UWP (Win10 Store) apps"
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2015 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_WINRT
    24 
    25 /* WinRT SDL video driver implementation
    26 
    27    Initial work on this was done by David Ludwig (dludwig@pobox.com), and
    28    was based off of SDL's "dummy" video driver.
    29  */
    30 
    31 /* Windows includes */
    32 #include <agile.h>
    33 #include <windows.graphics.display.h>
    34 #include <dxgi.h>
    35 #include <dxgi1_2.h>
    36 using namespace Windows::ApplicationModel::Core;
    37 using namespace Windows::Foundation;
    38 using namespace Windows::Graphics::Display;
    39 using namespace Windows::UI::Core;
    40 using namespace Windows::UI::ViewManagement;
    41 
    42 
    43 /* [re]declare Windows GUIDs locally, to limit the amount of external lib(s) SDL has to link to */
    44 static const GUID IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48,{ 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } };
    45 
    46 
    47 /* SDL includes */
    48 extern "C" {
    49 #include "SDL_video.h"
    50 #include "SDL_mouse.h"
    51 #include "../SDL_sysvideo.h"
    52 #include "../SDL_pixels_c.h"
    53 #include "../../events/SDL_events_c.h"
    54 #include "../../render/SDL_sysrender.h"
    55 #include "SDL_syswm.h"
    56 #include "SDL_winrtopengles.h"
    57 #include "../../core/windows/SDL_windows.h"
    58 }
    59 
    60 #include "../../core/winrt/SDL_winrtapp_direct3d.h"
    61 #include "../../core/winrt/SDL_winrtapp_xaml.h"
    62 #include "SDL_winrtvideo_cpp.h"
    63 #include "SDL_winrtevents_c.h"
    64 #include "SDL_winrtmouse_c.h"
    65 #include "SDL_main.h"
    66 #include "SDL_system.h"
    67 //#include "SDL_log.h"
    68 
    69 
    70 /* Initialization/Query functions */
    71 static int WINRT_VideoInit(_THIS);
    72 static int WINRT_InitModes(_THIS);
    73 static int WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
    74 static void WINRT_VideoQuit(_THIS);
    75 
    76 
    77 /* Window functions */
    78 static int WINRT_CreateWindow(_THIS, SDL_Window * window);
    79 static void WINRT_SetWindowSize(_THIS, SDL_Window * window);
    80 static void WINRT_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
    81 static void WINRT_DestroyWindow(_THIS, SDL_Window * window);
    82 static SDL_bool WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info);
    83 
    84 
    85 /* SDL-internal globals: */
    86 SDL_Window * WINRT_GlobalSDLWindow = NULL;
    87 
    88 
    89 /* WinRT driver bootstrap functions */
    90 
    91 static int
    92 WINRT_Available(void)
    93 {
    94     return (1);
    95 }
    96 
    97 static void
    98 WINRT_DeleteDevice(SDL_VideoDevice * device)
    99 {
   100     if (device->driverdata) {
   101         SDL_VideoData * video_data = (SDL_VideoData *)device->driverdata;
   102         if (video_data->winrtEglWindow) {
   103             video_data->winrtEglWindow->Release();
   104         }
   105         SDL_free(video_data);
   106     }
   107 
   108     SDL_free(device);
   109 }
   110 
   111 static SDL_VideoDevice *
   112 WINRT_CreateDevice(int devindex)
   113 {
   114     SDL_VideoDevice *device;
   115     SDL_VideoData *data;
   116 
   117     /* Initialize all variables that we clean on shutdown */
   118     device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
   119     if (!device) {
   120         SDL_OutOfMemory();
   121         if (device) {
   122             SDL_free(device);
   123         }
   124         return (0);
   125     }
   126 
   127     data = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
   128     if (!data) {
   129         SDL_OutOfMemory();
   130         return (0);
   131     }
   132     SDL_zerop(data);
   133     device->driverdata = data;
   134 
   135     /* Set the function pointers */
   136     device->VideoInit = WINRT_VideoInit;
   137     device->VideoQuit = WINRT_VideoQuit;
   138     device->CreateWindow = WINRT_CreateWindow;
   139     device->SetWindowSize = WINRT_SetWindowSize;
   140     device->SetWindowFullscreen = WINRT_SetWindowFullscreen;
   141     device->DestroyWindow = WINRT_DestroyWindow;
   142     device->SetDisplayMode = WINRT_SetDisplayMode;
   143     device->PumpEvents = WINRT_PumpEvents;
   144     device->GetWindowWMInfo = WINRT_GetWindowWMInfo;
   145 #ifdef SDL_VIDEO_OPENGL_EGL
   146     device->GL_LoadLibrary = WINRT_GLES_LoadLibrary;
   147     device->GL_GetProcAddress = WINRT_GLES_GetProcAddress;
   148     device->GL_UnloadLibrary = WINRT_GLES_UnloadLibrary;
   149     device->GL_CreateContext = WINRT_GLES_CreateContext;
   150     device->GL_MakeCurrent = WINRT_GLES_MakeCurrent;
   151     device->GL_SetSwapInterval = WINRT_GLES_SetSwapInterval;
   152     device->GL_GetSwapInterval = WINRT_GLES_GetSwapInterval;
   153     device->GL_SwapWindow = WINRT_GLES_SwapWindow;
   154     device->GL_DeleteContext = WINRT_GLES_DeleteContext;
   155 #endif
   156     device->free = WINRT_DeleteDevice;
   157 
   158     return device;
   159 }
   160 
   161 #define WINRTVID_DRIVER_NAME "winrt"
   162 VideoBootStrap WINRT_bootstrap = {
   163     WINRTVID_DRIVER_NAME, "SDL WinRT video driver",
   164     WINRT_Available, WINRT_CreateDevice
   165 };
   166 
   167 int
   168 WINRT_VideoInit(_THIS)
   169 {
   170     if (WINRT_InitModes(_this) < 0) {
   171         return -1;
   172     }
   173     WINRT_InitMouse(_this);
   174     WINRT_InitTouch(_this);
   175 
   176     return 0;
   177 }
   178 
   179 extern "C"
   180 Uint32 D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat);
   181 
   182 static void
   183 WINRT_DXGIModeToSDLDisplayMode(const DXGI_MODE_DESC * dxgiMode, SDL_DisplayMode * sdlMode)
   184 {
   185     SDL_zerop(sdlMode);
   186     sdlMode->w = dxgiMode->Width;
   187     sdlMode->h = dxgiMode->Height;
   188     sdlMode->refresh_rate = dxgiMode->RefreshRate.Numerator / dxgiMode->RefreshRate.Denominator;
   189     sdlMode->format = D3D11_DXGIFormatToSDLPixelFormat(dxgiMode->Format);
   190 }
   191 
   192 static int
   193 WINRT_AddDisplaysForOutput (_THIS, IDXGIAdapter1 * dxgiAdapter1, int outputIndex)
   194 {
   195     HRESULT hr;
   196     IDXGIOutput * dxgiOutput = NULL;
   197     DXGI_OUTPUT_DESC dxgiOutputDesc;
   198     SDL_VideoDisplay display;
   199     char * displayName = NULL;
   200     UINT numModes;
   201     DXGI_MODE_DESC * dxgiModes = NULL;
   202     int functionResult = -1;        /* -1 for failure, 0 for success */
   203     DXGI_MODE_DESC modeToMatch, closestMatch;
   204 
   205     SDL_zero(display);
   206 
   207     hr = dxgiAdapter1->EnumOutputs(outputIndex, &dxgiOutput);
   208     if (FAILED(hr)) {
   209         if (hr != DXGI_ERROR_NOT_FOUND) {
   210             WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIAdapter1::EnumOutputs failed", hr);
   211         }
   212         goto done;
   213     }
   214 
   215     hr = dxgiOutput->GetDesc(&dxgiOutputDesc);
   216     if (FAILED(hr)) {
   217         WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDesc failed", hr);
   218         goto done;
   219     }
   220 
   221     SDL_zero(modeToMatch);
   222     modeToMatch.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
   223     modeToMatch.Width = (dxgiOutputDesc.DesktopCoordinates.right - dxgiOutputDesc.DesktopCoordinates.left);
   224     modeToMatch.Height = (dxgiOutputDesc.DesktopCoordinates.bottom - dxgiOutputDesc.DesktopCoordinates.top);
   225     hr = dxgiOutput->FindClosestMatchingMode(&modeToMatch, &closestMatch, NULL);
   226     if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
   227         /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE gets returned by IDXGIOutput::FindClosestMatchingMode
   228            when running under the Windows Simulator, which uses Remote Desktop (formerly known as Terminal
   229            Services) under the hood.  According to the MSDN docs for the similar function,
   230            IDXGIOutput::GetDisplayModeList, DXGI_ERROR_NOT_CURRENTLY_AVAILABLE is returned if and
   231            when an app is run under a Terminal Services session, hence the assumption.
   232 
   233            In this case, just add an SDL display mode, with approximated values.
   234         */
   235         SDL_DisplayMode mode;
   236         SDL_zero(mode);
   237         display.name = "Windows Simulator / Terminal Services Display";
   238         mode.w = (dxgiOutputDesc.DesktopCoordinates.right - dxgiOutputDesc.DesktopCoordinates.left);
   239         mode.h = (dxgiOutputDesc.DesktopCoordinates.bottom - dxgiOutputDesc.DesktopCoordinates.top);
   240         mode.format = DXGI_FORMAT_B8G8R8A8_UNORM;
   241         mode.refresh_rate = 0;  /* Display mode is unknown, so just fill in zero, as specified by SDL's header files */
   242         display.desktop_mode = mode;
   243         display.current_mode = mode;
   244         if ( ! SDL_AddDisplayMode(&display, &mode)) {
   245             goto done;
   246         }
   247     } else if (FAILED(hr)) {
   248         WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::FindClosestMatchingMode failed", hr);
   249         goto done;
   250     } else {
   251         displayName = WIN_StringToUTF8(dxgiOutputDesc.DeviceName);
   252         display.name = displayName;
   253         WINRT_DXGIModeToSDLDisplayMode(&closestMatch, &display.desktop_mode);
   254         display.current_mode = display.desktop_mode;
   255 
   256         hr = dxgiOutput->GetDisplayModeList(DXGI_FORMAT_B8G8R8A8_UNORM, 0, &numModes, NULL);
   257         if (FAILED(hr)) {
   258             if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
   259                 // TODO, WinRT: make sure display mode(s) are added when using Terminal Services / Windows Simulator
   260             }
   261             WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDisplayModeList [get mode list size] failed", hr);
   262             goto done;
   263         }
   264 
   265         dxgiModes = (DXGI_MODE_DESC *)SDL_calloc(numModes, sizeof(DXGI_MODE_DESC));
   266         if ( ! dxgiModes) {
   267             SDL_OutOfMemory();
   268             goto done;
   269         }
   270 
   271         hr = dxgiOutput->GetDisplayModeList(DXGI_FORMAT_B8G8R8A8_UNORM, 0, &numModes, dxgiModes);
   272         if (FAILED(hr)) {
   273             WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDisplayModeList [get mode contents] failed", hr);
   274             goto done;
   275         }
   276 
   277         for (UINT i = 0; i < numModes; ++i) {
   278             SDL_DisplayMode sdlMode;
   279             WINRT_DXGIModeToSDLDisplayMode(&dxgiModes[i], &sdlMode);
   280             SDL_AddDisplayMode(&display, &sdlMode);
   281         }
   282     }
   283 
   284     if (SDL_AddVideoDisplay(&display) < 0) {
   285         goto done;
   286     }
   287 
   288     functionResult = 0;     /* 0 for Success! */
   289 done:
   290     if (dxgiModes) {
   291         SDL_free(dxgiModes);
   292     }
   293     if (dxgiOutput) {
   294         dxgiOutput->Release();
   295     }
   296     if (displayName) {
   297         SDL_free(displayName);
   298     }
   299     return functionResult;
   300 }
   301 
   302 static int
   303 WINRT_AddDisplaysForAdapter (_THIS, IDXGIFactory2 * dxgiFactory2, int adapterIndex)
   304 {
   305     HRESULT hr;
   306     IDXGIAdapter1 * dxgiAdapter1;
   307 
   308     hr = dxgiFactory2->EnumAdapters1(adapterIndex, &dxgiAdapter1);
   309     if (FAILED(hr)) {
   310         if (hr != DXGI_ERROR_NOT_FOUND) {
   311             WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory1::EnumAdapters1() failed", hr);
   312         }
   313         return -1;
   314     }
   315 
   316     for (int outputIndex = 0; ; ++outputIndex) {
   317         if (WINRT_AddDisplaysForOutput(_this, dxgiAdapter1, outputIndex) < 0) {
   318             /* HACK: The Windows App Certification Kit 10.0 can fail, when
   319                running the Store Apps' test, "Direct3D Feature Test".  The
   320                certification kit's error is:
   321 
   322                "Application App was not running at the end of the test. It likely crashed or was terminated for having become unresponsive."
   323 
   324                This was caused by SDL/WinRT's DXGI failing to report any
   325                outputs.  Attempts to get the 1st display-output from the
   326                1st display-adapter can fail, with IDXGIAdapter::EnumOutputs
   327                returning DXGI_ERROR_NOT_FOUND.  This could be a bug in Windows,
   328                the Windows App Certification Kit, or possibly in SDL/WinRT's
   329                display detection code.  Either way, try to detect when this
   330                happens, and use a hackish means to create a reasonable-as-possible
   331                'display mode'.  -- DavidL
   332             */
   333             if (adapterIndex == 0 && outputIndex == 0) {
   334                 SDL_VideoDisplay display;
   335                 SDL_DisplayMode mode;
   336 #if SDL_WINRT_USE_APPLICATIONVIEW
   337                 ApplicationView ^ appView = ApplicationView::GetForCurrentView();
   338 #endif
   339                 CoreWindow ^ coreWin = CoreWindow::GetForCurrentThread();
   340                 SDL_zero(display);
   341                 SDL_zero(mode);
   342                 display.name = "DXGI Display-detection Workaround";
   343 
   344                 /* HACK: ApplicationView's VisibleBounds property, appeared, via testing, to
   345                    give a better approximation of display-size, than did CoreWindow's
   346                    Bounds property, insofar that ApplicationView::VisibleBounds seems like
   347                    it will, at least some of the time, give the full display size (during the
   348                    failing test), whereas CoreWindow might not.  -- DavidL
   349                 */
   350 
   351 #if (NTDDI_VERSION >= NTDDI_WIN10) || (SDL_WINRT_USE_APPLICATIONVIEW && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
   352                 mode.w = WINRT_DIPS_TO_PHYSICAL_PIXELS(appView->VisibleBounds.Width);
   353                 mode.h = WINRT_DIPS_TO_PHYSICAL_PIXELS(appView->VisibleBounds.Height);
   354 #else
   355                 /* On platform(s) that do not support VisibleBounds, such as Windows 8.1,
   356                    fall back to CoreWindow's Bounds property.
   357                 */
   358                 mode.w = WINRT_DIPS_TO_PHYSICAL_PIXELS(coreWin->Bounds.Width);
   359                 mode.h = WINRT_DIPS_TO_PHYSICAL_PIXELS(coreWin->Bounds.Height);
   360 #endif
   361 
   362                 mode.format = DXGI_FORMAT_B8G8R8A8_UNORM;
   363                 mode.refresh_rate = 0;  /* Display mode is unknown, so just fill in zero, as specified by SDL's header files */
   364                 display.desktop_mode = mode;
   365                 display.current_mode = mode;
   366                 if ((SDL_AddDisplayMode(&display, &mode) < 0) ||
   367                     (SDL_AddVideoDisplay(&display) < 0))
   368                 {
   369                     return SDL_SetError("Failed to apply DXGI Display-detection workaround");
   370                 }
   371             }
   372 
   373             break;
   374         }
   375     }
   376 
   377     dxgiAdapter1->Release();
   378     return 0;
   379 }
   380 
   381 int
   382 WINRT_InitModes(_THIS)
   383 {
   384     /* HACK: Initialize a single display, for whatever screen the app's
   385          CoreApplicationView is on.
   386        TODO, WinRT: Try initializing multiple displays, one for each monitor.
   387          Appropriate WinRT APIs for this seem elusive, though.  -- DavidL
   388     */
   389 
   390     HRESULT hr;
   391     IDXGIFactory2 * dxgiFactory2 = NULL;
   392 
   393     hr = CreateDXGIFactory1(IID_IDXGIFactory2, (void **)&dxgiFactory2);
   394     if (FAILED(hr)) {
   395         WIN_SetErrorFromHRESULT(__FUNCTION__ ", CreateDXGIFactory1() failed", hr);
   396         return -1;
   397     }
   398 
   399     for (int adapterIndex = 0; ; ++adapterIndex) {
   400         if (WINRT_AddDisplaysForAdapter(_this, dxgiFactory2, adapterIndex) < 0) {
   401             break;
   402         }
   403     }
   404 
   405     return 0;
   406 }
   407 
   408 static int
   409 WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
   410 {
   411     return 0;
   412 }
   413 
   414 void
   415 WINRT_VideoQuit(_THIS)
   416 {
   417     WINRT_QuitMouse(_this);
   418 }
   419 
   420 static const Uint32 WINRT_DetectableFlags =
   421     SDL_WINDOW_MAXIMIZED |
   422     SDL_WINDOW_FULLSCREEN_DESKTOP |
   423     SDL_WINDOW_SHOWN |
   424     SDL_WINDOW_HIDDEN |
   425     SDL_WINDOW_MOUSE_FOCUS;
   426 
   427 extern "C" Uint32
   428 WINRT_DetectWindowFlags(SDL_Window * window)
   429 {
   430     Uint32 latestFlags = 0;
   431     SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
   432     bool is_fullscreen = false;
   433 
   434 #if SDL_WINRT_USE_APPLICATIONVIEW
   435     if (data->appView) {
   436         is_fullscreen = data->appView->IsFullScreen;
   437     }
   438 #elif (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION == NTDDI_WIN8)
   439     is_fullscreen = true;
   440 #endif
   441 
   442     if (data->coreWindow.Get()) {
   443         if (is_fullscreen) {
   444             SDL_VideoDisplay * display = SDL_GetDisplayForWindow(window);
   445             int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
   446             int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
   447 
   448 #if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION > NTDDI_WIN8)
   449             // On all WinRT platforms, except for WinPhone 8.0, rotate the
   450             // window size.  This is needed to properly calculate
   451             // fullscreen vs. maximized.
   452             const DisplayOrientations currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation);
   453             switch (currentOrientation) {
   454 #if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
   455                 case DisplayOrientations::Landscape:
   456                 case DisplayOrientations::LandscapeFlipped:
   457 #else
   458                 case DisplayOrientations::Portrait:
   459                 case DisplayOrientations::PortraitFlipped:
   460 #endif
   461                 {
   462                     int tmp = w;
   463                     w = h;
   464                     h = tmp;
   465                 } break;
   466             }
   467 #endif
   468 
   469             if (display->desktop_mode.w != w || display->desktop_mode.h != h) {
   470                 latestFlags |= SDL_WINDOW_MAXIMIZED;
   471             } else {
   472                 latestFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
   473             }
   474         }
   475 
   476         if (data->coreWindow->Visible) {
   477             latestFlags |= SDL_WINDOW_SHOWN;
   478         } else {
   479             latestFlags |= SDL_WINDOW_HIDDEN;
   480         }
   481 
   482 #if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION < NTDDI_WINBLUE)
   483         // data->coreWindow->PointerPosition is not supported on WinPhone 8.0
   484         latestFlags |= SDL_WINDOW_MOUSE_FOCUS;
   485 #else
   486         if (data->coreWindow->Bounds.Contains(data->coreWindow->PointerPosition)) {
   487             latestFlags |= SDL_WINDOW_MOUSE_FOCUS;
   488         }
   489 #endif
   490     }
   491 
   492     return latestFlags;
   493 }
   494 
   495 void
   496 WINRT_UpdateWindowFlags(SDL_Window * window, Uint32 mask)
   497 {
   498     mask &= WINRT_DetectableFlags;
   499     if (window) {
   500         Uint32 apply = WINRT_DetectWindowFlags(window);
   501         if ((apply & mask) & SDL_WINDOW_FULLSCREEN) {
   502             window->last_fullscreen_flags = window->flags;  // seems necessary to programmatically un-fullscreen, via SDL APIs
   503         }
   504         window->flags = (window->flags & ~mask) | (apply & mask);
   505     }
   506 }
   507 
   508 static bool
   509 WINRT_IsCoreWindowActive(CoreWindow ^ coreWindow)
   510 {
   511     /* WinRT does not appear to offer API(s) to determine window-activation state,
   512        at least not that I am aware of in Win8 - Win10.  As such, SDL tracks this
   513        itself, via window-activation events.
   514        
   515        If there *is* an API to track this, it should probably get used instead
   516        of the following hack (that uses "SDLHelperWindowActivationState").
   517          -- DavidL.
   518     */
   519     if (coreWindow->CustomProperties->HasKey("SDLHelperWindowActivationState")) {
   520         CoreWindowActivationState activationState = \
   521             safe_cast<CoreWindowActivationState>(coreWindow->CustomProperties->Lookup("SDLHelperWindowActivationState"));
   522         return (activationState != CoreWindowActivationState::Deactivated);
   523     }
   524 
   525     /* Assume that non-SDL tracked windows are active, although this should
   526        probably be avoided, if possible.
   527        
   528        This might not even be possible, in normal SDL use, at least as of
   529        this writing (Dec 22, 2015; via latest hg.libsdl.org/SDL clone)  -- DavidL
   530     */
   531     return true;
   532 }
   533 
   534 int
   535 WINRT_CreateWindow(_THIS, SDL_Window * window)
   536 {
   537     // Make sure that only one window gets created, at least until multimonitor
   538     // support is added.
   539     if (WINRT_GlobalSDLWindow != NULL) {
   540         SDL_SetError("WinRT only supports one window");
   541         return -1;
   542     }
   543 
   544     SDL_WindowData *data = new SDL_WindowData;  /* use 'new' here as SDL_WindowData may use WinRT/C++ types */
   545     if (!data) {
   546         SDL_OutOfMemory();
   547         return -1;
   548     }
   549     window->driverdata = data;
   550     data->sdlWindow = window;
   551 
   552     /* To note, when XAML support is enabled, access to the CoreWindow will not
   553        be possible, at least not via the SDL/XAML thread.  Attempts to access it
   554        from there will throw exceptions.  As such, the SDL_WindowData's
   555        'coreWindow' field will only be set (to a non-null value) if XAML isn't
   556        enabled.
   557     */
   558     if (!WINRT_XAMLWasEnabled) {
   559         data->coreWindow = CoreWindow::GetForCurrentThread();
   560 #if SDL_WINRT_USE_APPLICATIONVIEW
   561         data->appView = ApplicationView::GetForCurrentView();
   562 #endif
   563     }
   564 
   565     /* Make note of the requested window flags, before they start getting changed. */
   566     const Uint32 requestedFlags = window->flags;
   567 
   568 #if SDL_VIDEO_OPENGL_EGL
   569     /* Setup the EGL surface, but only if OpenGL ES 2 was requested. */
   570     if (!(window->flags & SDL_WINDOW_OPENGL)) {
   571         /* OpenGL ES 2 wasn't requested.  Don't set up an EGL surface. */
   572         data->egl_surface = EGL_NO_SURFACE;
   573     } else {
   574         /* OpenGL ES 2 was reuqested.  Set up an EGL surface. */
   575         SDL_VideoData * video_data = (SDL_VideoData *)_this->driverdata;
   576 
   577         /* Call SDL_EGL_ChooseConfig and eglCreateWindowSurface directly,
   578          * rather than via SDL_EGL_CreateSurface, as older versions of
   579          * ANGLE/WinRT may require that a C++ object, ComPtr<IUnknown>,
   580          * be passed into eglCreateWindowSurface.
   581          */
   582         if (SDL_EGL_ChooseConfig(_this) != 0) {
   583             char buf[512];
   584             SDL_snprintf(buf, sizeof(buf), "SDL_EGL_ChooseConfig failed: %s", SDL_GetError());
   585             return SDL_SetError("%s", buf);
   586         }
   587 
   588         if (video_data->winrtEglWindow) {   /* ... is the 'old' version of ANGLE/WinRT being used? */
   589             /* Attempt to create a window surface using older versions of
   590              * ANGLE/WinRT:
   591              */
   592             Microsoft::WRL::ComPtr<IUnknown> cpp_winrtEglWindow = video_data->winrtEglWindow;
   593             data->egl_surface = ((eglCreateWindowSurface_Old_Function)_this->egl_data->eglCreateWindowSurface)(
   594                 _this->egl_data->egl_display,
   595                 _this->egl_data->egl_config,
   596                 cpp_winrtEglWindow, NULL);
   597             if (data->egl_surface == NULL) {
   598                 return SDL_SetError("eglCreateWindowSurface failed");
   599             }
   600         } else if (data->coreWindow.Get() != nullptr) {
   601             /* Attempt to create a window surface using newer versions of
   602              * ANGLE/WinRT:
   603              */
   604             IInspectable * coreWindowAsIInspectable = reinterpret_cast<IInspectable *>(data->coreWindow.Get());
   605             data->egl_surface = _this->egl_data->eglCreateWindowSurface(
   606                 _this->egl_data->egl_display,
   607                 _this->egl_data->egl_config,
   608                 coreWindowAsIInspectable,
   609                 NULL);
   610             if (data->egl_surface == NULL) {
   611                 return SDL_SetError("eglCreateWindowSurface failed");
   612             }
   613         } else {
   614             return SDL_SetError("No supported means to create an EGL window surface are available");
   615         }
   616     }
   617 #endif
   618 
   619     /* Determine as many flags dynamically, as possible. */
   620     window->flags =
   621         SDL_WINDOW_BORDERLESS |
   622         SDL_WINDOW_RESIZABLE;
   623 
   624 #if SDL_VIDEO_OPENGL_EGL
   625     if (data->egl_surface) {
   626         window->flags |= SDL_WINDOW_OPENGL;
   627     }
   628 #endif
   629 
   630     if (WINRT_XAMLWasEnabled) {
   631         /* TODO, WinRT: set SDL_Window size, maybe position too, from XAML control */
   632         window->x = 0;
   633         window->y = 0;
   634         window->flags |= SDL_WINDOW_SHOWN;
   635         SDL_SetMouseFocus(NULL);        // TODO: detect this
   636         SDL_SetKeyboardFocus(NULL);     // TODO: detect this
   637     } else {
   638         /* WinRT 8.x apps seem to live in an environment where the OS controls the
   639            app's window size, with some apps being fullscreen, depending on
   640            user choice of various things.  For now, just adapt the SDL_Window to
   641            whatever Windows set-up as the native-window's geometry.
   642         */
   643         window->x = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Left);
   644         window->y = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Top);
   645 #if NTDDI_VERSION < NTDDI_WIN10
   646         /* On WinRT 8.x / pre-Win10, just use the size we were given. */
   647         window->w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
   648         window->h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
   649 #else
   650         /* On Windows 10, we occasionally get control over window size.  For windowed
   651            mode apps, try this.
   652         */
   653         bool didSetSize = false;
   654         if (!(requestedFlags & SDL_WINDOW_FULLSCREEN)) {
   655             const Windows::Foundation::Size size(WINRT_PHYSICAL_PIXELS_TO_DIPS(window->w),
   656                                                  WINRT_PHYSICAL_PIXELS_TO_DIPS(window->h));
   657             didSetSize = data->appView->TryResizeView(size);
   658         }
   659         if (!didSetSize) {
   660             /* We either weren't able to set the window size, or a request for
   661                fullscreen was made.  Get window-size info from the OS.
   662             */
   663             window->w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
   664             window->h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
   665         }
   666 #endif
   667 
   668         WINRT_UpdateWindowFlags(
   669             window,
   670             0xffffffff      /* Update any window flag(s) that WINRT_UpdateWindow can handle */
   671         );
   672 
   673         /* Try detecting if the window is active */
   674         bool isWindowActive = WINRT_IsCoreWindowActive(data->coreWindow.Get());
   675         if (isWindowActive) {
   676             SDL_SetKeyboardFocus(window);
   677         }
   678     }
   679  
   680     /* Make sure the WinRT app's IFramworkView can post events on
   681        behalf of SDL:
   682     */
   683     WINRT_GlobalSDLWindow = window;
   684 
   685     /* All done! */
   686     return 0;
   687 }
   688 
   689 void
   690 WINRT_SetWindowSize(_THIS, SDL_Window * window)
   691 {
   692 #if NTDDI_VERSION >= NTDDI_WIN10
   693     SDL_WindowData * data = (SDL_WindowData *)window->driverdata;
   694     const Windows::Foundation::Size size(WINRT_PHYSICAL_PIXELS_TO_DIPS(window->w),
   695                                          WINRT_PHYSICAL_PIXELS_TO_DIPS(window->h));
   696     data->appView->TryResizeView(size); // TODO, WinRT: return failure (to caller?) from TryResizeView()
   697 #endif
   698 }
   699 
   700 void
   701 WINRT_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   702 {
   703 #if NTDDI_VERSION >= NTDDI_WIN10
   704     SDL_WindowData * data = (SDL_WindowData *)window->driverdata;
   705     bool isWindowActive = WINRT_IsCoreWindowActive(data->coreWindow.Get());
   706     if (isWindowActive) {
   707         if (fullscreen) {
   708             if (!data->appView->IsFullScreenMode) {
   709                 data->appView->TryEnterFullScreenMode();    // TODO, WinRT: return failure (to caller?) from TryEnterFullScreenMode()
   710             }
   711         } else {
   712             if (data->appView->IsFullScreenMode) {
   713                 data->appView->ExitFullScreenMode();
   714             }
   715         }
   716     }
   717 #endif
   718 }
   719 
   720 
   721 void
   722 WINRT_DestroyWindow(_THIS, SDL_Window * window)
   723 {
   724     SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
   725 
   726     if (WINRT_GlobalSDLWindow == window) {
   727         WINRT_GlobalSDLWindow = NULL;
   728     }
   729 
   730     if (data) {
   731         // Delete the internal window data:
   732         delete data;
   733         data = NULL;
   734         window->driverdata = NULL;
   735     }
   736 }
   737 
   738 SDL_bool
   739 WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   740 {
   741     SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
   742 
   743     if (info->version.major <= SDL_MAJOR_VERSION) {
   744         info->subsystem = SDL_SYSWM_WINRT;
   745         info->info.winrt.window = reinterpret_cast<IInspectable *>(data->coreWindow.Get());
   746         return SDL_TRUE;
   747     } else {
   748         SDL_SetError("Application not compiled with SDL %d.%d\n",
   749                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   750         return SDL_FALSE;
   751     }
   752     return SDL_FALSE;
   753 }
   754 
   755 #endif /* SDL_VIDEO_DRIVER_WINRT */
   756 
   757 /* vi: set ts=4 sw=4 expandtab: */