From 623898f70bc41b0fad1ceb8fa27947f3b3931b78 Mon Sep 17 00:00:00 2001
From: David Ludwig <dludwig@pobox.com>
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  | 276 ++++++++++------
 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        | 380 +++++++++++++++-------
 src/video/winrt/SDL_winrtvideo_cpp.h      |  37 ++-
 9 files changed, 547 insertions(+), 239 deletions(-)

diff --git a/include/SDL_config_winrt.h b/include/SDL_config_winrt.h
index 0a33993f6..2511ab9fa 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 <sdkddkver.h>
+
+/* 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 267ce4eda..9b29aaee5 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()
+WINRT_ProcessWindowSizeChange() // TODO: Pass an SDL_Window-identifying thing into WINRT_ProcessWindowSizeChange()
 {
-    SDL_VideoDevice *_this = SDL_GetVideoDevice();
+    CoreWindow ^ coreWindow = CoreWindow::GetForCurrentThread();
+    if (coreWindow) {
+        if (WINRT_GlobalSDLWindow) {
+            SDL_Window * window = WINRT_GlobalSDLWindow;
+            SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
 
-    // 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;
-    }
+            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);
 
-    // 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;
-    }
+#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.
 
-    // 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);
+               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<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnActivated);
+        ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnAppActivated);
 
     CoreApplication::Suspending +=
         ref new EventHandler<SuspendingEventArgs^>(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<CoreWindow^, VisibilityChangedEventArgs^>(this, &SDL_WinRTApp::OnVisibilityChanged);
 
+    window->Activated +=
+        ref new TypedEventHandler<CoreWindow^, WindowActivatedEventArgs^>(this, &SDL_WinRTApp::OnWindowActivated);
+
     window->Closed += 
         ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &SDL_WinRTApp::OnWindowClosed);
 
@@ -360,6 +340,12 @@ void SDL_WinRTApp::SetWindow(CoreWindow^ window)
     window->PointerReleased +=
         ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerReleased);
 
+    window->PointerEntered +=
+        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerEntered);
+
+    window->PointerExited +=
+        ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerExited);
+
     window->PointerWheelChanged +=
         ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(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 6a8838ec8..9cd32fb56 100644
--- a/src/core/winrt/SDL_winrtapp_direct3d.h
+++ b/src/core/winrt/SDL_winrtapp_direct3d.h
@@ -56,16 +56,19 @@ protected:
 #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 ebe4100aa..c29cfdfe5 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 b29a87ab6..3abe7422a 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 b63c85fa3..047be7401 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 d900ef48f..2bd3adf29 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 edd56f025..f125a550c 100644
--- a/src/video/winrt/SDL_winrtvideo.cpp
+++ b/src/video/winrt/SDL_winrtvideo.cpp
@@ -30,8 +30,17 @@
 
 /* Windows includes */
 #include <agile.h>
-#include <wrl/client.h>
+#include <windows.graphics.display.h>
+#include <dxgi.h>
+#include <dxgi1_2.h>
+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)
+extern "C"
+Uint32 D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat);
+
+static void
+WINRT_DXGIModeToSDLDisplayMode(const DXGI_MODE_DESC * dxgiMode, SDL_DisplayMode * sdlMode)
 {
-    SDL_DisplayModeData * driverdata;
-
-    using namespace Windows::Graphics::Display;
-
-    // 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");
-    }
-
-    //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");
-    }
-
-    // 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;
-        }
-
-        default:
-            break;
-    }
-#endif
-
-    return 0;
+    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);
 }
 
-int
-WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src)
+static int
+WINRT_AddDisplaysForOutput (_THIS, IDXGIAdapter1 * dxgiAdapter1, int outputIndex)
 {
-    SDL_DisplayModeData * driverdata;
-    driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata));
-    if (!driverdata) {
-        return SDL_OutOfMemory();
+    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_memcpy(driverdata, src->driverdata, sizeof(SDL_DisplayModeData));
-    SDL_memcpy(dest, src, sizeof(SDL_DisplayMode));
-    dest->driverdata = driverdata;
+
+    hr = dxgiOutput->GetDesc(&dxgiOutputDesc);
+    if (FAILED(hr)) {
+        WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIOutput::GetDesc failed", hr);
+        goto done;
+    }
+
+    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;
+        }
+
+        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);
+        }
+    }
+
+    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;
+}
+
+static int
+WINRT_AddDisplaysForAdapter (_THIS, IDXGIFactory2 * dxgiFactory2, int adapterIndex)
+{
+    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;
+        }
+    }
+
+    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) {
-        return -1;
-    }
-    if (SDL_AddBasicVideoDisplay(&desktop_mode) < 0) {
+    HRESULT hr;
+    IDXGIFactory2 * dxgiFactory2 = NULL;
+
+    hr = CreateDXGIFactory1(IID_IDXGIFactory2, (void **)&dxgiFactory2);
+    if (FAILED(hr)) {
+        WIN_SetErrorFromHRESULT(__FUNCTION__ ", CreateDXGIFactory1() failed", hr);
         return -1;
     }
 
-    SDL_AddDisplayMode(&_this->displays[0], &mode);
+    int adapterIndex = 0;
+    for (int adapterIndex = 0; ; ++adapterIndex) {
+        if (WINRT_AddDisplaysForAdapter(_this, dxgiFactory2, adapterIndex) < 0) {
+            break;
+        }
+    }
+
     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_FULLSCREEN |
-        SDL_WINDOW_SHOWN |
+        SDL_WINDOW_BORDERLESS;
+#else
+    /* Set SDL_Window flags for Windows Phone 8.0 */
+    window->flags =
+        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.
+    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);
 
-       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;
+        WINRT_UpdateWindowFlags(
+            window,
+            0xffffffff      /* Update any window flag(s) that WINRT_UpdateWindow can handle */
+        );
 
-    /* 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);
+        /* 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<CoreWindowActivationState>(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 a39de826a..392ef20fd 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