From a45695a22a1c4730b11bbf1585a6dd5ef37c2917 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 24 Mar 2024 21:34:54 -0500 Subject: [PATCH] Rework Qt window handling during SDL window creation - Avoids blindly enumeration all top-level windows - Properly tracks screen changes during the connection process - Starts stream window minimized if the Qt window was minimized Fixes #1231 --- app/gui/StreamSegue.qml | 2 +- app/streaming/session.cpp | 81 +++++++++++++++++++++------------------ app/streaming/session.h | 6 +-- 3 files changed, 48 insertions(+), 41 deletions(-) diff --git a/app/gui/StreamSegue.qml b/app/gui/StreamSegue.qml index 3d8af4a1..16177926 100644 --- a/app/gui/StreamSegue.qml +++ b/app/gui/StreamSegue.qml @@ -176,7 +176,7 @@ Item { gc() // Run the streaming session to completion - session.exec(Screen.virtualX, Screen.virtualY) + session.exec(Window.window) } sourceComponent: Item {} diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index 9a651664..04fd9f0d 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #define CONN_TEST_SERVER "qt.conntest.moonlight-stream.org" @@ -549,8 +550,7 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere m_DecoderLock(0), m_AudioDisabled(false), m_AudioMuted(false), - m_DisplayOriginX(0), - m_DisplayOriginY(0), + m_QtWindow(nullptr), m_UnexpectedTermination(true), // Failure prior to streaming is unexpected m_InputHandler(nullptr), m_MouseEmulationRefCount(0), @@ -1117,26 +1117,38 @@ void Session::getWindowDimensions(int& x, int& y, // Create our window on the same display that Qt's UI // was being displayed on. else { - SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, - "Qt UI screen is at (%d,%d)", - m_DisplayOriginX, m_DisplayOriginY); - for (int i = 0; i < SDL_GetNumVideoDisplays(); i++) { - SDL_Rect displayBounds; + Q_ASSERT(m_QtWindow != nullptr); + if (m_QtWindow != nullptr) { + QScreen* screen = m_QtWindow->screen(); + if (screen != nullptr) { + QRect displayRect = screen->geometry(); - if (SDL_GetDisplayBounds(i, &displayBounds) == 0) { - if (displayBounds.x == m_DisplayOriginX && - displayBounds.y == m_DisplayOriginY) { - SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, - "SDL found matching display %d", - i); - displayIndex = i; - break; + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, + "Qt UI screen is at (%d,%d)", + displayRect.x(), displayRect.y()); + for (int i = 0; i < SDL_GetNumVideoDisplays(); i++) { + SDL_Rect displayBounds; + + if (SDL_GetDisplayBounds(i, &displayBounds) == 0) { + if (displayBounds.x == displayRect.x() && + displayBounds.y == displayRect.y()) { + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, + "SDL found matching display %d", + i); + displayIndex = i; + break; + } + } + else { + SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, + "SDL_GetDisplayBounds(%d) failed: %s", + i, SDL_GetError()); + } } } else { SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, - "SDL_GetDisplayBounds(%d) failed: %s", - i, SDL_GetError()); + "Qt window is not associated with a QScreen!"); } } } @@ -1503,10 +1515,9 @@ public: Session* m_Session; }; -void Session::exec(int displayOriginX, int displayOriginY) +void Session::exec(QWindow* qtWindow) { - m_DisplayOriginX = displayOriginX; - m_DisplayOriginY = displayOriginY; + m_QtWindow = qtWindow; // Use a separate thread for the streaming session on X11 or Wayland // to ensure we don't stomp on Qt's GL context. This breaks when using @@ -1610,15 +1621,14 @@ void Session::execInternal() // We always want a resizable window with High DPI enabled Uint32 defaultWindowFlags = SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE; - // If we're starting in windowed mode and the Moonlight GUI is maximized, - // match that with the streaming window. - if (!m_IsFullScreen) { - QWindowList windows = QGuiApplication::topLevelWindows(); - for (const QWindow* window : windows) { - if (window->windowState() & Qt::WindowMaximized) { - defaultWindowFlags |= SDL_WINDOW_MAXIMIZED; - break; - } + // If we're starting in windowed mode and the Moonlight GUI is maximized or + // minimized, match that with the streaming window. + if (!m_IsFullScreen && m_QtWindow != nullptr) { + if (m_QtWindow->windowState() & Qt::WindowMaximized) { + defaultWindowFlags |= SDL_WINDOW_MAXIMIZED; + } + else if (m_QtWindow->windowState() & Qt::WindowMinimized) { + defaultWindowFlags |= SDL_WINDOW_MINIMIZED; } } @@ -1662,16 +1672,13 @@ void Session::execInternal() // HACK: Remove once proper Dark Mode support lands in SDL #ifdef Q_OS_WIN32 - { - BOOL darkModeEnabled = FALSE; + if (m_QtWindow != nullptr) { + BOOL darkModeEnabled; // Query whether dark mode is enabled for our Qt window (which tracks the OS dark mode state) - QWindowList windows = QGuiApplication::topLevelWindows(); - for (const QWindow* window : windows) { - if (SUCCEEDED(DwmGetWindowAttribute((HWND)window->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, &darkModeEnabled, sizeof(darkModeEnabled))) || - SUCCEEDED(DwmGetWindowAttribute((HWND)window->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE_OLD, &darkModeEnabled, sizeof(darkModeEnabled)))) { - break; - } + if (FAILED(DwmGetWindowAttribute((HWND)m_QtWindow->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE, &darkModeEnabled, sizeof(darkModeEnabled))) && + FAILED(DwmGetWindowAttribute((HWND)m_QtWindow->winId(), DWMWA_USE_IMMERSIVE_DARK_MODE_OLD, &darkModeEnabled, sizeof(darkModeEnabled)))) { + darkModeEnabled = FALSE; } SDL_SysWMinfo info; diff --git a/app/streaming/session.h b/app/streaming/session.h index 26c5102c..c42040b8 100644 --- a/app/streaming/session.h +++ b/app/streaming/session.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -26,7 +27,7 @@ public: // Use Session::exec() or DeferredSessionCleanupTask instead. virtual ~Session() {}; - Q_INVOKABLE void exec(int displayOriginX, int displayOriginY); + Q_INVOKABLE void exec(QWindow* qtWindow); static void getDecoderInfo(SDL_Window* window, @@ -166,8 +167,7 @@ private: bool m_AudioDisabled; bool m_AudioMuted; Uint32 m_FullScreenFlag; - int m_DisplayOriginX; - int m_DisplayOriginY; + QWindow* m_QtWindow; bool m_ThreadedExec; bool m_UnexpectedTermination; SdlInputHandler* m_InputHandler;