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).
This commit is contained in:
David Ludwig 2015-11-26 00:41:39 -05:00
parent a5a80cd033
commit 623898f70b
9 changed files with 547 additions and 239 deletions

View File

@ -19,11 +19,23 @@
3. This notice may not be removed or altered from any source distribution. 3. This notice may not be removed or altered from any source distribution.
*/ */
#ifndef _SDL_config_windows_h #ifndef _SDL_config_winrt_h
#define _SDL_config_windows_h #define _SDL_config_winrt_h
#include "SDL_platform.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 */ /* This is a set of defines to configure the SDL features */
#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H) #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 #define SDL_ASSEMBLY_ROUTINES 1
#endif #endif
#endif /* _SDL_config_windows_h */ #endif /* _SDL_config_winrt_h */

View File

@ -184,97 +184,48 @@ static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *n
} }
static void 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. int x = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Left);
// This change was initially done, in part, to allow the Direct3D 11.1 int y = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Top);
// renderer to receive window-resize events as a device rotates. int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
// Before, rotating a device from landscape, to portrait, and then int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
// 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. #if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION == NTDDI_WIN8)
SDL_DisplayMode oldDisplayMode; /* WinPhone 8.0 always keeps its native window size in portrait,
SDL_zero(oldDisplayMode); regardless of orientation. This changes in WinPhone 8.1,
if (_this) { in which the native window's size changes along with
oldDisplayMode = _this->displays[0].desktop_mode; orientation.
}
// Setup the new display mode in the appropriate spots. Attempt to emulate WinPhone 8.1's behavior on WinPhone 8.0, with
if (_this) { regards to window size. This fixes a rendering bug that occurs
// Make a full copy of the display mode for display_modes[0], when a WinPhone 8.0 app is rotated to either 90 or 270 degrees.
// one with with a separately malloced 'driverdata' field. */
// SDL_VideoQuit(), if called, will attempt to free the driverdata const DisplayOrientations currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation);
// fields in 'desktop_mode' and each entry in the 'display_modes' switch (currentOrientation) {
// array. case DisplayOrientations::Landscape:
if (_this->displays[0].display_modes[0].driverdata) { case DisplayOrientations::LandscapeFlipped: {
// Free the previous mode's memory int tmp = w;
SDL_free(_this->displays[0].display_modes[0].driverdata); w = h;
_this->displays[0].display_modes[0].driverdata = NULL; h = tmp;
} } break;
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);
} }
#endif #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() : SDL_WinRTApp::SDL_WinRTApp() :
@ -286,7 +237,7 @@ SDL_WinRTApp::SDL_WinRTApp() :
void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView) void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView)
{ {
applicationView->Activated += applicationView->Activated +=
ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnActivated); ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnAppActivated);
CoreApplication::Suspending += CoreApplication::Suspending +=
ref new EventHandler<SuspendingEventArgs^>(this, &SDL_WinRTApp::OnSuspending); ref new EventHandler<SuspendingEventArgs^>(this, &SDL_WinRTApp::OnSuspending);
@ -305,35 +256,61 @@ void SDL_WinRTApp::OnOrientationChanged(Object^ sender)
#endif #endif
{ {
#if LOG_ORIENTATION_EVENTS==1 #if LOG_ORIENTATION_EVENTS==1
CoreWindow^ window = CoreWindow::GetForCurrentThread(); {
if (window) { CoreWindow^ window = CoreWindow::GetForCurrentThread();
SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Size={%f,%f}\n", if (window) {
__FUNCTION__, SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Bounds={%f,%f,%f,%f}\n",
WINRT_DISPLAY_PROPERTY(CurrentOrientation), __FUNCTION__,
WINRT_DISPLAY_PROPERTY(NativeOrientation), WINRT_DISPLAY_PROPERTY(CurrentOrientation),
WINRT_DISPLAY_PROPERTY(AutoRotationPreferences), WINRT_DISPLAY_PROPERTY(NativeOrientation),
window->Bounds.Width, WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
window->Bounds.Height); window->Bounds.X,
} else { window->Bounds.Y,
SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n", window->Bounds.Width,
__FUNCTION__, window->Bounds.Height);
WINRT_DISPLAY_PROPERTY(CurrentOrientation), } else {
WINRT_DISPLAY_PROPERTY(NativeOrientation), SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n",
WINRT_DISPLAY_PROPERTY(AutoRotationPreferences)); __FUNCTION__,
WINRT_DISPLAY_PROPERTY(CurrentOrientation),
WINRT_DISPLAY_PROPERTY(NativeOrientation),
WINRT_DISPLAY_PROPERTY(AutoRotationPreferences));
}
} }
#endif #endif
WINRT_ProcessWindowSizeChange(); 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) void SDL_WinRTApp::SetWindow(CoreWindow^ window)
{ {
#if LOG_WINDOW_EVENTS==1 #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__, __FUNCTION__,
WINRT_DISPLAY_PROPERTY(CurrentOrientation), WINRT_DISPLAY_PROPERTY(CurrentOrientation),
WINRT_DISPLAY_PROPERTY(NativeOrientation), WINRT_DISPLAY_PROPERTY(NativeOrientation),
WINRT_DISPLAY_PROPERTY(AutoRotationPreferences), WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
window->Bounds.X,
window->Bounds.Y,
window->Bounds.Width, window->Bounds.Width,
window->Bounds.Height); window->Bounds.Height);
#endif #endif
@ -344,6 +321,9 @@ void SDL_WinRTApp::SetWindow(CoreWindow^ window)
window->VisibilityChanged += window->VisibilityChanged +=
ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &SDL_WinRTApp::OnVisibilityChanged); ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &SDL_WinRTApp::OnVisibilityChanged);
window->Activated +=
ref new TypedEventHandler<CoreWindow^, WindowActivatedEventArgs^>(this, &SDL_WinRTApp::OnWindowActivated);
window->Closed += window->Closed +=
ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &SDL_WinRTApp::OnWindowClosed); ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &SDL_WinRTApp::OnWindowClosed);
@ -360,6 +340,12 @@ void SDL_WinRTApp::SetWindow(CoreWindow^ window)
window->PointerReleased += window->PointerReleased +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerReleased); 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 += window->PointerWheelChanged +=
ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerWheelChanged); 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) void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
{ {
#if LOG_WINDOW_EVENTS==1 #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__, __FUNCTION__,
args->Size.Width, args->Size.Height, 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(CurrentOrientation),
WINRT_DISPLAY_PROPERTY(NativeOrientation), WINRT_DISPLAY_PROPERTY(NativeOrientation),
WINRT_DISPLAY_PROPERTY(AutoRotationPreferences), WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
@ -550,20 +537,26 @@ void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEven
void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args) void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
{ {
#if LOG_WINDOW_EVENTS==1 #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__, __FUNCTION__,
(args->Visible ? "yes" : "no"), (args->Visible ? "yes" : "no"),
sender->Bounds.X, sender->Bounds.Y,
sender->Bounds.Width, sender->Bounds.Height,
(WINRT_GlobalSDLWindow ? "yes" : "no")); (WINRT_GlobalSDLWindow ? "yes" : "no"));
#endif #endif
m_windowVisible = args->Visible; m_windowVisible = args->Visible;
if (WINRT_GlobalSDLWindow) { if (WINRT_GlobalSDLWindow) {
SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid; SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid;
Uint32 latestWindowFlags = WINRT_DetectWindowFlags(WINRT_GlobalSDLWindow);
if (args->Visible) { if (args->Visible) {
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0); 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_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 { } else {
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0); SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0);
SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_LOST, 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) void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
{ {
#if LOG_WINDOW_EVENTS==1 #if LOG_WINDOW_EVENTS==1
@ -588,7 +634,7 @@ void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
m_windowClosed = true; m_windowClosed = true;
} }
void SDL_WinRTApp::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args) void SDL_WinRTApp::OnAppActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
{ {
CoreWindow::GetForCurrentThread()->Activate(); CoreWindow::GetForCurrentThread()->Activate();
} }
@ -688,10 +734,28 @@ void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args)
#if LOG_POINTER_EVENTS #if LOG_POINTER_EVENTS
WINRT_LogPointerEvent("pointer released", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); WINRT_LogPointerEvent("pointer released", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
#endif #endif
WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); 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) void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args)
{ {
#if LOG_POINTER_EVENTS #if LOG_POINTER_EVENTS

View File

@ -56,16 +56,19 @@ protected:
#endif #endif
void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args); void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args);
void OnLogicalDpiChanged(Platform::Object^ sender); 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 OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args);
void OnResuming(Platform::Object^ sender, Platform::Object^ args); void OnResuming(Platform::Object^ sender, Platform::Object^ args);
void OnExiting(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 OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);
void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ 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 OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
void OnPointerReleased(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 OnPointerWheelChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
void OnPointerMoved(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 OnMouseMoved(Windows::Devices::Input::MouseDevice^ mouseDevice, Windows::Devices::Input::MouseEventArgs^ args);
void OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ 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); void OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);

