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