src/video/winrt/SDL_winrtvideo.cpp
author David Ludwig <dludwig@pobox.com>
Thu, 26 Nov 2015 00:41:39 -0500
changeset 9924 355cccccc7dc
parent 9619 b94b6d0bff0f
child 9925 2be74843315c
permissions -rw-r--r--
WinRT: lots of display and windowing related fixes

This change-set fixes a lot of windowing related bugs, especially with
regards to Windows 8.x apps running on Windows 10 (which was the driver for
this work). The primary fixes include:
* listed display modes were wrong, especially when launching apps into a
non-fullscreen space
* reported window flags were often wrong, especially on Windows 10
* fullscreen/windowed mode switches weren't failing (they are not
programmatically possible in Win 8.x apps).
dludwig@8327
     1
/*
dludwig@8327
     2
  Simple DirectMedia Layer
slouken@9619
     3
  Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
dludwig@8327
     4
dludwig@8327
     5
  This software is provided 'as-is', without any express or implied
dludwig@8327
     6
  warranty.  In no event will the authors be held liable for any damages
dludwig@8327
     7
  arising from the use of this software.
dludwig@8327
     8
dludwig@8327
     9
  Permission is granted to anyone to use this software for any purpose,
dludwig@8327
    10
  including commercial applications, and to alter it and redistribute it
dludwig@8327
    11
  freely, subject to the following restrictions:
dludwig@8327
    12
dludwig@8327
    13
  1. The origin of this software must not be misrepresented; you must not
dludwig@8327
    14
     claim that you wrote the original software. If you use this software
dludwig@8327
    15
     in a product, an acknowledgment in the product documentation would be
dludwig@8327
    16
     appreciated but is not required.
dludwig@8327
    17
  2. Altered source versions must be plainly marked as such, and must not be
dludwig@8327
    18
     misrepresented as being the original software.
dludwig@8327
    19
  3. This notice may not be removed or altered from any source distribution.
dludwig@8327
    20
*/
dludwig@8600
    21
#include "../../SDL_internal.h"
dludwig@8327
    22
dludwig@8327
    23
#if SDL_VIDEO_DRIVER_WINRT
dludwig@8327
    24
dludwig@8327
    25
/* WinRT SDL video driver implementation
dludwig@8327
    26
dludwig@8327
    27
   Initial work on this was done by David Ludwig (dludwig@pobox.com), and
dludwig@8327
    28
   was based off of SDL's "dummy" video driver.
dludwig@8327
    29
 */
dludwig@8327
    30
dludwig@8494
    31
/* Windows includes */
dludwig@8494
    32
#include <agile.h>
dludwig@9924
    33
#include <windows.graphics.display.h>
dludwig@9924
    34
#include <dxgi.h>
dludwig@9924
    35
#include <dxgi1_2.h>
dludwig@9924
    36
using namespace Windows::ApplicationModel::Core;
dludwig@9924
    37
using namespace Windows::Foundation;
dludwig@8494
    38
using namespace Windows::UI::Core;
dludwig@9924
    39
using namespace Windows::UI::ViewManagement;
dludwig@9924
    40
dludwig@9924
    41
dludwig@9924
    42
/* [re]declare Windows GUIDs locally, to limit the amount of external lib(s) SDL has to link to */
dludwig@9924
    43
static const GUID IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48,{ 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } };
dludwig@8494
    44
dludwig@8494
    45
dludwig@8494
    46
/* SDL includes */
dludwig@8329
    47
extern "C" {
dludwig@8327
    48
#include "SDL_video.h"
dludwig@8327
    49
#include "SDL_mouse.h"
dludwig@8327
    50
#include "../SDL_sysvideo.h"
dludwig@8327
    51
#include "../SDL_pixels_c.h"
dludwig@8327
    52
#include "../../events/SDL_events_c.h"
dludwig@8400
    53
#include "../../render/SDL_sysrender.h"
dludwig@8411
    54
#include "SDL_syswm.h"
dludwig@8541
    55
#include "SDL_winrtopengles.h"
dludwig@9924
    56
#include "../../core/windows/SDL_windows.h"
dludwig@8329
    57
}
dludwig@8327
    58
dludwig@8522
    59
#include "../../core/winrt/SDL_winrtapp_direct3d.h"
dludwig@8522
    60
#include "../../core/winrt/SDL_winrtapp_xaml.h"
dludwig@8512
    61
#include "SDL_winrtvideo_cpp.h"
dludwig@8327
    62
#include "SDL_winrtevents_c.h"
dludwig@8516
    63
#include "SDL_winrtmouse_c.h"
dludwig@8505
    64
#include "SDL_main.h"
dludwig@8505
    65
#include "SDL_system.h"
dludwig@8755
    66
//#include "SDL_log.h"
dludwig@8327
    67
dludwig@8327
    68
dludwig@8327
    69
