1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-30 09:32:05 -04:00

logger: add a dedicated QML logging Singleton

- adds log.info/error/debug/warn/fatal
- adds ability to write logs to any file
- add CLI options in addition to env to set log levels
This commit is contained in:
bbedward
2026-04-29 15:40:44 -04:00
parent 3b96c6ab22
commit f76724f7cd
84 changed files with 1764 additions and 1297 deletions

View File

@@ -26,6 +26,17 @@ var runCmd = &cobra.Command{
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
daemon, _ := cmd.Flags().GetBool("daemon") daemon, _ := cmd.Flags().GetBool("daemon")
session, _ := cmd.Flags().GetBool("session") session, _ := cmd.Flags().GetBool("session")
if v, _ := cmd.Flags().GetString("log-level"); v != "" {
if err := os.Setenv("DMS_LOG_LEVEL", v); err != nil {
log.Fatalf("Failed to set DMS_LOG_LEVEL: %v", err)
}
}
if v, _ := cmd.Flags().GetString("log-file"); v != "" {
if err := os.Setenv("DMS_LOG_FILE", v); err != nil {
log.Fatalf("Failed to set DMS_LOG_FILE: %v", err)
}
}
log.ApplyEnvOverrides()
if daemon { if daemon {
runShellDaemon(session) runShellDaemon(session)
} else { } else {

View File

@@ -15,6 +15,8 @@ func init() {
runCmd.Flags().BoolP("daemon", "d", false, "Run in daemon mode") runCmd.Flags().BoolP("daemon", "d", false, "Run in daemon mode")
runCmd.Flags().Bool("daemon-child", false, "Internal flag for daemon child process") runCmd.Flags().Bool("daemon-child", false, "Internal flag for daemon child process")
runCmd.Flags().Bool("session", false, "Session managed (like as a systemd unit)") runCmd.Flags().Bool("session", false, "Session managed (like as a systemd unit)")
runCmd.Flags().String("log-level", "", "Log level: debug, info, warn, error, fatal (overrides DMS_LOG_LEVEL)")
runCmd.Flags().String("log-file", "", "Append logs to this file in addition to stderr (overrides DMS_LOG_FILE)")
runCmd.Flags().MarkHidden("daemon-child") runCmd.Flags().MarkHidden("daemon-child")
greeterCmd.AddCommand(greeterInstallCmd, greeterSyncCmd, greeterEnableCmd, greeterStatusCmd, greeterUninstallCmd) greeterCmd.AddCommand(greeterInstallCmd, greeterSyncCmd, greeterEnableCmd, greeterStatusCmd, greeterUninstallCmd)

View File

@@ -15,6 +15,8 @@ func init() {
runCmd.Flags().BoolP("daemon", "d", false, "Run in daemon mode") runCmd.Flags().BoolP("daemon", "d", false, "Run in daemon mode")
runCmd.Flags().Bool("daemon-child", false, "Internal flag for daemon child process") runCmd.Flags().Bool("daemon-child", false, "Internal flag for daemon child process")
runCmd.Flags().Bool("session", false, "Session managed (like as a systemd unit)") runCmd.Flags().Bool("session", false, "Session managed (like as a systemd unit)")
runCmd.Flags().String("log-level", "", "Log level: debug, info, warn, error, fatal (overrides DMS_LOG_LEVEL)")
runCmd.Flags().String("log-file", "", "Append logs to this file in addition to stderr (overrides DMS_LOG_FILE)")
runCmd.Flags().MarkHidden("daemon-child") runCmd.Flags().MarkHidden("daemon-child")
greeterCmd.AddCommand(greeterInstallCmd, greeterSyncCmd, greeterEnableCmd, greeterStatusCmd, greeterUninstallCmd) greeterCmd.AddCommand(greeterInstallCmd, greeterSyncCmd, greeterEnableCmd, greeterStatusCmd, greeterUninstallCmd)

View File

@@ -80,6 +80,16 @@ func getRuntimeDir() string {
return os.TempDir() return os.TempDir()
} }
func appendLogEnv(env []string) []string {
if v := os.Getenv("DMS_LOG_LEVEL"); v != "" {
env = append(env, "DMS_LOG_LEVEL="+v)
}
if v := os.Getenv("DMS_LOG_FILE"); v != "" {
env = append(env, "DMS_LOG_FILE="+v)
}
return env
}
func hasSystemdRun() bool { func hasSystemdRun() bool {
_, err := exec.LookPath("systemd-run") _, err := exec.LookPath("systemd-run")
return err == nil return err == nil
@@ -216,6 +226,8 @@ func runShellInteractive(session bool) {
cmd.Env = append(cmd.Env, "QT_QPA_PLATFORM=wayland;xcb") cmd.Env = append(cmd.Env, "QT_QPA_PLATFORM=wayland;xcb")
} }
cmd.Env = appendLogEnv(cmd.Env)
cmd.Stdin = os.Stdin cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
@@ -459,6 +471,8 @@ func runShellDaemon(session bool) {
cmd.Env = append(cmd.Env, "QT_QPA_PLATFORM=wayland;xcb") cmd.Env = append(cmd.Env, "QT_QPA_PLATFORM=wayland;xcb")
} }
cmd.Env = appendLogEnv(cmd.Env)
devNull, err := os.OpenFile("/dev/null", os.O_RDWR, 0) devNull, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
if err != nil { if err != nil {
log.Fatalf("Error opening /dev/null: %v", err) log.Fatalf("Error opening /dev/null: %v", err)

View File

@@ -66,12 +66,12 @@ require (
github.com/go-git/go-git/v6 v6.0.0-alpha.2 github.com/go-git/go-git/v6 v6.0.0-alpha.2
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/lucasb-eyer/go-colorful v1.4.0 github.com/lucasb-eyer/go-colorful v1.4.0
github.com/mattn/go-isatty v0.0.22 // indirect github.com/mattn/go-isatty v0.0.22
github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-localereader v0.0.1 // indirect
github.com/mattn/go-runewidth v0.0.23 // indirect github.com/mattn/go-runewidth v0.0.23 // indirect
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
github.com/muesli/cancelreader v0.2.2 // indirect github.com/muesli/cancelreader v0.2.2 // indirect
github.com/muesli/termenv v0.16.0 // indirect github.com/muesli/termenv v0.16.0
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/afero v1.15.0 github.com/spf13/afero v1.15.0

View File

@@ -1,12 +1,16 @@
package log package log
import ( import (
"io"
"os" "os"
"regexp"
"strings" "strings"
"sync" "sync"
"github.com/charmbracelet/lipgloss" "github.com/charmbracelet/lipgloss"
cblog "github.com/charmbracelet/log" cblog "github.com/charmbracelet/log"
"github.com/mattn/go-isatty"
"github.com/muesli/termenv"
) )
// Logger embeds the Charm Logger and adds Printf/Fatalf // Logger embeds the Charm Logger and adds Printf/Fatalf
@@ -21,8 +25,26 @@ func (l *Logger) Fatalf(format string, v ...any) { l.Logger.Fatalf(format, v...)
var ( var (
logger *Logger logger *Logger
initLogger sync.Once initLogger sync.Once
logMu sync.Mutex
logFile *os.File
logStderr io.Writer = os.Stderr
ansiRe = regexp.MustCompile(`\x1b\[[0-9;]*[a-zA-Z]`)
) )
// ansiStripWriter strips ANSI escape sequences before forwarding to w. Used
// for the file sink so colored stderr stays colored while the file stays plain.
type ansiStripWriter struct{ w io.Writer }
func (a *ansiStripWriter) Write(p []byte) (int, error) {
stripped := ansiRe.ReplaceAll(p, nil)
if _, err := a.w.Write(stripped); err != nil {
return 0, err
}
return len(p), nil
}
func parseLogLevel(level string) cblog.Level { func parseLogLevel(level string) cblog.Level {
switch strings.ToLower(level) { switch strings.ToLower(level) {
case "debug": case "debug":
@@ -86,7 +108,7 @@ func GetLogger() *Logger {
SetString(" DEBUG"). SetString(" DEBUG").
Foreground(lipgloss.Color("4")) Foreground(lipgloss.Color("4"))
base := cblog.New(os.Stderr) base := cblog.New(logStderr)
base.SetStyles(styles) base.SetStyles(styles)
base.SetReportTimestamp(false) base.SetReportTimestamp(false)
@@ -98,10 +120,85 @@ func GetLogger() *Logger {
base.SetPrefix(" go") base.SetPrefix(" go")
logger = &Logger{base} logger = &Logger{base}
if path := os.Getenv("DMS_LOG_FILE"); path != "" {
_ = SetLogFile(path)
}
}) })
return logger return logger
} }
// SetLevel updates the active log level. Accepts the same strings as
// DMS_LOG_LEVEL. Unknown values default to info.
func SetLevel(level string) {
GetLogger().SetLevel(parseLogLevel(level))
}
// SetLogFile makes the logger append to path in addition to stderr. Passing an
// empty string detaches the file sink. Atomic per-line writes (≤PIPE_BUF) on
// O_APPEND keep concurrent Go and QML writers from corrupting each other.
//
// Color handling: charmbracelet/log auto-detects color support from its
// io.Writer, and io.MultiWriter doesn't pass that through, so we force the ANSI
// profile when stderr is a TTY and route the file through ansiStripWriter so
// the file stays plain while stderr keeps its colors.
func SetLogFile(path string) error {
logMu.Lock()
defer logMu.Unlock()
if logFile != nil {
logFile.Close()
logFile = nil
}
l := GetLogger()
if path == "" {
l.SetOutput(logStderr)
applyColorProfile(l, logStderr)
return nil
}
f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0o644)
if err != nil {
return err
}
logFile = f
out := io.MultiWriter(logStderr, &ansiStripWriter{w: f})
l.SetOutput(out)
applyColorProfile(l, logStderr)
return nil
}
// applyColorProfile forces the renderer's color profile to match what stderr
// would produce on its own, undoing the auto-downgrade triggered by wrapping
// stderr in a non-TTY writer (e.g. io.MultiWriter).
func applyColorProfile(l *Logger, stderr io.Writer) {
f, ok := stderr.(*os.File)
if !ok {
l.SetColorProfile(termenv.Ascii)
return
}
if isatty.IsTerminal(f.Fd()) {
l.SetColorProfile(termenv.ANSI)
return
}
l.SetColorProfile(termenv.Ascii)
}
// ApplyEnvOverrides re-reads DMS_LOG_LEVEL and DMS_LOG_FILE and reconfigures
// the singleton. Safe to call after CLI flags have rewritten the environment.
func ApplyEnvOverrides() {
GetLogger()
if level := os.Getenv("DMS_LOG_LEVEL"); level != "" {
SetLevel(level)
}
if path := os.Getenv("DMS_LOG_FILE"); path != "" {
if err := SetLogFile(path); err != nil {
Warnf("Failed to open log file %q: %v", path, err)
}
}
}
// * Convenience wrappers // * Convenience wrappers
func Debug(msg any, keyvals ...any) { GetLogger().Debug(msg, keyvals...) } func Debug(msg any, keyvals ...any) { GetLogger().Debug(msg, keyvals...) }

View File

@@ -5,9 +5,11 @@ import QtCore
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("CacheData")
readonly property int cacheConfigVersion: 1 readonly property int cacheConfigVersion: 1
@@ -131,7 +133,7 @@ Singleton {
} }
} }
} catch (e) { } catch (e) {
console.warn("CacheData: Failed to parse cache:", e.message); log.warn("Failed to parse cache:", e.message);
} finally { } finally {
_loading = false; _loading = false;
} }
@@ -149,7 +151,7 @@ Singleton {
} }
function migrateFromUndefinedToV1(cache) { function migrateFromUndefinedToV1(cache) {
console.info("CacheData: Migrating configuration from undefined to version 1"); log.info("Migrating configuration from undefined to version 1");
} }
function cleanupUnusedKeys() { function cleanupUnusedKeys() {
@@ -164,7 +166,7 @@ Singleton {
for (const key in cache) { for (const key in cache) {
if (!validKeys.includes(key)) { if (!validKeys.includes(key)) {
console.log("CacheData: Removing unused key:", key); log.debug("Removing unused key:", key);
delete cache[key]; delete cache[key];
needsSave = true; needsSave = true;
} }
@@ -174,7 +176,7 @@ Singleton {
cacheFile.setText(JSON.stringify(cache, null, 2)); cacheFile.setText(JSON.stringify(cache, null, 2));
} }
} catch (e) { } catch (e) {
console.warn("CacheData: Failed to cleanup unused keys:", e.message); log.warn("Failed to cleanup unused keys:", e.message);
} }
} }
@@ -184,7 +186,7 @@ Singleton {
if (content && content.trim()) if (content && content.trim())
return JSON.parse(content); return JSON.parse(content);
} catch (e) { } catch (e) {
console.warn("CacheData: Failed to parse launcher cache:", e.message); log.warn("Failed to parse launcher cache:", e.message);
} }
return null; return null;
} }
@@ -220,7 +222,7 @@ Singleton {
} }
onLoadFailed: error => { onLoadFailed: error => {
if (!isGreeterMode) { if (!isGreeterMode) {
console.info("CacheData: No cache file found, starting fresh"); log.info("No cache file found, starting fresh");
} }
} }
} }

View File

@@ -5,9 +5,11 @@ import QtQuick
import Qt.labs.folderlistmodel import Qt.labs.folderlistmodel
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("I18n")
property string _resolvedLocale: "en" property string _resolvedLocale: "en"
@@ -54,15 +56,15 @@ Singleton {
try { try {
root.translations = JSON.parse(text()); root.translations = JSON.parse(text());
root.translationsLoaded = true; root.translationsLoaded = true;
console.info(`I18n: Loaded translations for '${root._resolvedLocale}' (${Object.keys(root.translations).length} contexts)`); log.info(`I18n: Loaded translations for '${root._resolvedLocale}' (${Object.keys(root.translations).length} contexts)`);
} catch (e) { } catch (e) {
console.warn(`I18n: Error parsing '${root._resolvedLocale}':`, e, "- falling back to English"); log.warn(`I18n: Error parsing '${root._resolvedLocale}':`, e, "- falling back to English");
root._fallbackToEnglish(); root._fallbackToEnglish();
} }
} }
onLoadFailed: error => { onLoadFailed: error => {
console.warn(`I18n: Failed to load '${root._resolvedLocale}' (${error}), ` + "falling back to English"); log.warn(`I18n: Failed to load '${root._resolvedLocale}' (${error}), ` + "falling back to English");
root._fallbackToEnglish(); root._fallbackToEnglish();
} }
} }
@@ -105,14 +107,14 @@ Singleton {
_selectedPath = fileUrl; _selectedPath = fileUrl;
translationsLoaded = false; translationsLoaded = false;
translations = ({}); translations = ({});
console.info(`I18n: Using locale '${localeTag}' from ${fileUrl}`); log.info(`I18n: Using locale '${localeTag}' from ${fileUrl}`);
} }
function _fallbackToEnglish() { function _fallbackToEnglish() {
_selectedPath = ""; _selectedPath = "";
translationsLoaded = false; translationsLoaded = false;
translations = ({}); translations = ({});
console.warn("I18n: Falling back to built-in English strings"); log.warn("Falling back to built-in English strings");
} }
function tr(term, context) { function tr(term, context) {

View File

@@ -3,9 +3,11 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import Quickshell import Quickshell
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("Proc")
readonly property int noTimeout: -1 readonly property int noTimeout: -1
property int defaultDebounceMs: 50 property int defaultDebounceMs: 50
@@ -112,7 +114,7 @@ Singleton {
const safeExitCode = exitCodeValue !== null && exitCodeValue !== undefined ? exitCodeValue : -1; const safeExitCode = exitCodeValue !== null && exitCodeValue !== undefined ? exitCodeValue : -1;
entry.callback(safeOutput, safeExitCode); entry.callback(safeOutput, safeExitCode);
} catch (e) { } catch (e) {
console.warn("runCommand callback error for command:", entry.command, "Error:", e); log.warn("runCommand callback error for command:", entry.command, "Error:", e);
} }
} }
try { try {

View File

@@ -12,6 +12,7 @@ import "settings/SessionStore.js" as Store
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("SessionData")
readonly property int sessionConfigVersion: 3 readonly property int sessionConfigVersion: 3
@@ -257,7 +258,7 @@ Singleton {
} catch (e) { } catch (e) {
_parseError = true; _parseError = true;
const msg = e.message; const msg = e.message;
console.error("SessionData: Failed to parse session.json - file will not be overwritten."); log.error("Failed to parse session.json - file will not be overwritten.");
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse session.json"), msg)); Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse session.json"), msg));
} }
} }
@@ -337,7 +338,7 @@ Singleton {
} catch (e) { } catch (e) {
_parseError = true; _parseError = true;
const msg = e.message; const msg = e.message;
console.error("SessionData: Failed to parse session.json - file will not be overwritten."); log.error("Failed to parse session.json - file will not be overwritten.");
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse session.json"), msg)); Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse session.json"), msg));
} }
} }
@@ -552,7 +553,7 @@ Singleton {
} }
if (!screen) { if (!screen) {
console.warn("SessionData: Screen not found"); log.warn("Screen not found");
return; return;
} }
@@ -649,7 +650,7 @@ Singleton {
} }
if (!screen) { if (!screen) {
console.warn("SessionData: Screen not found"); log.warn("Screen not found");
return; return;
} }
@@ -680,7 +681,7 @@ Singleton {
} }
if (!screen) { if (!screen) {
console.warn("SessionData: Screen not found"); log.warn("Screen not found");
return; return;
} }
@@ -711,7 +712,7 @@ Singleton {
} }
if (!screen) { if (!screen) {
console.warn("SessionData: Screen not found"); log.warn("Screen not found");
return; return;
} }
@@ -742,7 +743,7 @@ Singleton {
} }
if (!screen) { if (!screen) {
console.warn("SessionData: Screen not found"); log.warn("Screen not found");
return; return;
} }

View File

@@ -13,6 +13,7 @@ import "settings/SettingsStore.js" as Store
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("SettingsData")
readonly property int settingsConfigVersion: 5 readonly property int settingsConfigVersion: 5
@@ -1294,7 +1295,7 @@ Singleton {
} catch (e) { } catch (e) {
_parseError = true; _parseError = true;
const msg = e.message; const msg = e.message;
console.error("SettingsData: Failed to parse settings.json - file will not be overwritten. Error:", msg); log.error("Failed to parse settings.json - file will not be overwritten. Error:", msg);
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse settings.json"), msg)); Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse settings.json"), msg));
applyStoredTheme(); applyStoredTheme();
} finally { } finally {
@@ -1315,12 +1316,12 @@ Singleton {
if (_isReadOnly) { if (_isReadOnly) {
_hasUnsavedChanges = _checkForUnsavedChanges(); _hasUnsavedChanges = _checkForUnsavedChanges();
if (!wasReadOnly) if (!wasReadOnly)
console.info("SettingsData: settings.json is now read-only"); log.info("settings.json is now read-only");
} else { } else {
_loadedSettingsSnapshot = JSON.stringify(Store.toJson(root)); _loadedSettingsSnapshot = JSON.stringify(Store.toJson(root));
_hasUnsavedChanges = false; _hasUnsavedChanges = false;
if (wasReadOnly) if (wasReadOnly)
console.info("SettingsData: settings.json is now writable"); log.info("settings.json is now writable");
if (_pendingMigration) if (_pendingMigration)
settingsFile.setText(JSON.stringify(_pendingMigration, null, 2)); settingsFile.setText(JSON.stringify(_pendingMigration, null, 2));
} }
@@ -1374,7 +1375,7 @@ Singleton {
} catch (e) { } catch (e) {
const msg = e.message || String(e); const msg = e.message || String(e);
if (!_isMissingPluginSettingsError(e)) if (!_isMissingPluginSettingsError(e))
console.warn("SettingsData: Failed to load plugin_settings.json. Error:", msg); log.warn("Failed to load plugin_settings.json. Error:", msg);
_resetPluginSettings(); _resetPluginSettings();
} }
} }
@@ -1391,7 +1392,7 @@ Singleton {
} catch (e) { } catch (e) {
_pluginParseError = true; _pluginParseError = true;
const msg = e.message; const msg = e.message;
console.error("SettingsData: Failed to parse plugin_settings.json - file will not be overwritten. Error:", msg); log.error("Failed to parse plugin_settings.json - file will not be overwritten. Error:", msg);
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse plugin_settings.json"), msg)); Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse plugin_settings.json"), msg));
pluginSettings = {}; pluginSettings = {};
} finally { } finally {
@@ -2794,7 +2795,7 @@ Singleton {
} catch (e) { } catch (e) {
_parseError = true; _parseError = true;
const msg = e.message; const msg = e.message;
console.error("SettingsData: Failed to reload settings.json - file will not be overwritten. Error:", msg); log.error("Failed to reload settings.json - file will not be overwritten. Error:", msg);
Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse settings.json"), msg)); Qt.callLater(() => ToastService.showError(I18n.tr("Failed to parse settings.json"), msg));
} finally { } finally {
_loading = false; _loading = false;
@@ -2829,7 +2830,7 @@ Singleton {
if (!isGreeterMode) { if (!isGreeterMode) {
const msg = String(error || ""); const msg = String(error || "");
if (!_isMissingPluginSettingsError(error)) if (!_isMissingPluginSettingsError(error))
console.warn("SettingsData: Failed to load plugin_settings.json. Error:", msg); log.warn("Failed to load plugin_settings.json. Error:", msg);
_resetPluginSettings(); _resetPluginSettings();
} }
} }

View File

@@ -12,6 +12,7 @@ import "StockThemes.js" as StockThemes
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("Theme")
readonly property string stateDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericCacheLocation).toString()) + "/DankMaterialShell" readonly property string stateDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.GenericCacheLocation).toString()) + "/DankMaterialShell"
readonly property bool envDisableMatugen: Quickshell.env("DMS_DISABLE_MATUGEN") === "1" || Quickshell.env("DMS_DISABLE_MATUGEN") === "true" readonly property bool envDisableMatugen: Quickshell.env("DMS_DISABLE_MATUGEN") === "1" || Quickshell.env("DMS_DISABLE_MATUGEN") === "true"
@@ -148,7 +149,7 @@ Singleton {
} }
if (colorsFileLoadFailed && currentTheme === dynamic && rawWallpaperPath) { if (colorsFileLoadFailed && currentTheme === dynamic && rawWallpaperPath) {
console.info("Theme: Matugen now available, regenerating colors for dynamic theme"); log.info("Matugen now available, regenerating colors for dynamic theme");
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode); const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode);
const iconTheme = (typeof SettingsData !== "undefined" && SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default"; const iconTheme = (typeof SettingsData !== "undefined" && SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default";
const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot"; const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot";
@@ -376,7 +377,7 @@ Singleton {
"use": true "use": true
}, response => { }, response => {
if (!response.error) { if (!response.error) {
console.info("Theme automation: IP location enabled after connection"); log.info("Theme automation: IP location enabled after connection");
} }
}); });
} else if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) { } else if (SessionData.latitude !== 0.0 && SessionData.longitude !== 0.0) {
@@ -389,13 +390,13 @@ Singleton {
"longitude": SessionData.longitude "longitude": SessionData.longitude
}, locationResponse => { }, locationResponse => {
if (locationResponse?.error) { if (locationResponse?.error) {
console.warn("Theme automation: Failed to set location", locationResponse.error); log.warn("Theme automation: Failed to set location", locationResponse.error);
} }
}); });
} }
}); });
} else { } else {
console.warn("Theme automation: No location configured"); log.warn("Theme automation: No location configured");
} }
} }
} }
@@ -1525,12 +1526,12 @@ Singleton {
function setDesiredTheme(kind, value, isLight, iconTheme, matugenType, stockColors) { function setDesiredTheme(kind, value, isLight, iconTheme, matugenType, stockColors) {
if (!matugenAvailable) { if (!matugenAvailable) {
console.warn("Theme: matugen not available or disabled - cannot set system theme"); log.warn("matugen not available or disabled - cannot set system theme");
return; return;
} }
if (workerRunning) { if (workerRunning) {
console.info("Theme: Worker already running, queueing request"); log.info("Worker already running, queueing request");
pendingThemeRequest = { pendingThemeRequest = {
kind, kind,
value, value,
@@ -1542,7 +1543,7 @@ Singleton {
return; return;
} }
console.info("Theme: Setting desired theme -", kind, "mode:", isLight ? "light" : "dark", stockColors ? "(stock colors)" : "(dynamic)"); log.info("Setting desired theme -", kind, "mode:", isLight ? "light" : "dark", stockColors ? "(stock colors)" : "(dynamic)");
if (typeof NiriService !== "undefined" && CompositorService.isNiri) { if (typeof NiriService !== "undefined" && CompositorService.isNiri) {
NiriService.suppressNextToast(); NiriService.suppressNextToast();
@@ -1557,7 +1558,7 @@ Singleton {
"runUserTemplates": (typeof SettingsData !== "undefined") ? SettingsData.runUserMatugenTemplates : true "runUserTemplates": (typeof SettingsData !== "undefined") ? SettingsData.runUserMatugenTemplates : true
}; };
console.log("Theme: Starting matugen worker"); log.debug("Starting matugen worker");
workerRunning = true; workerRunning = true;
const args = ["dms", "matugen", "queue", "--state-dir", stateDir, "--shell-dir", shellDir, "--config-dir", configDir, "--kind", desired.kind, "--value", desired.value, "--mode", desired.mode, "--icon-theme", desired.iconTheme, "--matugen-type", desired.matugenType,]; const args = ["dms", "matugen", "queue", "--state-dir", stateDir, "--shell-dir", shellDir, "--config-dir", configDir, "--kind", desired.kind, "--value", desired.value, "--mode", desired.mode, "--icon-theme", desired.iconTheme, "--matugen-type", desired.matugenType,];
@@ -1715,7 +1716,7 @@ Singleton {
} }
if (!darkTheme || !darkTheme.primary) { if (!darkTheme || !darkTheme.primary) {
console.warn("Theme data not available for:", currentTheme); log.warn("Theme data not available for:", currentTheme);
return; return;
} }
@@ -1953,10 +1954,10 @@ Singleton {
id: systemThemeGenerator id: systemThemeGenerator
running: false running: false
stdout: SplitParser { stdout: SplitParser {
onRead: data => console.info("Theme worker:", data) onRead: data => log.info("Theme worker:", data)
} }
stderr: SplitParser { stderr: SplitParser {
onRead: data => console.warn("Theme worker:", data) onRead: data => log.warn("Theme worker:", data)
} }
onExited: exitCode => { onExited: exitCode => {
@@ -1965,18 +1966,18 @@ Singleton {
switch (exitCode) { switch (exitCode) {
case 0: case 0:
console.info("Theme: Matugen worker completed successfully"); log.info("Matugen worker completed successfully");
root.matugenCompleted(currentMode, "success"); root.matugenCompleted(currentMode, "success");
break; break;
case 2: case 2:
console.log("Theme: Matugen worker completed with code 2 (no changes needed)"); log.debug("Matugen worker completed with code 2 (no changes needed)");
root.matugenCompleted(currentMode, "no-changes"); root.matugenCompleted(currentMode, "no-changes");
break; break;
default: default:
if (typeof ToastService !== "undefined") { if (typeof ToastService !== "undefined") {
ToastService.showError("Theme worker failed (" + exitCode + ")"); ToastService.showError("Theme worker failed (" + exitCode + ")");
} }
console.warn("Theme: Matugen worker failed with exit code:", exitCode); log.warn("Matugen worker failed with exit code:", exitCode);
root.matugenCompleted(currentMode, "error"); root.matugenCompleted(currentMode, "error");
} }
@@ -1985,7 +1986,7 @@ Singleton {
const req = pendingThemeRequest; const req = pendingThemeRequest;
pendingThemeRequest = null; pendingThemeRequest = null;
console.info("Theme: Processing queued theme request"); log.info("Processing queued theme request");
setDesiredTheme(req.kind, req.value, req.isLight, req.iconTheme, req.matugenType, req.stockColors); setDesiredTheme(req.kind, req.value, req.isLight, req.iconTheme, req.matugenType, req.stockColors);
} }
} }
@@ -2039,7 +2040,7 @@ Singleton {
} }
} }
} catch (e) { } catch (e) {
console.error("Theme: Failed to parse dynamic colors:", e); log.error("Failed to parse dynamic colors:", e);
if (typeof ToastService !== "undefined") { if (typeof ToastService !== "undefined") {
ToastService.wallpaperErrorStatus = "error"; ToastService.wallpaperErrorStatus = "error";
ToastService.showError("Dynamic colors parse error: " + e.message); ToastService.showError("Dynamic colors parse error: " + e.message);
@@ -2059,11 +2060,11 @@ Singleton {
onLoadFailed: function (error) { onLoadFailed: function (error) {
if (currentTheme === dynamic) { if (currentTheme === dynamic) {
console.warn("Theme: Dynamic colors file load failed, marking for regeneration"); log.warn("Dynamic colors file load failed, marking for regeneration");
colorsFileLoadFailed = true; colorsFileLoadFailed = true;
const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode); const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode);
if (!isGreeterMode && matugenAvailable && rawWallpaperPath) { if (!isGreeterMode && matugenAvailable && rawWallpaperPath) {
console.log("Theme: Matugen available, triggering immediate regeneration"); log.debug("Matugen available, triggering immediate regeneration");
generateSystemThemesFromCurrentTheme(); generateSystemThemesFromCurrentTheme();
} }
} }
@@ -2187,7 +2188,7 @@ Singleton {
"endMinute": endMinute "endMinute": endMinute
}, response => { }, response => {
if (response && response.error) { if (response && response.error) {
console.error("Theme automation: Failed to sync time schedule:", response.error); log.error("Theme automation: Failed to sync time schedule:", response.error);
} }
}); });
@@ -2280,9 +2281,9 @@ Singleton {
if (root.themeModeAutomationActive) { if (root.themeModeAutomationActive) {
if (SessionData.nightModeUseIPLocation) { if (SessionData.nightModeUseIPLocation) {
console.warn("Theme automation: Waiting for IP location from backend"); log.warn("Theme automation: Waiting for IP location from backend");
} else { } else {
console.warn("Theme automation: Location mode requires coordinates"); log.warn("Theme automation: Location mode requires coordinates");
} }
} }
} }
@@ -2364,7 +2365,7 @@ Singleton {
"use": true "use": true
}, response => { }, response => {
if (response?.error) { if (response?.error) {
console.warn("Theme automation: Failed to enable IP location", response.error); log.warn("Theme automation: Failed to enable IP location", response.error);
} }
}); });
return true; return true;
@@ -2378,7 +2379,7 @@ Singleton {
"longitude": SessionData.longitude "longitude": SessionData.longitude
}, locResp => { }, locResp => {
if (locResp?.error) { if (locResp?.error) {
console.warn("Theme automation: Failed to set location", locResp.error); log.warn("Theme automation: Failed to set location", locResp.error);
} }
}); });
} }

