From 623898f70bc41b0fad1ceb8fa27947f3b3931b78 Mon Sep 17 00:00:00 2001 From: David Ludwig Date: Thu, 26 Nov 2015 00:41:39 -0500 Subject: [PATCH] WinRT: lots of display and windowing related fixes This change-set fixes a lot of windowing related bugs, especially with regards to Windows 8.x apps running on Windows 10 (which was the driver for this work). The primary fixes include: * listed display modes were wrong, especially when launching apps into a non-fullscreen space * reported window flags were often wrong, especially on Windows 10 * fullscreen/windowed mode switches weren't failing (they are not programmatically possible in Win 8.x apps). --- include/SDL_config_winrt.h | 18 +- src/core/winrt/SDL_winrtapp_direct3d.cpp | 284 ++++++++++------- src/core/winrt/SDL_winrtapp_direct3d.h | 5 +- src/render/direct3d11/SDL_render_d3d11.c | 6 +- src/video/SDL_video.c | 40 +++ src/video/winrt/SDL_winrtevents_c.h | 2 + src/video/winrt/SDL_winrtpointerinput.cpp | 22 ++ src/video/winrt/SDL_winrtvideo.cpp | 364 ++++++++++++++++------ src/video/winrt/SDL_winrtvideo_cpp.h | 37 ++- 9 files changed, 543 insertions(+), 235 deletions(-) diff --git a/include/SDL_config_winrt.h b/include/SDL_config_winrt.h index 0a33993f6943b..2511ab9fa5631 100644 --- a/include/SDL_config_winrt.h +++ b/include/SDL_config_winrt.h @@ -19,11 +19,23 @@ 3. This notice may not be removed or altered from any source distribution. */ -#ifndef _SDL_config_windows_h -#define _SDL_config_windows_h +#ifndef _SDL_config_winrt_h +#define _SDL_config_winrt_h #include "SDL_platform.h" +/* Make sure the Windows SDK's NTDDI_VERSION macro gets defined. This is used + by SDL to determine which version of the Windows SDK is being used. +*/ +#include + +/* Define possibly-undefined NTDDI values (used when compiling SDL against + older versions of the Windows SDK. +*/ +#ifndef NTDDI_WINBLUE +#define NTDDI_WINBLUE 0x06030000 +#endif + /* This is a set of defines to configure the SDL features */ #if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H) @@ -191,4 +203,4 @@ typedef unsigned int uintptr_t; #define SDL_ASSEMBLY_ROUTINES 1 #endif -#endif /* _SDL_config_windows_h */ +#endif /* _SDL_config_winrt_h */ diff --git a/src/core/winrt/SDL_winrtapp_direct3d.cpp b/src/core/winrt/SDL_winrtapp_direct3d.cpp index 267ce4eda03f4..9b29aaee50fbf 100644 --- a/src/core/winrt/SDL_winrtapp_direct3d.cpp +++ b/src/core/winrt/SDL_winrtapp_direct3d.cpp @@ -184,97 +184,48 @@ static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *n } static void -WINRT_ProcessWindowSizeChange() -{ - SDL_VideoDevice *_this = SDL_GetVideoDevice(); - - // Make the new window size be the one true fullscreen mode. - // This change was initially done, in part, to allow the Direct3D 11.1 - // renderer to receive window-resize events as a device rotates. - // Before, rotating a device from landscape, to portrait, and then - // back to landscape would cause the Direct3D 11.1 swap buffer to - // not get resized appropriately. SDL would, on the rotation from - // landscape to portrait, re-resize the SDL window to it's initial - // size (landscape). On the subsequent rotation, SDL would drop the - // window-resize event as it appeared the SDL window didn't change - // size, and the Direct3D 11.1 renderer wouldn't resize its swap - // chain. - SDL_DisplayMode newDisplayMode; - if (WINRT_CalcDisplayModeUsingNativeWindow(&newDisplayMode) != 0) { - return; - } - - // Make note of the old display mode, and it's old driverdata. - SDL_DisplayMode oldDisplayMode; - SDL_zero(oldDisplayMode); - if (_this) { - oldDisplayMode = _this->displays[0].desktop_mode; - } - - // Setup the new display mode in the appropriate spots. - if (_this) { - // Make a full copy of the display mode for display_modes[0], - // one with with a separately malloced 'driverdata' field. - // SDL_VideoQuit(), if called, will attempt to free the driverdata - // fields in 'desktop_mode' and each entry in the 'display_modes' - // array. - if (_this->displays[0].display_modes[0].driverdata) { - // Free the previous mode's memory - SDL_free(_this->displays[0].display_modes[0].driverdata); - _this->displays[0].display_modes[0].driverdata = NULL; - } - if (WINRT_DuplicateDisplayMode(&(_this->displays[0].display_modes[0]), &newDisplayMode) != 0) { - // Uh oh, something went wrong. A malloc call probably failed. - SDL_free(newDisplayMode.driverdata); - return; - } - - // Install 'newDisplayMode' into 'current_mode' and 'desktop_mode'. - _this->displays[0].current_mode = newDisplayMode; - _this->displays[0].desktop_mode = newDisplayMode; - } - - if (WINRT_GlobalSDLWindow) { - // If the window size changed, send a resize event to SDL and its host app: - int window_w = 0; - int window_h = 0; - SDL_GetWindowSize(WINRT_GlobalSDLWindow, &window_w, &window_h); - if ((window_w != newDisplayMode.w) || (window_h != newDisplayMode.h)) { - SDL_SendWindowEvent( - WINRT_GlobalSDLWindow, - SDL_WINDOWEVENT_RESIZED, - newDisplayMode.w, - newDisplayMode.h); - } else { -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - // HACK: Make sure that orientation changes - // lead to the Direct3D renderer's viewport getting updated: - // - // For some reason, this doesn't seem to need to be done on Windows 8.x, - // even when going from Landscape to LandscapeFlipped. It only seems to - // be needed on Windows Phone, at least when I tested on my devices. - // I'm not currently sure why this is, but it seems to work fine. -- David L. - // - // 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 - const DisplayOrientations oldOrientation = ((SDL_DisplayModeData *)oldDisplayMode.driverdata)->currentOrientation; - const DisplayOrientations newOrientation = ((SDL_DisplayModeData *)newDisplayMode.driverdata)->currentOrientation; - if (oldOrientation != newOrientation) - { - SDL_SendWindowEvent( - WINRT_GlobalSDLWindow, - SDL_WINDOWEVENT_SIZE_CHANGED, - newDisplayMode.w, - newDisplayMode.h); +WINRT_ProcessWindowSizeChange() // TODO: Pass an SDL_Window-identifying thing into WINRT_ProcessWindowSizeChange() +{ + CoreWindow ^ coreWindow = CoreWindow::GetForCurrentThread(); + if (coreWindow) { + if (WINRT_GlobalSDLWindow) { + SDL_Window * window = WINRT_GlobalSDLWindow; + SDL_WindowData * data = (SDL_WindowData *) window->driverdata; + + int x = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Left); + int y = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Top); + int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width); + int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height); + +#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION == NTDDI_WIN8) + /* WinPhone 8.0 always keeps its native window size in portrait, + regardless of orientation. This changes in WinPhone 8.1, + in which the native window's size changes along with + orientation. + + Attempt to emulate WinPhone 8.1's behavior on WinPhone 8.0, with + regards to window size. This fixes a rendering bug that occurs + when a WinPhone 8.0 app is rotated to either 90 or 270 degrees. + */ + const DisplayOrientations currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation); + switch (currentOrientation) { + case DisplayOrientations::Landscape: + case DisplayOrientations::LandscapeFlipped: { + int tmp = w; + w = h; + h = tmp; + } break; } #endif + + WINRT_UpdateWindowFlags(window, SDL_WINDOW_MAXIMIZED | SDL_WINDOW_FULLSCREEN_DESKTOP); + + /* The window can move during a resize event, such as when maximizing + or resizing from a corner */ + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y); + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h); } } - - // Finally, free the 'driverdata' field of the old 'desktop_mode'. - if (oldDisplayMode.driverdata) { - SDL_free(oldDisplayMode.driverdata); - oldDisplayMode.driverdata = NULL; - } } SDL_WinRTApp::SDL_WinRTApp() : @@ -286,7 +237,7 @@ SDL_WinRTApp::SDL_WinRTApp() : void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView) { applicationView->Activated += - ref new TypedEventHandler(this, &SDL_WinRTApp::OnActivated); + ref new TypedEventHandler(this, &SDL_WinRTApp::OnAppActivated); CoreApplication::Suspending += ref new EventHandler(this, &SDL_WinRTApp::OnSuspending); @@ -305,35 +256,61 @@ void SDL_WinRTApp::OnOrientationChanged(Object^ sender) #endif { #if LOG_ORIENTATION_EVENTS==1 - CoreWindow^ window = CoreWindow::GetForCurrentThread(); - if (window) { - SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Size={%f,%f}\n", - __FUNCTION__, - WINRT_DISPLAY_PROPERTY(CurrentOrientation), - WINRT_DISPLAY_PROPERTY(NativeOrientation), - WINRT_DISPLAY_PROPERTY(AutoRotationPreferences), - window->Bounds.Width, - window->Bounds.Height); - } else { - SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n", - __FUNCTION__, - WINRT_DISPLAY_PROPERTY(CurrentOrientation), - WINRT_DISPLAY_PROPERTY(NativeOrientation), - WINRT_DISPLAY_PROPERTY(AutoRotationPreferences)); + { + CoreWindow^ window = CoreWindow::GetForCurrentThread(); + if (window) { + SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Bounds={%f,%f,%f,%f}\n", + __FUNCTION__, + WINRT_DISPLAY_PROPERTY(CurrentOrientation), + WINRT_DISPLAY_PROPERTY(NativeOrientation), + WINRT_DISPLAY_PROPERTY(AutoRotationPreferences), + window->Bounds.X, + window->Bounds.Y, + window->Bounds.Width, + window->Bounds.Height); + } else { + SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n", + __FUNCTION__, + WINRT_DISPLAY_PROPERTY(CurrentOrientation), + WINRT_DISPLAY_PROPERTY(NativeOrientation), + WINRT_DISPLAY_PROPERTY(AutoRotationPreferences)); + } } #endif WINRT_ProcessWindowSizeChange(); + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // HACK: Make sure that orientation changes + // lead to the Direct3D renderer's viewport getting updated: + // + // For some reason, this doesn't seem to need to be done on Windows 8.x, + // even when going from Landscape to LandscapeFlipped. It only seems to + // be needed on Windows Phone, at least when I tested on my devices. + // I'm not currently sure why this is, but it seems to work fine. -- David L. + // + // 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 + SDL_Window * window = WINRT_GlobalSDLWindow; + if (window) { + SDL_WindowData * data = (SDL_WindowData *)window->driverdata; + int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width); + int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height); + SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SIZE_CHANGED, w, h); + } +#endif + } void SDL_WinRTApp::SetWindow(CoreWindow^ window) { #if LOG_WINDOW_EVENTS==1 - SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window Size={%f,%f}\n", + SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window bounds={%f, %f, %f,%f}\n", __FUNCTION__, WINRT_DISPLAY_PROPERTY(CurrentOrientation), WINRT_DISPLAY_PROPERTY(NativeOrientation), WINRT_DISPLAY_PROPERTY(AutoRotationPreferences), + window->Bounds.X, + window->Bounds.Y, window->Bounds.Width, window->Bounds.Height); #endif @@ -344,6 +321,9 @@ void SDL_WinRTApp::SetWindow(CoreWindow^ window) window->VisibilityChanged += ref new TypedEventHandler(this, &SDL_WinRTApp::OnVisibilityChanged); + window->Activated += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnWindowActivated); + window->Closed += ref new TypedEventHandler(this, &SDL_WinRTApp::OnWindowClosed); @@ -360,6 +340,12 @@ void SDL_WinRTApp::SetWindow(CoreWindow^ window) window->PointerReleased += ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerReleased); + window->PointerEntered += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerEntered); + + window->PointerExited += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerExited); + window->PointerWheelChanged += ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerWheelChanged); @@ -535,9 +521,10 @@ void SDL_WinRTApp::OnSettingsPaneCommandsRequested( void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args) { #if LOG_WINDOW_EVENTS==1 - SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, WINRT_GlobalSDLWindow?=%s\n", + 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", __FUNCTION__, args->Size.Width, args->Size.Height, + sender->Bounds.X, sender->Bounds.Y, sender->Bounds.Width, sender->Bounds.Height, WINRT_DISPLAY_PROPERTY(CurrentOrientation), WINRT_DISPLAY_PROPERTY(NativeOrientation), WINRT_DISPLAY_PROPERTY(AutoRotationPreferences), @@ -550,20 +537,26 @@ void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEven void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args) { #if LOG_WINDOW_EVENTS==1 - SDL_Log("%s, visible?=%s, WINRT_GlobalSDLWindow?=%s\n", + SDL_Log("%s, visible?=%s, bounds={%f,%f,%f,%f}, WINRT_GlobalSDLWindow?=%s\n", __FUNCTION__, (args->Visible ? "yes" : "no"), + sender->Bounds.X, sender->Bounds.Y, + sender->Bounds.Width, sender->Bounds.Height, (WINRT_GlobalSDLWindow ? "yes" : "no")); #endif m_windowVisible = args->Visible; if (WINRT_GlobalSDLWindow) { SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid; - + Uint32 latestWindowFlags = WINRT_DetectWindowFlags(WINRT_GlobalSDLWindow); if (args->Visible) { SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0); SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0); - SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0); + if (latestWindowFlags & SDL_WINDOW_MAXIMIZED) { + SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MAXIMIZED, 0, 0); + } else { + SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0); + } } else { SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0); SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0); @@ -580,6 +573,59 @@ void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEven } } +void SDL_WinRTApp::OnWindowActivated(CoreWindow^ sender, WindowActivatedEventArgs^ args) +{ +#if LOG_WINDOW_EVENTS==1 + SDL_Log("%s, WINRT_GlobalSDLWindow?=%s\n\n", + __FUNCTION__, + (WINRT_GlobalSDLWindow ? "yes" : "no")); +#endif + + /* There's no property in Win 8.x to tell whether a window is active or + not. [De]activation events are, however, sent to the app. We'll just + record those, in case the CoreWindow gets wrapped by an SDL_Window at + some future time. + */ + sender->CustomProperties->Insert("SDLHelperWindowActivationState", args->WindowActivationState); + + SDL_Window * window = WINRT_GlobalSDLWindow; + if (window) { + if (args->WindowActivationState != CoreWindowActivationState::Deactivated) { + SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0); + if (SDL_GetKeyboardFocus() != window) { + SDL_SetKeyboardFocus(window); + } + + /* Send a mouse-motion event as appropriate. + This doesn't work when called from OnPointerEntered, at least + not in WinRT CoreWindow apps (as OnPointerEntered doesn't + appear to be called after window-reactivation, at least not + in Windows 10, Build 10586.3 (November 2015 update, non-beta). + + Don't do it on WinPhone 8.0 though, as CoreWindow's 'PointerPosition' + property isn't available. + */ +#if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION >= NTDDI_WINBLUE) + Point cursorPos = WINRT_TransformCursorPosition(window, sender->PointerPosition, TransformToSDLWindowSize); + SDL_SendMouseMotion(window, 0, 0, (int)cursorPos.X, (int)cursorPos.Y); +#endif + + /* TODO, WinRT: see if the Win32 bugfix from https://hg.libsdl.org/SDL/rev/d278747da408 needs to be applied (on window activation) */ + //WIN_CheckAsyncMouseRelease(data); + + /* TODO, WinRT: implement clipboard support, if possible */ + ///* + // * FIXME: Update keyboard state + // */ + //WIN_CheckClipboardUpdate(data->videodata); + } else { + if (SDL_GetKeyboardFocus() == window) { + SDL_SetKeyboardFocus(NULL); + } + } + } +} + void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args) { #if LOG_WINDOW_EVENTS==1 @@ -588,7 +634,7 @@ void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args) m_windowClosed = true; } -void SDL_WinRTApp::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args) +void SDL_WinRTApp::OnAppActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args) { CoreWindow::GetForCurrentThread()->Activate(); } @@ -688,10 +734,28 @@ void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args) #if LOG_POINTER_EVENTS WINRT_LogPointerEvent("pointer released", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); #endif - + WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); } +void SDL_WinRTApp::OnPointerEntered(CoreWindow^ sender, PointerEventArgs^ args) +{ +#if LOG_POINTER_EVENTS + WINRT_LogPointerEvent("pointer entered", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); +#endif + + WINRT_ProcessPointerEnteredEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); +} + +void SDL_WinRTApp::OnPointerExited(CoreWindow^ sender, PointerEventArgs^ args) +{ +#if LOG_POINTER_EVENTS + WINRT_LogPointerEvent("pointer exited", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); +#endif + + WINRT_ProcessPointerExitedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); +} + void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args) { #if LOG_POINTER_EVENTS diff --git a/src/core/winrt/SDL_winrtapp_direct3d.h b/src/core/winrt/SDL_winrtapp_direct3d.h index 6a8838ec8f7ae..9cd32fb56c1ab 100644 --- a/src/core/winrt/SDL_winrtapp_direct3d.h +++ b/src/core/winrt/SDL_winrtapp_direct3d.h @@ -56,16 +56,19 @@ ref class SDL_WinRTApp sealed : public Windows::ApplicationModel::Core::IFramewo #endif void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args); void OnLogicalDpiChanged(Platform::Object^ sender); - void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args); + void OnAppActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args); void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args); void OnResuming(Platform::Object^ sender, Platform::Object^ args); void OnExiting(Platform::Object^ sender, Platform::Object^ args); + void OnWindowActivated(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowActivatedEventArgs^ args); void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args); void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args); void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); void OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); void OnPointerWheelChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); + void OnPointerEntered(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); + void OnPointerExited(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); void OnMouseMoved(Windows::Devices::Input::MouseDevice^ mouseDevice, Windows::Devices::Input::MouseEventArgs^ args); void OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args); void OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args); diff --git a/src/render/direct3d11/SDL_render_d3d11.c b/src/render/direct3d11/SDL_render_d3d11.c index ebe4100aa1d0f..c29cfdfe53dcc 100644 --- a/src/render/direct3d11/SDL_render_d3d11.c +++ b/src/render/direct3d11/SDL_render_d3d11.c @@ -760,8 +760,8 @@ SDL_RenderDriver D3D11_RenderDriver = { }; -static Uint32 -DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat) { +Uint32 +D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat) { switch (dxgiFormat) { case DXGI_FORMAT_B8G8R8A8_UNORM: return SDL_PIXELFORMAT_ARGB8888; @@ -2911,7 +2911,7 @@ D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, */ if (SDL_ConvertPixels( rect->w, rect->h, - DXGIFormatToSDLPixelFormat(stagingTextureDesc.Format), + D3D11_DXGIFormatToSDLPixelFormat(stagingTextureDesc.Format), textureMemory.pData, textureMemory.RowPitch, format, diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index b29a87ab65bee..3abe7422a499f 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -1125,6 +1125,10 @@ SDL_RestoreMousePosition(SDL_Window *window) } } +#if __WINRT__ +extern Uint32 WINRT_DetectWindowFlags(SDL_Window * window); +#endif + static int SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) { @@ -1164,6 +1168,30 @@ SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) window->last_fullscreen_flags = window->flags; return 0; } +#elif __WINRT__ + /* HACK: WinRT 8.x apps can't choose whether or not they are fullscreen + or not. The user can choose this, via OS-provided UI, but this can't + be set programmatically. + + Just look at what SDL's WinRT video backend code detected with regards + to fullscreen (being active, or not), and figure out a return/error code + from that. + */ + if (fullscreen == !(WINRT_DetectWindowFlags(window) & FULLSCREEN_MASK)) { + /* Uh oh, either: + 1. fullscreen was requested, and we're already windowed + 2. windowed-mode was requested, and we're already fullscreen + + WinRT 8.x can't resolve either programmatically, so we're + giving up. + */ + return -1; + } else { + /* Whatever was requested, fullscreen or windowed mode, is already + in-place. + */ + return 0; + } #endif display = SDL_GetDisplayForWindow(window); @@ -1377,6 +1405,18 @@ SDL_CreateWindow(const char *title, int x, int y, int w, int h, Uint32 flags) return NULL; } +#if __WINRT__ + /* HACK: WinRT 8.x apps can't choose whether or not they are fullscreen + or not. The user can choose this, via OS-provided UI, but this can't + be set programmatically. + + Just look at what SDL's WinRT video backend code detected with regards + to fullscreen (being active, or not), and figure out a return/error code + from that. + */ + flags = window->flags; +#endif + if (title) { SDL_SetWindowTitle(window, title); } diff --git a/src/video/winrt/SDL_winrtevents_c.h b/src/video/winrt/SDL_winrtevents_c.h index b63c85fa32d84..047be740186af 100644 --- a/src/video/winrt/SDL_winrtevents_c.h +++ b/src/video/winrt/SDL_winrtevents_c.h @@ -57,6 +57,8 @@ extern Uint8 WINRT_GetSDLButtonForPointerPoint(Windows::UI::Input::PointerPoint extern void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); extern void WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); extern void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); +extern void WINRT_ProcessPointerEnteredEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); +extern void WINRT_ProcessPointerExitedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); extern void WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); extern void WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args); diff --git a/src/video/winrt/SDL_winrtpointerinput.cpp b/src/video/winrt/SDL_winrtpointerinput.cpp index d900ef48fae54..2bd3adf29551d 100644 --- a/src/video/winrt/SDL_winrtpointerinput.cpp +++ b/src/video/winrt/SDL_winrtpointerinput.cpp @@ -306,6 +306,28 @@ void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::P } } +void WINRT_ProcessPointerEnteredEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window) { + return; + } + + if (!WINRT_IsTouchEvent(pointerPoint)) { + SDL_SetMouseFocus(window); + } +} + +void WINRT_ProcessPointerExitedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window) { + return; + } + + if (!WINRT_IsTouchEvent(pointerPoint)) { + SDL_SetMouseFocus(NULL); + } +} + void WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) { diff --git a/src/video/winrt/SDL_winrtvideo.cpp b/src/video/winrt/SDL_winrtvideo.cpp index edd56f025b9a7..f125a550cce7b 100644 --- a/src/video/winrt/SDL_winrtvideo.cpp +++ b/src/video/winrt/SDL_winrtvideo.cpp @@ -30,8 +30,17 @@ /* Windows includes */ #include -#include +#include +#include +#include +using namespace Windows::ApplicationModel::Core; +using namespace Windows::Foundation; using namespace Windows::UI::Core; +using namespace Windows::UI::ViewManagement; + + +/* [re]declare Windows GUIDs locally, to limit the amount of external lib(s) SDL has to link to */ +static const GUID IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48,{ 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } }; /* SDL includes */ @@ -44,6 +53,7 @@ extern "C" { #include "../../render/SDL_sysrender.h" #include "SDL_syswm.h" #include "SDL_winrtopengles.h" +#include "../../core/windows/SDL_windows.h" } #include "../../core/winrt/SDL_winrtapp_direct3d.h" @@ -161,110 +171,178 @@ WINRT_VideoInit(_THIS) return 0; } -int -WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode) -{ - SDL_DisplayModeData * driverdata; +extern "C" +Uint32 D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat); - using namespace Windows::Graphics::Display; +static void +WINRT_DXGIModeToSDLDisplayMode(const DXGI_MODE_DESC * dxgiMode, SDL_DisplayMode * sdlMode) +{ + SDL_zerop(sdlMode); + sdlMode->w = dxgiMode->Width; + sdlMode->h = dxgiMode->Height; + sdlMode->refresh_rate = dxgiMode->RefreshRate.Numerator / dxgiMode->RefreshRate.Denominator; + sdlMode->format = D3D11_DXGIFormatToSDLPixelFormat(dxgiMode->Format); +} - // 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 SDL_SetError("SDL/WinRT display modes cannot be calculated outside of the main thread, such as in SDL's XAML thread"); +static int +WINRT_AddDisplaysForOutput (_THIS, IDXGIAdapter1 * dxgiAdapter1, int outputIndex) +{ + HRESULT hr; + IDXGIOutput * dxgiOutput = NULL; + DXGI_OUTPUT_DESC dxgiOutputDesc; + SDL_VideoDisplay display; + char * displayName = NULL; + UINT numModes; + DXGI_MODE_DESC * dxgiModes = NULL; + int functionResult = -1; /* -1 for failure, 0 for success */ + DXGI_MODE_DESC modeToMatch, closestMatch; + + SDL_zero(display); + + hr = dxgiAdapter1->EnumOutputs(outputIndex, &dxgiOutput); + if (FAILED(hr)) { + if (hr != DXGI_ERROR_NOT_FOUND) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIAdapter1::EnumOutputs failed", hr); + } + goto done; } - //SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, DPI = %f\n", - // __FUNCTION__, - // CoreWindow::GetForCurrentThread()->Bounds.Width, CoreWindow::GetForCurrentThread()->Bounds.Height, - // WINRT_DISPLAY_PROPERTY(CurrentOrientation), - // WINRT_DISPLAY_PROPERTY(NativeOrientation), - // WINRT_DISPLAY_PROPERTY(AutoRotationPreferences), - // WINRT_DISPLAY_PROPERTY(LogicalDpi)); - - // Calculate the display size given the window size, taking into account - // the current display's DPI: - const float currentDPI = WINRT_DISPLAY_PROPERTY(LogicalDpi); - const float dipsPerInch = 96.0f; - const int w = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Width * currentDPI) / dipsPerInch); - const int h = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Height * currentDPI) / dipsPerInch); - if (w == 0 || w == h) { - return SDL_SetError("Unable to calculate the WinRT window/display's size"); + hr = dxgiOutput->GetDesc(&dxgiOutputDesc); + if (FAILED(hr)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDesc failed", hr); + goto done; } - // Create a driverdata field: - driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata)); - if (!driverdata) { - return SDL_OutOfMemory(); - } - SDL_zerop(driverdata); - - // Fill in most fields: - SDL_zerop(mode); - mode->format = SDL_PIXELFORMAT_RGB888; - mode->refresh_rate = 0; // TODO, WinRT: see if refresh rate data is available, or relevant (for WinRT apps) - mode->w = w; - mode->h = h; - mode->driverdata = driverdata; - driverdata->currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation); - -#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION == NTDDI_WIN8) - // On Windows Phone 8.0, the native window's size is always in portrait, - // regardless of the device's orientation. This is in contrast to - // Windows 8.x/RT and Windows Phone 8.1, which will resize the native window as the device's - // orientation changes. In order to compensate for this behavior, - // on Windows Phone, the mode's width and height will be swapped when - // the device is in a landscape (non-portrait) mode. - switch (driverdata->currentOrientation) { - case DisplayOrientations::Landscape: - case DisplayOrientations::LandscapeFlipped: - { - const int tmp = mode->h; - mode->h = mode->w; - mode->w = tmp; - break; + SDL_zero(modeToMatch); + modeToMatch.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + modeToMatch.Width = (dxgiOutputDesc.DesktopCoordinates.right - dxgiOutputDesc.DesktopCoordinates.left); + modeToMatch.Height = (dxgiOutputDesc.DesktopCoordinates.bottom - dxgiOutputDesc.DesktopCoordinates.top); + hr = dxgiOutput->FindClosestMatchingMode(&modeToMatch, &closestMatch, NULL); + if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) { + /* DXGI_ERROR_NOT_CURRENTLY_AVAILABLE gets returned by IDXGIOutput::FindClosestMatchingMode + when running under the Windows Simulator, which uses Remote Desktop (formerly known as Terminal + Services) under the hood. According to the MSDN docs for the similar function, + IDXGIOutput::GetDisplayModeList, DXGI_ERROR_NOT_CURRENTLY_AVAILABLE is returned if and + when an app is run under a Terminal Services session, hence the assumption. + + In this case, just add an SDL display mode, with approximated values. + */ + SDL_DisplayMode mode; + SDL_zero(mode); + display.name = "Windows Simulator / Terminal Services Display"; + mode.w = (dxgiOutputDesc.DesktopCoordinates.right - dxgiOutputDesc.DesktopCoordinates.left); + mode.h = (dxgiOutputDesc.DesktopCoordinates.bottom - dxgiOutputDesc.DesktopCoordinates.top); + mode.format = DXGI_FORMAT_B8G8R8A8_UNORM; + mode.refresh_rate = 0; /* Display mode is unknown, so just fill in zero, as specified by SDL's header files */ + display.desktop_mode = mode; + display.current_mode = mode; + if ( ! SDL_AddDisplayMode(&display, &mode)) { + goto done; + } + } else if (FAILED(hr)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::FindClosestMatchingMode failed", hr); + goto done; + } else { + displayName = WIN_StringToUTF8(dxgiOutputDesc.DeviceName); + display.name = displayName; + WINRT_DXGIModeToSDLDisplayMode(&closestMatch, &display.desktop_mode); + display.current_mode = display.desktop_mode; + + hr = dxgiOutput->GetDisplayModeList(DXGI_FORMAT_B8G8R8A8_UNORM, 0, &numModes, NULL); + if (FAILED(hr)) { + if (hr == DXGI_ERROR_NOT_CURRENTLY_AVAILABLE) { + // TODO, WinRT: make sure display mode(s) are added when using Terminal Services / Windows Simulator + } + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDisplayModeList [get mode list size] failed", hr); + goto done; } - default: - break; + dxgiModes = (DXGI_MODE_DESC *)SDL_calloc(numModes, sizeof(DXGI_MODE_DESC)); + if ( ! dxgiModes) { + SDL_OutOfMemory(); + goto done; + } + + hr = dxgiOutput->GetDisplayModeList(DXGI_FORMAT_B8G8R8A8_UNORM, 0, &numModes, dxgiModes); + if (FAILED(hr)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDisplayModeList [get mode contents] failed", hr); + goto done; + } + + for (UINT i = 0; i < numModes; ++i) { + SDL_DisplayMode sdlMode; + WINRT_DXGIModeToSDLDisplayMode(&dxgiModes[i], &sdlMode); + SDL_AddDisplayMode(&display, &sdlMode); + } } -#endif - return 0; + if (SDL_AddVideoDisplay(&display) < 0) { + goto done; + } + + functionResult = 0; /* 0 for Success! */ +done: + if (dxgiModes) { + SDL_free(dxgiModes); + } + if (dxgiOutput) { + dxgiOutput->Release(); + } + if (displayName) { + SDL_free(displayName); + } + return functionResult; } -int -WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src) +static int +WINRT_AddDisplaysForAdapter (_THIS, IDXGIFactory2 * dxgiFactory2, int adapterIndex) { - SDL_DisplayModeData * driverdata; - driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata)); - if (!driverdata) { - return SDL_OutOfMemory(); + HRESULT hr; + IDXGIAdapter1 * dxgiAdapter1; + + hr = dxgiFactory2->EnumAdapters1(adapterIndex, &dxgiAdapter1); + if (FAILED(hr)) { + if (hr != DXGI_ERROR_NOT_FOUND) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory1::EnumAdapters1() failed", hr); + } + return -1; + } + + for (int outputIndex = 0; ; ++outputIndex) { + if (WINRT_AddDisplaysForOutput(_this, dxgiAdapter1, outputIndex) < 0) { + break; + } } - SDL_memcpy(driverdata, src->driverdata, sizeof(SDL_DisplayModeData)); - SDL_memcpy(dest, src, sizeof(SDL_DisplayMode)); - dest->driverdata = driverdata; + + dxgiAdapter1->Release(); return 0; } int WINRT_InitModes(_THIS) { - // Retrieve the display mode: - SDL_DisplayMode mode, desktop_mode; - if (WINRT_CalcDisplayModeUsingNativeWindow(&mode) != 0) { - return -1; // If WINRT_CalcDisplayModeUsingNativeWindow fails, it'll already have set the SDL error - } + /* HACK: Initialize a single display, for whatever screen the app's + CoreApplicationView is on. + TODO, WinRT: Try initializing multiple displays, one for each monitor. + Appropriate WinRT APIs for this seem elusive, though. -- DavidL + */ - if (WINRT_DuplicateDisplayMode(&desktop_mode, &mode) != 0) { + HRESULT hr; + IDXGIFactory2 * dxgiFactory2 = NULL; + + hr = CreateDXGIFactory1(IID_IDXGIFactory2, (void **)&dxgiFactory2); + if (FAILED(hr)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", CreateDXGIFactory1() failed", hr); return -1; } - if (SDL_AddBasicVideoDisplay(&desktop_mode) < 0) { - return -1; + + int adapterIndex = 0; + for (int adapterIndex = 0; ; ++adapterIndex) { + if (WINRT_AddDisplaysForAdapter(_this, dxgiFactory2, adapterIndex) < 0) { + break; + } } - SDL_AddDisplayMode(&_this->displays[0], &mode); return 0; } @@ -280,6 +358,64 @@ WINRT_VideoQuit(_THIS) WINRT_QuitMouse(_this); } +extern "C" Uint32 +WINRT_DetectWindowFlags(SDL_Window * window) +{ + Uint32 latestFlags = 0; + SDL_WindowData * data = (SDL_WindowData *) window->driverdata; + bool is_fullscreen = false; + +#if SDL_WINRT_USE_APPLICATIONVIEW + if (data->appView) { + is_fullscreen = data->appView->IsFullScreen; + } +#elif (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) + is_fullscreen = true; +#endif + + if (data->coreWindow.Get()) { + if (is_fullscreen) { + SDL_VideoDisplay * display = SDL_GetDisplayForWindow(window); + if (display->desktop_mode.w != WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width) || + display->desktop_mode.h != WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height)) + { + latestFlags |= SDL_WINDOW_MAXIMIZED; + } else { + latestFlags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + } + } + + if (data->coreWindow->Visible) { + latestFlags |= SDL_WINDOW_SHOWN; + } else { + latestFlags |= SDL_WINDOW_HIDDEN; + } + +#if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION < NTDDI_WINBLUE) + // data->coreWindow->PointerPosition is not supported on WinPhone 8.0 + latestFlags |= SDL_WINDOW_MOUSE_FOCUS; +#else + if (data->coreWindow->Bounds.Contains(data->coreWindow->PointerPosition)) { + latestFlags |= SDL_WINDOW_MOUSE_FOCUS; + } +#endif + } + + return latestFlags; +} + +void +WINRT_UpdateWindowFlags(SDL_Window * window, Uint32 mask) +{ + if (window) { + Uint32 apply = WINRT_DetectWindowFlags(window); + if ((apply & mask) & SDL_WINDOW_FULLSCREEN) { + window->last_fullscreen_flags = window->flags; // seems necessary to programmatically un-fullscreen, via SDL APIs + } + window->flags = (window->flags & ~mask) | (apply & mask); + } +} + int WINRT_CreateWindow(_THIS, SDL_Window * window) { @@ -290,7 +426,7 @@ WINRT_CreateWindow(_THIS, SDL_Window * window) return -1; } - SDL_WindowData *data = new SDL_WindowData; + SDL_WindowData *data = new SDL_WindowData; /* use 'new' here as SDL_WindowData may use WinRT/C++ types */ if (!data) { SDL_OutOfMemory(); return -1; @@ -306,6 +442,9 @@ WINRT_CreateWindow(_THIS, SDL_Window * window) */ if (!WINRT_XAMLWasEnabled) { data->coreWindow = CoreWindow::GetForCurrentThread(); +#if SDL_WINRT_USE_APPLICATIONVIEW + data->appView = ApplicationView::GetForCurrentView(); +#endif } #if SDL_VIDEO_OPENGL_EGL @@ -359,17 +498,18 @@ WINRT_CreateWindow(_THIS, SDL_Window * window) } #endif - /* Make sure the window is considered to be positioned at {0,0}, - and is considered fullscreen, shown, and the like. - */ - window->x = 0; - window->y = 0; +#if SDL_WINRT_USE_APPLICATIONVIEW + /* Determine as many flags dynamically, as possible. */ + window->flags = + SDL_WINDOW_BORDERLESS; +#else + /* Set SDL_Window flags for Windows Phone 8.0 */ window->flags = - SDL_WINDOW_FULLSCREEN | - SDL_WINDOW_SHOWN | + SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_BORDERLESS | SDL_WINDOW_MAXIMIZED | SDL_WINDOW_INPUT_GRABBED; +#endif #if SDL_VIDEO_OPENGL_EGL if (data->egl_surface) { @@ -377,20 +517,40 @@ WINRT_CreateWindow(_THIS, SDL_Window * window) } #endif - /* WinRT does not, as of this writing, appear to support app-adjustable - window sizes. Set the window size to whatever the native WinRT - CoreWindow is set at. - - TODO, WinRT: if and when non-fullscreen XAML control support is added to SDL, consider making those resizable via SDL_Window's interfaces. - */ - window->w = _this->displays[0].current_mode.w; - window->h = _this->displays[0].current_mode.h; - - /* For now, treat WinRT apps as if they always have focus. - TODO, WinRT: try tracking keyboard and mouse focus state with respect to snapped apps - */ - SDL_SetMouseFocus(window); - SDL_SetKeyboardFocus(window); + if (WINRT_XAMLWasEnabled) { + /* TODO, WinRT: set SDL_Window size, maybe position too, from XAML control */ + window->x = 0; + window->y = 0; + window->flags |= SDL_WINDOW_SHOWN; + SDL_SetMouseFocus(NULL); // TODO: detect this + SDL_SetKeyboardFocus(NULL); // TODO: detect this + } else { + /* WinRT apps seem to live in an environment where the OS controls the + app's window size, with some apps being fullscreen, depending on + user choice of various things. For now, just adapt the SDL_Window to + whatever Windows set-up as the native-window's geometry. + */ + window->x = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Left); + window->y = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Top); + window->w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width); + window->h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height); + + WINRT_UpdateWindowFlags( + window, + 0xffffffff /* Update any window flag(s) that WINRT_UpdateWindow can handle */ + ); + + /* Try detecting if the window is active */ + bool isWindowActive = true; /* Presume the window is active, unless we've been told otherwise */ + if (data->coreWindow->CustomProperties->HasKey("SDLHelperWindowActivationState")) { + CoreWindowActivationState activationState = \ + safe_cast(data->coreWindow->CustomProperties->Lookup("SDLHelperWindowActivationState")); + isWindowActive = (activationState != CoreWindowActivationState::Deactivated); + } + if (isWindowActive) { + SDL_SetKeyboardFocus(window); + } + } /* Make sure the WinRT app's IFramworkView can post events on behalf of SDL: diff --git a/src/video/winrt/SDL_winrtvideo_cpp.h b/src/video/winrt/SDL_winrtvideo_cpp.h index a39de826a02de..392ef20fde4f8 100644 --- a/src/video/winrt/SDL_winrtvideo_cpp.h +++ b/src/video/winrt/SDL_winrtvideo_cpp.h @@ -29,6 +29,12 @@ #include "SDL_video.h" #include "SDL_events.h" +#if NTDDI_VERSION >= NTDDI_WINBLUE /* ApplicationView's functionality only becomes + useful for SDL in Win[Phone] 8.1 and up. + Plus, it is not available at all in WinPhone 8.0. */ +#define SDL_WINRT_USE_APPLICATIONVIEW 1 +#endif + extern "C" { #include "../SDL_sysvideo.h" #include "../SDL_egl_c.h" @@ -48,25 +54,17 @@ typedef struct SDL_VideoData { */ extern SDL_Window * WINRT_GlobalSDLWindow; -/* Creates a display mode for Plain Direct3D (non-XAML) apps, using the lone, native window's settings. - - Pass in an allocated SDL_DisplayMode field to store the data in. - - This function will return 0 on success, -1 on failure. - - If this function succeeds, be sure to call SDL_free on the - SDL_DisplayMode's driverdata field. +/* Updates one or more SDL_Window flags, by querying the OS' native windowing APIs. + SDL_Window flags that can be updated should be specified in 'mask'. */ -extern int WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode); - -/* Duplicates a display mode, copying over driverdata as necessary */ -extern int WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src); +extern void WINRT_UpdateWindowFlags(SDL_Window * window, Uint32 mask); +extern "C" Uint32 WINRT_DetectWindowFlags(SDL_Window * window); /* detects flags w/o applying them */ /* Display mode internals */ -typedef struct -{ - Windows::Graphics::Display::DisplayOrientations currentOrientation; -} SDL_DisplayModeData; +//typedef struct +//{ +// Windows::Graphics::Display::DisplayOrientations currentOrientation; +//} SDL_DisplayModeData; #ifdef __cplusplus_winrt @@ -77,6 +75,10 @@ typedef struct #define WINRT_DISPLAY_PROPERTY(NAME) (Windows::Graphics::Display::DisplayProperties::NAME) #endif +/* Converts DIPS to physical pixels */ +#define WINRT_DIPS_TO_PHYSICAL_PIXELS(DIPS) ((int)(0.5f + (((float)(DIPS) * (float)WINRT_DISPLAY_PROPERTY(LogicalDpi)) / 96.f))) + + /* Internal window data */ struct SDL_WindowData { @@ -85,6 +87,9 @@ struct SDL_WindowData #ifdef SDL_VIDEO_OPENGL_EGL EGLSurface egl_surface; #endif +#if SDL_WINRT_USE_APPLICATIONVIEW + Windows::UI::ViewManagement::ApplicationView ^ appView; +#endif }; #endif // ifdef __cplusplus_winrt