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