View File

@@ -27,6 +27,7 @@ import qs.Services
Item { Item {
id: root id: root
readonly property var log: Log.scoped("DMSShell")
property bool osdSurfacesLoaded: true property bool osdSurfacesLoaded: true
property int pendingOsdResumeReloads: 0 property int pendingOsdResumeReloads: 0
@@ -54,7 +55,7 @@ Item {
item.popoutService = PopoutService; item.popoutService = PopoutService;
} }
item.pluginId = pluginId; item.pluginId = pluginId;
console.info("Daemon plugin loaded:", pluginId); log.info("Daemon plugin loaded:", pluginId);
} }
} }
} }
@@ -93,7 +94,7 @@ Item {
} }
onFadeCancelled: { onFadeCancelled: {
console.log("Fade to lock cancelled by user on screen:", fadeWindowLoader.modelData.name); log.debug("Fade to lock cancelled by user on screen:", fadeWindowLoader.modelData.name);
} }
} }
@@ -133,7 +134,7 @@ Item {
} }
onFadeCancelled: { onFadeCancelled: {
console.log("Fade to DPMS cancelled by user on screen:", fadeDpmsWindowLoader.modelData.name); log.debug("Fade to DPMS cancelled by user on screen:", fadeDpmsWindowLoader.modelData.name);
} }
} }
@@ -773,7 +774,7 @@ Item {
cmd += " " + escapedPath; cmd += " " + escapedPath;
} }
console.log("FilePicker: Launching", cmd); log.debug("FilePicker: Launching", cmd);
Quickshell.execDetached({ Quickshell.execDetached({
command: ["sh", "-c", cmd] command: ["sh", "-c", cmd]
@@ -805,10 +806,10 @@ Item {
} }
function onAppPickerRequested(data) { function onAppPickerRequested(data) {
console.log("DMSShell: App picker requested with data:", JSON.stringify(data)); log.debug("App picker requested with data:", JSON.stringify(data));
if (!data || !data.target) { if (!data || !data.target) {
console.warn("DMSShell: Invalid app picker request data"); log.warn("Invalid app picker request data");
return; return;
} }

View File

@@ -9,6 +9,7 @@ import qs.Modules.Settings.DisplayConfig
Item { Item {
id: root id: root
readonly property var log: Log.scoped("DMSShellIPC")
required property var powerMenuModalLoader required property var powerMenuModalLoader
required property var processListModalLoader required property var processListModalLoader
@@ -861,7 +862,7 @@ Item {
function set(key: string, value: string): string { function set(key: string, value: string): string {
if (!(key in SettingsData)) { if (!(key in SettingsData)) {
console.warn("Cannot set property, not found:", key); log.warn("Cannot set property, not found:", key);
return "SETTINGS_INVALID_KEY"; return "SETTINGS_INVALID_KEY";
} }
@@ -894,12 +895,12 @@ Item {
throw "Unsupported type"; throw "Unsupported type";
} }
console.warn("Setting:", key, value); log.warn("Setting:", key, value);
SettingsData[key] = value; SettingsData[key] = value;
SettingsData.saveSettings(); SettingsData.saveSettings();
return "SETTINGS_SET_SUCCESS"; return "SETTINGS_SET_SUCCESS";
} catch (e) { } catch (e) {
console.warn("Failed to set property:", key, "error:", e); log.warn("Failed to set property:", key, "error:", e);
return "SETTINGS_SET_FAILURE"; return "SETTINGS_SET_FAILURE";
} }
} }

View File

@@ -1,5 +1,4 @@
import QtQuick import QtQuick
import Quickshell
import qs.Common import qs.Common
import qs.Modals.Common import qs.Modals.Common
import qs.Widgets import qs.Widgets
@@ -7,6 +6,7 @@ import qs.Services
DankModal { DankModal {
id: root id: root
readonly property var log: Log.scoped("AppPickerModal")
property string title: I18n.tr("Select Application") property string title: I18n.tr("Select Application")
property string targetData: "" property string targetData: ""
@@ -30,52 +30,52 @@ DankModal {
onBackgroundClicked: close() onBackgroundClicked: close()
onDialogClosed: { onDialogClosed: {
searchQuery = "" searchQuery = "";
selectedIndex = 0 selectedIndex = 0;
keyboardNavigationActive = false keyboardNavigationActive = false;
} }
onOpened: { onOpened: {
searchQuery = "" searchQuery = "";
updateApplicationList() updateApplicationList();
selectedIndex = 0 selectedIndex = 0;
Qt.callLater(() => { Qt.callLater(() => {
if (contentLoader.item && contentLoader.item.searchField) { if (contentLoader.item && contentLoader.item.searchField) {
contentLoader.item.searchField.text = "" contentLoader.item.searchField.text = "";
contentLoader.item.searchField.forceActiveFocus() contentLoader.item.searchField.forceActiveFocus();
} }
}) });
} }
function updateApplicationList() { function updateApplicationList() {
applicationsModel.clear() applicationsModel.clear();
const apps = AppSearchService.applications const apps = AppSearchService.applications;
const usageHistory = usageHistoryKey && SettingsData[usageHistoryKey] ? SettingsData[usageHistoryKey] : {} const usageHistory = usageHistoryKey && SettingsData[usageHistoryKey] ? SettingsData[usageHistoryKey] : {};
let filteredApps = [] let filteredApps = [];
for (const app of apps) { for (const app of apps) {
if (!app || !app.categories) continue if (!app || !app.categories)
continue;
let matchesCategory = categoryFilter.length === 0 let matchesCategory = categoryFilter.length === 0;
if (categoryFilter.length > 0) { if (categoryFilter.length > 0) {
try { try {
for (const cat of app.categories) { for (const cat of app.categories) {
if (categoryFilter.includes(cat)) { if (categoryFilter.includes(cat)) {
matchesCategory = true matchesCategory = true;
break break;
} }
} }
} catch (e) { } catch (e) {
console.warn("AppPicker: Error iterating categories for", app.name, ":", e) log.warn("AppPicker: Error iterating categories for", app.name, ":", e);
continue continue;
} }
} }
if (matchesCategory) { if (matchesCategory) {
const name = app.name || "" const name = app.name || "";
const lowerName = name.toLowerCase() const lowerName = name.toLowerCase();
const lowerQuery = searchQuery.toLowerCase() const lowerQuery = searchQuery.toLowerCase();
if (searchQuery === "" || lowerName.includes(lowerQuery)) { if (searchQuery === "" || lowerName.includes(lowerQuery)) {
filteredApps.push({ filteredApps.push({
@@ -84,21 +84,21 @@ DankModal {
exec: app.exec || app.execString || "", exec: app.exec || app.execString || "",
startupClass: app.startupWMClass || "", startupClass: app.startupWMClass || "",
appData: app appData: app
}) });
} }
} }
} }
filteredApps.sort((a, b) => { filteredApps.sort((a, b) => {
const aId = a.appData.id || a.appData.execString || a.appData.exec || "" const aId = a.appData.id || a.appData.execString || a.appData.exec || "";
const bId = b.appData.id || b.appData.execString || b.appData.exec || "" const bId = b.appData.id || b.appData.execString || b.appData.exec || "";
const aUsage = usageHistory[aId] ? usageHistory[aId].count : 0 const aUsage = usageHistory[aId] ? usageHistory[aId].count : 0;
const bUsage = usageHistory[bId] ? usageHistory[bId].count : 0 const bUsage = usageHistory[bId] ? usageHistory[bId].count : 0;
if (aUsage !== bUsage) { if (aUsage !== bUsage) {
return bUsage - aUsage return bUsage - aUsage;
} }
return (a.name || "").localeCompare(b.name || "") return (a.name || "").localeCompare(b.name || "");
}) });
filteredApps.forEach(app => { filteredApps.forEach(app => {
applicationsModel.append({ applicationsModel.append({
@@ -107,10 +107,10 @@ DankModal {
exec: app.exec, exec: app.exec,
startupClass: app.startupClass, startupClass: app.startupClass,
appId: app.appData.id || app.appData.execString || app.appData.exec || "" appId: app.appData.id || app.appData.execString || app.appData.exec || ""
}) });
}) });
console.log("AppPicker: Found " + filteredApps.length + " applications") log.debug("AppPicker: Found " + filteredApps.length + " applications");
} }
onSearchQueryChanged: updateApplicationList() onSearchQueryChanged: updateApplicationList()
@@ -129,56 +129,57 @@ DankModal {
focus: true focus: true
Keys.onEscapePressed: event => { Keys.onEscapePressed: event => {
root.close() root.close();
event.accepted = true event.accepted = true;
} }
Keys.onPressed: event => { Keys.onPressed: event => {
if (applicationsModel.count === 0) return if (applicationsModel.count === 0)
return;
// Toggle view mode with Tab key // Toggle view mode with Tab key
if (event.key === Qt.Key_Tab) { if (event.key === Qt.Key_Tab) {
root.viewMode = root.viewMode === "grid" ? "list" : "grid" root.viewMode = root.viewMode === "grid" ? "list" : "grid";
event.accepted = true event.accepted = true;
return return;
} }
if (root.viewMode === "grid") { if (root.viewMode === "grid") {
if (event.key === Qt.Key_Left) { if (event.key === Qt.Key_Left) {
root.keyboardNavigationActive = true root.keyboardNavigationActive = true;
root.selectedIndex = Math.max(0, root.selectedIndex - 1) root.selectedIndex = Math.max(0, root.selectedIndex - 1);
event.accepted = true event.accepted = true;
} else if (event.key === Qt.Key_Right) { } else if (event.key === Qt.Key_Right) {
root.keyboardNavigationActive = true root.keyboardNavigationActive = true;
root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + 1) root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + 1);
event.accepted = true event.accepted = true;
} else if (event.key === Qt.Key_Up) { } else if (event.key === Qt.Key_Up) {
root.keyboardNavigationActive = true root.keyboardNavigationActive = true;
root.selectedIndex = Math.max(0, root.selectedIndex - root.gridColumns) root.selectedIndex = Math.max(0, root.selectedIndex - root.gridColumns);
event.accepted = true event.accepted = true;
} else if (event.key === Qt.Key_Down) { } else if (event.key === Qt.Key_Down) {
root.keyboardNavigationActive = true root.keyboardNavigationActive = true;
root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + root.gridColumns) root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + root.gridColumns);
event.accepted = true event.accepted = true;
} }
} else { } else {
if (event.key === Qt.Key_Up) { if (event.key === Qt.Key_Up) {
root.keyboardNavigationActive = true root.keyboardNavigationActive = true;
root.selectedIndex = Math.max(0, root.selectedIndex - 1) root.selectedIndex = Math.max(0, root.selectedIndex - 1);
event.accepted = true event.accepted = true;
} else if (event.key === Qt.Key_Down) { } else if (event.key === Qt.Key_Down) {
root.keyboardNavigationActive = true root.keyboardNavigationActive = true;
root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + 1) root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + 1);
event.accepted = true event.accepted = true;
} }
} }
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
if (root.selectedIndex >= 0 && root.selectedIndex < applicationsModel.count) { if (root.selectedIndex >= 0 && root.selectedIndex < applicationsModel.count) {
const app = applicationsModel.get(root.selectedIndex) const app = applicationsModel.get(root.selectedIndex);
launchApplication(app) launchApplication(app);
} }
event.accepted = true event.accepted = true;
} }
} }
@@ -217,7 +218,7 @@ DankModal {
iconColor: root.viewMode === "list" ? Theme.primary : Theme.surfaceText iconColor: root.viewMode === "list" ? Theme.primary : Theme.surfaceText
backgroundColor: root.viewMode === "list" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" backgroundColor: root.viewMode === "list" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
onClicked: { onClicked: {
root.viewMode = "list" root.viewMode = "list";
} }
} }
@@ -229,7 +230,7 @@ DankModal {
iconColor: root.viewMode === "grid" ? Theme.primary : Theme.surfaceText iconColor: root.viewMode === "grid" ? Theme.primary : Theme.surfaceText
backgroundColor: root.viewMode === "grid" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent" backgroundColor: root.viewMode === "grid" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
onClicked: { onClicked: {
root.viewMode = "grid" root.viewMode = "grid";
} }
} }
} }
@@ -257,42 +258,42 @@ DankModal {
keyForwardTargets: [appContent] keyForwardTargets: [appContent]
onTextEdited: { onTextEdited: {
root.searchQuery = text root.searchQuery = text;
} }
Keys.onPressed: function (event) { Keys.onPressed: function (event) {
if (event.key === Qt.Key_Escape) { if (event.key === Qt.Key_Escape) {
root.close() root.close();
event.accepted = true event.accepted = true;
return return;
} }
const isEnterKey = [Qt.Key_Return, Qt.Key_Enter].includes(event.key) const isEnterKey = [Qt.Key_Return, Qt.Key_Enter].includes(event.key);
const hasText = text.length > 0 const hasText = text.length > 0;
if (isEnterKey && hasText) { if (isEnterKey && hasText) {
if (root.keyboardNavigationActive && applicationsModel.count > 0) { if (root.keyboardNavigationActive && applicationsModel.count > 0) {
const app = applicationsModel.get(root.selectedIndex) const app = applicationsModel.get(root.selectedIndex);
launchApplication(app) launchApplication(app);
} else if (applicationsModel.count > 0) { } else if (applicationsModel.count > 0) {
const app = applicationsModel.get(0) const app = applicationsModel.get(0);
launchApplication(app) launchApplication(app);
} }
event.accepted = true event.accepted = true;
return return;
} }
const navigationKeys = [Qt.Key_Down, Qt.Key_Up, Qt.Key_Left, Qt.Key_Right, Qt.Key_Tab, Qt.Key_Backtab] const navigationKeys = [Qt.Key_Down, Qt.Key_Up, Qt.Key_Left, Qt.Key_Right, Qt.Key_Tab, Qt.Key_Backtab];
const isNavigationKey = navigationKeys.includes(event.key) const isNavigationKey = navigationKeys.includes(event.key);
const isEmptyEnter = isEnterKey && !hasText const isEmptyEnter = isEnterKey && !hasText;
event.accepted = !(isNavigationKey || isEmptyEnter) event.accepted = !(isNavigationKey || isEmptyEnter);
} }
Connections { Connections {
function onShouldBeVisibleChanged() { function onShouldBeVisibleChanged() {
if (!root.shouldBeVisible) { if (!root.shouldBeVisible) {
searchField.focus = false searchField.focus = false;
} }
} }
@@ -303,12 +304,12 @@ DankModal {
Rectangle { Rectangle {
width: parent.width width: parent.width
height: { height: {
let usedHeight = 40 + Theme.spacingS let usedHeight = 40 + Theme.spacingS;
usedHeight += 52 + Theme.spacingS usedHeight += 52 + Theme.spacingS;
if (root.showTargetData) { if (root.showTargetData) {
usedHeight += 36 + Theme.spacingS usedHeight += 36 + Theme.spacingS;
} }
return parent.height - usedHeight return parent.height - usedHeight;
} }
radius: Theme.cornerRadius radius: Theme.cornerRadius
color: "transparent" color: "transparent"
@@ -320,14 +321,14 @@ DankModal {
property int itemSpacing: Theme.spacingS property int itemSpacing: Theme.spacingS
function ensureVisible(index) { function ensureVisible(index) {
if (index < 0 || index >= count) return if (index < 0 || index >= count)
return;
const itemY = index * (itemHeight + itemSpacing) const itemY = index * (itemHeight + itemSpacing);
const itemBottom = itemY + itemHeight const itemBottom = itemY + itemHeight;
if (itemY < contentY) { if (itemY < contentY) {
contentY = itemY contentY = itemY;
} else if (itemBottom > contentY + height) { } else if (itemBottom > contentY + height) {
contentY = itemBottom - height contentY = itemBottom - height;
} }
} }
@@ -343,9 +344,9 @@ DankModal {
spacing: itemSpacing spacing: itemSpacing
onCurrentIndexChanged: { onCurrentIndexChanged: {
root.selectedIndex = currentIndex root.selectedIndex = currentIndex;
if (root.keyboardNavigationActive) { if (root.keyboardNavigationActive) {
ensureVisible(currentIndex) ensureVisible(currentIndex);
} }
} }
@@ -360,11 +361,11 @@ DankModal {
hoverUpdatesSelection: true hoverUpdatesSelection: true
onItemClicked: (idx, modelData) => { onItemClicked: (idx, modelData) => {
launchApplication(modelData) launchApplication(modelData);
} }
onKeyboardNavigationReset: { onKeyboardNavigationReset: {
root.keyboardNavigationActive = false root.keyboardNavigationActive = false;
} }
} }
} }
@@ -373,14 +374,14 @@ DankModal {
id: appGrid id: appGrid
function ensureVisible(index) { function ensureVisible(index) {
if (index < 0 || index >= count) return if (index < 0 || index >= count)
return;
const itemY = Math.floor(index / root.gridColumns) * cellHeight const itemY = Math.floor(index / root.gridColumns) * cellHeight;
const itemBottom = itemY + cellHeight const itemBottom = itemY + cellHeight;
if (itemY < contentY) { if (itemY < contentY) {
contentY = itemY contentY = itemY;
} else if (itemBottom > contentY + height) { } else if (itemBottom > contentY + height) {
contentY = itemBottom - height contentY = itemBottom - height;
} }
} }
@@ -397,9 +398,9 @@ DankModal {
currentIndex: root.selectedIndex currentIndex: root.selectedIndex
onCurrentIndexChanged: { onCurrentIndexChanged: {
root.selectedIndex = currentIndex root.selectedIndex = currentIndex;
if (root.keyboardNavigationActive) { if (root.keyboardNavigationActive) {
ensureVisible(currentIndex) ensureVisible(currentIndex);
} }
} }
@@ -413,11 +414,11 @@ DankModal {
hoverUpdatesSelection: true hoverUpdatesSelection: true
onItemClicked: (idx, modelData) => { onItemClicked: (idx, modelData) => {
launchApplication(modelData) launchApplication(modelData);
} }
onKeyboardNavigationReset: { onKeyboardNavigationReset: {
root.keyboardNavigationActive = false root.keyboardNavigationActive = false;
} }
} }
} }
@@ -449,22 +450,22 @@ DankModal {
} }
function launchApplication(app) { function launchApplication(app) {
if (!app) return if (!app)
return;
root.applicationSelected(app, root.targetData) root.applicationSelected(app, root.targetData);
if (usageHistoryKey && app.appId) { if (usageHistoryKey && app.appId) {
const usageHistory = SettingsData[usageHistoryKey] || {} const usageHistory = SettingsData[usageHistoryKey] || {};
const currentCount = usageHistory[app.appId] ? usageHistory[app.appId].count : 0 const currentCount = usageHistory[app.appId] ? usageHistory[app.appId].count : 0;
usageHistory[app.appId] = { usageHistory[app.appId] = {
count: currentCount + 1, count: currentCount + 1,
lastUsed: Date.now(), lastUsed: Date.now(),
name: app.name name: app.name
} };
SettingsData.set(usageHistoryKey, usageHistory) SettingsData.set(usageHistoryKey, usageHistory);
} }
root.close() root.close();
} }
} }
} }

View File

