From 753f86b2820d95374f10ff4306fb39249f936464 Mon Sep 17 00:00:00 2001 From: Chev Date: Mon, 27 Apr 2026 18:37:05 -0600 Subject: [PATCH] frontend: Hide Twitch docks on minimized start When OBS starts hidden in the system tray, Twitch integration docks are created after the main window intentionally remains hidden. Floating dock widgets can still become visible on their own, so Twitch chat, stream info, stats, and activity feed panes may appear even though OBS itself started minimized. Track the intended visibility of Twitch docks while the main window is hidden, hide those docks during startup, and restore their saved visibility when the main window is first shown. Also allow secondary Twitch panes to restore their saved dock state during this hidden startup path before they are hidden. --- frontend/oauth/TwitchAuth.cpp | 89 ++++++++++++++++++++++++++++++++++- frontend/oauth/TwitchAuth.hpp | 16 ++++++- 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/frontend/oauth/TwitchAuth.cpp b/frontend/oauth/TwitchAuth.cpp index 3b35e7291545c7..7f0694a8dac86a 100644 --- a/frontend/oauth/TwitchAuth.cpp +++ b/frontend/oauth/TwitchAuth.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "moc_TwitchAuth.cpp" @@ -52,6 +53,8 @@ TwitchAuth::~TwitchAuth() return; OBSBasic *main = OBSBasic::Get(); + if (eventFilterInstalled) + main->removeEventFilter(this); main->RemoveDockWidget(TWITCH_CHAT_DOCK_NAME); main->RemoveDockWidget(TWITCH_INFO_DOCK_NAME); @@ -59,6 +62,78 @@ TwitchAuth::~TwitchAuth() main->RemoveDockWidget(TWITCH_FEED_DOCK_NAME); } +bool TwitchAuth::ShouldHideTwitchDocksOnStartup() +{ + OBSBasic *main = OBSBasic::Get(); + bool sysTrayEnabled = config_get_bool(App()->GetUserConfig(), "BasicWindow", "SysTrayEnabled"); + + return QSystemTrayIcon::isSystemTrayAvailable() && !main->isVisible() && sysTrayEnabled; +} + +void TwitchAuth::InstallDockVisibilityRestore() +{ + if (eventFilterInstalled) + return; + + OBSBasic::Get()->installEventFilter(this); + eventFilterInstalled = true; +} + +void TwitchAuth::DeferDockVisibility(QDockWidget *dock) +{ + if (!dock) + return; + + for (auto &deferredDock : deferredDocks) { + if (deferredDock.first == dock) { + dock->setVisible(false); + return; + } + } + + deferredDocks.emplace_back(dock, dock->isVisible()); + dock->setVisible(false); + deferredDockVisibilityRestore = true; + InstallDockVisibilityRestore(); +} + +void TwitchAuth::HideDeferredDocks() +{ + for (auto &deferredDock : deferredDocks) { + if (deferredDock.first) + deferredDock.first->setVisible(false); + } +} + +void TwitchAuth::RestoreDeferredDockVisibility() +{ + if (!deferredDockVisibilityRestore) + return; + + for (auto &deferredDock : deferredDocks) { + if (deferredDock.first) + deferredDock.first->setVisible(deferredDock.second); + } + + deferredDockVisibilityRestore = false; + deferredDocks.clear(); + + if (eventFilterInstalled) { + OBSBasic::Get()->removeEventFilter(this); + eventFilterInstalled = false; + } +} + +bool TwitchAuth::eventFilter(QObject *obj, QEvent *event) +{ + if (!deferredDockVisibilityRestore || event->type() != QEvent::Show || obj != OBSBasic::Get()) + return QObject::eventFilter(obj, event); + + RestoreDeferredDockVisibility(); + + return QObject::eventFilter(obj, event); +} + bool TwitchAuth::MakeApiRequest(const char *path, Json &json_out) { std::string client_id = TWITCH_CLIENTID; @@ -276,6 +351,10 @@ void TwitchAuth::LoadUI() main->restoreState(dockState); } + if (ShouldHideTwitchDocksOnStartup()) { + DeferDockVisibility(chat); + } + TryLoadSecondaryUIPanes(); uiLoaded = true; @@ -396,9 +475,17 @@ void TwitchAuth::LoadSecondaryUIPanes() const char *dockStateStr = config_get_string(main->Config(), service(), "DockState"); QByteArray dockState = QByteArray::fromBase64(QByteArray(dockStateStr)); - if (main->isVisible() || !main->isMaximized()) + if (ShouldHideTwitchDocksOnStartup() || main->isVisible() || !main->isMaximized()) main->restoreState(dockState); } + + if (ShouldHideTwitchDocksOnStartup()) { + DeferDockVisibility(main->findChild(TWITCH_CHAT_DOCK_NAME)); + HideDeferredDocks(); + DeferDockVisibility(info); + DeferDockVisibility(stats); + DeferDockVisibility(feed); + } } /* Twitch.tv has an OAuth for itself. If we try to load multiple panel pages diff --git a/frontend/oauth/TwitchAuth.hpp b/frontend/oauth/TwitchAuth.hpp index bbd8ca4b91b925..673324814beb12 100644 --- a/frontend/oauth/TwitchAuth.hpp +++ b/frontend/oauth/TwitchAuth.hpp @@ -4,12 +4,20 @@ #include +#include +#include + +#include +#include +#include #include class TwitchAuth : public OAuthStreamKey { Q_OBJECT - bool uiLoaded = false; + bool deferredDockVisibilityRestore = false; + bool eventFilterInstalled = false; + std::vector, bool>> deferredDocks; std::string name; std::string uuid; @@ -23,6 +31,12 @@ class TwitchAuth : public OAuthStreamKey { bool GetChannelInfo(); virtual void LoadUI() override; + bool eventFilter(QObject *obj, QEvent *event) override; + void DeferDockVisibility(QDockWidget *dock); + void HideDeferredDocks(); + void InstallDockVisibilityRestore(); + void RestoreDeferredDockVisibility(); + bool ShouldHideTwitchDocksOnStartup(); public: TwitchAuth(const Def &d);