From 7dd4815edf2f48a5b8b90ae028dc267c09d9c0b4 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Mon, 3 Sep 2018 22:17:34 -0400 Subject: [PATCH] Allow selection between full-screen exclusive mode and borderless windowed mode --- app/gui/SettingsView.qml | 65 ++++++++++++++++++++------- app/settings/streamingpreferences.cpp | 8 +++- app/settings/streamingpreferences.h | 14 ++++-- app/streaming/session.cpp | 28 +++++++----- app/streaming/session.hpp | 1 + 5 files changed, 83 insertions(+), 33 deletions(-) diff --git a/app/gui/SettingsView.qml b/app/gui/SettingsView.qml index 508a3215..0ce7f0de 100644 --- a/app/gui/SettingsView.qml +++ b/app/gui/SettingsView.qml @@ -230,26 +230,59 @@ ScrollView { } } - Row { - CheckBox { - id: fullScreenCheck - text: "Full-screen" - font.pointSize: 12 - checked: prefs.fullScreen - onCheckedChanged: { - prefs.fullScreen = checked + Label { + width: parent.width + id: windowModeTitle + text: qsTr("Display mode") + font.pointSize: 12 + wrapMode: Text.Wrap + color: "white" + } + + ComboBox { + // ignore setting the index at first, and actually set it when the component is loaded + Component.onCompleted: { + var savedWm = prefs.windowMode + currentIndex = 0 + for (var i = 0; i < windowModeListModel.count; i++) { + var thisWm = windowModeListModel.get(i).val; + if (savedWm === thisWm) { + currentIndex = i + } } } - CheckBox { - id: vsyncCheck - text: "Enable V-Sync" - font.pointSize: 12 - visible: fullScreenCheck.checked - checked: prefs.enableVsync - onCheckedChanged: { - prefs.enableVsync = checked + id: windowModeComboBox + width: Math.min(bitrateDesc.implicitWidth, parent.width) + textRole: "text" + model: ListModel { + id: windowModeListModel + ListElement { + text: "Full-screen" + val: StreamingPreferences.WM_FULLSCREEN } + ListElement { + text: "Borderless windowed" + val: StreamingPreferences.WM_FULLSCREEN_DESKTOP + } + ListElement { + text: "Windowed" + val: StreamingPreferences.WM_WINDOWED + } + } + onActivated: { + prefs.windowMode = windowModeListModel.get(currentIndex).val + } + } + + CheckBox { + id: vsyncCheck + text: "Enable V-Sync" + font.pointSize: 12 + visible: prefs.windowMode === StreamingPreferences.WM_FULLSCREEN + checked: prefs.enableVsync + onCheckedChanged: { + prefs.enableVsync = checked } } } diff --git a/app/settings/streamingpreferences.cpp b/app/settings/streamingpreferences.cpp index 8cbf313c..a10eab0e 100644 --- a/app/settings/streamingpreferences.cpp +++ b/app/settings/streamingpreferences.cpp @@ -16,6 +16,7 @@ #define SER_AUDIOCFG "audiocfg" #define SER_VIDEOCFG "videocfg" #define SER_VIDEODEC "videodec" +#define SER_WINDOWMODE "windowmode" StreamingPreferences::StreamingPreferences() { @@ -30,7 +31,6 @@ void StreamingPreferences::reload() height = settings.value(SER_HEIGHT, 720).toInt(); fps = settings.value(SER_FPS, 60).toInt(); bitrateKbps = settings.value(SER_BITRATE, getDefaultBitrate(width, height, fps)).toInt(); - fullScreen = settings.value(SER_FULLSCREEN, true).toBool(); enableVsync = settings.value(SER_VSYNC, true).toBool(); gameOptimizations = settings.value(SER_GAMEOPTS, true).toBool(); playAudioOnHost = settings.value(SER_HOSTAUDIO, false).toBool(); @@ -41,6 +41,10 @@ void StreamingPreferences::reload() static_cast(VideoCodecConfig::VCC_AUTO)).toInt()); videoDecoderSelection = static_cast(settings.value(SER_VIDEODEC, static_cast(VideoDecoderSelection::VDS_AUTO)).toInt()); + windowMode = static_cast(settings.value(SER_WINDOWMODE, + // Try to load from the old preference value too + static_cast(settings.value(SER_FULLSCREEN, true).toBool() ? + WindowMode::WM_FULLSCREEN : WindowMode::WM_WINDOWED)).toInt()); } void StreamingPreferences::save() @@ -51,7 +55,6 @@ void StreamingPreferences::save() settings.setValue(SER_HEIGHT, height); settings.setValue(SER_FPS, fps); settings.setValue(SER_BITRATE, bitrateKbps); - settings.setValue(SER_FULLSCREEN, fullScreen); settings.setValue(SER_VSYNC, enableVsync); settings.setValue(SER_GAMEOPTS, gameOptimizations); settings.setValue(SER_HOSTAUDIO, playAudioOnHost); @@ -59,6 +62,7 @@ void StreamingPreferences::save() settings.setValue(SER_AUDIOCFG, static_cast(audioConfig)); settings.setValue(SER_VIDEOCFG, static_cast(videoCodecConfig)); settings.setValue(SER_VIDEODEC, static_cast(videoDecoderSelection)); + settings.setValue(SER_WINDOWMODE, static_cast(windowMode)); } bool StreamingPreferences::hasAnyHardwareAcceleration() diff --git a/app/settings/streamingpreferences.h b/app/settings/streamingpreferences.h index b06020d2..7125a4f2 100644 --- a/app/settings/streamingpreferences.h +++ b/app/settings/streamingpreferences.h @@ -50,11 +50,18 @@ public: }; Q_ENUM(VideoDecoderSelection) + enum WindowMode + { + WM_FULLSCREEN, + WM_FULLSCREEN_DESKTOP, + WM_WINDOWED + }; + Q_ENUM(WindowMode); + Q_PROPERTY(int width MEMBER width NOTIFY displayModeChanged) Q_PROPERTY(int height MEMBER height NOTIFY displayModeChanged) Q_PROPERTY(int fps MEMBER fps NOTIFY displayModeChanged) Q_PROPERTY(int bitrateKbps MEMBER bitrateKbps NOTIFY bitrateChanged) - Q_PROPERTY(bool fullScreen MEMBER fullScreen NOTIFY fullScreenChanged) Q_PROPERTY(bool enableVsync MEMBER enableVsync NOTIFY enableVsyncChanged) Q_PROPERTY(bool gameOptimizations MEMBER gameOptimizations NOTIFY gameOptimizationsChanged) Q_PROPERTY(bool playAudioOnHost MEMBER playAudioOnHost NOTIFY playAudioOnHostChanged) @@ -62,13 +69,13 @@ public: Q_PROPERTY(AudioConfig audioConfig MEMBER audioConfig NOTIFY audioConfigChanged) Q_PROPERTY(VideoCodecConfig videoCodecConfig MEMBER videoCodecConfig NOTIFY videoCodecConfigChanged) Q_PROPERTY(VideoDecoderSelection videoDecoderSelection MEMBER videoDecoderSelection NOTIFY videoDecoderSelectionChanged) + Q_PROPERTY(WindowMode windowMode MEMBER windowMode NOTIFY windowModeChanged) // Directly accessible members for preferences int width; int height; int fps; int bitrateKbps; - bool fullScreen; bool enableVsync; bool gameOptimizations; bool playAudioOnHost; @@ -76,11 +83,11 @@ public: AudioConfig audioConfig; VideoCodecConfig videoCodecConfig; VideoDecoderSelection videoDecoderSelection; + WindowMode windowMode; signals: void displayModeChanged(); void bitrateChanged(); - void fullScreenChanged(); void enableVsyncChanged(); void gameOptimizationsChanged(); void playAudioOnHostChanged(); @@ -88,5 +95,6 @@ signals: void audioConfigChanged(); void videoCodecConfigChanged(); void videoDecoderSelectionChanged(); + void windowModeChanged(); }; diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index 8eb92a91..3a332d24 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -19,13 +19,6 @@ #include "video/sl.h" #endif -#if defined(Q_OS_DARWIN) -// Using full-screen desktop allows allows Spaces to work on macOS. -#define SDL_OS_FULLSCREEN_FLAG SDL_WINDOW_FULLSCREEN_DESKTOP -#else -#define SDL_OS_FULLSCREEN_FLAG SDL_WINDOW_FULLSCREEN -#endif - #ifdef Q_OS_WIN32 // Scaling the icon down on Win32 looks dreadful, so render at lower res #define ICON_SIZE 32 @@ -372,6 +365,17 @@ Session::Session(NvComputer* computer, NvApp& app) else { m_StreamConfig.packetSize = 1024; } + + switch (m_Preferences.windowMode) + { + case StreamingPreferences::WM_FULLSCREEN_DESKTOP: + m_FullScreenFlag = SDL_WINDOW_FULLSCREEN_DESKTOP; + break; + case StreamingPreferences::WM_FULLSCREEN: + default: + m_FullScreenFlag = SDL_WINDOW_FULLSCREEN; + break; + } } void Session::emitLaunchWarning(QString text) @@ -595,7 +599,7 @@ void Session::getWindowDimensions(bool fullScreen, void Session::toggleFullscreen() { - bool fullScreen = !(SDL_GetWindowFlags(m_Window) & SDL_OS_FULLSCREEN_FLAG); + bool fullScreen = !(SDL_GetWindowFlags(m_Window) & m_FullScreenFlag); int x, y, width, height; @@ -613,7 +617,7 @@ void Session::toggleFullscreen() if (fullScreen) { SDL_SetWindowResizable(m_Window, SDL_FALSE); - SDL_SetWindowFullscreen(m_Window, SDL_OS_FULLSCREEN_FLAG); + SDL_SetWindowFullscreen(m_Window, m_FullScreenFlag); } } @@ -715,7 +719,7 @@ void Session::exec() QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); int x, y, width, height; - getWindowDimensions(m_Preferences.fullScreen, + getWindowDimensions(m_Preferences.windowMode != StreamingPreferences::WM_WINDOWED, x, y, width, height); m_Window = SDL_CreateWindow("Moonlight", @@ -736,7 +740,7 @@ void Session::exec() // For non-full screen windows, call getWindowDimensions() // again after creating a window to allow it to account // for window chrome size. - if (!m_Preferences.fullScreen) { + if (m_Preferences.windowMode == StreamingPreferences::WM_WINDOWED) { getWindowDimensions(false, x, y, width, height); SDL_SetWindowPosition(m_Window, x, y); @@ -754,7 +758,7 @@ void Session::exec() } // Enter full screen - SDL_SetWindowFullscreen(m_Window, SDL_OS_FULLSCREEN_FLAG); + SDL_SetWindowFullscreen(m_Window, m_FullScreenFlag); } QSvgRenderer svgIconRenderer(QString(":/res/moonlight.svg")); diff --git a/app/streaming/session.hpp b/app/streaming/session.hpp index 8f07baf9..2639fb8e 100644 --- a/app/streaming/session.hpp +++ b/app/streaming/session.hpp @@ -110,6 +110,7 @@ private: SDL_SpinLock m_DecoderLock; bool m_NeedsIdr; bool m_AudioDisabled; + Uint32 m_FullScreenFlag; int m_ActiveVideoFormat; int m_ActiveVideoWidth;