/* Initialization/Query functions */
dludwig@8327
    70
static int WINRT_VideoInit(_THIS);
dludwig@8374
    71
static int WINRT_InitModes(_THIS);
dludwig@8327
    72
static int WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
dludwig@8327
    73
static void WINRT_VideoQuit(_THIS);
dludwig@8327
    74
dludwig@8494
    75
dludwig@8333
    76
/* Window functions */
dludwig@8522
    77
static int WINRT_CreateWindow(_THIS, SDL_Window * window);
dludwig@8333
    78
static void WINRT_DestroyWindow(_THIS, SDL_Window * window);
dludwig@8411
    79
static SDL_bool WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info);
dludwig@8333
    80
dludwig@8494
    81
dludwig@8515
    82
/* SDL-internal globals: */
dludwig@8497
    83
SDL_Window * WINRT_GlobalSDLWindow = NULL;
dludwig@8498
    84
dludwig@8498
    85
dludwig@8327
    86
/* WinRT driver bootstrap functions */
dludwig@8327
    87
dludwig@8327
    88
static int
dludwig@8327
    89
WINRT_Available(void)
dludwig@8327
    90
{
dludwig@8328
    91
    return (1);
dludwig@8327
    92
}
dludwig@8327
    93
dludwig@8327
    94
static void
dludwig@8327
    95
WINRT_DeleteDevice(SDL_VideoDevice * device)
dludwig@8327
    96
{
dludwig@8663
    97
    if (device->driverdata) {
dludwig@8663
    98
        SDL_VideoData * video_data = (SDL_VideoData *)device->driverdata;
dludwig@8663
    99
        if (video_data->winrtEglWindow) {
dludwig@8663
   100
            video_data->winrtEglWindow->Release();
dludwig@8663
   101
        }
dludwig@8663
   102
        SDL_free(video_data);
dludwig@8663
   103
    }
dludwig@8663
   104
dludwig@8327
   105
    SDL_free(device);
dludwig@8327
   106
}
dludwig@8327
   107
dludwig@8327
   108
static SDL_VideoDevice *
dludwig@8327
   109
WINRT_CreateDevice(int devindex)
dludwig@8327
   110
{
dludwig@8327
   111
    SDL_VideoDevice *device;
dludwig@8663
   112
    SDL_VideoData *data;
dludwig@8327
   113
dludwig@8327
   114
    /* Initialize all variables that we clean on shutdown */
dludwig@8327
   115
    device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
dludwig@8327
   116
    if (!device) {
dludwig@8327
   117
        SDL_OutOfMemory();
dludwig@8327
   118
        if (device) {
dludwig@8327
   119
            SDL_free(device);
dludwig@8327
   120
        }
dludwig@8327
   121
        return (0);
dludwig@8327
   122
    }
dludwig@8327
   123
dludwig@8663
   124
    data = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
dludwig@8663
   125
    if (!data) {
dludwig@8663
   126
        SDL_OutOfMemory();
dludwig@8663
   127
        return (0);
dludwig@8663
   128
    }
dludwig@8663
   129
    SDL_zerop(data);
dludwig@8663
   130
    device->driverdata = data;
dludwig@8663
   131
dludwig@8327
   132
    /* Set the function pointers */
dludwig@8327
   133
    device->VideoInit = WINRT_VideoInit;
dludwig@8327
   134
    device->VideoQuit = WINRT_VideoQuit;
dludwig@8333
   135
    device->CreateWindow = WINRT_CreateWindow;
dludwig@8333
   136
    device->DestroyWindow = WINRT_DestroyWindow;
dludwig@8327
   137
    device->SetDisplayMode = WINRT_SetDisplayMode;
dludwig@8327
   138
    device->PumpEvents = WINRT_PumpEvents;
dludwig@8411
   139
    device->GetWindowWMInfo = WINRT_GetWindowWMInfo;
dludwig@8541
   140
#ifdef SDL_VIDEO_OPENGL_EGL
slouken@8582
   141
    device->GL_LoadLibrary = WINRT_GLES_LoadLibrary;
slouken@8582
   142
    device->GL_GetProcAddress = WINRT_GLES_GetProcAddress;
slouken@8582
   143
    device->GL_UnloadLibrary = WINRT_GLES_UnloadLibrary;
slouken@8582
   144
    device->GL_CreateContext = WINRT_GLES_CreateContext;
slouken@8582
   145
    device->GL_MakeCurrent = WINRT_GLES_MakeCurrent;
slouken@8582
   146
    device->GL_SetSwapInterval = WINRT_GLES_SetSwapInterval;
slouken@8582
   147
    device->GL_GetSwapInterval = WINRT_GLES_GetSwapInterval;
slouken@8582
   148
    device->GL_SwapWindow = WINRT_GLES_SwapWindow;
dludwig@8541
   149
    device->GL_DeleteContext = WINRT_GLES_DeleteContext;
dludwig@8541
   150
#endif
dludwig@8433
   151
    device->free = WINRT_DeleteDevice;
dludwig@8327
   152
dludwig@8327
   153
    return device;
dludwig@8327
   154
}
dludwig@8327
   155
