From 2cafee9de1813a048bad8264766eb189be65b78b Mon Sep 17 00:00:00 2001 From: David Ludwig Date: Tue, 27 Aug 2013 21:21:09 -0400 Subject: [PATCH] WinRT: experimental and preliminary support for XAML-based overlays on Windows 8/RT The XAML support here is still rudimentary. Bugs do exist. You've been warned. XAML support in Windows Phone 8 is not yet available (in SDL/WinRT). --- VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj | 8 + .../SDL/SDL_VS2012-WinRT.vcxproj.filters | 3 + include/SDL_system.h | 14 ++ src/core/winrt/SDL_winrtapp.cpp | 8 +- src/core/winrt/SDL_winrtxaml.cpp | 162 ++++++++++++++++++ src/render/direct3d11/SDL_render_d3d11.cpp | 104 ++++++++--- src/video/winrt/SDL_winrtevents.cpp | 98 ++++++++++- src/video/winrt/SDL_winrtevents_c.h | 11 +- src/video/winrt/SDL_winrtmouse.cpp | 25 +-- src/video/winrt/SDL_winrtvideo.cpp | 30 +++- 10 files changed, 415 insertions(+), 48 deletions(-) create mode 100644 src/core/winrt/SDL_winrtxaml.cpp diff --git a/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj b/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj index 6a3c609f2276d..d662e6942f16c 100644 --- a/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj +++ b/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj @@ -70,6 +70,14 @@ true true + + true + true + true + true + true + true + diff --git a/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj.filters b/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj.filters index 5889533ec015b..4d4fee55d0d6a 100644 --- a/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj.filters +++ b/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj.filters @@ -270,6 +270,9 @@ Source Files + + Source Files + diff --git a/include/SDL_system.h b/include/SDL_system.h index 0610dd22ef809..447d5f7436025 100644 --- a/include/SDL_system.h +++ b/include/SDL_system.h @@ -155,6 +155,20 @@ extern DECLSPEC const wchar_t * SDLCALL SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path */ extern DECLSPEC const char * SDLCALL SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType); +#ifdef __cplusplus_winrt +/** + * \brief Initializes a WinRT and XAML based application. + * + * \param backgroundPanel The XAML background panel to draw onto and receive + * events from. + * \param mainFunction The SDL app's C-style main(). + * \ret 0 on success, -1 on failure. On failure, use SDL_GetError to retrieve more + * information on the failure. + */ +/* TODO, WinRT: consider making SDL_WinRTInitXAMLApp accept a void pointer to IUnknown, rather than a C++/CX reference */ +extern DECLSPEC int SDLCALL SDL_WinRTInitXAMLApp(Platform::Object^ backgroundPanel, int (*mainFunction)(int, char **)); + +#endif // ifdef __cplusplus_winrt #endif /* __WINRT__ */ diff --git a/src/core/winrt/SDL_winrtapp.cpp b/src/core/winrt/SDL_winrtapp.cpp index ef800f6f4edbc..167489237eaed 100644 --- a/src/core/winrt/SDL_winrtapp.cpp +++ b/src/core/winrt/SDL_winrtapp.cpp @@ -361,17 +361,17 @@ void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args) void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args) { - WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args); + WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); } void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args) { - WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args); + WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); } void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args) { - WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args); + WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); } void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args) @@ -381,7 +381,7 @@ void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args) void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args) { - WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args); + WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); } void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args) diff --git a/src/core/winrt/SDL_winrtxaml.cpp b/src/core/winrt/SDL_winrtxaml.cpp new file mode 100644 index 0000000000000..811f332d4112f --- /dev/null +++ b/src/core/winrt/SDL_winrtxaml.cpp @@ -0,0 +1,162 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2013 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +/* Windows includes */ +#include +#include + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP +#include +#endif + + +/* SDL includes */ +#include "SDL.h" +//#include "SDL_error.h" +//#include "SDL_log.h" +//#include "SDL_main.h" +//#include "SDL_system.h" +#include "../../video/winrt/SDL_winrtevents_c.h" + + +/* External globals: */ +extern SDL_Window * WINRT_GlobalSDLWindow; + + +/* Internal globals: */ +SDL_bool WINRT_XAMLWasEnabled = SDL_FALSE; +int (*WINRT_XAMLAppMainFunction)(int, char **) = NULL; + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP +ISwapChainBackgroundPanelNative * WINRT_GlobalSwapChainBackgroundPanelNative = NULL; +static Windows::Foundation::EventRegistrationToken WINRT_XAMLAppEventToken; +#endif + + +/* + * Input event handlers (XAML) + */ +#if WINAPI_FAMILY == WINAPI_FAMILY_APP + +static void +WINRT_OnPointerPressedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args) +{ + WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr)); +} + +static void +WINRT_OnPointerReleasedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args) +{ + WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr)); +} + +static void +WINRT_OnPointerWheelChangedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args) +{ + WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr)); +} + +static void +WINRT_OnPointerMovedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args) +{ + WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr)); +} + +#endif // WINAPI_FAMILY == WINAPI_FAMILY_APP + + +/* + * XAML-to-SDL Rendering Callback + */ +#if WINAPI_FAMILY == WINAPI_FAMILY_APP + +static void +WINRT_OnRenderViaXAML(_In_ Platform::Object^ sender, _In_ Platform::Object^ args) +{ + WINRT_CycleXAMLThread(); +} + +#endif // WINAPI_FAMILY == WINAPI_FAMILY_APP + + +/* + * SDL + XAML Initialization + */ + +extern "C" int +SDL_WinRTInitXAMLApp(Platform::Object ^backgroundPanel, int (*mainFunction)(int, char **)) +{ +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + return SDL_SetError("XAML support is not yet available in Windows Phone."); +#else + // Declare C++/CX namespaces: + using namespace Platform; + using namespace Windows::Foundation; + using namespace Windows::UI::Core; + using namespace Windows::UI::Xaml; + using namespace Windows::UI::Xaml::Controls; + using namespace Windows::UI::Xaml::Input; + using namespace Windows::UI::Xaml::Media; + + // Make sure we have a valid XAML element (to draw onto): + if ( ! backgroundPanel) { + return SDL_SetError("'backgroundPanel' can't be NULL"); + } + + SwapChainBackgroundPanel ^swapChainBackgroundPanel = dynamic_cast(backgroundPanel); + if ( ! swapChainBackgroundPanel) { + return SDL_SetError("An unknown or unsupported type of XAML control was specified."); + } + + // Setup event handlers: + swapChainBackgroundPanel->PointerPressed += ref new PointerEventHandler(WINRT_OnPointerPressedViaXAML); + swapChainBackgroundPanel->PointerReleased += ref new PointerEventHandler(WINRT_OnPointerReleasedViaXAML); + swapChainBackgroundPanel->PointerWheelChanged += ref new PointerEventHandler(WINRT_OnPointerWheelChangedViaXAML); + swapChainBackgroundPanel->PointerMoved += ref new PointerEventHandler(WINRT_OnPointerMovedViaXAML); + + // Setup for rendering: + IInspectable *panelInspectable = (IInspectable*) reinterpret_cast(swapChainBackgroundPanel); + panelInspectable->QueryInterface(__uuidof(ISwapChainBackgroundPanelNative), (void **)&WINRT_GlobalSwapChainBackgroundPanelNative); + + WINRT_XAMLAppEventToken = CompositionTarget::Rendering::add(ref new EventHandler(WINRT_OnRenderViaXAML)); + + // Make sure the app is ready to call the SDL-centric main() function: + WINRT_XAMLAppMainFunction = mainFunction; + SDL_SetMainReady(); + + // Make sure video-init knows that we're initializing XAML: + SDL_bool oldXAMLWasEnabledValue = WINRT_XAMLWasEnabled; + WINRT_XAMLWasEnabled = SDL_TRUE; + + // Make sure video modes are detected now, while we still have access to the WinRT + // CoreWindow. WinRT will not allow the app's CoreWindow to be accessed via the + // SDL/WinRT thread. + if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { + // SDL_InitSubSystem will, on error, set the SDL error. Let that propogate to + // the caller to here: + WINRT_XAMLWasEnabled = oldXAMLWasEnabledValue; + return -1; + } + + // All done, for now. + return 0; +#endif // WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP / else +} diff --git a/src/render/direct3d11/SDL_render_d3d11.cpp b/src/render/direct3d11/SDL_render_d3d11.cpp index c7d6334443744..cee1edb9c492f 100644 --- a/src/render/direct3d11/SDL_render_d3d11.cpp +++ b/src/render/direct3d11/SDL_render_d3d11.cpp @@ -26,6 +26,11 @@ #ifdef __WINRT__ #include #include + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP +#include +#endif + #endif extern "C" { @@ -608,6 +613,13 @@ D3D11_ConvertDipsToPixels(float dips) } #endif + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP +// TODO, WinRT, XAML: get the ISwapChainBackgroundPanelNative from something other than a global var +extern ISwapChainBackgroundPanelNative * WINRT_GlobalSwapChainBackgroundPanelNative; +#endif + + // Initialize all resources that change when the window's size changes. // TODO, WinRT: get D3D11_CreateWindowSizeDependentResources working on Win32 HRESULT @@ -619,15 +631,28 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer) // Store the window bounds so the next time we get a SizeChanged event we can // avoid rebuilding everything if the size is identical. - ABI::Windows::Foundation::Rect coreWindowBounds; - result = coreWindow->get_Bounds(&coreWindowBounds); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__", Get Window Bounds", result); - return result; + ABI::Windows::Foundation::Rect nativeWindowBounds; + if (coreWindow) { + result = coreWindow->get_Bounds(&nativeWindowBounds); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__", Get Window Bounds", result); + return result; + } + } else { + // TODO, WinRT, XAML: clean up window-bounds code in D3D11_CreateWindowSizeDependentResources + SDL_DisplayMode displayMode; + if (SDL_GetDesktopDisplayMode(0, &displayMode) < 0) { + SDL_SetError(__FUNCTION__", Get Window Bounds (XAML): Unable to retrieve the native window's size"); + return E_FAIL; + } + + nativeWindowBounds.Width = (FLOAT) displayMode.w; + nativeWindowBounds.Height = (FLOAT) displayMode.h; } - data->windowSizeInDIPs.x = coreWindowBounds.Width; - data->windowSizeInDIPs.y = coreWindowBounds.Height; + // TODO, WinRT, XAML: see if window/control sizes are in DIPs, or something else. If something else, then adjust renderer size tracking accordingly. + data->windowSizeInDIPs.x = nativeWindowBounds.Width; + data->windowSizeInDIPs.y = nativeWindowBounds.Height; // Calculate the necessary swap chain and render target size in pixels. float windowWidth = D3D11_ConvertDipsToPixels(data->windowSizeInDIPs.x); @@ -660,6 +685,8 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer) } else { + const bool usingXAML = (coreWindow == nullptr); + // Otherwise, create a new one using the same adapter as the existing Direct3D device. DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0}; swapChainDesc.Width = static_cast(data->renderTargetSize.x); // Match the size of the window. @@ -674,7 +701,11 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer) swapChainDesc.Scaling = DXGI_SCALING_STRETCH; // On phone, only stretch and aspect-ratio stretch scaling are allowed. swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // On phone, no swap effects are supported. #else - swapChainDesc.Scaling = DXGI_SCALING_NONE; + if (usingXAML) { + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + } else { + swapChainDesc.Scaling = DXGI_SCALING_NONE; + } swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect. #endif swapChainDesc.Flags = 0; @@ -703,25 +734,48 @@ D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer) return result; } - IUnknown * coreWindowAsIUnknown = nullptr; - result = coreWindow->QueryInterface(&coreWindowAsIUnknown); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__ ", CoreWindow to IUnknown", result); - return result; - } + if (usingXAML) { + result = dxgiFactory->CreateSwapChainForComposition( + data->d3dDevice.Get(), + &swapChainDesc, + nullptr, + &data->swapChain); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", CreateSwapChainForComposition", result); + return result; + } - result = dxgiFactory->CreateSwapChainForCoreWindow( - data->d3dDevice.Get(), - coreWindowAsIUnknown, - &swapChainDesc, - nullptr, // Allow on all displays. - &data->swapChain - ); - if (FAILED(result)) { - WIN_SetErrorFromHRESULT(__FUNCTION__, result); - return result; +#if WINAPI_FAMILY == WINAPI_FAMILY_APP + result = WINRT_GlobalSwapChainBackgroundPanelNative->SetSwapChain(data->swapChain.Get()); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ISwapChainBackgroundPanelNative::SetSwapChain", result); + return result; + } +#else + SDL_SetError(__FUNCTION__ ", XAML support is not yet available for Windows Phone"); + return E_FAIL; +#endif + } else { + IUnknown * coreWindowAsIUnknown = nullptr; + result = coreWindow->QueryInterface(&coreWindowAsIUnknown); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", CoreWindow to IUnknown", result); + return result; + } + + result = dxgiFactory->CreateSwapChainForCoreWindow( + data->d3dDevice.Get(), + coreWindowAsIUnknown, + &swapChainDesc, + nullptr, // Allow on all displays. + &data->swapChain + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__, result); + return result; + } } - + // Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and // ensures that the application will only render after each VSync, minimizing power consumption. result = dxgiDevice->SetMaximumFrameLatency(1); diff --git a/src/video/winrt/SDL_winrtevents.cpp b/src/video/winrt/SDL_winrtevents.cpp index ef1cb690eb27b..10f4137af584d 100644 --- a/src/video/winrt/SDL_winrtevents.cpp +++ b/src/video/winrt/SDL_winrtevents.cpp @@ -25,23 +25,117 @@ /* SDL includes */ #include "SDL_winrtevents_c.h" #include "../../core/winrt/SDL_winrtapp.h" +#include "SDL_assert.h" +#include "SDL_system.h" extern "C" { #include "../SDL_sysvideo.h" #include "../../events/SDL_events_c.h" } + +/* Forward declarations and globals */ extern SDL_WinRTApp ^ SDL_WinRTGlobalApp; +extern int (*WINRT_XAMLAppMainFunction)(int, char **); +extern void WINRT_YieldXAMLThread(); -/* General event-management function(s) */ +/* Global event management */ void WINRT_PumpEvents(_THIS) { - SDL_WinRTGlobalApp->PumpEvents(); + if (SDL_WinRTGlobalApp) { + SDL_WinRTGlobalApp->PumpEvents(); + } else if (WINRT_XAMLAppMainFunction) { + WINRT_YieldXAMLThread(); + } +} + + +/* XAML Thread management */ + +enum SDL_XAMLAppThreadState +{ + ThreadState_NotLaunched = 0, + ThreadState_Running, + ThreadState_Yielding +}; + +static SDL_XAMLAppThreadState _threadState = ThreadState_NotLaunched; +static SDL_Thread * _XAMLThread = nullptr; +static SDL_mutex * _mutex = nullptr; +static SDL_cond * _cond = nullptr; + +static void +WINRT_YieldXAMLThread() +{ + SDL_LockMutex(_mutex); + SDL_assert(_threadState == ThreadState_Running); + _threadState = ThreadState_Yielding; + SDL_UnlockMutex(_mutex); + + SDL_CondSignal(_cond); + + SDL_LockMutex(_mutex); + while (_threadState != ThreadState_Running) { + SDL_CondWait(_cond, _mutex); + } + SDL_UnlockMutex(_mutex); +} + +static int +WINRT_XAMLThreadMain(void * userdata) +{ + return WINRT_XAMLAppMainFunction(0, NULL); +} + +void +WINRT_CycleXAMLThread() +{ + switch (_threadState) { + case ThreadState_NotLaunched: + { + _cond = SDL_CreateCond(); + + _mutex = SDL_CreateMutex(); + _threadState = ThreadState_Running; + _XAMLThread = SDL_CreateThread(WINRT_XAMLThreadMain, "SDL/XAML App Thread", nullptr); + + SDL_LockMutex(_mutex); + while (_threadState != ThreadState_Yielding) { + SDL_CondWait(_cond, _mutex); + } + SDL_UnlockMutex(_mutex); + + break; + } + + case ThreadState_Running: + { + SDL_assert(false); + break; + } + + case ThreadState_Yielding: + { + SDL_LockMutex(_mutex); + SDL_assert(_threadState == ThreadState_Yielding); + _threadState = ThreadState_Running; + SDL_UnlockMutex(_mutex); + + SDL_CondSignal(_cond); + + SDL_LockMutex(_mutex); + while (_threadState != ThreadState_Yielding) { + SDL_CondWait(_cond, _mutex); + } + SDL_UnlockMutex(_mutex); + } + } } + #endif /* SDL_VIDEO_DRIVER_WINRT */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/winrt/SDL_winrtevents_c.h b/src/video/winrt/SDL_winrtevents_c.h index 68e746a72aeef..6038a7c9f7f89 100644 --- a/src/video/winrt/SDL_winrtevents_c.h +++ b/src/video/winrt/SDL_winrtevents_c.h @@ -50,10 +50,13 @@ extern void WINRT_ProcessKeyUpEvent(Windows::UI::Core::KeyEventArgs ^args); /* Pointers (Mice, Touch, etc.) */ extern void WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args); -extern void WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Core::PointerEventArgs ^args); -extern void WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Core::PointerEventArgs ^args); -extern void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Core::PointerEventArgs ^args); -extern void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Core::PointerEventArgs ^args); +extern void WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); +extern void WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); +extern void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); +extern void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); + +/* XAML Thread Management */ +extern void WINRT_CycleXAMLThread(); #endif diff --git a/src/video/winrt/SDL_winrtmouse.cpp b/src/video/winrt/SDL_winrtmouse.cpp index 1cbb4af3cca32..841a28cc2ed7b 100644 --- a/src/video/winrt/SDL_winrtmouse.cpp +++ b/src/video/winrt/SDL_winrtmouse.cpp @@ -110,6 +110,11 @@ WINRT_FreeCursor(SDL_Cursor * cursor) static int WINRT_ShowCursor(SDL_Cursor * cursor) { + // TODO, WinRT, XAML: make WINRT_ShowCursor work when XAML support is enabled. + if ( ! CoreWindow::GetForCurrentThread()) { + return 0; + } + if (cursor) { CoreCursor ^* theCursor = (CoreCursor ^*) cursor->driverdata; CoreWindow::GetForCurrentThread()->PointerCursor = *theCursor; @@ -334,25 +339,25 @@ WINRT_LogPointerEvent(const char * header, PointerEventArgs ^ args, Windows::Fou } void -WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Core::PointerEventArgs ^args) +WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) { #if LOG_POINTER_EVENTS - WINRT_LogPointerEvent("pointer moved", args, TransformCursor(args->CurrentPoint->Position)); + WINRT_LogPointerEvent("pointer moved", args, TransformCursor(pointerPoint->Position)); #endif if (!window || WINRT_UseRelativeMouseMode) { return; } - Windows::Foundation::Point transformedPoint = TransformCursor(window, args->CurrentPoint->Position); + Windows::Foundation::Point transformedPoint = TransformCursor(window, pointerPoint->Position); SDL_SendMouseMotion(window, 0, 0, (int)transformedPoint.X, (int)transformedPoint.Y); } void -WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Core::PointerEventArgs ^args) +WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) { #if LOG_POINTER_EVENTS - WINRT_LogPointerEvent("wheel changed", args, TransformCursor(args->CurrentPoint->Position)); + WINRT_LogPointerEvent("wheel changed", args, TransformCursor(pointerPoint->Position)); #endif if (!window) { @@ -360,11 +365,11 @@ WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Core::Poi } // FIXME: This may need to accumulate deltas up to WHEEL_DELTA - short motion = args->CurrentPoint->Properties->MouseWheelDelta / WHEEL_DELTA; + short motion = pointerPoint->Properties->MouseWheelDelta / WHEEL_DELTA; SDL_SendMouseWheel(window, 0, 0, motion); } -void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Core::PointerEventArgs ^args) +void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) { #if LOG_POINTER_EVENTS WINRT_LogPointerEvent("mouse up", args, TransformCursor(args->CurrentPoint->Position)); @@ -374,13 +379,13 @@ void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Core::Po return; } - Uint8 button = WINRT_GetSDLButtonForPointerPoint(args->CurrentPoint); + Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint); if (button) { SDL_SendMouseButton(window, 0, SDL_RELEASED, button); } } -void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Core::PointerEventArgs ^args) +void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) { #if LOG_POINTER_EVENTS WINRT_LogPointerEvent("mouse down", args, TransformCursor(args->CurrentPoint->Position)); @@ -390,7 +395,7 @@ void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Core::Poi return; } - Uint8 button = WINRT_GetSDLButtonForPointerPoint(args->CurrentPoint); + Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint); if (button) { SDL_SendMouseButton(window, 0, SDL_PRESSED, button); } diff --git a/src/video/winrt/SDL_winrtvideo.cpp b/src/video/winrt/SDL_winrtvideo.cpp index fcaca6a98c822..8fecf2cd26d26 100644 --- a/src/video/winrt/SDL_winrtvideo.cpp +++ b/src/video/winrt/SDL_winrtvideo.cpp @@ -47,8 +47,11 @@ extern "C" { #include "../../core/winrt/SDL_winrtapp.h" #include "SDL_winrtevents_c.h" #include "SDL_winrtmouse.h" +#include "SDL_main.h" +#include "SDL_system.h" extern SDL_WinRTApp ^ SDL_WinRTGlobalApp; +extern SDL_bool WINRT_XAMLWasEnabled; /* Initialization/Query functions */ @@ -84,6 +87,7 @@ SDL_Window * WINRT_GlobalSDLWindow = NULL; SDL_VideoDevice * WINRT_GlobalSDLVideoDevice = NULL; + /* WinRT driver bootstrap functions */ static int @@ -154,6 +158,13 @@ WINRT_CalcDisplayModeUsingNativeWindow() SDL_DisplayMode mode; SDL_zero(mode); + // Go no further if a native window cannot be accessed. This can happen, + // for example, if this function is called from certain threads, such as + // the SDL/XAML thread. + if (!CoreWindow::GetForCurrentThread()) { + return mode; + } + // Fill in most fields: mode.format = SDL_PIXELFORMAT_RGB888; mode.refresh_rate = 0; // TODO, WinRT: see if refresh rate data is available, or relevant (for WinRT apps) @@ -169,11 +180,15 @@ WINRT_CalcDisplayModeUsingNativeWindow() return mode; } - -static int +int WINRT_InitModes(_THIS) { + // Retrieve the display mode: SDL_DisplayMode mode = WINRT_CalcDisplayModeUsingNativeWindow(); + if (mode.w == 0 || mode.h == 0) { + return SDL_SetError("Unable to calculate the WinRT window/display's size"); + } + if (SDL_AddBasicVideoDisplay(&mode) < 0) { return -1; } @@ -211,7 +226,16 @@ WINRT_CreateWindow(_THIS, SDL_Window * window) } window->driverdata = data; data->sdlWindow = window; - data->coreWindow = CoreWindow::GetForCurrentThread(); + + /* To note, when XAML support is enabled, access to the CoreWindow will not + be possible, at least not via the SDL/XAML thread. Attempts to access it + from there will throw exceptions. As such, the SDL_WindowData's + 'coreWindow' field will only be set (to a non-null value) if XAML isn't + enabled. + */ + if (!WINRT_XAMLWasEnabled) { + data->coreWindow = CoreWindow::GetForCurrentThread(); + } /* Make sure the window is considered to be positioned at {0,0}, and is considered fullscreen, shown, and the like.