@@ -7,6 +7,7 @@ import qs.Widgets
DankModal { DankModal {
id: root id: root
readonly property var log: Log.scoped("BluetoothPairingModal")
layerNamespace: "dms:bluetooth-pairing" layerNamespace: "dms:bluetooth-pairing"
@@ -24,7 +25,7 @@ DankModal {
property string passkeyInput: "" property string passkeyInput: ""
function show(pairingData) { function show(pairingData) {
console.log("BluetoothPairingModal.show() called:", JSON.stringify(pairingData)); log.debug("BluetoothPairingModal.show() called:", JSON.stringify(pairingData));
token = pairingData.token || ""; token = pairingData.token || "";
deviceName = pairingData.deviceName || ""; deviceName = pairingData.deviceName || "";
deviceAddress = pairingData.deviceAddr || ""; deviceAddress = pairingData.deviceAddr || "";
@@ -33,7 +34,7 @@ DankModal {
pinInput = ""; pinInput = "";
passkeyInput = ""; passkeyInput = "";
console.log("BluetoothPairingModal: Calling open()"); log.debug("Calling open()");
open(); open();
Qt.callLater(() => { Qt.callLater(() => {
if (contentLoader.item) { if (contentLoader.item) {

View File

@@ -2,9 +2,11 @@ import QtQuick
import Quickshell import Quickshell
import qs.Common import qs.Common
import qs.Modals import qs.Modals
import qs.Services
AppPickerModal { AppPickerModal {
id: root id: root
readonly property var log: Log.scoped("BrowserPickerModal")
property string url: "" property string url: ""
@@ -17,35 +19,44 @@ AppPickerModal {
showTargetData: true showTargetData: true
function shellEscape(str) { function shellEscape(str) {
return "'" + str.replace(/'/g, "'\\''") + "'" return "'" + str.replace(/'/g, "'\\''") + "'";
} }
onApplicationSelected: (app, url) => { onApplicationSelected: (app, url) => {
if (!app) return if (!app)
return;
let cmd = app.exec || "";
const escapedUrl = shellEscape(url);
let cmd = app.exec || "" let hasField = false;
const escapedUrl = shellEscape(url) if (cmd.includes("%u")) {
cmd = cmd.replace("%u", escapedUrl);
let hasField = false hasField = true;
if (cmd.includes("%u")) { cmd = cmd.replace("%u", escapedUrl); hasField = true } } else if (cmd.includes("%U")) {
else if (cmd.includes("%U")) { cmd = cmd.replace("%U", escapedUrl); hasField = true } cmd = cmd.replace("%U", escapedUrl);
else if (cmd.includes("%f")) { cmd = cmd.replace("%f", escapedUrl); hasField = true } hasField = true;
else if (cmd.includes("%F")) { cmd = cmd.replace("%F", escapedUrl); hasField = true } } else if (cmd.includes("%f")) {
cmd = cmd.replace("%f", escapedUrl);
cmd = cmd.replace(/%[ikc]/g, "") hasField = true;
} else if (cmd.includes("%F")) {
if (!hasField) { cmd = cmd.replace("%F", escapedUrl);
cmd += " " + escapedUrl hasField = true;
} }
console.log("BrowserPicker: Launching", cmd) cmd = cmd.replace(/%[ikc]/g, "");
if (!hasField) {
cmd += " " + escapedUrl;
}
log.debug("BrowserPicker: Launching", cmd);
Quickshell.execDetached({ Quickshell.execDetached({
command: ["sh", "-c", cmd] command: ["sh", "-c", cmd]
}) });
} }
onViewModeChanged: { onViewModeChanged: {
SettingsData.set("browserPickerViewMode", viewMode) SettingsData.set("browserPickerViewMode", viewMode);
} }
} }

View File

@@ -6,6 +6,7 @@ import qs.Widgets
Item { Item {
id: thumbnail id: thumbnail
readonly property var log: Log.scoped("ClipboardThumbnail")
required property var entry required property var entry
required property string entryType required property string entryType
@@ -52,7 +53,7 @@ Item {
modal.activeImageLoads--; modal.activeImageLoads--;
} }
if (response.error) { if (response.error) {
console.warn("ClipboardThumbnail: Failed to load image:", entry.id); log.warn("Failed to load image:", entry.id);
return; return;
} }
const data = response.result?.data; const data = response.result?.data;

View File

@@ -7,6 +7,7 @@ import qs.Widgets
Item { Item {
id: root id: root
readonly property var log: Log.scoped("DankModal")
property string layerNamespace: "dms:modal" property string layerNamespace: "dms:modal"
property alias content: contentLoader.sourceComponent property alias content: contentLoader.sourceComponent
@@ -246,10 +247,10 @@ Item {
return WlrLayershell.Overlay; return WlrLayershell.Overlay;
switch (Quickshell.env("DMS_MODAL_LAYER")) { switch (Quickshell.env("DMS_MODAL_LAYER")) {
case "bottom": case "bottom":
console.error("DankModal: 'bottom' layer is not valid for modals. Defaulting to 'top' layer."); log.error("'bottom' layer is not valid for modals. Defaulting to 'top' layer.");
return WlrLayershell.Top; return WlrLayershell.Top;
case "background": case "background":
console.error("DankModal: 'background' layer is not valid for modals. Defaulting to 'top' layer."); log.error("'background' layer is not valid for modals. Defaulting to 'top' layer.");
return WlrLayershell.Top; return WlrLayershell.Top;
case "overlay": case "overlay":
return WlrLayershell.Overlay; return WlrLayershell.Overlay;

View File

@@ -9,6 +9,7 @@ import qs.Widgets
DankModal { DankModal {
id: root id: root
readonly property var log: Log.scoped("DankColorPickerModal")
layerNamespace: "dms:color-picker" layerNamespace: "dms:color-picker"
@@ -111,7 +112,7 @@ DankModal {
hideInstant(); hideInstant();
Proc.runCommand("dms-color-pick", ["dms", "color", "pick", "--json"], (output, exitCode) => { Proc.runCommand("dms-color-pick", ["dms", "color", "pick", "--json"], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("dms color pick exited with code:", exitCode); log.warn("dms color pick exited with code:", exitCode);
root.show(); root.show();
return; return;
} }
@@ -120,11 +121,11 @@ DankModal {
if (result.hex) { if (result.hex) {
applyPickedColor(result.hex); applyPickedColor(result.hex);
} else { } else {
console.warn("Failed to parse dms color pick output: missing hex"); log.warn("Failed to parse dms color pick output: missing hex");
root.show(); root.show();
} }
} catch (e) { } catch (e) {
console.warn("Failed to parse dms color pick JSON:", e); log.warn("Failed to parse dms color pick JSON:", e);
root.show(); root.show();
} }
}, 0, Proc.noTimeout); }, 0, Proc.noTimeout);

View File

@@ -8,6 +8,7 @@ import qs.Widgets
Item { Item {
id: root id: root
readonly property var log: Log.scoped("DankLauncherV2Modal")
visible: false visible: false
@@ -323,10 +324,10 @@ Item {
WlrLayershell.layer: { WlrLayershell.layer: {
switch (Quickshell.env("DMS_MODAL_LAYER")) { switch (Quickshell.env("DMS_MODAL_LAYER")) {
case "bottom": case "bottom":
console.error("DankModal: 'bottom' layer is not valid for modals. Defaulting to 'top' layer."); log.error("DankModal: 'bottom' layer is not valid for modals. Defaulting to 'top' layer.");
return WlrLayershell.Top; return WlrLayershell.Top;
case "background": case "background":
console.error("DankModal: 'background' layer is not valid for modals. Defaulting to 'top' layer."); log.error("DankModal: 'background' layer is not valid for modals. Defaulting to 'top' layer.");
return WlrLayershell.Top; return WlrLayershell.Top;
case "overlay": case "overlay":
return WlrLayershell.Overlay; return WlrLayershell.Overlay;

View File

@@ -1,10 +1,12 @@
import QtQuick import QtQuick
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
import qs.Widgets import qs.Widgets
Item { Item {
id: root id: root
readonly property var log: Log.scoped("GreeterDoctorPage")
property bool isRunning: false property bool isRunning: false
property bool hasRun: false property bool hasRun: false
@@ -228,9 +230,7 @@ Item {
text: { text: {
if (root.errorCount === 0) if (root.errorCount === 0)
return I18n.tr("All checks passed", "greeter doctor page success"); return I18n.tr("All checks passed", "greeter doctor page success");
return root.errorCount === 1 return root.errorCount === 1 ? I18n.tr("%1 issue found", "greeter doctor page error count").arg(root.errorCount) : I18n.tr("%1 issues found", "greeter doctor page error count").arg(root.errorCount);
? I18n.tr("%1 issue found", "greeter doctor page error count").arg(root.errorCount)
: I18n.tr("%1 issues found", "greeter doctor page error count").arg(root.errorCount);
} }
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: root.errorCount > 0 ? Theme.error : Theme.surfaceVariantText color: root.errorCount > 0 ? Theme.error : Theme.surfaceVariantText
@@ -412,7 +412,7 @@ Item {
else else
root.selectedFilter = "ok"; root.selectedFilter = "ok";
} catch (e) { } catch (e) {
console.error("GreeterDoctorPage: Failed to parse doctor output:", e); log.error("Failed to parse doctor output:", e);
} }
} }
} }

View File

@@ -7,6 +7,7 @@ import qs.Widgets
FloatingWindow { FloatingWindow {
id: root id: root
readonly property var log: Log.scoped("GreeterModal")
property bool disablePopupTransparency: true property bool disablePopupTransparency: true
property int currentPage: 0 property int currentPage: 0
@@ -105,7 +106,7 @@ FloatingWindow {
root.cheatsheetData = JSON.parse(trimmed); root.cheatsheetData = JSON.parse(trimmed);
root.cheatsheetLoaded = true; root.cheatsheetLoaded = true;
} catch (e) { } catch (e) {
console.warn("Greeter: Failed to parse cheatsheet:", e); log.warn("Greeter: Failed to parse cheatsheet:", e);
} }
} }
} }

View File

@@ -9,6 +9,7 @@ import qs.Widgets
FloatingWindow { FloatingWindow {
id: processListModal id: processListModal
readonly property var log: Log.scoped("ProcessListModal")
property bool disablePopupTransparency: true property bool disablePopupTransparency: true
property int currentTab: 0 property int currentTab: 0
@@ -22,7 +23,7 @@ FloatingWindow {
function show() { function show() {
if (!DgopService.dgopAvailable) { if (!DgopService.dgopAvailable) {
console.warn("ProcessListModal: dgop is not available"); log.warn("dgop is not available");
return; return;
} }
visible = true; visible = true;
@@ -36,7 +37,7 @@ FloatingWindow {
function toggle() { function toggle() {
if (!DgopService.dgopAvailable) { if (!DgopService.dgopAvailable) {
console.warn("ProcessListModal: dgop is not available"); log.warn("dgop is not available");
return; return;
} }
visible = !visible; visible = !visible;
@@ -44,7 +45,7 @@ FloatingWindow {
function focusOrToggle() { function focusOrToggle() {
if (!DgopService.dgopAvailable) { if (!DgopService.dgopAvailable) {
console.warn("ProcessListModal: dgop is not available"); log.warn("dgop is not available");
return; return;
} }
if (visible) { if (visible) {

View File

@@ -7,6 +7,7 @@ import qs.Widgets
FloatingWindow { FloatingWindow {
id: root id: root
readonly property var log: Log.scoped("WorkspaceRenameModal")
property bool disablePopupTransparency: true property bool disablePopupTransparency: true
readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2 readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2
@@ -39,7 +40,7 @@ FloatingWindow {
} else if (CompositorService.isHyprland) { } else if (CompositorService.isHyprland) {
HyprlandService.renameWorkspace(name); HyprlandService.renameWorkspace(name);
} else { } else {
console.warn("WorkspaceRenameModal: rename not supported for this compositor"); log.warn("rename not supported for this compositor");
} }
} }

View File

@@ -7,6 +7,7 @@ import "../utils/layout.js" as LayoutUtils
Column { Column {
id: root id: root
readonly property var log: Log.scoped("DragDropGrid")
property bool editMode: false property bool editMode: false
property string expandedSection: "" property string expandedSection: ""
@@ -988,7 +989,7 @@ Column {
return true; return true;
} }
} catch (e) { } catch (e) {
console.warn("DragDropGrid: stale plugin component for", pluginId, "- reloading"); log.warn("stale plugin component for", pluginId, "- reloading");
PluginService.reloadPlugin(pluginId); PluginService.reloadPlugin(pluginId);
} }
return false; return false;

View File

@@ -6,6 +6,7 @@ import "../utils/widgets.js" as WidgetUtils
QtObject { QtObject {
id: root id: root
readonly property var log: Log.scoped("WidgetModel")
property var vpnBuiltinInstance: null property var vpnBuiltinInstance: null
property var cupsBuiltinInstance: null property var cupsBuiltinInstance: null
@@ -26,7 +27,7 @@ QtObject {
const widgets = SettingsData.controlCenterWidgets || []; const widgets = SettingsData.controlCenterWidgets || [];
const hasVpnWidget = widgets.some(w => w.id === "builtin_vpn"); const hasVpnWidget = widgets.some(w => w.id === "builtin_vpn");
if (!hasVpnWidget && vpnLoader.active) { if (!hasVpnWidget && vpnLoader.active) {
console.log("VpnWidget: No VPN widget in control center, deactivating loader"); log.debug("VpnWidget: No VPN widget in control center, deactivating loader");
vpnLoader.active = false; vpnLoader.active = false;
} }
} }
@@ -55,7 +56,7 @@ QtObject {
const widgets = SettingsData.controlCenterWidgets || []; const widgets = SettingsData.controlCenterWidgets || [];
const hasCupsWidget = widgets.some(w => w.id === "builtin_cups"); const hasCupsWidget = widgets.some(w => w.id === "builtin_cups");
if (!hasCupsWidget && cupsLoader.active) { if (!hasCupsWidget && cupsLoader.active) {
console.log("CupsWidget: No CUPS widget in control center, deactivating loader"); log.debug("CupsWidget: No CUPS widget in control center, deactivating loader");
cupsLoader.active = false; cupsLoader.active = false;
} }
} }

View File

@@ -1,9 +1,11 @@
import QtQuick import QtQuick
import qs.Common import qs.Common
import qs.Modules.ControlCenter.Widgets import qs.Modules.ControlCenter.Widgets
import qs.Services
CompoundPill { CompoundPill {
id: root id: root
readonly property var log: Log.scoped("ColorPickerPill")
property var colorPickerModal: null property var colorPickerModal: null
@@ -14,14 +16,14 @@ CompoundPill {
secondaryText: I18n.tr("Choose a color") secondaryText: I18n.tr("Choose a color")
onToggled: { onToggled: {
console.log("ColorPickerPill toggled, modal:", colorPickerModal); log.debug("ColorPickerPill toggled, modal:", colorPickerModal);
if (colorPickerModal) { if (colorPickerModal) {
colorPickerModal.show(); colorPickerModal.show();
} }
} }
onExpandClicked: { onExpandClicked: {
console.log("ColorPickerPill expandClicked, modal:", colorPickerModal); log.debug("ColorPickerPill expandClicked, modal:", colorPickerModal);
if (colorPickerModal) { if (colorPickerModal) {
colorPickerModal.show(); colorPickerModal.show();
} }

View File

@@ -7,6 +7,7 @@ import qs.Services
PanelWindow { PanelWindow {
id: barWindow id: barWindow
readonly property var log: Log.scoped("DankBarWindow")
required property var rootWindow required property var rootWindow
required property var barConfig required property var barConfig
@@ -164,7 +165,7 @@ PanelWindow {
barWindow.BackgroundEffect.blurRegion = region; barWindow.BackgroundEffect.blurRegion = region;
barWindow.blurRegion = region; barWindow.blurRegion = region;
} catch (e) { } catch (e) {
console.warn("BarBlur: Failed to create blur region:", e); log.warn("BarBlur: Failed to create blur region:", e);
} }
} }
@@ -534,11 +535,11 @@ PanelWindow {
Connections { Connections {
target: PluginService target: PluginService
function onPluginLoaded(pluginId) { function onPluginLoaded(pluginId) {
console.info("DankBar: Plugin loaded:", pluginId); log.info("DankBar: Plugin loaded:", pluginId);
SettingsData.widgetDataChanged(); SettingsData.widgetDataChanged();
} }
function onPluginUnloaded(pluginId) { function onPluginUnloaded(pluginId) {
console.info("DankBar: Plugin unloaded:", pluginId); log.info("DankBar: Plugin unloaded:", pluginId);
SettingsData.widgetDataChanged(); SettingsData.widgetDataChanged();
} }
} }

View File

@@ -9,6 +9,7 @@ import qs.Widgets
BasePill { BasePill {
id: root id: root
readonly property var log: Log.scoped("AppsDock")
enableBackgroundHover: false enableBackgroundHover: false
enableCursor: false enableCursor: false
@@ -550,9 +551,9 @@ BasePill {
showBadge: root.showOverflowBadge showBadge: root.showOverflowBadge
z: 10 z: 10
onClicked: { onClicked: {
console.log("Overflow button clicked! Current state:", root.overflowExpanded); log.debug("Overflow button clicked! Current state:", root.overflowExpanded);
root.overflowExpanded = !root.overflowExpanded; root.overflowExpanded = !root.overflowExpanded;
console.log("New state:", root.overflowExpanded); log.debug("New state:", root.overflowExpanded);
} }
} }

View File

@@ -7,6 +7,7 @@ import qs.Widgets
BasePill { BasePill {
id: battery id: battery
readonly property var log: Log.scoped("Battery")
property bool batteryPopupVisible: false property bool batteryPopupVisible: false
property var popoutTarget: null property var popoutTarget: null
@@ -130,13 +131,13 @@ BasePill {
// Check if this is a touchpad // Check if this is a touchpad
if (delta !== 120 && delta !== -120) { if (delta !== 120 && delta !== -120) {
touchpadAccumulator += delta; touchpadAccumulator += delta;
console.info("Acc: "+touchpadAccumulator); log.info("Acc: " + touchpadAccumulator);
if (Math.abs(touchpadAccumulator) < 500) if (Math.abs(touchpadAccumulator) < 500)
return; return;
delta = touchpadAccumulator; delta = touchpadAccumulator;
touchpadAccumulator = 0; touchpadAccumulator = 0;
} }
console.info("Trigger! Delta: "+delta) log.info("Trigger! Delta: " + delta);
// This is after the other delta checks so it only shows on valid Y scroll // This is after the other delta checks so it only shows on valid Y scroll
if (typeof PowerProfiles === "undefined") { if (typeof PowerProfiles === "undefined") {
@@ -149,11 +150,14 @@ BasePill {
var index = profiles.findIndex(profile => PowerProfiles.profile === profile); var index = profiles.findIndex(profile => PowerProfiles.profile === profile);
// Step once based on mouse wheel direction // Step once based on mouse wheel direction
if (delta > 0) index += 1; if (delta > 0)
else index -= 1; index += 1;
else
index -= 1;
// Already at end of list, can't go further // Already at end of list, can't go further
if (index < 0 || index >= profiles.length) return; if (index < 0 || index >= profiles.length)
return;
// Set new profile // Set new profile
PowerProfiles.profile = profiles[index]; PowerProfiles.profile = profiles[index];

View File

@@ -6,6 +6,7 @@ import qs.Widgets
Rectangle { Rectangle {
id: root id: root
readonly property var log: Log.scoped("CalendarOverviewCard")
implicitWidth: SettingsData.showWeekNumber ? 736 : 700 implicitWidth: SettingsData.showWeekNumber ? 736 : 700
@@ -521,7 +522,7 @@ Rectangle {
onClicked: { onClicked: {
if (modelData.url && modelData.url !== "") { if (modelData.url && modelData.url !== "") {
if (Qt.openUrlExternally(modelData.url) === false) { if (Qt.openUrlExternally(modelData.url) === false) {
console.warn("Failed to open URL: " + modelData.url); log.warn("Failed to open URL: " + modelData.url);
} else { } else {
root.closeDash(); root.closeDash();
} }

View File

@@ -7,6 +7,7 @@ import qs.Widgets
Item { Item {
id: root id: root
readonly property var log: Log.scoped("WeatherTab")
LayoutMirroring.enabled: I18n.isRtl LayoutMirroring.enabled: I18n.isRtl
LayoutMirroring.childrenInherit: true LayoutMirroring.childrenInherit: true
@@ -45,7 +46,7 @@ Item {
hourlyList.currentIndex = Math.max(0, Math.min((WeatherService.weather.hourlyForecast?.length ?? 1) - 1, WeatherService.calendarHourDifference((new Date()), date) + (new Date()).getHours())); hourlyList.currentIndex = Math.max(0, Math.min((WeatherService.weather.hourlyForecast?.length ?? 1) - 1, WeatherService.calendarHourDifference((new Date()), date) + (new Date()).getHours()));
} }
} catch (e) { } catch (e) {
console.warn("Weather Date Sync Error:", e); log.warn("Weather Date Sync Error:", e);
} }
syncing = false; syncing = false;

View File

@@ -5,9 +5,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import "GreetdEnv.js" as GreetdEnv import "GreetdEnv.js" as GreetdEnv
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("GreetdMemory")
readonly property string greetCfgDir: Quickshell.env("DMS_GREET_CFG_DIR") || "/var/cache/dms-greeter" readonly property string greetCfgDir: Quickshell.env("DMS_GREET_CFG_DIR") || "/var/cache/dms-greeter"
readonly property string sessionConfigPath: greetCfgDir + "/session.json" readonly property string sessionConfigPath: greetCfgDir + "/session.json"
@@ -42,7 +44,7 @@ Singleton {
nightModeEnabled = config.nightModeEnabled !== undefined ? config.nightModeEnabled : false; nightModeEnabled = config.nightModeEnabled !== undefined ? config.nightModeEnabled : false;
} }
} catch (e) { } catch (e) {
console.warn("Failed to parse greeter session config:", e); log.warn("Failed to parse greeter session config:", e);
} }
} }
@@ -56,7 +58,7 @@ Singleton {
if (!rememberLastSession || !rememberLastUser) if (!rememberLastSession || !rememberLastUser)
saveMemory(); saveMemory();
} catch (e) { } catch (e) {
console.warn("Failed to parse greetd memory:", e); log.warn("Failed to parse greetd memory:", e);
} }
} }
@@ -122,7 +124,7 @@ Singleton {
parseSessionConfig(sessionConfigFileView.text()); parseSessionConfig(sessionConfigFileView.text());
} }
onLoadFailed: error => { onLoadFailed: error => {
console.warn("Could not load greeter session config from", root.sessionConfigPath, "error:", error); log.warn("Could not load greeter session config from", root.sessionConfigPath, "error:", error);
} }
} }
} }

View File

@@ -5,10 +5,12 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
import "GreetdEnv.js" as GreetdEnv import "GreetdEnv.js" as GreetdEnv
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("GreetdSettings")
readonly property string configPath: { readonly property string configPath: {
const greetCfgDir = Quickshell.env("DMS_GREET_CFG_DIR") || "/var/cache/dms-greeter"; const greetCfgDir = Quickshell.env("DMS_GREET_CFG_DIR") || "/var/cache/dms-greeter";
@@ -81,8 +83,7 @@ Singleton {
currentThemeName = settings.currentThemeName !== undefined ? settings.currentThemeName : "purple"; currentThemeName = settings.currentThemeName !== undefined ? settings.currentThemeName : "purple";
customThemeFile = settings.customThemeFile !== undefined ? settings.customThemeFile : ""; customThemeFile = settings.customThemeFile !== undefined ? settings.customThemeFile : "";
registryThemeVariants = settings.registryThemeVariants !== undefined ? registryThemeVariants = settings.registryThemeVariants !== undefined ? settings.registryThemeVariants : ({});
settings.registryThemeVariants : ({});
matugenScheme = settings.matugenScheme !== undefined ? settings.matugenScheme : "scheme-tonal-spot"; matugenScheme = settings.matugenScheme !== undefined ? settings.matugenScheme : "scheme-tonal-spot";
use24HourClock = settings.use24HourClock !== undefined ? settings.use24HourClock : true; use24HourClock = settings.use24HourClock !== undefined ? settings.use24HourClock : true;
showSeconds = settings.showSeconds !== undefined ? settings.showSeconds : false; showSeconds = settings.showSeconds !== undefined ? settings.showSeconds : false;
@@ -142,7 +143,7 @@ Singleton {
Theme.applyGreeterTheme(currentThemeName); Theme.applyGreeterTheme(currentThemeName);
} }
} catch (e) { } catch (e) {
console.warn("Failed to parse greetd settings:", e); log.warn("Failed to parse greetd settings:", e);
} finally { } finally {
settingsLoaded = true; settingsLoaded = true;
} }
@@ -192,7 +193,7 @@ Singleton {
parseSettings(settingsFile.text()); parseSettings(settingsFile.text());
} }
onLoadFailed: error => { onLoadFailed: error => {
console.warn("Failed to load greetd settings:", error); log.warn("Failed to load greetd settings:", error);
root.parseSettings(""); root.parseSettings("");
} }
} }

View File

@@ -1,9 +1,11 @@
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import qs.Services
Item { Item {
id: keyboard_controller id: keyboard_controller
readonly property var log: Log.scoped("KeyboardController")
// reference on the TextInput // reference on the TextInput
property Item target property Item target
@@ -14,21 +16,20 @@ Item {
function show() { function show() {
if (!isKeyboardActive && keyboard === null) { if (!isKeyboardActive && keyboard === null) {
keyboard = keyboardComponent.createObject( keyboard = keyboardComponent.createObject(keyboard_controller.rootObject);
keyboard_controller.rootObject) keyboard.target = keyboard_controller.target;
keyboard.target = keyboard_controller.target keyboard.dismissed.connect(hide);
keyboard.dismissed.connect(hide) isKeyboardActive = true;
isKeyboardActive = true
} else } else
console.log("The keyboard is already shown") log.debug("The keyboard is already shown");
} }
function hide() { function hide() {
if (isKeyboardActive && keyboard !== null) { if (isKeyboardActive && keyboard !== null) {
keyboard.destroy() keyboard.destroy();
isKeyboardActive = false isKeyboardActive = false;
} else } else
console.log("The keyboard is already hidden") log.debug("The keyboard is already hidden");
} }
// private // private

View File

@@ -14,6 +14,7 @@ import qs.Widgets
Item { Item {
id: root id: root
readonly property var log: Log.scoped("LockScreenContent")
function encodeFileUrl(path) { function encodeFileUrl(path) {
if (!path) if (!path)
@@ -95,9 +96,9 @@ Item {
if (SessionService.loginctlAvailable && DMSService.apiVersion >= 2) { if (SessionService.loginctlAvailable && DMSService.apiVersion >= 2) {
DMSService.sendRequest("loginctl.lockerReady", null, resp => { DMSService.sendRequest("loginctl.lockerReady", null, resp => {
if (resp?.error) if (resp?.error)
console.warn("lockerReady failed:", resp.error); log.warn("lockerReady failed:", resp.error);
else else
console.log("lockerReady sent (afterAnimating/afterRendering)"); log.debug("lockerReady sent (afterAnimating/afterRendering)");
}); });
} }
} }
@@ -803,7 +804,7 @@ Item {
} }
if (pam.passwd.active) { if (pam.passwd.active) {
console.log("PAM is active, ignoring input"); log.debug("PAM is active, ignoring input");
event.accepted = true; event.accepted = true;
return; return;
} }
@@ -1622,7 +1623,7 @@ Item {
buttonSize: 40 buttonSize: 40
onClicked: { onClicked: {
if (demoMode) { if (demoMode) {
console.log("Demo: Power Menu"); log.debug("Demo: Power Menu");
} else { } else {
powerMenu.show(); powerMenu.show();
} }

View File

@@ -3,9 +3,11 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import qs.Services
PanelWindow { PanelWindow {
id: root id: root
readonly property var log: Log.scoped("LockScreenDemo")
property bool demoActive: false property bool demoActive: false
@@ -25,12 +27,12 @@ PanelWindow {
color: "transparent" color: "transparent"
function showDemo(): void { function showDemo(): void {
console.log("Showing lock screen demo"); log.debug("Showing lock screen demo");
demoActive = true; demoActive = true;
} }
function hideDemo(): void { function hideDemo(): void {
console.log("Hiding lock screen demo"); log.debug("Hiding lock screen demo");
demoActive = false; demoActive = false;
} }

View File

@@ -7,6 +7,7 @@ import qs.Services
Item { Item {
id: root id: root
readonly property var log: Log.scoped("VideoScreensaver")
required property string screenName required property string screenName
property bool active: false property bool active: false
@@ -53,7 +54,7 @@ Item {
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0 || !videoPicker.result) { if (exitCode !== 0 || !videoPicker.result) {
console.warn("VideoScreensaver: no video found in folder"); log.warn("no video found in folder");
ToastService.showError(I18n.tr("Video Screensaver"), I18n.tr("No video found in folder")); ToastService.showError(I18n.tr("Video Screensaver"), I18n.tr("No video found in folder"));
root.dismiss(); root.dismiss();
} }
@@ -98,14 +99,14 @@ Item {
`, background, "VideoScreensaver.VideoPlayer"); `, background, "VideoScreensaver.VideoPlayer");
videoPlayer.errorOccurred.connect((error, errorString) => { videoPlayer.errorOccurred.connect((error, errorString) => {
console.warn("VideoScreensaver: playback error:", errorString); log.warn("playback error:", errorString);
ToastService.showError(I18n.tr("Video Screensaver"), I18n.tr("Playback error: ") + errorString); ToastService.showError(I18n.tr("Video Screensaver"), I18n.tr("Playback error: ") + errorString);
root.dismiss(); root.dismiss();
}); });
return true; return true;
} catch (e) { } catch (e) {
console.warn("VideoScreensaver: Failed to create video player:", e); log.warn("Failed to create video player:", e);
return false; return false;
} }
} }

View File

@@ -1,10 +1,12 @@
import QtQuick import QtQuick
import Quickshell import Quickshell
import qs.Common import qs.Common
import qs.Services
import qs.Widgets import qs.Widgets
Item { Item {
id: root id: root
readonly property var log: Log.scoped("PluginSettings")
required property string pluginId required property string pluginId
property var pluginService: null property var pluginService: null
@@ -131,7 +133,7 @@ Item {
return; return;
} }
if (!hasPermission) { if (!hasPermission) {
console.warn("PluginSettings: Plugin", pluginId, "does not have settings_write permission"); log.warn("Plugin", pluginId, "does not have settings_write permission");
return; return;
} }
if (pluginService.savePluginData) { if (pluginService.savePluginData) {

View File

@@ -9,6 +9,7 @@ import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("DisplayConfigState")
readonly property bool hasOutputBackend: WlrOutputService.wlrOutputAvailable readonly property bool hasOutputBackend: WlrOutputService.wlrOutputAvailable
readonly property var wlrOutputs: WlrOutputService.outputs readonly property var wlrOutputs: WlrOutputService.outputs
@@ -106,7 +107,7 @@ Singleton {
function findMatchingProfile() { function findMatchingProfile() {
const profiles = validatedProfiles; const profiles = validatedProfiles;
console.log("[Profile Match] Current outputs:", JSON.stringify(currentOutputSet)); log.debug("[Profile Match] Current outputs:", JSON.stringify(currentOutputSet));
let bestMatch = ""; let bestMatch = "";
let bestScore = -1; let bestScore = -1;
@@ -116,25 +117,25 @@ Singleton {
const profile = profiles[profileId]; const profile = profiles[profileId];
const profileSet = new Set(profile.outputSet); const profileSet = new Set(profile.outputSet);
console.log("[Profile Match] Checking", profile.name, "outputSet:", JSON.stringify(profile.outputSet)); log.debug("[Profile Match] Checking", profile.name, "outputSet:", JSON.stringify(profile.outputSet));
let allCurrentPresent = true; let allCurrentPresent = true;
for (const output of currentOutputSet) { for (const output of currentOutputSet) {
if (!profileSet.has(output)) { if (!profileSet.has(output)) {
console.log("[Profile Match] - Missing output:", output); log.debug("[Profile Match] - Missing output:", output);
allCurrentPresent = false; allCurrentPresent = false;
break; break;
} }
} }
if (!allCurrentPresent) { if (!allCurrentPresent) {
console.log("[Profile Match] - SKIP: not all current outputs present"); log.debug("[Profile Match] - SKIP: not all current outputs present");
continue; continue;
} }
const disconnectedCount = profile.outputSet.length - currentOutputSet.length; const disconnectedCount = profile.outputSet.length - currentOutputSet.length;
const score = currentOutputSet.length * 100 - disconnectedCount; const score = currentOutputSet.length * 100 - disconnectedCount;
const updatedAt = profile.updatedAt || profile.createdAt || 0; const updatedAt = profile.updatedAt || profile.createdAt || 0;
console.log("[Profile Match] - MATCH score:", score, "(disconnected:", disconnectedCount, "updatedAt:", updatedAt + ")"); log.debug("[Profile Match] - MATCH score:", score, "(disconnected:", disconnectedCount, "updatedAt:", updatedAt + ")");
if (score > bestScore || (score === bestScore && updatedAt > bestUpdatedAt)) { if (score > bestScore || (score === bestScore && updatedAt > bestUpdatedAt)) {
bestScore = score; bestScore = score;
@@ -142,7 +143,7 @@ Singleton {
bestUpdatedAt = updatedAt; bestUpdatedAt = updatedAt;
} }
} }
console.log("[Profile Match] Best match:", bestMatch, "score:", bestScore); log.debug("[Profile Match] Best match:", bestMatch, "score:", bestScore);
return bestMatch; return bestMatch;
} }

View File

@@ -6,6 +6,7 @@ import qs.Services
Column { Column {
id: root id: root
readonly property var log: Log.scoped("WidgetsTabSection")
property var items: [] property var items: []
property var allWidgets: [] property var allWidgets: []
@@ -1726,11 +1727,11 @@ Column {
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
onOpened: { onOpened: {
console.log("Privacy context menu opened"); log.debug("Privacy context menu opened");
} }
onClosed: { onClosed: {
console.log("Privacy Center context menu closed"); log.debug("Privacy Center context menu closed");
} }
background: Rectangle { background: Rectangle {

View File

@@ -7,6 +7,7 @@ import qs.Widgets
import qs.Services import qs.Services
Variants { Variants {
readonly property var log: Log.scoped("WallpaperBackground")
model: { model: {
if (SessionData.isGreeterMode) { if (SessionData.isGreeterMode) {
return Quickshell.screens; return Quickshell.screens;
@@ -103,7 +104,7 @@ Variants {
function _recheckScreenScale() { function _recheckScreenScale() {
const newScale = CompositorService.getScreenScale(modelData); const newScale = CompositorService.getScreenScale(modelData);
if (newScale !== root.screenScale) { if (newScale !== root.screenScale) {
console.info("WallpaperBackground: screen scale corrected for", modelData.name + ":", root.screenScale, "->", newScale); log.info("screen scale corrected for", modelData.name + ":", root.screenScale, "->", newScale);
root.screenScale = newScale; root.screenScale = newScale;
} }
} }

View File

@@ -8,6 +8,7 @@ import qs.Widgets
Item { Item {
id: root id: root
readonly property var log: Log.scoped("OverviewWidget")
required property var panelWindow required property var panelWindow
required property bool overviewOpen required property bool overviewOpen
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(panelWindow.screen) readonly property HyprlandMonitor monitor: Hyprland.monitorFor(panelWindow.screen)
@@ -276,7 +277,7 @@ Item {
} }
return result; return result;
} catch (e) { } catch (e) {
console.error("OverviewWidget filter error:", e); log.error("OverviewWidget filter error:", e);
return []; return [];
} }
} }

View File

@@ -4,9 +4,11 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import Quickshell import Quickshell
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("AppSearchService")
property var applications: [] property var applications: []
property var _cachedCategories: null property var _cachedCategories: null
@@ -811,7 +813,7 @@ Singleton {
}); });
isPersistent = false; isPersistent = false;
} catch (e) { } catch (e) {
console.warn("AppSearchService: Error creating temporary plugin instance", pluginId, ":", e); log.warn("Error creating temporary plugin instance", pluginId, ":", e);
return []; return [];
} }
} }
@@ -831,7 +833,7 @@ Singleton {
instance.destroy(); instance.destroy();
} }
} catch (e) { } catch (e) {
console.warn("AppSearchService: Error getting items from plugin", pluginId, ":", e); log.warn("Error getting items from plugin", pluginId, ":", e);
if (!isPersistent) if (!isPersistent)
instance.destroy(); instance.destroy();
} }
@@ -857,7 +859,7 @@ Singleton {
}); });
isPersistent = false; isPersistent = false;
} catch (e) { } catch (e) {
console.warn("AppSearchService: Error creating temporary plugin instance for execution", pluginId, ":", e); log.warn("Error creating temporary plugin instance for execution", pluginId, ":", e);
return false; return false;
} }
} }
@@ -877,7 +879,7 @@ Singleton {
instance.destroy(); instance.destroy();
} }
} catch (e) { } catch (e) {
console.warn("AppSearchService: Error executing item from plugin", pluginId, ":", e); log.warn("Error executing item from plugin", pluginId, ":", e);
if (!isPersistent) if (!isPersistent)
instance.destroy(); instance.destroy();
} }
@@ -949,7 +951,7 @@ Singleton {
try { try {
return instance.getCategories() || []; return instance.getCategories() || [];
} catch (e) { } catch (e) {
console.warn("AppSearchService: Error getting categories from plugin", pluginId, ":", e); log.warn("Error getting categories from plugin", pluginId, ":", e);
return []; return [];
} }
} }
@@ -968,7 +970,7 @@ Singleton {
try { try {
instance.setCategory(categoryId); instance.setCategory(categoryId);
} catch (e) { } catch (e) {
console.warn("AppSearchService: Error setting category on plugin", pluginId, ":", e); log.warn("Error setting category on plugin", pluginId, ":", e);
} }
} }

View File

@@ -11,6 +11,7 @@ import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("AudioService")
readonly property PwNode sink: Pipewire.defaultAudioSink readonly property PwNode sink: Pipewire.defaultAudioSink
readonly property PwNode source: Pipewire.defaultAudioSource readonly property PwNode source: Pipewire.defaultAudioSource
@@ -143,7 +144,7 @@ Singleton {
function setDeviceAlias(nodeName, customAlias) { function setDeviceAlias(nodeName, customAlias) {
if (!nodeName) { if (!nodeName) {
console.error("AudioService: Cannot set alias - nodeName is empty"); log.error("Cannot set alias - nodeName is empty");
return false; return false;
} }
@@ -189,8 +190,8 @@ EOFCONFIG
Proc.runCommand("writeWireplumberConfig", ["sh", "-c", shellCmd], (output, exitCode) => { Proc.runCommand("writeWireplumberConfig", ["sh", "-c", shellCmd], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.error("AudioService: Failed to write WirePlumber config. Exit code:", exitCode); log.error("Failed to write WirePlumber config. Exit code:", exitCode);
console.error("AudioService: Error output:", output); log.error("Error output:", output);
ToastService.showError(I18n.tr("Failed to save audio config"), output || ""); ToastService.showError(I18n.tr("Failed to save audio config"), output || "");
return; return;
} }
@@ -305,7 +306,7 @@ EOFCONFIG
ToastService.showInfo(I18n.tr("Audio system restarted"), I18n.tr("Device names updated")); ToastService.showInfo(I18n.tr("Audio system restarted"), I18n.tr("Device names updated"));
wireplumberReloadCompleted(true); wireplumberReloadCompleted(true);
} else { } else {
console.error("AudioService: Failed to restart WirePlumber:", output); log.error("Failed to restart WirePlumber:", output);
ToastService.showError(I18n.tr("Failed to restart audio system"), output); ToastService.showError(I18n.tr("Failed to restart audio system"), output);
wireplumberReloadCompleted(false); wireplumberReloadCompleted(false);
} }
@@ -317,7 +318,7 @@ EOFCONFIG
Proc.runCommand("readWireplumberConfig", ["cat", configPath], (output, exitCode) => { Proc.runCommand("readWireplumberConfig", ["cat", configPath], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.log("AudioService: No existing WirePlumber config found"); log.debug("No existing WirePlumber config found");
return; return;
} }
@@ -340,7 +341,7 @@ EOFCONFIG
if (Object.keys(aliases).length > 0) { if (Object.keys(aliases).length > 0) {
deviceAliases = aliases; deviceAliases = aliases;
console.log("AudioService: Loaded", Object.keys(aliases).length, "device aliases"); log.debug("Loaded", Object.keys(aliases).length, "device aliases");
} }
}, 0); }, 0);
} }
@@ -394,13 +395,13 @@ EOFCONFIG
Proc.runCommand("getCurrentSoundTheme", ["sh", "-c", "gsettings get org.gnome.desktop.sound theme-name 2>/dev/null | sed \"s/'//g\""], (output, exitCode) => { Proc.runCommand("getCurrentSoundTheme", ["sh", "-c", "gsettings get org.gnome.desktop.sound theme-name 2>/dev/null | sed \"s/'//g\""], (output, exitCode) => {
if (exitCode === 0 && output.trim()) { if (exitCode === 0 && output.trim()) {
currentSoundTheme = output.trim(); currentSoundTheme = output.trim();
console.log("AudioService: Current system sound theme:", currentSoundTheme); log.debug("Current system sound theme:", currentSoundTheme);
if (SettingsData.useSystemSoundTheme) { if (SettingsData.useSystemSoundTheme) {
discoverSoundFiles(currentSoundTheme); discoverSoundFiles(currentSoundTheme);
} }
} else { } else {
currentSoundTheme = ""; currentSoundTheme = "";
console.log("AudioService: No system sound theme found"); log.debug("No system sound theme found");
} }
}, 0); }, 0);
} }
@@ -510,22 +511,22 @@ EOFCONFIG
const themeLower = currentSoundTheme.toLowerCase(); const themeLower = currentSoundTheme.toLowerCase();
if (SettingsData.useSystemSoundTheme && specialConditions[themeLower]?.includes(soundEvent)) { if (SettingsData.useSystemSoundTheme && specialConditions[themeLower]?.includes(soundEvent)) {
const bundledPath = Qt.resolvedUrl(soundMap[soundEvent] || "../assets/sounds/freedesktop/message.wav"); const bundledPath = Qt.resolvedUrl(soundMap[soundEvent] || "../assets/sounds/freedesktop/message.wav");
console.log("AudioService: Using bundled sound (special condition) for", soundEvent, ":", bundledPath); log.debug("Using bundled sound (special condition) for", soundEvent, ":", bundledPath);
return bundledPath; return bundledPath;
} }
if (SettingsData.useSystemSoundTheme && soundFilePaths[soundEvent]) { if (SettingsData.useSystemSoundTheme && soundFilePaths[soundEvent]) {
console.log("AudioService: Using system sound for", soundEvent, ":", soundFilePaths[soundEvent]); log.debug("Using system sound for", soundEvent, ":", soundFilePaths[soundEvent]);
return soundFilePaths[soundEvent]; return soundFilePaths[soundEvent];
} }
const bundledPath = Qt.resolvedUrl(soundMap[soundEvent] || "../assets/sounds/freedesktop/message.wav"); const bundledPath = Qt.resolvedUrl(soundMap[soundEvent] || "../assets/sounds/freedesktop/message.wav");
console.log("AudioService: Using bundled sound for", soundEvent, ":", bundledPath); log.debug("Using bundled sound for", soundEvent, ":", bundledPath);
return bundledPath; return bundledPath;
} }
function reloadSounds() { function reloadSounds() {
console.log("AudioService: Reloading sounds, useSystemSoundTheme:", SettingsData.useSystemSoundTheme, "currentSoundTheme:", currentSoundTheme); log.debug("Reloading sounds, useSystemSoundTheme:", SettingsData.useSystemSoundTheme, "currentSoundTheme:", currentSoundTheme);
if (SettingsData.useSystemSoundTheme && currentSoundTheme) { if (SettingsData.useSystemSoundTheme && currentSoundTheme) {
discoverSoundFiles(currentSoundTheme); discoverSoundFiles(currentSoundTheme);
} else { } else {
@@ -549,7 +550,7 @@ EOFCONFIG
MediaDevices { MediaDevices {
id: devices id: devices
Component.onCompleted: { Component.onCompleted: {
console.log("AudioService: MediaDevices initialized, default output:", defaultAudioOutput?.description) log.debug("MediaDevices initialized, default output:", defaultAudioOutput?.description)
} }
} }
`, root, "AudioService.MediaDevices"); `, root, "AudioService.MediaDevices");
@@ -560,7 +561,7 @@ EOFCONFIG
Connections { Connections {
target: root.mediaDevices target: root.mediaDevices
function onDefaultAudioOutputChanged() { function onDefaultAudioOutputChanged() {
console.log("AudioService: Default audio output changed, recreating sound players") log.debug("Default audio output changed, recreating sound players")
root.destroySoundPlayers() root.destroySoundPlayers()
root.createSoundPlayers() root.createSoundPlayers()
} }
@@ -568,7 +569,7 @@ EOFCONFIG
`, root, "AudioService.MediaDevicesConnections"); `, root, "AudioService.MediaDevicesConnections");
} }
} catch (e) { } catch (e) {
console.log("AudioService: MediaDevices not available, using default audio output"); log.debug("MediaDevices not available, using default audio output");
mediaDevices = null; mediaDevices = null;
} }
} }
@@ -682,7 +683,7 @@ EOFCONFIG
} }
`, root, "AudioService.LoginSound"); `, root, "AudioService.LoginSound");
} catch (e) { } catch (e) {
console.warn("AudioService: Error creating sound players:", e); log.warn("Error creating sound players:", e);
} }
} }

View File

@@ -1,5 +1,4 @@
pragma Singleton pragma Singleton
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtQuick import QtQuick
@@ -19,206 +18,217 @@ Singleton {
readonly property bool enhancedPairingAvailable: DMSService.dmsAvailable && DMSService.apiVersion >= 9 && DMSService.capabilities.includes("bluetooth") readonly property bool enhancedPairingAvailable: DMSService.dmsAvailable && DMSService.apiVersion >= 9 && DMSService.capabilities.includes("bluetooth")
readonly property bool connected: { readonly property bool connected: {
if (!adapter || !adapter.devices) { if (!adapter || !adapter.devices) {
return false return false;
} }
let isConnected = false let isConnected = false;
adapter.devices.values.forEach(dev => { if (dev.connected) isConnected = true }) adapter.devices.values.forEach(dev => {
return isConnected if (dev.connected)
isConnected = true;
});
return isConnected;
} }
readonly property var pairedDevices: { readonly property var pairedDevices: {
if (!adapter || !adapter.devices) { if (!adapter || !adapter.devices) {
return [] return [];
} }
return adapter.devices.values.filter(dev => { return adapter.devices.values.filter(dev => {
return dev && (dev.paired || dev.trusted) return dev && (dev.paired || dev.trusted);
}) });
} }
readonly property var allDevicesWithBattery: { readonly property var allDevicesWithBattery: {
if (!adapter || !adapter.devices) { if (!adapter || !adapter.devices) {
return [] return [];
} }
return adapter.devices.values.filter(dev => { return adapter.devices.values.filter(dev => {
return dev && dev.batteryAvailable && dev.battery > 0 return dev && dev.batteryAvailable && dev.battery > 0;
}) });
} }
function sortDevices(devices) { function sortDevices(devices) {
return devices.sort((a, b) => { return devices.sort((a, b) => {
const aName = a.name || a.deviceName || "" const aName = a.name || a.deviceName || "";
const bName = b.name || b.deviceName || "" const bName = b.name || b.deviceName || "";
const aAddr = a.address || "" const aAddr = a.address || "";
const bAddr = b.address || "" const bAddr = b.address || "";
const aHasRealName = aName.includes(" ") && aName.length > 3 const aHasRealName = aName.includes(" ") && aName.length > 3;
const bHasRealName = bName.includes(" ") && bName.length > 3 const bHasRealName = bName.includes(" ") && bName.length > 3;
if (aHasRealName && !bHasRealName) return -1 if (aHasRealName && !bHasRealName)
if (!aHasRealName && bHasRealName) return 1 return -1;
if (!aHasRealName && bHasRealName)
return 1;
if (aHasRealName && bHasRealName) { if (aHasRealName && bHasRealName) {
return aName.localeCompare(bName) return aName.localeCompare(bName);
} }
return aAddr.localeCompare(bAddr) return aAddr.localeCompare(bAddr);
}) });
} }
function getDeviceIcon(device) { function getDeviceIcon(device) {
if (!device) { if (!device) {
return "bluetooth" return "bluetooth";
} }
const name = (device.name || device.deviceName || "").toLowerCase() const name = (device.name || device.deviceName || "").toLowerCase();
const icon = (device.icon || "").toLowerCase() const icon = (device.icon || "").toLowerCase();
const audioKeywords = ["headset", "audio", "headphone", "airpod", "arctis"] const audioKeywords = ["headset", "audio", "headphone", "airpod", "arctis"];
if (audioKeywords.some(keyword => icon.includes(keyword) || name.includes(keyword))) { if (audioKeywords.some(keyword => icon.includes(keyword) || name.includes(keyword))) {
return "headset" return "headset";
} }
if (icon.includes("mouse") || name.includes("mouse")) { if (icon.includes("mouse") || name.includes("mouse")) {
return "mouse" return "mouse";
} }
if (icon.includes("keyboard") || name.includes("keyboard")) { if (icon.includes("keyboard") || name.includes("keyboard")) {
return "keyboard" return "keyboard";
} }
const phoneKeywords = ["phone", "iphone", "android", "samsung"] const phoneKeywords = ["phone", "iphone", "android", "samsung"];
if (phoneKeywords.some(keyword => icon.includes(keyword) || name.includes(keyword))) { if (phoneKeywords.some(keyword => icon.includes(keyword) || name.includes(keyword))) {
return "smartphone" return "smartphone";
} }
if (icon.includes("watch") || name.includes("watch")) { if (icon.includes("watch") || name.includes("watch")) {
return "watch" return "watch";
} }
if (icon.includes("speaker") || name.includes("speaker")) { if (icon.includes("speaker") || name.includes("speaker")) {
return "speaker" return "speaker";
} }
if (icon.includes("display") || name.includes("tv")) { if (icon.includes("display") || name.includes("tv")) {
return "tv" return "tv";
} }
return "bluetooth" return "bluetooth";
} }
function canConnect(device) { function canConnect(device) {
if (!device) { if (!device) {
return false return false;
} }
return !device.paired && !device.pairing && !device.blocked return !device.paired && !device.pairing && !device.blocked;
} }
function getSignalStrength(device) { function getSignalStrength(device) {
if (!device || device.signalStrength === undefined || device.signalStrength <= 0) { if (!device || device.signalStrength === undefined || device.signalStrength <= 0) {
return "Unknown" return "Unknown";
} }
const signal = device.signalStrength const signal = device.signalStrength;
if (signal >= 80) { if (signal >= 80) {
return "Excellent" return "Excellent";
} }
if (signal >= 60) { if (signal >= 60) {
return "Good" return "Good";
} }
if (signal >= 40) { if (signal >= 40) {
return "Fair" return "Fair";
} }
if (signal >= 20) { if (signal >= 20) {
return "Poor" return "Poor";
} }
return "Very Poor" return "Very Poor";
} }
function getSignalIcon(device) { function getSignalIcon(device) {
if (!device || device.signalStrength === undefined || device.signalStrength <= 0) { if (!device || device.signalStrength === undefined || device.signalStrength <= 0) {
return "signal_cellular_null" return "signal_cellular_null";
} }
const signal = device.signalStrength const signal = device.signalStrength;
if (signal >= 80) { if (signal >= 80) {
return "signal_cellular_4_bar" return "signal_cellular_4_bar";
} }
if (signal >= 60) { if (signal >= 60) {
return "signal_cellular_3_bar" return "signal_cellular_3_bar";
} }
if (signal >= 40) { if (signal >= 40) {
return "signal_cellular_2_bar" return "signal_cellular_2_bar";
} }
if (signal >= 20) { if (signal >= 20) {
return "signal_cellular_1_bar" return "signal_cellular_1_bar";
} }
return "signal_cellular_0_bar" return "signal_cellular_0_bar";
} }
function isDeviceBusy(device) { function isDeviceBusy(device) {
if (!device) { if (!device) {
return false return false;
} }
return device.pairing || device.state === BluetoothDeviceState.Disconnecting || device.state === BluetoothDeviceState.Connecting return device.pairing || device.state === BluetoothDeviceState.Disconnecting || device.state === BluetoothDeviceState.Connecting;
} }
function connectDeviceWithTrust(device) { function connectDeviceWithTrust(device) {
if (!device) { if (!device) {
return return;
} }
device.trusted = true device.trusted = true;
device.connect() device.connect();
} }
function pairDevice(device, callback) { function pairDevice(device, callback) {
if (!device) { if (!device) {
if (callback) callback({error: "Invalid device"}) if (callback)
return callback({
error: "Invalid device"
});
return;
} }
// The DMS backend actually implements a bluez agent, so we can pair anything // The DMS backend actually implements a bluez agent, so we can pair anything
if (enhancedPairingAvailable) { if (enhancedPairingAvailable) {
const devicePath = getDevicePath(device) const devicePath = getDevicePath(device);
DMSService.bluetoothPair(devicePath, callback) DMSService.bluetoothPair(devicePath, callback);
return return;
} }
// Quickshell does not implement a bluez agent, so we can try to pair but only with devices that don't require a passcode // Quickshell does not implement a bluez agent, so we can try to pair but only with devices that don't require a passcode
device.trusted = true device.trusted = true;
device.connect() device.connect();
if (callback) callback({success: true}) if (callback)
callback({
success: true
});
} }
function getCardName(device) { function getCardName(device) {
if (!device) { if (!device) {
return "" return "";
} }
return `bluez_card.${device.address.replace(/:/g, "_")}` return `bluez_card.${device.address.replace(/:/g, "_")}`;
} }
function getDevicePath(device) { function getDevicePath(device) {
if (!device || !device.address) { if (!device || !device.address) {
return "" return "";
} }
const adapterPath = adapter ? "/org/bluez/hci0" : "/org/bluez/hci0" const adapterPath = adapter ? "/org/bluez/hci0" : "/org/bluez/hci0";
return `${adapterPath}/dev_${device.address.replace(/:/g, "_")}` return `${adapterPath}/dev_${device.address.replace(/:/g, "_")}`;
} }
function isAudioDevice(device) { function isAudioDevice(device) {
if (!device) { if (!device) {
return false return false;
} }
const icon = getDeviceIcon(device) const icon = getDeviceIcon(device);
return icon === "headset" || icon === "speaker" return icon === "headset" || icon === "speaker";
} }
function getCodecInfo(codecName) { function getCodecInfo(codecName) {
const codec = codecName.replace(/-/g, "_").toUpperCase() const codec = codecName.replace(/-/g, "_").toUpperCase();
const codecMap = { const codecMap = {
"LDAC": { "LDAC": {
@@ -261,77 +271,77 @@ Singleton {
"description": "Basic speech codec • Legacy compatibility", "description": "Basic speech codec • Legacy compatibility",
"qualityColor": "#9E9E9E" "qualityColor": "#9E9E9E"
} }
} };
return codecMap[codec] || { return codecMap[codec] || {
"name": codecName, "name": codecName,
"description": "Unknown codec", "description": "Unknown codec",
"qualityColor": "#9E9E9E" "qualityColor": "#9E9E9E"
} };
} }
property var deviceCodecs: ({}) property var deviceCodecs: ({})
function updateDeviceCodec(deviceAddress, codec) { function updateDeviceCodec(deviceAddress, codec) {
deviceCodecs[deviceAddress] = codec deviceCodecs[deviceAddress] = codec;
deviceCodecsChanged() deviceCodecsChanged();
} }
function refreshDeviceCodec(device) { function refreshDeviceCodec(device) {
if (!device || !device.connected || !isAudioDevice(device)) { if (!device || !device.connected || !isAudioDevice(device)) {
return return;
} }
const cardName = getCardName(device) const cardName = getCardName(device);
codecQueryProcess.cardName = cardName codecQueryProcess.cardName = cardName;
codecQueryProcess.deviceAddress = device.address codecQueryProcess.deviceAddress = device.address;
codecQueryProcess.availableCodecs = [] codecQueryProcess.availableCodecs = [];
codecQueryProcess.parsingTargetCard = false codecQueryProcess.parsingTargetCard = false;
codecQueryProcess.detectedCodec = "" codecQueryProcess.detectedCodec = "";
codecQueryProcess.running = true codecQueryProcess.running = true;
} }
function getCurrentCodec(device, callback) { function getCurrentCodec(device, callback) {
if (!device || !device.connected || !isAudioDevice(device)) { if (!device || !device.connected || !isAudioDevice(device)) {
callback("") callback("");
return return;
} }
const cardName = getCardName(device) const cardName = getCardName(device);
codecQueryProcess.cardName = cardName codecQueryProcess.cardName = cardName;
codecQueryProcess.callback = callback codecQueryProcess.callback = callback;
codecQueryProcess.availableCodecs = [] codecQueryProcess.availableCodecs = [];
codecQueryProcess.parsingTargetCard = false codecQueryProcess.parsingTargetCard = false;
codecQueryProcess.detectedCodec = "" codecQueryProcess.detectedCodec = "";
codecQueryProcess.running = true codecQueryProcess.running = true;
} }
function getAvailableCodecs(device, callback) { function getAvailableCodecs(device, callback) {
if (!device || !device.connected || !isAudioDevice(device)) { if (!device || !device.connected || !isAudioDevice(device)) {
callback([], "") callback([], "");
return return;
} }
const cardName = getCardName(device) const cardName = getCardName(device);
codecFullQueryProcess.cardName = cardName codecFullQueryProcess.cardName = cardName;
codecFullQueryProcess.callback = callback codecFullQueryProcess.callback = callback;
codecFullQueryProcess.availableCodecs = [] codecFullQueryProcess.availableCodecs = [];
codecFullQueryProcess.parsingTargetCard = false codecFullQueryProcess.parsingTargetCard = false;
codecFullQueryProcess.detectedCodec = "" codecFullQueryProcess.detectedCodec = "";
codecFullQueryProcess.running = true codecFullQueryProcess.running = true;
} }
function switchCodec(device, profileName, callback) { function switchCodec(device, profileName, callback) {
if (!device || !isAudioDevice(device)) { if (!device || !isAudioDevice(device)) {
callback(false, "Invalid device") callback(false, "Invalid device");
return return;
} }
const cardName = getCardName(device) const cardName = getCardName(device);
codecSwitchProcess.cardName = cardName codecSwitchProcess.cardName = cardName;
codecSwitchProcess.profile = profileName codecSwitchProcess.profile = profileName;
codecSwitchProcess.callback = callback codecSwitchProcess.callback = callback;
codecSwitchProcess.running = true codecSwitchProcess.running = true;
} }
Process { Process {
@@ -349,67 +359,67 @@ Singleton {
onExited: (exitCode, exitStatus) => { onExited: (exitCode, exitStatus) => {
if (exitCode === 0 && detectedCodec) { if (exitCode === 0 && detectedCodec) {
if (deviceAddress) { if (deviceAddress) {
root.updateDeviceCodec(deviceAddress, detectedCodec) root.updateDeviceCodec(deviceAddress, detectedCodec);
} }
if (callback) { if (callback) {
callback(detectedCodec) callback(detectedCodec);
} }
} else if (callback) { } else if (callback) {
callback("") callback("");
} }
parsingTargetCard = false parsingTargetCard = false;
detectedCodec = "" detectedCodec = "";
availableCodecs = [] availableCodecs = [];
deviceAddress = "" deviceAddress = "";
callback = null callback = null;
} }
stdout: SplitParser { stdout: SplitParser {
splitMarker: "\n" splitMarker: "\n"
onRead: data => { onRead: data => {
let line = data.trim() let line = data.trim();
if (line.includes(`Name: ${codecQueryProcess.cardName}`)) { if (line.includes(`Name: ${codecQueryProcess.cardName}`)) {
codecQueryProcess.parsingTargetCard = true codecQueryProcess.parsingTargetCard = true;
return return;
} }
if (codecQueryProcess.parsingTargetCard && line.startsWith("Name: ") && !line.includes(codecQueryProcess.cardName)) { if (codecQueryProcess.parsingTargetCard && line.startsWith("Name: ") && !line.includes(codecQueryProcess.cardName)) {
codecQueryProcess.parsingTargetCard = false codecQueryProcess.parsingTargetCard = false;
return return;
} }
if (codecQueryProcess.parsingTargetCard) { if (codecQueryProcess.parsingTargetCard) {
if (line.startsWith("Active Profile:")) { if (line.startsWith("Active Profile:")) {
let profile = line.split(": ")[1] || "" let profile = line.split(": ")[1] || "";
let activeCodec = codecQueryProcess.availableCodecs.find(c => { let activeCodec = codecQueryProcess.availableCodecs.find(c => {
return c.profile === profile return c.profile === profile;
}) });
if (activeCodec) { if (activeCodec) {
codecQueryProcess.detectedCodec = activeCodec.name codecQueryProcess.detectedCodec = activeCodec.name;
} }
return return;
} }
if (line.includes("codec") && line.includes("available: yes")) { if (line.includes("codec") && line.includes("available: yes")) {
let parts = line.split(": ") let parts = line.split(": ");
if (parts.length >= 2) { if (parts.length >= 2) {
let profile = parts[0].trim() let profile = parts[0].trim();
let description = parts[1] let description = parts[1];
let codecMatch = description.match(/codec ([^\)\s]+)/i) let codecMatch = description.match(/codec ([^\)\s]+)/i);
let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN" let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN";
let codecInfo = root.getCodecInfo(codecName) let codecInfo = root.getCodecInfo(codecName);
if (codecInfo && !codecQueryProcess.availableCodecs.some(c => { if (codecInfo && !codecQueryProcess.availableCodecs.some(c => {
return c.profile === profile return c.profile === profile;
})) { })) {
let newCodecs = codecQueryProcess.availableCodecs.slice() let newCodecs = codecQueryProcess.availableCodecs.slice();
newCodecs.push({ newCodecs.push({
"name": codecInfo.name, "name": codecInfo.name,
"profile": profile, "profile": profile,
"description": codecInfo.description, "description": codecInfo.description,
"qualityColor": codecInfo.qualityColor "qualityColor": codecInfo.qualityColor
}) });
codecQueryProcess.availableCodecs = newCodecs codecQueryProcess.availableCodecs = newCodecs;
} }
} }
} }
@@ -431,59 +441,59 @@ Singleton {
onExited: function (exitCode, exitStatus) { onExited: function (exitCode, exitStatus) {
if (callback) { if (callback) {
callback(exitCode === 0 ? availableCodecs : [], exitCode === 0 ? detectedCodec : "") callback(exitCode === 0 ? availableCodecs : [], exitCode === 0 ? detectedCodec : "");
} }
parsingTargetCard = false parsingTargetCard = false;
detectedCodec = "" detectedCodec = "";
availableCodecs = [] availableCodecs = [];
callback = null callback = null;
} }
stdout: SplitParser { stdout: SplitParser {
splitMarker: "\n" splitMarker: "\n"
onRead: data => { onRead: data => {
let line = data.trim() let line = data.trim();
if (line.includes(`Name: ${codecFullQueryProcess.cardName}`)) { if (line.includes(`Name: ${codecFullQueryProcess.cardName}`)) {
codecFullQueryProcess.parsingTargetCard = true codecFullQueryProcess.parsingTargetCard = true;
return return;
} }
if (codecFullQueryProcess.parsingTargetCard && line.startsWith("Name: ") && !line.includes(codecFullQueryProcess.cardName)) { if (codecFullQueryProcess.parsingTargetCard && line.startsWith("Name: ") && !line.includes(codecFullQueryProcess.cardName)) {
codecFullQueryProcess.parsingTargetCard = false codecFullQueryProcess.parsingTargetCard = false;
return return;
} }
if (codecFullQueryProcess.parsingTargetCard) { if (codecFullQueryProcess.parsingTargetCard) {
if (line.startsWith("Active Profile:")) { if (line.startsWith("Active Profile:")) {
let profile = line.split(": ")[1] || "" let profile = line.split(": ")[1] || "";
let activeCodec = codecFullQueryProcess.availableCodecs.find(c => { let activeCodec = codecFullQueryProcess.availableCodecs.find(c => {
return c.profile === profile return c.profile === profile;
}) });
if (activeCodec) { if (activeCodec) {
codecFullQueryProcess.detectedCodec = activeCodec.name codecFullQueryProcess.detectedCodec = activeCodec.name;
} }
return return;
} }
if (line.includes("codec") && line.includes("available: yes")) { if (line.includes("codec") && line.includes("available: yes")) {
let parts = line.split(": ") let parts = line.split(": ");
if (parts.length >= 2) { if (parts.length >= 2) {
let profile = parts[0].trim() let profile = parts[0].trim();
let description = parts[1] let description = parts[1];
let codecMatch = description.match(/codec ([^\)\s]+)/i) let codecMatch = description.match(/codec ([^\)\s]+)/i);
let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN" let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN";
let codecInfo = root.getCodecInfo(codecName) let codecInfo = root.getCodecInfo(codecName);
if (codecInfo && !codecFullQueryProcess.availableCodecs.some(c => { if (codecInfo && !codecFullQueryProcess.availableCodecs.some(c => {
return c.profile === profile return c.profile === profile;
})) { })) {
let newCodecs = codecFullQueryProcess.availableCodecs.slice() let newCodecs = codecFullQueryProcess.availableCodecs.slice();
newCodecs.push({ newCodecs.push({
"name": codecInfo.name, "name": codecInfo.name,
"profile": profile, "profile": profile,
"description": codecInfo.description, "description": codecInfo.description,
"qualityColor": codecInfo.qualityColor "qualityColor": codecInfo.qualityColor
}) });
codecFullQueryProcess.availableCodecs = newCodecs codecFullQueryProcess.availableCodecs = newCodecs;
} }
} }
} }
@@ -503,7 +513,7 @@ Singleton {
onExited: function (exitCode, exitStatus) { onExited: function (exitCode, exitStatus) {
if (callback) { if (callback) {
callback(exitCode === 0, exitCode === 0 ? "Codec switched successfully" : "Failed to switch codec") callback(exitCode === 0, exitCode === 0 ? "Codec switched successfully" : "Failed to switch codec");
} }
// If successful, refresh the codec for this device // If successful, refresh the codec for this device
@@ -511,13 +521,13 @@ Singleton {
if (root.adapter && root.adapter.devices) { if (root.adapter && root.adapter.devices) {
root.adapter.devices.values.forEach(device => { root.adapter.devices.values.forEach(device => {
if (device && root.getCardName(device) === cardName) { if (device && root.getCardName(device) === cardName) {
Qt.callLater(() => root.refreshDeviceCodec(device)) Qt.callLater(() => root.refreshDeviceCodec(device));
} }
}) });
} }
} }
callback = null callback = null;
} }
} }
} }

View File

@@ -6,9 +6,11 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Wayland // ! Import is needed despite what qmlls says import Quickshell.Wayland // ! Import is needed despite what qmlls says
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("BlurService")
property bool quickshellSupported: false property bool quickshellSupported: false
property bool compositorSupported: false property bool compositorSupported: false
@@ -52,7 +54,7 @@ Singleton {
targetWindow.BackgroundEffect.blurRegion = region; targetWindow.BackgroundEffect.blurRegion = region;
return region; return region;
} catch (e) { } catch (e) {
console.warn("BlurService: Failed to create blur region:", e); log.warn("Failed to create blur region:", e);
return null; return null;
} }
} }
@@ -84,15 +86,15 @@ Singleton {
onStreamFinished: { onStreamFinished: {
root.compositorSupported = text.trim() === "supported"; root.compositorSupported = text.trim() === "supported";
if (root.compositorSupported) if (root.compositorSupported)
console.info("BlurService: Compositor supports ext-background-effect-v1"); log.info("Compositor supports ext-background-effect-v1");
else else
console.info("BlurService: Compositor does not support ext-background-effect-v1"); log.info("Compositor does not support ext-background-effect-v1");
} }
} }
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("BlurService: blur probe failed with code:", exitCode); log.warn("blur probe failed with code:", exitCode);
} }
} }
@@ -104,10 +106,10 @@ Singleton {
`, root, "BlurAvailabilityTest"); `, root, "BlurAvailabilityTest");
test.destroy(); test.destroy();
quickshellSupported = true; quickshellSupported = true;
console.info("BlurService: Quickshell blur support available"); log.info("Quickshell blur support available");
blurProbe.running = true; blurProbe.running = true;
} catch (e) { } catch (e) {
console.info("BlurService: BackgroundEffect not available - blur disabled. Requires a newer version of Quickshell."); log.info("BackgroundEffect not available - blur disabled. Requires a newer version of Quickshell.");
} }
} }
} }

View File

@@ -19,68 +19,69 @@ Singleton {
function checkKhalAvailability() { function checkKhalAvailability() {
if (!khalCheckProcess.running) if (!khalCheckProcess.running)
khalCheckProcess.running = true khalCheckProcess.running = true;
} }
function detectKhalDateFormat() { function detectKhalDateFormat() {
if (!khalFormatProcess.running) if (!khalFormatProcess.running)
khalFormatProcess.running = true khalFormatProcess.running = true;
} }
function parseKhalDateFormat(formatExample) { function parseKhalDateFormat(formatExample) {
let qtFormat = formatExample.replace("12", "MM").replace("21", "dd").replace("2013", "yyyy") let qtFormat = formatExample.replace("12", "MM").replace("21", "dd").replace("2013", "yyyy");
return { format: qtFormat, parser: null } return {
format: qtFormat,
parser: null
};
} }
function loadCurrentMonth() { function loadCurrentMonth() {
if (!root.khalAvailable) if (!root.khalAvailable)
return return;
let today = new Date();
let today = new Date() let firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
let firstDay = new Date(today.getFullYear(), today.getMonth(), 1) let lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);
let lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0)
// Add padding // Add padding
let startDate = new Date(firstDay) let startDate = new Date(firstDay);
startDate.setDate(startDate.getDate() - firstDay.getDay() - 7) startDate.setDate(startDate.getDate() - firstDay.getDay() - 7);
let endDate = new Date(lastDay) let endDate = new Date(lastDay);
endDate.setDate(endDate.getDate() + (6 - lastDay.getDay()) + 7) endDate.setDate(endDate.getDate() + (6 - lastDay.getDay()) + 7);
loadEvents(startDate, endDate) loadEvents(startDate, endDate);
} }
function loadEvents(startDate, endDate) { function loadEvents(startDate, endDate) {
if (!root.khalAvailable) { if (!root.khalAvailable) {
return return;
} }
if (eventsProcess.running) { if (eventsProcess.running) {
return return;
} }
// Store last requested date range for refresh timer // Store last requested date range for refresh timer
root.lastStartDate = startDate root.lastStartDate = startDate;
root.lastEndDate = endDate root.lastEndDate = endDate;
root.isLoading = true root.isLoading = true;
// Format dates for khal using detected format // Format dates for khal using detected format
let startDateStr = Qt.formatDate(startDate, root.khalDateFormat) let startDateStr = Qt.formatDate(startDate, root.khalDateFormat);
let endDateStr = Qt.formatDate(endDate, root.khalDateFormat) let endDateStr = Qt.formatDate(endDate, root.khalDateFormat);
eventsProcess.requestStartDate = startDate eventsProcess.requestStartDate = startDate;
eventsProcess.requestEndDate = endDate eventsProcess.requestEndDate = endDate;
eventsProcess.command = ["khal", "list", "--json", "title", "--json", "description", "--json", "start-date", "--json", "start-time", "--json", "end-date", "--json", "end-time", "--json", "all-day", "--json", "location", "--json", "url", startDateStr, endDateStr] eventsProcess.command = ["khal", "list", "--json", "title", "--json", "description", "--json", "start-date", "--json", "start-time", "--json", "end-date", "--json", "end-time", "--json", "all-day", "--json", "location", "--json", "url", startDateStr, endDateStr];
eventsProcess.running = true eventsProcess.running = true;
} }
function getEventsForDate(date) { function getEventsForDate(date) {
let dateKey = Qt.formatDate(date, "yyyy-MM-dd") let dateKey = Qt.formatDate(date, "yyyy-MM-dd");
return root.eventsByDate[dateKey] || [] return root.eventsByDate[dateKey] || [];
} }
function hasEventsForDate(date) { function hasEventsForDate(date) {
let events = getEventsForDate(date) let events = getEventsForDate(date);
return events.length > 0 return events.length > 0;
} }
// Initialize on component completion // Initialize on component completion
Component.onCompleted: { Component.onCompleted: {
detectKhalDateFormat() detectKhalDateFormat();
} }
// Process for detecting khal date format // Process for detecting khal date format
@@ -91,22 +92,22 @@ Singleton {
running: false running: false
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) { if (exitCode !== 0) {
checkKhalAvailability() checkKhalAvailability();
} }
} }
stdout: StdioCollector { stdout: StdioCollector {
onStreamFinished: { onStreamFinished: {
let lines = text.split('\n') let lines = text.split('\n');
for (let line of lines) { for (let line of lines) {
if (line.startsWith('dateformat:')) { if (line.startsWith('dateformat:')) {
let formatExample = line.substring(line.indexOf(':') + 1).trim() let formatExample = line.substring(line.indexOf(':') + 1).trim();
let formatInfo = parseKhalDateFormat(formatExample) let formatInfo = parseKhalDateFormat(formatExample);
root.khalDateFormat = formatInfo.format root.khalDateFormat = formatInfo.format;
break break;
} }
} }
checkKhalAvailability() checkKhalAvailability();
} }
} }
} }
@@ -118,9 +119,9 @@ Singleton {
command: ["khal", "list", "today"] command: ["khal", "list", "today"]
running: false running: false
onExited: exitCode => { onExited: exitCode => {
root.khalAvailable = (exitCode === 0) root.khalAvailable = (exitCode === 0);
if (exitCode === 0) { if (exitCode === 0) {
loadCurrentMonth() loadCurrentMonth();
} }
} }
} }
@@ -135,100 +136,96 @@ Singleton {
running: false running: false
onExited: exitCode => { onExited: exitCode => {
root.isLoading = false root.isLoading = false;
if (exitCode !== 0) { if (exitCode !== 0) {
root.lastError = "Failed to load events (exit code: " + exitCode + ")" root.lastError = "Failed to load events (exit code: " + exitCode + ")";
return return;
} }
try { try {
let newEventsByDate = {} let newEventsByDate = {};
let lines = eventsProcess.rawOutput.split('\n') let lines = eventsProcess.rawOutput.split('\n');
for (let line of lines) { for (let line of lines) {
line = line.trim() line = line.trim();
if (!line || line === "[]") if (!line || line === "[]")
continue continue;
// Parse JSON line // Parse JSON line
let dayEvents = JSON.parse(line) let dayEvents = JSON.parse(line);
// Process each event in this day's array // Process each event in this day's array
for (let event of dayEvents) { for (let event of dayEvents) {
if (!event.title) if (!event.title)
continue continue;
// Parse start and end dates using detected format // Parse start and end dates using detected format
let startDate, endDate let startDate, endDate;
if (event['start-date']) { if (event['start-date']) {
startDate = Date.fromLocaleString(I18n.locale(), event['start-date'], root.khalDateFormat) startDate = Date.fromLocaleString(I18n.locale(), event['start-date'], root.khalDateFormat);
} else { } else {
startDate = new Date() startDate = new Date();
} }
if (event['end-date']) { if (event['end-date']) {
endDate = Date.fromLocaleString(I18n.locale(), event['end-date'], root.khalDateFormat) endDate = Date.fromLocaleString(I18n.locale(), event['end-date'], root.khalDateFormat);
} else { } else {
endDate = new Date(startDate) endDate = new Date(startDate);
} }
// Create start/end times // Create start/end times
let startTime = new Date(startDate) let startTime = new Date(startDate);
let endTime = new Date(endDate) let endTime = new Date(endDate);
if (event['start-time'] if (event['start-time'] && event['all-day'] !== "True") {
&& event['all-day'] !== "True") {
// Parse time if available and not all-day // Parse time if available and not all-day
let timeStr = event['start-time'] let timeStr = event['start-time'];
if (timeStr) { if (timeStr) {
// Match time with optional seconds and AM/PM // Match time with optional seconds and AM/PM
let timeParts = timeStr.match(/(\d+):(\d+)(?::\d+)?\s*(AM|PM)?/i) let timeParts = timeStr.match(/(\d+):(\d+)(?::\d+)?\s*(AM|PM)?/i);
if (timeParts) { if (timeParts) {
let hours = parseInt(timeParts[1]) let hours = parseInt(timeParts[1]);
let minutes = parseInt(timeParts[2]) let minutes = parseInt(timeParts[2]);
// Handle AM/PM conversion if present // Handle AM/PM conversion if present
if (timeParts[3]) { if (timeParts[3]) {
let period = timeParts[3].toUpperCase() let period = timeParts[3].toUpperCase();
if (period === 'PM' && hours !== 12) { if (period === 'PM' && hours !== 12) {
hours += 12 hours += 12;
} else if (period === 'AM' && hours === 12) { } else if (period === 'AM' && hours === 12) {
hours = 0 hours = 0;
} }
} }
startTime.setHours(hours, minutes) startTime.setHours(hours, minutes);
if (event['end-time']) { if (event['end-time']) {
let endTimeParts = event['end-time'].match( let endTimeParts = event['end-time'].match(/(\d+):(\d+)(?::\d+)?\s*(AM|PM)?/i);
/(\d+):(\d+)(?::\d+)?\s*(AM|PM)?/i)
if (endTimeParts) { if (endTimeParts) {
let endHours = parseInt(endTimeParts[1]) let endHours = parseInt(endTimeParts[1]);
let endMinutes = parseInt(endTimeParts[2]) let endMinutes = parseInt(endTimeParts[2]);
// Handle AM/PM conversion if present // Handle AM/PM conversion if present
if (endTimeParts[3]) { if (endTimeParts[3]) {
let endPeriod = endTimeParts[3].toUpperCase() let endPeriod = endTimeParts[3].toUpperCase();
if (endPeriod === 'PM' && endHours !== 12) { if (endPeriod === 'PM' && endHours !== 12) {
endHours += 12 endHours += 12;
} else if (endPeriod === 'AM' && endHours === 12) { } else if (endPeriod === 'AM' && endHours === 12) {
endHours = 0 endHours = 0;
} }
} }
endTime.setHours(endHours, endMinutes) endTime.setHours(endHours, endMinutes);
} }
} else { } else {
// Default to 1 hour duration on same day // Default to 1 hour duration on same day
endTime = new Date(startTime) endTime = new Date(startTime);
endTime.setHours( endTime.setHours(startTime.getHours() + 1);
startTime.getHours() + 1)
} }
} }
} }
} }
// Create unique ID for this event (to track multi-day events) // Create unique ID for this event (to track multi-day events)
let eventId = event.title + "_" + event['start-date'] let eventId = event.title + "_" + event['start-date'] + "_" + (event['start-time'] || 'allday');
+ "_" + (event['start-time'] || 'allday')
// Create event object template // Create event object template
let extractedUrl = "" let extractedUrl = "";
if (!event.url && event.description) { if (!event.url && event.description) {
let urlMatch = event.description.match(/https?:\/\/[^\s]+/) let urlMatch = event.description.match(/https?:\/\/[^\s]+/);
if (urlMatch) { if (urlMatch) {
extractedUrl = urlMatch[0] extractedUrl = urlMatch[0];
} }
} }
let eventTemplate = { let eventTemplate = {
@@ -242,75 +239,71 @@ Singleton {
"calendar": "", "calendar": "",
"color": "", "color": "",
"allDay": event['all-day'] === "True", "allDay": event['all-day'] === "True",
"isMultiDay": startDate.toDateString( "isMultiDay": startDate.toDateString() !== endDate.toDateString()
) !== endDate.toDateString() };
}
// Add event to each day it spans // Add event to each day it spans
let currentDate = new Date(startDate) let currentDate = new Date(startDate);
while (currentDate <= endDate) { while (currentDate <= endDate) {
let dateKey = Qt.formatDate(currentDate, let dateKey = Qt.formatDate(currentDate, "yyyy-MM-dd");
"yyyy-MM-dd")
if (!newEventsByDate[dateKey]) if (!newEventsByDate[dateKey])
newEventsByDate[dateKey] = [] newEventsByDate[dateKey] = [];
// Check if this exact event is already added to this date (prevent duplicates) // Check if this exact event is already added to this date (prevent duplicates)
let existingEvent = newEventsByDate[dateKey].find( let existingEvent = newEventsByDate[dateKey].find(e => {
e => { return e.id === eventId;
return e.id === eventId });
})
if (existingEvent) { if (existingEvent) {
// Move to next day without adding duplicate // Move to next day without adding duplicate
currentDate.setDate(currentDate.getDate() + 1) currentDate.setDate(currentDate.getDate() + 1);
continue continue;
} }
// Create a copy of the event for this date // Create a copy of the event for this date
let dayEvent = Object.assign({}, eventTemplate) let dayEvent = Object.assign({}, eventTemplate);
// For multi-day events, adjust the display time for this specific day // For multi-day events, adjust the display time for this specific day
if (currentDate.getTime() === startDate.getTime()) { if (currentDate.getTime() === startDate.getTime()) {
// First day - use original start time // First day - use original start time
dayEvent.start = new Date(startTime) dayEvent.start = new Date(startTime);
} else { } else {
// Subsequent days - start at beginning of day for all-day events // Subsequent days - start at beginning of day for all-day events
dayEvent.start = new Date(currentDate) dayEvent.start = new Date(currentDate);
if (!dayEvent.allDay) if (!dayEvent.allDay)
dayEvent.start.setHours(0, 0, 0, 0) dayEvent.start.setHours(0, 0, 0, 0);
} }
if (currentDate.getTime() === endDate.getTime()) { if (currentDate.getTime() === endDate.getTime()) {
// Last day - use original end time // Last day - use original end time
dayEvent.end = new Date(endTime) dayEvent.end = new Date(endTime);
} else { } else {
// Earlier days - end at end of day for all-day events // Earlier days - end at end of day for all-day events
dayEvent.end = new Date(currentDate) dayEvent.end = new Date(currentDate);
if (!dayEvent.allDay) if (!dayEvent.allDay)
dayEvent.end.setHours(23, 59, 59, 999) dayEvent.end.setHours(23, 59, 59, 999);
} }
newEventsByDate[dateKey].push(dayEvent) newEventsByDate[dateKey].push(dayEvent);
// Move to next day // Move to next day
currentDate.setDate(currentDate.getDate() + 1) currentDate.setDate(currentDate.getDate() + 1);
} }
} }
} }
// Sort events by start time within each date // Sort events by start time within each date
for (let dateKey in newEventsByDate) { for (let dateKey in newEventsByDate) {
newEventsByDate[dateKey].sort((a, b) => { newEventsByDate[dateKey].sort((a, b) => {
return a.start.getTime( return a.start.getTime() - b.start.getTime();
) - b.start.getTime() });
})
} }
root.eventsByDate = newEventsByDate root.eventsByDate = newEventsByDate;
root.lastError = "" root.lastError = "";
} catch (error) { } catch (error) {
root.lastError = "Failed to parse events JSON: " + error.toString() root.lastError = "Failed to parse events JSON: " + error.toString();
root.eventsByDate = {} root.eventsByDate = {};
} }
// Reset for next run // Reset for next run
eventsProcess.rawOutput = "" eventsProcess.rawOutput = "";
} }
stdout: SplitParser { stdout: SplitParser {
splitMarker: "\n" splitMarker: "\n"
onRead: data => { onRead: data => {
eventsProcess.rawOutput += data + "\n" eventsProcess.rawOutput += data + "\n";
} }
} }
} }

View File

@@ -6,9 +6,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("ChangelogService")
readonly property string currentVersion: "1.4" readonly property string currentVersion: "1.4"
readonly property bool changelogEnabled: false readonly property bool changelogEnabled: false
@@ -101,7 +103,7 @@ Singleton {
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("ChangelogService: Failed to create changelog marker"); log.warn("Failed to create changelog marker");
} }
} }
} }

View File

@@ -5,9 +5,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("ClipboardService")
readonly property int longTextThreshold: 200 readonly property int longTextThreshold: 200
@@ -78,7 +80,7 @@ Singleton {
} }
DMSService.sendRequest("clipboard.getHistory", null, function (response) { DMSService.sendRequest("clipboard.getHistory", null, function (response) {
if (response.error) { if (response.error) {
console.warn("ClipboardService: Failed to get history:", response.error); log.warn("Failed to get history:", response.error);
return; return;
} }
internalEntries = response.result || []; internalEntries = response.result || [];
@@ -144,7 +146,7 @@ Singleton {
"id": entry.id "id": entry.id
}, function (response) { }, function (response) {
if (response.error) { if (response.error) {
console.warn("ClipboardService: Failed to delete entry:", response.error); log.warn("Failed to delete entry:", response.error);
return; return;
} }
internalEntries = internalEntries.filter(e => e.id !== entry.id); internalEntries = internalEntries.filter(e => e.id !== entry.id);
@@ -169,7 +171,7 @@ Singleton {
"id": entry.id "id": entry.id
}, function (response) { }, function (response) {
if (response.error) { if (response.error) {
console.warn("ClipboardService: Failed to delete entry:", response.error); log.warn("Failed to delete entry:", response.error);
return; return;
} }
internalEntries = internalEntries.filter(e => e.id !== entry.id); internalEntries = internalEntries.filter(e => e.id !== entry.id);
@@ -223,7 +225,7 @@ Singleton {
const savedCount = pinnedCount; const savedCount = pinnedCount;
DMSService.sendRequest("clipboard.clearHistory", null, function (response) { DMSService.sendRequest("clipboard.clearHistory", null, function (response) {
if (response.error) { if (response.error) {
console.warn("ClipboardService: Failed to clear history:", response.error); log.warn("Failed to clear history:", response.error);
return; return;
} }
refresh(); refresh();

View File

@@ -7,9 +7,11 @@ import Quickshell.I3
import Quickshell.Wayland import Quickshell.Wayland
import Quickshell.Hyprland import Quickshell.Hyprland
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("CompositorService")
property bool isHyprland: false property bool isHyprland: false
property bool isNiri: false property bool isNiri: false
@@ -52,7 +54,7 @@ Singleton {
randrScales = scales; randrScales = scales;
} }
} catch (e) { } catch (e) {
console.warn("CompositorService: failed to parse randr data:", e); log.warn("failed to parse randr data:", e);
} }
} }
randrReady = true; randrReady = true;
@@ -379,9 +381,7 @@ Singleton {
const focusedWin = NiriService.windows.find(nw => nw.is_focused); const focusedWin = NiriService.windows.find(nw => nw.is_focused);
if (!focusedWin) if (!focusedWin)
return []; return [];
const screenWsIds = new Set( const screenWsIds = new Set(NiriService.allWorkspaces.filter(ws => ws.output === screenName).map(ws => ws.id));
NiriService.allWorkspaces.filter(ws => ws.output === screenName).map(ws => ws.id)
);
return screenWsIds.has(focusedWin.workspace_id) ? toplevels : []; return screenWsIds.has(focusedWin.workspace_id) ? toplevels : [];
} }
return NiriService.filterCurrentDisplay(toplevels, screenName); return NiriService.filterCurrentDisplay(toplevels, screenName);
@@ -454,7 +454,7 @@ Singleton {
} }
} }
} catch (e) { } catch (e) {
console.warn("CompositorService: workspace snapshot failed:", e); log.warn("workspace snapshot failed:", e);
} }
if (currentWorkspaceId === null) if (currentWorkspaceId === null)
@@ -498,7 +498,7 @@ Singleton {
isMiracle = false; isMiracle = false;
isLabwc = false; isLabwc = false;
compositor = "hyprland"; compositor = "hyprland";
console.info("CompositorService: Detected Hyprland"); log.info("Detected Hyprland");
return; return;
} }
@@ -513,7 +513,7 @@ Singleton {
isMiracle = false; isMiracle = false;
isLabwc = false; isLabwc = false;
compositor = "niri"; compositor = "niri";
console.info("CompositorService: Detected Niri with socket:", niriSocket); log.info("Detected Niri with socket:", niriSocket);
NiriService.generateNiriBlurrule(); NiriService.generateNiriBlurrule();
} }
}, 0); }, 0);
@@ -531,7 +531,7 @@ Singleton {
isMiracle = false; isMiracle = false;
isLabwc = false; isLabwc = false;
compositor = "sway"; compositor = "sway";
console.info("CompositorService: Detected Sway with socket:", swaySocket); log.info("Detected Sway with socket:", swaySocket);
} }
}, 0); }, 0);
return; return;
@@ -548,7 +548,7 @@ Singleton {
isMiracle = true; isMiracle = true;
isLabwc = false; isLabwc = false;
compositor = "miracle"; compositor = "miracle";
console.info("CompositorService: Detected Miracle WM with socket:", miracleSocket); log.info("Detected Miracle WM with socket:", miracleSocket);
} }
}, 0); }, 0);
return; return;
@@ -565,7 +565,7 @@ Singleton {
isMiracle = false; isMiracle = false;
isLabwc = false; isLabwc = false;
compositor = "scroll"; compositor = "scroll";
console.info("CompositorService: Detected Scroll with socket:", scrollSocket); log.info("Detected Scroll with socket:", scrollSocket);
} }
}, 0); }, 0);
return; return;
@@ -580,7 +580,7 @@ Singleton {
isMiracle = false; isMiracle = false;
isLabwc = true; isLabwc = true;
compositor = "labwc"; compositor = "labwc";
console.info("CompositorService: Detected LabWC with PID:", labwcPid); log.info("Detected LabWC with PID:", labwcPid);
return; return;
} }
@@ -595,7 +595,7 @@ Singleton {
isMiracle = false; isMiracle = false;
isLabwc = false; isLabwc = false;
compositor = "unknown"; compositor = "unknown";
console.warn("CompositorService: No compositor detected"); log.warn("No compositor detected");
} }
} }
@@ -618,7 +618,7 @@ Singleton {
isMiracle = false; isMiracle = false;
isLabwc = false; isLabwc = false;
compositor = "dwl"; compositor = "dwl";
console.info("CompositorService: Detected DWL via DMS capability"); log.info("Detected DWL via DMS capability");
} }
} }
@@ -638,7 +638,7 @@ Singleton {
if (isLabwc) { if (isLabwc) {
Quickshell.execDetached(["dms", "dpms", "off"]); Quickshell.execDetached(["dms", "dpms", "off"]);
} }
console.warn("CompositorService: Cannot power off monitors, unknown compositor"); log.warn("Cannot power off monitors, unknown compositor");
} }
function powerOnMonitors() { function powerOnMonitors() {
@@ -657,12 +657,12 @@ Singleton {
if (isLabwc) { if (isLabwc) {
Quickshell.execDetached(["dms", "dpms", "on"]); Quickshell.execDetached(["dms", "dpms", "on"]);
} }
console.warn("CompositorService: Cannot power on monitors, unknown compositor"); log.warn("Cannot power on monitors, unknown compositor");
} }
function _dwlPowerOffMonitors() { function _dwlPowerOffMonitors() {
if (!Quickshell.screens || Quickshell.screens.length === 0) { if (!Quickshell.screens || Quickshell.screens.length === 0) {
console.warn("CompositorService: No screens available for DWL power off"); log.warn("No screens available for DWL power off");
return; return;
} }
@@ -676,7 +676,7 @@ Singleton {
function _dwlPowerOnMonitors() { function _dwlPowerOnMonitors() {
if (!Quickshell.screens || Quickshell.screens.length === 0) { if (!Quickshell.screens || Quickshell.screens.length === 0) {
console.warn("CompositorService: No screens available for DWL power on"); log.warn("No screens available for DWL power on");
return; return;
} }

View File

@@ -4,9 +4,11 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import Quickshell import Quickshell
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("CupsService")
property int refCount: 0 property int refCount: 0
@@ -205,7 +207,7 @@ Singleton {
enabled: DMSService.isConnected enabled: DMSService.isConnected
function onCupsStateUpdate(data) { function onCupsStateUpdate(data) {
console.log("CupsService: Subscription update received"); log.debug("Subscription update received");
getState(); getState();
} }

View File

@@ -4,9 +4,11 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import Quickshell import Quickshell
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("DMSNetworkService")
property bool networkAvailable: false property bool networkAvailable: false
property string backend: "" property string backend: ""
@@ -141,7 +143,7 @@ Singleton {
function onNetworkStateUpdate(data) { function onNetworkStateUpdate(data) {
const networksCount = data.wifiNetworks?.length ?? "null"; const networksCount = data.wifiNetworks?.length ?? "null";
console.log("DMSNetworkService: Subscription update received, networks:", networksCount); log.debug("Subscription update received, networks:", networksCount);
updateState(data); updateState(data);
} }
} }
@@ -301,7 +303,7 @@ Singleton {
const timeout = 30000; const timeout = 30000;
if (busyDuration > timeout) { if (busyDuration > timeout) {
console.warn("DMSNetworkService: VPN operation timed out after", timeout, "ms"); log.warn("VPN operation timed out after", timeout, "ms");
vpnIsBusy = false; vpnIsBusy = false;
pendingVpnUuid = ""; pendingVpnUuid = "";
vpnBusyStartTime = 0; vpnBusyStartTime = 0;
@@ -331,7 +333,7 @@ Singleton {
if (pendingConnectionSSID) { if (pendingConnectionSSID) {
if (wifiConnected && currentWifiSSID === pendingConnectionSSID && wifiIP) { if (wifiConnected && currentWifiSSID === pendingConnectionSSID && wifiIP) {
const elapsed = Date.now() - pendingConnectionStartTime; const elapsed = Date.now() - pendingConnectionStartTime;
console.info("DMSNetworkService: Successfully connected to", pendingConnectionSSID, "in", elapsed, "ms"); log.info("Successfully connected to", pendingConnectionSSID, "in", elapsed, "ms");
ToastService.showInfo(`Connected to ${pendingConnectionSSID}`); ToastService.showInfo(`Connected to ${pendingConnectionSSID}`);
if (userPreference === "wifi" || userPreference === "auto") { if (userPreference === "wifi" || userPreference === "auto") {
@@ -402,7 +404,7 @@ Singleton {
DMSService.sendRequest("network.wifi.scan", params, response => { DMSService.sendRequest("network.wifi.scan", params, response => {
isScanning = false; isScanning = false;
if (response.error) { if (response.error) {
console.warn("DMSNetworkService: WiFi scan failed:", response.error); log.warn("WiFi scan failed:", response.error);
} else { } else {
Qt.callLater(() => getState()); Qt.callLater(() => getState());
} }
@@ -485,10 +487,10 @@ Singleton {
} }
function submitCredentials(token, secrets, save) { function submitCredentials(token, secrets, save) {
console.log("submitCredentials: networkAvailable=" + networkAvailable + " apiVersion=" + DMSService.apiVersion); log.debug("submitCredentials: networkAvailable=" + networkAvailable + " apiVersion=" + DMSService.apiVersion);
if (!networkAvailable || DMSService.apiVersion < 7) { if (!networkAvailable || DMSService.apiVersion < 7) {
console.warn("submitCredentials: Aborting - networkAvailable=" + networkAvailable + " apiVersion=" + DMSService.apiVersion); log.warn("submitCredentials: Aborting - networkAvailable=" + networkAvailable + " apiVersion=" + DMSService.apiVersion);
return; return;
} }
@@ -502,7 +504,7 @@ Singleton {
DMSService.sendRequest("network.credentials.submit", params, response => { DMSService.sendRequest("network.credentials.submit", params, response => {
if (response.error) { if (response.error) {
console.warn("DMSNetworkService: Failed to submit credentials:", response.error); log.warn("Failed to submit credentials:", response.error);
} }
}); });
} }
@@ -520,7 +522,7 @@ Singleton {
DMSService.sendRequest("network.credentials.cancel", params, response => { DMSService.sendRequest("network.credentials.cancel", params, response => {
if (response.error) { if (response.error) {
console.warn("DMSNetworkService: Failed to cancel credentials:", response.error); log.warn("Failed to cancel credentials:", response.error);
} }
}); });
} }
@@ -533,7 +535,7 @@ Singleton {
ssid: ssid ssid: ssid
}, response => { }, response => {
if (response.error) { if (response.error) {
console.warn("Failed to forget network:", response.error); log.warn("Failed to forget network:", response.error);
} else { } else {
ToastService.showInfo(I18n.tr("Forgot network %1").arg(ssid)); ToastService.showInfo(I18n.tr("Forgot network %1").arg(ssid));
@@ -565,7 +567,7 @@ Singleton {
wifiToggling = false; wifiToggling = false;
if (response.error) { if (response.error) {
console.warn("Failed to toggle WiFi:", response.error); log.warn("Failed to toggle WiFi:", response.error);
} else if (response.result) { } else if (response.result) {
wifiEnabled = response.result.enabled; wifiEnabled = response.result.enabled;
ToastService.showInfo(wifiEnabled ? I18n.tr("WiFi enabled") : I18n.tr("WiFi disabled")); ToastService.showInfo(wifiEnabled ? I18n.tr("WiFi enabled") : I18n.tr("WiFi disabled"));
@@ -600,7 +602,7 @@ Singleton {
targetPreference = ""; targetPreference = "";
if (response.error) { if (response.error) {
console.warn("Failed to set network preference:", response.error); log.warn("Failed to set network preference:", response.error);
} }
}); });
} }

View File

@@ -5,9 +5,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("DMSService")
property bool dmsAvailable: false property bool dmsAvailable: false
property var capabilities: [] property var capabilities: []
@@ -198,14 +200,14 @@ Singleton {
try { try {
response = JSON.parse(line); response = JSON.parse(line);
} catch (e) { } catch (e) {
console.warn("DMSService: Failed to parse request response:", line.substring(0, 100)); log.warn("Failed to parse request response:", line.substring(0, 100));
return; return;
} }
const isClipboard = clipboardRequestIds[response.id]; const isClipboard = clipboardRequestIds[response.id];
if (isClipboard) if (isClipboard)
delete clipboardRequestIds[response.id]; delete clipboardRequestIds[response.id];
else else
console.log("DMSService: Request socket <<", line); log.debug("Request socket <<", line);
handleResponse(response); handleResponse(response);
} }
} }
@@ -232,11 +234,11 @@ Singleton {
try { try {
response = JSON.parse(line); response = JSON.parse(line);
} catch (e) { } catch (e) {
console.warn("DMSService: Failed to parse subscription event:", line.substring(0, 100)); log.warn("Failed to parse subscription event:", line.substring(0, 100));
return; return;
} }
if (!line.includes("clipboard")) if (!line.includes("clipboard"))
console.log("DMSService: Subscribe socket <<", line); log.debug("Subscribe socket <<", line);
handleSubscriptionEvent(response); handleSubscriptionEvent(response);
} }
} }
@@ -251,9 +253,9 @@ Singleton {
request.params = { request.params = {
"services": activeSubscriptions "services": activeSubscriptions
}; };
console.log("DMSService: Subscribing to services:", JSON.stringify(activeSubscriptions)); log.debug("Subscribing to services:", JSON.stringify(activeSubscriptions));
} else { } else {
console.log("DMSService: Subscribing to all services"); log.debug("Subscribing to all services");
} }
subscribeSocket.send(request); subscribeSocket.send(request);
@@ -291,7 +293,7 @@ Singleton {
} else { } else {
const filtered = activeSubscriptions.filter(s => s !== service); const filtered = activeSubscriptions.filter(s => s !== service);
if (filtered.length === 0) { if (filtered.length === 0) {
console.warn("DMSService: Cannot remove last subscription"); log.warn("Cannot remove last subscription");
return; return;
} }
subscribe(filtered); subscribe(filtered);
@@ -316,7 +318,7 @@ Singleton {
if (response.error) { if (response.error) {
if (response.error.includes("unknown method") && response.error.includes("subscribe")) { if (response.error.includes("unknown method") && response.error.includes("subscribe")) {
if (!shownOutdatedError) { if (!shownOutdatedError) {
console.error("DMSService: Server does not support subscribe method"); log.error("Server does not support subscribe method");
ToastService.showError(I18n.tr("DMS out of date"), I18n.tr("To update, run the following command:"), updateCommand); ToastService.showError(I18n.tr("DMS out of date"), I18n.tr("To update, run the following command:"), updateCommand);
shownOutdatedError = true; shownOutdatedError = true;
} }
@@ -336,7 +338,7 @@ Singleton {
cliVersion = data.cliVersion || ""; cliVersion = data.cliVersion || "";
capabilities = data.capabilities || []; capabilities = data.capabilities || [];
console.info("DMSService: Connected (API v" + apiVersion + ", CLI " + cliVersion + ") -", JSON.stringify(capabilities)); log.info("Connected (API v" + apiVersion + ", CLI " + cliVersion + ") -", JSON.stringify(capabilities));
if (apiVersion < expectedApiVersion) { if (apiVersion < expectedApiVersion) {
ToastService.showError("DMS server is outdated (API v" + apiVersion + ", expected v" + expectedApiVersion + ")"); ToastService.showError("DMS server is outdated (API v" + apiVersion + ", expected v" + expectedApiVersion + ")");
@@ -401,7 +403,7 @@ Singleton {
function sendRequest(method, params, callback) { function sendRequest(method, params, callback) {
if (!isConnected) { if (!isConnected) {
console.warn("DMSService.sendRequest: Not connected, method:", method); log.warn("DMSService.sendRequest: Not connected, method:", method);
if (callback) { if (callback) {
callback({ callback({
"error": "not connected to DMS socket" "error": "not connected to DMS socket"
@@ -427,7 +429,7 @@ Singleton {
if (method.startsWith("clipboard")) { if (method.startsWith("clipboard")) {
clipboardRequestIds[id] = true; clipboardRequestIds[id] = true;
} else { } else {
console.log("DMSService.sendRequest: Sending request id=" + id + " method=" + method); log.debug("DMSService.sendRequest: Sending request id=" + id + " method=" + method);
} }
requestSocket.send(request); requestSocket.send(request);
} }

View File

@@ -1,10 +1,8 @@
pragma Singleton pragma Singleton
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Io
Singleton { Singleton {
id: root id: root

View File

@@ -5,9 +5,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("DgopService")
property int refCount: 0 property int refCount: 0
property int updateInterval: refCount > 0 ? 3000 : 30000 property int updateInterval: refCount > 0 ? 3000 : 30000
@@ -643,7 +645,7 @@ Singleton {
onStarted: dgopProcessPid = processId ?? 0 onStarted: dgopProcessPid = processId ?? 0
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("Dgop process failed with exit code:", exitCode); log.warn("Dgop process failed with exit code:", exitCode);
isUpdating = false; isUpdating = false;
} }
} }
@@ -654,8 +656,8 @@ Singleton {
const data = JSON.parse(text.trim()); const data = JSON.parse(text.trim());
parseData(data); parseData(data);
} catch (e) { } catch (e) {
console.warn("Failed to parse dgop JSON:", e); log.warn("Failed to parse dgop JSON:", e);
console.warn("Raw text was:", text.substring(0, 200)); log.warn("Raw text was:", text.substring(0, 200));
isUpdating = false; isUpdating = false;
} }
} }
@@ -669,7 +671,7 @@ Singleton {
running: false running: false
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("GPU init process failed with exit code:", exitCode); log.warn("GPU init process failed with exit code:", exitCode);
} }
} }
stdout: StdioCollector { stdout: StdioCollector {
@@ -679,7 +681,7 @@ Singleton {
const data = JSON.parse(text.trim()); const data = JSON.parse(text.trim());
parseData(data); parseData(data);
} catch (e) { } catch (e) {
console.warn("Failed to parse GPU init JSON:", e); log.warn("Failed to parse GPU init JSON:", e);
} }
} }
} }
@@ -692,7 +694,7 @@ Singleton {
running: false running: false
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("System init process failed with exit code:", exitCode); log.warn("System init process failed with exit code:", exitCode);
} }
} }
stdout: StdioCollector { stdout: StdioCollector {
@@ -702,7 +704,7 @@ Singleton {
const data = JSON.parse(text.trim()); const data = JSON.parse(text.trim());
parseData(data); parseData(data);
} catch (e) { } catch (e) {
console.warn("Failed to parse system init JSON:", e); log.warn("Failed to parse system init JSON:", e);
} }
} }
} }
@@ -727,7 +729,7 @@ Singleton {
} }
} }
} else { } else {
console.warn("dgop is not installed or not in PATH"); log.warn("dgop is not installed or not in PATH");
} }
} }
} }
@@ -738,7 +740,7 @@ Singleton {
running: false running: false
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("Failed to read /etc/os-release"); log.warn("Failed to read /etc/os-release");
} }
} }
stdout: StdioCollector { stdout: StdioCollector {
@@ -761,9 +763,9 @@ Singleton {
// Prefer PRETTY_NAME, fallback to NAME // Prefer PRETTY_NAME, fallback to NAME
const distroName = prettyName || name || "Linux"; const distroName = prettyName || name || "Linux";
distribution = distroName; distribution = distroName;
console.info("Detected distribution:", distroName); log.info("Detected distribution:", distroName);
} catch (e) { } catch (e) {
console.warn("Failed to parse /etc/os-release:", e); log.warn("Failed to parse /etc/os-release:", e);
distribution = "Linux"; distribution = "Linux";
} }
} }

View File

@@ -5,9 +5,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("DisplayService")
property bool brightnessAvailable: devices.length > 0 property bool brightnessAvailable: devices.length > 0
property var devices: [] property var devices: []
@@ -247,7 +249,7 @@ Singleton {
function setBrightness(percentage, device, suppressOsd) { function setBrightness(percentage, device, suppressOsd) {
const actualDevice = device === "" ? getDefaultDevice() : (device || currentDevice || getDefaultDevice()); const actualDevice = device === "" ? getDefaultDevice() : (device || currentDevice || getDefaultDevice());
if (!actualDevice) { if (!actualDevice) {
console.warn("DisplayService: No device selected for brightness change"); log.warn("No device selected for brightness change");
return; return;
} }
@@ -273,14 +275,14 @@ Singleton {
} }
if (maxValue <= 0) { if (maxValue <= 0) {
console.warn("DisplayService: Invalid max value for device", actualDevice, "- skipping brightness change"); log.warn("Invalid max value for device", actualDevice, "- skipping brightness change");
return; return;
} }
const clampedValue = Math.max(minValue, Math.min(maxValue, percentage)); const clampedValue = Math.max(minValue, Math.min(maxValue, percentage));
if (!DMSService.isConnected) { if (!DMSService.isConnected) {
console.warn("DisplayService: Not connected to DMS"); log.warn("Not connected to DMS");
return; return;
} }
@@ -319,7 +321,7 @@ Singleton {
DMSService.sendRequest("brightness.setBrightness", params, response => { DMSService.sendRequest("brightness.setBrightness", params, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to set brightness:", response.error); log.error("Failed to set brightness:", response.error);
ToastService.showError(I18n.tr("Failed to set brightness"), response.error, "", "brightness"); ToastService.showError(I18n.tr("Failed to set brightness"), response.error, "", "brightness");
} else { } else {
ToastService.dismissCategory("brightness"); ToastService.dismissCategory("brightness");
@@ -453,7 +455,7 @@ Singleton {
"enabled": true "enabled": true
}, response => { }, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to enable gamma control:", response.error); log.error("Failed to enable gamma control:", response.error);
ToastService.showError(I18n.tr("Failed to enable night mode"), response.error, "", "night-mode"); ToastService.showError(I18n.tr("Failed to enable night mode"), response.error, "", "night-mode");
nightModeEnabled = false; nightModeEnabled = false;
SessionData.setNightModeEnabled(false); SessionData.setNightModeEnabled(false);
@@ -481,7 +483,7 @@ Singleton {
"enabled": false "enabled": false
}, response => { }, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to disable gamma control:", response.error); log.error("Failed to disable gamma control:", response.error);
ToastService.showError(I18n.tr("Failed to disable night mode"), response.error, "", "night-mode"); ToastService.showError(I18n.tr("Failed to disable night mode"), response.error, "", "night-mode");
} else { } else {
ToastService.dismissCategory("night-mode"); ToastService.dismissCategory("night-mode");
@@ -505,7 +507,7 @@ Singleton {
"sunset": null "sunset": null
}, response => { }, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to clear manual times:", response.error); log.error("Failed to clear manual times:", response.error);
return; return;
} }
@@ -513,7 +515,7 @@ Singleton {
"use": false "use": false
}, response => { }, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to disable IP location:", response.error); log.error("Failed to disable IP location:", response.error);
return; return;
} }
@@ -522,7 +524,7 @@ Singleton {
"high": temperature "high": temperature
}, response => { }, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to set temperature:", response.error); log.error("Failed to set temperature:", response.error);
ToastService.showError(I18n.tr("Failed to set night mode temperature"), response.error, "", "night-mode"); ToastService.showError(I18n.tr("Failed to set night mode temperature"), response.error, "", "night-mode");
} else { } else {
ToastService.dismissCategory("night-mode"); ToastService.dismissCategory("night-mode");
@@ -564,7 +566,7 @@ Singleton {
"use": false "use": false
}, response => { }, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to disable IP location:", response.error); log.error("Failed to disable IP location:", response.error);
return; return;
} }
@@ -573,7 +575,7 @@ Singleton {
"high": highTemp "high": highTemp
}, response => { }, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to set temperature:", response.error); log.error("Failed to set temperature:", response.error);
ToastService.showError(I18n.tr("Failed to set night mode temperature"), response.error, "", "night-mode"); ToastService.showError(I18n.tr("Failed to set night mode temperature"), response.error, "", "night-mode");
return; return;
} }
@@ -583,7 +585,7 @@ Singleton {
"sunset": sunset "sunset": sunset
}, response => { }, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to set manual times:", response.error); log.error("Failed to set manual times:", response.error);
ToastService.showError(I18n.tr("Failed to set night mode schedule"), response.error, "", "night-mode"); ToastService.showError(I18n.tr("Failed to set night mode schedule"), response.error, "", "night-mode");
} else { } else {
ToastService.dismissCategory("night-mode"); ToastService.dismissCategory("night-mode");
@@ -602,7 +604,7 @@ Singleton {
"sunset": null "sunset": null
}, response => { }, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to clear manual times:", response.error); log.error("Failed to clear manual times:", response.error);
return; return;
} }
@@ -611,7 +613,7 @@ Singleton {
"high": highTemp "high": highTemp
}, response => { }, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to set temperature:", response.error); log.error("Failed to set temperature:", response.error);
ToastService.showError(I18n.tr("Failed to set night mode temperature"), response.error, "", "night-mode"); ToastService.showError(I18n.tr("Failed to set night mode temperature"), response.error, "", "night-mode");
return; return;
} }
@@ -621,7 +623,7 @@ Singleton {
"use": true "use": true
}, response => { }, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to enable IP location:", response.error); log.error("Failed to enable IP location:", response.error);
ToastService.showError(I18n.tr("Failed to enable IP location"), response.error, "", "night-mode"); ToastService.showError(I18n.tr("Failed to enable IP location"), response.error, "", "night-mode");
} else { } else {
ToastService.dismissCategory("night-mode"); ToastService.dismissCategory("night-mode");
@@ -632,7 +634,7 @@ Singleton {
"use": false "use": false
}, response => { }, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to disable IP location:", response.error); log.error("Failed to disable IP location:", response.error);
return; return;
} }
@@ -641,7 +643,7 @@ Singleton {
"longitude": SessionData.longitude "longitude": SessionData.longitude
}, response => { }, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to set location:", response.error); log.error("Failed to set location:", response.error);
ToastService.showError(I18n.tr("Failed to set night mode location"), response.error, "", "night-mode"); ToastService.showError(I18n.tr("Failed to set night mode location"), response.error, "", "night-mode");
} else { } else {
ToastService.dismissCategory("night-mode"); ToastService.dismissCategory("night-mode");
@@ -649,7 +651,7 @@ Singleton {
}); });
}); });
} else { } else {
console.warn("DisplayService: Location mode selected but no coordinates set and IP location disabled"); log.warn("Location mode selected but no coordinates set and IP location disabled");
} }
}); });
}); });
@@ -703,7 +705,7 @@ Singleton {
if (response.error) { if (response.error) {
gammaControlAvailable = false; gammaControlAvailable = false;
automationAvailable = false; automationAvailable = false;
console.error("DisplayService: Gamma control not available:", response.error); log.error("Gamma control not available:", response.error);
} else { } else {
gammaControlAvailable = true; gammaControlAvailable = true;
automationAvailable = true; automationAvailable = true;
@@ -713,7 +715,7 @@ Singleton {
"enabled": true "enabled": true
}, enableResponse => { }, enableResponse => {
if (enableResponse.error) { if (enableResponse.error) {
console.error("DisplayService: Failed to enable gamma control on startup:", enableResponse.error); log.error("Failed to enable gamma control on startup:", enableResponse.error);
return; return;
} }
@@ -772,7 +774,7 @@ Singleton {
DMSService.sendRequest("brightness.rescan", null, response => { DMSService.sendRequest("brightness.rescan", null, response => {
if (response.error) { if (response.error) {
console.error("DisplayService: Failed to rescan brightness devices:", response.error); log.error("Failed to rescan brightness devices:", response.error);
} }
}); });
} }

View File

@@ -6,9 +6,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("DwlService")
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation))
readonly property string mangoDmsDir: configDir + "/mango/dms" readonly property string mangoDmsDir: configDir + "/mango/dms"
@@ -91,7 +93,7 @@ Singleton {
const hasDwl = DMSService.capabilities.includes("dwl"); const hasDwl = DMSService.capabilities.includes("dwl");
if (hasDwl && !dwlAvailable) { if (hasDwl && !dwlAvailable) {
dwlAvailable = true; dwlAvailable = true;
console.info("DwlService: DWL capability detected"); log.info("DWL capability detected");
requestState(); requestState();
refreshOutputScales(); refreshOutputScales();
} else if (!hasDwl) { } else if (!hasDwl) {
@@ -130,7 +132,7 @@ Singleton {
"toggleTagset": toggleTagset "toggleTagset": toggleTagset
}, response => { }, response => {
if (response.error) { if (response.error) {
console.warn("DwlService: setTags error:", response.error); log.warn("setTags error:", response.error);
} }
}); });
} }
@@ -146,7 +148,7 @@ Singleton {
"xorTags": xorTags "xorTags": xorTags
}, response => { }, response => {
if (response.error) { if (response.error) {
console.warn("DwlService: setClientTags error:", response.error); log.warn("setClientTags error:", response.error);
} }
}); });
} }
@@ -161,7 +163,7 @@ Singleton {
"index": index "index": index
}, response => { }, response => {
if (response.error) { if (response.error) {
console.warn("DwlService: setLayout error:", response.error); log.warn("setLayout error:", response.error);
} }
}); });
} }
@@ -205,7 +207,7 @@ Singleton {
function toggleTag(outputName, tagIndex) { function toggleTag(outputName, tagIndex) {
const output = getOutputState(outputName); const output = getOutputState(outputName);
if (!output || !output.tags) { if (!output || !output.tags) {
console.log("toggleTag: no output or tags for", outputName); log.debug("toggleTag: no output or tags for", outputName);
return; return;
} }
@@ -219,13 +221,13 @@ Singleton {
const clickedMask = 1 << tagIndex; const clickedMask = 1 << tagIndex;
const newMask = currentMask ^ clickedMask; const newMask = currentMask ^ clickedMask;
console.log("toggleTag:", outputName, "tag:", tagIndex, "currentMask:", currentMask.toString(2), "clickedMask:", clickedMask.toString(2), "newMask:", newMask.toString(2)); log.debug("toggleTag:", outputName, "tag:", tagIndex, "currentMask:", currentMask.toString(2), "clickedMask:", clickedMask.toString(2), "newMask:", newMask.toString(2));
if (newMask === 0) { if (newMask === 0) {
console.log("toggleTag: newMask is 0, switching to tag", tagIndex); log.debug("toggleTag: newMask is 0, switching to tag", tagIndex);
setTags(outputName, 1 << tagIndex, 0); setTags(outputName, 1 << tagIndex, 0);
} else { } else {
console.log("toggleTag: setting combined mask", newMask); log.debug("toggleTag: setting combined mask", newMask);
setTags(outputName, newMask, 0); setTags(outputName, newMask, 0);
} }
} }
@@ -256,14 +258,14 @@ Singleton {
} }
outputScales = newScales; outputScales = newScales;
} catch (e) { } catch (e) {
console.warn("DwlService: Failed to parse mmsg output:", e); log.warn("Failed to parse mmsg output:", e);
} }
} }
} }
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("DwlService: mmsg failed with exit code:", exitCode); log.warn("mmsg failed with exit code:", exitCode);
} }
} }
} }
@@ -333,10 +335,10 @@ Singleton {
Proc.runCommand("mango-write-outputs", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { Proc.runCommand("mango-write-outputs", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("DwlService: Failed to write outputs config:", output); log.warn("Failed to write outputs config:", output);
return; return;
} }
console.info("DwlService: Generated outputs config at", outputsPath); log.info("Generated outputs config at", outputsPath);
if (CompositorService.isDwl) if (CompositorService.isDwl)
reloadConfig(); reloadConfig();
}); });
@@ -345,7 +347,7 @@ Singleton {
function reloadConfig() { function reloadConfig() {
Proc.runCommand("mango-reload", ["mmsg", "-d", "reload_config"], (output, exitCode) => { Proc.runCommand("mango-reload", ["mmsg", "-d", "reload_config"], (output, exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("DwlService: mmsg reload_config failed:", output); log.warn("mmsg reload_config failed:", output);
}); });
} }
@@ -372,10 +374,10 @@ borderpx=${borderSize}
Proc.runCommand("mango-write-layout", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { Proc.runCommand("mango-write-layout", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("DwlService: Failed to write layout config:", output); log.warn("Failed to write layout config:", output);
return; return;
} }
console.info("DwlService: Generated layout config at", layoutPath); log.info("Generated layout config at", layoutPath);
reloadConfig(); reloadConfig();
}); });
} }
@@ -407,13 +409,13 @@ borderpx=${borderSize}
if (!CompositorService.isDwl) if (!CompositorService.isDwl)
return; return;
console.log("DwlService: Generating cursor config..."); log.debug("Generating cursor config...");
const settings = typeof SettingsData !== "undefined" ? SettingsData.cursorSettings : null; const settings = typeof SettingsData !== "undefined" ? SettingsData.cursorSettings : null;
if (!settings) { if (!settings) {
Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => { Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("DwlService: Failed to write cursor config:", output); log.warn("Failed to write cursor config:", output);
}); });
return; return;
} }
@@ -426,7 +428,7 @@ borderpx=${borderSize}
if (isDefaultConfig) { if (isDefaultConfig) {
Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => { Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("DwlService: Failed to write cursor config:", output); log.warn("Failed to write cursor config:", output);
}); });
return; return;
} }
@@ -444,10 +446,10 @@ cursor_size=${size}`;
Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${cursorPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && cat > "${cursorPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("DwlService: Failed to write cursor config:", output); log.warn("Failed to write cursor config:", output);
return; return;
} }
console.info("DwlService: Generated cursor config at", cursorPath); log.info("Generated cursor config at", cursorPath);
reloadConfig(); reloadConfig();
}); });
} }

View File

@@ -3,9 +3,11 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import Quickshell import Quickshell
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("ExtWorkspaceService")
property bool extWorkspaceAvailable: false property bool extWorkspaceAvailable: false
property var groups: [] property var groups: []
@@ -49,13 +51,13 @@ Singleton {
if (typeof CompositorService !== "undefined") { if (typeof CompositorService !== "undefined") {
const useExtWorkspace = DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && !CompositorService.isMiracle); const useExtWorkspace = DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && !CompositorService.isMiracle);
if (!useExtWorkspace) { if (!useExtWorkspace) {
console.info("ExtWorkspaceService: ext-workspace available but compositor has native support"); log.info("ext-workspace available but compositor has native support");
extWorkspaceAvailable = false; extWorkspaceAvailable = false;
return; return;
} }
} }
extWorkspaceAvailable = true; extWorkspaceAvailable = true;
console.info("ExtWorkspaceService: ext-workspace capability detected"); log.info("ext-workspace capability detected");
DMSService.addSubscription("extworkspace"); DMSService.addSubscription("extworkspace");
requestState(); requestState();
} else if (!hasExtWorkspace) { } else if (!hasExtWorkspace) {
@@ -78,9 +80,9 @@ Singleton {
function handleStateUpdate(state) { function handleStateUpdate(state) {
groups = state.groups || []; groups = state.groups || [];
if (groups.length === 0) { if (groups.length === 0) {
console.warn("ExtWorkspaceService: Received empty workspace groups from backend"); log.warn("Received empty workspace groups from backend");
} else { } else {
console.log("ExtWorkspaceService: Updated with", groups.length, "workspace groups"); log.debug("Updated with", groups.length, "workspace groups");
} }
stateChanged(); stateChanged();
} }
@@ -95,7 +97,7 @@ Singleton {
"groupID": groupID "groupID": groupID
}, response => { }, response => {
if (response.error) { if (response.error) {
console.warn("ExtWorkspaceService: activateWorkspace error:", response.error); log.warn("activateWorkspace error:", response.error);
} }
}); });
} }
@@ -110,7 +112,7 @@ Singleton {
"groupID": groupID "groupID": groupID
}, response => { }, response => {
if (response.error) { if (response.error) {
console.warn("ExtWorkspaceService: deactivateWorkspace error:", response.error); log.warn("deactivateWorkspace error:", response.error);
} }
}); });
} }
@@ -125,7 +127,7 @@ Singleton {
"groupID": groupID "groupID": groupID
}, response => { }, response => {
if (response.error) { if (response.error) {
console.warn("ExtWorkspaceService: removeWorkspace error:", response.error); log.warn("removeWorkspace error:", response.error);
} }
}); });
} }
@@ -140,7 +142,7 @@ Singleton {
"name": name "name": name
}, response => { }, response => {
if (response.error) { if (response.error) {
console.warn("ExtWorkspaceService: createWorkspace error:", response.error); log.warn("createWorkspace error:", response.error);
} }
}); });
} }
@@ -272,6 +274,6 @@ Singleton {
return; return;
} }
} }
console.warn("ExtWorkspaceService: workspace not found:", workspaceName); log.warn("workspace not found:", workspaceName);
} }
} }

View File

@@ -6,9 +6,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("FirstLaunchService")
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell" readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell"
readonly property string settingsPath: configDir + "/settings.json" readonly property string settingsPath: configDir + "/settings.json"
@@ -77,10 +79,10 @@ Singleton {
if (result === "first") { if (result === "first") {
root.isFirstLaunch = true; root.isFirstLaunch = true;
console.info("FirstLaunchService: First launch detected, greeter will be shown"); log.info("First launch detected, greeter will be shown");
} else if (result === "existing_user") { } else if (result === "existing_user") {
root.isFirstLaunch = false; root.isFirstLaunch = false;
console.info("FirstLaunchService: Existing user detected, silently creating marker"); log.info("Existing user detected, silently creating marker");
touchMarkerProcess.running = true; touchMarkerProcess.running = true;
} else { } else {
root.isFirstLaunch = false; root.isFirstLaunch = false;
@@ -102,9 +104,9 @@ Singleton {
onExited: exitCode => { onExited: exitCode => {
if (exitCode === 0) { if (exitCode === 0) {
console.info("FirstLaunchService: First launch marker created"); log.info("First launch marker created");
} else { } else {
console.warn("FirstLaunchService: Failed to create first launch marker"); log.warn("Failed to create first launch marker");
} }
} }
} }

View File

@@ -6,9 +6,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Hyprland import Quickshell.Hyprland
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("HyprlandService")
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation))
readonly property string hyprDmsDir: configDir + "/hypr/dms" readonly property string hyprDmsDir: configDir + "/hypr/dms"
@@ -29,7 +31,7 @@ Singleton {
function ensureWindowrulesConfig() { function ensureWindowrulesConfig() {
Proc.runCommand("hypr-ensure-windowrules", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && [ ! -f "${windowrulesPath}" ] && touch "${windowrulesPath}" || true`], (output, exitCode) => { Proc.runCommand("hypr-ensure-windowrules", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && [ ! -f "${windowrulesPath}" ] && touch "${windowrulesPath}" || true`], (output, exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("HyprlandService: Failed to ensure windowrules.conf:", output); log.warn("Failed to ensure windowrules.conf:", output);
}); });
} }
@@ -159,10 +161,10 @@ Singleton {
Proc.runCommand("hypr-write-outputs", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { Proc.runCommand("hypr-write-outputs", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("HyprlandService: Failed to write outputs config:", output); log.warn("Failed to write outputs config:", output);
return; return;
} }
console.info("HyprlandService: Generated outputs config at", outputsPath); log.info("Generated outputs config at", outputsPath);
if (CompositorService.isHyprland) if (CompositorService.isHyprland)
reloadConfig(); reloadConfig();
}); });
@@ -171,7 +173,7 @@ Singleton {
function reloadConfig() { function reloadConfig() {
Proc.runCommand("hyprctl-reload", ["hyprctl", "reload"], (output, exitCode) => { Proc.runCommand("hyprctl-reload", ["hyprctl", "reload"], (output, exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("HyprlandService: hyprctl reload failed:", output); log.warn("hyprctl reload failed:", output);
}); });
} }
@@ -202,10 +204,10 @@ decoration {
Proc.runCommand("hypr-write-layout", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { Proc.runCommand("hypr-write-layout", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${layoutPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("HyprlandService: Failed to write layout config:", output); log.warn("Failed to write layout config:", output);
return; return;
} }
console.info("HyprlandService: Generated layout config at", layoutPath); log.info("Generated layout config at", layoutPath);
reloadConfig(); reloadConfig();
}); });
} }
@@ -264,7 +266,7 @@ decoration {
if (!settings) { if (!settings) {
Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => { Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("HyprlandService: Failed to write cursor config:", output); log.warn("Failed to write cursor config:", output);
}); });
return; return;
} }
@@ -282,7 +284,7 @@ decoration {
if (!hasTheme && !hasNonDefaultSize && !hasCursorSettings) { if (!hasTheme && !hasNonDefaultSize && !hasCursorSettings) {
Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => { Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("HyprlandService: Failed to write cursor config:", output); log.warn("Failed to write cursor config:", output);
}); });
return; return;
} }
@@ -313,7 +315,7 @@ decoration {
Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${cursorPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => { Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${cursorPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("HyprlandService: Failed to write cursor config:", output); log.warn("Failed to write cursor config:", output);
return; return;
} }
if (hasTheme) if (hasTheme)
@@ -331,7 +333,7 @@ decoration {
const fullName = wsId + " " + newName; const fullName = wsId + " " + newName;
Proc.runCommand("hyprland-rename-ws", ["hyprctl", "dispatch", "renameworkspace", String(wsId), fullName], (output, exitCode) => { Proc.runCommand("hyprland-rename-ws", ["hyprctl", "dispatch", "renameworkspace", String(wsId), fullName], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("HyprlandService: Failed to rename workspace:", output); log.warn("Failed to rename workspace:", output);
} }
}); });
} }

View File

@@ -5,9 +5,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Wayland import Quickshell.Wayland
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("IdleService")
readonly property bool idleMonitorAvailable: { readonly property bool idleMonitorAvailable: {
try { try {
@@ -82,7 +84,7 @@ Singleton {
function createIdleMonitors() { function createIdleMonitors() {
if (!idleMonitorAvailable) { if (!idleMonitorAvailable) {
console.info("IdleService: IdleMonitor not available, skipping creation"); log.info("IdleMonitor not available, skipping creation");
return; return;
} }
@@ -157,7 +159,7 @@ Singleton {
} }
}); });
} catch (e) { } catch (e) {
console.warn("IdleService: Error creating IdleMonitors:", e); log.warn("Error creating IdleMonitors:", e);
} }
} }
@@ -181,11 +183,11 @@ Singleton {
onExternalInhibitActiveChanged: { onExternalInhibitActiveChanged: {
if (externalInhibitActive) { if (externalInhibitActive) {
const apps = DMSService.screensaverInhibitors.map(i => i.appName).join(", "); const apps = DMSService.screensaverInhibitors.map(i => i.appName).join(", ");
console.info("IdleService: External idle inhibit active from:", apps || "unknown"); log.info("External idle inhibit active from:", apps || "unknown");
SessionService.idleInhibited = true; SessionService.idleInhibited = true;
SessionService.inhibitReason = "External app: " + (apps || "unknown"); SessionService.inhibitReason = "External app: " + (apps || "unknown");
} else { } else {
console.info("IdleService: External idle inhibit released"); log.info("External idle inhibit released");
SessionService.idleInhibited = false; SessionService.idleInhibited = false;
SessionService.inhibitReason = "Keep system awake"; SessionService.inhibitReason = "Keep system awake";
} }
@@ -193,9 +195,9 @@ Singleton {
Component.onCompleted: { Component.onCompleted: {
if (!idleMonitorAvailable) { if (!idleMonitorAvailable) {
console.warn("IdleService: IdleMonitor not available - power management disabled. This requires a newer version of Quickshell."); log.warn("IdleMonitor not available - power management disabled. This requires a newer version of Quickshell.");
} else { } else {
console.info("IdleService: Initialized with idle monitoring support"); log.info("Initialized with idle monitoring support");
createIdleMonitors(); createIdleMonitors();
} }

View File

@@ -8,14 +8,16 @@ import Quickshell.Io
import Quickshell.Wayland import Quickshell.Wayland
// ! Even though qmlls says this is unused, it is wrong // ! Even though qmlls says this is unused, it is wrong
import qs.Common import qs.Common
import qs.Services
import "../Common/KeybindActions.js" as Actions import "../Common/KeybindActions.js" as Actions
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("KeybindsService")
Component.onCompleted: { Component.onCompleted: {
if (!shortcutInhibitorAvailable) { if (!shortcutInhibitorAvailable) {
console.warn("[KeybindsService] ShortcutInhibitor is not available in this environment, keybinds editor disabled."); log.warn("ShortcutInhibitor is not available in this environment, keybinds editor disabled.");
} }
} }
@@ -150,7 +152,7 @@ Singleton {
try { try {
root.cheatsheet = JSON.parse(text); root.cheatsheet = JSON.parse(text);
} catch (e) { } catch (e) {
console.error("[KeybindsService] Failed to parse cheatsheet:", e); log.error("Failed to parse cheatsheet:", e);
root.cheatsheet = {}; root.cheatsheet = {};
} }
root.cheatsheetLoading = false; root.cheatsheetLoading = false;
@@ -161,7 +163,7 @@ Singleton {
onExited: exitCode => { onExited: exitCode => {
if (exitCode === 0) if (exitCode === 0)
return; return;
console.warn("[KeybindsService] Cheatsheet load failed with code:", exitCode); log.warn("Cheatsheet load failed with code:", exitCode);
root.cheatsheetLoading = false; root.cheatsheetLoading = false;
} }
} }
@@ -176,7 +178,7 @@ Singleton {
root._rawData = JSON.parse(text); root._rawData = JSON.parse(text);
root._processData(); root._processData();
} catch (e) { } catch (e) {
console.error("[KeybindsService] Failed to parse binds:", e); log.error("Failed to parse binds:", e);
} }
root.loading = false; root.loading = false;
} }
@@ -184,7 +186,7 @@ Singleton {
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("[KeybindsService] Load process failed with code:", exitCode); log.warn("Load process failed with code:", exitCode);
root.loading = false; root.loading = false;
} }
} }
@@ -206,7 +208,7 @@ Singleton {
onExited: exitCode => { onExited: exitCode => {
root.saving = false; root.saving = false;
if (exitCode !== 0) { if (exitCode !== 0) {
console.error("[KeybindsService] Save failed with code:", exitCode); log.error("Save failed with code:", exitCode);
root.bindSaveCompleted(false); root.bindSaveCompleted(false);
return; return;
} }
@@ -231,7 +233,7 @@ Singleton {
onExited: exitCode => { onExited: exitCode => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.error("[KeybindsService] Remove failed with code:", exitCode); log.error("Remove failed with code:", exitCode);
return; return;
} }
root.lastError = ""; root.lastError = "";
@@ -255,7 +257,7 @@ Singleton {
onExited: exitCode => { onExited: exitCode => {
root.fixing = false; root.fixing = false;
if (exitCode !== 0) { if (exitCode !== 0) {
console.error("[KeybindsService] Fix failed with code:", exitCode); log.error("Fix failed with code:", exitCode);
return; return;
} }
root.lastError = ""; root.lastError = "";

File diff suppressed because it is too large Load Diff

View File

@@ -3,8 +3,6 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import Quickshell import Quickshell
import Quickshell.Io
import qs.Common
Singleton { Singleton {
id: root id: root

226
quickshell/Services/Log.qml Normal file
View File

@@ -0,0 +1,226 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
enum Level {
Debug,
Info,
Warn,
Error,
Fatal
}
readonly property int level: _parseLevel(Quickshell.env("DMS_LOG_LEVEL"))
readonly property string levelName: _levelName(level)
readonly property string _logFilePath: Quickshell.env("DMS_LOG_FILE") || ""
readonly property bool _useColor: !Quickshell.env("NO_COLOR") && Quickshell.env("DMS_LOG_NO_COLOR") !== "1"
function scoped(module) {
return {
debug: function () {
root._emit(Log.Level.Debug, module, arguments);
},
info: function () {
root._emit(Log.Level.Info, module, arguments);
},
warn: function () {
root._emit(Log.Level.Warn, module, arguments);
},
error: function () {
root._emit(Log.Level.Error, module, arguments);
},
fatal: function () {
root._emit(Log.Level.Fatal, module, arguments);
}
};
}
function debug() {
_emit(Log.Level.Debug, "", arguments);
}
function info() {
_emit(Log.Level.Info, "", arguments);
}
function warn() {
_emit(Log.Level.Warn, "", arguments);
}
function error() {
_emit(Log.Level.Error, "", arguments);
}
function fatal() {
_emit(Log.Level.Fatal, "", arguments);
}
function callStack() {
const trace = _captureStack(0).split("\n").map(l => l.trim()).filter(l => l.length > 0);
_emit(Log.Level.Info, "Debug", ["--------------------------"]);
_emit(Log.Level.Info, "Debug", ["Current call stack"]);
for (const line of trace)
_emit(Log.Level.Info, "Debug", ["- " + line]);
_emit(Log.Level.Info, "Debug", ["--------------------------"]);
}
function _parseLevel(name) {
switch ((name || "").toLowerCase()) {
case "debug":
return Log.Level.Debug;
case "warn":
case "warning":
return Log.Level.Warn;
case "error":
return Log.Level.Error;
case "fatal":
return Log.Level.Fatal;
default:
return Log.Level.Info;
}
}
function _levelName(lvl) {
switch (lvl) {
case Log.Level.Debug:
return "debug";
case Log.Level.Info:
return "info";
case Log.Level.Warn:
return "warn";
case Log.Level.Error:
return "error";
case Log.Level.Fatal:
return "fatal";
}
return "info";
}
function _levelTag(lvl, color) {
let tag, ansi;
switch (lvl) {
case Log.Level.Fatal:
tag = " FATAL";
ansi = "\x1b[31m";
break;
case Log.Level.Error:
tag = " ERROR";
ansi = "\x1b[91m";
break;
case Log.Level.Warn:
tag = " WARN";
ansi = "\x1b[33m";
break;
case Log.Level.Info:
tag = " INFO";
ansi = "\x1b[32m";
break;
case Log.Level.Debug:
tag = " DEBUG";
ansi = "\x1b[34m";
break;
default:
return " INFO";
}
if (!color)
return tag;
return ansi + tag + "\x1b[0m";
}
function _stringify(v) {
if (v === null)
return "null";
if (v === undefined)
return "undefined";
if (typeof v === "string")
return v;
if (v instanceof Error)
return v.toString();
try {
return JSON.stringify(v);
} catch (e) {
return String(v);
}
}
function _captureStack(skip) {
try {
throw new Error();
} catch (e) {
const lines = (e.stack || "").split("\n");
return lines.slice(1 + (skip || 0)).join("\n");
}
}
function _callerLocation() {
const stack = _captureStack(2);
const lines = stack.split("\n");
for (const line of lines) {
const m = line.match(/([^/@\s]+\.qml):(\d+)/);
if (!m)
continue;
if (m[1] === "Log.qml")
continue;
return {
file: m[1],
line: m[2]
};
}
return null;
}
function _emit(lvl, module, args) {
if (lvl < root.level)
return;
const argList = Array.from(args);
const loc = _callerLocation();
const msg = argList.map(_stringify).join(" ");
let tag;
if (module && loc && loc.file === module + ".qml")
tag = "[" + module + ":" + loc.line + "] ";
else if (module && loc)
tag = "[" + module + "] (" + loc.file + ":" + loc.line + ") ";
else if (module)
tag = "[" + module + "] ";
else if (loc)
tag = "(" + loc.file + ":" + loc.line + ") ";
else
tag = "";
const body = tag + msg;
switch (lvl) {
case Log.Level.Debug:
console.debug(body);
break;
case Log.Level.Info:
console.info(body);
break;
case Log.Level.Warn:
console.warn(body);
break;
case Log.Level.Error:
case Log.Level.Fatal:
console.error(body);
break;
}
if (root._logFilePath && fileTee.running)
fileTee.write(_levelTag(lvl, false) + " qml: " + body + "\n");
if (lvl === Log.Level.Fatal)
Qt.callLater(() => Qt.exit(1));
}
Process {
id: fileTee
command: ["sh", "-c", "exec tee -a \"$0\" >/dev/null", root._logFilePath]
stdinEnabled: true
running: root._logFilePath.length > 0
}
}

View File

@@ -6,6 +6,7 @@ import Quickshell
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("MultimediaService")
property bool available: false property bool available: false
@@ -14,6 +15,7 @@ Singleton {
const testObj = Qt.createQmlObject(` const testObj = Qt.createQmlObject(`
import QtQuick import QtQuick
import QtMultimedia import QtMultimedia
import qs.Services
Item {} Item {}
`, root, "MultimediaService.TestComponent"); `, root, "MultimediaService.TestComponent");
if (testObj) { if (testObj) {
@@ -29,7 +31,7 @@ Singleton {
Component.onCompleted: { Component.onCompleted: {
if (!detectAvailability()) { if (!detectAvailability()) {
console.warn("MultimediaService: QtMultimedia not available"); log.warn("QtMultimedia not available");
} }
} }
} }

View File

@@ -5,9 +5,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("MuxService")
property var sessions: [] property var sessions: []
property bool loading: false property bool loading: false
@@ -34,32 +36,36 @@ Singleton {
}) })
function getTerminalFlag(terminal) { function getTerminalFlag(terminal) {
return terminalFlags[terminal] ?? ["-e"] return terminalFlags[terminal] ?? ["-e"];
} }
readonly property string terminal: SessionData.resolveTerminal() || "ghostty" readonly property string terminal: SessionData.resolveTerminal() || "ghostty"
function _terminalPrefix() { function _terminalPrefix() {
return [terminal].concat(getTerminalFlag(terminal)) return [terminal].concat(getTerminalFlag(terminal));
} }
Process { Process {
id: tmuxCheckProcess id: tmuxCheckProcess
command: ["which", "tmux"] command: ["which", "tmux"]
running: false running: false
onExited: (code) => { root.tmuxAvailable = (code === 0) } onExited: code => {
root.tmuxAvailable = (code === 0);
}
} }
Process { Process {
id: zellijCheckProcess id: zellijCheckProcess
command: ["which", "zellij"] command: ["which", "zellij"]
running: false running: false
onExited: (code) => { root.zellijAvailable = (code === 0) } onExited: code => {
root.zellijAvailable = (code === 0);
}
} }
function checkAvailability() { function checkAvailability() {
tmuxCheckProcess.running = true tmuxCheckProcess.running = true;
zellijCheckProcess.running = true zellijCheckProcess.running = true;
} }
Component.onCompleted: checkAvailability() Component.onCompleted: checkAvailability()
@@ -72,141 +78,139 @@ Singleton {
onStreamFinished: { onStreamFinished: {
try { try {
if (root.muxType === "zellij") if (root.muxType === "zellij")
root._parseZellijSessions(text) root._parseZellijSessions(text);
else else
root._parseTmuxSessions(text) root._parseTmuxSessions(text);
} catch (e) { } catch (e) {
console.error("[MuxService] Error parsing sessions:", e) log.error("Error parsing sessions:", e);
root.sessions = [] root.sessions = [];
} }
root.loading = false root.loading = false;
} }
} }
stderr: SplitParser { stderr: SplitParser {
onRead: (line) => { onRead: line => {
if (line.trim()) if (line.trim())
console.error("[MuxService] stderr:", line) log.error("stderr:", line);
} }
} }
onExited: (code) => { onExited: code => {
if (code !== 0 && code !== 1) { if (code !== 0 && code !== 1) {
console.warn("[MuxService] Process exited with code:", code) log.warn("Process exited with code:", code);
root.sessions = [] root.sessions = [];
} }
root.loading = false root.loading = false;
} }
} }
function refreshSessions() { function refreshSessions() {
if (!root.currentMuxAvailable) { if (!root.currentMuxAvailable) {
root.sessions = [] root.sessions = [];
return return;
} }
root.loading = true root.loading = true;
if (listProcess.running) if (listProcess.running)
listProcess.running = false listProcess.running = false;
if (root.muxType === "zellij") if (root.muxType === "zellij")
listProcess.command = ["zellij", "list-sessions", "--no-formatting"] listProcess.command = ["zellij", "list-sessions", "--no-formatting"];
else else
listProcess.command = ["tmux", "list-sessions", "-F", "#{session_name}|#{session_windows}|#{session_attached}"] listProcess.command = ["tmux", "list-sessions", "-F", "#{session_name}|#{session_windows}|#{session_attached}"];
Qt.callLater(function () { Qt.callLater(function () {
listProcess.running = true listProcess.running = true;
}) });
} }
function _isSessionExcluded(name) { function _isSessionExcluded(name) {
var filter = SettingsData.muxSessionFilter.trim() var filter = SettingsData.muxSessionFilter.trim();
if (filter.length === 0) if (filter.length === 0)
return false return false;
var parts = filter.split(",") var parts = filter.split(",");
for (var i = 0; i < parts.length; i++) { for (var i = 0; i < parts.length; i++) {
var pattern = parts[i].trim() var pattern = parts[i].trim();
if (pattern.length === 0) if (pattern.length === 0)
continue continue;
if (pattern.startsWith("/") && pattern.endsWith("/") && pattern.length > 2) { if (pattern.startsWith("/") && pattern.endsWith("/") && pattern.length > 2) {
try { try {
var re = new RegExp(pattern.slice(1, -1)) var re = new RegExp(pattern.slice(1, -1));
if (re.test(name)) if (re.test(name))
return true return true;
} catch (e) {} } catch (e) {}
} else { } else {
if (name.toLowerCase() === pattern.toLowerCase()) if (name.toLowerCase() === pattern.toLowerCase())
return true return true;
} }
} }
return false return false;
} }
function _parseTmuxSessions(output) { function _parseTmuxSessions(output) {
var sessionList = [] var sessionList = [];
var lines = output.trim().split('\n') var lines = output.trim().split('\n');
for (var i = 0; i < lines.length; i++) { for (var i = 0; i < lines.length; i++) {
var line = lines[i].trim() var line = lines[i].trim();
if (line.length === 0) if (line.length === 0)
continue continue;
var parts = line.split('|');
var parts = line.split('|')
if (parts.length >= 3 && !_isSessionExcluded(parts[0])) { if (parts.length >= 3 && !_isSessionExcluded(parts[0])) {
sessionList.push({ sessionList.push({
name: parts[0], name: parts[0],
windows: parts[1], windows: parts[1],
attached: parts[2] === "1" attached: parts[2] === "1"
}) });
} }
} }
root.sessions = sessionList root.sessions = sessionList;
} }
function _parseZellijSessions(output) { function _parseZellijSessions(output) {
var sessionList = [] var sessionList = [];
var lines = output.trim().split('\n') var lines = output.trim().split('\n');
for (var i = 0; i < lines.length; i++) { for (var i = 0; i < lines.length; i++) {
var line = lines[i].trim() var line = lines[i].trim();
if (line.length === 0) if (line.length === 0)
continue continue;
var exited = line.includes("(EXITED");
var exited = line.includes("(EXITED") var bracketIdx = line.indexOf(" [");
var bracketIdx = line.indexOf(" [") var name = (bracketIdx > 0 ? line.substring(0, bracketIdx) : line).trim();
var name = (bracketIdx > 0 ? line.substring(0, bracketIdx) : line).trim()
if (!_isSessionExcluded(name)) { if (!_isSessionExcluded(name)) {
sessionList.push({ sessionList.push({
name: name, name: name,
windows: "N/A", windows: "N/A",
attached: !exited attached: !exited
}) });
} }
} }
root.sessions = sessionList root.sessions = sessionList;
} }
function attachToSession(name) { function attachToSession(name) {
if (SettingsData.muxUseCustomCommand && SettingsData.muxCustomCommand) { if (SettingsData.muxUseCustomCommand && SettingsData.muxCustomCommand) {
Quickshell.execDetached([Paths.expandTilde(SettingsData.muxCustomCommand), name]) Quickshell.execDetached([Paths.expandTilde(SettingsData.muxCustomCommand), name]);
} else if (root.muxType === "zellij") { } else if (root.muxType === "zellij") {
Quickshell.execDetached(_terminalPrefix().concat(["zellij", "attach", name])) Quickshell.execDetached(_terminalPrefix().concat(["zellij", "attach", name]));
} else { } else {
Quickshell.execDetached(_terminalPrefix().concat(["tmux", "attach", "-t", name])) Quickshell.execDetached(_terminalPrefix().concat(["tmux", "attach", "-t", name]));
} }
} }
function createSession(name) { function createSession(name) {
if (SettingsData.muxUseCustomCommand && SettingsData.muxCustomCommand) { if (SettingsData.muxUseCustomCommand && SettingsData.muxCustomCommand) {
Quickshell.execDetached([Paths.expandTilde(SettingsData.muxCustomCommand), name]) Quickshell.execDetached([Paths.expandTilde(SettingsData.muxCustomCommand), name]);
} else if (root.muxType === "zellij") { } else if (root.muxType === "zellij") {
Quickshell.execDetached(_terminalPrefix().concat(["zellij", "-s", name])) Quickshell.execDetached(_terminalPrefix().concat(["zellij", "-s", name]));
} else { } else {
Quickshell.execDetached(_terminalPrefix().concat(["tmux", "new-session", "-s", name])) Quickshell.execDetached(_terminalPrefix().concat(["tmux", "new-session", "-s", name]));
} }
} }
@@ -214,17 +218,17 @@ Singleton {
function renameSession(oldName, newName) { function renameSession(oldName, newName) {
if (root.muxType === "zellij") if (root.muxType === "zellij")
return return;
Quickshell.execDetached(["tmux", "rename-session", "-t", oldName, newName]) Quickshell.execDetached(["tmux", "rename-session", "-t", oldName, newName]);
Qt.callLater(refreshSessions) Qt.callLater(refreshSessions);
} }
function killSession(name) { function killSession(name) {
if (root.muxType === "zellij") { if (root.muxType === "zellij") {
Quickshell.execDetached(["zellij", "kill-session", name]) Quickshell.execDetached(["zellij", "kill-session", name]);
} else { } else {
Quickshell.execDetached(["tmux", "kill-session", "-t", name]) Quickshell.execDetached(["tmux", "kill-session", "-t", name]);
} }
Qt.callLater(refreshSessions) Qt.callLater(refreshSessions);
} }
} }

View File

@@ -3,9 +3,11 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import Quickshell import Quickshell
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("NetworkService")
property bool networkAvailable: activeService !== null property bool networkAvailable: activeService !== null
property string backend: activeService?.backend ?? "" property string backend: activeService?.backend ?? ""
@@ -97,12 +99,12 @@ Singleton {
readonly property string socketPath: Quickshell.env("DMS_SOCKET") readonly property string socketPath: Quickshell.env("DMS_SOCKET")
Component.onCompleted: { Component.onCompleted: {
console.info("NetworkService: Initializing..."); log.info("Initializing...");
if (!socketPath || socketPath.length === 0) { if (!socketPath || socketPath.length === 0) {
console.info("NetworkService: DMS_SOCKET not set, using LegacyNetworkService"); log.info("DMS_SOCKET not set, using LegacyNetworkService");
useLegacyService(); useLegacyService();
} else { } else {
console.log("NetworkService: DMS_SOCKET found, waiting for capabilities..."); log.debug("DMS_SOCKET found, waiting for capabilities...");
} }
} }
@@ -111,13 +113,13 @@ Singleton {
function onNetworkAvailableChanged() { function onNetworkAvailableChanged() {
if (!activeService && DMSNetworkService.networkAvailable) { if (!activeService && DMSNetworkService.networkAvailable) {
console.info("NetworkService: Network capability detected, using DMSNetworkService"); log.info("Network capability detected, using DMSNetworkService");
activeService = DMSNetworkService; activeService = DMSNetworkService;
usingLegacy = false; usingLegacy = false;
console.info("NetworkService: Switched to DMSNetworkService, networkAvailable:", networkAvailable); log.info("Switched to DMSNetworkService, networkAvailable:", networkAvailable);
connectSignals(); connectSignals();
} else if (!activeService && !DMSNetworkService.networkAvailable && socketPath && socketPath.length > 0) { } else if (!activeService && !DMSNetworkService.networkAvailable && socketPath && socketPath.length > 0) {
console.info("NetworkService: Network capability not available in DMS, using LegacyNetworkService"); log.info("Network capability not available in DMS, using LegacyNetworkService");
useLegacyService(); useLegacyService();
} }
} }
@@ -126,7 +128,7 @@ Singleton {
function useLegacyService() { function useLegacyService() {
activeService = LegacyNetworkService; activeService = LegacyNetworkService;
usingLegacy = true; usingLegacy = true;
console.info("NetworkService: Switched to LegacyNetworkService, networkAvailable:", networkAvailable); log.info("Switched to LegacyNetworkService, networkAvailable:", networkAvailable);
if (LegacyNetworkService.activate) { if (LegacyNetworkService.activate) {
LegacyNetworkService.activate(); LegacyNetworkService.activate();
} }

View File

@@ -6,9 +6,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("NiriService")
readonly property string socketPath: Quickshell.env("NIRI_SOCKET") readonly property string socketPath: Quickshell.env("NIRI_SOCKET")
@@ -118,10 +120,10 @@ Singleton {
onExited: exitCode => { onExited: exitCode => {
if (exitCode === 0) { if (exitCode === 0) {
console.info("NiriService: Generated layout config at", configPath); log.info("Generated layout config at", configPath);
return; return;
} }
console.warn("NiriService: Failed to write layout config, exit code:", exitCode); log.warn("Failed to write layout config, exit code:", exitCode);
} }
} }
@@ -132,10 +134,10 @@ Singleton {
onExited: exitCode => { onExited: exitCode => {
if (exitCode === 0) { if (exitCode === 0) {
console.info("NiriService: Generated alttab config at", alttabPath); log.info("Generated alttab config at", alttabPath);
return; return;
} }
console.warn("NiriService: Failed to write alttab config, exit code:", exitCode); log.warn("Failed to write alttab config, exit code:", exitCode);
} }
} }
@@ -145,10 +147,10 @@ Singleton {
onExited: exitCode => { onExited: exitCode => {
if (exitCode === 0) { if (exitCode === 0) {
console.info("NiriService: Generated wpblur config at", blurrulePath); log.info("Generated wpblur config at", blurrulePath);
return; return;
} }
console.warn("NiriService: Failed to write wpblur config, exit code:", exitCode); log.warn("Failed to write wpblur config, exit code:", exitCode);
} }
} }
@@ -159,10 +161,10 @@ Singleton {
onExited: exitCode => { onExited: exitCode => {
if (exitCode === 0) { if (exitCode === 0) {
console.info("NiriService: Generated cursor config at", cursorPath); log.info("Generated cursor config at", cursorPath);
return; return;
} }
console.warn("NiriService: Failed to write cursor config, exit code:", exitCode); log.warn("Failed to write cursor config, exit code:", exitCode);
} }
} }
@@ -184,7 +186,7 @@ Singleton {
const event = JSON.parse(line); const event = JSON.parse(line);
handleNiriEvent(event); handleNiriEvent(event);
} catch (e) { } catch (e) {
console.warn("NiriService: Failed to parse event:", line, e); log.warn("Failed to parse event:", line, e);
} }
} }
} }
@@ -201,19 +203,19 @@ Singleton {
return; return;
Proc.runCommand("niri-fetch-outputs", ["niri", "msg", "-j", "outputs"], (output, exitCode) => { Proc.runCommand("niri-fetch-outputs", ["niri", "msg", "-j", "outputs"], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("NiriService: Failed to fetch outputs, exit code:", exitCode); log.warn("Failed to fetch outputs, exit code:", exitCode);
return; return;
} }
try { try {
const outputsData = JSON.parse(output); const outputsData = JSON.parse(output);
outputs = outputsData; outputs = outputsData;
console.info("NiriService: Loaded", Object.keys(outputsData).length, "outputs"); log.info("Loaded", Object.keys(outputsData).length, "outputs");
updateDisplayScales(); updateDisplayScales();
if (windows.length > 0) { if (windows.length > 0) {
windows = sortWindowsByLayout(windows); windows = sortWindowsByLayout(windows);
} }
} catch (e) { } catch (e) {
console.warn("NiriService: Failed to parse outputs:", e); log.warn("Failed to parse outputs:", e);
} }
}); });
} }
@@ -1076,7 +1078,7 @@ Singleton {
} }
function doGenerateNiriLayoutConfig() { function doGenerateNiriLayoutConfig() {
console.log("NiriService: Generating layout config..."); log.debug("Generating layout config...");
const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12; const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12;
const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4; const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4;
@@ -1136,7 +1138,7 @@ Singleton {
const path = niriDmsDir + "/" + name + ".kdl"; const path = niriDmsDir + "/" + name + ".kdl";
Proc.runCommand("niri-ensure-" + name, ["sh", "-c", `mkdir -p "${niriDmsDir}" && [ ! -f "${path}" ] && touch "${path}" || true`], (output, exitCode) => { Proc.runCommand("niri-ensure-" + name, ["sh", "-c", `mkdir -p "${niriDmsDir}" && [ ! -f "${path}" ] && touch "${path}" || true`], (output, exitCode) => {
if (exitCode !== 0) if (exitCode !== 0)
console.warn("NiriService: Failed to ensure " + name + ".kdl, exit code:", exitCode); log.warn("Failed to ensure " + name + ".kdl, exit code:", exitCode);
}); });
} }
@@ -1144,7 +1146,7 @@ Singleton {
} }
function generateNiriBlurrule() { function generateNiriBlurrule() {
console.log("NiriService: Generating wpblur config..."); log.debug("Generating wpblur config...");
const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
const niriDmsDir = configDir + "/niri/dms"; const niriDmsDir = configDir + "/niri/dms";
@@ -1160,7 +1162,7 @@ Singleton {
if (!CompositorService.isNiri) if (!CompositorService.isNiri)
return; return;
console.log("NiriService: Generating cursor config..."); log.debug("Generating cursor config...");
const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)); const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
const niriDmsDir = configDir + "/niri/dms"; const niriDmsDir = configDir + "/niri/dms";
@@ -1275,12 +1277,12 @@ Singleton {
const fullCommand = commands.join(" && "); const fullCommand = commands.join(" && ");
Proc.runCommand("niri-output-config", ["sh", "-c", fullCommand], (output, exitCode) => { Proc.runCommand("niri-output-config", ["sh", "-c", fullCommand], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("NiriService: Failed to apply output config:", output); log.warn("Failed to apply output config:", output);
if (callback) if (callback)
callback(false, output); callback(false, output);
return; return;
} }
console.info("NiriService: Applied output config for", outputName); log.info("Applied output config for", outputName);
fetchOutputs(); fetchOutputs();
if (callback) if (callback)
callback(true, "Success"); callback(true, "Success");
@@ -1369,10 +1371,10 @@ Singleton {
Proc.runCommand("niri-write-outputs", ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${kdlContent}EOF`], (output, exitCode) => { Proc.runCommand("niri-write-outputs", ["sh", "-c", `mkdir -p "${niriDmsDir}" && cat > "${outputsPath}" << 'EOF'\n${kdlContent}EOF`], (output, exitCode) => {
if (exitCode !== 0) { if (exitCode !== 0) {
console.warn("NiriService: Failed to write outputs config:", output); log.warn("Failed to write outputs config:", output);
return; return;
} }
console.info("NiriService: Generated outputs config at", outputsPath); log.info("Generated outputs config at", outputsPath);
}); });
} }