dludwig@8494
   156
#define WINRTVID_DRIVER_NAME "winrt"
dludwig@8327
   157
VideoBootStrap WINRT_bootstrap = {
dludwig@8500
   158
    WINRTVID_DRIVER_NAME, "SDL WinRT video driver",
dludwig@8327
   159
    WINRT_Available, WINRT_CreateDevice
dludwig@8327
   160
};
dludwig@8327
   161
dludwig@8327
   162
int
dludwig@8327
   163
WINRT_VideoInit(_THIS)
dludwig@8327
   164
{
dludwig@8374
   165
    if (WINRT_InitModes(_this) < 0) {
dludwig@8374
   166
        return -1;
dludwig@8374
   167
    }
dludwig@8374
   168
    WINRT_InitMouse(_this);
dludwig@8515
   169
    WINRT_InitTouch(_this);
dludwig@8522
   170
dludwig@8374
   171
    return 0;
dludwig@8374
   172
}
dludwig@8374
   173
dludwig@9924
   174
extern "C"
dludwig@9924
   175
Uint32 D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat);
dludwig@9924
   176
dludwig@9924
   177
static void
dludwig@9924
   178
WINRT_DXGIModeToSDLDisplayMode(const DXGI_MODE_DESC * dxgiMode, SDL_DisplayMode * sdlMode)
dludwig@8522
   179
{
dludwig@9924
   180
    SDL_zerop(sdlMode);
dludwig@9924
   181
    sdlMode->w = dxgiMode->Width;
dludwig@9924
   182
    sdlMode->h = dxgiMode->Height;
dludwig@9924
   183
    sdlMode->refresh_rate = dxgiMode->RefreshRate.Numerator / dxgiMode->RefreshRate.Denominator;
dludwig@9924
   184
    sdlMode->format = D3D11_DXGIFormatToSDLPixelFormat(dxgiMode->Format);
dludwig@9924
   185
}
dludwig@8578
   186
dludwig@9924
   187
static int
dludwig@9924
   188
