SDL  2.0
SDL_winrtvideo.cpp
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #if SDL_VIDEO_DRIVER_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>
37 using namespace Windows::ApplicationModel::Core;
38 using namespace Windows::Foundation;
39 using namespace Windows::Graphics::Display;
40 using namespace Windows::UI::Core;
41 using 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 */
45 static const GUID IID_IDisplayRequest = { 0xe5732044, 0xf49f, 0x4b60, { 0x8d, 0xd4, 0x5e, 0x7e, 0x3a, 0x63, 0x2a, 0xc0 } };
46 static const GUID IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } };
47 
48 
49 /* SDL includes */
50 extern "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"
66 #include "SDL_winrtgamebar_cpp.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 */
74 static int WINRT_VideoInit(_THIS);
75 static int WINRT_InitModes(_THIS);
76 static int WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
77 static void WINRT_VideoQuit(_THIS);
78 
79 
80 /* Window functions */
81 static int WINRT_CreateWindow(_THIS, SDL_Window * window);
82 static void WINRT_SetWindowSize(_THIS, SDL_Window * window);
83 static void WINRT_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display, SDL_bool fullscreen);
84 static void WINRT_DestroyWindow(_THIS, SDL_Window * window);
85 static SDL_bool WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info);
86 
87 
88 /* Misc functions */
89 static ABI::Windows::System::Display::IDisplayRequest * WINRT_CreateDisplayRequest(_THIS);
90 extern void WINRT_SuspendScreenSaver(_THIS);
91 
92 
93 /* SDL-internal globals: */
95 
96 
97 /* WinRT driver bootstrap functions */
98 
99 static int
100 WINRT_Available(void)
101 {
102  return (1);
103 }
104 
105 static void
106 WINRT_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 
116  SDL_free(device);
117 }
118 
119 static SDL_VideoDevice *
120 WINRT_CreateDevice(int devindex)
121 {
124 
125  /* Initialize all variables that we clean on shutdown */
126  device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
127  if (!device) {
128  SDL_OutOfMemory();
129  return (0);
130  }
131 
132  data = (SDL_VideoData *) SDL_calloc(1, sizeof(SDL_VideoData));
133  if (!data) {
134  SDL_OutOfMemory();
135  SDL_free(device);
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 
181 int
182 WINRT_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 
198 extern "C"
199 Uint32 D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat);
200 
201 static void
202 WINRT_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 
211 static int
212 WINRT_AddDisplaysForOutput (_THIS, IDXGIAdapter1 * dxgiAdapter1, int outputIndex)
213 {
214  HRESULT hr;
215  IDXGIOutput * dxgiOutput = NULL;
216  DXGI_OUTPUT_DESC dxgiOutputDesc;
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) {
286  SDL_OutOfMemory();
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! */
308 done:
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 
321 static int
322 WINRT_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) {
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 
400 int
401 WINRT_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 
427 static int
428 WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
429 {
430  return 0;
431 }
432 
433 void
434 WINRT_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 
445 static const Uint32 WINRT_DetectableFlags =
451 
452 extern "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) {
469  SDL_VideoDisplay * display = SDL_GetDisplayForWindow(window);
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)
521 void
523 {
524  mask &= WINRT_DetectableFlags;
525  if (window) {
526  Uint32 apply = WINRT_DetectWindowFlags(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 
534 static bool
535 WINRT_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 
560 int
561 WINRT_CreateWindow(_THIS, SDL_Window * window)
562 {
563  // Make sure that only one window gets created, at least until multimonitor
564  // support is added.
565  if (WINRT_GlobalSDLWindow != NULL) {
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) {
572  SDL_OutOfMemory();
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  */
584  if (!WINRT_XAMLWasEnabled) {
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 
656  if (WINRT_XAMLWasEnabled) {
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) {
702  SDL_SetKeyboardFocus(window);
703  }
704  }
705 
706  /* Make sure the WinRT app's IFramworkView can post events on
707  behalf of SDL:
708  */
709  WINRT_GlobalSDLWindow = window;
710 
711  /* All done! */
712  return 0;
713 }
714 
715 void
716 WINRT_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 
726 void
727 WINRT_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 
747 void
748 WINRT_DestroyWindow(_THIS, SDL_Window * window)
749 {
750  SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
751 
752  if (WINRT_GlobalSDLWindow == window) {
753  WINRT_GlobalSDLWindow = NULL;
754  }
755 
756  if (data) {
757  // Delete the internal window data:
758  delete data;
759  data = NULL;
760  window->driverdata = NULL;
761  }
762 }
763 
764 SDL_bool
765 WINRT_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) {
770  info->subsystem = SDL_SYSWM_WINRT;
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 
781 static ABI::Windows::System::Display::IDisplayRequest *
782 WINRT_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 
812 done:
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 
826 void
827 WINRT_SuspendScreenSaver(_THIS)
828 {
829  SDL_VideoData *driverdata = (SDL_VideoData *)_this->driverdata;
830  if (driverdata && driverdata->displayRequest) {
831  ABI::Windows::System::Display::IDisplayRequest * displayRequest = (ABI::Windows::System::Display::IDisplayRequest *) driverdata->displayRequest;
832  if (_this->suspend_screensaver) {
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 SDL_MINOR_VERSION
Definition: SDL_version.h:61
#define SDL_GetError
void WINRT_UpdateWindowFlags(SDL_Window *window, Uint32 mask)
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:630
#define EGL_NO_SURFACE
Definition: egl.h:100
#define SDL_MAJOR_VERSION
Definition: SDL_version.h:60
SDL_bool(* IsScreenKeyboardShown)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:294
#define SDL_WINRT_USE_APPLICATIONVIEW
struct wl_display * display
void(* free)(_THIS)
Definition: SDL_sysvideo.h:390
GLfloat GLfloat GLfloat GLfloat h
int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr)
int(* GL_SetSwapInterval)(_THIS, int interval)
Definition: SDL_sysvideo.h:260
The structure that defines a display mode.
Definition: SDL_video.h:53
SDL_version version
Definition: SDL_syswm.h:196
Uint8 major
Definition: SDL_version.h:53
void WINRT_InitMouse(_THIS)
void(* SetWindowSize)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:215
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_SYSWM_TYPE subsystem
Definition: SDL_syswm.h:197
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:151
uint32_t Uint32
Definition: SDL_stdinc.h:181
#define SDL_zerop(x)
Definition: SDL_stdinc.h:417
int SDL_AddVideoDisplay(const SDL_VideoDisplay *display)
Definition: SDL_video.c:606
int(* GL_LoadLibrary)(_THIS, const char *path)
Definition: SDL_sysvideo.h:254
int(* SetDisplayMode)(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
Definition: SDL_sysvideo.h:204
static SDL_VideoDevice * _this
Definition: SDL_video.c:121
static SDL_AudioDeviceID device
Definition: loopwave.c:37
#define FAILED(x)
Definition: SDL_directx.h:54
VideoBootStrap WINRT_bootstrap
SDL_bool(* GetWindowWMInfo)(_THIS, SDL_Window *window, struct SDL_SysWMinfo *info)
Definition: SDL_sysvideo.h:247
SDL_GLContext(* GL_CreateContext)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:257
#define _THIS
int(* GL_MakeCurrent)(_THIS, SDL_Window *window, SDL_GLContext context)
Definition: SDL_sysvideo.h:258
#define SDL_free
void WINRT_InitTouch(_THIS)
HRESULT(WINAPI *GetDpiForMonitor)(HMONITOR hmonitor
void WINRT_PumpEvents(_THIS)
int done
Definition: checkkeys.c:28
GLenum GLint GLuint mask
IUnknown * displayRequest
SDL_DisplayMode current_mode
Definition: SDL_sysvideo.h:132
GLenum mode
GLubyte GLubyte GLubyte GLubyte w
void(* DestroyWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:234
#define WIN_StringToUTF8(S)
Definition: SDL_windows.h:46
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
Uint32 WINRT_DetectWindowFlags(SDL_Window *window)
GLenum GLuint GLenum GLsizei const GLchar * buf
SDL_bool(* HasScreenKeyboardSupport)(_THIS)
Definition: SDL_sysvideo.h:291
GLsizeiptr size
SDL_Window * WINRT_GlobalSDLWindow
void(* GL_UnloadLibrary)(_THIS)
Definition: SDL_sysvideo.h:256
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
Window window
Definition: SDL_syswm.h:218
#define NULL
Definition: begin_code.h:164
int(* CreateSDLWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:210
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:139
SDL_DisplayMode desktop_mode
Definition: SDL_sysvideo.h:131
void(* VideoQuit)(_THIS)
Definition: SDL_sysvideo.h:166
Uint32 last_fullscreen_flags
Definition: SDL_sysvideo.h:84
#define SDL_SetError
#define SDL_calloc
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
Definition: SDL_video.c:1073
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
int(* GL_SwapWindow)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:262
void(* ShowScreenKeyboard)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:292
The type used to identify a window.
Definition: SDL_sysvideo.h:73
SDL_bool WINRT_XAMLWasEnabled
void WINRT_QuitMouse(_THIS)
SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode *mode)
Definition: SDL_video.c:743
IUnknown * winrtEglWindow
int(* VideoInit)(_THIS)
Definition: SDL_sysvideo.h:160
#define SDL_snprintf
SDL_bool suspend_screensaver
Definition: SDL_sysvideo.h:310
union SDL_SysWMinfo::@18 info
void(* SetWindowFullscreen)(_THIS, SDL_Window *window, SDL_VideoDisplay *display, SDL_bool fullscreen)
Definition: SDL_sysvideo.h:230
void * driverdata
Definition: SDL_sysvideo.h:111
void(* GL_DeleteContext)(_THIS, SDL_GLContext context)
Definition: SDL_sysvideo.h:263
Uint32 format
Definition: SDL_video.h:55
int(* GL_GetSwapInterval)(_THIS)
Definition: SDL_sysvideo.h:261
Uint32 flags
Definition: SDL_sysvideo.h:83
void(* SuspendScreenSaver)(_THIS)
Definition: SDL_sysvideo.h:283
void *(* GL_GetProcAddress)(_THIS, const char *proc)
Definition: SDL_sysvideo.h:255
EGLSurface egl_surface
void(* PumpEvents)(_THIS)
Definition: SDL_sysvideo.h:280
void(* HideScreenKeyboard)(_THIS, SDL_Window *window)
Definition: SDL_sysvideo.h:293