View File

@@ -6,9 +6,11 @@ import QtCore
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("NotepadStorageService")
property int refCount: 0 property int refCount: 0
@@ -39,7 +41,7 @@ Singleton {
root.metadataLoaded = true root.metadataLoaded = true
root.validateTabs() root.validateTabs()
} catch(e) { } catch(e) {
console.warn("Failed to parse notepad metadata:", e) log.warn("Failed to parse notepad metadata:", e)
root.createDefaultTab() root.createDefaultTab()
} }
} }
@@ -148,7 +150,7 @@ Singleton {
callback: callback callback: callback
}) })
} else { } else {
console.warn("Tab file does not exist:", fullPath) log.warn("Tab file does not exist:", fullPath)
callback("") callback("")
} }
} }
@@ -389,7 +391,7 @@ Singleton {
} }
onSaveFailed: { onSaveFailed: {
console.error("Failed to save tab content") log.error("Failed to save tab content")
if (creationCallback) { if (creationCallback) {
creationCallback() creationCallback()
} }

View File

@@ -6,10 +6,12 @@ import Quickshell
import Quickshell.Io import Quickshell.Io
import Quickshell.Services.Notifications import Quickshell.Services.Notifications
import qs.Common import qs.Common
import qs.Services
import "../Common/markdown2html.js" as Markdown2Html import "../Common/markdown2html.js" as Markdown2Html
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("NotificationService")
readonly property list<NotifWrapper> notifications: [] readonly property list<NotifWrapper> notifications: []
readonly property list<NotifWrapper> allWrappers: [] readonly property list<NotifWrapper> allWrappers: []
@@ -153,7 +155,7 @@ Singleton {
historyAdapter.notifications = historyList; historyAdapter.notifications = historyList;
historyFileView.writeAdapter(); historyFileView.writeAdapter();
} catch (e) { } catch (e) {
console.warn("NotificationService: save history failed:", e); log.warn("save history failed:", e);
} }
} }
@@ -203,7 +205,7 @@ Singleton {
if ((maxAgeMs > 0 && loaded.length !== (historyAdapter.notifications || []).length) || needsRewrite) if ((maxAgeMs > 0 && loaded.length !== (historyAdapter.notifications || []).length) || needsRewrite)
saveHistory(); saveHistory();
} catch (e) { } catch (e) {
console.warn("NotificationService: load history failed:", e); log.warn("load history failed:", e);
historyLoaded = true; historyLoaded = true;
} }
} }
@@ -403,7 +405,7 @@ Singleton {
try { try {
return new RegExp(pattern, "i").test(value); return new RegExp(pattern, "i").test(value);
} catch (e) { } catch (e) {
console.warn("NotificationService: invalid notification rule regex:", pattern); log.warn("invalid notification rule regex:", pattern);
return false; return false;
} }
} }