WINRT_AddDisplaysForOutput (_THIS, IDXGIAdapter1 * dxgiAdapter1, int outputIndex)
dludwig@9924
   189
{
dludwig@9924
   190
    HRESULT hr;
dludwig@9924
   191
    IDXGIOutput * dxgiOutput = NULL;
dludwig@9924
   192
    DXGI_OUTPUT_DESC dxgiOutputDesc;
dludwig@9924
   193
    SDL_VideoDisplay display;
dludwig@9924
   194
    char * displayName = NULL;
dludwig@9924
   195
    UINT numModes;
dludwig@9924
   196
    DXGI_MODE_DESC * dxgiModes = NULL;
dludwig@9924
   197
    int functionResult = -1;        /* -1 for failure, 0 for success */
dludwig@9924
   198
    DXGI_MODE_DESC modeToMatch, closestMatch;
dludwig@8522
   199
dludwig@9924
   200
    SDL_zero(display);
dludwig@9924
   201
dludwig@9924
   202
    hr = dxgiAdapter1->EnumOutputs(outputIndex, &dxgiOutput);
dludwig@9924
   203
    if (FAILED(hr)) {
dludwig@9924
   204
        if (hr != DXGI_ERROR_NOT_FOUND) {
dludwig@9924
   205
            WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIAdapter1::EnumOutputs failed", hr);
dludwig@9924
   206
        }
dludwig@9924
   207
        goto done;
dludwig@8522
   208
    }
dludwig@8522
   209
dludwig@9924
   210
    hr = dxgiOutput->GetDesc(&dxgiOutputDesc);
dludwig@9924
   211
    if (FAILED(hr)) {
dludwig@9924
   212
        WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDesc failed", hr);
dludwig@9924
   213
        goto done;
dludwig@8579
   214
    }
dludwig@8579
   215
dludwig@9924
   216
    SDL_zero(modeToMatch);
dludwig@9924
   217
    modeToMatch.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
dludwig@9924
   218
    modeToMatch.Width = (dxgiOutputDesc.DesktopCoordinates.right - dxgiOutputDesc.DesktopCoordinates.left);
dludwig@9924
   219
    modeToMatch.Height = (dxgiOutputDesc.DesktopCoordinates.bottom - dxgiOutputDesc.DesktopCoordinates.top);
dludwig@9924
   220
    hr = dxgiOutput->FindClosestMatchingMode(&modeToMatch, &closestMatch, NULL);
dludwig@9924
   221
    if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
dludwig@9924
   222
        /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE gets returned by IDXGIOutput::FindClosestMatchingMode
dludwig@9924
   223
           when running under the Windows Simulator, which uses Remote Desktop (formerly known as Terminal
dludwig@9924
   224
           Services) under the hood.  According to the MSDN docs for the similar function,
dludwig@9924
   225
           IDXGIOutput::GetDisplayModeList, DXGI_ERROR_NOT_CURRENTLY_AVAILABLE is returned if and
dludwig@9924
   226
           when an app is run under a Terminal Services session, hence the assumption.
dludwig@9924
   227
dludwig@9924
   228
           In this case, just add an SDL display mode, with approximated values.
dludwig@9924
   229
        */
dludwig@9924
   230
        SDL_DisplayMode mode;
dludwig@9924
   231
        SDL_zero(mode);
dludwig@9924
   232
        display.name = "Windows Simulator / Terminal Services Display";
dludwig@9924
   233
        mode.w = (dxgiOutputDesc.DesktopCoordinates.right - dxgiOutputDesc.DesktopCoordinates.left);
dludwig@9924
   234
        mode.h = (dxgiOutputDesc.DesktopCoordinates.bottom - dxgiOutputDesc.DesktopCoordinates.top);
dludwig@9924
   235
        mode.format = DXGI_FORMAT_B8G8R8A8_UNORM;
dludwig@9924
   236
        mode.refresh_rate = 0;  /* Display mode is unknown, so just fill in zero, as specified by SDL's header files */
dludwig@9924
   237
        display.desktop_mode = mode;
dludwig@9924
   238
        display.current_mode = mode;
dludwig@9924
   239
        if ( ! SDL_AddDisplayMode(&display, &mode)) {
dludwig@9924
   240
            goto done;
dludwig@9924
   241
        }
dludwig@9924
   242
    } else if (FAILED(hr)) {
dludwig@9924
   243
        WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::FindClosestMatchingMode failed", hr);
dludwig@9924
   244
        goto done;
dludwig@9924
   245
    } else {
dludwig@9924
   246
        displayName = WIN_StringToUTF8(dxgiOutputDesc.DeviceName);
dludwig@9924
   247
        display.name = displayName;
dludwig@9924
   248
        WINRT_DXGIModeToSDLDisplayMode(&closestMatch, &display.desktop_mode);
dludwig@9924
   249
        display.current_mode = display.desktop_mode;
dludwig@9924
   250
dludwig@9924
   251
        hr = dxgiOutput->GetDisplayModeList(DXGI_FORMAT_B8G8R8A8_UNORM, 0, &numModes, NULL);
dludwig@9924
   252
        if (FAILED(hr)) {
dludwig@9924
   253
            if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) {
dludwig@9924
   254
                // TODO, WinRT: make sure display mode(s) are added when using Terminal Services / Windows Simulator
dludwig@9924
   255
            }
dludwig@9924
   256
            WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDisplayModeList [get mode list size] failed", hr);
dludwig@9924
   257
            goto done;
dludwig@9924
   258
        }
dludwig@9924
   259
dludwig@9924
   260
        dxgiModes = (DXGI_MODE_DESC *)SDL_calloc(numModes, sizeof(DXGI_MODE_DESC));
dludwig@9924
   261
        if ( ! dxgiModes) {
dludwig@9924
   262
            SDL_OutOfMemory();
dludwig@9924
   263
            goto done;
dludwig@9924
   264
        }
dludwig@9924
   265
dludwig@9924
   266
        hr = dxgiOutput->GetDisplayModeList(DXGI_FORMAT_B8G8R8A8_UNORM, 0, &numModes, dxgiModes);
dludwig@9924
   267
        if (FAILED(hr)) {
dludwig@9924
   268
            WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDisplayModeList [get mode contents] failed", hr);
dludwig@9924
   269
            goto done;
dludwig@9924
   270
        }
dludwig@9924
   271
dludwig@9924
   272
        for (UINT i = 0; i < numModes; ++i) {
dludwig@9924
   273
            SDL_DisplayMode sdlMode;
dludwig@9924
   274
            WINRT_DXGIModeToSDLDisplayMode(&dxgiModes[i], &sdlMode);
dludwig@9924
   275
            SDL_AddDisplayMode(&display, &sdlMode);
dludwig@9924
   276
        }
dludwig@8578
   277
    }
dludwig@8578
   278
dludwig@9924
   279
    if (SDL_AddVideoDisplay(&display) < 0) {
dludwig@9924
   280
        goto done;
dludwig@9924
   281
    }
dludwig@8522
   282
dludwig@9924
   283
    functionResult = 0;     /* 0 for Success! */
dludwig@9924
   284
done:
dludwig@9924
   285
    if (dxgiModes) {
dludwig@9924
   286
        SDL_free(dxgiModes);
dludwig@9924
   287
    }