View File

@ -760,8 +760,8 @@ SDL_RenderDriver D3D11_RenderDriver = {
}; };
static Uint32 Uint32
DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat) { D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat) {
switch (dxgiFormat) { switch (dxgiFormat) {
case DXGI_FORMAT_B8G8R8A8_UNORM: case DXGI_FORMAT_B8G8R8A8_UNORM:
return SDL_PIXELFORMAT_ARGB8888; return SDL_PIXELFORMAT_ARGB8888;
@ -2911,7 +2911,7 @@ D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
*/ */
if (SDL_ConvertPixels( if (SDL_ConvertPixels(
rect->w, rect->h, rect->w, rect->h,
DXGIFormatToSDLPixelFormat(stagingTextureDesc.Format), D3D11_DXGIFormatToSDLPixelFormat(stagingTextureDesc.Format),
textureMemory.pData, textureMemory.pData,
textureMemory.RowPitch, textureMemory.RowPitch,
format, format,

View File

@ -1125,6 +1125,10 @@ SDL_RestoreMousePosition(SDL_Window *window)
} }
} }
#if __WINRT__
extern Uint32 WINRT_DetectWindowFlags(SDL_Window * window);
#endif
static int static int
SDL_UpdateFullscreenMode(SDL_Window * window, SDL_bool fullscreen) 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; window->last_fullscreen_flags = window->flags;
return 0; 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 #endif
display = SDL_GetDisplayForWindow(window); 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; 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) { if (title) {
SDL_SetWindowTitle(window, title); SDL_SetWindowTitle(window, title);
} }

View File

@ -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_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint);
extern void WINRT_ProcessPointerMovedEvent(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_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_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint);
extern void WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args); extern void WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args);