View File

@@ -10,6 +10,7 @@ import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("PluginService")
property var availablePlugins: ({}) property var availablePlugins: ({})
property var loadedPlugins: ({}) property var loadedPlugins: ({})
@@ -167,13 +168,13 @@ Singleton {
const manifest = JSON.parse(raw) const manifest = JSON.parse(raw)
root._onManifestParsed(absPath, manifest, "${sourceTag}", ${mtimeEpochMs}) root._onManifestParsed(absPath, manifest, "${sourceTag}", ${mtimeEpochMs})
} catch (e) { } catch (e) {
console.error("PluginService: bad manifest", absPath, e.message) log.error("bad manifest", absPath, e.message)
knownManifests[absPath] = { mtime: ${mtimeEpochMs}, source: "${sourceTag}", bad: true } knownManifests[absPath] = { mtime: ${mtimeEpochMs}, source: "${sourceTag}", bad: true }
} }
fv.destroy() fv.destroy()
} }
onLoadFailed: (err) => { onLoadFailed: (err) => {
console.warn("PluginService: manifest load failed", absPath, err) log.warn("manifest load failed", absPath, err)
fv.destroy() fv.destroy()
} }
} }
@@ -186,7 +187,7 @@ Singleton {
function _onManifestParsed(absPath, manifest, sourceTag, mtimeEpochMs) { function _onManifestParsed(absPath, manifest, sourceTag, mtimeEpochMs) {
if (!manifest || !manifest.id || !manifest.name || !manifest.component) { if (!manifest || !manifest.id || !manifest.name || !manifest.component) {
console.error("PluginService: invalid manifest fields:", absPath); log.error("invalid manifest fields:", absPath);
knownManifests[absPath] = { knownManifests[absPath] = {
mtime: mtimeEpochMs, mtime: mtimeEpochMs,
source: sourceTag, source: sourceTag,
@@ -269,7 +270,7 @@ Singleton {
function loadPlugin(pluginId, bustCache) { function loadPlugin(pluginId, bustCache) {
const plugin = availablePlugins[pluginId]; const plugin = availablePlugins[pluginId];
if (!plugin) { if (!plugin) {
console.error("PluginService: Plugin not found:", pluginId); log.error("Plugin not found:", pluginId);
pluginLoadFailed(pluginId, "Plugin not found"); pluginLoadFailed(pluginId, "Plugin not found");
return false; return false;
} }
@@ -296,7 +297,7 @@ Singleton {
url += "?t=" + Date.now(); url += "?t=" + Date.now();
const comp = Qt.createComponent(url, Component.PreferSynchronous); const comp = Qt.createComponent(url, Component.PreferSynchronous);
if (comp.status === Component.Error) { if (comp.status === Component.Error) {
console.error("PluginService: component error", pluginId, comp.errorString()); log.error("component error", pluginId, comp.errorString());
pluginLoadFailed(pluginId, comp.errorString()); pluginLoadFailed(pluginId, comp.errorString());
return false; return false;
} }
@@ -310,7 +311,7 @@ Singleton {
"pluginService": root "pluginService": root
}); });
if (!instance) { if (!instance) {
console.error("PluginService: failed to instantiate plugin:", pluginId, comp.errorString()); log.error("failed to instantiate plugin:", pluginId, comp.errorString());
pluginLoadFailed(pluginId, comp.errorString()); pluginLoadFailed(pluginId, comp.errorString());
return false; return false;
} }
@@ -339,7 +340,7 @@ Singleton {
pluginLoaded(pluginId); pluginLoaded(pluginId);
return true; return true;
} catch (e) { } catch (e) {
console.error("PluginService: Error loading plugin:", pluginId, e.message); log.error("Error loading plugin:", pluginId, e.message);
pluginLoadFailed(pluginId, e.message); pluginLoadFailed(pluginId, e.message);
return false; return false;
} }
@@ -348,7 +349,7 @@ Singleton {
function unloadPlugin(pluginId) { function unloadPlugin(pluginId) {
const plugin = loadedPlugins[pluginId]; const plugin = loadedPlugins[pluginId];
if (!plugin) { if (!plugin) {
console.warn("PluginService: Plugin not loaded:", pluginId); log.warn("Plugin not loaded:", pluginId);
return false; return false;
} }
@@ -392,7 +393,7 @@ Singleton {
pluginUnloaded(pluginId); pluginUnloaded(pluginId);
return true; return true;
} catch (error) { } catch (error) {
console.error("PluginService: Error unloading plugin:", pluginId, "Error:", error.message); log.error("Error unloading plugin:", pluginId, "Error:", error.message);
return false; return false;
} }
} }
@@ -705,7 +706,7 @@ Singleton {
fv.setText(content); fv.setText(content);
}); });
} catch (e) { } catch (e) {
console.warn("PluginService: Failed to write state for", pluginId, e.message); log.warn("Failed to write state for", pluginId, e.message);
} }
} }
@@ -753,14 +754,14 @@ Singleton {
process.command = ["mkdir", "-p", pluginDirectory]; process.command = ["mkdir", "-p", pluginDirectory];
process.exited.connect(function (exitCode) { process.exited.connect(function (exitCode) {
if (exitCode !== 0) { if (exitCode !== 0) {
console.error("PluginService: Failed to create plugin directory, exit code:", exitCode); log.error("Failed to create plugin directory, exit code:", exitCode);
} }
process.destroy(); process.destroy();
}); });
process.running = true; process.running = true;
return true; return true;
} else { } else {
console.error("PluginService: Failed to create mkdir process"); log.error("Failed to create mkdir process");
return false; return false;
} }
} }