dludwig@9924
   288
    if (dxgiOutput) {
dludwig@9924
   289
        dxgiOutput->Release();
dludwig@9924
   290
    }
dludwig@9924
   291
    if (displayName) {
dludwig@9924
   292
        SDL_free(displayName);
dludwig@9924
   293
    }
dludwig@9924
   294
    return functionResult;
dludwig@9924
   295
}
dludwig@9924
   296
dludwig@9924
   297
static int
dludwig@9924
   298
WINRT_AddDisplaysForAdapter (_THIS, IDXGIFactory2 * dxgiFactory2, int adapterIndex)
dludwig@9924
   299
{
dludwig@9924
   300
    HRESULT hr;
dludwig@9924
   301
    IDXGIAdapter1 * dxgiAdapter1;
dludwig@9924
   302
dludwig@9924
   303
    hr = dxgiFactory2->EnumAdapters1(adapterIndex, &dxgiAdapter1);
dludwig@9924
   304
    if (FAILED(hr)) {
dludwig@9924
   305
        if (hr != DXGI_ERROR_NOT_FOUND) {
dludwig@9924
   306
            WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory1::EnumAdapters1() failed", hr);
dludwig@9924
   307
        }
dludwig@9924
   308
        return -1;
dludwig@9924
   309
    }
dludwig@9924
   310
dludwig@9924
   311
    for (int outputIndex = 0; ; ++outputIndex) {
dludwig@9924
   312
        if (WINRT_AddDisplaysForOutput(_this, dxgiAdapter1, outputIndex) < 0) {
dludwig@8522
   313
            break;
dludwig@8522
   314
        }
dludwig@9924
   315
    }
dludwig@8522
   316
dludwig@9924
   317
    dxgiAdapter1->Release();
dludwig@8578
   318
    return 0;
dludwig@8522
   319
}
dludwig@8503
   320
dludwig@8505
   321
int
dludwig@8374
   322
WINRT_InitModes(_THIS)
dludwig@8374
   323
{
dludwig@9924
   324
    /* HACK: Initialize a single display, for whatever screen the app's
dludwig@9924
   325
         CoreApplicationView is on.
dludwig@9924
   326
       TODO, WinRT: Try initializing multiple displays, one for each monitor.
dludwig@9924
   327
         Appropriate WinRT APIs for this seem elusive, though.  -- DavidL
dludwig@9924
   328
    */
dludwig@8522
   329
dludwig@9924
   330
    HRESULT hr;
dludwig@9924
   331
    IDXGIFactory2 * dxgiFactory2 = NULL;
dludwig@9924
   332
dludwig@9924
   333
    hr = CreateDXGIFactory1(IID_IDXGIFactory2, (void **)&dxgiFactory2);
dludwig@9924
   334
    if (FAILED(hr)) {
dludwig@9924
   335
        WIN_SetErrorFromHRESULT(__FUNCTION__ ", CreateDXGIFactory1() failed", hr);
dludwig@8522
   336
        return -1;
dludwig@8374
   337
    }
dludwig@8374
   338
dludwig@9924
   339
    int adapterIndex = 0;
dludwig@9924
   340
    for (int adapterIndex = 0; ; ++adapterIndex) {
dludwig@9924
   341
        if (WINRT_AddDisplaysForAdapter(_this, dxgiFactory2, adapterIndex) < 0) {
dludwig@9924
   342
            break;
dludwig@9924
   343
        }
dludwig@9924
   344
    }
dludwig@9924
   345
dludwig@8327
   346
    return 0;
dludwig@8327
   347
}
dludwig@8327
   348
dludwig@8327
   349
static int
dludwig@8327
   350
WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
dludwig@8327
   351
{
dludwig@8327
   352
    return 0;
dludwig@8327
   353
}
dludwig@8327
   354
dludwig@8327
   355
void
dludwig@8327
   356
WINRT_VideoQuit(_THIS)
dludwig@8327
   357
{
dludwig@8374
   358
    WINRT_QuitMouse(_this);
dludwig@8327
   359
}
dludwig@8327
   360
dludwig@9924
   361
extern "C" Uint32
dludwig@9924
   362
WINRT_DetectWindowFlags(SDL_Window * window)
dludwig@9924
   363
{
dludwig@9924
   364
    Uint32 latestFlags = 0;
dludwig@9924
   365
    SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
dludwig@9924
   366
    bool is_fullscreen = false;
dludwig@9924
   367
dludwig@9924
   368
#if SDL_WINRT_USE_APPLICATIONVIEW
dludwig@9924
   369
    if (data->appView) {
dludwig@9924
   370
        is_fullscreen = data->appView->IsFullScreen;
dludwig@9924
   371
    }
dludwig@9924
   372
#elif (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
dludwig@9924
   373
    is_fullscreen = true;
dludwig@9924
   374
#endif
dludwig@9924
   375
dludwig@9924
   376
    if (data->coreWindow.Get()) {
dludwig@9924
   377
        if (is_fullscreen) {
dludwig@9924
   378
            SDL_VideoDisplay * display = SDL_GetDisplayForWindow(window);
dludwig@9924
   379
            if (display->desktop_mode.w != WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width) ||
dludwig@9924
   380
                display->desktop_mode.h != WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height))
dludwig@9924
   381
            {
dludwig@9924
   382
                latestFlags |= SDL_WINDOW_MAXIMIZED;
dludwig@9924
   383
            } else {
dludwig@9924
   384
                latestFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
dludwig@9924
   385
            }
dludwig@9924
   386
        }
