mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-24 21:42:51 -05:00
Compare commits
8 Commits
37f972d075
...
bae32e51ff
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bae32e51ff | ||
|
|
edfda965e9 | ||
|
|
a547966b23 | ||
|
|
f6279b1b2e | ||
|
|
957c89a85d | ||
|
|
571a9dabcd | ||
|
|
51ca9a7686 | ||
|
|
c141ad1e34 |
@@ -50,15 +50,18 @@ func findConfig(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
configStateFile := filepath.Join(getRuntimeDir(), "danklinux.path")
|
configStateFile := filepath.Join(getRuntimeDir(), "danklinux.path")
|
||||||
if data, readErr := os.ReadFile(configStateFile); readErr == nil {
|
if data, readErr := os.ReadFile(configStateFile); readErr == nil {
|
||||||
statePath := strings.TrimSpace(string(data))
|
if len(getAllDMSPIDs()) == 0 {
|
||||||
shellPath := filepath.Join(statePath, "shell.qml")
|
os.Remove(configStateFile)
|
||||||
|
|
||||||
if info, statErr := os.Stat(shellPath); statErr == nil && !info.IsDir() {
|
|
||||||
log.Debug("Using config from active session state file: %s", statePath)
|
|
||||||
configPath = statePath
|
|
||||||
log.Debug("Using config from: %s", configPath)
|
|
||||||
return nil // <-- Guard statement
|
|
||||||
} else {
|
} else {
|
||||||
|
statePath := strings.TrimSpace(string(data))
|
||||||
|
shellPath := filepath.Join(statePath, "shell.qml")
|
||||||
|
|
||||||
|
if info, statErr := os.Stat(shellPath); statErr == nil && !info.IsDir() {
|
||||||
|
log.Debug("Using config from active session state file: %s", statePath)
|
||||||
|
configPath = statePath
|
||||||
|
log.Debug("Using config from: %s", configPath)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
os.Remove(configStateFile)
|
os.Remove(configStateFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"slices"
|
"slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -526,6 +527,14 @@ func runShellDaemon(session bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var qsHasAnyDisplay = sync.OnceValue(func() bool {
|
||||||
|
out, err := exec.Command("qs", "ipc", "--help").Output()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return strings.Contains(string(out), "--any-display")
|
||||||
|
})
|
||||||
|
|
||||||
func parseTargetsFromIPCShowOutput(output string) ipcTargets {
|
func parseTargetsFromIPCShowOutput(output string) ipcTargets {
|
||||||
targets := make(ipcTargets)
|
targets := make(ipcTargets)
|
||||||
var currentTarget string
|
var currentTarget string
|
||||||
@@ -556,7 +565,11 @@ func parseTargetsFromIPCShowOutput(output string) ipcTargets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getShellIPCCompletions(args []string, _ string) []string {
|
func getShellIPCCompletions(args []string, _ string) []string {
|
||||||
cmdArgs := []string{"-p", configPath, "ipc", "show"}
|
cmdArgs := []string{"ipc"}
|
||||||
|
if qsHasAnyDisplay() {
|
||||||
|
cmdArgs = append(cmdArgs, "--any-display")
|
||||||
|
}
|
||||||
|
cmdArgs = append(cmdArgs, "-p", configPath, "show")
|
||||||
cmd := exec.Command("qs", cmdArgs...)
|
cmd := exec.Command("qs", cmdArgs...)
|
||||||
var targets ipcTargets
|
var targets ipcTargets
|
||||||
|
|
||||||
@@ -610,7 +623,12 @@ func runShellIPCCommand(args []string) {
|
|||||||
args = append([]string{"call"}, args...)
|
args = append([]string{"call"}, args...)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdArgs := append([]string{"-p", configPath, "ipc"}, args...)
|
cmdArgs := []string{"ipc"}
|
||||||
|
if qsHasAnyDisplay() {
|
||||||
|
cmdArgs = append(cmdArgs, "--any-display")
|
||||||
|
}
|
||||||
|
cmdArgs = append(cmdArgs, "-p", configPath)
|
||||||
|
cmdArgs = append(cmdArgs, args...)
|
||||||
cmd := exec.Command("qs", cmdArgs...)
|
cmd := exec.Command("qs", cmdArgs...)
|
||||||
cmd.Stdin = os.Stdin
|
cmd.Stdin = os.Stdin
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
|
|||||||
@@ -252,6 +252,28 @@ func (a *SecretAgent) GetSecrets(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if settingName == "vpn" && a.backend != nil {
|
if settingName == "vpn" && a.backend != nil {
|
||||||
|
// Check for cached PKCS11 PIN first
|
||||||
|
isPKCS11Request := len(fields) == 1 && fields[0] == "key_pass"
|
||||||
|
if isPKCS11Request {
|
||||||
|
a.backend.cachedPKCS11Mu.Lock()
|
||||||
|
cached := a.backend.cachedPKCS11PIN
|
||||||
|
if cached != nil && cached.ConnectionUUID == connUuid {
|
||||||
|
a.backend.cachedPKCS11PIN = nil
|
||||||
|
a.backend.cachedPKCS11Mu.Unlock()
|
||||||
|
|
||||||
|
log.Infof("[SecretAgent] Using cached PKCS11 PIN")
|
||||||
|
|
||||||
|
out := nmSettingMap{}
|
||||||
|
vpnSec := nmVariantMap{}
|
||||||
|
vpnSec["secrets"] = dbus.MakeVariant(map[string]string{"key_pass": cached.PIN})
|
||||||
|
out[settingName] = vpnSec
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
a.backend.cachedPKCS11Mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for cached VPN password
|
||||||
a.backend.cachedVPNCredsMu.Lock()
|
a.backend.cachedVPNCredsMu.Lock()
|
||||||
cached := a.backend.cachedVPNCreds
|
cached := a.backend.cachedVPNCreds
|
||||||
if cached != nil && cached.ConnectionUUID == connUuid {
|
if cached != nil && cached.ConnectionUUID == connUuid {
|
||||||
@@ -261,9 +283,9 @@ func (a *SecretAgent) GetSecrets(
|
|||||||
log.Infof("[SecretAgent] Using cached password from pre-activation prompt")
|
log.Infof("[SecretAgent] Using cached password from pre-activation prompt")
|
||||||
|
|
||||||
out := nmSettingMap{}
|
out := nmSettingMap{}
|
||||||
sec := nmVariantMap{}
|
vpnSec := nmVariantMap{}
|
||||||
sec["password"] = dbus.MakeVariant(cached.Password)
|
vpnSec["secrets"] = dbus.MakeVariant(map[string]string{"password": cached.Password})
|
||||||
out[settingName] = sec
|
out[settingName] = vpnSec
|
||||||
|
|
||||||
if cached.SavePassword {
|
if cached.SavePassword {
|
||||||
a.backend.pendingVPNSaveMu.Lock()
|
a.backend.pendingVPNSaveMu.Lock()
|
||||||
@@ -367,16 +389,41 @@ func (a *SecretAgent) GetSecrets(
|
|||||||
}
|
}
|
||||||
sec[k] = dbus.MakeVariant(v)
|
sec[k] = dbus.MakeVariant(v)
|
||||||
}
|
}
|
||||||
out[settingName] = sec
|
|
||||||
|
// Check if this is PKCS11 auth (key_pass)
|
||||||
|
pin, isPKCS11 := reply.Secrets["key_pass"]
|
||||||
|
|
||||||
switch settingName {
|
switch settingName {
|
||||||
case "802-1x":
|
|
||||||
log.Infof("[SecretAgent] Returning 802-1x enterprise secrets with %d fields", len(sec))
|
|
||||||
case "vpn":
|
case "vpn":
|
||||||
log.Infof("[SecretAgent] Returning VPN secrets with %d fields for %s", len(sec), vpnSvc)
|
// VPN secrets must be wrapped in a "secrets" key per NM spec
|
||||||
}
|
secretsDict := make(map[string]string)
|
||||||
|
for k, v := range reply.Secrets {
|
||||||
|
if k != "username" {
|
||||||
|
secretsDict[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vpnSec := nmVariantMap{}
|
||||||
|
vpnSec["secrets"] = dbus.MakeVariant(secretsDict)
|
||||||
|
out[settingName] = vpnSec
|
||||||
|
log.Infof("[SecretAgent] Returning VPN secrets with %d fields for %s", len(secretsDict), vpnSvc)
|
||||||
|
|
||||||
if settingName == "vpn" && a.backend != nil && (vpnUsername != "" || reply.Save) {
|
// Cache PKCS11 PIN in case GetSecrets is called again during activation
|
||||||
|
if isPKCS11 && a.backend != nil {
|
||||||
|
a.backend.cachedPKCS11Mu.Lock()
|
||||||
|
a.backend.cachedPKCS11PIN = &cachedPKCS11PIN{
|
||||||
|
ConnectionUUID: connUuid,
|
||||||
|
PIN: pin,
|
||||||
|
}
|
||||||
|
a.backend.cachedPKCS11Mu.Unlock()
|
||||||
|
log.Infof("[SecretAgent] Cached PKCS11 PIN for potential re-request")
|
||||||
|
}
|
||||||
|
case "802-1x":
|
||||||
|
out[settingName] = sec
|
||||||
|
log.Infof("[SecretAgent] Returning 802-1x enterprise secrets with %d fields", len(sec))
|
||||||
|
default:
|
||||||
|
out[settingName] = sec
|
||||||
|
}
|
||||||
|
if settingName == "vpn" && a.backend != nil && !isPKCS11 && (vpnUsername != "" || reply.Save) {
|
||||||
pw := reply.Secrets["password"]
|
pw := reply.Secrets["password"]
|
||||||
a.backend.pendingVPNSaveMu.Lock()
|
a.backend.pendingVPNSaveMu.Lock()
|
||||||
a.backend.pendingVPNSave = &pendingVPNCredentials{
|
a.backend.pendingVPNSave = &pendingVPNCredentials{
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ type NetworkManagerBackend struct {
|
|||||||
pendingVPNSaveMu sync.Mutex
|
pendingVPNSaveMu sync.Mutex
|
||||||
cachedVPNCreds *cachedVPNCredentials
|
cachedVPNCreds *cachedVPNCredentials
|
||||||
cachedVPNCredsMu sync.Mutex
|
cachedVPNCredsMu sync.Mutex
|
||||||
|
cachedPKCS11PIN *cachedPKCS11PIN
|
||||||
|
cachedPKCS11Mu sync.Mutex
|
||||||
|
|
||||||
onStateChange func()
|
onStateChange func()
|
||||||
}
|
}
|
||||||
@@ -89,6 +91,11 @@ type cachedVPNCredentials struct {
|
|||||||
SavePassword bool
|
SavePassword bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type cachedPKCS11PIN struct {
|
||||||
|
ConnectionUUID string
|
||||||
|
PIN string
|
||||||
|
}
|
||||||
|
|
||||||
func NewNetworkManagerBackend(nmConn ...gonetworkmanager.NetworkManager) (*NetworkManagerBackend, error) {
|
func NewNetworkManagerBackend(nmConn ...gonetworkmanager.NetworkManager) (*NetworkManagerBackend, error) {
|
||||||
var nm gonetworkmanager.NetworkManager
|
var nm gonetworkmanager.NetworkManager
|
||||||
var err error
|
var err error
|
||||||
|
|||||||
@@ -683,6 +683,11 @@ func (b *NetworkManagerBackend) updateVPNConnectionState() {
|
|||||||
b.state.LastError = ""
|
b.state.LastError = ""
|
||||||
b.stateMutex.Unlock()
|
b.stateMutex.Unlock()
|
||||||
|
|
||||||
|
// Clear cached PKCS11 PIN on success
|
||||||
|
b.cachedPKCS11Mu.Lock()
|
||||||
|
b.cachedPKCS11PIN = nil
|
||||||
|
b.cachedPKCS11Mu.Unlock()
|
||||||
|
|
||||||
b.pendingVPNSaveMu.Lock()
|
b.pendingVPNSaveMu.Lock()
|
||||||
pending := b.pendingVPNSave
|
pending := b.pendingVPNSave
|
||||||
b.pendingVPNSave = nil
|
b.pendingVPNSave = nil
|
||||||
@@ -699,6 +704,11 @@ func (b *NetworkManagerBackend) updateVPNConnectionState() {
|
|||||||
b.state.ConnectingVPNUUID = ""
|
b.state.ConnectingVPNUUID = ""
|
||||||
b.state.LastError = "VPN connection failed"
|
b.state.LastError = "VPN connection failed"
|
||||||
b.stateMutex.Unlock()
|
b.stateMutex.Unlock()
|
||||||
|
|
||||||
|
// Clear cached PKCS11 PIN on failure
|
||||||
|
b.cachedPKCS11Mu.Lock()
|
||||||
|
b.cachedPKCS11PIN = nil
|
||||||
|
b.cachedPKCS11Mu.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -711,6 +721,11 @@ func (b *NetworkManagerBackend) updateVPNConnectionState() {
|
|||||||
b.state.ConnectingVPNUUID = ""
|
b.state.ConnectingVPNUUID = ""
|
||||||
b.state.LastError = "VPN connection failed"
|
b.state.LastError = "VPN connection failed"
|
||||||
b.stateMutex.Unlock()
|
b.stateMutex.Unlock()
|
||||||
|
|
||||||
|
// Clear cached PKCS11 PIN
|
||||||
|
b.cachedPKCS11Mu.Lock()
|
||||||
|
b.cachedPKCS11PIN = nil
|
||||||
|
b.cachedPKCS11Mu.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,15 +7,20 @@ import Quickshell
|
|||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import "settings/SessionSpec.js" as Spec
|
||||||
|
import "settings/SessionStore.js" as Store
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property int sessionConfigVersion: 1
|
readonly property int sessionConfigVersion: 2
|
||||||
|
|
||||||
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
|
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
|
||||||
property bool hasTriedDefaultSession: false
|
|
||||||
property bool _parseError: false
|
property bool _parseError: false
|
||||||
|
property bool _hasLoaded: false
|
||||||
|
property bool _isReadOnly: false
|
||||||
|
property bool _hasUnsavedChanges: false
|
||||||
|
property var _loadedSessionSnapshot: null
|
||||||
readonly property string _stateUrl: StandardPaths.writableLocation(StandardPaths.GenericStateLocation)
|
readonly property string _stateUrl: StandardPaths.writableLocation(StandardPaths.GenericStateLocation)
|
||||||
readonly property string _stateDir: Paths.strip(_stateUrl)
|
readonly property string _stateDir: Paths.strip(_stateUrl)
|
||||||
|
|
||||||
@@ -94,97 +99,103 @@ Singleton {
|
|||||||
property string wifiDeviceOverride: ""
|
property string wifiDeviceOverride: ""
|
||||||
property bool weatherHourlyDetailed: true
|
property bool weatherHourlyDetailed: true
|
||||||
|
|
||||||
|
property string weatherLocation: "New York, NY"
|
||||||
|
property string weatherCoordinates: "40.7128,-74.0060"
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (!isGreeterMode) {
|
if (!isGreeterMode) {
|
||||||
loadSettings();
|
loadSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property var _pendingMigration: null
|
||||||
|
|
||||||
function loadSettings() {
|
function loadSettings() {
|
||||||
|
_hasUnsavedChanges = false;
|
||||||
|
_pendingMigration = null;
|
||||||
|
|
||||||
if (isGreeterMode) {
|
if (isGreeterMode) {
|
||||||
parseSettings(greeterSessionFile.text());
|
parseSettings(greeterSessionFile.text());
|
||||||
} else {
|
return;
|
||||||
parseSettings(settingsFile.text());
|
|
||||||
}
|
}
|
||||||
|
parseSettings(settingsFile.text());
|
||||||
|
_checkSessionWritable();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _checkSessionWritable() {
|
||||||
|
sessionWritableCheckProcess.running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _onWritableCheckComplete(writable) {
|
||||||
|
_isReadOnly = !writable;
|
||||||
|
if (_isReadOnly) {
|
||||||
|
console.info("SessionData: session.json is read-only (NixOS home-manager mode)");
|
||||||
|
} else if (_pendingMigration) {
|
||||||
|
settingsFile.setText(JSON.stringify(_pendingMigration, null, 2));
|
||||||
|
}
|
||||||
|
_pendingMigration = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _checkForUnsavedChanges() {
|
||||||
|
if (!_hasLoaded || !_loadedSessionSnapshot)
|
||||||
|
return false;
|
||||||
|
const current = getCurrentSessionJson();
|
||||||
|
return current !== _loadedSessionSnapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentSessionJson() {
|
||||||
|
return JSON.stringify(Store.toJson(root), null, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseSettings(content) {
|
function parseSettings(content) {
|
||||||
_parseError = false;
|
_parseError = false;
|
||||||
try {
|
try {
|
||||||
if (!content || !content.trim())
|
if (!content || !content.trim()) {
|
||||||
|
_parseError = true;
|
||||||
return;
|
return;
|
||||||
var settings = JSON.parse(content);
|
}
|
||||||
isLightMode = settings.isLightMode !== undefined ? settings.isLightMode : false;
|
|
||||||
|
|
||||||
if (settings.wallpaperPath && settings.wallpaperPath.startsWith("we:")) {
|
let obj = JSON.parse(content);
|
||||||
|
|
||||||
|
if (obj.brightnessLogarithmicDevices && !obj.brightnessExponentialDevices) {
|
||||||
|
obj.brightnessExponentialDevices = obj.brightnessLogarithmicDevices;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj.nightModeStartTime !== undefined) {
|
||||||
|
const parts = obj.nightModeStartTime.split(":");
|
||||||
|
obj.nightModeStartHour = parseInt(parts[0]) || 18;
|
||||||
|
obj.nightModeStartMinute = parseInt(parts[1]) || 0;
|
||||||
|
}
|
||||||
|
if (obj.nightModeEndTime !== undefined) {
|
||||||
|
const parts = obj.nightModeEndTime.split(":");
|
||||||
|
obj.nightModeEndHour = parseInt(parts[0]) || 6;
|
||||||
|
obj.nightModeEndMinute = parseInt(parts[1]) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldVersion = obj.configVersion ?? 0;
|
||||||
|
if (oldVersion === 0) {
|
||||||
|
migrateFromUndefinedToV1(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldVersion < sessionConfigVersion) {
|
||||||
|
const settingsDataRef = (typeof SettingsData !== "undefined") ? SettingsData : null;
|
||||||
|
const migrated = Store.migrateToVersion(obj, sessionConfigVersion, settingsDataRef);
|
||||||
|
if (migrated) {
|
||||||
|
_pendingMigration = migrated;
|
||||||
|
obj = migrated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Store.parse(root, obj);
|
||||||
|
|
||||||
|
if (wallpaperPath && wallpaperPath.startsWith("we:")) {
|
||||||
console.warn("WallpaperEngine wallpaper detected, resetting wallpaper");
|
console.warn("WallpaperEngine wallpaper detected, resetting wallpaper");
|
||||||
wallpaperPath = "";
|
wallpaperPath = "";
|
||||||
Quickshell.execDetached(["notify-send", "-u", "critical", "-a", "DMS", "-i", "dialog-warning", "WallpaperEngine Support Moved", "WallpaperEngine support has been moved to a plugin. Please enable the Linux Wallpaper Engine plugin in Settings → Plugins to continue using WallpaperEngine."]);
|
Quickshell.execDetached(["notify-send", "-u", "critical", "-a", "DMS", "-i", "dialog-warning", "WallpaperEngine Support Moved", "WallpaperEngine support has been moved to a plugin. Please enable the Linux Wallpaper Engine plugin in Settings → Plugins to continue using WallpaperEngine."]);
|
||||||
} else {
|
|
||||||
wallpaperPath = settings.wallpaperPath !== undefined ? settings.wallpaperPath : "";
|
|
||||||
}
|
}
|
||||||
perMonitorWallpaper = settings.perMonitorWallpaper !== undefined ? settings.perMonitorWallpaper : false;
|
|
||||||
monitorWallpapers = settings.monitorWallpapers !== undefined ? settings.monitorWallpapers : {};
|
|
||||||
perModeWallpaper = settings.perModeWallpaper !== undefined ? settings.perModeWallpaper : false;
|
|
||||||
wallpaperPathLight = settings.wallpaperPathLight !== undefined ? settings.wallpaperPathLight : "";
|
|
||||||
wallpaperPathDark = settings.wallpaperPathDark !== undefined ? settings.wallpaperPathDark : "";
|
|
||||||
monitorWallpapersLight = settings.monitorWallpapersLight !== undefined ? settings.monitorWallpapersLight : {};
|
|
||||||
monitorWallpapersDark = settings.monitorWallpapersDark !== undefined ? settings.monitorWallpapersDark : {};
|
|
||||||
brightnessExponentialDevices = settings.brightnessExponentialDevices !== undefined ? settings.brightnessExponentialDevices : (settings.brightnessLogarithmicDevices || {});
|
|
||||||
brightnessUserSetValues = settings.brightnessUserSetValues !== undefined ? settings.brightnessUserSetValues : {};
|
|
||||||
brightnessExponentValues = settings.brightnessExponentValues !== undefined ? settings.brightnessExponentValues : {};
|
|
||||||
doNotDisturb = settings.doNotDisturb !== undefined ? settings.doNotDisturb : false;
|
|
||||||
nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false;
|
|
||||||
nightModeTemperature = settings.nightModeTemperature !== undefined ? settings.nightModeTemperature : 4500;
|
|
||||||
nightModeHighTemperature = settings.nightModeHighTemperature !== undefined ? settings.nightModeHighTemperature : 6500;
|
|
||||||
nightModeAutoEnabled = settings.nightModeAutoEnabled !== undefined ? settings.nightModeAutoEnabled : false;
|
|
||||||
nightModeAutoMode = settings.nightModeAutoMode !== undefined ? settings.nightModeAutoMode : "time";
|
|
||||||
if (settings.nightModeStartTime !== undefined) {
|
|
||||||
const parts = settings.nightModeStartTime.split(":");
|
|
||||||
nightModeStartHour = parseInt(parts[0]) || 18;
|
|
||||||
nightModeStartMinute = parseInt(parts[1]) || 0;
|
|
||||||
} else {
|
|
||||||
nightModeStartHour = settings.nightModeStartHour !== undefined ? settings.nightModeStartHour : 18;
|
|
||||||
nightModeStartMinute = settings.nightModeStartMinute !== undefined ? settings.nightModeStartMinute : 0;
|
|
||||||
}
|
|
||||||
if (settings.nightModeEndTime !== undefined) {
|
|
||||||
const parts = settings.nightModeEndTime.split(":");
|
|
||||||
nightModeEndHour = parseInt(parts[0]) || 6;
|
|
||||||
nightModeEndMinute = parseInt(parts[1]) || 0;
|
|
||||||
} else {
|
|
||||||
nightModeEndHour = settings.nightModeEndHour !== undefined ? settings.nightModeEndHour : 6;
|
|
||||||
nightModeEndMinute = settings.nightModeEndMinute !== undefined ? settings.nightModeEndMinute : 0;
|
|
||||||
}
|
|
||||||
latitude = settings.latitude !== undefined ? settings.latitude : 0.0;
|
|
||||||
longitude = settings.longitude !== undefined ? settings.longitude : 0.0;
|
|
||||||
nightModeUseIPLocation = settings.nightModeUseIPLocation !== undefined ? settings.nightModeUseIPLocation : false;
|
|
||||||
nightModeLocationProvider = settings.nightModeLocationProvider !== undefined ? settings.nightModeLocationProvider : "";
|
|
||||||
pinnedApps = settings.pinnedApps !== undefined ? settings.pinnedApps : [];
|
|
||||||
hiddenTrayIds = settings.hiddenTrayIds !== undefined ? settings.hiddenTrayIds : [];
|
|
||||||
selectedGpuIndex = settings.selectedGpuIndex !== undefined ? settings.selectedGpuIndex : 0;
|
|
||||||
nvidiaGpuTempEnabled = settings.nvidiaGpuTempEnabled !== undefined ? settings.nvidiaGpuTempEnabled : false;
|
|
||||||
nonNvidiaGpuTempEnabled = settings.nonNvidiaGpuTempEnabled !== undefined ? settings.nonNvidiaGpuTempEnabled : false;
|
|
||||||
enabledGpuPciIds = settings.enabledGpuPciIds !== undefined ? settings.enabledGpuPciIds : [];
|
|
||||||
wifiDeviceOverride = settings.wifiDeviceOverride !== undefined ? settings.wifiDeviceOverride : "";
|
|
||||||
weatherHourlyDetailed = settings.weatherHourlyDetailed !== undefined ? settings.weatherHourlyDetailed : true;
|
|
||||||
wallpaperCyclingEnabled = settings.wallpaperCyclingEnabled !== undefined ? settings.wallpaperCyclingEnabled : false;
|
|
||||||
wallpaperCyclingMode = settings.wallpaperCyclingMode !== undefined ? settings.wallpaperCyclingMode : "interval";
|
|
||||||
wallpaperCyclingInterval = settings.wallpaperCyclingInterval !== undefined ? settings.wallpaperCyclingInterval : 300;
|
|
||||||
wallpaperCyclingTime = settings.wallpaperCyclingTime !== undefined ? settings.wallpaperCyclingTime : "06:00";
|
|
||||||
monitorCyclingSettings = settings.monitorCyclingSettings !== undefined ? settings.monitorCyclingSettings : {};
|
|
||||||
lastBrightnessDevice = settings.lastBrightnessDevice !== undefined ? settings.lastBrightnessDevice : "";
|
|
||||||
launchPrefix = settings.launchPrefix !== undefined ? settings.launchPrefix : "";
|
|
||||||
wallpaperTransition = settings.wallpaperTransition !== undefined ? settings.wallpaperTransition : "fade";
|
|
||||||
includedTransitions = settings.includedTransitions !== undefined ? settings.includedTransitions : availableWallpaperTransitions.filter(t => t !== "none");
|
|
||||||
recentColors = settings.recentColors !== undefined ? settings.recentColors : [];
|
|
||||||
showThirdPartyPlugins = settings.showThirdPartyPlugins !== undefined ? settings.showThirdPartyPlugins : false;
|
|
||||||
|
|
||||||
if (settings.configVersion === undefined) {
|
_hasLoaded = true;
|
||||||
migrateFromUndefinedToV1(settings);
|
_loadedSessionSnapshot = getCurrentSessionJson();
|
||||||
saveSettings();
|
|
||||||
} else if (settings.configVersion === sessionConfigVersion) {
|
|
||||||
cleanupUnusedKeys();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isGreeterMode && typeof Theme !== "undefined") {
|
if (!isGreeterMode && typeof Theme !== "undefined") {
|
||||||
Theme.generateSystemThemesFromCurrentTheme();
|
Theme.generateSystemThemesFromCurrentTheme();
|
||||||
@@ -202,56 +213,13 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
if (isGreeterMode || _parseError)
|
if (isGreeterMode || _parseError || !_hasLoaded)
|
||||||
return;
|
return;
|
||||||
settingsFile.setText(JSON.stringify({
|
if (_isReadOnly) {
|
||||||
"isLightMode": isLightMode,
|
_hasUnsavedChanges = _checkForUnsavedChanges();
|
||||||
"wallpaperPath": wallpaperPath,
|
return;
|
||||||
"perMonitorWallpaper": perMonitorWallpaper,
|
}
|
||||||
"monitorWallpapers": monitorWallpapers,
|
settingsFile.setText(getCurrentSessionJson());
|
||||||
"perModeWallpaper": perModeWallpaper,
|
|
||||||
"wallpaperPathLight": wallpaperPathLight,
|
|
||||||
"wallpaperPathDark": wallpaperPathDark,
|
|
||||||
"monitorWallpapersLight": monitorWallpapersLight,
|
|
||||||
"monitorWallpapersDark": monitorWallpapersDark,
|
|
||||||
"brightnessExponentialDevices": brightnessExponentialDevices,
|
|
||||||
"brightnessUserSetValues": brightnessUserSetValues,
|
|
||||||
"brightnessExponentValues": brightnessExponentValues,
|
|
||||||
"doNotDisturb": doNotDisturb,
|
|
||||||
"nightModeEnabled": nightModeEnabled,
|
|
||||||
"nightModeTemperature": nightModeTemperature,
|
|
||||||
"nightModeHighTemperature": nightModeHighTemperature,
|
|
||||||
"nightModeAutoEnabled": nightModeAutoEnabled,
|
|
||||||
"nightModeAutoMode": nightModeAutoMode,
|
|
||||||
"nightModeStartHour": nightModeStartHour,
|
|
||||||
"nightModeStartMinute": nightModeStartMinute,
|
|
||||||
"nightModeEndHour": nightModeEndHour,
|
|
||||||
"nightModeEndMinute": nightModeEndMinute,
|
|
||||||
"latitude": latitude,
|
|
||||||
"longitude": longitude,
|
|
||||||
"nightModeUseIPLocation": nightModeUseIPLocation,
|
|
||||||
"nightModeLocationProvider": nightModeLocationProvider,
|
|
||||||
"pinnedApps": pinnedApps,
|
|
||||||
"hiddenTrayIds": hiddenTrayIds,
|
|
||||||
"selectedGpuIndex": selectedGpuIndex,
|
|
||||||
"nvidiaGpuTempEnabled": nvidiaGpuTempEnabled,
|
|
||||||
"nonNvidiaGpuTempEnabled": nonNvidiaGpuTempEnabled,
|
|
||||||
"enabledGpuPciIds": enabledGpuPciIds,
|
|
||||||
"wifiDeviceOverride": wifiDeviceOverride,
|
|
||||||
"weatherHourlyDetailed": weatherHourlyDetailed,
|
|
||||||
"wallpaperCyclingEnabled": wallpaperCyclingEnabled,
|
|
||||||
"wallpaperCyclingMode": wallpaperCyclingMode,
|
|
||||||
"wallpaperCyclingInterval": wallpaperCyclingInterval,
|
|
||||||
"wallpaperCyclingTime": wallpaperCyclingTime,
|
|
||||||
"monitorCyclingSettings": monitorCyclingSettings,
|
|
||||||
"lastBrightnessDevice": lastBrightnessDevice,
|
|
||||||
"launchPrefix": launchPrefix,
|
|
||||||
"wallpaperTransition": wallpaperTransition,
|
|
||||||
"includedTransitions": includedTransitions,
|
|
||||||
"recentColors": recentColors,
|
|
||||||
"showThirdPartyPlugins": showThirdPartyPlugins,
|
|
||||||
"configVersion": sessionConfigVersion
|
|
||||||
}, null, 2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function migrateFromUndefinedToV1(settings) {
|
function migrateFromUndefinedToV1(settings) {
|
||||||
@@ -302,32 +270,6 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanupUnusedKeys() {
|
|
||||||
const validKeys = ["isLightMode", "wallpaperPath", "perMonitorWallpaper", "monitorWallpapers", "perModeWallpaper", "wallpaperPathLight", "wallpaperPathDark", "monitorWallpapersLight", "monitorWallpapersDark", "doNotDisturb", "nightModeEnabled", "nightModeTemperature", "nightModeHighTemperature", "nightModeAutoEnabled", "nightModeAutoMode", "nightModeStartHour", "nightModeStartMinute", "nightModeEndHour", "nightModeEndMinute", "latitude", "longitude", "nightModeUseIPLocation", "nightModeLocationProvider", "pinnedApps", "hiddenTrayIds", "selectedGpuIndex", "nvidiaGpuTempEnabled", "nonNvidiaGpuTempEnabled", "enabledGpuPciIds", "wifiDeviceOverride", "weatherHourlyDetailed", "wallpaperCyclingEnabled", "wallpaperCyclingMode", "wallpaperCyclingInterval", "wallpaperCyclingTime", "monitorCyclingSettings", "lastBrightnessDevice", "brightnessExponentialDevices", "brightnessUserSetValues", "brightnessExponentValues", "launchPrefix", "wallpaperTransition", "includedTransitions", "recentColors", "showThirdPartyPlugins", "configVersion"];
|
|
||||||
|
|
||||||
try {
|
|
||||||
const content = settingsFile.text();
|
|
||||||
if (!content || !content.trim())
|
|
||||||
return;
|
|
||||||
const settings = JSON.parse(content);
|
|
||||||
let needsSave = false;
|
|
||||||
|
|
||||||
for (const key in settings) {
|
|
||||||
if (!validKeys.includes(key)) {
|
|
||||||
console.log("SessionData: Removing unused key:", key);
|
|
||||||
delete settings[key];
|
|
||||||
needsSave = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (needsSave) {
|
|
||||||
settingsFile.setText(JSON.stringify(settings, null, 2));
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.warn("SessionData: Failed to cleanup unused keys:", e.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setLightMode(lightMode) {
|
function setLightMode(lightMode) {
|
||||||
isSwitchingMode = true;
|
isSwitchingMode = true;
|
||||||
isLightMode = lightMode;
|
isLightMode = lightMode;
|
||||||
@@ -919,6 +861,12 @@ Singleton {
|
|||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setWeatherLocation(displayName, coordinates) {
|
||||||
|
weatherLocation = displayName;
|
||||||
|
weatherCoordinates = coordinates;
|
||||||
|
saveSettings();
|
||||||
|
}
|
||||||
|
|
||||||
function syncWallpaperForCurrentMode() {
|
function syncWallpaperForCurrentMode() {
|
||||||
if (!perModeWallpaper)
|
if (!perModeWallpaper)
|
||||||
return;
|
return;
|
||||||
@@ -1001,14 +949,8 @@ Singleton {
|
|||||||
watchChanges: !isGreeterMode
|
watchChanges: !isGreeterMode
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
if (!isGreeterMode) {
|
if (!isGreeterMode) {
|
||||||
|
_hasUnsavedChanges = false;
|
||||||
parseSettings(settingsFile.text());
|
parseSettings(settingsFile.text());
|
||||||
hasTriedDefaultSession = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onLoadFailed: error => {
|
|
||||||
if (!isGreeterMode && !hasTriedDefaultSession) {
|
|
||||||
hasTriedDefaultSession = true;
|
|
||||||
defaultSessionCheckProcess.running = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1033,14 +975,17 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: defaultSessionCheckProcess
|
id: sessionWritableCheckProcess
|
||||||
|
|
||||||
command: ["sh", "-c", "CONFIG_DIR=\"" + _stateDir + "/DankMaterialShell\"; if [ -f \"$CONFIG_DIR/default-session.json\" ] && [ ! -f \"$CONFIG_DIR/session.json\" ]; then cp --no-preserve=mode \"$CONFIG_DIR/default-session.json\" \"$CONFIG_DIR/session.json\" && echo 'copied'; else echo 'not_found'; fi"]
|
property string sessionPath: Paths.strip(settingsFile.path)
|
||||||
|
|
||||||
|
command: ["sh", "-c", "[ -w \"" + sessionPath + "\" ] && echo 'writable' || echo 'readonly'"]
|
||||||
running: false
|
running: false
|
||||||
onExited: exitCode => {
|
|
||||||
if (exitCode === 0) {
|
stdout: StdioCollector {
|
||||||
console.info("Copied default-session.json to session.json");
|
onStreamFinished: {
|
||||||
settingsFile.reload();
|
const result = text.trim();
|
||||||
|
root._onWritableCheckComplete(result === "writable");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import "settings/SettingsStore.js" as Store
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property int settingsConfigVersion: 4
|
readonly property int settingsConfigVersion: 5
|
||||||
|
|
||||||
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
|
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
|
||||||
|
|
||||||
@@ -57,7 +57,10 @@ Singleton {
|
|||||||
property bool _pluginSettingsLoading: false
|
property bool _pluginSettingsLoading: false
|
||||||
property bool _parseError: false
|
property bool _parseError: false
|
||||||
property bool _pluginParseError: false
|
property bool _pluginParseError: false
|
||||||
property bool hasTriedDefaultSettings: false
|
property bool _hasLoaded: false
|
||||||
|
property bool _isReadOnly: false
|
||||||
|
property bool _hasUnsavedChanges: false
|
||||||
|
property var _loadedSettingsSnapshot: null
|
||||||
property var pluginSettings: ({})
|
property var pluginSettings: ({})
|
||||||
|
|
||||||
property alias dankBarLeftWidgetsModel: leftWidgetsModel
|
property alias dankBarLeftWidgetsModel: leftWidgetsModel
|
||||||
@@ -201,8 +204,10 @@ Singleton {
|
|||||||
property bool spotlightCloseNiriOverview: true
|
property bool spotlightCloseNiriOverview: true
|
||||||
property bool niriOverviewOverlayEnabled: true
|
property bool niriOverviewOverlayEnabled: true
|
||||||
|
|
||||||
property string weatherLocation: "New York, NY"
|
property string _legacyWeatherLocation: "New York, NY"
|
||||||
property string weatherCoordinates: "40.7128,-74.0060"
|
property string _legacyWeatherCoordinates: "40.7128,-74.0060"
|
||||||
|
readonly property string weatherLocation: SessionData.weatherLocation
|
||||||
|
readonly property string weatherCoordinates: SessionData.weatherCoordinates
|
||||||
property bool useAutoLocation: false
|
property bool useAutoLocation: false
|
||||||
property bool weatherEnabled: true
|
property bool weatherEnabled: true
|
||||||
|
|
||||||
@@ -775,6 +780,9 @@ Singleton {
|
|||||||
function loadSettings() {
|
function loadSettings() {
|
||||||
_loading = true;
|
_loading = true;
|
||||||
_parseError = false;
|
_parseError = false;
|
||||||
|
_hasUnsavedChanges = false;
|
||||||
|
_pendingMigration = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const txt = settingsFile.text();
|
const txt = settingsFile.text();
|
||||||
let obj = (txt && txt.trim()) ? JSON.parse(txt) : null;
|
let obj = (txt && txt.trim()) ? JSON.parse(txt) : null;
|
||||||
@@ -783,15 +791,25 @@ Singleton {
|
|||||||
if (oldVersion < settingsConfigVersion) {
|
if (oldVersion < settingsConfigVersion) {
|
||||||
const migrated = Store.migrateToVersion(obj, settingsConfigVersion);
|
const migrated = Store.migrateToVersion(obj, settingsConfigVersion);
|
||||||
if (migrated) {
|
if (migrated) {
|
||||||
settingsFile.setText(JSON.stringify(migrated, null, 2));
|
_pendingMigration = migrated;
|
||||||
obj = migrated;
|
obj = migrated;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Store.parse(root, obj);
|
Store.parse(root, obj);
|
||||||
|
|
||||||
|
if (obj.weatherLocation !== undefined)
|
||||||
|
_legacyWeatherLocation = obj.weatherLocation;
|
||||||
|
if (obj.weatherCoordinates !== undefined)
|
||||||
|
_legacyWeatherCoordinates = obj.weatherCoordinates;
|
||||||
|
|
||||||
|
_loadedSettingsSnapshot = JSON.stringify(Store.toJson(root));
|
||||||
|
_hasLoaded = true;
|
||||||
applyStoredTheme();
|
applyStoredTheme();
|
||||||
applyStoredIconTheme();
|
applyStoredIconTheme();
|
||||||
Processes.detectQtTools();
|
Processes.detectQtTools();
|
||||||
|
|
||||||
|
_checkSettingsWritable();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_parseError = true;
|
_parseError = true;
|
||||||
const msg = e.message;
|
const msg = e.message;
|
||||||
@@ -805,6 +823,33 @@ Singleton {
|
|||||||
loadPluginSettings();
|
loadPluginSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
property var _pendingMigration: null
|
||||||
|
|
||||||
|
function _checkSettingsWritable() {
|
||||||
|
settingsWritableCheckProcess.running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _onWritableCheckComplete(writable) {
|
||||||
|
_isReadOnly = !writable;
|
||||||
|
if (_isReadOnly) {
|
||||||
|
console.info("SettingsData: settings.json is read-only (NixOS home-manager mode)");
|
||||||
|
} else if (_pendingMigration) {
|
||||||
|
settingsFile.setText(JSON.stringify(_pendingMigration, null, 2));
|
||||||
|
}
|
||||||
|
_pendingMigration = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _checkForUnsavedChanges() {
|
||||||
|
if (!_hasLoaded || !_loadedSettingsSnapshot)
|
||||||
|
return false;
|
||||||
|
const current = JSON.stringify(Store.toJson(root));
|
||||||
|
return current !== _loadedSettingsSnapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCurrentSettingsJson() {
|
||||||
|
return JSON.stringify(Store.toJson(root), null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
function loadPluginSettings() {
|
function loadPluginSettings() {
|
||||||
_pluginSettingsLoading = true;
|
_pluginSettingsLoading = true;
|
||||||
parsePluginSettings(pluginSettingsFile.text());
|
parsePluginSettings(pluginSettingsFile.text());
|
||||||
@@ -832,8 +877,12 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
if (_loading || _parseError)
|
if (_loading || _parseError || !_hasLoaded)
|
||||||
return;
|
return;
|
||||||
|
if (_isReadOnly) {
|
||||||
|
_hasUnsavedChanges = _checkForUnsavedChanges();
|
||||||
|
return;
|
||||||
|
}
|
||||||
settingsFile.setText(JSON.stringify(Store.toJson(root), null, 2));
|
settingsFile.setText(JSON.stringify(Store.toJson(root), null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1398,9 +1447,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setWeatherLocation(displayName, coordinates) {
|
function setWeatherLocation(displayName, coordinates) {
|
||||||
weatherLocation = displayName;
|
SessionData.setWeatherLocation(displayName, coordinates);
|
||||||
weatherCoordinates = coordinates;
|
|
||||||
saveSettings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setIconTheme(themeName) {
|
function setIconTheme(themeName) {
|
||||||
@@ -1798,11 +1845,24 @@ Singleton {
|
|||||||
if (isGreeterMode)
|
if (isGreeterMode)
|
||||||
return;
|
return;
|
||||||
_loading = true;
|
_loading = true;
|
||||||
|
_hasUnsavedChanges = false;
|
||||||
try {
|
try {
|
||||||
const txt = settingsFile.text();
|
const txt = settingsFile.text();
|
||||||
const obj = (txt && txt.trim()) ? JSON.parse(txt) : null;
|
if (!txt || !txt.trim()) {
|
||||||
|
_parseError = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const obj = JSON.parse(txt);
|
||||||
_parseError = false;
|
_parseError = false;
|
||||||
Store.parse(root, obj);
|
Store.parse(root, obj);
|
||||||
|
|
||||||
|
if (obj.weatherLocation !== undefined)
|
||||||
|
_legacyWeatherLocation = obj.weatherLocation;
|
||||||
|
if (obj.weatherCoordinates !== undefined)
|
||||||
|
_legacyWeatherCoordinates = obj.weatherCoordinates;
|
||||||
|
|
||||||
|
_loadedSettingsSnapshot = JSON.stringify(Store.toJson(root));
|
||||||
|
_hasLoaded = true;
|
||||||
applyStoredTheme();
|
applyStoredTheme();
|
||||||
applyStoredIconTheme();
|
applyStoredIconTheme();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -1813,13 +1873,9 @@ Singleton {
|
|||||||
} finally {
|
} finally {
|
||||||
_loading = false;
|
_loading = false;
|
||||||
}
|
}
|
||||||
hasTriedDefaultSettings = false;
|
|
||||||
}
|
}
|
||||||
onLoadFailed: error => {
|
onLoadFailed: error => {
|
||||||
if (!isGreeterMode && !hasTriedDefaultSettings) {
|
if (!isGreeterMode) {
|
||||||
hasTriedDefaultSettings = true;
|
|
||||||
Processes.checkDefaultSettings();
|
|
||||||
} else if (!isGreeterMode) {
|
|
||||||
applyStoredTheme();
|
applyStoredTheme();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1846,4 +1902,20 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
property bool pluginSettingsFileExists: false
|
property bool pluginSettingsFileExists: false
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: settingsWritableCheckProcess
|
||||||
|
|
||||||
|
property string settingsPath: Paths.strip(settingsFile.path)
|
||||||
|
|
||||||
|
command: ["sh", "-c", "[ -w \"" + settingsPath + "\" ] && echo 'writable' || echo 'readonly'"]
|
||||||
|
running: false
|
||||||
|
|
||||||
|
stdout: StdioCollector {
|
||||||
|
onStreamFinished: {
|
||||||
|
const result = text.trim();
|
||||||
|
root._onWritableCheckComplete(result === "writable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,6 @@ Singleton {
|
|||||||
pluginSettingsCheckProcess.running = true;
|
pluginSettingsCheckProcess.running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkDefaultSettings() {
|
|
||||||
defaultSettingsCheckProcess.running = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
property var qtToolsDetectionProcess: Process {
|
property var qtToolsDetectionProcess: Process {
|
||||||
command: ["sh", "-c", "echo -n 'qt5ct:'; command -v qt5ct >/dev/null && echo 'true' || echo 'false'; echo -n 'qt6ct:'; command -v qt6ct >/dev/null && echo 'true' || echo 'false'; echo -n 'gtk:'; (command -v gsettings >/dev/null || command -v dconf >/dev/null) && echo 'true' || echo 'false'"]
|
command: ["sh", "-c", "echo -n 'qt5ct:'; command -v qt5ct >/dev/null && echo 'true' || echo 'false'; echo -n 'qt6ct:'; command -v qt6ct >/dev/null && echo 'true' || echo 'false'; echo -n 'gtk:'; (command -v gsettings >/dev/null || command -v dconf >/dev/null) && echo 'true' || echo 'false'"]
|
||||||
running: false
|
running: false
|
||||||
@@ -51,25 +47,6 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
property var defaultSettingsCheckProcess: Process {
|
|
||||||
command: ["sh", "-c", "CONFIG_DIR=\"" + (settingsRoot?._configDir || "") + "/DankMaterialShell\"; if [ -f \"$CONFIG_DIR/default-settings.json\" ] && [ ! -f \"$CONFIG_DIR/settings.json\" ]; then cp --no-preserve=mode \"$CONFIG_DIR/default-settings.json\" \"$CONFIG_DIR/settings.json\" && echo 'copied'; else echo 'not_found'; fi"]
|
|
||||||
running: false
|
|
||||||
onExited: function (exitCode) {
|
|
||||||
if (!settingsRoot)
|
|
||||||
return;
|
|
||||||
if (exitCode === 0) {
|
|
||||||
console.info("Copied default-settings.json to settings.json");
|
|
||||||
if (settingsRoot.settingsFile) {
|
|
||||||
settingsRoot.settingsFile.reload();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (typeof ThemeApplier !== "undefined") {
|
|
||||||
ThemeApplier.applyStoredTheme(settingsRoot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
property var fprintdDetectionProcess: Process {
|
property var fprintdDetectionProcess: Process {
|
||||||
command: ["sh", "-c", "command -v fprintd-list >/dev/null 2>&1"]
|
command: ["sh", "-c", "command -v fprintd-list >/dev/null 2>&1"]
|
||||||
running: false
|
running: false
|
||||||
|
|||||||
63
quickshell/Common/settings/SessionSpec.js
Normal file
63
quickshell/Common/settings/SessionSpec.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
.pragma library
|
||||||
|
|
||||||
|
var SPEC = {
|
||||||
|
isLightMode: { def: false },
|
||||||
|
doNotDisturb: { def: false },
|
||||||
|
|
||||||
|
wallpaperPath: { def: "" },
|
||||||
|
perMonitorWallpaper: { def: false },
|
||||||
|
monitorWallpapers: { def: {} },
|
||||||
|
perModeWallpaper: { def: false },
|
||||||
|
wallpaperPathLight: { def: "" },
|
||||||
|
wallpaperPathDark: { def: "" },
|
||||||
|
monitorWallpapersLight: { def: {} },
|
||||||
|
monitorWallpapersDark: { def: {} },
|
||||||
|
wallpaperTransition: { def: "fade" },
|
||||||
|
includedTransitions: { def: ["fade", "wipe", "disc", "stripes", "iris bloom", "pixelate", "portal"] },
|
||||||
|
|
||||||
|
wallpaperCyclingEnabled: { def: false },
|
||||||
|
wallpaperCyclingMode: { def: "interval" },
|
||||||
|
wallpaperCyclingInterval: { def: 300 },
|
||||||
|
wallpaperCyclingTime: { def: "06:00" },
|
||||||
|
monitorCyclingSettings: { def: {} },
|
||||||
|
|
||||||
|
nightModeEnabled: { def: false },
|
||||||
|
nightModeTemperature: { def: 4500 },
|
||||||
|
nightModeHighTemperature: { def: 6500 },
|
||||||
|
nightModeAutoEnabled: { def: false },
|
||||||
|
nightModeAutoMode: { def: "time" },
|
||||||
|
nightModeStartHour: { def: 18 },
|
||||||
|
nightModeStartMinute: { def: 0 },
|
||||||
|
nightModeEndHour: { def: 6 },
|
||||||
|
nightModeEndMinute: { def: 0 },
|
||||||
|
latitude: { def: 0.0 },
|
||||||
|
longitude: { def: 0.0 },
|
||||||
|
nightModeUseIPLocation: { def: false },
|
||||||
|
nightModeLocationProvider: { def: "" },
|
||||||
|
|
||||||
|
weatherLocation: { def: "New York, NY" },
|
||||||
|
weatherCoordinates: { def: "40.7128,-74.0060" },
|
||||||
|
|
||||||
|
pinnedApps: { def: [] },
|
||||||
|
hiddenTrayIds: { def: [] },
|
||||||
|
recentColors: { def: [] },
|
||||||
|
showThirdPartyPlugins: { def: false },
|
||||||
|
launchPrefix: { def: "" },
|
||||||
|
lastBrightnessDevice: { def: "" },
|
||||||
|
|
||||||
|
brightnessExponentialDevices: { def: {} },
|
||||||
|
brightnessUserSetValues: { def: {} },
|
||||||
|
brightnessExponentValues: { def: {} },
|
||||||
|
|
||||||
|
selectedGpuIndex: { def: 0 },
|
||||||
|
nvidiaGpuTempEnabled: { def: false },
|
||||||
|
nonNvidiaGpuTempEnabled: { def: false },
|
||||||
|
enabledGpuPciIds: { def: [] },
|
||||||
|
|
||||||
|
wifiDeviceOverride: { def: "" },
|
||||||
|
weatherHourlyDetailed: { def: true }
|
||||||
|
};
|
||||||
|
|
||||||
|
function getValidKeys() {
|
||||||
|
return Object.keys(SPEC).concat(["configVersion"]);
|
||||||
|
}
|
||||||
92
quickshell/Common/settings/SessionStore.js
Normal file
92
quickshell/Common/settings/SessionStore.js
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
.pragma library
|
||||||
|
|
||||||
|
.import "./SessionSpec.js" as SpecModule
|
||||||
|
|
||||||
|
function parse(root, jsonObj) {
|
||||||
|
var SPEC = SpecModule.SPEC;
|
||||||
|
for (var k in SPEC) {
|
||||||
|
root[k] = SPEC[k].def;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!jsonObj) return;
|
||||||
|
|
||||||
|
for (var k in jsonObj) {
|
||||||
|
if (!SPEC[k]) continue;
|
||||||
|
var raw = jsonObj[k];
|
||||||
|
var spec = SPEC[k];
|
||||||
|
var coerce = spec.coerce;
|
||||||
|
root[k] = coerce ? (coerce(raw) !== undefined ? coerce(raw) : root[k]) : raw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toJson(root) {
|
||||||
|
var SPEC = SpecModule.SPEC;
|
||||||
|
var out = {};
|
||||||
|
for (var k in SPEC) {
|
||||||
|
if (SPEC[k].persist === false) continue;
|
||||||
|
out[k] = root[k];
|
||||||
|
}
|
||||||
|
out.configVersion = root.sessionConfigVersion;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrateToVersion(obj, targetVersion, settingsData) {
|
||||||
|
if (!obj) return null;
|
||||||
|
|
||||||
|
var session = JSON.parse(JSON.stringify(obj));
|
||||||
|
var currentVersion = session.configVersion || 0;
|
||||||
|
|
||||||
|
if (currentVersion >= targetVersion) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentVersion < 2) {
|
||||||
|
console.info("SessionData: Migrating session from version", currentVersion, "to version 2");
|
||||||
|
console.info("SessionData: Importing weather location and coordinates from settings");
|
||||||
|
|
||||||
|
if (settingsData && typeof settingsData !== "undefined") {
|
||||||
|
if (session.weatherLocation === undefined || session.weatherLocation === "New York, NY") {
|
||||||
|
var settingsWeatherLocation = settingsData._legacyWeatherLocation;
|
||||||
|
if (settingsWeatherLocation && settingsWeatherLocation !== "New York, NY") {
|
||||||
|
session.weatherLocation = settingsWeatherLocation;
|
||||||
|
console.info("SessionData: Migrated weatherLocation:", settingsWeatherLocation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session.weatherCoordinates === undefined || session.weatherCoordinates === "40.7128,-74.0060") {
|
||||||
|
var settingsWeatherCoordinates = settingsData._legacyWeatherCoordinates;
|
||||||
|
if (settingsWeatherCoordinates && settingsWeatherCoordinates !== "40.7128,-74.0060") {
|
||||||
|
session.weatherCoordinates = settingsWeatherCoordinates;
|
||||||
|
console.info("SessionData: Migrated weatherCoordinates:", settingsWeatherCoordinates);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session.configVersion = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return session;
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup(fileText) {
|
||||||
|
var getValidKeys = SpecModule.getValidKeys;
|
||||||
|
if (!fileText || !fileText.trim()) return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
var session = JSON.parse(fileText);
|
||||||
|
var validKeys = getValidKeys();
|
||||||
|
var needsSave = false;
|
||||||
|
|
||||||
|
for (var key in session) {
|
||||||
|
if (validKeys.indexOf(key) < 0) {
|
||||||
|
delete session[key];
|
||||||
|
needsSave = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return needsSave ? JSON.stringify(session, null, 2) : null;
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("SessionData: Failed to cleanup unused keys:", e.message);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -112,8 +112,6 @@ var SPEC = {
|
|||||||
spotlightCloseNiriOverview: { def: true },
|
spotlightCloseNiriOverview: { def: true },
|
||||||
niriOverviewOverlayEnabled: { def: true },
|
niriOverviewOverlayEnabled: { def: true },
|
||||||
|
|
||||||
weatherLocation: { def: "New York, NY" },
|
|
||||||
weatherCoordinates: { def: "40.7128,-74.0060" },
|
|
||||||
useAutoLocation: { def: false },
|
useAutoLocation: { def: false },
|
||||||
weatherEnabled: { def: true },
|
weatherEnabled: { def: true },
|
||||||
|
|
||||||
|
|||||||
@@ -214,6 +214,16 @@ function migrateToVersion(obj, targetVersion) {
|
|||||||
settings.configVersion = 4;
|
settings.configVersion = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentVersion < 5) {
|
||||||
|
console.info("Migrating settings from version", currentVersion, "to version 5");
|
||||||
|
console.info("Moving sensitive data (weather location, coordinates) to session.json");
|
||||||
|
|
||||||
|
delete settings.weatherLocation;
|
||||||
|
delete settings.weatherCoordinates;
|
||||||
|
|
||||||
|
settings.configVersion = 5;
|
||||||
|
}
|
||||||
|
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -220,9 +220,91 @@ FloatingWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: readOnlyBanner
|
||||||
|
|
||||||
|
property bool showBanner: (SettingsData._isReadOnly && SettingsData._hasUnsavedChanges) || (SessionData._isReadOnly && SessionData._hasUnsavedChanges)
|
||||||
|
|
||||||
|
width: parent.width
|
||||||
|
height: showBanner ? bannerContent.implicitHeight + Theme.spacingM * 2 : 0
|
||||||
|
color: Theme.surfaceContainerHigh
|
||||||
|
visible: showBanner
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Behavior on height {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: bannerContent
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
anchors.leftMargin: Theme.spacingL
|
||||||
|
anchors.rightMargin: Theme.spacingM
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "info"
|
||||||
|
size: Theme.iconSize
|
||||||
|
color: Theme.warning
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
id: bannerText
|
||||||
|
|
||||||
|
text: I18n.tr("Settings are read-only. Changes will not persist.", "read-only settings warning for NixOS home-manager users")
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: Math.max(100, parent.width - (copySettingsButton.visible ? copySettingsButton.width + Theme.spacingM : 0) - (copySessionButton.visible ? copySessionButton.width + Theme.spacingM : 0) - Theme.spacingM * 2 - Theme.iconSize)
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
id: copySettingsButton
|
||||||
|
|
||||||
|
visible: SettingsData._isReadOnly && SettingsData._hasUnsavedChanges
|
||||||
|
text: "settings.json"
|
||||||
|
iconName: "content_copy"
|
||||||
|
backgroundColor: Theme.primary
|
||||||
|
textColor: Theme.primaryText
|
||||||
|
buttonHeight: 32
|
||||||
|
horizontalPadding: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
onClicked: {
|
||||||
|
Quickshell.execDetached(["dms", "cl", "copy", SettingsData.getCurrentSettingsJson()]);
|
||||||
|
ToastService.showInfo(I18n.tr("Copied to clipboard"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
id: copySessionButton
|
||||||
|
|
||||||
|
visible: SessionData._isReadOnly && SessionData._hasUnsavedChanges
|
||||||
|
text: "session.json"
|
||||||
|
iconName: "content_copy"
|
||||||
|
backgroundColor: Theme.primary
|
||||||
|
textColor: Theme.primaryText
|
||||||
|
buttonHeight: 32
|
||||||
|
horizontalPadding: Theme.spacingM
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
onClicked: {
|
||||||
|
Quickshell.execDetached(["dms", "cl", "copy", SessionData.getCurrentSessionJson()]);
|
||||||
|
ToastService.showInfo(I18n.tr("Copied to clipboard"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height - 48
|
height: parent.height - 48 - readOnlyBanner.height
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
SettingsSidebar {
|
SettingsSidebar {
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ Item {
|
|||||||
currentIndex = clampedIndex;
|
currentIndex = clampedIndex;
|
||||||
positionViewAtIndex(clampedIndex, GridView.Contain);
|
positionViewAtIndex(clampedIndex, GridView.Contain);
|
||||||
}
|
}
|
||||||
enableAnimation = true;
|
Qt.callLater(() => { enableAnimation = true; });
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
@@ -465,12 +465,6 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BusyIndicator {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
running: thumbnailImage.status === Image.Loading
|
|
||||||
visible: running
|
|
||||||
}
|
|
||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cornerRadius: parent.radius
|
cornerRadius: parent.radius
|
||||||
|
|||||||
@@ -35,6 +35,17 @@ Variants {
|
|||||||
|
|
||||||
readonly property real widgetHeight: SettingsData.dockIconSize
|
readonly property real widgetHeight: SettingsData.dockIconSize
|
||||||
readonly property real effectiveBarHeight: widgetHeight + SettingsData.dockSpacing * 2 + 10 + borderThickness * 2
|
readonly property real effectiveBarHeight: widgetHeight + SettingsData.dockSpacing * 2 + 10 + borderThickness * 2
|
||||||
|
function getBarHeight(barConfig) {
|
||||||
|
if (!barConfig)
|
||||||
|
return 0;
|
||||||
|
const innerPadding = barConfig.innerPadding ?? 4;
|
||||||
|
const widgetThickness = Math.max(20, 26 + innerPadding * 0.6);
|
||||||
|
const barThickness = Math.max(widgetThickness + innerPadding + 4, Theme.barHeight - 4 - (8 - innerPadding));
|
||||||
|
const spacing = barConfig.spacing ?? 4;
|
||||||
|
const bottomGap = barConfig.bottomGap ?? 0;
|
||||||
|
return barThickness + spacing + bottomGap;
|
||||||
|
}
|
||||||
|
|
||||||
readonly property real barSpacing: {
|
readonly property real barSpacing: {
|
||||||
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default");
|
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default");
|
||||||
if (!defaultBar)
|
if (!defaultBar)
|
||||||
@@ -60,6 +71,36 @@ Variants {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
readonly property real adjacentTopBarHeight: {
|
||||||
|
if (!isVertical || autoHide)
|
||||||
|
return 0;
|
||||||
|
const screenName = dock.modelData?.name ?? "";
|
||||||
|
const topBar = SettingsData.barConfigs.find(bc => {
|
||||||
|
if (!bc.enabled || bc.autoHide || !(bc.visible ?? true))
|
||||||
|
return false;
|
||||||
|
if (bc.position !== SettingsData.Position.Top && bc.position !== 0)
|
||||||
|
return false;
|
||||||
|
const onThisScreen = bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all") || bc.screenPreferences.includes(screenName);
|
||||||
|
return onThisScreen;
|
||||||
|
});
|
||||||
|
return getBarHeight(topBar);
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property real adjacentLeftBarWidth: {
|
||||||
|
if (isVertical || autoHide)
|
||||||
|
return 0;
|
||||||
|
const screenName = dock.modelData?.name ?? "";
|
||||||
|
const leftBar = SettingsData.barConfigs.find(bc => {
|
||||||
|
if (!bc.enabled || bc.autoHide || !(bc.visible ?? true))
|
||||||
|
return false;
|
||||||
|
if (bc.position !== SettingsData.Position.Left && bc.position !== 2)
|
||||||
|
return false;
|
||||||
|
const onThisScreen = bc.screenPreferences.length === 0 || bc.screenPreferences.includes("all") || bc.screenPreferences.includes(screenName);
|
||||||
|
return onThisScreen;
|
||||||
|
});
|
||||||
|
return getBarHeight(leftBar);
|
||||||
|
}
|
||||||
|
|
||||||
readonly property real dockMargin: SettingsData.dockSpacing
|
readonly property real dockMargin: SettingsData.dockSpacing
|
||||||
readonly property real positionSpacing: barSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin
|
readonly property real positionSpacing: barSpacing + SettingsData.dockBottomGap + SettingsData.dockMargin
|
||||||
readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1
|
readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1
|
||||||
@@ -186,27 +227,31 @@ Variants {
|
|||||||
|
|
||||||
function showTooltipForHoveredButton() {
|
function showTooltipForHoveredButton() {
|
||||||
dockTooltip.hide();
|
dockTooltip.hide();
|
||||||
if (dock.hoveredButton && dock.reveal && !slideXAnimation.running && !slideYAnimation.running) {
|
if (!dock.hoveredButton || !dock.reveal || slideXAnimation.running || slideYAnimation.running)
|
||||||
const buttonGlobalPos = dock.hoveredButton.mapToGlobal(0, 0);
|
return;
|
||||||
const tooltipText = dock.hoveredButton.tooltipText || "";
|
|
||||||
if (tooltipText) {
|
const buttonGlobalPos = dock.hoveredButton.mapToGlobal(0, 0);
|
||||||
const screenX = dock.screen ? (dock.screen.x || 0) : 0;
|
const tooltipText = dock.hoveredButton.tooltipText || "";
|
||||||
const screenY = dock.screen ? (dock.screen.y || 0) : 0;
|
if (!tooltipText)
|
||||||
const screenHeight = dock.screen ? dock.screen.height : 0;
|
return;
|
||||||
if (!dock.isVertical) {
|
|
||||||
const isBottom = SettingsData.dockPosition === SettingsData.Position.Bottom;
|
const screenX = dock.screen ? (dock.screen.x || 0) : 0;
|
||||||
const globalX = buttonGlobalPos.x + dock.hoveredButton.width / 2;
|
const screenY = dock.screen ? (dock.screen.y || 0) : 0;
|
||||||
const screenRelativeY = isBottom ? (screenHeight - dock.effectiveBarHeight - SettingsData.dockSpacing - SettingsData.dockBottomGap - SettingsData.dockMargin - 35) : (buttonGlobalPos.y - screenY + dock.hoveredButton.height + Theme.spacingS);
|
const screenHeight = dock.screen ? dock.screen.height : 0;
|
||||||
dockTooltip.show(tooltipText, globalX, screenRelativeY, dock.screen, false, false);
|
|
||||||
} else {
|
if (!dock.isVertical) {
|
||||||
const isLeft = SettingsData.dockPosition === SettingsData.Position.Left;
|
const isBottom = SettingsData.dockPosition === SettingsData.Position.Bottom;
|
||||||
const tooltipOffset = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + Theme.spacingXS;
|
const globalX = buttonGlobalPos.x + dock.hoveredButton.width / 2 + adjacentLeftBarWidth;
|
||||||
const tooltipX = isLeft ? tooltipOffset : (dock.screen.width - tooltipOffset);
|
const screenRelativeY = isBottom ? (screenHeight - dock.effectiveBarHeight - SettingsData.dockSpacing - SettingsData.dockBottomGap - SettingsData.dockMargin - barSpacing - 35) : (buttonGlobalPos.y - screenY + dock.hoveredButton.height + Theme.spacingS);
|
||||||
const screenRelativeY = buttonGlobalPos.y - screenY + dock.hoveredButton.height / 2;
|
dockTooltip.show(tooltipText, globalX, screenRelativeY, dock.screen, false, false);
|
||||||
dockTooltip.show(tooltipText, screenX + tooltipX, screenRelativeY, dock.screen, isLeft, !isLeft);
|
return;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isLeft = SettingsData.dockPosition === SettingsData.Position.Left;
|
||||||
|
const tooltipOffset = dock.effectiveBarHeight + SettingsData.dockSpacing + SettingsData.dockMargin + barSpacing + Theme.spacingXS;
|
||||||
|
const tooltipX = isLeft ? tooltipOffset : (dock.screen.width - tooltipOffset);
|
||||||
|
const screenRelativeY = buttonGlobalPos.y - screenY + dock.hoveredButton.height / 2 + adjacentTopBarHeight;
|
||||||
|
dockTooltip.show(tooltipText, screenX + tooltipX, screenRelativeY, dock.screen, isLeft, !isLeft);
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
|||||||
@@ -186,13 +186,11 @@ exec = sh -c "$QS_CMD; hyprctl dispatch exit"
|
|||||||
HYPRLAND_EOF
|
HYPRLAND_EOF
|
||||||
COMPOSITOR_CONFIG="$TEMP_CONFIG"
|
COMPOSITOR_CONFIG="$TEMP_CONFIG"
|
||||||
fi
|
fi
|
||||||
CURRENT_VERSION=$(hyprland --version | grep "Tag:" | awk '{print $2}' | tr -d 'v,')
|
if command -v start-hyprland >/dev/null 2>&1; then
|
||||||
MINIMUM_VERSION="0.53.0"
|
exec start-hyprland -- --config "$COMPOSITOR_CONFIG"
|
||||||
if [ "$(printf '%s\n%s' "$MINIMUM_VERSION" "$CURRENT_VERSION" | sort -V | head -n1)" = "$MINIMUM_VERSION" ]; then
|
else
|
||||||
exec start-hyprland -- --config "$COMPOSITOR_CONFIG"
|
exec Hyprland -c "$COMPOSITOR_CONFIG"
|
||||||
else
|
fi
|
||||||
exec Hyprland -c "$COMPOSITOR_CONFIG"
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
sway)
|
sway)
|
||||||
|
|||||||
@@ -4,11 +4,7 @@ export XDG_SESSION_TYPE=wayland
|
|||||||
export QT_QPA_PLATFORM=wayland
|
export QT_QPA_PLATFORM=wayland
|
||||||
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
|
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
|
||||||
export EGL_PLATFORM=gbm
|
export EGL_PLATFORM=gbm
|
||||||
CURRENT_VERSION=$(hyprland --version | grep "Tag:" | awk '{print $2}' | tr -d 'v,')
|
if command -v start-hyprland >/dev/null 2>&1; then
|
||||||
|
|
||||||
MINIMUM_VERSION="0.53.0"
|
|
||||||
|
|
||||||
if [ "$(printf '%s\n%s' "$MINIMUM_VERSION" "$CURRENT_VERSION" | sort -V | head -n1)" = "$MINIMUM_VERSION" ]; then
|
|
||||||
exec start-hyprland -- -c /etc/greetd/dms-hypr.conf
|
exec start-hyprland -- -c /etc/greetd/dms-hypr.conf
|
||||||
else
|
else
|
||||||
exec Hyprland -c /etc/greetd/dms-hypr.conf
|
exec Hyprland -c /etc/greetd/dms-hypr.conf
|
||||||
|
|||||||
@@ -455,8 +455,8 @@ Item {
|
|||||||
onTextEdited: {
|
onTextEdited: {
|
||||||
if (text && longitudeInput.text) {
|
if (text && longitudeInput.text) {
|
||||||
const coords = text + "," + longitudeInput.text;
|
const coords = text + "," + longitudeInput.text;
|
||||||
SettingsData.weatherCoordinates = coords;
|
SessionData.weatherCoordinates = coords;
|
||||||
SettingsData.saveSettings();
|
SessionData.saveSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -505,8 +505,8 @@ Item {
|
|||||||
onTextEdited: {
|
onTextEdited: {
|
||||||
if (text && latitudeInput.text) {
|
if (text && latitudeInput.text) {
|
||||||
const coords = latitudeInput.text + "," + text;
|
const coords = latitudeInput.text + "," + text;
|
||||||
SettingsData.weatherCoordinates = coords;
|
SessionData.weatherCoordinates = coords;
|
||||||
SettingsData.saveSettings();
|
SessionData.saveSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,24 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell.Io
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
|
|
||||||
Image {
|
Image {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string imagePath: ""
|
property string imagePath: ""
|
||||||
property string imageHash: ""
|
|
||||||
property int maxCacheSize: 512
|
property int maxCacheSize: 512
|
||||||
|
|
||||||
|
function djb2Hash(str) {
|
||||||
|
if (!str)
|
||||||
|
return "";
|
||||||
|
let hash = 5381;
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
hash = ((hash << 5) + hash) + str.charCodeAt(i);
|
||||||
|
hash = hash & 0x7FFFFFFF;
|
||||||
|
}
|
||||||
|
return hash.toString(16).padStart(8, '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property string imageHash: imagePath ? djb2Hash(imagePath) : ""
|
||||||
readonly property string cachePath: imageHash ? `${Paths.stringify(Paths.imagecache)}/${imageHash}@${maxCacheSize}x${maxCacheSize}.png` : ""
|
readonly property string cachePath: imageHash ? `${Paths.stringify(Paths.imagecache)}/${imageHash}@${maxCacheSize}x${maxCacheSize}.png` : ""
|
||||||
|
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
@@ -15,43 +26,27 @@ Image {
|
|||||||
sourceSize.width: maxCacheSize
|
sourceSize.width: maxCacheSize
|
||||||
sourceSize.height: maxCacheSize
|
sourceSize.height: maxCacheSize
|
||||||
smooth: true
|
smooth: true
|
||||||
|
|
||||||
onImagePathChanged: {
|
onImagePathChanged: {
|
||||||
if (!imagePath) {
|
if (!imagePath) {
|
||||||
source = ""
|
source = "";
|
||||||
imageHash = ""
|
return;
|
||||||
return
|
|
||||||
}
|
}
|
||||||
hashProcess.command = ["sha256sum", Paths.strip(imagePath)]
|
Paths.mkdir(Paths.imagecache);
|
||||||
hashProcess.running = true
|
source = cachePath || imagePath;
|
||||||
}
|
}
|
||||||
onCachePathChanged: {
|
|
||||||
if (!imageHash || !cachePath)
|
|
||||||
return
|
|
||||||
|
|
||||||
Paths.mkdir(Paths.imagecache)
|
|
||||||
source = cachePath
|
|
||||||
}
|
|
||||||
onStatusChanged: {
|
onStatusChanged: {
|
||||||
if (source == cachePath && status === Image.Error) {
|
if (source == cachePath && status === Image.Error) {
|
||||||
source = imagePath
|
source = imagePath;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (source != imagePath || status !== Image.Ready || !imageHash || !cachePath)
|
if (source != imagePath || status !== Image.Ready || !cachePath)
|
||||||
return
|
return;
|
||||||
|
Paths.mkdir(Paths.imagecache);
|
||||||
Paths.mkdir(Paths.imagecache)
|
const grabPath = cachePath;
|
||||||
const grabPath = cachePath
|
if (visible && width > 0 && height > 0 && Window.window?.visible) {
|
||||||
if (visible && width > 0 && height > 0 && Window.window && Window.window.visible)
|
grabToImage(res => res.saveToFile(grabPath));
|
||||||
grabToImage(res => {
|
|
||||||
return res.saveToFile(grabPath)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: hashProcess
|
|
||||||
|
|
||||||
stdout: StdioCollector {
|
|
||||||
onStreamFinished: root.imageHash = text.split(" ")[0]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ Rectangle {
|
|||||||
radius: parent.radius
|
radius: parent.radius
|
||||||
color: {
|
color: {
|
||||||
if (pressed)
|
if (pressed)
|
||||||
return Theme.primaryPressed;
|
return Theme.withAlpha(root.textColor, 0.20);
|
||||||
if (hovered)
|
if (hovered)
|
||||||
return Theme.primaryHover;
|
return Theme.withAlpha(root.textColor, 0.12);
|
||||||
return "transparent";
|
return "transparent";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user