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