SDL_winrtapp_direct3d.cpp (28855B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 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> 27using namespace std; 28 29 30/* Windows includes */ 31#include "ppltasks.h" 32using namespace concurrency; 33using namespace Windows::ApplicationModel; 34using namespace Windows::ApplicationModel::Core; 35using namespace Windows::ApplicationModel::Activation; 36using namespace Windows::Devices::Input; 37using namespace Windows::Graphics::Display; 38using namespace Windows::Foundation; 39using namespace Windows::System; 40using namespace Windows::UI::Core; 41using namespace Windows::UI::Input; 42 43#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP 44using namespace Windows::Phone::UI::Input; 45#endif 46 47 48/* SDL includes */ 49extern "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 */ 77extern "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(). 95SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr; 96 97ref class SDLApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource 98{ 99public: 100 virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView(); 101}; 102 103IFrameworkView^ 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. 108 SDL_assert(!SDL_WinRTGlobalApp); 109 SDL_WinRTApp ^ app = ref new SDL_WinRTApp(); 110 if (!SDL_WinRTGlobalApp) 111 { 112 SDL_WinRTGlobalApp = app; 113 } 114 return app; 115} 116 117int 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 125static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *name, const char *oldValue, const char *newValue) 126{ 127 SDL_assert(SDL_strcmp(name, SDL_HINT_ORIENTATIONS) == 0); 128 129 // Start with no orientation flags, then add each in as they're parsed 130 // from newValue. 131 unsigned int orientationFlags = 0; 132 if (newValue) { 133 std::istringstream tokenizer(newValue); 134 while (!tokenizer.eof()) { 135 std::string orientationName; 136 std::getline(tokenizer, orientationName, ' '); 137 if (orientationName == "LandscapeLeft") { 138 orientationFlags |= (unsigned int) DisplayOrientations::LandscapeFlipped; 139 } else if (orientationName == "LandscapeRight") { 140 orientationFlags |= (unsigned int) DisplayOrientations::Landscape; 141 } else if (orientationName == "Portrait") { 142 orientationFlags |= (unsigned int) DisplayOrientations::Portrait; 143 } else if (orientationName == "PortraitUpsideDown") { 144 orientationFlags |= (unsigned int) DisplayOrientations::PortraitFlipped; 145 } 146 } 147 } 148 149 // If no valid orientation flags were specified, use a reasonable set of defaults: 150 if (!orientationFlags) { 151 // TODO, WinRT: consider seeing if an app's default orientation flags can be found out via some API call(s). 152 orientationFlags = (unsigned int) ( \ 153 DisplayOrientations::Landscape | 154 DisplayOrientations::LandscapeFlipped | 155 DisplayOrientations::Portrait | 156 DisplayOrientations::PortraitFlipped); 157 } 158 159 // Set the orientation/rotation preferences. Please note that this does 160 // not constitute a 100%-certain lock of a given set of possible 161 // orientations. According to Microsoft's documentation on WinRT [1] 162 // when a device is not capable of being rotated, Windows may ignore 163 // the orientation preferences, and stick to what the device is capable of 164 // displaying. 165 // 166 // [1] Documentation on the 'InitialRotationPreference' setting for a 167 // Windows app's manifest file describes how some orientation/rotation 168 // preferences may be ignored. See 169 // http://msdn.microsoft.com/en-us/library/windows/apps/hh700343.aspx 170 // for details. Microsoft's "Display orientation sample" also gives an 171 // outline of how Windows treats device rotation 172 // (http://code.msdn.microsoft.com/Display-Orientation-Sample-19a58e93). 173 WINRT_DISPLAY_PROPERTY(AutoRotationPreferences) = (DisplayOrientations) orientationFlags; 174} 175 176static void 177WINRT_ProcessWindowSizeChange() 178{ 179 SDL_VideoDevice *_this = SDL_GetVideoDevice(); 180 181 // Make the new window size be the one true fullscreen mode. 182 // This change was initially done, in part, to allow the Direct3D 11.1 183 // renderer to receive window-resize events as a device rotates. 184 // Before, rotating a device from landscape, to portrait, and then 185 // back to landscape would cause the Direct3D 11.1 swap buffer to 186 // not get resized appropriately. SDL would, on the rotation from 187 // landscape to portrait, re-resize the SDL window to it's initial 188 // size (landscape). On the subsequent rotation, SDL would drop the 189 // window-resize event as it appeared the SDL window didn't change 190 // size, and the Direct3D 11.1 renderer wouldn't resize its swap 191 // chain. 192 SDL_DisplayMode newDisplayMode; 193 if (WINRT_CalcDisplayModeUsingNativeWindow(&newDisplayMode) != 0) { 194 return; 195 } 196 197 // Make note of the old display mode, and it's old driverdata. 198 SDL_DisplayMode oldDisplayMode; 199 SDL_zero(oldDisplayMode); 200 if (_this) { 201 oldDisplayMode = _this->displays[0].desktop_mode; 202 } 203 204 // Setup the new display mode in the appropriate spots. 205 if (_this) { 206 // Make a full copy of the display mode for display_modes[0], 207 // one with with a separately malloced 'driverdata' field. 208 // SDL_VideoQuit(), if called, will attempt to free the driverdata 209 // fields in 'desktop_mode' and each entry in the 'display_modes' 210 // array. 211 if (_this->displays[0].display_modes[0].driverdata) { 212 // Free the previous mode's memory 213 SDL_free(_this->displays[0].display_modes[0].driverdata); 214 _this->displays[0].display_modes[0].driverdata = NULL; 215 } 216 if (WINRT_DuplicateDisplayMode(&(_this->displays[0].display_modes[0]), &newDisplayMode) != 0) { 217 // Uh oh, something went wrong. A malloc call probably failed. 218 SDL_free(newDisplayMode.driverdata); 219 return; 220 } 221 222 // Install 'newDisplayMode' into 'current_mode' and 'desktop_mode'. 223 _this->displays[0].current_mode = newDisplayMode; 224 _this->displays[0].desktop_mode = newDisplayMode; 225 } 226 227 if (WINRT_GlobalSDLWindow) { 228 // If the window size changed, send a resize event to SDL and its host app: 229 int window_w = 0; 230 int window_h = 0; 231 SDL_GetWindowSize(WINRT_GlobalSDLWindow, &window_w, &window_h); 232 if ((window_w != newDisplayMode.w) || (window_h != newDisplayMode.h)) { 233 SDL_SendWindowEvent( 234 WINRT_GlobalSDLWindow, 235 SDL_WINDOWEVENT_RESIZED, 236 newDisplayMode.w, 237 newDisplayMode.h); 238 } else { 239#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP 240 // HACK: Make sure that orientation changes 241 // lead to the Direct3D renderer's viewport getting updated: 242 // 243 // For some reason, this doesn't seem to need to be done on Windows 8.x, 244 // even when going from Landscape to LandscapeFlipped. It only seems to 245 // be needed on Windows Phone, at least when I tested on my devices. 246 // I'm not currently sure why this is, but it seems to work fine. -- David L. 247 // 248 // 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 249 const DisplayOrientations oldOrientation = ((SDL_DisplayModeData *)oldDisplayMode.driverdata)->currentOrientation; 250 const DisplayOrientations newOrientation = ((SDL_DisplayModeData *)newDisplayMode.driverdata)->currentOrientation; 251 if (oldOrientation != newOrientation) 252 { 253 SDL_SendWindowEvent( 254 WINRT_GlobalSDLWindow, 255 SDL_WINDOWEVENT_SIZE_CHANGED, 256 newDisplayMode.w, 257 newDisplayMode.h); 258 } 259#endif 260 } 261 } 262 263 // Finally, free the 'driverdata' field of the old 'desktop_mode'. 264 if (oldDisplayMode.driverdata) { 265 SDL_free(oldDisplayMode.driverdata); 266 oldDisplayMode.driverdata = NULL; 267 } 268} 269 270SDL_WinRTApp::SDL_WinRTApp() : 271 m_windowClosed(false), 272 m_windowVisible(true) 273{ 274} 275 276void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView) 277{ 278 applicationView->Activated += 279 ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnActivated); 280 281 CoreApplication::Suspending += 282 ref new EventHandler<SuspendingEventArgs^>(this, &SDL_WinRTApp::OnSuspending); 283 284 CoreApplication::Resuming += 285 ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnResuming); 286 287 CoreApplication::Exiting += 288 ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnExiting); 289} 290 291#if NTDDI_VERSION > NTDDI_WIN8 292void SDL_WinRTApp::OnOrientationChanged(DisplayInformation^ sender, Object^ args) 293#else 294void SDL_WinRTApp::OnOrientationChanged(Object^ sender) 295#endif 296{ 297#if LOG_ORIENTATION_EVENTS==1 298 CoreWindow^ window = CoreWindow::GetForCurrentThread(); 299 if (window) { 300 SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Size={%f,%f}\n", 301 __FUNCTION__, 302 WINRT_DISPLAY_PROPERTY(CurrentOrientation), 303 WINRT_DISPLAY_PROPERTY(NativeOrientation), 304 WINRT_DISPLAY_PROPERTY(AutoRotationPreferences), 305 window->Bounds.Width, 306 window->Bounds.Height); 307 } else { 308 SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n", 309 __FUNCTION__, 310 WINRT_DISPLAY_PROPERTY(CurrentOrientation), 311 WINRT_DISPLAY_PROPERTY(NativeOrientation), 312 WINRT_DISPLAY_PROPERTY(AutoRotationPreferences)); 313 } 314#endif 315 316 WINRT_ProcessWindowSizeChange(); 317} 318 319void SDL_WinRTApp::SetWindow(CoreWindow^ window) 320{ 321#if LOG_WINDOW_EVENTS==1 322 SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window Size={%f,%f}\n", 323 __FUNCTION__, 324 WINRT_DISPLAY_PROPERTY(CurrentOrientation), 325 WINRT_DISPLAY_PROPERTY(NativeOrientation), 326 WINRT_DISPLAY_PROPERTY(AutoRotationPreferences), 327 window->Bounds.Width, 328 window->Bounds.Height); 329#endif 330 331 window->SizeChanged += 332 ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &SDL_WinRTApp::OnWindowSizeChanged); 333 334 window->VisibilityChanged += 335 ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &SDL_WinRTApp::OnVisibilityChanged); 336 337 window->Closed += 338 ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &SDL_WinRTApp::OnWindowClosed); 339 340#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP 341 window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0); 342#endif 343 344 window->PointerPressed += 345 ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerPressed); 346 347 window->PointerMoved += 348 ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerMoved); 349 350 window->PointerReleased += 351 ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerReleased); 352 353 window->PointerWheelChanged += 354 ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerWheelChanged); 355 356#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP 357 // Retrieves relative-only mouse movements: 358 Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved += 359 ref new TypedEventHandler<MouseDevice^, MouseEventArgs^>(this, &SDL_WinRTApp::OnMouseMoved); 360#endif 361 362 window->KeyDown += 363 ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyDown); 364 365 window->KeyUp += 366 ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyUp); 367 368#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP 369 HardwareButtons::BackPressed += 370 ref new EventHandler<BackPressedEventArgs^>(this, &SDL_WinRTApp::OnBackButtonPressed); 371#endif 372 373#if NTDDI_VERSION > NTDDI_WIN8 374 DisplayInformation::GetForCurrentView()->OrientationChanged += 375 ref new TypedEventHandler<Windows::Graphics::Display::DisplayInformation^, Object^>(this, &SDL_WinRTApp::OnOrientationChanged); 376#else 377 DisplayProperties::OrientationChanged += 378 ref new DisplayPropertiesEventHandler(this, &SDL_WinRTApp::OnOrientationChanged); 379#endif 380 381 // Register the hint, SDL_HINT_ORIENTATIONS, with SDL. 382 // 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. 383 SDL_AddHintCallback(SDL_HINT_ORIENTATIONS, WINRT_SetDisplayOrientationsPreference, NULL); 384 385#if WINAPI_FAMILY == WINAPI_FAMILY_APP // for Windows 8/8.1/RT apps... (and not Phone apps) 386 // Make sure we know when a user has opened the app's settings pane. 387 // This is needed in order to display a privacy policy, which needs 388 // to be done for network-enabled apps, as per Windows Store requirements. 389 using namespace Windows::UI::ApplicationSettings; 390 SettingsPane::GetForCurrentView()->CommandsRequested += 391 ref new TypedEventHandler<SettingsPane^, SettingsPaneCommandsRequestedEventArgs^> 392 (this, &SDL_WinRTApp::OnSettingsPaneCommandsRequested); 393#endif 394} 395 396void SDL_WinRTApp::Load(Platform::String^ entryPoint) 397{ 398} 399 400void SDL_WinRTApp::Run() 401{ 402 SDL_SetMainReady(); 403 if (WINRT_SDLAppEntryPoint) 404 { 405 // TODO, WinRT: pass the C-style main() a reasonably realistic 406 // representation of command line arguments. 407 int argc = 0; 408 char **argv = NULL; 409 WINRT_SDLAppEntryPoint(argc, argv); 410 } 411} 412 413static bool IsSDLWindowEventPending(SDL_WindowEventID windowEventID) 414{ 415 SDL_Event events[128]; 416 const int count = SDL_PeepEvents(events, sizeof(events)/sizeof(SDL_Event), SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT); 417 for (int i = 0; i < count; ++i) { 418 if (events[i].window.event == windowEventID) { 419 return true; 420 } 421 } 422 return false; 423} 424 425bool SDL_WinRTApp::ShouldWaitForAppResumeEvents() 426{ 427 /* Don't wait if the app is visible: */ 428 if (m_windowVisible) { 429 return false; 430 } 431 432 /* Don't wait until the window-hide events finish processing. 433 * Do note that if an app-suspend event is sent (as indicated 434 * by SDL_APP_WILLENTERBACKGROUND and SDL_APP_DIDENTERBACKGROUND 435 * events), then this code may be a moot point, as WinRT's 436 * own event pump (aka ProcessEvents()) will pause regardless 437 * of what we do here. This happens on Windows Phone 8, to note. 438 * Windows 8.x apps, on the other hand, may get a chance to run 439 * these. 440 */ 441 if (IsSDLWindowEventPending(SDL_WINDOWEVENT_HIDDEN)) { 442 return false; 443 } else if (IsSDLWindowEventPending(SDL_WINDOWEVENT_FOCUS_LOST)) { 444 return false; 445 } else if (IsSDLWindowEventPending(SDL_WINDOWEVENT_MINIMIZED)) { 446 return false; 447 } 448 449 return true; 450} 451 452void SDL_WinRTApp::PumpEvents() 453{ 454 if (!m_windowClosed) { 455 if (!ShouldWaitForAppResumeEvents()) { 456 /* This is the normal way in which events should be pumped. 457 * 'ProcessAllIfPresent' will make ProcessEvents() process anywhere 458 * from zero to N events, and will then return. 459 */ 460 CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); 461 } else { 462 /* This style of event-pumping, with 'ProcessOneAndAllPending', 463 * will cause anywhere from one to N events to be processed. If 464 * at least one event is processed, the call will return. If 465 * no events are pending, then the call will wait until one is 466 * available, and will not return (to the caller) until this 467 * happens! This should only occur when the app is hidden. 468 */ 469 CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending); 470 } 471 } 472} 473 474void SDL_WinRTApp::Uninitialize() 475{ 476} 477 478#if WINAPI_FAMILY == WINAPI_FAMILY_APP 479void SDL_WinRTApp::OnSettingsPaneCommandsRequested( 480 Windows::UI::ApplicationSettings::SettingsPane ^p, 481 Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args) 482{ 483 using namespace Platform; 484 using namespace Windows::UI::ApplicationSettings; 485 using namespace Windows::UI::Popups; 486 487 String ^privacyPolicyURL = nullptr; // a URL to an app's Privacy Policy 488 String ^privacyPolicyLabel = nullptr; // label/link text 489 const char *tmpHintValue = NULL; // SDL_GetHint-retrieved value, used immediately 490 wchar_t *tmpStr = NULL; // used for UTF8 to UCS2 conversion 491 492 // Setup a 'Privacy Policy' link, if one is available (via SDL_GetHint): 493 tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_URL); 494 if (tmpHintValue && tmpHintValue[0] != '\0') { 495 // Convert the privacy policy's URL to UCS2: 496 tmpStr = WIN_UTF8ToString(tmpHintValue); 497 privacyPolicyURL = ref new String(tmpStr); 498 SDL_free(tmpStr); 499 500 // Optionally retrieve custom label-text for the link. If this isn't 501 // available, a default value will be used instead. 502 tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_LABEL); 503 if (tmpHintValue && tmpHintValue[0] != '\0') { 504 tmpStr = WIN_UTF8ToString(tmpHintValue); 505 privacyPolicyLabel = ref new String(tmpStr); 506 SDL_free(tmpStr); 507 } else { 508 privacyPolicyLabel = ref new String(L"Privacy Policy"); 509 } 510 511 // Register the link, along with a handler to be called if and when it is 512 // clicked: 513 auto cmd = ref new SettingsCommand(L"privacyPolicy", privacyPolicyLabel, 514 ref new UICommandInvokedHandler([=](IUICommand ^) { 515 Windows::System::Launcher::LaunchUriAsync(ref new Uri(privacyPolicyURL)); 516 })); 517 args->Request->ApplicationCommands->Append(cmd); 518 } 519} 520#endif // if WINAPI_FAMILY == WINAPI_FAMILY_APP 521 522void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args) 523{ 524#if LOG_WINDOW_EVENTS==1 525 SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, WINRT_GlobalSDLWindow?=%s\n", 526 __FUNCTION__, 527 args->Size.Width, args->Size.Height, 528 WINRT_DISPLAY_PROPERTY(CurrentOrientation), 529 WINRT_DISPLAY_PROPERTY(NativeOrientation), 530 WINRT_DISPLAY_PROPERTY(AutoRotationPreferences), 531 (WINRT_GlobalSDLWindow ? "yes" : "no")); 532#endif 533 534 WINRT_ProcessWindowSizeChange(); 535} 536 537void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args) 538{ 539#if LOG_WINDOW_EVENTS==1 540 SDL_Log("%s, visible?=%s, WINRT_GlobalSDLWindow?=%s\n", 541 __FUNCTION__, 542 (args->Visible ? "yes" : "no"), 543 (WINRT_GlobalSDLWindow ? "yes" : "no")); 544#endif 545 546 m_windowVisible = args->Visible; 547 if (WINRT_GlobalSDLWindow) { 548 SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid; 549 550 if (args->Visible) { 551 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0); 552 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0); 553 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0); 554 } else { 555 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0); 556 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0); 557 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0); 558 } 559 560 // HACK: Prevent SDL's window-hide handling code, which currently 561 // triggers a fake window resize (possibly erronously), from 562 // marking the SDL window's surface as invalid. 563 // 564 // A better solution to this probably involves figuring out if the 565 // fake window resize can be prevented. 566 WINRT_GlobalSDLWindow->surface_valid = wasSDLWindowSurfaceValid; 567 } 568} 569 570void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args) 571{ 572#if LOG_WINDOW_EVENTS==1 573 SDL_Log("%s\n", __FUNCTION__); 574#endif 575 m_windowClosed = true; 576} 577 578void SDL_WinRTApp::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args) 579{ 580 CoreWindow::GetForCurrentThread()->Activate(); 581} 582 583void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args) 584{ 585 // Save app state asynchronously after requesting a deferral. Holding a deferral 586 // indicates that the application is busy performing suspending operations. Be 587 // aware that a deferral may not be held indefinitely. After about five seconds, 588 // the app will be forced to exit. 589 590 // ... but first, let the app know it's about to go to the background. 591 // The separation of events may be important, given that the deferral 592 // runs in a separate thread. This'll make SDL_APP_WILLENTERBACKGROUND 593 // the only event among the two that runs in the main thread. Given 594 // that a few WinRT operations can only be done from the main thread 595 // (things that access the WinRT CoreWindow are one example of this), 596 // this could be important. 597 SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND); 598 599 SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral(); 600 create_task([this, deferral]() 601 { 602 // Send an app did-enter-background event immediately to observers. 603 // CoreDispatcher::ProcessEvents, which is the backbone on which 604 // SDL_WinRTApp::PumpEvents is built, will not return to its caller 605 // once it sends out a suspend event. Any events posted to SDL's 606 // event queue won't get received until the WinRT app is resumed. 607 // SDL_AddEventWatch() may be used to receive app-suspend events on 608 // WinRT. 609 SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND); 610 611 // Let the Direct3D 11 renderer prepare for the app to be backgrounded. 612 // This is necessary for Windows 8.1, possibly elsewhere in the future. 613 // More details at: http://msdn.microsoft.com/en-us/library/windows/apps/Hh994929.aspx 614#if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED 615 if (WINRT_GlobalSDLWindow) { 616 SDL_Renderer * renderer = SDL_GetRenderer(WINRT_GlobalSDLWindow); 617 if (renderer && (SDL_strcmp(renderer->info.name, "direct3d11") == 0)) { 618 D3D11_Trim(renderer); 619 } 620 } 621#endif 622 623 deferral->Complete(); 624 }); 625} 626 627void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args) 628{ 629 // Restore any data or state that was unloaded on suspend. By default, data 630 // and state are persisted when resuming from suspend. Note that these events 631 // do not occur if the app was previously terminated. 632 SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND); 633 SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND); 634} 635 636void SDL_WinRTApp::OnExiting(Platform::Object^ sender, Platform::Object^ args) 637{ 638 SDL_SendAppEvent(SDL_APP_TERMINATING); 639} 640 641static void 642WINRT_LogPointerEvent(const char * header, Windows::UI::Core::PointerEventArgs ^ args, Windows::Foundation::Point transformedPoint) 643{ 644 Windows::UI::Input::PointerPoint ^ pt = args->CurrentPoint; 645 SDL_Log("%s: Position={%f,%f}, Transformed Pos={%f, %f}, MouseWheelDelta=%d, FrameId=%d, PointerId=%d, SDL button=%d\n", 646 header, 647 pt->Position.X, pt->Position.Y, 648 transformedPoint.X, transformedPoint.Y, 649 pt->Properties->MouseWheelDelta, 650 pt->FrameId, 651 pt->PointerId, 652 WINRT_GetSDLButtonForPointerPoint(pt)); 653} 654 655void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args) 656{ 657#if LOG_POINTER_EVENTS 658 WINRT_LogPointerEvent("pointer pressed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); 659#endif 660 661 WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); 662} 663 664void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args) 665{ 666#if LOG_POINTER_EVENTS 667 WINRT_LogPointerEvent("pointer moved", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); 668#endif 669 670 WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); 671} 672 673void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args) 674{ 675#if LOG_POINTER_EVENTS 676 WINRT_LogPointerEvent("pointer released", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); 677#endif 678 679 WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); 680} 681 682void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args) 683{ 684#if LOG_POINTER_EVENTS 685 WINRT_LogPointerEvent("pointer wheel changed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); 686#endif 687 688 WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); 689} 690 691void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args) 692{ 693 WINRT_ProcessMouseMovedEvent(WINRT_GlobalSDLWindow, args); 694} 695 696void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args) 697{ 698 WINRT_ProcessKeyDownEvent(args); 699} 700 701void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args) 702{ 703 WINRT_ProcessKeyUpEvent(args); 704} 705 706#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP 707void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args) 708{ 709 SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_AC_BACK); 710 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_AC_BACK); 711 712 const char *hint = SDL_GetHint(SDL_HINT_WINRT_HANDLE_BACK_BUTTON); 713 if (hint) { 714 if (*hint == '1') { 715 args->Handled = true; 716 } 717 } 718} 719#endif 720