From ccb0e7c1e48a89c40f10f7fa9ae11386123ffd57 Mon Sep 17 00:00:00 2001 From: WarmUpTill <19472752+WarmUpTill@users.noreply.github.com> Date: Mon, 17 Aug 2026 19:31:03 +0200 Subject: [PATCH] Adaptitions for kWin support on Flatpak --- data/locale/en-US.ini | 3 + lib/linux/advanced-scene-switcher-nix.cpp | 95 +++++++++++++++++++---- lib/linux/kwin-helpers.cpp | 18 +++-- lib/linux/kwin-helpers.h | 2 +- 4 files changed, 98 insertions(+), 20 deletions(-) diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 7a51fbcc..62217589 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -3123,3 +3123,6 @@ AdvSceneSwitcher.sceneGroupTab.defaultname="Scene Group %1" AdvSceneSwitcher.sceneGroupTab.exists="Scene Group or Scene name exists already" AdvSceneSwitcher.sceneGroupTab.help="Scene Groups can be selected as a target just like a regular scene.\n\nAs the name suggests a scene group is a collection of multiple scenes.\nThe scene group will advance through the list of its assigned scenes depending on the configured settings, which can be found on the right side.\n\nYou can configure the scene group to advance to the next scene in the list:\nAfter a number of times the scene group is selected as a target.\nAfter a certain amount of time has passed.\nOr randomly.\n\nFor example, a scene group containing the scenes ...\nScene 1\nScene 2\nScene 3 \n... will activate \"Scene 1\" the first time it is selected as a target.\nThe second time it will activate \"Scene 2\".\nThe remaining times \"Scene 3\" will be activated.\n\nClick the highlighted plus symbol below to add a new scene group." AdvSceneSwitcher.sceneGroupTab.scenes.help="Select the scene group you want to modify on the left.\n\nSelect a scene to add to this scene group by selecting the scene above and clicking the plus symbol below.\n\nA scene can be added multiple times to the same scene group." +AdvSceneSwitcher.kwin.flatpakPermissionWarning="Window detection via KWin is unavailable.\nThe OBS Studio Flatpak sandbox is missing the 'org.kde.KWin' D-Bus permission this feature needs.\nRun the following, then restart OBS:\nflatpak override --user --talk-name=org.kde.KWin com.obsproject.Studio" +AdvSceneSwitcher.wayland.flatpakPermissionWarning="Window detection is unavailable.\nThe OBS Studio Flatpak has no X11 access on this Wayland session, and no compatible integration exists yet for this desktop.\nRunning OBS under an X11 session, or a non-Flatpak install, allows this feature to work." +AdvSceneSwitcher.flatpakWindowDetectionWarning.doNotShowAgain="Don't show this warning again" diff --git a/lib/linux/advanced-scene-switcher-nix.cpp b/lib/linux/advanced-scene-switcher-nix.cpp index 2862a38c..4aaa8a36 100644 --- a/lib/linux/advanced-scene-switcher-nix.cpp +++ b/lib/linux/advanced-scene-switcher-nix.cpp @@ -1,5 +1,13 @@ #include "platform-funcs.hpp" + #include "log-helper.hpp" +#include "obs-module-helper.hpp" +#include "plugin-state-helpers.hpp" +#include "ui-helpers.hpp" + +#include +#include +#include #include #include @@ -628,27 +636,88 @@ int ignoreXerror(Display *d, XErrorEvent *e) return 0; } +static bool warnAboutWindowDetectionUnavailable = true; + +static bool setupWindowDetectionWarningPersistence = []() { + AddSaveStep([](obs_data_t *obj) { + obs_data_set_bool(obj, "warnAboutFlatpakWindowDetection", + warnAboutWindowDetectionUnavailable); + }); + AddLoadStep([](obs_data_t *obj) { + obs_data_set_default_bool( + obj, "warnAboutFlatpakWindowDetection", true); + warnAboutWindowDetectionUnavailable = obs_data_get_bool( + obj, "warnAboutFlatpakWindowDetection"); + }); + return true; +}(); + +static void showWindowDetectionWarning(const char *messageId) +{ + auto mainWindow = + static_cast(obs_frontend_get_main_window()); + QMessageBox msgBox(QMessageBox::Warning, + obs_module_text("AdvSceneSwitcher.pluginName"), + obs_module_text(messageId), QMessageBox::Ok, + mainWindow); + auto checkbox = new QCheckBox( + obs_module_text( + "AdvSceneSwitcher.flatpakWindowDetectionWarning.doNotShowAgain")); + msgBox.setCheckBox(checkbox); + msgBox.exec(); + warnAboutWindowDetectionUnavailable = !checkbox->isChecked(); +} + +static void handleWindowDetectionUnavailable(bool hasX11) +{ + if (hasX11 || KWin || !warnAboutWindowDetectionUnavailable) { + return; + } + + if (!qEnvironmentVariableIsSet("FLATPAK_ID")) { + return; + } + + const bool onKDE = qEnvironmentVariable("XDG_CURRENT_DESKTOP") + .contains("KDE", Qt::CaseInsensitive); + const char *messageId = onKDE + ? "AdvSceneSwitcher.kwin.flatpakPermissionWarning" + : "AdvSceneSwitcher.wayland.flatpakPermissionWarning"; + + blog(LOG_WARNING, + "window detection unavailable: OBS Flatpak sandbox has no X11 " + "access on this Wayland session and %s", + onKDE ? "the KWin D-Bus compat call was blocked (missing " + "'org.kde.KWin' talk-name permission)" + : "no compatible native Wayland integration exists for " + "this desktop"); + + AddFinishedLoadingStep([messageId]() { + showWindowDetectionWarning(messageId); + }); +} + void PlatformInit() { + const bool kwinAvailable = isKWinAvailable(); + KWin = kwinAvailable && registerKWinDBusListener(¬ifier) && + startKWinScript(KWinScriptObjectPath); + if (KWin) { + blog(LOG_INFO, "using KWin compat"); + } else { + blog(LOG_INFO, "not using KWin compat"); + } + + initProcps(); + initProc2(); + auto display = disp(); + handleWindowDetectionUnavailable(display != nullptr); if (!display) { return; } - KWin = isKWinAvailable(); - if (!(KWin && startKWinScript(KWinScriptObjectPath) && - registerKWinDBusListener(¬ifier))) { - // something bad happened while trying to initialize - // the KWin script/dbus so disable it - KWin = false; - blog(LOG_INFO, "not using KWin compat"); - } else { - blog(LOG_INFO, "using KWin compat"); - } - initXss(); - initProcps(); - initProc2(); XSetErrorHandler(ignoreXerror); } diff --git a/lib/linux/kwin-helpers.cpp b/lib/linux/kwin-helpers.cpp index 7d7efb68..010389c9 100644 --- a/lib/linux/kwin-helpers.cpp +++ b/lib/linux/kwin-helpers.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -96,12 +97,16 @@ bool isKWinAvailable() bool startKWinScript(QString &scriptObjectPath) { + // Not RuntimeLocation: under Flatpak, $XDG_RUNTIME_DIR is private to + // the sandbox, so the unsandboxed KWin process can't read it back. const QString scriptPath = - "/tmp/AdvancedSceneSwitcher/KWinFocusNotifier.js"; + QStandardPaths::writableLocation( + QStandardPaths::CacheLocation) + + "/AdvancedSceneSwitcher/KWinFocusNotifier.js"; const QString script = - R"(var adss = "com.github.AdvancedSceneSwitcher"; -var adssPath = "/com/github/AdvancedSceneSwitcher"; + R"(var adss = "com.obsproject.Studio.Plugin.SceneSwitcher"; +var adssPath = "/com/obsproject/Studio/Plugin/SceneSwitcher"; function trackWindow(window) { var id = window.internalId.toString(); @@ -129,7 +134,8 @@ workspace.windowActivated.connect(function(client) { }))"; if (const QDir dir; !dir.mkpath(QFileInfo(scriptPath).absolutePath())) { - blog(LOG_ERROR, "error creating /tmp/AdvancedSceneSwitcher"); + blog(LOG_ERROR, + "error creating KWinFocusNotifier script directory"); return false; } @@ -198,8 +204,8 @@ bool stopKWinScript(const QString &scriptObjectPath) bool registerKWinDBusListener(FocusNotifier *notifier) { - static const QString serviceName = "com.github.AdvancedSceneSwitcher"; - static const QString objectPath = "/com/github/AdvancedSceneSwitcher"; + static const QString serviceName = "com.obsproject.Studio.Plugin.SceneSwitcher"; + static const QString objectPath = "/com/obsproject/Studio/Plugin/SceneSwitcher"; auto bus = QDBusConnection::sessionBus(); if (bus.objectRegisteredAt(objectPath)) { diff --git a/lib/linux/kwin-helpers.h b/lib/linux/kwin-helpers.h index 5f023e53..cb957ae1 100644 --- a/lib/linux/kwin-helpers.h +++ b/lib/linux/kwin-helpers.h @@ -12,7 +12,7 @@ namespace advss { class FocusNotifier final : public QObject { Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "com.github.AdvancedSceneSwitcher") + Q_CLASSINFO("D-Bus Interface", "com.obsproject.Studio.Plugin.SceneSwitcher") static std::mutex _mutex; static int activePID;