View File

@@ -6,6 +6,7 @@ import Quickshell
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("PolkitService")
readonly property bool disablePolkitIntegration: Quickshell.env("DMS_DISABLE_POLKIT") === "1" readonly property bool disablePolkitIntegration: Quickshell.env("DMS_DISABLE_POLKIT") === "1"
@@ -17,6 +18,7 @@ Singleton {
const qmlString = ` const qmlString = `
import QtQuick import QtQuick
import Quickshell.Services.Polkit import Quickshell.Services.Polkit
import qs.Services
PolkitAgent { PolkitAgent {
} }
@@ -24,10 +26,10 @@ Singleton {
agent = Qt.createQmlObject(qmlString, root, "PolkitService.Agent") agent = Qt.createQmlObject(qmlString, root, "PolkitService.Agent")
polkitAvailable = true polkitAvailable = true
console.info("PolkitService: Initialized successfully") log.info("Initialized successfully")
} catch (e) { } catch (e) {
polkitAvailable = false polkitAvailable = false
console.warn("PolkitService: Polkit not available - authentication prompts disabled. This requires a newer version of Quickshell.") log.warn("Polkit not available - authentication prompts disabled. This requires a newer version of Quickshell.")
} }
} }

View File

@@ -5,9 +5,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("PortalService")
property bool accountsServiceAvailable: false property bool accountsServiceAvailable: false
property string systemProfileImage: "" property string systemProfileImage: ""
@@ -127,7 +129,7 @@ Singleton {
"iconTheme": themeName "iconTheme": themeName
}, response => { }, response => {
if (response.error) { if (response.error) {
console.warn("PortalService: Failed to set icon theme:", response.error); log.warn("Failed to set icon theme:", response.error);
} }
}); });
} }
@@ -139,7 +141,7 @@ Singleton {
"path": imagePath || "" "path": imagePath || ""
}, response => { }, response => {
if (response.error) { if (response.error) {
console.warn("PortalService: Failed to set icon file:", response.error); log.warn("Failed to set icon file:", response.error);
const errorMsg = response.error.toString(); const errorMsg = response.error.toString();
let userMessage = I18n.tr("Failed to set profile image"); let userMessage = I18n.tr("Failed to set profile image");
@@ -169,7 +171,7 @@ Singleton {
if (socketPath && socketPath.length > 0) { if (socketPath && socketPath.length > 0) {
checkDMSCapabilities(); checkDMSCapabilities();
} else { } else {
console.info("PortalService: DMS_SOCKET not set"); log.info("DMS_SOCKET not set");
} }
colorSchemeDetector.running = true; colorSchemeDetector.running = true;
} }
@@ -207,7 +209,7 @@ Singleton {
checkAccountsService(); checkAccountsService();
checkSettingsPortal(); checkSettingsPortal();
} else { } else {
console.info("PortalService: freedesktop capability not available in DMS"); log.info("freedesktop capability not available in DMS");
} }
} }