dludwig@9924
   387
dludwig@9924
   388
        if (data->coreWindow->Visible) {
dludwig@9924
   389
            latestFlags |= SDL_WINDOW_SHOWN;
dludwig@9924
   390
        } else {
dludwig@9924
   391
            latestFlags |= SDL_WINDOW_HIDDEN;
dludwig@9924
   392
        }
dludwig@9924
   393
dludwig@9924
   394
#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION < NTDDI_WINBLUE)
dludwig@9924
   395
        // data->coreWindow->PointerPosition is not supported on WinPhone 8.0
dludwig@9924
   396
        latestFlags |= SDL_WINDOW_MOUSE_FOCUS;
dludwig@9924
   397
#else
dludwig@9924
   398
        if (data->coreWindow->Bounds.Contains(data->coreWindow->PointerPosition)) {
dludwig@9924
   399
            latestFlags |= SDL_WINDOW_MOUSE_FOCUS;
dludwig@9924
   400
        }
dludwig@9924
   401
#endif
dludwig@9924
   402
    }
dludwig@9924
   403
dludwig@9924
   404
    return latestFlags;
dludwig@9924
   405
}
dludwig@9924
   406
dludwig@9924
   407
void
dludwig@9924
   408
WINRT_UpdateWindowFlags(SDL_Window * window, Uint32 mask)
dludwig@9924
   409
{
dludwig@9924
   410
    if (window) {
dludwig@9924
   411
        Uint32 apply = WINRT_DetectWindowFlags(window);
dludwig@9924
   412
        if ((apply & mask) & SDL_WINDOW_FULLSCREEN) {
dludwig@9924
   413
            window->last_fullscreen_flags = window->flags;  // seems necessary to programmatically un-fullscreen, via SDL APIs
dludwig@9924
   414
        }
dludwig@9924
   415
        window->flags = (window->flags & ~mask) | (apply & mask);
dludwig@9924
   416
    }
dludwig@9924
   417
}
dludwig@9924
   418
dludwig@8522
   419
int
dludwig@8522
   420
