Browse Source

WinRT: added SDL_*ScreenSaver() support; fixed crash when restoring app from screensaver

David Ludwig 8 years ago
parent
commit
5020fe8fdb
2 changed files with 85 additions and 3 deletions
  1. 79 3
      src/video/winrt/SDL_winrtvideo.cpp
  2. 6 0
      src/video/winrt/SDL_winrtvideo_cpp.h

+ 79 - 3
src/video/winrt/SDL_winrtvideo.cpp

@@ -31,6 +31,7 @@
 /* Windows includes */
 #include <agile.h>
 #include <windows.graphics.display.h>
+#include <windows.system.display.h>
 #include <dxgi.h>
 #include <dxgi1_2.h>
 using namespace Windows::ApplicationModel::Core;
@@ -41,7 +42,8 @@ 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 } };
+static const GUID IID_IDisplayRequest   = { 0xe5732044, 0xf49f, 0x4b60, { 0x8d, 0xd4, 0x5e, 0x7e, 0x3a, 0x63, 0x2a, 0xc0 } };
+static const GUID IID_IDXGIFactory2     = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } };
 
 
 /* SDL includes */
@@ -83,6 +85,11 @@ static void WINRT_DestroyWindow(_THIS, SDL_Window * window);
 static SDL_bool WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info);
 
 
+/* Misc functions */
+static ABI::Windows::System::Display::IDisplayRequest * WINRT_CreateDisplayRequest(_THIS);
+extern void WINRT_SuspendScreenSaver(_THIS);
+
+
 /* SDL-internal globals: */
 SDL_Window * WINRT_GlobalSDLWindow = NULL;
 
@@ -140,6 +147,7 @@ WINRT_CreateDevice(int devindex)
     device->SetDisplayMode = WINRT_SetDisplayMode;
     device->PumpEvents = WINRT_PumpEvents;
     device->GetWindowWMInfo = WINRT_GetWindowWMInfo;
+    device->SuspendScreenSaver = WINRT_SuspendScreenSaver;
 
 #if NTDDI_VERSION >= NTDDI_WIN10
     device->HasScreenKeyboardSupport = WINRT_HasScreenKeyboardSupport;
@@ -173,13 +181,17 @@ VideoBootStrap WINRT_bootstrap = {
 int
 WINRT_VideoInit(_THIS)
 {
+    SDL_VideoData * driverdata = (SDL_VideoData *) _this->driverdata;
     if (WINRT_InitModes(_this) < 0) {
         return -1;
     }
     WINRT_InitMouse(_this);
     WINRT_InitTouch(_this);
     WINRT_InitGameBar(_this);
-
+    if (driverdata) {
+        /* Initialize screensaver-disabling support */
+        driverdata->displayRequest = WINRT_CreateDisplayRequest(_this);
+    }
     return 0;
 }
 
@@ -421,6 +433,11 @@ WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
 void
 WINRT_VideoQuit(_THIS)
 {
+    SDL_VideoData * driverdata = (SDL_VideoData *) _this->driverdata;
+    if (driverdata && driverdata->displayRequest) {
+        driverdata->displayRequest->Release();
+        driverdata->displayRequest = NULL;
+    }
     WINRT_QuitGameBar(_this);
     WINRT_QuitMouse(_this);
 }
@@ -491,7 +508,7 @@ WINRT_DetectWindowFlags(SDL_Window * window)
         // data->coreWindow->PointerPosition is not supported on WinPhone 8.0
         latestFlags |= SDL_WINDOW_MOUSE_FOCUS;
 #else
-        if (data->coreWindow->Bounds.Contains(data->coreWindow->PointerPosition)) {
+        if (data->coreWindow->Visible && data->coreWindow->Bounds.Contains(data->coreWindow->PointerPosition)) {
             latestFlags |= SDL_WINDOW_MOUSE_FOCUS;
         }
 #endif
@@ -761,6 +778,65 @@ WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
     return SDL_FALSE;
 }
 
+static ABI::Windows::System::Display::IDisplayRequest *
+WINRT_CreateDisplayRequest(_THIS)
+{
+    /* Setup a WinRT DisplayRequest object, usable for enabling/disabling screensaver requests */
+    wchar_t *wClassName = L"Windows.System.Display.DisplayRequest";
+    HSTRING hClassName;
+    IActivationFactory *pActivationFactory = NULL;
+    IInspectable * pDisplayRequestRaw = nullptr;
+    ABI::Windows::System::Display::IDisplayRequest * pDisplayRequest = nullptr;
+    HRESULT hr;
+
+    hr = ::WindowsCreateString(wClassName, (UINT32)wcslen(wClassName), &hClassName);
+    if (FAILED(hr)) {
+        goto done;
+    }
+
+    hr = Windows::Foundation::GetActivationFactory(hClassName, &pActivationFactory);
+    if (FAILED(hr)) {
+        goto done;
+    }
+
+    hr = pActivationFactory->ActivateInstance(&pDisplayRequestRaw);
+    if (FAILED(hr)) {
+        goto done;
+    }
+
+    hr = pDisplayRequestRaw->QueryInterface(IID_IDisplayRequest, (void **) &pDisplayRequest);
+    if (FAILED(hr)) {
+        goto done;
+    }
+
+done:
+    if (pDisplayRequestRaw) {
+        pDisplayRequestRaw->Release();
+    }
+    if (pActivationFactory) {
+        pActivationFactory->Release();
+    }
+    if (hClassName) {
+        ::WindowsDeleteString(hClassName);
+    }
+
+    return pDisplayRequest;
+}
+
+void
+WINRT_SuspendScreenSaver(_THIS)
+{
+    SDL_VideoData *driverdata = (SDL_VideoData *)_this->driverdata;
+    if (driverdata->displayRequest) {
+        ABI::Windows::System::Display::IDisplayRequest * displayRequest = (ABI::Windows::System::Display::IDisplayRequest *) driverdata->displayRequest;
+        if (_this->suspend_screensaver) {
+            displayRequest->RequestActive();
+        } else {
+            displayRequest->RequestRelease();
+        }
+    }
+}
+
 #endif /* SDL_VIDEO_DRIVER_WINRT */
 
 /* vi: set ts=4 sw=4 expandtab: */

+ 6 - 0
src/video/winrt/SDL_winrtvideo_cpp.h

@@ -51,6 +51,12 @@ typedef struct SDL_VideoData {
        These are just a struct with a 64-bit integer inside them
     */
     Windows::Foundation::EventRegistrationToken gameBarIsInputRedirectedToken;
+
+    /* A WinRT DisplayRequest, used for implementing SDL_*ScreenSaver() functions.
+     * This is really a pointer to a 'ABI::Windows::System::Display::IDisplayRequest *',
+     * It's casted to 'IUnknown *', to help with building SDL.
+    */
+    IUnknown *displayRequest;
 } SDL_VideoData;
 
 /* The global, WinRT, SDL Window.