From fe0214d5222862d03972c328283f6eeeed8a0742 Mon Sep 17 00:00:00 2001 From: bbedward Date: Fri, 10 Jul 2026 15:44:36 -0400 Subject: [PATCH] theme: prevent failed portal writes from reverting theme mode related: #2786 port 1.5 (cherry picked from commit d82d86df5cb932fc275dcf30c35cd72705a21065) --- core/internal/matugen/matugen.go | 15 +++++--- quickshell/Common/Theme.qml | 4 +-- quickshell/Services/PortalService.qml | 49 +++++++++++++++------------ 3 files changed, 39 insertions(+), 29 deletions(-) diff --git a/core/internal/matugen/matugen.go b/core/internal/matugen/matugen.go index 750614d11..4b3bf01b0 100644 --- a/core/internal/matugen/matugen.go +++ b/core/internal/matugen/matugen.go @@ -260,15 +260,15 @@ func Run(opts Options) error { return buildErr } + if opts.SyncModeWithPortal { + syncColorScheme(opts.Mode) + } + if !changed { log.Info("No color changes detected, skipping refresh") return ErrNoChanges } - if opts.SyncModeWithPortal { - syncColorScheme(opts.Mode) - } - log.Info("Done") return nil } @@ -1006,6 +1006,13 @@ func syncColorScheme(mode ColorMode) { scheme = "default" } + if cur, err := utils.GsettingsGet("org.gnome.desktop.interface", "color-scheme"); err == nil { + cur = strings.Trim(cur, "'") + if cur == scheme || (mode == ColorModeLight && cur == "prefer-light") { + return + } + } + if err := utils.GsettingsSet("org.gnome.desktop.interface", "color-scheme", scheme); err != nil { log.Warnf("Failed to sync color-scheme: %v", err) } diff --git a/quickshell/Common/Theme.qml b/quickshell/Common/Theme.qml index 3f2ad3ea0..05d1e9d99 100644 --- a/quickshell/Common/Theme.qml +++ b/quickshell/Common/Theme.qml @@ -1336,9 +1336,7 @@ Singleton { } if (!isGreeterMode) { - if (!matugenAvailable) { - PortalService.setLightMode(light); - } + PortalService.setLightMode(light); if (typeof SettingsData !== "undefined") { SettingsData.updateCosmicThemeMode(light); } diff --git a/quickshell/Services/PortalService.qml b/quickshell/Services/PortalService.qml index 71bcb3e2f..ac9e5c958 100644 --- a/quickshell/Services/PortalService.qml +++ b/quickshell/Services/PortalService.qml @@ -16,6 +16,7 @@ Singleton { property string profileImage: "" property bool settingsPortalAvailable: false property int systemColorScheme: 0 + property bool colorSchemeInitialized: false property bool freedeskAvailable: false property string colorSchemeCommand: "" @@ -97,15 +98,24 @@ Singleton { return typeof Theme !== "undefined"; } - // Only follow values stable for the settle window — the opt-in GTK4-refresh toggle reverts within ~400ms and following it would loop. - function evaluateColorScheme() { + // Follow only genuine portal transitions, debounced by the settle window — the + // opt-in GTK4-refresh toggle reverts within ~400ms, and a stale portal value + // (broken gsettings→portal bridge) must never revert a DMS-initiated change. + function handlePortalColorScheme(scheme) { + const isTransition = colorSchemeInitialized && scheme !== systemColorScheme; + colorSchemeInitialized = true; + systemColorScheme = scheme; + if (!canSyncColorScheme()) return; - const shouldBeLight = systemColorScheme !== 1; + + const shouldBeLight = scheme !== 1; if (Theme.isLightMode === shouldBeLight) { colorSchemeSettleTimer.stop(); return; } + if (!isTransition) + return; colorSchemeSettleTimer.restart(); } @@ -138,13 +148,16 @@ Singleton { return; } - const targetScheme = isLightMode ? "default" : "prefer-dark"; + const preferLight = isLightMode && systemColorScheme === 2; + const targetScheme = isLightMode ? (preferLight ? "prefer-light" : "default") : "prefer-dark"; - if (colorSchemeCommand === "gsettings") { + switch (colorSchemeCommand) { + case "gsettings": Quickshell.execDetached(["gsettings", "set", "org.gnome.desktop.interface", "color-scheme", targetScheme]); - } - if (colorSchemeCommand === "dconf") { + break; + case "dconf": Quickshell.execDetached(["dconf", "write", "/org/gnome/desktop/interface/color-scheme", `'${targetScheme}'`]); + break; } } @@ -206,8 +219,11 @@ Singleton { target: typeof SettingsData !== "undefined" ? SettingsData : null function onSyncModeWithPortalChanged() { - if (SettingsData.syncModeWithPortal) - root.evaluateColorScheme(); + if (!SettingsData.syncModeWithPortal) + return; + if (typeof Theme === "undefined") + return; + root.setSystemColorScheme(Theme.isLightMode); } } @@ -218,17 +234,7 @@ Singleton { if (!data || !data.settings) return; root.settingsPortalAvailable = data.settings.available === true; - root.systemColorScheme = data.settings.colorScheme || 0; - root.evaluateColorScheme(); - } - } - - Connections { - target: typeof Theme !== "undefined" ? Theme : null - - function onWorkerRunningChanged() { - if (!Theme.workerRunning) - root.evaluateColorScheme(); + root.handlePortalColorScheme(data.settings.colorScheme || 0); } } @@ -288,8 +294,7 @@ Singleton { DMSService.sendRequest("freedesktop.getState", null, response => { if (response.result && response.result.settings) { settingsPortalAvailable = response.result.settings.available || false; - systemColorScheme = response.result.settings.colorScheme || 0; - evaluateColorScheme(); + handlePortalColorScheme(response.result.settings.colorScheme || 0); } }); }