SDL  2.0
SDL_winrtapp_direct3d.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 /* Standard C++11 includes */
24 #include <functional>
25 #include <string>
26 #include <sstream>
27 using namespace std;
28 
29 
30 /* Windows includes */
31 #include "ppltasks.h"
32 using namespace concurrency;
33 using namespace Windows::ApplicationModel;
34 using namespace Windows::ApplicationModel::Core;
36 using namespace Windows::Devices::Input;
37 using namespace Windows::Graphics::Display;
38 using namespace Windows::Foundation;
39 using namespace Windows::System;
40 using namespace Windows::UI::Core;
41 using namespace Windows::UI::Input;
42 
43 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
44 using namespace Windows::Phone::UI::Input;
45 #endif
46 
47 
48 /* SDL includes */
49 extern "C" {
50 #include "../../SDL_internal.h"
51 #include "SDL_assert.h"
52 #include "SDL_events.h"
53 #include "SDL_hints.h"
54 #include "SDL_log.h"
55 #include "SDL_main.h"
56 #include "SDL_stdinc.h"
57 #include "SDL_render.h"
58 #include "../../video/SDL_sysvideo.h"
59 //#include "../../SDL_hints_c.h"
60 #include "../../events/SDL_events_c.h"
61 #include "../../events/SDL_keyboard_c.h"
62 #include "../../events/SDL_mouse_c.h"
63 #include "../../events/SDL_windowevents_c.h"
64 #include "../../render/SDL_sysrender.h"
65 #include "../windows/SDL_windows.h"
66 }
67 
68 #include "../../video/winrt/SDL_winrtevents_c.h"
69 #include "../../video/winrt/SDL_winrtvideo_cpp.h"
70 #include "SDL_winrtapp_common.h"
71 #include "SDL_winrtapp_direct3d.h"
72 
73 #if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
74 /* Calling IDXGIDevice3::Trim on the active Direct3D 11.x device is necessary
75  * when Windows 8.1 apps are about to get suspended.
76  */
77 extern "C" void D3D11_Trim(SDL_Renderer *);
78 #endif
79 
80 
81 // Compile-time debugging options:
82 // To enable, uncomment; to disable, comment them out.
83 //#define LOG_POINTER_EVENTS 1
84 //#define LOG_WINDOW_EVENTS 1
85 //#define LOG_ORIENTATION_EVENTS 1
86 
87 
88 // HACK, DLudwig: record a reference to the global, WinRT 'app'/view.
89 // SDL/WinRT will use this throughout its code.
90 //
91 // TODO, WinRT: consider replacing SDL_WinRTGlobalApp with something
92 // non-global, such as something created inside
93 // SDL_InitSubSystem(SDL_INIT_VIDEO), or something inside
94 // SDL_CreateWindow().
95 SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr;
96 
97 ref class SDLApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
98 {
99 public:
100  virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
101 };
102 
103 IFrameworkView^ SDLApplicationSource::CreateView()
104 {
105  // TODO, WinRT: see if this function (CreateView) can ever get called
106  // more than once. For now, just prevent it from ever assigning
107  // SDL_WinRTGlobalApp more than once.
109  SDL_WinRTApp ^ app = ref new SDL_WinRTApp();
110  if (!SDL_WinRTGlobalApp)
111  {
112  SDL_WinRTGlobalApp = app;
113  }
114  return app;
115 }
116 
117 int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **))
118 {
119  WINRT_SDLAppEntryPoint = mainFunction;
120  auto direct3DApplicationSource = ref new SDLApplicationSource();
121  CoreApplication::Run(direct3DApplicationSource);
122  return 0;
123 }
124 
125 static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *name, const char *oldValue, const char *newValue)
126 {
128 
129  /* HACK: prevent SDL from altering an app's .appxmanifest-set orientation
130  * from being changed on startup, by detecting when SDL_HINT_ORIENTATIONS
131  * is getting registered.
132  *
133  * TODO, WinRT: consider reading in an app's .appxmanifest file, and apply its orientation when 'newValue == NULL'.
134  */
135  if ((oldValue == NULL) && (newValue == NULL)) {
136  return;
137  }
138 
139  // Start with no orientation flags, then add each in as they're parsed
140  // from newValue.
141  unsigned int orientationFlags = 0;
142  if (newValue) {
143  std::istringstream tokenizer(newValue);
144  while (!tokenizer.eof()) {
145  std::string orientationName;
146  std::getline(tokenizer, orientationName, ' ');
147  if (orientationName == "LandscapeLeft") {
148  orientationFlags |= (unsigned int) DisplayOrientations::LandscapeFlipped;
149  } else if (orientationName == "LandscapeRight") {
150  orientationFlags |= (unsigned int) DisplayOrientations::Landscape;
151  } else if (orientationName == "Portrait") {
152  orientationFlags |= (unsigned int) DisplayOrientations::Portrait;
153  } else if (orientationName == "PortraitUpsideDown") {
154  orientationFlags |= (unsigned int) DisplayOrientations::PortraitFlipped;
155  }
156  }
157  }
158 
159  // If no valid orientation flags were specified, use a reasonable set of defaults:
160  if (!orientationFlags) {
161  // TODO, WinRT: consider seeing if an app's default orientation flags can be found out via some API call(s).
162  orientationFlags = (unsigned int) ( \
163  DisplayOrientations::Landscape |
164  DisplayOrientations::LandscapeFlipped |
165  DisplayOrientations::Portrait |
166  DisplayOrientations::PortraitFlipped);
167  }
168 
169  // Set the orientation/rotation preferences. Please note that this does
170  // not constitute a 100%-certain lock of a given set of possible
171  // orientations. According to Microsoft's documentation on WinRT [1]
172  // when a device is not capable of being rotated, Windows may ignore
173  // the orientation preferences, and stick to what the device is capable of
174  // displaying.
175  //
176  // [1] Documentation on the 'InitialRotationPreference' setting for a
177  // Windows app's manifest file describes how some orientation/rotation
178  // preferences may be ignored. See
179  // http://msdn.microsoft.com/en-us/library/windows/apps/hh700343.aspx
180  // for details. Microsoft's "Display orientation sample" also gives an
181  // outline of how Windows treats device rotation
182  // (http://code.msdn.microsoft.com/Display-Orientation-Sample-19a58e93).
183  WINRT_DISPLAY_PROPERTY(AutoRotationPreferences) = (DisplayOrientations) orientationFlags;
184 }
185 
186 static void
187 WINRT_ProcessWindowSizeChange() // TODO: Pass an SDL_Window-identifying thing into WINRT_ProcessWindowSizeChange()
188 {
189  CoreWindow ^ coreWindow = CoreWindow::GetForCurrentThread();
190  if (coreWindow) {
191  if (WINRT_GlobalSDLWindow) {
194 
195  int x = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Left);
196  int y = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Top);
197  int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
198  int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
199 
200 #if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION == NTDDI_WIN8)
201  /* WinPhone 8.0 always keeps its native window size in portrait,
202  regardless of orientation. This changes in WinPhone 8.1,
203  in which the native window's size changes along with
204  orientation.
205 
206  Attempt to emulate WinPhone 8.1's behavior on WinPhone 8.0, with
207  regards to window size. This fixes a rendering bug that occurs
208  when a WinPhone 8.0 app is rotated to either 90 or 270 degrees.
209  */
210  const DisplayOrientations currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation);
211  switch (currentOrientation) {
212  case DisplayOrientations::Landscape:
213  case DisplayOrientations::LandscapeFlipped: {
214  int tmp = w;
215  w = h;
216  h = tmp;
217  } break;
218  }
219 #endif
220 
221  const Uint32 latestFlags = WINRT_DetectWindowFlags(window);
222  if (latestFlags & SDL_WINDOW_MAXIMIZED) {
224  } else {
226  }
227 
229 
230  /* The window can move during a resize event, such as when maximizing
231  or resizing from a corner */
234  }
235  }
236 }
237 
238 SDL_WinRTApp::SDL_WinRTApp() :
239  m_windowClosed(false),
240  m_windowVisible(true)
241 {
242 }
243 
244 void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView)
245 {
246  applicationView->Activated +=
247  ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnAppActivated);
248 
249  CoreApplication::Suspending +=
250  ref new EventHandler<SuspendingEventArgs^>(this, &SDL_WinRTApp::OnSuspending);
251 
252  CoreApplication::Resuming +=
253  ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnResuming);
254 
255  CoreApplication::Exiting +=
256  ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnExiting);
257 }
258 
259 #if NTDDI_VERSION > NTDDI_WIN8
260 void SDL_WinRTApp::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
261 #else
262 void SDL_WinRTApp::OnOrientationChanged(Object^ sender)
263 #endif
264 {
265 #if LOG_ORIENTATION_EVENTS==1
266  {
267  CoreWindow^ window = CoreWindow::GetForCurrentThread();
268  if (window) {
269  SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Bounds={%f,%f,%f,%f}\n",
270  __FUNCTION__,
271  WINRT_DISPLAY_PROPERTY(CurrentOrientation),
272  WINRT_DISPLAY_PROPERTY(NativeOrientation),
273  WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
274  window->Bounds.X,
275  window->Bounds.Y,
276  window->Bounds.Width,
277  window->Bounds.Height);
278  } else {
279  SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n",
280  __FUNCTION__,
281  WINRT_DISPLAY_PROPERTY(CurrentOrientation),
282  WINRT_DISPLAY_PROPERTY(NativeOrientation),
283  WINRT_DISPLAY_PROPERTY(AutoRotationPreferences));
284  }
285  }
286 #endif
287 
289 
290 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
291  // HACK: Make sure that orientation changes
292  // lead to the Direct3D renderer's viewport getting updated:
293  //
294  // For some reason, this doesn't seem to need to be done on Windows 8.x,
295  // even when going from Landscape to LandscapeFlipped. It only seems to
296  // be needed on Windows Phone, at least when I tested on my devices.
297  // I'm not currently sure why this is, but it seems to work fine. -- David L.
298  //
299  // TODO, WinRT: do more extensive research into why orientation changes on Win 8.x don't need D3D changes, or if they might, in some cases
301  if (window) {
303  int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
304  int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
306  }
307 #endif
308 
309 }
310 
311 void SDL_WinRTApp::SetWindow(CoreWindow^ window)
312 {
313 #if LOG_WINDOW_EVENTS==1
314  SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window bounds={%f, %f, %f,%f}\n",
315  __FUNCTION__,
316  WINRT_DISPLAY_PROPERTY(CurrentOrientation),
317  WINRT_DISPLAY_PROPERTY(NativeOrientation),
318  WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
319  window->Bounds.X,
320  window->Bounds.Y,
321  window->Bounds.Width,
322  window->Bounds.Height);
323 #endif
324 
325  window->SizeChanged +=
326  ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &SDL_WinRTApp::OnWindowSizeChanged);
327 
328  window->VisibilityChanged +=
329  ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &SDL_WinRTApp::OnVisibilityChanged);
330 
331  window->Activated +=
332  ref new TypedEventHandler<CoreWindow^, WindowActivatedEventArgs^>(this, &SDL_WinRTApp::OnWindowActivated);
333 
334  window->Closed +=
335  ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &SDL_WinRTApp::OnWindowClosed);
336 
337 #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
338  window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
339 #endif
340 
341  window->PointerPressed +=
342  ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerPressed);
343 
344  window->PointerMoved +=
345  ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerMoved);
346 
347  window->PointerReleased +=
348  ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerReleased);
349 
350  window->PointerEntered +=
351  ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerEntered);
352 
353  window->PointerExited +=
354  ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerExited);
355 
356  window->PointerWheelChanged +=
357  ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerWheelChanged);
358 
359 #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
360  // Retrieves relative-only mouse movements:
361  Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved +=
362  ref new TypedEventHandler<MouseDevice^, MouseEventArgs^>(this, &SDL_WinRTApp::OnMouseMoved);
363 #endif
364 
365  window->KeyDown +=
366  ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyDown);
367 
368  window->KeyUp +=
369  ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyUp);
370 
371  window->CharacterReceived +=
372  ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &SDL_WinRTApp::OnCharacterReceived);
373 
374 #if NTDDI_VERSION >= NTDDI_WIN10
375  Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->BackRequested +=
376  ref new EventHandler<BackRequestedEventArgs^>(this, &SDL_WinRTApp::OnBackButtonPressed);
377 #elif WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
378  HardwareButtons::BackPressed +=
379  ref new EventHandler<BackPressedEventArgs^>(this, &SDL_WinRTApp::OnBackButtonPressed);
380 #endif
381 
382 #if NTDDI_VERSION > NTDDI_WIN8
383  DisplayInformation::GetForCurrentView()->OrientationChanged +=
384  ref new TypedEventHandler<Windows::Graphics::Display::DisplayInformation^, Object^>(this, &SDL_WinRTApp::OnOrientationChanged);
385 #else
386  DisplayProperties::OrientationChanged +=
387  ref new DisplayPropertiesEventHandler(this, &SDL_WinRTApp::OnOrientationChanged);
388 #endif
389 
390  // Register the hint, SDL_HINT_ORIENTATIONS, with SDL.
391  // TODO, WinRT: see if an app's default orientation can be found out via WinRT API(s), then set the initial value of SDL_HINT_ORIENTATIONS accordingly.
393 
394 #if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10) // for Windows 8/8.1/RT apps... (and not Phone apps)
395  // Make sure we know when a user has opened the app's settings pane.
396  // This is needed in order to display a privacy policy, which needs
397  // to be done for network-enabled apps, as per Windows Store requirements.
398  using namespace Windows::UI::ApplicationSettings;
399  SettingsPane::GetForCurrentView()->CommandsRequested +=
400  ref new TypedEventHandler<SettingsPane^, SettingsPaneCommandsRequestedEventArgs^>
401  (this, &SDL_WinRTApp::OnSettingsPaneCommandsRequested);
402 #endif
403 }
404 
405 void SDL_WinRTApp::Load(Platform::String^ entryPoint)
406 {
407 }
408 
409 void SDL_WinRTApp::Run()
410 {
413  {
414  // TODO, WinRT: pass the C-style main() a reasonably realistic
415  // representation of command line arguments.
416  int argc = 0;
417  char **argv = NULL;
418  WINRT_SDLAppEntryPoint(argc, argv);
419  }
420 }
421 
422 static bool IsSDLWindowEventPending(SDL_WindowEventID windowEventID)
423 {
424  SDL_Event events[128];
425  const int count = SDL_PeepEvents(events, sizeof(events)/sizeof(SDL_Event), SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT);
426  for (int i = 0; i < count; ++i) {
427  if (events[i].window.event == windowEventID) {
428  return true;
429  }
430  }
431  return false;
432 }
433 
434 bool SDL_WinRTApp::ShouldWaitForAppResumeEvents()
435 {
436  /* Don't wait if the app is visible: */
437  if (m_windowVisible) {
438  return false;
439  }
440 
441  /* Don't wait until the window-hide events finish processing.
442  * Do note that if an app-suspend event is sent (as indicated
443  * by SDL_APP_WILLENTERBACKGROUND and SDL_APP_DIDENTERBACKGROUND
444  * events), then this code may be a moot point, as WinRT's
445  * own event pump (aka ProcessEvents()) will pause regardless
446  * of what we do here. This happens on Windows Phone 8, to note.
447  * Windows 8.x apps, on the other hand, may get a chance to run
448  * these.
449  */
451  return false;
453  return false;
455  return false;
456  }
457 
458  return true;
459 }
460 
461 void SDL_WinRTApp::PumpEvents()
462 {
463  if (!m_windowClosed) {
464  if (!ShouldWaitForAppResumeEvents()) {
465  /* This is the normal way in which events should be pumped.
466  * 'ProcessAllIfPresent' will make ProcessEvents() process anywhere
467  * from zero to N events, and will then return.
468  */
469  CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
470  } else {
471  /* This style of event-pumping, with 'ProcessOneAndAllPending',
472  * will cause anywhere from one to N events to be processed. If
473  * at least one event is processed, the call will return. If
474  * no events are pending, then the call will wait until one is
475  * available, and will not return (to the caller) until this
476  * happens! This should only occur when the app is hidden.
477  */
478  CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
479  }
480  }
481 }
482 
483 void SDL_WinRTApp::Uninitialize()
484 {
485 }
486 
487 #if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10)
488 void SDL_WinRTApp::OnSettingsPaneCommandsRequested(
489  Windows::UI::ApplicationSettings::SettingsPane ^p,
490  Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args)
491 {
492  using namespace Platform;
493  using namespace Windows::UI::ApplicationSettings;
494  using namespace Windows::UI::Popups;
495 
496  String ^privacyPolicyURL = nullptr; // a URL to an app's Privacy Policy
497  String ^privacyPolicyLabel = nullptr; // label/link text
498  const char *tmpHintValue = NULL; // SDL_GetHint-retrieved value, used immediately
499  wchar_t *tmpStr = NULL; // used for UTF8 to UCS2 conversion
500 
501  // Setup a 'Privacy Policy' link, if one is available (via SDL_GetHint):
503  if (tmpHintValue && tmpHintValue[0] != '\0') {
504  // Convert the privacy policy's URL to UCS2:
505  tmpStr = WIN_UTF8ToString(tmpHintValue);
506  privacyPolicyURL = ref new String(tmpStr);
507  SDL_free(tmpStr);
508 
509  // Optionally retrieve custom label-text for the link. If this isn't
510  // available, a default value will be used instead.
512  if (tmpHintValue && tmpHintValue[0] != '\0') {
513  tmpStr = WIN_UTF8ToString(tmpHintValue);
514  privacyPolicyLabel = ref new String(tmpStr);
515  SDL_free(tmpStr);
516  } else {
517  privacyPolicyLabel = ref new String(L"Privacy Policy");
518  }
519 
520  // Register the link, along with a handler to be called if and when it is
521  // clicked:
522  auto cmd = ref new SettingsCommand(L"privacyPolicy", privacyPolicyLabel,
523  ref new UICommandInvokedHandler([=](IUICommand ^) {
524  Windows::System::Launcher::LaunchUriAsync(ref new Uri(privacyPolicyURL));
525  }));
526  args->Request->ApplicationCommands->Append(cmd);
527  }
528 }
529 #endif // if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10)
530 
531 void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
532 {
533 #if LOG_WINDOW_EVENTS==1
534  SDL_Log("%s, size={%f,%f}, bounds={%f,%f,%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, WINRT_GlobalSDLWindow?=%s\n",
535  __FUNCTION__,
536  args->Size.Width, args->Size.Height,
537  sender->Bounds.X, sender->Bounds.Y, sender->Bounds.Width, sender->Bounds.Height,
538  WINRT_DISPLAY_PROPERTY(CurrentOrientation),
539  WINRT_DISPLAY_PROPERTY(NativeOrientation),
540  WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
541  (WINRT_GlobalSDLWindow ? "yes" : "no"));
542 #endif
543 
545 }
546 
547 void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
548 {
549 #if LOG_WINDOW_EVENTS==1
550  SDL_Log("%s, visible?=%s, bounds={%f,%f,%f,%f}, WINRT_GlobalSDLWindow?=%s\n",
551  __FUNCTION__,
552  (args->Visible ? "yes" : "no"),
553  sender->Bounds.X, sender->Bounds.Y,
554  sender->Bounds.Width, sender->Bounds.Height,
555  (WINRT_GlobalSDLWindow ? "yes" : "no"));
556 #endif
557 
558  m_windowVisible = args->Visible;
559  if (WINRT_GlobalSDLWindow) {
560  SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid;
562  if (args->Visible) {
565  if (latestWindowFlags & SDL_WINDOW_MAXIMIZED) {
567  } else {
569  }
570  } else {
574  }
575 
576  // HACK: Prevent SDL's window-hide handling code, which currently
577  // triggers a fake window resize (possibly erronously), from
578  // marking the SDL window's surface as invalid.
579  //
580  // A better solution to this probably involves figuring out if the
581  // fake window resize can be prevented.
582  WINRT_GlobalSDLWindow->surface_valid = wasSDLWindowSurfaceValid;
583  }
584 }
585 
586 void SDL_WinRTApp::OnWindowActivated(CoreWindow^ sender, WindowActivatedEventArgs^ args)
587 {
588 #if LOG_WINDOW_EVENTS==1
589  SDL_Log("%s, WINRT_GlobalSDLWindow?=%s\n\n",
590  __FUNCTION__,
591  (WINRT_GlobalSDLWindow ? "yes" : "no"));
592 #endif
593 
594  /* There's no property in Win 8.x to tell whether a window is active or
595  not. [De]activation events are, however, sent to the app. We'll just
596  record those, in case the CoreWindow gets wrapped by an SDL_Window at
597  some future time.
598  */
599  sender->CustomProperties->Insert("SDLHelperWindowActivationState", args->WindowActivationState);
600 
602  if (window) {
603  if (args->WindowActivationState != CoreWindowActivationState::Deactivated) {
605  if (SDL_GetKeyboardFocus() != window) {
606  SDL_SetKeyboardFocus(window);
607  }
608 
609  /* Send a mouse-motion event as appropriate.
610  This doesn't work when called from OnPointerEntered, at least
611  not in WinRT CoreWindow apps (as OnPointerEntered doesn't
612  appear to be called after window-reactivation, at least not
613  in Windows 10, Build 10586.3 (November 2015 update, non-beta).
614 
615  Don't do it on WinPhone 8.0 though, as CoreWindow's 'PointerPosition'
616  property isn't available.
617  */
618 #if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION >= NTDDI_WINBLUE)
619  Point cursorPos = WINRT_TransformCursorPosition(window, sender->PointerPosition, TransformToSDLWindowSize);
620  SDL_SendMouseMotion(window, 0, 0, (int)cursorPos.X, (int)cursorPos.Y);
621 #endif
622 
623  /* TODO, WinRT: see if the Win32 bugfix from https://hg.libsdl.org/SDL/rev/d278747da408 needs to be applied (on window activation) */
624  //WIN_CheckAsyncMouseRelease(data);
625 
626  /* TODO, WinRT: implement clipboard support, if possible */
627  ///*
628  // * FIXME: Update keyboard state
629  // */
630  //WIN_CheckClipboardUpdate(data->videodata);
631 
632  // HACK: Resetting the mouse-cursor here seems to fix
633  // https://bugzilla.libsdl.org/show_bug.cgi?id=3217, whereby a
634  // WinRT app's mouse cursor may switch to Windows' 'wait' cursor,
635  // after a user alt-tabs back into a full-screened SDL app.
636  // This bug does not appear to reproduce 100% of the time.
637  // It may be a bug in Windows itself (v.10.0.586.36, as tested,
638  // and the most-recent as of this writing).
640  } else {
641  if (SDL_GetKeyboardFocus() == window) {
643  }
644  }
645  }
646 }
647 
648 void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
649 {
650 #if LOG_WINDOW_EVENTS==1
651  SDL_Log("%s\n", __FUNCTION__);
652 #endif
653  m_windowClosed = true;
654 }
655 
656 void SDL_WinRTApp::OnAppActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
657 {
658  CoreWindow::GetForCurrentThread()->Activate();
659 }
660 
661 void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
662 {
663  // Save app state asynchronously after requesting a deferral. Holding a deferral
664  // indicates that the application is busy performing suspending operations. Be
665  // aware that a deferral may not be held indefinitely. After about five seconds,
666  // the app will be forced to exit.
667 
668  // ... but first, let the app know it's about to go to the background.
669  // The separation of events may be important, given that the deferral
670  // runs in a separate thread. This'll make SDL_APP_WILLENTERBACKGROUND
671  // the only event among the two that runs in the main thread. Given
672  // that a few WinRT operations can only be done from the main thread
673  // (things that access the WinRT CoreWindow are one example of this),
674  // this could be important.
676 
677  SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
678  create_task([this, deferral]()
679  {
680  // Send an app did-enter-background event immediately to observers.
681  // CoreDispatcher::ProcessEvents, which is the backbone on which
682  // SDL_WinRTApp::PumpEvents is built, will not return to its caller
683  // once it sends out a suspend event. Any events posted to SDL's
684  // event queue won't get received until the WinRT app is resumed.
685  // SDL_AddEventWatch() may be used to receive app-suspend events on
686  // WinRT.
688 
689  // Let the Direct3D 11 renderer prepare for the app to be backgrounded.
690  // This is necessary for Windows 8.1, possibly elsewhere in the future.
691  // More details at: http://msdn.microsoft.com/en-us/library/windows/apps/Hh994929.aspx
692 #if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
693  if (WINRT_GlobalSDLWindow) {
695  if (renderer && (SDL_strcmp(renderer->info.name, "direct3d11") == 0)) {
696  D3D11_Trim(renderer);
697  }
698  }
699 #endif
700 
701  deferral->Complete();
702  });
703 }
704 
705 void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args)
706 {
707  // Restore any data or state that was unloaded on suspend. By default, data
708  // and state are persisted when resuming from suspend. Note that these events
709  // do not occur if the app was previously terminated.
712 }
713 
714 void SDL_WinRTApp::OnExiting(Platform::Object^ sender, Platform::Object^ args)
715 {
717 }
718 
719 static void
720 WINRT_LogPointerEvent(const char * header, Windows::UI::Core::PointerEventArgs ^ args, Windows::Foundation::Point transformedPoint)
721 {
722  Windows::UI::Input::PointerPoint ^ pt = args->CurrentPoint;
723  SDL_Log("%s: Position={%f,%f}, Transformed Pos={%f, %f}, MouseWheelDelta=%d, FrameId=%d, PointerId=%d, SDL button=%d\n",
724  header,
725  pt->Position.X, pt->Position.Y,
726  transformedPoint.X, transformedPoint.Y,
727  pt->Properties->MouseWheelDelta,
728  pt->FrameId,
729  pt->PointerId,
730  WINRT_GetSDLButtonForPointerPoint(pt));
731 }
732 
733 void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
734 {
735 #if LOG_POINTER_EVENTS
736  WINRT_LogPointerEvent("pointer pressed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
737 #endif
738 
739  WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
740 }
741 
742 void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
743 {
744 #if LOG_POINTER_EVENTS
745  WINRT_LogPointerEvent("pointer moved", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
746 #endif
747 
748  WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
749 }
750 
751 void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args)
752 {
753 #if LOG_POINTER_EVENTS
754  WINRT_LogPointerEvent("pointer released", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
755 #endif
756 
757  WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
758 }
759 
760 void SDL_WinRTApp::OnPointerEntered(CoreWindow^ sender, PointerEventArgs^ args)
761 {
762 #if LOG_POINTER_EVENTS
763  WINRT_LogPointerEvent("pointer entered", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
764 #endif
765 
766  WINRT_ProcessPointerEnteredEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
767 }
768 
769 void SDL_WinRTApp::OnPointerExited(CoreWindow^ sender, PointerEventArgs^ args)
770 {
771 #if LOG_POINTER_EVENTS
772  WINRT_LogPointerEvent("pointer exited", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
773 #endif
774 
775  WINRT_ProcessPointerExitedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
776 }
777 
778 void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args)
779 {
780 #if LOG_POINTER_EVENTS
781  WINRT_LogPointerEvent("pointer wheel changed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
782 #endif
783 
784  WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
785 }
786 
787 void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args)
788 {
789  WINRT_ProcessMouseMovedEvent(WINRT_GlobalSDLWindow, args);
790 }
791 
792 void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
793 {
794  WINRT_ProcessKeyDownEvent(args);
795 }
796 
797 void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
798 {
799  WINRT_ProcessKeyUpEvent(args);
800 }
801 
802 void SDL_WinRTApp::OnCharacterReceived(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CharacterReceivedEventArgs^ args)
803 {
804  WINRT_ProcessCharacterReceivedEvent(args);
805 }
806 
807 template <typename BackButtonEventArgs>
808 static void WINRT_OnBackButtonPressed(BackButtonEventArgs ^ args)
809 {
812 
814  if (hint) {
815  if (*hint == '1') {
816  args->Handled = true;
817  }
818  }
819 }
820 
821 #if NTDDI_VERSION == NTDDI_WIN10
822 void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::UI::Core::BackRequestedEventArgs^ args)
823 
824 {
826 }
827 #elif WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
828 void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args)
829 
830 {
832 }
833 #endif
834 
#define WIN_UTF8ToString(S)
Definition: SDL_windows.h:46
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
SDL_RendererInfo info
GLsizei const GLchar *const * string
#define SDL_SetMainReady
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1564
SDL_Window * window
GLfloat GLfloat p
static SDL_Event events[EVENT_BUF_SIZE]
Definition: testgesture.c:36
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
#define SDL_GetHint
STL namespace.
static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *name, const char *oldValue, const char *newValue)
GLuint const GLchar * name
#define SDL_SetCursor
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
#define SDL_GetKeyboardFocus
const char * name
Definition: SDL_render.h:80
#define SDL_HINT_WINRT_PRIVACY_POLICY_URL
A URL to a WinRT app&#39;s privacy policy.
Definition: SDL_hints.h:448
#define SDL_HINT_WINRT_PRIVACY_POLICY_LABEL
Label text for a WinRT app&#39;s privacy policy link.
Definition: SDL_hints.h:469
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
Definition: SDL_keyboard.c:661
int SDL_WinRTInitNonXAMLApp(int(*mainFunction)(int, char **))
SDL_bool
Definition: SDL_stdinc.h:126
SDL_WinRTApp SDL_WinRTGlobalApp
static void WINRT_OnBackButtonPressed(BackButtonEventArgs^args)
SDL_Renderer * renderer
#define SDL_Log
int Run(void *data)
Definition: testlock.c:65
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:188
#define SDL_PeepEvents
void SDL_free(void *mem)
SDL_WindowEventID
Event subtype for window events.
Definition: SDL_video.h:136
Uint32 WINRT_DetectWindowFlags(SDL_Window *window)
SDL_Window * WINRT_GlobalSDLWindow
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
#define SDL_assert(condition)
Definition: SDL_assert.h:167
#define SDL_GetRenderer
#define SDL_HINT_ORIENTATIONS
A variable controlling which orientations are allowed on iOS.
Definition: SDL_hints.h:278
#define NULL
Definition: begin_code.h:143
The type used to identify a window.
Definition: SDL_sysvideo.h:71
#define SDL_AddHintCallback
int(* WINRT_SDLAppEntryPoint)(int, char **)
static void WINRT_ProcessWindowSizeChange()
General event structure.
Definition: SDL_events.h:521
GLubyte GLubyte GLubyte GLubyte w
int SDL_SendAppEvent(SDL_EventType eventType)
Definition: SDL_events.c:622
#define SDL_strcmp
void * driverdata
Definition: SDL_sysvideo.h:106
#define SDL_PRESSED
Definition: SDL_events.h:50
#define SDL_HINT_WINRT_HANDLE_BACK_BUTTON
Allows back-button-press events on Windows Phone to be marked as handled.
Definition: SDL_hints.h:521
GLenum GLint ref
SDL_bool surface_valid
Definition: SDL_sysvideo.h:94
#define SDL_RELEASED
Definition: SDL_events.h:49
static void WINRT_LogPointerEvent(const char *header, Windows::UI::Core::PointerEventArgs^args, Windows::Foundation::Point transformedPoint)
GLfloat GLfloat GLfloat GLfloat h
static bool IsSDLWindowEventPending(SDL_WindowEventID windowEventID)