WINRT_CreateWindow(_THIS, SDL_Window * window)
dludwig@8522
   421
{
dludwig@8522
   422
    // Make sure that only one window gets created, at least until multimonitor
dludwig@8522
   423
    // support is added.
dludwig@8522
   424
    if (WINRT_GlobalSDLWindow != NULL) {
dludwig@8522
   425
        SDL_SetError("WinRT only supports one window");
dludwig@8522
   426
        return -1;
dludwig@8522
   427
    }
dludwig@8522
   428
dludwig@9924
   429
    SDL_WindowData *data = new SDL_WindowData;  /* use 'new' here as SDL_WindowData may use WinRT/C++ types */
dludwig@8522
   430
    if (!data) {
dludwig@8522
   431
        SDL_OutOfMemory();
dludwig@8522
   432
        return -1;
dludwig@8522
   433
    }
dludwig@8522
   434
    window->driverdata = data;
dludwig@8522
   435
    data->sdlWindow = window;
dludwig@8522
   436
dludwig@8522
   437
    /* To note, when XAML support is enabled, access to the CoreWindow will not
dludwig@8522
   438
       be possible, at least not via the SDL/XAML thread.  Attempts to access it
dludwig@8522
   439
       from there will throw exceptions.  As such, the SDL_WindowData's
dludwig@8522
   440
       'coreWindow' field will only be set (to a non-null value) if XAML isn't
dludwig@8522
   441
       enabled.
dludwig@8522
   442
    */
dludwig@8522
   443
    if (!WINRT_XAMLWasEnabled) {
dludwig@8522
   444
        data->coreWindow = CoreWindow::GetForCurrentThread();
dludwig@9924
   445
#if SDL_WINRT_USE_APPLICATIONVIEW
dludwig@9924
   446
        data->appView = ApplicationView::GetForCurrentView();
dludwig@9924
   447
#endif
dludwig@8522
   448
    }
dludwig@8522
   449
dludwig@8541
   450
#if SDL_VIDEO_OPENGL_EGL
dludwig@8541
   451
    /* Setup the EGL surface, but only if OpenGL ES 2 was requested. */
dludwig@8541
   452
    if (!(window->flags & SDL_WINDOW_OPENGL)) {
dludwig@8541
   453
        /* OpenGL ES 2 wasn't requested.  Don't set up an EGL surface. */
dludwig@8541
   454
        data->egl_surface = EGL_NO_SURFACE;
dludwig@8541
   455
    } else {
dludwig@8541
   456
        /* OpenGL ES 2 was reuqested.  Set up an EGL surface. */
dludwig@8663
   457
        SDL_VideoData * video_data = (SDL_VideoData *)_this->driverdata;
dludwig@8572
   458
dludwig@8663
   459
        /* Call SDL_EGL_ChooseConfig and eglCreateWindowSurface directly,
dludwig@9212
   460
         * rather than via SDL_EGL_CreateSurface, as older versions of
dludwig@9212
   461
         * ANGLE/WinRT may require that a C++ object, ComPtr<IUnknown>,
dludwig@9212
   462
         * be passed into eglCreateWindowSurface.
dludwig@8572
   463
         */
dludwig@8663
   464
        if (SDL_EGL_ChooseConfig(_this) != 0) {
dludwig@8663
   465
            char buf[512];
dludwig@8663
   466
            SDL_snprintf(buf, sizeof(buf), "SDL_EGL_ChooseConfig failed: %s", SDL_GetError());
philipp@9557
   467
            return SDL_SetError("%s", buf);
dludwig@8663
   468
        }
dludwig@8572
   469
dludwig@9211
   470
        if (video_data->winrtEglWindow) {   /* ... is the 'old' version of ANGLE/WinRT being used? */
dludwig@9211
   471
            /* Attempt to create a window surface using older versions of
dludwig@9211
   472
             * ANGLE/WinRT:
dludwig@9211
   473
             */
dludwig@9211
   474
            Microsoft::WRL::ComPtr<IUnknown> cpp_winrtEglWindow = video_data->winrtEglWindow;
dludwig@9211
   475
            data->egl_surface = ((eglCreateWindowSurface_Old_Function)_this->egl_data->eglCreateWindowSurface)(
dludwig@9211
   476
                _this->egl_data->egl_display,
dludwig@9211
   477
                _this->egl_data->egl_config,
dludwig@9211
   478
                cpp_winrtEglWindow, NULL);
dludwig@9211
   479
            if (data->egl_surface == NULL) {
dludwig@9211
   480
                return SDL_SetError("eglCreateWindowSurface failed");
dludwig@9211
   481
            }
dludwig@9211
   482
        } else if (data->coreWindow.Get() != nullptr) {
dludwig@9211
   483
            /* Attempt to create a window surface using newer versions of
dludwig@9211
   484
             * ANGLE/WinRT:
dludwig@9211
   485
             */
dludwig@9211
   486
            IInspectable * coreWindowAsIInspectable = reinterpret_cast<IInspectable *>(data->coreWindow.Get());
dludwig@9211
   487
            data->egl_surface = _this->egl_data->eglCreateWindowSurface(
dludwig@9211
   488
                _this->egl_data->egl_display,
dludwig@9211
   489
                _this->egl_data->egl_config,
dludwig@9211
   490
                coreWindowAsIInspectable,
dludwig@9211
   491
                NULL);
dludwig@9211
   492
            if (data->egl_surface == NULL) {
dludwig@9211
   493
                return SDL_SetError("eglCreateWindowSurface failed");
dludwig@9211
   494
            }
dludwig@9211
   495
        } else {
dludwig@9211
   496
            return SDL_SetError("No supported means to create an EGL window surface are available");
dludwig@8541
   497
        }
dludwig@8541
   498
    }
dludwig@8541
   499
#endif
dludwig@8541
   500
dludwig@9924
   501
#if SDL_WINRT_USE_APPLICATIONVIEW
dludwig@9924
   502
    /* Determine as many flags dynamically, as possible. */
dludwig@8522
   503
    window->flags =
dludwig@9924
   504
        SDL_WINDOW_BORDERLESS;
dludwig@9924
   505
#else
dludwig@9924
   506
    /* Set SDL_Window flags for Windows Phone 8.0 */
dludwig@9924
   507
    window->flags =
dludwig@9924
   508
        SDL_WINDOW_FULLSCREEN_DESKTOP |
dludwig@8522
   509
        SDL_WINDOW_BORDERLESS |
dludwig@8522
   510
        SDL_WINDOW_MAXIMIZED |
dludwig@8522
   511
        SDL_WINDOW_INPUT_GRABBED;
dludwig@9924
   512
#endif
dludwig@8522
   513
dludwig@8541
   514
#if SDL_VIDEO_OPENGL_EGL
dludwig@8541
   515
    if (data->egl_surface) {
dludwig@8541
   516
        window->flags |= SDL_WINDOW_OPENGL;
dludwig@8541
   517
    }
dludwig@8541
   518
#endif
dludwig@8541
   519
dludwig@9924
   520
    if (WINRT_XAMLWasEnabled) {
dludwig@9924
   521
        /* TODO, WinRT: set SDL_Window size, maybe position too, from XAML control */
dludwig@9924
   522
        window->x = 0;
dludwig@9924
   523
        window->y = 0;
dludwig@9924
   524
        window->flags |= SDL_WINDOW_SHOWN;
dludwig@9924
   525
        SDL_SetMouseFocus(NULL);        // TODO: detect this
dludwig@9924
   526
        SDL_SetKeyboardFocus(NULL);     // TODO: detect this
dludwig@9924
   527
    } else {
dludwig@9924
   528
        /* WinRT apps seem to live in an environment where the OS controls the
dludwig@9924
   529
           app's window size, with some apps being fullscreen, depending on
dludwig@9924
   530
           user choice of various things.  For now, just adapt the SDL_Window to
dludwig@9924
   531
           whatever Windows set-up as the native-window's geometry.
dludwig@9924
   532
        */
dludwig@9924
   533
        window->x = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Left);
dludwig@9924
   534
        window->y = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Top);
