mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-23 11:35:25 -04:00
portal: add bidirectional syncing with freedesktop color-scheme, read in
addition to the existing write
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
||||||
"github.com/AvengeMedia/DankMaterialShell/core/pkg/dbusutil"
|
"github.com/AvengeMedia/DankMaterialShell/core/pkg/dbusutil"
|
||||||
"github.com/godbus/dbus/v5"
|
"github.com/godbus/dbus/v5"
|
||||||
)
|
)
|
||||||
@@ -94,9 +95,65 @@ func (m *Manager) initializeSettings() error {
|
|||||||
return fmt.Errorf("failed to update settings state: %w", err)
|
return fmt.Errorf("failed to update settings state: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go m.watchSettingsChanges()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) watchSettingsChanges() {
|
||||||
|
conn, err := dbus.ConnectSessionBus()
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("color-scheme watcher: session bus connect: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := conn.AddMatchSignal(
|
||||||
|
dbus.WithMatchInterface(dbusPortalSettingsInterface),
|
||||||
|
dbus.WithMatchMember("SettingChanged"),
|
||||||
|
); err != nil {
|
||||||
|
log.Warnf("Failed to watch portal settings changes: %v", err)
|
||||||
|
conn.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
signals := make(chan *dbus.Signal, 64)
|
||||||
|
conn.Signal(signals)
|
||||||
|
|
||||||
|
for sig := range signals {
|
||||||
|
if sig.Name != dbusPortalSettingsInterface+".SettingChanged" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(sig.Body) < 3 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace, _ := sig.Body[0].(string)
|
||||||
|
key, _ := sig.Body[1].(string)
|
||||||
|
if namespace != "org.freedesktop.appearance" || key != "color-scheme" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
variant, ok := sig.Body[2].(dbus.Variant)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
colorScheme, ok := dbusutil.As[uint32](variant)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
m.stateMutex.Lock()
|
||||||
|
changed := m.state.Settings.ColorScheme != colorScheme || !m.state.Settings.Available
|
||||||
|
m.state.Settings.ColorScheme = colorScheme
|
||||||
|
m.state.Settings.Available = true
|
||||||
|
m.stateMutex.Unlock()
|
||||||
|
|
||||||
|
if changed {
|
||||||
|
m.NotifySubscribers()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Manager) updateAccountsState() error {
|
func (m *Manager) updateAccountsState() error {
|
||||||
if !m.state.Accounts.Available || m.accountsObj == nil {
|
if !m.state.Accounts.Available || m.accountsObj == nil {
|
||||||
return fmt.Errorf("accounts service not available")
|
return fmt.Errorf("accounts service not available")
|
||||||
@@ -134,10 +191,23 @@ func (m *Manager) updateSettingsState() error {
|
|||||||
var variant dbus.Variant
|
var variant dbus.Variant
|
||||||
err := m.settingsObj.Call(dbusPortalSettingsInterface+".ReadOne", 0, "org.freedesktop.appearance", "color-scheme").Store(&variant)
|
err := m.settingsObj.Call(dbusPortalSettingsInterface+".ReadOne", 0, "org.freedesktop.appearance", "color-scheme").Store(&variant)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
// Older xdg-desktop-portal versions only expose the deprecated Read.
|
||||||
|
var nested dbus.Variant
|
||||||
|
if rerr := m.settingsObj.Call(dbusPortalSettingsInterface+".Read", 0, "org.freedesktop.appearance", "color-scheme").Store(&nested); rerr != nil {
|
||||||
|
log.Warnf("color-scheme: ReadOne (%v) and Read (%v) both failed", err, rerr)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
variant = nested
|
||||||
}
|
}
|
||||||
|
|
||||||
if colorScheme, ok := dbusutil.As[uint32](variant); ok {
|
colorScheme, ok := dbusutil.As[uint32](variant)
|
||||||
|
if !ok {
|
||||||
|
// Read double-wraps the value in a variant.
|
||||||
|
if inner, innerOk := variant.Value().(dbus.Variant); innerOk {
|
||||||
|
colorScheme, ok = dbusutil.As[uint32](inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
m.stateMutex.Lock()
|
m.stateMutex.Lock()
|
||||||
m.state.Settings.ColorScheme = colorScheme
|
m.state.Settings.ColorScheme = colorScheme
|
||||||
m.stateMutex.Unlock()
|
m.stateMutex.Unlock()
|
||||||
|
|||||||
+12
-27
@@ -175,8 +175,7 @@ Item {
|
|||||||
property bool barSurfacesLoaded: true
|
property bool barSurfacesLoaded: true
|
||||||
|
|
||||||
function recreateBarSurfaces() {
|
function recreateBarSurfaces() {
|
||||||
log.info("Recreating bar surfaces, screens:", Quickshell.screens.length,
|
log.info("Recreating bar surfaces, screens:", Quickshell.screens.length, Quickshell.screens.map(s => s.name).join(","));
|
||||||
Quickshell.screens.map(s => s.name).join(","));
|
|
||||||
if (barSurfacesLoaded)
|
if (barSurfacesLoaded)
|
||||||
barSurfacesLoaded = false;
|
barSurfacesLoaded = false;
|
||||||
barSurfaceReloadAction.schedule();
|
barSurfaceReloadAction.schedule();
|
||||||
@@ -345,12 +344,7 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function triggerSurfaceRecovery(source) {
|
function triggerSurfaceRecovery(source) {
|
||||||
log.info("Surface recovery triggered by:", source,
|
log.info("Surface recovery triggered by:", source, "screens:", Quickshell.screens.length, Quickshell.screens.map(s => s.name).join(","), "barLoaded:", root.barSurfacesLoaded, "frameLoaded:", root.frameSurfacesLoaded, "dockEnabled:", root.dockEnabled);
|
||||||
"screens:", Quickshell.screens.length,
|
|
||||||
Quickshell.screens.map(s => s.name).join(","),
|
|
||||||
"barLoaded:", root.barSurfacesLoaded,
|
|
||||||
"frameLoaded:", root.frameSurfacesLoaded,
|
|
||||||
"dockEnabled:", root.dockEnabled);
|
|
||||||
surfaceResumeRecoveryTimer.pass = 0;
|
surfaceResumeRecoveryTimer.pass = 0;
|
||||||
surfaceResumeRecoveryTimer.interval = 800;
|
surfaceResumeRecoveryTimer.interval = 800;
|
||||||
surfaceResumeRecoveryTimer.restart();
|
surfaceResumeRecoveryTimer.restart();
|
||||||
@@ -361,15 +355,11 @@ Item {
|
|||||||
function onScreensChanged() {
|
function onScreensChanged() {
|
||||||
const hasReal = root._hasRealScreen();
|
const hasReal = root._hasRealScreen();
|
||||||
const currentNames = root._getRealScreenNames();
|
const currentNames = root._getRealScreenNames();
|
||||||
log.info("Screens changed:", Quickshell.screens.length,
|
log.info("Screens changed:", Quickshell.screens.length, Quickshell.screens.map(s => "'" + s.name + "'").join(","), "hasReal:", hasReal, "hadReal:", root.hadRealScreen);
|
||||||
Quickshell.screens.map(s => "'" + s.name + "'").join(","),
|
|
||||||
"hasReal:", hasReal, "hadReal:", root.hadRealScreen);
|
|
||||||
const fullReconnect = !root.hadRealScreen && hasReal;
|
const fullReconnect = !root.hadRealScreen && hasReal;
|
||||||
const partialReconnect = root.previousRealScreenNames.length > 0
|
const partialReconnect = root.previousRealScreenNames.length > 0 && currentNames.some(name => !root.previousRealScreenNames.includes(name));
|
||||||
&& currentNames.some(name => !root.previousRealScreenNames.includes(name));
|
|
||||||
if (fullReconnect || partialReconnect) {
|
if (fullReconnect || partialReconnect) {
|
||||||
log.info("Screen reconnect detected, scheduling surface recovery",
|
log.info("Screen reconnect detected, scheduling surface recovery", "full:", fullReconnect, "partial:", partialReconnect);
|
||||||
"full:", fullReconnect, "partial:", partialReconnect);
|
|
||||||
root.scheduleScreenReconnectRecovery();
|
root.scheduleScreenReconnectRecovery();
|
||||||
}
|
}
|
||||||
root.hadRealScreen = hasReal;
|
root.hadRealScreen = hasReal;
|
||||||
@@ -429,9 +419,7 @@ Item {
|
|||||||
property int pass: 0
|
property int pass: 0
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
pass++;
|
pass++;
|
||||||
log.info("Surface recovery pass", pass,
|
log.info("Surface recovery pass", pass, "screens:", Quickshell.screens.length, Quickshell.screens.map(s => s.name).join(","));
|
||||||
"screens:", Quickshell.screens.length,
|
|
||||||
Quickshell.screens.map(s => s.name).join(","));
|
|
||||||
|
|
||||||
root.recreateBarSurfaces();
|
root.recreateBarSurfaces();
|
||||||
|
|
||||||
@@ -457,11 +445,12 @@ Item {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
dockRecreateDebounce.start();
|
dockRecreateDebounce.start();
|
||||||
// Force PolkitService singleton to initialize
|
|
||||||
PolkitService.polkitAvailable;
|
|
||||||
// Force DisplayConfigState singleton to initialize so auto-config runs at startup
|
|
||||||
DisplayConfigState.hasOutputBackend;
|
|
||||||
loginSoundTimer.start();
|
loginSoundTimer.start();
|
||||||
|
|
||||||
|
// These are dummy references just to trigger the singletons onCompleted to trigger
|
||||||
|
PolkitService.polkitAvailable;
|
||||||
|
DisplayConfigState.hasOutputBackend;
|
||||||
|
PortalService.systemColorScheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
@@ -1041,11 +1030,7 @@ Item {
|
|||||||
target: SessionService
|
target: SessionService
|
||||||
|
|
||||||
function onSessionResumed() {
|
function onSessionResumed() {
|
||||||
log.info("Session resumed: screens:", Quickshell.screens.length,
|
log.info("Session resumed: screens:", Quickshell.screens.length, Quickshell.screens.map(s => s.name).join(","), "barLoaded:", root.barSurfacesLoaded, "frameLoaded:", root.frameSurfacesLoaded, "dockEnabled:", root.dockEnabled);
|
||||||
Quickshell.screens.map(s => s.name).join(","),
|
|
||||||
"barLoaded:", root.barSurfacesLoaded,
|
|
||||||
"frameLoaded:", root.frameSurfacesLoaded,
|
|
||||||
"dockEnabled:", root.dockEnabled);
|
|
||||||
|
|
||||||
root.pendingOsdResumeReloads = 2;
|
root.pendingOsdResumeReloads = 2;
|
||||||
osdResumeRecreateTimer.interval = 400;
|
osdResumeRecreateTimer.interval = 400;
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ Singleton {
|
|||||||
signal openUrlRequested(string url)
|
signal openUrlRequested(string url)
|
||||||
signal appPickerRequested(var data)
|
signal appPickerRequested(var data)
|
||||||
signal screensaverStateUpdate(var data)
|
signal screensaverStateUpdate(var data)
|
||||||
|
signal freedesktopStateUpdate(var data)
|
||||||
signal clipboardStateUpdate(var data)
|
signal clipboardStateUpdate(var data)
|
||||||
signal locationStateUpdate(var data)
|
signal locationStateUpdate(var data)
|
||||||
signal sysupdateStateUpdate(var data)
|
signal sysupdateStateUpdate(var data)
|
||||||
@@ -384,6 +385,8 @@ Singleton {
|
|||||||
screensaverInhibited = data.inhibited || false;
|
screensaverInhibited = data.inhibited || false;
|
||||||
screensaverInhibitors = data.inhibitors || [];
|
screensaverInhibitors = data.inhibitors || [];
|
||||||
screensaverStateUpdate(data);
|
screensaverStateUpdate(data);
|
||||||
|
} else if (service === "freedesktop") {
|
||||||
|
freedesktopStateUpdate(data);
|
||||||
} else if (service === "dbus") {
|
} else if (service === "dbus") {
|
||||||
dbusSignalReceived(data.subscriptionId || "", data);
|
dbusSignalReceived(data.subscriptionId || "", data);
|
||||||
} else if (service === "clipboard") {
|
} else if (service === "clipboard") {
|
||||||
|
|||||||
@@ -87,17 +87,22 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSystemColorScheme() {
|
function evaluateColorScheme() {
|
||||||
if (typeof SettingsData !== "undefined" && SettingsData.syncModeWithPortal === false) {
|
if (typeof SettingsData === "undefined" || !SettingsData.syncModeWithPortal)
|
||||||
return;
|
return;
|
||||||
}
|
if (!settingsPortalAvailable)
|
||||||
if (!freedeskAvailable)
|
|
||||||
return;
|
return;
|
||||||
DMSService.sendRequest("freedesktop.settings.getColorScheme", null, response => {
|
if (typeof SessionData !== "undefined" && SessionData.themeModeAutoEnabled)
|
||||||
if (response.result) {
|
return;
|
||||||
systemColorScheme = response.result.value || 0;
|
if (typeof Theme === "undefined")
|
||||||
}
|
return;
|
||||||
});
|
// Defer mid-generation: setLightMode's regen would be dropped, and DMS's own transient color-scheme toggle would be misread. Re-run on worker completion.
|
||||||
|
if (Theme.workerRunning)
|
||||||
|
return;
|
||||||
|
const shouldBeLight = systemColorScheme !== 1;
|
||||||
|
if (Theme.isLightMode === shouldBeLight)
|
||||||
|
return;
|
||||||
|
Theme.setLightMode(shouldBeLight, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setLightMode(isLightMode) {
|
function setLightMode(isLightMode) {
|
||||||
@@ -176,6 +181,36 @@ Singleton {
|
|||||||
colorSchemeDetector.running = true;
|
colorSchemeDetector.running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: typeof SettingsData !== "undefined" ? SettingsData : null
|
||||||
|
|
||||||
|
function onSyncModeWithPortalChanged() {
|
||||||
|
if (SettingsData.syncModeWithPortal)
|
||||||
|
root.evaluateColorScheme();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: DMSService
|
||||||
|
|
||||||
|
function onFreedesktopStateUpdate(data) {
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: DMSService
|
target: DMSService
|
||||||
|
|
||||||
@@ -232,9 +267,8 @@ Singleton {
|
|||||||
DMSService.sendRequest("freedesktop.getState", null, response => {
|
DMSService.sendRequest("freedesktop.getState", null, response => {
|
||||||
if (response.result && response.result.settings) {
|
if (response.result && response.result.settings) {
|
||||||
settingsPortalAvailable = response.result.settings.available || false;
|
settingsPortalAvailable = response.result.settings.available || false;
|
||||||
if (settingsPortalAvailable && SettingsData.syncModeWithPortal) {
|
systemColorScheme = response.result.settings.colorScheme || 0;
|
||||||
getSystemColorScheme();
|
evaluateColorScheme();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user