View File

@@ -8,9 +8,11 @@ import Quickshell.Hyprland
import Quickshell.I3 import Quickshell.I3
import Quickshell.Wayland import Quickshell.Wayland
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("SessionService")
property bool hasUwsm: false property bool hasUwsm: false
property bool isElogind: false property bool isElogind: false
@@ -64,15 +66,15 @@ Singleton {
detectHibernateProcess.running = true; detectHibernateProcess.running = true;
detectPrimeRunProcess.running = true; detectPrimeRunProcess.running = true;
detectWtypeProcess.running = true; detectWtypeProcess.running = true;
console.info("SessionService: Native inhibitor available:", nativeInhibitorAvailable); log.info("Native inhibitor available:", nativeInhibitorAvailable);
if (!SettingsData.loginctlLockIntegration) { if (!SettingsData.loginctlLockIntegration) {
console.log("SessionService: loginctl lock integration disabled by user"); log.debug("loginctl lock integration disabled by user");
return; return;
} }
if (socketPath && socketPath.length > 0) { if (socketPath && socketPath.length > 0) {
checkDMSCapabilities(); checkDMSCapabilities();
} else { } else {
console.log("SessionService: DMS_SOCKET not set"); log.debug("DMS_SOCKET not set");
} }
} }
} }
@@ -93,7 +95,7 @@ Singleton {
command: ["sh", "-c", "ps -eo comm= | grep -E '^(elogind|elogind-daemon)$'"] command: ["sh", "-c", "ps -eo comm= | grep -E '^(elogind|elogind-daemon)$'"]
onExited: function (exitCode) { onExited: function (exitCode) {
console.log("SessionService: Elogind detection exited with code", exitCode); log.debug("Elogind detection exited with code", exitCode);
isElogind = (exitCode === 0); isElogind = (exitCode === 0);
} }
} }
@@ -396,7 +398,7 @@ Singleton {
if (idleInhibited) { if (idleInhibited) {
return; return;
} }
console.log("SessionService: Enabling idle inhibit (native:", nativeInhibitorAvailable, ")"); log.debug("Enabling idle inhibit (native:", nativeInhibitorAvailable, ")");
idleInhibited = true; idleInhibited = true;
inhibitorChanged(); inhibitorChanged();
} }
@@ -405,7 +407,7 @@ Singleton {
if (!idleInhibited) { if (!idleInhibited) {
return; return;
} }
console.log("SessionService: Disabling idle inhibit (native:", nativeInhibitorAvailable, ")"); log.debug("Disabling idle inhibit (native:", nativeInhibitorAvailable, ")");
idleInhibited = false; idleInhibited = false;
inhibitorChanged(); inhibitorChanged();
} }
@@ -441,19 +443,19 @@ Singleton {
return ["true"]; return ["true"];
} }
console.log("SessionService: Starting systemd/elogind inhibit process"); log.debug("Starting systemd/elogind inhibit process");
return [isElogind ? "elogind-inhibit" : "systemd-inhibit", "--what=idle", "--who=quickshell", `--why=${inhibitReason}`, "--mode=block", "sleep", "infinity"]; return [isElogind ? "elogind-inhibit" : "systemd-inhibit", "--what=idle", "--who=quickshell", `--why=${inhibitReason}`, "--mode=block", "sleep", "infinity"];
} }
running: idleInhibited && !nativeInhibitorAvailable running: idleInhibited && !nativeInhibitorAvailable
onRunningChanged: { onRunningChanged: {
console.log("SessionService: Inhibit process running:", running, "(native:", nativeInhibitorAvailable, ")"); log.debug("Inhibit process running:", running, "(native:", nativeInhibitorAvailable, ")");
} }
onExited: function (exitCode) { onExited: function (exitCode) {
if (idleInhibited && exitCode !== 0 && !nativeInhibitorAvailable) { if (idleInhibited && exitCode !== 0 && !nativeInhibitorAvailable) {
console.warn("SessionService: Inhibitor process crashed with exit code:", exitCode); log.warn("Inhibitor process crashed with exit code:", exitCode);
idleInhibited = false; idleInhibited = false;
ToastService.showWarning("Idle inhibitor failed"); ToastService.showWarning("Idle inhibitor failed");
} }
@@ -545,7 +547,7 @@ Singleton {
} }
} else { } else {
loginctlAvailable = false; loginctlAvailable = false;
console.log("SessionService: loginctl capability not available in DMS"); log.debug("loginctl capability not available in DMS");
} }
if (DMSService.capabilities.includes("dbus")) { if (DMSService.capabilities.includes("dbus")) {
@@ -574,7 +576,7 @@ Singleton {
prepareForSleepSubscriptionPending = false; prepareForSleepSubscriptionPending = false;
if (response.error) { if (response.error) {
console.warn("SessionService: Failed to subscribe to PrepareForSleep:", response.error); log.warn("Failed to subscribe to PrepareForSleep:", response.error);
return; return;
} }
@@ -621,9 +623,9 @@ Singleton {
enabled: SettingsData.lockBeforeSuspend enabled: SettingsData.lockBeforeSuspend
}, response => { }, response => {
if (response.error) { if (response.error) {
console.warn("SessionService: Failed to sync lock before suspend:", response.error); log.warn("Failed to sync lock before suspend:", response.error);
} else { } else {
console.log("SessionService: Synced lock before suspend:", SettingsData.lockBeforeSuspend); log.debug("Synced lock before suspend:", SettingsData.lockBeforeSuspend);
} }
}); });
} }
@@ -637,9 +639,9 @@ Singleton {
enabled: SettingsData.loginctlLockIntegration && SettingsData.lockBeforeSuspend enabled: SettingsData.loginctlLockIntegration && SettingsData.lockBeforeSuspend
}, response => { }, response => {
if (response.error) { if (response.error) {
console.warn("SessionService: Failed to sync sleep inhibitor:", response.error); log.warn("Failed to sync sleep inhibitor:", response.error);
} else { } else {
console.log("SessionService: Synced sleep inhibitor:", SettingsData.loginctlLockIntegration); log.debug("Synced sleep inhibitor:", SettingsData.loginctlLockIntegration);
} }
}); });
} }