dludwig@9924
   535
        window->w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
dludwig@9924
   536
        window->h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
dludwig@8522
   537
dludwig@9924
   538
        WINRT_UpdateWindowFlags(
dludwig@9924
   539
            window,
dludwig@9924
   540
            0xffffffff      /* Update any window flag(s) that WINRT_UpdateWindow can handle */
dludwig@9924
   541
        );
dludwig@8551
   542
dludwig@9924
   543
        /* Try detecting if the window is active */
dludwig@9924
   544
        bool isWindowActive = true;     /* Presume the window is active, unless we've been told otherwise */
dludwig@9924
   545
        if (data->coreWindow->CustomProperties->HasKey("SDLHelperWindowActivationState")) {
dludwig@9924
   546
            CoreWindowActivationState activationState = \
dludwig@9924
   547
                safe_cast<CoreWindowActivationState>(data->coreWindow->CustomProperties->Lookup("SDLHelperWindowActivationState"));
dludwig@9924
   548
            isWindowActive = (activationState != CoreWindowActivationState::Deactivated);
dludwig@9924
   549
        }
dludwig@9924
   550
        if (isWindowActive) {
dludwig@9924
   551
            SDL_SetKeyboardFocus(window);
dludwig@9924
   552
        }
dludwig@9924
   553
    }
dludwig@8522
   554
 
dludwig@8522
   555
    /* Make sure the WinRT app's IFramworkView can post events on
dludwig@8522
   556
       behalf of SDL:
dludwig@8522
   557
    */
dludwig@8522
   558
    WINRT_GlobalSDLWindow = window;
dludwig@8522
   559
dludwig@8522
   560
    /* All done! */
dludwig@8522
   561
    return 0;
dludwig@8522
   562
}
dludwig@8522
   563
dludwig@8333
   564
void
dludwig@8333
   565
WINRT_DestroyWindow(_THIS, SDL_Window * window)
dludwig@8333
   566
{
dludwig@8411
   567
    SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
dludwig@8411
   568
dludwig@8497
   569
    if (WINRT_GlobalSDLWindow == window) {
dludwig@8497
   570
        WINRT_GlobalSDLWindow = NULL;
dludwig@8424
   571
    }
dludwig@8424
   572
dludwig@8411
   573
    if (data) {
dludwig@8411
   574
        // Delete the internal window data:
dludwig@8411
   575
        delete data;
dludwig@8411
   576
        data = NULL;
dludwig@9214
   577
        window->driverdata = NULL;
dludwig@8411
   578
    }
dludwig@8333
   579
}
dludwig@8333
   580
dludwig@8522
   581
SDL_bool
dludwig@8522
   582
WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
dludwig@8522
   583
{
dludwig@8522
   584
    SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
dludwig@8522
   585
dludwig@8522
   586
    if (info->version.major <= SDL_MAJOR_VERSION) {
dludwig@8522
   587
        info->subsystem = SDL_SYSWM_WINRT;
dludwig@8527
   588
        info->info.winrt.window = reinterpret_cast<IInspectable *>(data->coreWindow.Get());
dludwig@8522
   589
        return SDL_TRUE;
dludwig@8522
   590
    } else {
dludwig@8522
   591
        SDL_SetError("Application not compiled with SDL %d.%d\n",
dludwig@8522
   592
                     SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
dludwig@8522
   593
        return SDL_FALSE;
dludwig@8522
   594
    }
dludwig@8522
   595
    return SDL_FALSE;
dludwig@8411
   596
}
dludwig@8333
   597
dludwig@8327
   598
#endif /* SDL_VIDEO_DRIVER_WINRT */
dludwig@8327
   599
dludwig@8327
   600
/* vi: set ts=4 sw=4 expandtab: */