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