View File

@ -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 void
WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
{ {

View File

@ -30,8 +30,17 @@
/* Windows includes */ /* Windows includes */
#include <agile.h> #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::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 */ /* SDL includes */
@ -44,6 +53,7 @@ extern "C" {
#include "../../render/SDL_sysrender.h" #include "../../render/SDL_sysrender.h"
#include "SDL_syswm.h" #include "SDL_syswm.h"
#include "SDL_winrtopengles.h" #include "SDL_winrtopengles.h"
#include "../../core/windows/SDL_windows.h"
} }
#include "../../core/winrt/SDL_winrtapp_direct3d.h" #include "../../core/winrt/SDL_winrtapp_direct3d.h"
@ -161,110 +171,178 @@ WINRT_VideoInit(_THIS)
return 0; return 0;
} }
int extern "C"
WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode) Uint32 D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat);
static void
WINRT_DXGIModeToSDLDisplayMode(const DXGI_MODE_DESC * dxgiMode, SDL_DisplayMode * sdlMode)
{ {
SDL_DisplayModeData * driverdata; SDL_zerop(sdlMode);
sdlMode->w = dxgiMode->Width;
using namespace Windows::Graphics::Display; sdlMode->h = dxgiMode->Height;
sdlMode->refresh_rate = dxgiMode->RefreshRate.Numerator / dxgiMode->RefreshRate.Denominator;
// Go no further if a native window cannot be accessed. This can happen, sdlMode->format = D3D11_DXGIFormatToSDLPixelFormat(dxgiMode->Format);
// 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;
} }
int static int
WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src) WINRT_AddDisplaysForOutput (_THIS, IDXGIAdapter1 * dxgiAdapter1, int outputIndex)
{ {
SDL_DisplayModeData * driverdata; HRESULT hr;
driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata)); IDXGIOutput * dxgiOutput = NULL;
if (!driverdata) { DXGI_OUTPUT_DESC dxgiOutputDesc;
return SDL_OutOfMemory(); 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)); hr = dxgiOutput->GetDesc(&dxgiOutputDesc);
dest->driverdata = driverdata; 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; return 0;
} }
int int
WINRT_InitModes(_THIS) WINRT_InitModes(_THIS)
{ {
// Retrieve the display mode: /* HACK: Initialize a single display, for whatever screen the app's
SDL_DisplayMode mode, desktop_mode; CoreApplicationView is on.
if (WINRT_CalcDisplayModeUsingNativeWindow(&mode) != 0) { TODO, WinRT: Try initializing multiple displays, one for each monitor.
return -1; // If WINRT_CalcDisplayModeUsingNativeWindow fails, it'll already have set the SDL error Appropriate WinRT APIs for this seem elusive, though. -- DavidL
} */
if (WINRT_DuplicateDisplayMode(&desktop_mode, &mode) != 0) { HRESULT hr;
return -1; IDXGIFactory2 * dxgiFactory2 = NULL;
}
if (SDL_AddBasicVideoDisplay(&desktop_mode) < 0) { hr = CreateDXGIFactory1(IID_IDXGIFactory2, (void **)&dxgiFactory2);
if (FAILED(hr)) {
WIN_SetErrorFromHRESULT(__FUNCTION__ ", CreateDXGIFactory1() failed", hr);
return -1; 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; return 0;
} }
@ -280,6 +358,64 @@ WINRT_VideoQuit(_THIS)
WINRT_QuitMouse(_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 int
WINRT_CreateWindow(_THIS, SDL_Window * window) WINRT_CreateWindow(_THIS, SDL_Window * window)
{ {
@ -290,7 +426,7 @@ WINRT_CreateWindow(_THIS, SDL_Window * window)
return -1; 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) { if (!data) {
SDL_OutOfMemory(); SDL_OutOfMemory();
return -1; return -1;
@ -306,6 +442,9 @@ WINRT_CreateWindow(_THIS, SDL_Window * window)
*/ */
if (!WINRT_XAMLWasEnabled) { if (!WINRT_XAMLWasEnabled) {
data->coreWindow = CoreWindow::GetForCurrentThread(); data->coreWindow = CoreWindow::GetForCurrentThread();
#if SDL_WINRT_USE_APPLICATIONVIEW
data->appView = ApplicationView::GetForCurrentView();
#endif
} }
#if SDL_VIDEO_OPENGL_EGL #if SDL_VIDEO_OPENGL_EGL
@ -359,17 +498,18 @@ WINRT_CreateWindow(_THIS, SDL_Window * window)
} }
#endif #endif
/* Make sure the window is considered to be positioned at {0,0}, #if SDL_WINRT_USE_APPLICATIONVIEW
and is considered fullscreen, shown, and the like. /* Determine as many flags dynamically, as possible. */
*/
window->x = 0;
window->y = 0;
window->flags = window->flags =
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_BORDERLESS;
SDL_WINDOW_SHOWN | #else
/* Set SDL_Window flags for Windows Phone 8.0 */
window->flags =
SDL_WINDOW_FULLSCREEN_DESKTOP |
SDL_WINDOW_BORDERLESS | SDL_WINDOW_BORDERLESS |
SDL_WINDOW_MAXIMIZED | SDL_WINDOW_MAXIMIZED |
SDL_WINDOW_INPUT_GRABBED; SDL_WINDOW_INPUT_GRABBED;
#endif
#if SDL_VIDEO_OPENGL_EGL #if SDL_VIDEO_OPENGL_EGL
if (data->egl_surface) { if (data->egl_surface) {
@ -377,20 +517,40 @@ WINRT_CreateWindow(_THIS, SDL_Window * window)
} }
#endif #endif
/* WinRT does not, as of this writing, appear to support app-adjustable if (WINRT_XAMLWasEnabled) {
window sizes. Set the window size to whatever the native WinRT /* TODO, WinRT: set SDL_Window size, maybe position too, from XAML control */
CoreWindow is set at. 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. WINRT_UpdateWindowFlags(
*/ window,
window->w = _this->displays[0].current_mode.w; 0xffffffff /* Update any window flag(s) that WINRT_UpdateWindow can handle */
window->h = _this->displays[0].current_mode.h; );
/* For now, treat WinRT apps as if they always have focus. /* Try detecting if the window is active */
TODO, WinRT: try tracking keyboard and mouse focus state with respect to snapped apps bool isWindowActive = true; /* Presume the window is active, unless we've been told otherwise */
*/ if (data->coreWindow->CustomProperties->HasKey("SDLHelperWindowActivationState")) {
SDL_SetMouseFocus(window); CoreWindowActivationState activationState = \
SDL_SetKeyboardFocus(window); 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 /* Make sure the WinRT app's IFramworkView can post events on
behalf of SDL: behalf of SDL:

View File

@ -29,6 +29,12 @@
#include "SDL_video.h" #include "SDL_video.h"
#include "SDL_events.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" { extern "C" {
#include "../SDL_sysvideo.h" #include "../SDL_sysvideo.h"
#include "../SDL_egl_c.h" #include "../SDL_egl_c.h"
@ -48,25 +54,17 @@ typedef struct SDL_VideoData {
*/ */
extern SDL_Window * WINRT_GlobalSDLWindow; extern SDL_Window * WINRT_GlobalSDLWindow;
/* Creates a display mode for Plain Direct3D (non-XAML) apps, using the lone, native window's settings. /* 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'.
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.
*/ */
extern int WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode); extern void WINRT_UpdateWindowFlags(SDL_Window * window, Uint32 mask);
extern "C" Uint32 WINRT_DetectWindowFlags(SDL_Window * window); /* detects flags w/o applying them */
/* Duplicates a display mode, copying over driverdata as necessary */
extern int WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src);
/* Display mode internals */ /* Display mode internals */
typedef struct //typedef struct
{ //{
Windows::Graphics::Display::DisplayOrientations currentOrientation; // Windows::Graphics::Display::DisplayOrientations currentOrientation;
} SDL_DisplayModeData; //} SDL_DisplayModeData;
#ifdef __cplusplus_winrt #ifdef __cplusplus_winrt
@ -77,6 +75,10 @@ typedef struct
#define WINRT_DISPLAY_PROPERTY(NAME) (Windows::Graphics::Display::DisplayProperties::NAME) #define WINRT_DISPLAY_PROPERTY(NAME) (Windows::Graphics::Display::DisplayProperties::NAME)
#endif #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 */ /* Internal window data */
struct SDL_WindowData struct SDL_WindowData
{ {
@ -85,6 +87,9 @@ struct SDL_WindowData
#ifdef SDL_VIDEO_OPENGL_EGL #ifdef SDL_VIDEO_OPENGL_EGL
EGLSurface egl_surface; EGLSurface egl_surface;
#endif #endif
#if SDL_WINRT_USE_APPLICATIONVIEW
Windows::UI::ViewManagement::ApplicationView ^ appView;
#endif
}; };
#endif // ifdef __cplusplus_winrt #endif // ifdef __cplusplus_winrt