src/video/winrt/SDL_winrtvideo.cpp
author Sam Lantinga
Sat, 02 Jan 2016 10:10:34 -0800
changeset 9998 f67cf37e9cd4
parent 9993 e05d46c27ce3
child 10112 f3c18811079d
permissions -rw-r--r--
Updated copyright to 2016
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 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 // TODO, WinRT: consider removing WINRT_UpdateWindowFlags, and just calling WINRT_DetectWindowFlags as-appropriate (with appropriate calls to SDL_SendWindowEvent)
   496 void
   497 WINRT_UpdateWindowFlags(SDL_Window * window, Uint32 mask)
   498 {
   499     mask &= WINRT_DetectableFlags;
   500     if (window) {
   501         Uint32 apply = WINRT_DetectWindowFlags(window);
   502         if ((apply & mask) & SDL_WINDOW_FULLSCREEN) {
   503             window->last_fullscreen_flags = window->flags;  // seems necessary to programmatically un-fullscreen, via SDL APIs
   504         }
   505         window->flags = (window->flags & ~mask) | (apply & mask);
   506     }
   507 }
   508 
   509 static bool
   510 WINRT_IsCoreWindowActive(CoreWindow ^ coreWindow)
   511 {
   512     /* WinRT does not appear to offer API(s) to determine window-activation state,
   513        at least not that I am aware of in Win8 - Win10.  As such, SDL tracks this
   514        itself, via window-activation events.
   515        
   516        If there *is* an API to track this, it should probably get used instead
   517        of the following hack (that uses "SDLHelperWindowActivationState").
   518          -- DavidL.
   519     */
   520     if (coreWindow->CustomProperties->HasKey("SDLHelperWindowActivationState")) {
   521         CoreWindowActivationState activationState = \
   522             safe_cast<CoreWindowActivationState>(coreWindow->CustomProperties->Lookup("SDLHelperWindowActivationState"));
   523         return (activationState != CoreWindowActivationState::Deactivated);
   524     }
   525 
   526     /* Assume that non-SDL tracked windows are active, although this should
   527        probably be avoided, if possible.
   528        
   529        This might not even be possible, in normal SDL use, at least as of
   530        this writing (Dec 22, 2015; via latest hg.libsdl.org/SDL clone)  -- DavidL
   531     */
   532     return true;
   533 }
   534 
   535 int
   536 WINRT_CreateWindow(_THIS, SDL_Window * window)
   537 {
   538     // Make sure that only one window gets created, at least until multimonitor
   539     // support is added.
   540     if (WINRT_GlobalSDLWindow != NULL) {
   541         SDL_SetError("WinRT only supports one window");
   542         return -1;
   543     }
   544 
   545     SDL_WindowData *data = new SDL_WindowData;  /* use 'new' here as SDL_WindowData may use WinRT/C++ types */
   546     if (!data) {
   547         SDL_OutOfMemory();
   548         return -1;
   549     }
   550     window->driverdata = data;
   551     data->sdlWindow = window;
   552 
   553     /* To note, when XAML support is enabled, access to the CoreWindow will not
   554        be possible, at least not via the SDL/XAML thread.  Attempts to access it
   555        from there will throw exceptions.  As such, the SDL_WindowData's
   556        'coreWindow' field will only be set (to a non-null value) if XAML isn't
   557        enabled.
   558     */
   559     if (!WINRT_XAMLWasEnabled) {
   560         data->coreWindow = CoreWindow::GetForCurrentThread();
   561 #if SDL_WINRT_USE_APPLICATIONVIEW
   562         data->appView = ApplicationView::GetForCurrentView();
   563 #endif
   564     }
   565 
   566     /* Make note of the requested window flags, before they start getting changed. */
   567     const Uint32 requestedFlags = window->flags;
   568 
   569 #if SDL_VIDEO_OPENGL_EGL
   570     /* Setup the EGL surface, but only if OpenGL ES 2 was requested. */
   571     if (!(window->flags & SDL_WINDOW_OPENGL)) {
   572         /* OpenGL ES 2 wasn't requested.  Don't set up an EGL surface. */
   573         data->egl_surface = EGL_NO_SURFACE;
   574     } else {
   575         /* OpenGL ES 2 was reuqested.  Set up an EGL surface. */
   576         SDL_VideoData * video_data = (SDL_VideoData *)_this->driverdata;
   577 
   578         /* Call SDL_EGL_ChooseConfig and eglCreateWindowSurface directly,
   579          * rather than via SDL_EGL_CreateSurface, as older versions of
   580          * ANGLE/WinRT may require that a C++ object, ComPtr<IUnknown>,
   581          * be passed into eglCreateWindowSurface.
   582          */
   583         if (SDL_EGL_ChooseConfig(_this) != 0) {
   584             char buf[512];
   585             SDL_snprintf(buf, sizeof(buf), "SDL_EGL_ChooseConfig failed: %s", SDL_GetError());
   586             return SDL_SetError("%s", buf);
   587         }
   588 
   589         if (video_data->winrtEglWindow) {   /* ... is the 'old' version of ANGLE/WinRT being used? */
   590             /* Attempt to create a window surface using older versions of
   591              * ANGLE/WinRT:
   592              */
   593             Microsoft::WRL::ComPtr<IUnknown> cpp_winrtEglWindow = video_data->winrtEglWindow;
   594             data->egl_surface = ((eglCreateWindowSurface_Old_Function)_this->egl_data->eglCreateWindowSurface)(
   595                 _this->egl_data->egl_display,
   596                 _this->egl_data->egl_config,
   597                 cpp_winrtEglWindow, NULL);
   598             if (data->egl_surface == NULL) {
   599                 return SDL_SetError("eglCreateWindowSurface failed");
   600             }
   601         } else if (data->coreWindow.Get() != nullptr) {
   602             /* Attempt to create a window surface using newer versions of
   603              * ANGLE/WinRT:
   604              */
   605             IInspectable * coreWindowAsIInspectable = reinterpret_cast<IInspectable *>(data->coreWindow.Get());
   606             data->egl_surface = _this->egl_data->eglCreateWindowSurface(
   607                 _this->egl_data->egl_display,
   608                 _this->egl_data->egl_config,
   609                 coreWindowAsIInspectable,
   610                 NULL);
   611             if (data->egl_surface == NULL) {
   612                 return SDL_SetError("eglCreateWindowSurface failed");
   613             }
   614         } else {
   615             return SDL_SetError("No supported means to create an EGL window surface are available");
   616         }
   617     }
   618 #endif
   619 
   620     /* Determine as many flags dynamically, as possible. */
   621     window->flags =
   622         SDL_WINDOW_BORDERLESS |
   623         SDL_WINDOW_RESIZABLE;
   624 
   625 #if SDL_VIDEO_OPENGL_EGL
   626     if (data->egl_surface) {
   627         window->flags |= SDL_WINDOW_OPENGL;
   628     }
   629 #endif
   630 
   631     if (WINRT_XAMLWasEnabled) {
   632         /* TODO, WinRT: set SDL_Window size, maybe position too, from XAML control */
   633         window->x = 0;
   634         window->y = 0;
   635         window->flags |= SDL_WINDOW_SHOWN;
   636         SDL_SetMouseFocus(NULL);        // TODO: detect this
   637         SDL_SetKeyboardFocus(NULL);     // TODO: detect this
   638     } else {
   639         /* WinRT 8.x apps seem to live in an environment where the OS controls the
   640            app's window size, with some apps being fullscreen, depending on
   641            user choice of various things.  For now, just adapt the SDL_Window to
   642            whatever Windows set-up as the native-window's geometry.
   643         */
   644         window->x = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Left);
   645         window->y = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Top);
   646 #if NTDDI_VERSION < NTDDI_WIN10
   647         /* On WinRT 8.x / pre-Win10, just use the size we were given. */
   648         window->w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
   649         window->h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
   650 #else
   651         /* On Windows 10, we occasionally get control over window size.  For windowed
   652            mode apps, try this.
   653         */
   654         bool didSetSize = false;
   655         if (!(requestedFlags & SDL_WINDOW_FULLSCREEN)) {
   656             const Windows::Foundation::Size size(WINRT_PHYSICAL_PIXELS_TO_DIPS(window->w),
   657                                                  WINRT_PHYSICAL_PIXELS_TO_DIPS(window->h));
   658             didSetSize = data->appView->TryResizeView(size);
   659         }
   660         if (!didSetSize) {
   661             /* We either weren't able to set the window size, or a request for
   662                fullscreen was made.  Get window-size info from the OS.
   663             */
   664             window->w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
   665             window->h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
   666         }
   667 #endif
   668 
   669         WINRT_UpdateWindowFlags(
   670             window,
   671             0xffffffff      /* Update any window flag(s) that WINRT_UpdateWindow can handle */
   672         );
   673 
   674         /* Try detecting if the window is active */
   675         bool isWindowActive = WINRT_IsCoreWindowActive(data->coreWindow.Get());
   676         if (isWindowActive) {
   677             SDL_SetKeyboardFocus(window);
   678         }
   679     }
   680  
   681     /* Make sure the WinRT app's IFramworkView can post events on
   682        behalf of SDL:
   683     */
   684     WINRT_GlobalSDLWindow = window;
   685 
   686     /* All done! */
   687     return 0;
   688 }
   689 
   690 void
   691 WINRT_SetWindowSize(_THIS, SDL_Window * window)
   692 {
   693 #if NTDDI_VERSION >= NTDDI_WIN10
   694     SDL_WindowData * data = (SDL_WindowData *)window->driverdata;
   695     const Windows::Foundation::Size size(WINRT_PHYSICAL_PIXELS_TO_DIPS(window->w),
   696                                          WINRT_PHYSICAL_PIXELS_TO_DIPS(window->h));
   697     data->appView->TryResizeView(size); // TODO, WinRT: return failure (to caller?) from TryResizeView()
   698 #endif
   699 }
   700 
   701 void
   702 WINRT_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen)
   703 {
   704 #if NTDDI_VERSION >= NTDDI_WIN10
   705     SDL_WindowData * data = (SDL_WindowData *)window->driverdata;
   706     bool isWindowActive = WINRT_IsCoreWindowActive(data->coreWindow.Get());
   707     if (isWindowActive) {
   708         if (fullscreen) {
   709             if (!data->appView->IsFullScreenMode) {
   710                 data->appView->TryEnterFullScreenMode();    // TODO, WinRT: return failure (to caller?) from TryEnterFullScreenMode()
   711             }
   712         } else {
   713             if (data->appView->IsFullScreenMode) {
   714                 data->appView->ExitFullScreenMode();
   715             }
   716         }
   717     }
   718 #endif
   719 }
   720 
   721 
   722 void
   723 WINRT_DestroyWindow(_THIS, SDL_Window * window)
   724 {
   725     SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
   726 
   727     if (WINRT_GlobalSDLWindow == window) {
   728         WINRT_GlobalSDLWindow = NULL;
   729     }
   730 
   731     if (data) {
   732         // Delete the internal window data:
   733         delete data;
   734         data = NULL;
   735         window->driverdata = NULL;
   736     }
   737 }
   738 
   739 SDL_bool
   740 WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
   741 {
   742     SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
   743 
   744     if (info->version.major <= SDL_MAJOR_VERSION) {
   745         info->subsystem = SDL_SYSWM_WINRT;
   746         info->info.winrt.window = reinterpret_cast<IInspectable *>(data->coreWindow.Get());
   747         return SDL_TRUE;
   748     } else {
   749         SDL_SetError("Application not compiled with SDL %d.%d\n",
   750                      SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   751         return SDL_FALSE;
   752     }
   753     return SDL_FALSE;
   754 }
   755 
   756 #endif /* SDL_VIDEO_DRIVER_WINRT */
   757 
   758 /* vi: set ts=4 sw=4 expandtab: */