View File

@@ -5,9 +5,11 @@ import QtQuick
import Quickshell import Quickshell
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("SettingsSearchService")
property string query: "" property string query: ""
property var results: [] property var results: []
@@ -41,12 +43,12 @@ Singleton {
root.indexLoaded = true; root.indexLoaded = true;
root._rebuildTranslationCache(); root._rebuildTranslationCache();
} catch (e) { } catch (e) {
console.warn("SettingsSearchService: Failed to parse index:", e); log.warn("Failed to parse index:", e);
root.settingsIndex = []; root.settingsIndex = [];
root._translatedCache = []; root._translatedCache = [];
} }
} }
onLoadFailed: error => console.warn("SettingsSearchService: Failed to load index:", error) onLoadFailed: error => log.warn("Failed to load index:", error)
} }
function registerCard(settingKey, item, flickable) { function registerCard(settingKey, item, flickable) {

View File

@@ -4,9 +4,11 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import Quickshell import Quickshell
import qs.Common import qs.Common
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("VPNService")
readonly property bool available: DMSNetworkService.vpnAvailable readonly property bool available: DMSNetworkService.vpnAvailable
@@ -48,7 +50,7 @@ Singleton {
DMSService.sendRequest("network.vpn.plugins", null, response => { DMSService.sendRequest("network.vpn.plugins", null, response => {
pluginsLoading = false; pluginsLoading = false;
if (response.error) { if (response.error) {
console.warn("VPNService: Failed to fetch plugins:", response.error); log.warn("Failed to fetch plugins:", response.error);
return; return;
} }
if (!response.result) if (!response.result)

View File

@@ -3,9 +3,11 @@ pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import Quickshell import Quickshell
import qs.Services
Singleton { Singleton {
id: root id: root
readonly property var log: Log.scoped("WlrOutputService")
property bool wlrOutputAvailable: false property bool wlrOutputAvailable: false
property var outputs: [] property var outputs: []
@@ -53,7 +55,7 @@ Singleton {
const hasWlrOutput = DMSService.capabilities.includes("wlroutput"); const hasWlrOutput = DMSService.capabilities.includes("wlroutput");
if (hasWlrOutput && !wlrOutputAvailable) { if (hasWlrOutput && !wlrOutputAvailable) {
wlrOutputAvailable = true; wlrOutputAvailable = true;
console.info("WlrOutputService: wlr-output-management capability detected"); log.info("wlr-output-management capability detected");
requestState(); requestState();
return; return;
} }
@@ -81,11 +83,11 @@ Singleton {
serial = state.serial || 0; serial = state.serial || 0;
if (outputs.length === 0) { if (outputs.length === 0) {
console.warn("WlrOutputService: Received empty outputs list"); log.warn("Received empty outputs list");
} else { } else {
console.log("WlrOutputService: Updated with", outputs.length, "outputs, serial:", serial); log.debug("Updated with", outputs.length, "outputs, serial:", serial);
outputs.forEach((output, index) => { outputs.forEach((output, index) => {
console.log("WlrOutputService: Output", index, "-", output.name, "enabled:", output.enabled, "mode:", output.currentMode ? output.currentMode.width + "x" + output.currentMode.height + "@" + (output.currentMode.refresh / 1000) + "Hz" : "none"); log.debug("Output", index, "-", output.name, "enabled:", output.enabled, "mode:", output.currentMode ? output.currentMode.width + "x" + output.currentMode.height + "@" + (output.currentMode.refresh / 1000) + "Hz" : "none");
}); });
} }
stateChanged(); stateChanged();
@@ -112,9 +114,9 @@ Singleton {
return; return;
} }
console.log("WlrOutputService: Applying configuration for", heads.length, "outputs"); log.debug("Applying configuration for", heads.length, "outputs");
heads.forEach((head, index) => { heads.forEach((head, index) => {
console.log("WlrOutputService: Head", index, "- name:", head.name, "enabled:", head.enabled, "modeId:", head.modeId, "customMode:", JSON.stringify(head.customMode), "position:", JSON.stringify(head.position), "scale:", head.scale, "transform:", head.transform, "adaptiveSync:", head.adaptiveSync); log.debug("Head", index, "- name:", head.name, "enabled:", head.enabled, "modeId:", head.modeId, "customMode:", JSON.stringify(head.customMode), "position:", JSON.stringify(head.position), "scale:", head.scale, "transform:", head.transform, "adaptiveSync:", head.adaptiveSync);
}); });
DMSService.sendRequest("wlroutput.applyConfiguration", { DMSService.sendRequest("wlroutput.applyConfiguration", {
@@ -124,9 +126,9 @@ Singleton {
const message = response.error || response.result?.message || ""; const message = response.error || response.result?.message || "";
if (response.error) { if (response.error) {
console.warn("WlrOutputService: applyConfiguration error:", response.error); log.warn("applyConfiguration error:", response.error);
} else { } else {
console.log("WlrOutputService: Configuration applied successfully"); log.debug("Configuration applied successfully");
} }
configurationApplied(success, message); configurationApplied(success, message);
@@ -144,7 +146,7 @@ Singleton {
return; return;
} }
console.log("WlrOutputService: Testing configuration for", heads.length, "outputs"); log.debug("Testing configuration for", heads.length, "outputs");
DMSService.sendRequest("wlroutput.testConfiguration", { DMSService.sendRequest("wlroutput.testConfiguration", {
"heads": heads "heads": heads
@@ -153,9 +155,9 @@ Singleton {
const message = response.error || response.result?.message || ""; const message = response.error || response.result?.message || "";
if (response.error) { if (response.error) {
console.warn("WlrOutputService: testConfiguration error:", response.error); log.warn("testConfiguration error:", response.error);
} else { } else {
console.log("WlrOutputService: Configuration test passed"); log.debug("Configuration test passed");
} }
if (callback) { if (callback) {
@@ -167,7 +169,7 @@ Singleton {
function setOutputEnabled(outputName, enabled, callback) { function setOutputEnabled(outputName, enabled, callback) {
const output = getOutput(outputName); const output = getOutput(outputName);
if (!output) { if (!output) {
console.warn("WlrOutputService: Output not found:", outputName); log.warn("Output not found:", outputName);
if (callback) { if (callback) {
callback(false, "Output not found"); callback(false, "Output not found");
} }

View File

@@ -6,6 +6,7 @@ import qs.Services
PanelWindow { PanelWindow {
id: root id: root
readonly property var log: Log.scoped("DankOSD")
property string blurNamespace: "dms:osd" property string blurNamespace: "dms:osd"
WlrLayershell.namespace: blurNamespace WlrLayershell.namespace: blurNamespace
@@ -94,10 +95,10 @@ PanelWindow {
WlrLayershell.layer: { WlrLayershell.layer: {
switch (Quickshell.env("DMS_OSD_LAYER")) { switch (Quickshell.env("DMS_OSD_LAYER")) {
case "bottom": case "bottom":
console.warn("DankOSD: 'bottom' layer is not valid for OSDs. Defaulting to 'overlay' layer."); log.warn("'bottom' layer is not valid for OSDs. Defaulting to 'overlay' layer.");
return WlrLayershell.Overlay; return WlrLayershell.Overlay;
case "background": case "background":
console.warn("DankOSD: 'background' layer is not valid for OSDs. Defaulting to 'overlay' layer."); log.warn("'background' layer is not valid for OSDs. Defaulting to 'overlay' layer.");
return WlrLayershell.Overlay; return WlrLayershell.Overlay;
case "top": case "top":
return WlrLayershell.Top; return WlrLayershell.Top;

View File

@@ -6,6 +6,7 @@ import qs.Services
Item { Item {
id: root id: root
readonly property var log: Log.scoped("DankPopout")
property string layerNamespace: "dms:popout" property string layerNamespace: "dms:popout"
property alias content: contentLoader.sourceComponent property alias content: contentLoader.sourceComponent
@@ -414,10 +415,10 @@ Item {
WlrLayershell.layer: { WlrLayershell.layer: {
switch (Quickshell.env("DMS_POPOUT_LAYER")) { switch (Quickshell.env("DMS_POPOUT_LAYER")) {
case "bottom": case "bottom":
console.warn("DankPopout: 'bottom' layer is not valid for popouts. Defaulting to 'top' layer."); log.warn("'bottom' layer is not valid for popouts. Defaulting to 'top' layer.");
return WlrLayershell.Top; return WlrLayershell.Top;
case "background": case "background":
console.warn("DankPopout: 'background' layer is not valid for popouts. Defaulting to 'top' layer."); log.warn("'background' layer is not valid for popouts. Defaulting to 'top' layer.");
return WlrLayershell.Top; return WlrLayershell.Top;
case "overlay": case "overlay":
return WlrLayershell.Overlay; return WlrLayershell.Overlay;

View File

@@ -11,6 +11,7 @@ import "../Common/KeybindActions.js" as Actions
Item { Item {
id: root id: root
readonly property var log: Log.scoped("KeybindItem")
LayoutMirroring.enabled: I18n.isRtl LayoutMirroring.enabled: I18n.isRtl
LayoutMirroring.childrenInherit: true LayoutMirroring.childrenInherit: true
@@ -716,7 +717,7 @@ Item {
const key = KeyUtils.xkbKeyFromQtKey(qtKey); const key = KeyUtils.xkbKeyFromQtKey(qtKey);
if (!key) { if (!key) {
console.warn("[KeybindItem] Unknown key:", event.key, "mods:", event.modifiers); log.warn("Unknown key:", event.key, "mods:", event.modifiers);
return; return;
} }

View File

@@ -3,24 +3,25 @@ import qs.Services
Item { Item {
id: root id: root
readonly property var log: Log.scoped("PluginGlobalVar")
required property string varName required property string varName
property var defaultValue: undefined property var defaultValue: undefined
readonly property var value: { readonly property var value: {
const pid = parent?.pluginId ?? "" const pid = parent?.pluginId ?? "";
if (!pid || !PluginService.globalVars[pid]) { if (!pid || !PluginService.globalVars[pid]) {
return defaultValue return defaultValue;
} }
return PluginService.globalVars[pid][varName] ?? defaultValue return PluginService.globalVars[pid][varName] ?? defaultValue;
} }
function set(newValue) { function set(newValue) {
const pid = parent?.pluginId ?? "" const pid = parent?.pluginId ?? "";
if (pid) { if (pid) {
PluginService.setGlobalVar(pid, varName, newValue) PluginService.setGlobalVar(pid, varName, newValue);
} else { } else {
console.warn("PluginGlobalVar: Cannot set", varName, "- no pluginId from parent") log.warn("Cannot set", varName, "- no pluginId from parent");
} }
} }