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:
@@ -26,6 +26,17 @@ var runCmd = &cobra.Command{
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
daemon, _ := cmd.Flags().GetBool("daemon")
|
||||
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 {
|
||||
runShellDaemon(session)
|
||||
} else {
|
||||
|
||||
@@ -15,6 +15,8 @@ func init() {
|
||||
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("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")
|
||||
|
||||
greeterCmd.AddCommand(greeterInstallCmd, greeterSyncCmd, greeterEnableCmd, greeterStatusCmd, greeterUninstallCmd)
|
||||
|
||||
@@ -15,6 +15,8 @@ func init() {
|
||||
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("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")
|
||||
|
||||
greeterCmd.AddCommand(greeterInstallCmd, greeterSyncCmd, greeterEnableCmd, greeterStatusCmd, greeterUninstallCmd)
|
||||
|
||||
@@ -80,6 +80,16 @@ func getRuntimeDir() string {
|
||||
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 {
|
||||
_, err := exec.LookPath("systemd-run")
|
||||
return err == nil
|
||||
@@ -216,6 +226,8 @@ func runShellInteractive(session bool) {
|
||||
cmd.Env = append(cmd.Env, "QT_QPA_PLATFORM=wayland;xcb")
|
||||
}
|
||||
|
||||
cmd.Env = appendLogEnv(cmd.Env)
|
||||
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
@@ -459,6 +471,8 @@ func runShellDaemon(session bool) {
|
||||
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)
|
||||
if err != nil {
|
||||
log.Fatalf("Error opening /dev/null: %v", err)
|
||||
|
||||
@@ -66,12 +66,12 @@ require (
|
||||
github.com/go-git/go-git/v6 v6.0.0-alpha.2
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
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-runewidth v0.0.23 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // 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/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/spf13/afero v1.15.0
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
cblog "github.com/charmbracelet/log"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/muesli/termenv"
|
||||
)
|
||||
|
||||
// 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 (
|
||||
logger *Logger
|
||||
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 {
|
||||
switch strings.ToLower(level) {
|
||||
case "debug":
|
||||
@@ -86,7 +108,7 @@ func GetLogger() *Logger {
|
||||
SetString(" DEBUG").
|
||||
Foreground(lipgloss.Color("4"))
|
||||
|
||||
base := cblog.New(os.Stderr)
|
||||
base := cblog.New(logStderr)
|
||||
base.SetStyles(styles)
|
||||
base.SetReportTimestamp(false)
|
||||
|
||||
@@ -98,10 +120,85 @@ func GetLogger() *Logger {
|
||||
base.SetPrefix(" go")
|
||||
|
||||
logger = &Logger{base}
|
||||
|
||||
if path := os.Getenv("DMS_LOG_FILE"); path != "" {
|
||||
_ = SetLogFile(path)
|
||||
}
|
||||
})
|
||||
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
|
||||
|
||||
func Debug(msg any, keyvals ...any) { GetLogger().Debug(msg, keyvals...) }
|
||||
|
||||
@@ -5,9 +5,11 @@ import QtCore
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("CacheData")
|
||||
|
||||
readonly property int cacheConfigVersion: 1
|
||||
|
||||
@@ -131,7 +133,7 @@ Singleton {
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("CacheData: Failed to parse cache:", e.message);
|
||||
log.warn("Failed to parse cache:", e.message);
|
||||
} finally {
|
||||
_loading = false;
|
||||
}
|
||||
@@ -149,7 +151,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function migrateFromUndefinedToV1(cache) {
|
||||
console.info("CacheData: Migrating configuration from undefined to version 1");
|
||||
log.info("Migrating configuration from undefined to version 1");
|
||||
}
|
||||
|
||||
function cleanupUnusedKeys() {
|
||||
@@ -164,7 +166,7 @@ Singleton {
|
||||
|
||||
for (const key in cache) {
|
||||
if (!validKeys.includes(key)) {
|
||||
console.log("CacheData: Removing unused key:", key);
|
||||
log.debug("Removing unused key:", key);
|
||||
delete cache[key];
|
||||
needsSave = true;
|
||||
}
|
||||
@@ -174,7 +176,7 @@ Singleton {
|
||||
cacheFile.setText(JSON.stringify(cache, null, 2));
|
||||
}
|
||||
} 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())
|
||||
return JSON.parse(content);
|
||||
} catch (e) {
|
||||
console.warn("CacheData: Failed to parse launcher cache:", e.message);
|
||||
log.warn("Failed to parse launcher cache:", e.message);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -220,7 +222,7 @@ Singleton {
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
if (!isGreeterMode) {
|
||||
console.info("CacheData: No cache file found, starting fresh");
|
||||
log.info("No cache file found, starting fresh");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@ import QtQuick
|
||||
import Qt.labs.folderlistmodel
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("I18n")
|
||||
|
||||
property string _resolvedLocale: "en"
|
||||
|
||||
@@ -54,15 +56,15 @@ Singleton {
|
||||
try {
|
||||
root.translations = JSON.parse(text());
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -105,14 +107,14 @@ Singleton {
|
||||
_selectedPath = fileUrl;
|
||||
translationsLoaded = false;
|
||||
translations = ({});
|
||||
console.info(`I18n: Using locale '${localeTag}' from ${fileUrl}`);
|
||||
log.info(`I18n: Using locale '${localeTag}' from ${fileUrl}`);
|
||||
}
|
||||
|
||||
function _fallbackToEnglish() {
|
||||
_selectedPath = "";
|
||||
translationsLoaded = false;
|
||||
translations = ({});
|
||||
console.warn("I18n: Falling back to built-in English strings");
|
||||
log.warn("Falling back to built-in English strings");
|
||||
}
|
||||
|
||||
function tr(term, context) {
|
||||
|
||||
@@ -3,9 +3,11 @@ pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("Proc")
|
||||
|
||||
readonly property int noTimeout: -1
|
||||
property int defaultDebounceMs: 50
|
||||
@@ -112,7 +114,7 @@ Singleton {
|
||||
const safeExitCode = exitCodeValue !== null && exitCodeValue !== undefined ? exitCodeValue : -1;
|
||||
entry.callback(safeOutput, safeExitCode);
|
||||
} 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 {
|
||||
|
||||
@@ -12,6 +12,7 @@ import "settings/SessionStore.js" as Store
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("SessionData")
|
||||
|
||||
readonly property int sessionConfigVersion: 3
|
||||
|
||||
@@ -257,7 +258,7 @@ Singleton {
|
||||
} catch (e) {
|
||||
_parseError = true;
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -337,7 +338,7 @@ Singleton {
|
||||
} catch (e) {
|
||||
_parseError = true;
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -552,7 +553,7 @@ Singleton {
|
||||
}
|
||||
|
||||
if (!screen) {
|
||||
console.warn("SessionData: Screen not found");
|
||||
log.warn("Screen not found");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -649,7 +650,7 @@ Singleton {
|
||||
}
|
||||
|
||||
if (!screen) {
|
||||
console.warn("SessionData: Screen not found");
|
||||
log.warn("Screen not found");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -680,7 +681,7 @@ Singleton {
|
||||
}
|
||||
|
||||
if (!screen) {
|
||||
console.warn("SessionData: Screen not found");
|
||||
log.warn("Screen not found");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -711,7 +712,7 @@ Singleton {
|
||||
}
|
||||
|
||||
if (!screen) {
|
||||
console.warn("SessionData: Screen not found");
|
||||
log.warn("Screen not found");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -742,7 +743,7 @@ Singleton {
|
||||
}
|
||||
|
||||
if (!screen) {
|
||||
console.warn("SessionData: Screen not found");
|
||||
log.warn("Screen not found");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import "settings/SettingsStore.js" as Store
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("SettingsData")
|
||||
|
||||
readonly property int settingsConfigVersion: 5
|
||||
|
||||
@@ -1294,7 +1295,7 @@ Singleton {
|
||||
} catch (e) {
|
||||
_parseError = true;
|
||||
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));
|
||||
applyStoredTheme();
|
||||
} finally {
|
||||
@@ -1315,12 +1316,12 @@ Singleton {
|
||||
if (_isReadOnly) {
|
||||
_hasUnsavedChanges = _checkForUnsavedChanges();
|
||||
if (!wasReadOnly)
|
||||
console.info("SettingsData: settings.json is now read-only");
|
||||
log.info("settings.json is now read-only");
|
||||
} else {
|
||||
_loadedSettingsSnapshot = JSON.stringify(Store.toJson(root));
|
||||
_hasUnsavedChanges = false;
|
||||
if (wasReadOnly)
|
||||
console.info("SettingsData: settings.json is now writable");
|
||||
log.info("settings.json is now writable");
|
||||
if (_pendingMigration)
|
||||
settingsFile.setText(JSON.stringify(_pendingMigration, null, 2));
|
||||
}
|
||||
@@ -1374,7 +1375,7 @@ Singleton {
|
||||
} catch (e) {
|
||||
const msg = e.message || String(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();
|
||||
}
|
||||
}
|
||||
@@ -1391,7 +1392,7 @@ Singleton {
|
||||
} catch (e) {
|
||||
_pluginParseError = true;
|
||||
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));
|
||||
pluginSettings = {};
|
||||
} finally {
|
||||
@@ -2794,7 +2795,7 @@ Singleton {
|
||||
} catch (e) {
|
||||
_parseError = true;
|
||||
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));
|
||||
} finally {
|
||||
_loading = false;
|
||||
@@ -2829,7 +2830,7 @@ Singleton {
|
||||
if (!isGreeterMode) {
|
||||
const msg = String(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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import "StockThemes.js" as StockThemes
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("Theme")
|
||||
|
||||
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"
|
||||
@@ -148,7 +149,7 @@ Singleton {
|
||||
}
|
||||
|
||||
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 iconTheme = (typeof SettingsData !== "undefined" && SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default";
|
||||
const selectedMatugenType = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot";
|
||||
@@ -376,7 +377,7 @@ Singleton {
|
||||
"use": true
|
||||
}, response => {
|
||||
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) {
|
||||
@@ -389,13 +390,13 @@ Singleton {
|
||||
"longitude": SessionData.longitude
|
||||
}, locationResponse => {
|
||||
if (locationResponse?.error) {
|
||||
console.warn("Theme automation: Failed to set location", locationResponse.error);
|
||||
log.warn("Theme automation: Failed to set location", locationResponse.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (workerRunning) {
|
||||
console.info("Theme: Worker already running, queueing request");
|
||||
log.info("Worker already running, queueing request");
|
||||
pendingThemeRequest = {
|
||||
kind,
|
||||
value,
|
||||
@@ -1542,7 +1543,7 @@ Singleton {
|
||||
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) {
|
||||
NiriService.suppressNextToast();
|
||||
@@ -1557,7 +1558,7 @@ Singleton {
|
||||
"runUserTemplates": (typeof SettingsData !== "undefined") ? SettingsData.runUserMatugenTemplates : true
|
||||
};
|
||||
|
||||
console.log("Theme: Starting matugen worker");
|
||||
log.debug("Starting matugen worker");
|
||||
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,];
|
||||
@@ -1715,7 +1716,7 @@ Singleton {
|
||||
}
|
||||
|
||||
if (!darkTheme || !darkTheme.primary) {
|
||||
console.warn("Theme data not available for:", currentTheme);
|
||||
log.warn("Theme data not available for:", currentTheme);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1953,10 +1954,10 @@ Singleton {
|
||||
id: systemThemeGenerator
|
||||
running: false
|
||||
stdout: SplitParser {
|
||||
onRead: data => console.info("Theme worker:", data)
|
||||
onRead: data => log.info("Theme worker:", data)
|
||||
}
|
||||
stderr: SplitParser {
|
||||
onRead: data => console.warn("Theme worker:", data)
|
||||
onRead: data => log.warn("Theme worker:", data)
|
||||
}
|
||||
|
||||
onExited: exitCode => {
|
||||
@@ -1965,18 +1966,18 @@ Singleton {
|
||||
|
||||
switch (exitCode) {
|
||||
case 0:
|
||||
console.info("Theme: Matugen worker completed successfully");
|
||||
log.info("Matugen worker completed successfully");
|
||||
root.matugenCompleted(currentMode, "success");
|
||||
break;
|
||||
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");
|
||||
break;
|
||||
default:
|
||||
if (typeof ToastService !== "undefined") {
|
||||
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");
|
||||
}
|
||||
|
||||
@@ -1985,7 +1986,7 @@ Singleton {
|
||||
|
||||
const req = pendingThemeRequest;
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -2039,7 +2040,7 @@ Singleton {
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Theme: Failed to parse dynamic colors:", e);
|
||||
log.error("Failed to parse dynamic colors:", e);
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.wallpaperErrorStatus = "error";
|
||||
ToastService.showError("Dynamic colors parse error: " + e.message);
|
||||
@@ -2059,11 +2060,11 @@ Singleton {
|
||||
|
||||
onLoadFailed: function (error) {
|
||||
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;
|
||||
const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode);
|
||||
if (!isGreeterMode && matugenAvailable && rawWallpaperPath) {
|
||||
console.log("Theme: Matugen available, triggering immediate regeneration");
|
||||
log.debug("Matugen available, triggering immediate regeneration");
|
||||
generateSystemThemesFromCurrentTheme();
|
||||
}
|
||||
}
|
||||
@@ -2187,7 +2188,7 @@ Singleton {
|
||||
"endMinute": endMinute
|
||||
}, response => {
|
||||
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 (SessionData.nightModeUseIPLocation) {
|
||||
console.warn("Theme automation: Waiting for IP location from backend");
|
||||
log.warn("Theme automation: Waiting for IP location from backend");
|
||||
} else {
|
||||
console.warn("Theme automation: Location mode requires coordinates");
|
||||
log.warn("Theme automation: Location mode requires coordinates");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2364,7 +2365,7 @@ Singleton {
|
||||
"use": true
|
||||
}, response => {
|
||||
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;
|
||||
@@ -2378,7 +2379,7 @@ Singleton {
|
||||
"longitude": SessionData.longitude
|
||||
}, locResp => {
|
||||
if (locResp?.error) {
|
||||
console.warn("Theme automation: Failed to set location", locResp.error);
|
||||
log.warn("Theme automation: Failed to set location", locResp.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import qs.Services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DMSShell")
|
||||
|
||||
property bool osdSurfacesLoaded: true
|
||||
property int pendingOsdResumeReloads: 0
|
||||
@@ -54,7 +55,7 @@ Item {
|
||||
item.popoutService = PopoutService;
|
||||
}
|
||||
item.pluginId = pluginId;
|
||||
console.info("Daemon plugin loaded:", pluginId);
|
||||
log.info("Daemon plugin loaded:", pluginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,7 +94,7 @@ Item {
|
||||
}
|
||||
|
||||
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: {
|
||||
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;
|
||||
}
|
||||
|
||||
console.log("FilePicker: Launching", cmd);
|
||||
log.debug("FilePicker: Launching", cmd);
|
||||
|
||||
Quickshell.execDetached({
|
||||
command: ["sh", "-c", cmd]
|
||||
@@ -805,10 +806,10 @@ Item {
|
||||
}
|
||||
|
||||
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) {
|
||||
console.warn("DMSShell: Invalid app picker request data");
|
||||
log.warn("Invalid app picker request data");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import qs.Modules.Settings.DisplayConfig
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DMSShellIPC")
|
||||
|
||||
required property var powerMenuModalLoader
|
||||
required property var processListModalLoader
|
||||
@@ -861,7 +862,7 @@ Item {
|
||||
|
||||
function set(key: string, value: string): string {
|
||||
if (!(key in SettingsData)) {
|
||||
console.warn("Cannot set property, not found:", key);
|
||||
log.warn("Cannot set property, not found:", key);
|
||||
return "SETTINGS_INVALID_KEY";
|
||||
}
|
||||
|
||||
@@ -894,12 +895,12 @@ Item {
|
||||
throw "Unsupported type";
|
||||
}
|
||||
|
||||
console.warn("Setting:", key, value);
|
||||
log.warn("Setting:", key, value);
|
||||
SettingsData[key] = value;
|
||||
SettingsData.saveSettings();
|
||||
return "SETTINGS_SET_SUCCESS";
|
||||
} catch (e) {
|
||||
console.warn("Failed to set property:", key, "error:", e);
|
||||
log.warn("Failed to set property:", key, "error:", e);
|
||||
return "SETTINGS_SET_FAILURE";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Modals.Common
|
||||
import qs.Widgets
|
||||
@@ -7,6 +6,7 @@ import qs.Services
|
||||
|
||||
DankModal {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("AppPickerModal")
|
||||
|
||||
property string title: I18n.tr("Select Application")
|
||||
property string targetData: ""
|
||||
@@ -30,52 +30,52 @@ DankModal {
|
||||
onBackgroundClicked: close()
|
||||
|
||||
onDialogClosed: {
|
||||
searchQuery = ""
|
||||
selectedIndex = 0
|
||||
keyboardNavigationActive = false
|
||||
searchQuery = "";
|
||||
selectedIndex = 0;
|
||||
keyboardNavigationActive = false;
|
||||
}
|
||||
|
||||
onOpened: {
|
||||
searchQuery = ""
|
||||
updateApplicationList()
|
||||
selectedIndex = 0
|
||||
searchQuery = "";
|
||||
updateApplicationList();
|
||||
selectedIndex = 0;
|
||||
Qt.callLater(() => {
|
||||
if (contentLoader.item && contentLoader.item.searchField) {
|
||||
contentLoader.item.searchField.text = ""
|
||||
contentLoader.item.searchField.forceActiveFocus()
|
||||
contentLoader.item.searchField.text = "";
|
||||
contentLoader.item.searchField.forceActiveFocus();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function updateApplicationList() {
|
||||
applicationsModel.clear()
|
||||
const apps = AppSearchService.applications
|
||||
const usageHistory = usageHistoryKey && SettingsData[usageHistoryKey] ? SettingsData[usageHistoryKey] : {}
|
||||
let filteredApps = []
|
||||
applicationsModel.clear();
|
||||
const apps = AppSearchService.applications;
|
||||
const usageHistory = usageHistoryKey && SettingsData[usageHistoryKey] ? SettingsData[usageHistoryKey] : {};
|
||||
let filteredApps = [];
|
||||
|
||||
for (const app of apps) {
|
||||
if (!app || !app.categories) continue
|
||||
|
||||
let matchesCategory = categoryFilter.length === 0
|
||||
if (!app || !app.categories)
|
||||
continue;
|
||||
let matchesCategory = categoryFilter.length === 0;
|
||||
|
||||
if (categoryFilter.length > 0) {
|
||||
try {
|
||||
for (const cat of app.categories) {
|
||||
if (categoryFilter.includes(cat)) {
|
||||
matchesCategory = true
|
||||
break
|
||||
matchesCategory = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("AppPicker: Error iterating categories for", app.name, ":", e)
|
||||
continue
|
||||
log.warn("AppPicker: Error iterating categories for", app.name, ":", e);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (matchesCategory) {
|
||||
const name = app.name || ""
|
||||
const lowerName = name.toLowerCase()
|
||||
const lowerQuery = searchQuery.toLowerCase()
|
||||
const name = app.name || "";
|
||||
const lowerName = name.toLowerCase();
|
||||
const lowerQuery = searchQuery.toLowerCase();
|
||||
|
||||
if (searchQuery === "" || lowerName.includes(lowerQuery)) {
|
||||
filteredApps.push({
|
||||
@@ -84,21 +84,21 @@ DankModal {
|
||||
exec: app.exec || app.execString || "",
|
||||
startupClass: app.startupWMClass || "",
|
||||
appData: app
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filteredApps.sort((a, b) => {
|
||||
const aId = a.appData.id || a.appData.execString || a.appData.exec || ""
|
||||
const bId = b.appData.id || b.appData.execString || b.appData.exec || ""
|
||||
const aUsage = usageHistory[aId] ? usageHistory[aId].count : 0
|
||||
const bUsage = usageHistory[bId] ? usageHistory[bId].count : 0
|
||||
const aId = a.appData.id || a.appData.execString || a.appData.exec || "";
|
||||
const bId = b.appData.id || b.appData.execString || b.appData.exec || "";
|
||||
const aUsage = usageHistory[aId] ? usageHistory[aId].count : 0;
|
||||
const bUsage = usageHistory[bId] ? usageHistory[bId].count : 0;
|
||||
if (aUsage !== bUsage) {
|
||||
return bUsage - aUsage
|
||||
return bUsage - aUsage;
|
||||
}
|
||||
return (a.name || "").localeCompare(b.name || "")
|
||||
})
|
||||
return (a.name || "").localeCompare(b.name || "");
|
||||
});
|
||||
|
||||
filteredApps.forEach(app => {
|
||||
applicationsModel.append({
|
||||
@@ -107,10 +107,10 @@ DankModal {
|
||||
exec: app.exec,
|
||||
startupClass: app.startupClass,
|
||||
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()
|
||||
@@ -129,56 +129,57 @@ DankModal {
|
||||
focus: true
|
||||
|
||||
Keys.onEscapePressed: event => {
|
||||
root.close()
|
||||
event.accepted = true
|
||||
root.close();
|
||||
event.accepted = true;
|
||||
}
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (applicationsModel.count === 0) return
|
||||
if (applicationsModel.count === 0)
|
||||
return;
|
||||
|
||||
// Toggle view mode with Tab key
|
||||
if (event.key === Qt.Key_Tab) {
|
||||
root.viewMode = root.viewMode === "grid" ? "list" : "grid"
|
||||
event.accepted = true
|
||||
return
|
||||
root.viewMode = root.viewMode === "grid" ? "list" : "grid";
|
||||
event.accepted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (root.viewMode === "grid") {
|
||||
if (event.key === Qt.Key_Left) {
|
||||
root.keyboardNavigationActive = true
|
||||
root.selectedIndex = Math.max(0, root.selectedIndex - 1)
|
||||
event.accepted = true
|
||||
root.keyboardNavigationActive = true;
|
||||
root.selectedIndex = Math.max(0, root.selectedIndex - 1);
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Right) {
|
||||
root.keyboardNavigationActive = true
|
||||
root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + 1)
|
||||
event.accepted = true
|
||||
root.keyboardNavigationActive = true;
|
||||
root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + 1);
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
root.keyboardNavigationActive = true
|
||||
root.selectedIndex = Math.max(0, root.selectedIndex - root.gridColumns)
|
||||
event.accepted = true
|
||||
root.keyboardNavigationActive = true;
|
||||
root.selectedIndex = Math.max(0, root.selectedIndex - root.gridColumns);
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Down) {
|
||||
root.keyboardNavigationActive = true
|
||||
root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + root.gridColumns)
|
||||
event.accepted = true
|
||||
root.keyboardNavigationActive = true;
|
||||
root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + root.gridColumns);
|
||||
event.accepted = true;
|
||||
}
|
||||
} else {
|
||||
if (event.key === Qt.Key_Up) {
|
||||
root.keyboardNavigationActive = true
|
||||
root.selectedIndex = Math.max(0, root.selectedIndex - 1)
|
||||
event.accepted = true
|
||||
root.keyboardNavigationActive = true;
|
||||
root.selectedIndex = Math.max(0, root.selectedIndex - 1);
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Down) {
|
||||
root.keyboardNavigationActive = true
|
||||
root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + 1)
|
||||
event.accepted = true
|
||||
root.keyboardNavigationActive = true;
|
||||
root.selectedIndex = Math.min(applicationsModel.count - 1, root.selectedIndex + 1);
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
if (root.selectedIndex >= 0 && root.selectedIndex < applicationsModel.count) {
|
||||
const app = applicationsModel.get(root.selectedIndex)
|
||||
launchApplication(app)
|
||||
const app = applicationsModel.get(root.selectedIndex);
|
||||
launchApplication(app);
|
||||
}
|
||||
event.accepted = true
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +218,7 @@ DankModal {
|
||||
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"
|
||||
onClicked: {
|
||||
root.viewMode = "list"
|
||||
root.viewMode = "list";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +230,7 @@ DankModal {
|
||||
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"
|
||||
onClicked: {
|
||||
root.viewMode = "grid"
|
||||
root.viewMode = "grid";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,42 +258,42 @@ DankModal {
|
||||
keyForwardTargets: [appContent]
|
||||
|
||||
onTextEdited: {
|
||||
root.searchQuery = text
|
||||
root.searchQuery = text;
|
||||
}
|
||||
|
||||
Keys.onPressed: function (event) {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
root.close()
|
||||
event.accepted = true
|
||||
return
|
||||
root.close();
|
||||
event.accepted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const isEnterKey = [Qt.Key_Return, Qt.Key_Enter].includes(event.key)
|
||||
const hasText = text.length > 0
|
||||
const isEnterKey = [Qt.Key_Return, Qt.Key_Enter].includes(event.key);
|
||||
const hasText = text.length > 0;
|
||||
|
||||
if (isEnterKey && hasText) {
|
||||
if (root.keyboardNavigationActive && applicationsModel.count > 0) {
|
||||
const app = applicationsModel.get(root.selectedIndex)
|
||||
launchApplication(app)
|
||||
const app = applicationsModel.get(root.selectedIndex);
|
||||
launchApplication(app);
|
||||
} else if (applicationsModel.count > 0) {
|
||||
const app = applicationsModel.get(0)
|
||||
launchApplication(app)
|
||||
const app = applicationsModel.get(0);
|
||||
launchApplication(app);
|
||||
}
|
||||
event.accepted = true
|
||||
return
|
||||
event.accepted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
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 isEmptyEnter = isEnterKey && !hasText
|
||||
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 isEmptyEnter = isEnterKey && !hasText;
|
||||
|
||||
event.accepted = !(isNavigationKey || isEmptyEnter)
|
||||
event.accepted = !(isNavigationKey || isEmptyEnter);
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onShouldBeVisibleChanged() {
|
||||
if (!root.shouldBeVisible) {
|
||||
searchField.focus = false
|
||||
searchField.focus = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,12 +304,12 @@ DankModal {
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: {
|
||||
let usedHeight = 40 + Theme.spacingS
|
||||
usedHeight += 52 + Theme.spacingS
|
||||
let usedHeight = 40 + Theme.spacingS;
|
||||
usedHeight += 52 + Theme.spacingS;
|
||||
if (root.showTargetData) {
|
||||
usedHeight += 36 + Theme.spacingS
|
||||
usedHeight += 36 + Theme.spacingS;
|
||||
}
|
||||
return parent.height - usedHeight
|
||||
return parent.height - usedHeight;
|
||||
}
|
||||
radius: Theme.cornerRadius
|
||||
color: "transparent"
|
||||
@@ -320,14 +321,14 @@ DankModal {
|
||||
property int itemSpacing: Theme.spacingS
|
||||
|
||||
function ensureVisible(index) {
|
||||
if (index < 0 || index >= count) return
|
||||
|
||||
const itemY = index * (itemHeight + itemSpacing)
|
||||
const itemBottom = itemY + itemHeight
|
||||
if (index < 0 || index >= count)
|
||||
return;
|
||||
const itemY = index * (itemHeight + itemSpacing);
|
||||
const itemBottom = itemY + itemHeight;
|
||||
if (itemY < contentY) {
|
||||
contentY = itemY
|
||||
contentY = itemY;
|
||||
} else if (itemBottom > contentY + height) {
|
||||
contentY = itemBottom - height
|
||||
contentY = itemBottom - height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,9 +344,9 @@ DankModal {
|
||||
spacing: itemSpacing
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
root.selectedIndex = currentIndex
|
||||
root.selectedIndex = currentIndex;
|
||||
if (root.keyboardNavigationActive) {
|
||||
ensureVisible(currentIndex)
|
||||
ensureVisible(currentIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,11 +361,11 @@ DankModal {
|
||||
hoverUpdatesSelection: true
|
||||
|
||||
onItemClicked: (idx, modelData) => {
|
||||
launchApplication(modelData)
|
||||
launchApplication(modelData);
|
||||
}
|
||||
|
||||
onKeyboardNavigationReset: {
|
||||
root.keyboardNavigationActive = false
|
||||
root.keyboardNavigationActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -373,14 +374,14 @@ DankModal {
|
||||
id: appGrid
|
||||
|
||||
function ensureVisible(index) {
|
||||
if (index < 0 || index >= count) return
|
||||
|
||||
const itemY = Math.floor(index / root.gridColumns) * cellHeight
|
||||
const itemBottom = itemY + cellHeight
|
||||
if (index < 0 || index >= count)
|
||||
return;
|
||||
const itemY = Math.floor(index / root.gridColumns) * cellHeight;
|
||||
const itemBottom = itemY + cellHeight;
|
||||
if (itemY < contentY) {
|
||||
contentY = itemY
|
||||
contentY = itemY;
|
||||
} else if (itemBottom > contentY + height) {
|
||||
contentY = itemBottom - height
|
||||
contentY = itemBottom - height;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,9 +398,9 @@ DankModal {
|
||||
currentIndex: root.selectedIndex
|
||||
|
||||
onCurrentIndexChanged: {
|
||||
root.selectedIndex = currentIndex
|
||||
root.selectedIndex = currentIndex;
|
||||
if (root.keyboardNavigationActive) {
|
||||
ensureVisible(currentIndex)
|
||||
ensureVisible(currentIndex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,11 +414,11 @@ DankModal {
|
||||
hoverUpdatesSelection: true
|
||||
|
||||
onItemClicked: (idx, modelData) => {
|
||||
launchApplication(modelData)
|
||||
launchApplication(modelData);
|
||||
}
|
||||
|
||||
onKeyboardNavigationReset: {
|
||||
root.keyboardNavigationActive = false
|
||||
root.keyboardNavigationActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -449,22 +450,22 @@ DankModal {
|
||||
}
|
||||
|
||||
function launchApplication(app) {
|
||||
if (!app) return
|
||||
|
||||
root.applicationSelected(app, root.targetData)
|
||||
if (!app)
|
||||
return;
|
||||
root.applicationSelected(app, root.targetData);
|
||||
|
||||
if (usageHistoryKey && app.appId) {
|
||||
const usageHistory = SettingsData[usageHistoryKey] || {}
|
||||
const currentCount = usageHistory[app.appId] ? usageHistory[app.appId].count : 0
|
||||
const usageHistory = SettingsData[usageHistoryKey] || {};
|
||||
const currentCount = usageHistory[app.appId] ? usageHistory[app.appId].count : 0;
|
||||
usageHistory[app.appId] = {
|
||||
count: currentCount + 1,
|
||||
lastUsed: Date.now(),
|
||||
name: app.name
|
||||
}
|
||||
SettingsData.set(usageHistoryKey, usageHistory)
|
||||
};
|
||||
SettingsData.set(usageHistoryKey, usageHistory);
|
||||
}
|
||||
|
||||
root.close()
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import qs.Widgets
|
||||
|
||||
DankModal {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("BluetoothPairingModal")
|
||||
|
||||
layerNamespace: "dms:bluetooth-pairing"
|
||||
|
||||
@@ -24,7 +25,7 @@ DankModal {
|
||||
property string passkeyInput: ""
|
||||
|
||||
function show(pairingData) {
|
||||
console.log("BluetoothPairingModal.show() called:", JSON.stringify(pairingData));
|
||||
log.debug("BluetoothPairingModal.show() called:", JSON.stringify(pairingData));
|
||||
token = pairingData.token || "";
|
||||
deviceName = pairingData.deviceName || "";
|
||||
deviceAddress = pairingData.deviceAddr || "";
|
||||
@@ -33,7 +34,7 @@ DankModal {
|
||||
pinInput = "";
|
||||
passkeyInput = "";
|
||||
|
||||
console.log("BluetoothPairingModal: Calling open()");
|
||||
log.debug("Calling open()");
|
||||
open();
|
||||
Qt.callLater(() => {
|
||||
if (contentLoader.item) {
|
||||
|
||||
@@ -2,9 +2,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Modals
|
||||
import qs.Services
|
||||
|
||||
AppPickerModal {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("BrowserPickerModal")
|
||||
|
||||
property string url: ""
|
||||
|
||||
@@ -17,35 +19,44 @@ AppPickerModal {
|
||||
showTargetData: true
|
||||
|
||||
function shellEscape(str) {
|
||||
return "'" + str.replace(/'/g, "'\\''") + "'"
|
||||
return "'" + str.replace(/'/g, "'\\''") + "'";
|
||||
}
|
||||
|
||||
onApplicationSelected: (app, url) => {
|
||||
if (!app) return
|
||||
if (!app)
|
||||
return;
|
||||
let cmd = app.exec || "";
|
||||
const escapedUrl = shellEscape(url);
|
||||
|
||||
let cmd = app.exec || ""
|
||||
const escapedUrl = shellEscape(url)
|
||||
|
||||
let hasField = false
|
||||
if (cmd.includes("%u")) { cmd = cmd.replace("%u", escapedUrl); hasField = true }
|
||||
else if (cmd.includes("%U")) { cmd = cmd.replace("%U", escapedUrl); hasField = true }
|
||||
else if (cmd.includes("%f")) { cmd = cmd.replace("%f", escapedUrl); hasField = true }
|
||||
else if (cmd.includes("%F")) { cmd = cmd.replace("%F", escapedUrl); hasField = true }
|
||||
|
||||
cmd = cmd.replace(/%[ikc]/g, "")
|
||||
|
||||
if (!hasField) {
|
||||
cmd += " " + escapedUrl
|
||||
let hasField = false;
|
||||
if (cmd.includes("%u")) {
|
||||
cmd = cmd.replace("%u", escapedUrl);
|
||||
hasField = true;
|
||||
} else if (cmd.includes("%U")) {
|
||||
cmd = cmd.replace("%U", escapedUrl);
|
||||
hasField = true;
|
||||
} else if (cmd.includes("%f")) {
|
||||
cmd = cmd.replace("%f", escapedUrl);
|
||||
hasField = true;
|
||||
} else if (cmd.includes("%F")) {
|
||||
cmd = cmd.replace("%F", escapedUrl);
|
||||
hasField = true;
|
||||
}
|
||||
|
||||
console.log("BrowserPicker: Launching", cmd)
|
||||
cmd = cmd.replace(/%[ikc]/g, "");
|
||||
|
||||
if (!hasField) {
|
||||
cmd += " " + escapedUrl;
|
||||
}
|
||||
|
||||
log.debug("BrowserPicker: Launching", cmd);
|
||||
|
||||
Quickshell.execDetached({
|
||||
command: ["sh", "-c", cmd]
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
onViewModeChanged: {
|
||||
SettingsData.set("browserPickerViewMode", viewMode)
|
||||
SettingsData.set("browserPickerViewMode", viewMode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: thumbnail
|
||||
readonly property var log: Log.scoped("ClipboardThumbnail")
|
||||
|
||||
required property var entry
|
||||
required property string entryType
|
||||
@@ -52,7 +53,7 @@ Item {
|
||||
modal.activeImageLoads--;
|
||||
}
|
||||
if (response.error) {
|
||||
console.warn("ClipboardThumbnail: Failed to load image:", entry.id);
|
||||
log.warn("Failed to load image:", entry.id);
|
||||
return;
|
||||
}
|
||||
const data = response.result?.data;
|
||||
|
||||
@@ -7,6 +7,7 @@ import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DankModal")
|
||||
|
||||
property string layerNamespace: "dms:modal"
|
||||
property alias content: contentLoader.sourceComponent
|
||||
@@ -246,10 +247,10 @@ Item {
|
||||
return WlrLayershell.Overlay;
|
||||
switch (Quickshell.env("DMS_MODAL_LAYER")) {
|
||||
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;
|
||||
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;
|
||||
case "overlay":
|
||||
return WlrLayershell.Overlay;
|
||||
|
||||
@@ -9,6 +9,7 @@ import qs.Widgets
|
||||
|
||||
DankModal {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DankColorPickerModal")
|
||||
|
||||
layerNamespace: "dms:color-picker"
|
||||
|
||||
@@ -111,7 +112,7 @@ DankModal {
|
||||
hideInstant();
|
||||
Proc.runCommand("dms-color-pick", ["dms", "color", "pick", "--json"], (output, exitCode) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("dms color pick exited with code:", exitCode);
|
||||
log.warn("dms color pick exited with code:", exitCode);
|
||||
root.show();
|
||||
return;
|
||||
}
|
||||
@@ -120,11 +121,11 @@ DankModal {
|
||||
if (result.hex) {
|
||||
applyPickedColor(result.hex);
|
||||
} 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();
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to parse dms color pick JSON:", e);
|
||||
log.warn("Failed to parse dms color pick JSON:", e);
|
||||
root.show();
|
||||
}
|
||||
}, 0, Proc.noTimeout);
|
||||
|
||||
@@ -8,6 +8,7 @@ import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DankLauncherV2Modal")
|
||||
|
||||
visible: false
|
||||
|
||||
@@ -323,10 +324,10 @@ Item {
|
||||
WlrLayershell.layer: {
|
||||
switch (Quickshell.env("DMS_MODAL_LAYER")) {
|
||||
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;
|
||||
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;
|
||||
case "overlay":
|
||||
return WlrLayershell.Overlay;
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import QtQuick
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("GreeterDoctorPage")
|
||||
|
||||
property bool isRunning: false
|
||||
property bool hasRun: false
|
||||
@@ -228,9 +230,7 @@ Item {
|
||||
text: {
|
||||
if (root.errorCount === 0)
|
||||
return I18n.tr("All checks passed", "greeter doctor page success");
|
||||
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);
|
||||
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);
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: root.errorCount > 0 ? Theme.error : Theme.surfaceVariantText
|
||||
@@ -412,7 +412,7 @@ Item {
|
||||
else
|
||||
root.selectedFilter = "ok";
|
||||
} catch (e) {
|
||||
console.error("GreeterDoctorPage: Failed to parse doctor output:", e);
|
||||
log.error("Failed to parse doctor output:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import qs.Widgets
|
||||
|
||||
FloatingWindow {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("GreeterModal")
|
||||
|
||||
property bool disablePopupTransparency: true
|
||||
property int currentPage: 0
|
||||
@@ -105,7 +106,7 @@ FloatingWindow {
|
||||
root.cheatsheetData = JSON.parse(trimmed);
|
||||
root.cheatsheetLoaded = true;
|
||||
} catch (e) {
|
||||
console.warn("Greeter: Failed to parse cheatsheet:", e);
|
||||
log.warn("Greeter: Failed to parse cheatsheet:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import qs.Widgets
|
||||
|
||||
FloatingWindow {
|
||||
id: processListModal
|
||||
readonly property var log: Log.scoped("ProcessListModal")
|
||||
|
||||
property bool disablePopupTransparency: true
|
||||
property int currentTab: 0
|
||||
@@ -22,7 +23,7 @@ FloatingWindow {
|
||||
|
||||
function show() {
|
||||
if (!DgopService.dgopAvailable) {
|
||||
console.warn("ProcessListModal: dgop is not available");
|
||||
log.warn("dgop is not available");
|
||||
return;
|
||||
}
|
||||
visible = true;
|
||||
@@ -36,7 +37,7 @@ FloatingWindow {
|
||||
|
||||
function toggle() {
|
||||
if (!DgopService.dgopAvailable) {
|
||||
console.warn("ProcessListModal: dgop is not available");
|
||||
log.warn("dgop is not available");
|
||||
return;
|
||||
}
|
||||
visible = !visible;
|
||||
@@ -44,7 +45,7 @@ FloatingWindow {
|
||||
|
||||
function focusOrToggle() {
|
||||
if (!DgopService.dgopAvailable) {
|
||||
console.warn("ProcessListModal: dgop is not available");
|
||||
log.warn("dgop is not available");
|
||||
return;
|
||||
}
|
||||
if (visible) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import qs.Widgets
|
||||
|
||||
FloatingWindow {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("WorkspaceRenameModal")
|
||||
|
||||
property bool disablePopupTransparency: true
|
||||
readonly property int inputFieldHeight: Theme.fontSizeMedium + Theme.spacingL * 2
|
||||
@@ -39,7 +40,7 @@ FloatingWindow {
|
||||
} else if (CompositorService.isHyprland) {
|
||||
HyprlandService.renameWorkspace(name);
|
||||
} else {
|
||||
console.warn("WorkspaceRenameModal: rename not supported for this compositor");
|
||||
log.warn("rename not supported for this compositor");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import "../utils/layout.js" as LayoutUtils
|
||||
|
||||
Column {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DragDropGrid")
|
||||
|
||||
property bool editMode: false
|
||||
property string expandedSection: ""
|
||||
@@ -988,7 +989,7 @@ Column {
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("DragDropGrid: stale plugin component for", pluginId, "- reloading");
|
||||
log.warn("stale plugin component for", pluginId, "- reloading");
|
||||
PluginService.reloadPlugin(pluginId);
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -6,6 +6,7 @@ import "../utils/widgets.js" as WidgetUtils
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("WidgetModel")
|
||||
|
||||
property var vpnBuiltinInstance: null
|
||||
property var cupsBuiltinInstance: null
|
||||
@@ -26,7 +27,7 @@ QtObject {
|
||||
const widgets = SettingsData.controlCenterWidgets || [];
|
||||
const hasVpnWidget = widgets.some(w => w.id === "builtin_vpn");
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -55,7 +56,7 @@ QtObject {
|
||||
const widgets = SettingsData.controlCenterWidgets || [];
|
||||
const hasCupsWidget = widgets.some(w => w.id === "builtin_cups");
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Modules.ControlCenter.Widgets
|
||||
import qs.Services
|
||||
|
||||
CompoundPill {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("ColorPickerPill")
|
||||
|
||||
property var colorPickerModal: null
|
||||
|
||||
@@ -14,14 +16,14 @@ CompoundPill {
|
||||
secondaryText: I18n.tr("Choose a color")
|
||||
|
||||
onToggled: {
|
||||
console.log("ColorPickerPill toggled, modal:", colorPickerModal);
|
||||
log.debug("ColorPickerPill toggled, modal:", colorPickerModal);
|
||||
if (colorPickerModal) {
|
||||
colorPickerModal.show();
|
||||
}
|
||||
}
|
||||
|
||||
onExpandClicked: {
|
||||
console.log("ColorPickerPill expandClicked, modal:", colorPickerModal);
|
||||
log.debug("ColorPickerPill expandClicked, modal:", colorPickerModal);
|
||||
if (colorPickerModal) {
|
||||
colorPickerModal.show();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import qs.Services
|
||||
|
||||
PanelWindow {
|
||||
id: barWindow
|
||||
readonly property var log: Log.scoped("DankBarWindow")
|
||||
|
||||
required property var rootWindow
|
||||
required property var barConfig
|
||||
@@ -164,7 +165,7 @@ PanelWindow {
|
||||
barWindow.BackgroundEffect.blurRegion = region;
|
||||
barWindow.blurRegion = region;
|
||||
} 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 {
|
||||
target: PluginService
|
||||
function onPluginLoaded(pluginId) {
|
||||
console.info("DankBar: Plugin loaded:", pluginId);
|
||||
log.info("DankBar: Plugin loaded:", pluginId);
|
||||
SettingsData.widgetDataChanged();
|
||||
}
|
||||
function onPluginUnloaded(pluginId) {
|
||||
console.info("DankBar: Plugin unloaded:", pluginId);
|
||||
log.info("DankBar: Plugin unloaded:", pluginId);
|
||||
SettingsData.widgetDataChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import qs.Widgets
|
||||
|
||||
BasePill {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("AppsDock")
|
||||
|
||||
enableBackgroundHover: false
|
||||
enableCursor: false
|
||||
@@ -550,9 +551,9 @@ BasePill {
|
||||
showBadge: root.showOverflowBadge
|
||||
z: 10
|
||||
onClicked: {
|
||||
console.log("Overflow button clicked! Current state:", root.overflowExpanded);
|
||||
log.debug("Overflow button clicked! Current state:", root.overflowExpanded);
|
||||
root.overflowExpanded = !root.overflowExpanded;
|
||||
console.log("New state:", root.overflowExpanded);
|
||||
log.debug("New state:", root.overflowExpanded);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import qs.Widgets
|
||||
|
||||
BasePill {
|
||||
id: battery
|
||||
readonly property var log: Log.scoped("Battery")
|
||||
|
||||
property bool batteryPopupVisible: false
|
||||
property var popoutTarget: null
|
||||
@@ -130,13 +131,13 @@ BasePill {
|
||||
// Check if this is a touchpad
|
||||
if (delta !== 120 && delta !== -120) {
|
||||
touchpadAccumulator += delta;
|
||||
console.info("Acc: "+touchpadAccumulator);
|
||||
log.info("Acc: " + touchpadAccumulator);
|
||||
if (Math.abs(touchpadAccumulator) < 500)
|
||||
return;
|
||||
delta = touchpadAccumulator;
|
||||
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
|
||||
if (typeof PowerProfiles === "undefined") {
|
||||
@@ -149,11 +150,14 @@ BasePill {
|
||||
var index = profiles.findIndex(profile => PowerProfiles.profile === profile);
|
||||
|
||||
// Step once based on mouse wheel direction
|
||||
if (delta > 0) index += 1;
|
||||
else index -= 1;
|
||||
if (delta > 0)
|
||||
index += 1;
|
||||
else
|
||||
index -= 1;
|
||||
|
||||
// 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
|
||||
PowerProfiles.profile = profiles[index];
|
||||
|
||||
@@ -6,6 +6,7 @@ import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("CalendarOverviewCard")
|
||||
|
||||
implicitWidth: SettingsData.showWeekNumber ? 736 : 700
|
||||
|
||||
@@ -521,7 +522,7 @@ Rectangle {
|
||||
onClicked: {
|
||||
if (modelData.url && modelData.url !== "") {
|
||||
if (Qt.openUrlExternally(modelData.url) === false) {
|
||||
console.warn("Failed to open URL: " + modelData.url);
|
||||
log.warn("Failed to open URL: " + modelData.url);
|
||||
} else {
|
||||
root.closeDash();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("WeatherTab")
|
||||
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
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()));
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Weather Date Sync Error:", e);
|
||||
log.warn("Weather Date Sync Error:", e);
|
||||
}
|
||||
|
||||
syncing = false;
|
||||
|
||||
@@ -5,9 +5,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import "GreetdEnv.js" as GreetdEnv
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
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 sessionConfigPath: greetCfgDir + "/session.json"
|
||||
@@ -42,7 +44,7 @@ Singleton {
|
||||
nightModeEnabled = config.nightModeEnabled !== undefined ? config.nightModeEnabled : false;
|
||||
}
|
||||
} 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)
|
||||
saveMemory();
|
||||
} 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());
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import "GreetdEnv.js" as GreetdEnv
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("GreetdSettings")
|
||||
|
||||
readonly property string configPath: {
|
||||
const greetCfgDir = Quickshell.env("DMS_GREET_CFG_DIR") || "/var/cache/dms-greeter";
|
||||
@@ -81,8 +83,7 @@ Singleton {
|
||||
|
||||
currentThemeName = settings.currentThemeName !== undefined ? settings.currentThemeName : "purple";
|
||||
customThemeFile = settings.customThemeFile !== undefined ? settings.customThemeFile : "";
|
||||
registryThemeVariants = settings.registryThemeVariants !== undefined ?
|
||||
settings.registryThemeVariants : ({});
|
||||
registryThemeVariants = settings.registryThemeVariants !== undefined ? settings.registryThemeVariants : ({});
|
||||
matugenScheme = settings.matugenScheme !== undefined ? settings.matugenScheme : "scheme-tonal-spot";
|
||||
use24HourClock = settings.use24HourClock !== undefined ? settings.use24HourClock : true;
|
||||
showSeconds = settings.showSeconds !== undefined ? settings.showSeconds : false;
|
||||
@@ -142,7 +143,7 @@ Singleton {
|
||||
Theme.applyGreeterTheme(currentThemeName);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to parse greetd settings:", e);
|
||||
log.warn("Failed to parse greetd settings:", e);
|
||||
} finally {
|
||||
settingsLoaded = true;
|
||||
}
|
||||
@@ -192,7 +193,7 @@ Singleton {
|
||||
parseSettings(settingsFile.text());
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
console.warn("Failed to load greetd settings:", error);
|
||||
log.warn("Failed to load greetd settings:", error);
|
||||
root.parseSettings("");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Services
|
||||
|
||||
Item {
|
||||
id: keyboard_controller
|
||||
readonly property var log: Log.scoped("KeyboardController")
|
||||
|
||||
// reference on the TextInput
|
||||
property Item target
|
||||
@@ -14,21 +16,20 @@ Item {
|
||||
|
||||
function show() {
|
||||
if (!isKeyboardActive && keyboard === null) {
|
||||
keyboard = keyboardComponent.createObject(
|
||||
keyboard_controller.rootObject)
|
||||
keyboard.target = keyboard_controller.target
|
||||
keyboard.dismissed.connect(hide)
|
||||
isKeyboardActive = true
|
||||
keyboard = keyboardComponent.createObject(keyboard_controller.rootObject);
|
||||
keyboard.target = keyboard_controller.target;
|
||||
keyboard.dismissed.connect(hide);
|
||||
isKeyboardActive = true;
|
||||
} else
|
||||
console.log("The keyboard is already shown")
|
||||
log.debug("The keyboard is already shown");
|
||||
}
|
||||
|
||||
function hide() {
|
||||
if (isKeyboardActive && keyboard !== null) {
|
||||
keyboard.destroy()
|
||||
isKeyboardActive = false
|
||||
keyboard.destroy();
|
||||
isKeyboardActive = false;
|
||||
} else
|
||||
console.log("The keyboard is already hidden")
|
||||
log.debug("The keyboard is already hidden");
|
||||
}
|
||||
|
||||
// private
|
||||
|
||||
@@ -14,6 +14,7 @@ import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("LockScreenContent")
|
||||
|
||||
function encodeFileUrl(path) {
|
||||
if (!path)
|
||||
@@ -95,9 +96,9 @@ Item {
|
||||
if (SessionService.loginctlAvailable && DMSService.apiVersion >= 2) {
|
||||
DMSService.sendRequest("loginctl.lockerReady", null, resp => {
|
||||
if (resp?.error)
|
||||
console.warn("lockerReady failed:", resp.error);
|
||||
log.warn("lockerReady failed:", resp.error);
|
||||
else
|
||||
console.log("lockerReady sent (afterAnimating/afterRendering)");
|
||||
log.debug("lockerReady sent (afterAnimating/afterRendering)");
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -803,7 +804,7 @@ Item {
|
||||
}
|
||||
|
||||
if (pam.passwd.active) {
|
||||
console.log("PAM is active, ignoring input");
|
||||
log.debug("PAM is active, ignoring input");
|
||||
event.accepted = true;
|
||||
return;
|
||||
}
|
||||
@@ -1622,7 +1623,7 @@ Item {
|
||||
buttonSize: 40
|
||||
onClicked: {
|
||||
if (demoMode) {
|
||||
console.log("Demo: Power Menu");
|
||||
log.debug("Demo: Power Menu");
|
||||
} else {
|
||||
powerMenu.show();
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Services
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("LockScreenDemo")
|
||||
|
||||
property bool demoActive: false
|
||||
|
||||
@@ -25,12 +27,12 @@ PanelWindow {
|
||||
color: "transparent"
|
||||
|
||||
function showDemo(): void {
|
||||
console.log("Showing lock screen demo");
|
||||
log.debug("Showing lock screen demo");
|
||||
demoActive = true;
|
||||
}
|
||||
|
||||
function hideDemo(): void {
|
||||
console.log("Hiding lock screen demo");
|
||||
log.debug("Hiding lock screen demo");
|
||||
demoActive = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import qs.Services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("VideoScreensaver")
|
||||
|
||||
required property string screenName
|
||||
property bool active: false
|
||||
@@ -53,7 +54,7 @@ Item {
|
||||
|
||||
onExited: exitCode => {
|
||||
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"));
|
||||
root.dismiss();
|
||||
}
|
||||
@@ -98,14 +99,14 @@ Item {
|
||||
`, background, "VideoScreensaver.VideoPlayer");
|
||||
|
||||
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);
|
||||
root.dismiss();
|
||||
});
|
||||
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.warn("VideoScreensaver: Failed to create video player:", e);
|
||||
log.warn("Failed to create video player:", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("PluginSettings")
|
||||
|
||||
required property string pluginId
|
||||
property var pluginService: null
|
||||
@@ -131,7 +133,7 @@ Item {
|
||||
return;
|
||||
}
|
||||
if (!hasPermission) {
|
||||
console.warn("PluginSettings: Plugin", pluginId, "does not have settings_write permission");
|
||||
log.warn("Plugin", pluginId, "does not have settings_write permission");
|
||||
return;
|
||||
}
|
||||
if (pluginService.savePluginData) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DisplayConfigState")
|
||||
|
||||
readonly property bool hasOutputBackend: WlrOutputService.wlrOutputAvailable
|
||||
readonly property var wlrOutputs: WlrOutputService.outputs
|
||||
@@ -106,7 +107,7 @@ Singleton {
|
||||
function findMatchingProfile() {
|
||||
const profiles = validatedProfiles;
|
||||
|
||||
console.log("[Profile Match] Current outputs:", JSON.stringify(currentOutputSet));
|
||||
log.debug("[Profile Match] Current outputs:", JSON.stringify(currentOutputSet));
|
||||
|
||||
let bestMatch = "";
|
||||
let bestScore = -1;
|
||||
@@ -116,25 +117,25 @@ Singleton {
|
||||
const profile = profiles[profileId];
|
||||
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;
|
||||
for (const output of currentOutputSet) {
|
||||
if (!profileSet.has(output)) {
|
||||
console.log("[Profile Match] - Missing output:", output);
|
||||
log.debug("[Profile Match] - Missing output:", output);
|
||||
allCurrentPresent = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!allCurrentPresent) {
|
||||
console.log("[Profile Match] - SKIP: not all current outputs present");
|
||||
log.debug("[Profile Match] - SKIP: not all current outputs present");
|
||||
continue;
|
||||
}
|
||||
|
||||
const disconnectedCount = profile.outputSet.length - currentOutputSet.length;
|
||||
const score = currentOutputSet.length * 100 - disconnectedCount;
|
||||
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)) {
|
||||
bestScore = score;
|
||||
@@ -142,7 +143,7 @@ Singleton {
|
||||
bestUpdatedAt = updatedAt;
|
||||
}
|
||||
}
|
||||
console.log("[Profile Match] Best match:", bestMatch, "score:", bestScore);
|
||||
log.debug("[Profile Match] Best match:", bestMatch, "score:", bestScore);
|
||||
return bestMatch;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import qs.Services
|
||||
|
||||
Column {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("WidgetsTabSection")
|
||||
|
||||
property var items: []
|
||||
property var allWidgets: []
|
||||
@@ -1726,11 +1727,11 @@ Column {
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||
|
||||
onOpened: {
|
||||
console.log("Privacy context menu opened");
|
||||
log.debug("Privacy context menu opened");
|
||||
}
|
||||
|
||||
onClosed: {
|
||||
console.log("Privacy Center context menu closed");
|
||||
log.debug("Privacy Center context menu closed");
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
|
||||
@@ -7,6 +7,7 @@ import qs.Widgets
|
||||
import qs.Services
|
||||
|
||||
Variants {
|
||||
readonly property var log: Log.scoped("WallpaperBackground")
|
||||
model: {
|
||||
if (SessionData.isGreeterMode) {
|
||||
return Quickshell.screens;
|
||||
@@ -103,7 +104,7 @@ Variants {
|
||||
function _recheckScreenScale() {
|
||||
const newScale = CompositorService.getScreenScale(modelData);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("OverviewWidget")
|
||||
required property var panelWindow
|
||||
required property bool overviewOpen
|
||||
readonly property HyprlandMonitor monitor: Hyprland.monitorFor(panelWindow.screen)
|
||||
@@ -276,7 +277,7 @@ Item {
|
||||
}
|
||||
return result;
|
||||
} catch (e) {
|
||||
console.error("OverviewWidget filter error:", e);
|
||||
log.error("OverviewWidget filter error:", e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@ pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("AppSearchService")
|
||||
|
||||
property var applications: []
|
||||
property var _cachedCategories: null
|
||||
@@ -811,7 +813,7 @@ Singleton {
|
||||
});
|
||||
isPersistent = false;
|
||||
} catch (e) {
|
||||
console.warn("AppSearchService: Error creating temporary plugin instance", pluginId, ":", e);
|
||||
log.warn("Error creating temporary plugin instance", pluginId, ":", e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -831,7 +833,7 @@ Singleton {
|
||||
instance.destroy();
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("AppSearchService: Error getting items from plugin", pluginId, ":", e);
|
||||
log.warn("Error getting items from plugin", pluginId, ":", e);
|
||||
if (!isPersistent)
|
||||
instance.destroy();
|
||||
}
|
||||
@@ -857,7 +859,7 @@ Singleton {
|
||||
});
|
||||
isPersistent = false;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
@@ -877,7 +879,7 @@ Singleton {
|
||||
instance.destroy();
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("AppSearchService: Error executing item from plugin", pluginId, ":", e);
|
||||
log.warn("Error executing item from plugin", pluginId, ":", e);
|
||||
if (!isPersistent)
|
||||
instance.destroy();
|
||||
}
|
||||
@@ -949,7 +951,7 @@ Singleton {
|
||||
try {
|
||||
return instance.getCategories() || [];
|
||||
} catch (e) {
|
||||
console.warn("AppSearchService: Error getting categories from plugin", pluginId, ":", e);
|
||||
log.warn("Error getting categories from plugin", pluginId, ":", e);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -968,7 +970,7 @@ Singleton {
|
||||
try {
|
||||
instance.setCategory(categoryId);
|
||||
} catch (e) {
|
||||
console.warn("AppSearchService: Error setting category on plugin", pluginId, ":", e);
|
||||
log.warn("Error setting category on plugin", pluginId, ":", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("AudioService")
|
||||
|
||||
readonly property PwNode sink: Pipewire.defaultAudioSink
|
||||
readonly property PwNode source: Pipewire.defaultAudioSource
|
||||
@@ -143,7 +144,7 @@ Singleton {
|
||||
|
||||
function setDeviceAlias(nodeName, customAlias) {
|
||||
if (!nodeName) {
|
||||
console.error("AudioService: Cannot set alias - nodeName is empty");
|
||||
log.error("Cannot set alias - nodeName is empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -189,8 +190,8 @@ EOFCONFIG
|
||||
|
||||
Proc.runCommand("writeWireplumberConfig", ["sh", "-c", shellCmd], (output, exitCode) => {
|
||||
if (exitCode !== 0) {
|
||||
console.error("AudioService: Failed to write WirePlumber config. Exit code:", exitCode);
|
||||
console.error("AudioService: Error output:", output);
|
||||
log.error("Failed to write WirePlumber config. Exit code:", exitCode);
|
||||
log.error("Error output:", output);
|
||||
ToastService.showError(I18n.tr("Failed to save audio config"), output || "");
|
||||
return;
|
||||
}
|
||||
@@ -305,7 +306,7 @@ EOFCONFIG
|
||||
ToastService.showInfo(I18n.tr("Audio system restarted"), I18n.tr("Device names updated"));
|
||||
wireplumberReloadCompleted(true);
|
||||
} 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);
|
||||
wireplumberReloadCompleted(false);
|
||||
}
|
||||
@@ -317,7 +318,7 @@ EOFCONFIG
|
||||
|
||||
Proc.runCommand("readWireplumberConfig", ["cat", configPath], (output, exitCode) => {
|
||||
if (exitCode !== 0) {
|
||||
console.log("AudioService: No existing WirePlumber config found");
|
||||
log.debug("No existing WirePlumber config found");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -340,7 +341,7 @@ EOFCONFIG
|
||||
|
||||
if (Object.keys(aliases).length > 0) {
|
||||
deviceAliases = aliases;
|
||||
console.log("AudioService: Loaded", Object.keys(aliases).length, "device aliases");
|
||||
log.debug("Loaded", Object.keys(aliases).length, "device aliases");
|
||||
}
|
||||
}, 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) => {
|
||||
if (exitCode === 0 && output.trim()) {
|
||||
currentSoundTheme = output.trim();
|
||||
console.log("AudioService: Current system sound theme:", currentSoundTheme);
|
||||
log.debug("Current system sound theme:", currentSoundTheme);
|
||||
if (SettingsData.useSystemSoundTheme) {
|
||||
discoverSoundFiles(currentSoundTheme);
|
||||
}
|
||||
} else {
|
||||
currentSoundTheme = "";
|
||||
console.log("AudioService: No system sound theme found");
|
||||
log.debug("No system sound theme found");
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
@@ -510,22 +511,22 @@ EOFCONFIG
|
||||
const themeLower = currentSoundTheme.toLowerCase();
|
||||
if (SettingsData.useSystemSoundTheme && specialConditions[themeLower]?.includes(soundEvent)) {
|
||||
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;
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
discoverSoundFiles(currentSoundTheme);
|
||||
} else {
|
||||
@@ -549,7 +550,7 @@ EOFCONFIG
|
||||
MediaDevices {
|
||||
id: devices
|
||||
Component.onCompleted: {
|
||||
console.log("AudioService: MediaDevices initialized, default output:", defaultAudioOutput?.description)
|
||||
log.debug("MediaDevices initialized, default output:", defaultAudioOutput?.description)
|
||||
}
|
||||
}
|
||||
`, root, "AudioService.MediaDevices");
|
||||
@@ -560,7 +561,7 @@ EOFCONFIG
|
||||
Connections {
|
||||
target: root.mediaDevices
|
||||
function onDefaultAudioOutputChanged() {
|
||||
console.log("AudioService: Default audio output changed, recreating sound players")
|
||||
log.debug("Default audio output changed, recreating sound players")
|
||||
root.destroySoundPlayers()
|
||||
root.createSoundPlayers()
|
||||
}
|
||||
@@ -568,7 +569,7 @@ EOFCONFIG
|
||||
`, root, "AudioService.MediaDevicesConnections");
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("AudioService: MediaDevices not available, using default audio output");
|
||||
log.debug("MediaDevices not available, using default audio output");
|
||||
mediaDevices = null;
|
||||
}
|
||||
}
|
||||
@@ -682,7 +683,7 @@ EOFCONFIG
|
||||
}
|
||||
`, root, "AudioService.LoginSound");
|
||||
} catch (e) {
|
||||
console.warn("AudioService: Error creating sound players:", e);
|
||||
log.warn("Error creating sound players:", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
@@ -19,206 +18,217 @@ Singleton {
|
||||
readonly property bool enhancedPairingAvailable: DMSService.dmsAvailable && DMSService.apiVersion >= 9 && DMSService.capabilities.includes("bluetooth")
|
||||
readonly property bool connected: {
|
||||
if (!adapter || !adapter.devices) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
let isConnected = false
|
||||
adapter.devices.values.forEach(dev => { if (dev.connected) isConnected = true })
|
||||
return isConnected
|
||||
let isConnected = false;
|
||||
adapter.devices.values.forEach(dev => {
|
||||
if (dev.connected)
|
||||
isConnected = true;
|
||||
});
|
||||
return isConnected;
|
||||
}
|
||||
readonly property var pairedDevices: {
|
||||
if (!adapter || !adapter.devices) {
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
|
||||
return adapter.devices.values.filter(dev => {
|
||||
return dev && (dev.paired || dev.trusted)
|
||||
})
|
||||
return dev && (dev.paired || dev.trusted);
|
||||
});
|
||||
}
|
||||
readonly property var allDevicesWithBattery: {
|
||||
if (!adapter || !adapter.devices) {
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
|
||||
return adapter.devices.values.filter(dev => {
|
||||
return dev && dev.batteryAvailable && dev.battery > 0
|
||||
})
|
||||
return dev && dev.batteryAvailable && dev.battery > 0;
|
||||
});
|
||||
}
|
||||
|
||||
function sortDevices(devices) {
|
||||
return devices.sort((a, b) => {
|
||||
const aName = a.name || a.deviceName || ""
|
||||
const bName = b.name || b.deviceName || ""
|
||||
const aAddr = a.address || ""
|
||||
const bAddr = b.address || ""
|
||||
const aName = a.name || a.deviceName || "";
|
||||
const bName = b.name || b.deviceName || "";
|
||||
const aAddr = a.address || "";
|
||||
const bAddr = b.address || "";
|
||||
|
||||
const aHasRealName = aName.includes(" ") && aName.length > 3
|
||||
const bHasRealName = bName.includes(" ") && bName.length > 3
|
||||
const aHasRealName = aName.includes(" ") && aName.length > 3;
|
||||
const bHasRealName = bName.includes(" ") && bName.length > 3;
|
||||
|
||||
if (aHasRealName && !bHasRealName) return -1
|
||||
if (!aHasRealName && bHasRealName) return 1
|
||||
if (aHasRealName && !bHasRealName)
|
||||
return -1;
|
||||
if (!aHasRealName && bHasRealName)
|
||||
return 1;
|
||||
|
||||
if (aHasRealName && bHasRealName) {
|
||||
return aName.localeCompare(bName)
|
||||
return aName.localeCompare(bName);
|
||||
}
|
||||
|
||||
return aAddr.localeCompare(bAddr)
|
||||
})
|
||||
return aAddr.localeCompare(bAddr);
|
||||
});
|
||||
}
|
||||
|
||||
function getDeviceIcon(device) {
|
||||
if (!device) {
|
||||
return "bluetooth"
|
||||
return "bluetooth";
|
||||
}
|
||||
|
||||
const name = (device.name || device.deviceName || "").toLowerCase()
|
||||
const icon = (device.icon || "").toLowerCase()
|
||||
const name = (device.name || device.deviceName || "").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))) {
|
||||
return "headset"
|
||||
return "headset";
|
||||
}
|
||||
|
||||
if (icon.includes("mouse") || name.includes("mouse")) {
|
||||
return "mouse"
|
||||
return "mouse";
|
||||
}
|
||||
|
||||
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))) {
|
||||
return "smartphone"
|
||||
return "smartphone";
|
||||
}
|
||||
|
||||
if (icon.includes("watch") || name.includes("watch")) {
|
||||
return "watch"
|
||||
return "watch";
|
||||
}
|
||||
|
||||
if (icon.includes("speaker") || name.includes("speaker")) {
|
||||
return "speaker"
|
||||
return "speaker";
|
||||
}
|
||||
|
||||
if (icon.includes("display") || name.includes("tv")) {
|
||||
return "tv"
|
||||
return "tv";
|
||||
}
|
||||
|
||||
return "bluetooth"
|
||||
return "bluetooth";
|
||||
}
|
||||
|
||||
function canConnect(device) {
|
||||
if (!device) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
return !device.paired && !device.pairing && !device.blocked
|
||||
return !device.paired && !device.pairing && !device.blocked;
|
||||
}
|
||||
|
||||
function getSignalStrength(device) {
|
||||
if (!device || device.signalStrength === undefined || device.signalStrength <= 0) {
|
||||
return "Unknown"
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
const signal = device.signalStrength
|
||||
const signal = device.signalStrength;
|
||||
if (signal >= 80) {
|
||||
return "Excellent"
|
||||
return "Excellent";
|
||||
}
|
||||
if (signal >= 60) {
|
||||
return "Good"
|
||||
return "Good";
|
||||
}
|
||||
if (signal >= 40) {
|
||||
return "Fair"
|
||||
return "Fair";
|
||||
}
|
||||
if (signal >= 20) {
|
||||
return "Poor"
|
||||
return "Poor";
|
||||
}
|
||||
|
||||
return "Very Poor"
|
||||
return "Very Poor";
|
||||
}
|
||||
|
||||
function getSignalIcon(device) {
|
||||
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) {
|
||||
return "signal_cellular_4_bar"
|
||||
return "signal_cellular_4_bar";
|
||||
}
|
||||
if (signal >= 60) {
|
||||
return "signal_cellular_3_bar"
|
||||
return "signal_cellular_3_bar";
|
||||
}
|
||||
if (signal >= 40) {
|
||||
return "signal_cellular_2_bar"
|
||||
return "signal_cellular_2_bar";
|
||||
}
|
||||
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) {
|
||||
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) {
|
||||
if (!device) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
device.trusted = true
|
||||
device.connect()
|
||||
device.trusted = true;
|
||||
device.connect();
|
||||
}
|
||||
|
||||
function pairDevice(device, callback) {
|
||||
if (!device) {
|
||||
if (callback) callback({error: "Invalid device"})
|
||||
return
|
||||
if (callback)
|
||||
callback({
|
||||
error: "Invalid device"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// The DMS backend actually implements a bluez agent, so we can pair anything
|
||||
if (enhancedPairingAvailable) {
|
||||
const devicePath = getDevicePath(device)
|
||||
DMSService.bluetoothPair(devicePath, callback)
|
||||
return
|
||||
const devicePath = getDevicePath(device);
|
||||
DMSService.bluetoothPair(devicePath, callback);
|
||||
return;
|
||||
}
|
||||
|
||||
// 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.connect()
|
||||
if (callback) callback({success: true})
|
||||
device.trusted = true;
|
||||
device.connect();
|
||||
if (callback)
|
||||
callback({
|
||||
success: true
|
||||
});
|
||||
}
|
||||
|
||||
function getCardName(device) {
|
||||
if (!device) {
|
||||
return ""
|
||||
return "";
|
||||
}
|
||||
return `bluez_card.${device.address.replace(/:/g, "_")}`
|
||||
return `bluez_card.${device.address.replace(/:/g, "_")}`;
|
||||
}
|
||||
|
||||
function getDevicePath(device) {
|
||||
if (!device || !device.address) {
|
||||
return ""
|
||||
return "";
|
||||
}
|
||||
const adapterPath = adapter ? "/org/bluez/hci0" : "/org/bluez/hci0"
|
||||
return `${adapterPath}/dev_${device.address.replace(/:/g, "_")}`
|
||||
const adapterPath = adapter ? "/org/bluez/hci0" : "/org/bluez/hci0";
|
||||
return `${adapterPath}/dev_${device.address.replace(/:/g, "_")}`;
|
||||
}
|
||||
|
||||
function isAudioDevice(device) {
|
||||
if (!device) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
const icon = getDeviceIcon(device)
|
||||
return icon === "headset" || icon === "speaker"
|
||||
const icon = getDeviceIcon(device);
|
||||
return icon === "headset" || icon === "speaker";
|
||||
}
|
||||
|
||||
function getCodecInfo(codecName) {
|
||||
const codec = codecName.replace(/-/g, "_").toUpperCase()
|
||||
const codec = codecName.replace(/-/g, "_").toUpperCase();
|
||||
|
||||
const codecMap = {
|
||||
"LDAC": {
|
||||
@@ -261,77 +271,77 @@ Singleton {
|
||||
"description": "Basic speech codec • Legacy compatibility",
|
||||
"qualityColor": "#9E9E9E"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return codecMap[codec] || {
|
||||
"name": codecName,
|
||||
"description": "Unknown codec",
|
||||
"qualityColor": "#9E9E9E"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
property var deviceCodecs: ({})
|
||||
|
||||
function updateDeviceCodec(deviceAddress, codec) {
|
||||
deviceCodecs[deviceAddress] = codec
|
||||
deviceCodecsChanged()
|
||||
deviceCodecs[deviceAddress] = codec;
|
||||
deviceCodecsChanged();
|
||||
}
|
||||
|
||||
function refreshDeviceCodec(device) {
|
||||
if (!device || !device.connected || !isAudioDevice(device)) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
const cardName = getCardName(device)
|
||||
codecQueryProcess.cardName = cardName
|
||||
codecQueryProcess.deviceAddress = device.address
|
||||
codecQueryProcess.availableCodecs = []
|
||||
codecQueryProcess.parsingTargetCard = false
|
||||
codecQueryProcess.detectedCodec = ""
|
||||
codecQueryProcess.running = true
|
||||
const cardName = getCardName(device);
|
||||
codecQueryProcess.cardName = cardName;
|
||||
codecQueryProcess.deviceAddress = device.address;
|
||||
codecQueryProcess.availableCodecs = [];
|
||||
codecQueryProcess.parsingTargetCard = false;
|
||||
codecQueryProcess.detectedCodec = "";
|
||||
codecQueryProcess.running = true;
|
||||
}
|
||||
|
||||
function getCurrentCodec(device, callback) {
|
||||
if (!device || !device.connected || !isAudioDevice(device)) {
|
||||
callback("")
|
||||
return
|
||||
callback("");
|
||||
return;
|
||||
}
|
||||
|
||||
const cardName = getCardName(device)
|
||||
codecQueryProcess.cardName = cardName
|
||||
codecQueryProcess.callback = callback
|
||||
codecQueryProcess.availableCodecs = []
|
||||
codecQueryProcess.parsingTargetCard = false
|
||||
codecQueryProcess.detectedCodec = ""
|
||||
codecQueryProcess.running = true
|
||||
const cardName = getCardName(device);
|
||||
codecQueryProcess.cardName = cardName;
|
||||
codecQueryProcess.callback = callback;
|
||||
codecQueryProcess.availableCodecs = [];
|
||||
codecQueryProcess.parsingTargetCard = false;
|
||||
codecQueryProcess.detectedCodec = "";
|
||||
codecQueryProcess.running = true;
|
||||
}
|
||||
|
||||
function getAvailableCodecs(device, callback) {
|
||||
if (!device || !device.connected || !isAudioDevice(device)) {
|
||||
callback([], "")
|
||||
return
|
||||
callback([], "");
|
||||
return;
|
||||
}
|
||||
|
||||
const cardName = getCardName(device)
|
||||
codecFullQueryProcess.cardName = cardName
|
||||
codecFullQueryProcess.callback = callback
|
||||
codecFullQueryProcess.availableCodecs = []
|
||||
codecFullQueryProcess.parsingTargetCard = false
|
||||
codecFullQueryProcess.detectedCodec = ""
|
||||
codecFullQueryProcess.running = true
|
||||
const cardName = getCardName(device);
|
||||
codecFullQueryProcess.cardName = cardName;
|
||||
codecFullQueryProcess.callback = callback;
|
||||
codecFullQueryProcess.availableCodecs = [];
|
||||
codecFullQueryProcess.parsingTargetCard = false;
|
||||
codecFullQueryProcess.detectedCodec = "";
|
||||
codecFullQueryProcess.running = true;
|
||||
}
|
||||
|
||||
function switchCodec(device, profileName, callback) {
|
||||
if (!device || !isAudioDevice(device)) {
|
||||
callback(false, "Invalid device")
|
||||
return
|
||||
callback(false, "Invalid device");
|
||||
return;
|
||||
}
|
||||
|
||||
const cardName = getCardName(device)
|
||||
codecSwitchProcess.cardName = cardName
|
||||
codecSwitchProcess.profile = profileName
|
||||
codecSwitchProcess.callback = callback
|
||||
codecSwitchProcess.running = true
|
||||
const cardName = getCardName(device);
|
||||
codecSwitchProcess.cardName = cardName;
|
||||
codecSwitchProcess.profile = profileName;
|
||||
codecSwitchProcess.callback = callback;
|
||||
codecSwitchProcess.running = true;
|
||||
}
|
||||
|
||||
Process {
|
||||
@@ -349,67 +359,67 @@ Singleton {
|
||||
onExited: (exitCode, exitStatus) => {
|
||||
if (exitCode === 0 && detectedCodec) {
|
||||
if (deviceAddress) {
|
||||
root.updateDeviceCodec(deviceAddress, detectedCodec)
|
||||
root.updateDeviceCodec(deviceAddress, detectedCodec);
|
||||
}
|
||||
if (callback) {
|
||||
callback(detectedCodec)
|
||||
callback(detectedCodec);
|
||||
}
|
||||
} else if (callback) {
|
||||
callback("")
|
||||
callback("");
|
||||
}
|
||||
|
||||
parsingTargetCard = false
|
||||
detectedCodec = ""
|
||||
availableCodecs = []
|
||||
deviceAddress = ""
|
||||
callback = null
|
||||
parsingTargetCard = false;
|
||||
detectedCodec = "";
|
||||
availableCodecs = [];
|
||||
deviceAddress = "";
|
||||
callback = null;
|
||||
}
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: data => {
|
||||
let line = data.trim()
|
||||
let line = data.trim();
|
||||
|
||||
if (line.includes(`Name: ${codecQueryProcess.cardName}`)) {
|
||||
codecQueryProcess.parsingTargetCard = true
|
||||
return
|
||||
codecQueryProcess.parsingTargetCard = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (codecQueryProcess.parsingTargetCard && line.startsWith("Name: ") && !line.includes(codecQueryProcess.cardName)) {
|
||||
codecQueryProcess.parsingTargetCard = false
|
||||
return
|
||||
codecQueryProcess.parsingTargetCard = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (codecQueryProcess.parsingTargetCard) {
|
||||
if (line.startsWith("Active Profile:")) {
|
||||
let profile = line.split(": ")[1] || ""
|
||||
let profile = line.split(": ")[1] || "";
|
||||
let activeCodec = codecQueryProcess.availableCodecs.find(c => {
|
||||
return c.profile === profile
|
||||
})
|
||||
return c.profile === profile;
|
||||
});
|
||||
if (activeCodec) {
|
||||
codecQueryProcess.detectedCodec = activeCodec.name
|
||||
codecQueryProcess.detectedCodec = activeCodec.name;
|
||||
}
|
||||
return
|
||||
return;
|
||||
}
|
||||
if (line.includes("codec") && line.includes("available: yes")) {
|
||||
let parts = line.split(": ")
|
||||
let parts = line.split(": ");
|
||||
if (parts.length >= 2) {
|
||||
let profile = parts[0].trim()
|
||||
let description = parts[1]
|
||||
let codecMatch = description.match(/codec ([^\)\s]+)/i)
|
||||
let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN"
|
||||
let codecInfo = root.getCodecInfo(codecName)
|
||||
let profile = parts[0].trim();
|
||||
let description = parts[1];
|
||||
let codecMatch = description.match(/codec ([^\)\s]+)/i);
|
||||
let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN";
|
||||
let codecInfo = root.getCodecInfo(codecName);
|
||||
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({
|
||||
"name": codecInfo.name,
|
||||
"profile": profile,
|
||||
"description": codecInfo.description,
|
||||
"qualityColor": codecInfo.qualityColor
|
||||
})
|
||||
codecQueryProcess.availableCodecs = newCodecs
|
||||
});
|
||||
codecQueryProcess.availableCodecs = newCodecs;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -431,59 +441,59 @@ Singleton {
|
||||
|
||||
onExited: function (exitCode, exitStatus) {
|
||||
if (callback) {
|
||||
callback(exitCode === 0 ? availableCodecs : [], exitCode === 0 ? detectedCodec : "")
|
||||
callback(exitCode === 0 ? availableCodecs : [], exitCode === 0 ? detectedCodec : "");
|
||||
}
|
||||
parsingTargetCard = false
|
||||
detectedCodec = ""
|
||||
availableCodecs = []
|
||||
callback = null
|
||||
parsingTargetCard = false;
|
||||
detectedCodec = "";
|
||||
availableCodecs = [];
|
||||
callback = null;
|
||||
}
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: data => {
|
||||
let line = data.trim()
|
||||
let line = data.trim();
|
||||
|
||||
if (line.includes(`Name: ${codecFullQueryProcess.cardName}`)) {
|
||||
codecFullQueryProcess.parsingTargetCard = true
|
||||
return
|
||||
codecFullQueryProcess.parsingTargetCard = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (codecFullQueryProcess.parsingTargetCard && line.startsWith("Name: ") && !line.includes(codecFullQueryProcess.cardName)) {
|
||||
codecFullQueryProcess.parsingTargetCard = false
|
||||
return
|
||||
codecFullQueryProcess.parsingTargetCard = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (codecFullQueryProcess.parsingTargetCard) {
|
||||
if (line.startsWith("Active Profile:")) {
|
||||
let profile = line.split(": ")[1] || ""
|
||||
let profile = line.split(": ")[1] || "";
|
||||
let activeCodec = codecFullQueryProcess.availableCodecs.find(c => {
|
||||
return c.profile === profile
|
||||
})
|
||||
return c.profile === profile;
|
||||
});
|
||||
if (activeCodec) {
|
||||
codecFullQueryProcess.detectedCodec = activeCodec.name
|
||||
codecFullQueryProcess.detectedCodec = activeCodec.name;
|
||||
}
|
||||
return
|
||||
return;
|
||||
}
|
||||
if (line.includes("codec") && line.includes("available: yes")) {
|
||||
let parts = line.split(": ")
|
||||
let parts = line.split(": ");
|
||||
if (parts.length >= 2) {
|
||||
let profile = parts[0].trim()
|
||||
let description = parts[1]
|
||||
let codecMatch = description.match(/codec ([^\)\s]+)/i)
|
||||
let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN"
|
||||
let codecInfo = root.getCodecInfo(codecName)
|
||||
let profile = parts[0].trim();
|
||||
let description = parts[1];
|
||||
let codecMatch = description.match(/codec ([^\)\s]+)/i);
|
||||
let codecName = codecMatch ? codecMatch[1].toUpperCase() : "UNKNOWN";
|
||||
let codecInfo = root.getCodecInfo(codecName);
|
||||
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({
|
||||
"name": codecInfo.name,
|
||||
"profile": profile,
|
||||
"description": codecInfo.description,
|
||||
"qualityColor": codecInfo.qualityColor
|
||||
})
|
||||
codecFullQueryProcess.availableCodecs = newCodecs
|
||||
});
|
||||
codecFullQueryProcess.availableCodecs = newCodecs;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -503,7 +513,7 @@ Singleton {
|
||||
|
||||
onExited: function (exitCode, exitStatus) {
|
||||
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
|
||||
@@ -511,13 +521,13 @@ Singleton {
|
||||
if (root.adapter && root.adapter.devices) {
|
||||
root.adapter.devices.values.forEach(device => {
|
||||
if (device && root.getCardName(device) === cardName) {
|
||||
Qt.callLater(() => root.refreshDeviceCodec(device))
|
||||
Qt.callLater(() => root.refreshDeviceCodec(device));
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
callback = null
|
||||
callback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,11 @@ import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Wayland // ! Import is needed despite what qmlls says
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("BlurService")
|
||||
|
||||
property bool quickshellSupported: false
|
||||
property bool compositorSupported: false
|
||||
@@ -52,7 +54,7 @@ Singleton {
|
||||
targetWindow.BackgroundEffect.blurRegion = region;
|
||||
return region;
|
||||
} catch (e) {
|
||||
console.warn("BlurService: Failed to create blur region:", e);
|
||||
log.warn("Failed to create blur region:", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -84,15 +86,15 @@ Singleton {
|
||||
onStreamFinished: {
|
||||
root.compositorSupported = text.trim() === "supported";
|
||||
if (root.compositorSupported)
|
||||
console.info("BlurService: Compositor supports ext-background-effect-v1");
|
||||
log.info("Compositor supports ext-background-effect-v1");
|
||||
else
|
||||
console.info("BlurService: Compositor does not support ext-background-effect-v1");
|
||||
log.info("Compositor does not support ext-background-effect-v1");
|
||||
}
|
||||
}
|
||||
|
||||
onExited: exitCode => {
|
||||
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");
|
||||
test.destroy();
|
||||
quickshellSupported = true;
|
||||
console.info("BlurService: Quickshell blur support available");
|
||||
log.info("Quickshell blur support available");
|
||||
blurProbe.running = true;
|
||||
} 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,68 +19,69 @@ Singleton {
|
||||
|
||||
function checkKhalAvailability() {
|
||||
if (!khalCheckProcess.running)
|
||||
khalCheckProcess.running = true
|
||||
khalCheckProcess.running = true;
|
||||
}
|
||||
|
||||
function detectKhalDateFormat() {
|
||||
if (!khalFormatProcess.running)
|
||||
khalFormatProcess.running = true
|
||||
khalFormatProcess.running = true;
|
||||
}
|
||||
|
||||
function parseKhalDateFormat(formatExample) {
|
||||
let qtFormat = formatExample.replace("12", "MM").replace("21", "dd").replace("2013", "yyyy")
|
||||
return { format: qtFormat, parser: null }
|
||||
let qtFormat = formatExample.replace("12", "MM").replace("21", "dd").replace("2013", "yyyy");
|
||||
return {
|
||||
format: qtFormat,
|
||||
parser: null
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function loadCurrentMonth() {
|
||||
if (!root.khalAvailable)
|
||||
return
|
||||
|
||||
let today = new Date()
|
||||
let firstDay = new Date(today.getFullYear(), today.getMonth(), 1)
|
||||
let lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0)
|
||||
return;
|
||||
let today = new Date();
|
||||
let firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
let lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);
|
||||
// Add padding
|
||||
let startDate = new Date(firstDay)
|
||||
startDate.setDate(startDate.getDate() - firstDay.getDay() - 7)
|
||||
let endDate = new Date(lastDay)
|
||||
endDate.setDate(endDate.getDate() + (6 - lastDay.getDay()) + 7)
|
||||
loadEvents(startDate, endDate)
|
||||
let startDate = new Date(firstDay);
|
||||
startDate.setDate(startDate.getDate() - firstDay.getDay() - 7);
|
||||
let endDate = new Date(lastDay);
|
||||
endDate.setDate(endDate.getDate() + (6 - lastDay.getDay()) + 7);
|
||||
loadEvents(startDate, endDate);
|
||||
}
|
||||
|
||||
function loadEvents(startDate, endDate) {
|
||||
if (!root.khalAvailable) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
if (eventsProcess.running) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
// Store last requested date range for refresh timer
|
||||
root.lastStartDate = startDate
|
||||
root.lastEndDate = endDate
|
||||
root.isLoading = true
|
||||
root.lastStartDate = startDate;
|
||||
root.lastEndDate = endDate;
|
||||
root.isLoading = true;
|
||||
// Format dates for khal using detected format
|
||||
let startDateStr = Qt.formatDate(startDate, root.khalDateFormat)
|
||||
let endDateStr = Qt.formatDate(endDate, root.khalDateFormat)
|
||||
eventsProcess.requestStartDate = startDate
|
||||
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.running = true
|
||||
let startDateStr = Qt.formatDate(startDate, root.khalDateFormat);
|
||||
let endDateStr = Qt.formatDate(endDate, root.khalDateFormat);
|
||||
eventsProcess.requestStartDate = startDate;
|
||||
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.running = true;
|
||||
}
|
||||
|
||||
function getEventsForDate(date) {
|
||||
let dateKey = Qt.formatDate(date, "yyyy-MM-dd")
|
||||
return root.eventsByDate[dateKey] || []
|
||||
let dateKey = Qt.formatDate(date, "yyyy-MM-dd");
|
||||
return root.eventsByDate[dateKey] || [];
|
||||
}
|
||||
|
||||
function hasEventsForDate(date) {
|
||||
let events = getEventsForDate(date)
|
||||
return events.length > 0
|
||||
let events = getEventsForDate(date);
|
||||
return events.length > 0;
|
||||
}
|
||||
|
||||
// Initialize on component completion
|
||||
Component.onCompleted: {
|
||||
detectKhalDateFormat()
|
||||
detectKhalDateFormat();
|
||||
}
|
||||
|
||||
// Process for detecting khal date format
|
||||
@@ -91,22 +92,22 @@ Singleton {
|
||||
running: false
|
||||
onExited: exitCode => {
|
||||
if (exitCode !== 0) {
|
||||
checkKhalAvailability()
|
||||
checkKhalAvailability();
|
||||
}
|
||||
}
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
let lines = text.split('\n')
|
||||
let lines = text.split('\n');
|
||||
for (let line of lines) {
|
||||
if (line.startsWith('dateformat:')) {
|
||||
let formatExample = line.substring(line.indexOf(':') + 1).trim()
|
||||
let formatInfo = parseKhalDateFormat(formatExample)
|
||||
root.khalDateFormat = formatInfo.format
|
||||
break
|
||||
let formatExample = line.substring(line.indexOf(':') + 1).trim();
|
||||
let formatInfo = parseKhalDateFormat(formatExample);
|
||||
root.khalDateFormat = formatInfo.format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
checkKhalAvailability()
|
||||
checkKhalAvailability();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -118,9 +119,9 @@ Singleton {
|
||||
command: ["khal", "list", "today"]
|
||||
running: false
|
||||
onExited: exitCode => {
|
||||
root.khalAvailable = (exitCode === 0)
|
||||
root.khalAvailable = (exitCode === 0);
|
||||
if (exitCode === 0) {
|
||||
loadCurrentMonth()
|
||||
loadCurrentMonth();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -135,100 +136,96 @@ Singleton {
|
||||
|
||||
running: false
|
||||
onExited: exitCode => {
|
||||
root.isLoading = false
|
||||
root.isLoading = false;
|
||||
if (exitCode !== 0) {
|
||||
root.lastError = "Failed to load events (exit code: " + exitCode + ")"
|
||||
return
|
||||
root.lastError = "Failed to load events (exit code: " + exitCode + ")";
|
||||
return;
|
||||
}
|
||||
try {
|
||||
let newEventsByDate = {}
|
||||
let lines = eventsProcess.rawOutput.split('\n')
|
||||
let newEventsByDate = {};
|
||||
let lines = eventsProcess.rawOutput.split('\n');
|
||||
for (let line of lines) {
|
||||
line = line.trim()
|
||||
line = line.trim();
|
||||
if (!line || line === "[]")
|
||||
continue
|
||||
continue;
|
||||
|
||||
// Parse JSON line
|
||||
let dayEvents = JSON.parse(line)
|
||||
let dayEvents = JSON.parse(line);
|
||||
// Process each event in this day's array
|
||||
for (let event of dayEvents) {
|
||||
if (!event.title)
|
||||
continue
|
||||
continue;
|
||||
|
||||
// Parse start and end dates using detected format
|
||||
let startDate, endDate
|
||||
let startDate, endDate;
|
||||
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 {
|
||||
startDate = new Date()
|
||||
startDate = new 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 {
|
||||
endDate = new Date(startDate)
|
||||
endDate = new Date(startDate);
|
||||
}
|
||||
// Create start/end times
|
||||
let startTime = new Date(startDate)
|
||||
let endTime = new Date(endDate)
|
||||
if (event['start-time']
|
||||
&& event['all-day'] !== "True") {
|
||||
let startTime = new Date(startDate);
|
||||
let endTime = new Date(endDate);
|
||||
if (event['start-time'] && event['all-day'] !== "True") {
|
||||
// Parse time if available and not all-day
|
||||
let timeStr = event['start-time']
|
||||
let timeStr = event['start-time'];
|
||||
if (timeStr) {
|
||||
// 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) {
|
||||
let hours = parseInt(timeParts[1])
|
||||
let minutes = parseInt(timeParts[2])
|
||||
let hours = parseInt(timeParts[1]);
|
||||
let minutes = parseInt(timeParts[2]);
|
||||
|
||||
// Handle AM/PM conversion if present
|
||||
if (timeParts[3]) {
|
||||
let period = timeParts[3].toUpperCase()
|
||||
let period = timeParts[3].toUpperCase();
|
||||
if (period === 'PM' && hours !== 12) {
|
||||
hours += 12
|
||||
hours += 12;
|
||||
} else if (period === 'AM' && hours === 12) {
|
||||
hours = 0
|
||||
hours = 0;
|
||||
}
|
||||
}
|
||||
|
||||
startTime.setHours(hours, minutes)
|
||||
startTime.setHours(hours, minutes);
|
||||
if (event['end-time']) {
|
||||
let endTimeParts = event['end-time'].match(
|
||||
/(\d+):(\d+)(?::\d+)?\s*(AM|PM)?/i)
|
||||
let endTimeParts = event['end-time'].match(/(\d+):(\d+)(?::\d+)?\s*(AM|PM)?/i);
|
||||
if (endTimeParts) {
|
||||
let endHours = parseInt(endTimeParts[1])
|
||||
let endMinutes = parseInt(endTimeParts[2])
|
||||
let endHours = parseInt(endTimeParts[1]);
|
||||
let endMinutes = parseInt(endTimeParts[2]);
|
||||
|
||||
// Handle AM/PM conversion if present
|
||||
if (endTimeParts[3]) {
|
||||
let endPeriod = endTimeParts[3].toUpperCase()
|
||||
let endPeriod = endTimeParts[3].toUpperCase();
|
||||
if (endPeriod === 'PM' && endHours !== 12) {
|
||||
endHours += 12
|
||||
endHours += 12;
|
||||
} else if (endPeriod === 'AM' && endHours === 12) {
|
||||
endHours = 0
|
||||
endHours = 0;
|
||||
}
|
||||
}
|
||||
|
||||
endTime.setHours(endHours, endMinutes)
|
||||
endTime.setHours(endHours, endMinutes);
|
||||
}
|
||||
} else {
|
||||
// Default to 1 hour duration on same day
|
||||
endTime = new Date(startTime)
|
||||
endTime.setHours(
|
||||
startTime.getHours() + 1)
|
||||
endTime = new Date(startTime);
|
||||
endTime.setHours(startTime.getHours() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Create unique ID for this event (to track multi-day events)
|
||||
let eventId = event.title + "_" + event['start-date']
|
||||
+ "_" + (event['start-time'] || 'allday')
|
||||
let eventId = event.title + "_" + event['start-date'] + "_" + (event['start-time'] || 'allday');
|
||||
// Create event object template
|
||||
let extractedUrl = ""
|
||||
let extractedUrl = "";
|
||||
if (!event.url && event.description) {
|
||||
let urlMatch = event.description.match(/https?:\/\/[^\s]+/)
|
||||
let urlMatch = event.description.match(/https?:\/\/[^\s]+/);
|
||||
if (urlMatch) {
|
||||
extractedUrl = urlMatch[0]
|
||||
extractedUrl = urlMatch[0];
|
||||
}
|
||||
}
|
||||
let eventTemplate = {
|
||||
@@ -242,75 +239,71 @@ Singleton {
|
||||
"calendar": "",
|
||||
"color": "",
|
||||
"allDay": event['all-day'] === "True",
|
||||
"isMultiDay": startDate.toDateString(
|
||||
) !== endDate.toDateString()
|
||||
}
|
||||
"isMultiDay": startDate.toDateString() !== endDate.toDateString()
|
||||
};
|
||||
// Add event to each day it spans
|
||||
let currentDate = new Date(startDate)
|
||||
let currentDate = new Date(startDate);
|
||||
while (currentDate <= endDate) {
|
||||
let dateKey = Qt.formatDate(currentDate,
|
||||
"yyyy-MM-dd")
|
||||
let dateKey = Qt.formatDate(currentDate, "yyyy-MM-dd");
|
||||
if (!newEventsByDate[dateKey])
|
||||
newEventsByDate[dateKey] = []
|
||||
newEventsByDate[dateKey] = [];
|
||||
|
||||
// Check if this exact event is already added to this date (prevent duplicates)
|
||||
let existingEvent = newEventsByDate[dateKey].find(
|
||||
e => {
|
||||
return e.id === eventId
|
||||
})
|
||||
let existingEvent = newEventsByDate[dateKey].find(e => {
|
||||
return e.id === eventId;
|
||||
});
|
||||
if (existingEvent) {
|
||||
// Move to next day without adding duplicate
|
||||
currentDate.setDate(currentDate.getDate() + 1)
|
||||
continue
|
||||
currentDate.setDate(currentDate.getDate() + 1);
|
||||
continue;
|
||||
}
|
||||
// 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
|
||||
if (currentDate.getTime() === startDate.getTime()) {
|
||||
// First day - use original start time
|
||||
dayEvent.start = new Date(startTime)
|
||||
dayEvent.start = new Date(startTime);
|
||||
} else {
|
||||
// Subsequent days - start at beginning of day for all-day events
|
||||
dayEvent.start = new Date(currentDate)
|
||||
dayEvent.start = new Date(currentDate);
|
||||
if (!dayEvent.allDay)
|
||||
dayEvent.start.setHours(0, 0, 0, 0)
|
||||
dayEvent.start.setHours(0, 0, 0, 0);
|
||||
}
|
||||
if (currentDate.getTime() === endDate.getTime()) {
|
||||
// Last day - use original end time
|
||||
dayEvent.end = new Date(endTime)
|
||||
dayEvent.end = new Date(endTime);
|
||||
} else {
|
||||
// Earlier days - end at end of day for all-day events
|
||||
dayEvent.end = new Date(currentDate)
|
||||
dayEvent.end = new Date(currentDate);
|
||||
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
|
||||
currentDate.setDate(currentDate.getDate() + 1)
|
||||
currentDate.setDate(currentDate.getDate() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort events by start time within each date
|
||||
for (let dateKey in newEventsByDate) {
|
||||
newEventsByDate[dateKey].sort((a, b) => {
|
||||
return a.start.getTime(
|
||||
) - b.start.getTime()
|
||||
})
|
||||
return a.start.getTime() - b.start.getTime();
|
||||
});
|
||||
}
|
||||
root.eventsByDate = newEventsByDate
|
||||
root.lastError = ""
|
||||
root.eventsByDate = newEventsByDate;
|
||||
root.lastError = "";
|
||||
} catch (error) {
|
||||
root.lastError = "Failed to parse events JSON: " + error.toString()
|
||||
root.eventsByDate = {}
|
||||
root.lastError = "Failed to parse events JSON: " + error.toString();
|
||||
root.eventsByDate = {};
|
||||
}
|
||||
// Reset for next run
|
||||
eventsProcess.rawOutput = ""
|
||||
eventsProcess.rawOutput = "";
|
||||
}
|
||||
|
||||
stdout: SplitParser {
|
||||
splitMarker: "\n"
|
||||
onRead: data => {
|
||||
eventsProcess.rawOutput += data + "\n"
|
||||
eventsProcess.rawOutput += data + "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("ChangelogService")
|
||||
|
||||
readonly property string currentVersion: "1.4"
|
||||
readonly property bool changelogEnabled: false
|
||||
@@ -101,7 +103,7 @@ Singleton {
|
||||
|
||||
onExited: exitCode => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("ChangelogService: Failed to create changelog marker");
|
||||
log.warn("Failed to create changelog marker");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("ClipboardService")
|
||||
|
||||
readonly property int longTextThreshold: 200
|
||||
|
||||
@@ -78,7 +80,7 @@ Singleton {
|
||||
}
|
||||
DMSService.sendRequest("clipboard.getHistory", null, function (response) {
|
||||
if (response.error) {
|
||||
console.warn("ClipboardService: Failed to get history:", response.error);
|
||||
log.warn("Failed to get history:", response.error);
|
||||
return;
|
||||
}
|
||||
internalEntries = response.result || [];
|
||||
@@ -144,7 +146,7 @@ Singleton {
|
||||
"id": entry.id
|
||||
}, function (response) {
|
||||
if (response.error) {
|
||||
console.warn("ClipboardService: Failed to delete entry:", response.error);
|
||||
log.warn("Failed to delete entry:", response.error);
|
||||
return;
|
||||
}
|
||||
internalEntries = internalEntries.filter(e => e.id !== entry.id);
|
||||
@@ -169,7 +171,7 @@ Singleton {
|
||||
"id": entry.id
|
||||
}, function (response) {
|
||||
if (response.error) {
|
||||
console.warn("ClipboardService: Failed to delete entry:", response.error);
|
||||
log.warn("Failed to delete entry:", response.error);
|
||||
return;
|
||||
}
|
||||
internalEntries = internalEntries.filter(e => e.id !== entry.id);
|
||||
@@ -223,7 +225,7 @@ Singleton {
|
||||
const savedCount = pinnedCount;
|
||||
DMSService.sendRequest("clipboard.clearHistory", null, function (response) {
|
||||
if (response.error) {
|
||||
console.warn("ClipboardService: Failed to clear history:", response.error);
|
||||
log.warn("Failed to clear history:", response.error);
|
||||
return;
|
||||
}
|
||||
refresh();
|
||||
|
||||
@@ -7,9 +7,11 @@ import Quickshell.I3
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("CompositorService")
|
||||
|
||||
property bool isHyprland: false
|
||||
property bool isNiri: false
|
||||
@@ -52,7 +54,7 @@ Singleton {
|
||||
randrScales = scales;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("CompositorService: failed to parse randr data:", e);
|
||||
log.warn("failed to parse randr data:", e);
|
||||
}
|
||||
}
|
||||
randrReady = true;
|
||||
@@ -379,9 +381,7 @@ Singleton {
|
||||
const focusedWin = NiriService.windows.find(nw => nw.is_focused);
|
||||
if (!focusedWin)
|
||||
return [];
|
||||
const screenWsIds = new Set(
|
||||
NiriService.allWorkspaces.filter(ws => ws.output === screenName).map(ws => ws.id)
|
||||
);
|
||||
const screenWsIds = new Set(NiriService.allWorkspaces.filter(ws => ws.output === screenName).map(ws => ws.id));
|
||||
return screenWsIds.has(focusedWin.workspace_id) ? toplevels : [];
|
||||
}
|
||||
return NiriService.filterCurrentDisplay(toplevels, screenName);
|
||||
@@ -454,7 +454,7 @@ Singleton {
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("CompositorService: workspace snapshot failed:", e);
|
||||
log.warn("workspace snapshot failed:", e);
|
||||
}
|
||||
|
||||
if (currentWorkspaceId === null)
|
||||
@@ -498,7 +498,7 @@ Singleton {
|
||||
isMiracle = false;
|
||||
isLabwc = false;
|
||||
compositor = "hyprland";
|
||||
console.info("CompositorService: Detected Hyprland");
|
||||
log.info("Detected Hyprland");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -513,7 +513,7 @@ Singleton {
|
||||
isMiracle = false;
|
||||
isLabwc = false;
|
||||
compositor = "niri";
|
||||
console.info("CompositorService: Detected Niri with socket:", niriSocket);
|
||||
log.info("Detected Niri with socket:", niriSocket);
|
||||
NiriService.generateNiriBlurrule();
|
||||
}
|
||||
}, 0);
|
||||
@@ -531,7 +531,7 @@ Singleton {
|
||||
isMiracle = false;
|
||||
isLabwc = false;
|
||||
compositor = "sway";
|
||||
console.info("CompositorService: Detected Sway with socket:", swaySocket);
|
||||
log.info("Detected Sway with socket:", swaySocket);
|
||||
}
|
||||
}, 0);
|
||||
return;
|
||||
@@ -548,7 +548,7 @@ Singleton {
|
||||
isMiracle = true;
|
||||
isLabwc = false;
|
||||
compositor = "miracle";
|
||||
console.info("CompositorService: Detected Miracle WM with socket:", miracleSocket);
|
||||
log.info("Detected Miracle WM with socket:", miracleSocket);
|
||||
}
|
||||
}, 0);
|
||||
return;
|
||||
@@ -565,7 +565,7 @@ Singleton {
|
||||
isMiracle = false;
|
||||
isLabwc = false;
|
||||
compositor = "scroll";
|
||||
console.info("CompositorService: Detected Scroll with socket:", scrollSocket);
|
||||
log.info("Detected Scroll with socket:", scrollSocket);
|
||||
}
|
||||
}, 0);
|
||||
return;
|
||||
@@ -580,7 +580,7 @@ Singleton {
|
||||
isMiracle = false;
|
||||
isLabwc = true;
|
||||
compositor = "labwc";
|
||||
console.info("CompositorService: Detected LabWC with PID:", labwcPid);
|
||||
log.info("Detected LabWC with PID:", labwcPid);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -595,7 +595,7 @@ Singleton {
|
||||
isMiracle = false;
|
||||
isLabwc = false;
|
||||
compositor = "unknown";
|
||||
console.warn("CompositorService: No compositor detected");
|
||||
log.warn("No compositor detected");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,7 +618,7 @@ Singleton {
|
||||
isMiracle = false;
|
||||
isLabwc = false;
|
||||
compositor = "dwl";
|
||||
console.info("CompositorService: Detected DWL via DMS capability");
|
||||
log.info("Detected DWL via DMS capability");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -638,7 +638,7 @@ Singleton {
|
||||
if (isLabwc) {
|
||||
Quickshell.execDetached(["dms", "dpms", "off"]);
|
||||
}
|
||||
console.warn("CompositorService: Cannot power off monitors, unknown compositor");
|
||||
log.warn("Cannot power off monitors, unknown compositor");
|
||||
}
|
||||
|
||||
function powerOnMonitors() {
|
||||
@@ -657,12 +657,12 @@ Singleton {
|
||||
if (isLabwc) {
|
||||
Quickshell.execDetached(["dms", "dpms", "on"]);
|
||||
}
|
||||
console.warn("CompositorService: Cannot power on monitors, unknown compositor");
|
||||
log.warn("Cannot power on monitors, unknown compositor");
|
||||
}
|
||||
|
||||
function _dwlPowerOffMonitors() {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -676,7 +676,7 @@ Singleton {
|
||||
|
||||
function _dwlPowerOnMonitors() {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,11 @@ pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("CupsService")
|
||||
|
||||
property int refCount: 0
|
||||
|
||||
@@ -205,7 +207,7 @@ Singleton {
|
||||
enabled: DMSService.isConnected
|
||||
|
||||
function onCupsStateUpdate(data) {
|
||||
console.log("CupsService: Subscription update received");
|
||||
log.debug("Subscription update received");
|
||||
getState();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,11 @@ pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DMSNetworkService")
|
||||
|
||||
property bool networkAvailable: false
|
||||
property string backend: ""
|
||||
@@ -141,7 +143,7 @@ Singleton {
|
||||
|
||||
function onNetworkStateUpdate(data) {
|
||||
const networksCount = data.wifiNetworks?.length ?? "null";
|
||||
console.log("DMSNetworkService: Subscription update received, networks:", networksCount);
|
||||
log.debug("Subscription update received, networks:", networksCount);
|
||||
updateState(data);
|
||||
}
|
||||
}
|
||||
@@ -301,7 +303,7 @@ Singleton {
|
||||
const timeout = 30000;
|
||||
|
||||
if (busyDuration > timeout) {
|
||||
console.warn("DMSNetworkService: VPN operation timed out after", timeout, "ms");
|
||||
log.warn("VPN operation timed out after", timeout, "ms");
|
||||
vpnIsBusy = false;
|
||||
pendingVpnUuid = "";
|
||||
vpnBusyStartTime = 0;
|
||||
@@ -331,7 +333,7 @@ Singleton {
|
||||
if (pendingConnectionSSID) {
|
||||
if (wifiConnected && currentWifiSSID === pendingConnectionSSID && wifiIP) {
|
||||
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}`);
|
||||
|
||||
if (userPreference === "wifi" || userPreference === "auto") {
|
||||
@@ -402,7 +404,7 @@ Singleton {
|
||||
DMSService.sendRequest("network.wifi.scan", params, response => {
|
||||
isScanning = false;
|
||||
if (response.error) {
|
||||
console.warn("DMSNetworkService: WiFi scan failed:", response.error);
|
||||
log.warn("WiFi scan failed:", response.error);
|
||||
} else {
|
||||
Qt.callLater(() => getState());
|
||||
}
|
||||
@@ -485,10 +487,10 @@ Singleton {
|
||||
}
|
||||
|
||||
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) {
|
||||
console.warn("submitCredentials: Aborting - networkAvailable=" + networkAvailable + " apiVersion=" + DMSService.apiVersion);
|
||||
log.warn("submitCredentials: Aborting - networkAvailable=" + networkAvailable + " apiVersion=" + DMSService.apiVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -502,7 +504,7 @@ Singleton {
|
||||
|
||||
DMSService.sendRequest("network.credentials.submit", params, response => {
|
||||
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 => {
|
||||
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
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.warn("Failed to forget network:", response.error);
|
||||
log.warn("Failed to forget network:", response.error);
|
||||
} else {
|
||||
ToastService.showInfo(I18n.tr("Forgot network %1").arg(ssid));
|
||||
|
||||
@@ -565,7 +567,7 @@ Singleton {
|
||||
wifiToggling = false;
|
||||
|
||||
if (response.error) {
|
||||
console.warn("Failed to toggle WiFi:", response.error);
|
||||
log.warn("Failed to toggle WiFi:", response.error);
|
||||
} else if (response.result) {
|
||||
wifiEnabled = response.result.enabled;
|
||||
ToastService.showInfo(wifiEnabled ? I18n.tr("WiFi enabled") : I18n.tr("WiFi disabled"));
|
||||
@@ -600,7 +602,7 @@ Singleton {
|
||||
targetPreference = "";
|
||||
|
||||
if (response.error) {
|
||||
console.warn("Failed to set network preference:", response.error);
|
||||
log.warn("Failed to set network preference:", response.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DMSService")
|
||||
|
||||
property bool dmsAvailable: false
|
||||
property var capabilities: []
|
||||
@@ -198,14 +200,14 @@ Singleton {
|
||||
try {
|
||||
response = JSON.parse(line);
|
||||
} 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;
|
||||
}
|
||||
const isClipboard = clipboardRequestIds[response.id];
|
||||
if (isClipboard)
|
||||
delete clipboardRequestIds[response.id];
|
||||
else
|
||||
console.log("DMSService: Request socket <<", line);
|
||||
log.debug("Request socket <<", line);
|
||||
handleResponse(response);
|
||||
}
|
||||
}
|
||||
@@ -232,11 +234,11 @@ Singleton {
|
||||
try {
|
||||
response = JSON.parse(line);
|
||||
} 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;
|
||||
}
|
||||
if (!line.includes("clipboard"))
|
||||
console.log("DMSService: Subscribe socket <<", line);
|
||||
log.debug("Subscribe socket <<", line);
|
||||
handleSubscriptionEvent(response);
|
||||
}
|
||||
}
|
||||
@@ -251,9 +253,9 @@ Singleton {
|
||||
request.params = {
|
||||
"services": activeSubscriptions
|
||||
};
|
||||
console.log("DMSService: Subscribing to services:", JSON.stringify(activeSubscriptions));
|
||||
log.debug("Subscribing to services:", JSON.stringify(activeSubscriptions));
|
||||
} else {
|
||||
console.log("DMSService: Subscribing to all services");
|
||||
log.debug("Subscribing to all services");
|
||||
}
|
||||
|
||||
subscribeSocket.send(request);
|
||||
@@ -291,7 +293,7 @@ Singleton {
|
||||
} else {
|
||||
const filtered = activeSubscriptions.filter(s => s !== service);
|
||||
if (filtered.length === 0) {
|
||||
console.warn("DMSService: Cannot remove last subscription");
|
||||
log.warn("Cannot remove last subscription");
|
||||
return;
|
||||
}
|
||||
subscribe(filtered);
|
||||
@@ -316,7 +318,7 @@ Singleton {
|
||||
if (response.error) {
|
||||
if (response.error.includes("unknown method") && response.error.includes("subscribe")) {
|
||||
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);
|
||||
shownOutdatedError = true;
|
||||
}
|
||||
@@ -336,7 +338,7 @@ Singleton {
|
||||
cliVersion = data.cliVersion || "";
|
||||
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) {
|
||||
ToastService.showError("DMS server is outdated (API v" + apiVersion + ", expected v" + expectedApiVersion + ")");
|
||||
@@ -401,7 +403,7 @@ Singleton {
|
||||
|
||||
function sendRequest(method, params, callback) {
|
||||
if (!isConnected) {
|
||||
console.warn("DMSService.sendRequest: Not connected, method:", method);
|
||||
log.warn("DMSService.sendRequest: Not connected, method:", method);
|
||||
if (callback) {
|
||||
callback({
|
||||
"error": "not connected to DMS socket"
|
||||
@@ -427,7 +429,7 @@ Singleton {
|
||||
if (method.startsWith("clipboard")) {
|
||||
clipboardRequestIds[id] = true;
|
||||
} else {
|
||||
console.log("DMSService.sendRequest: Sending request id=" + id + " method=" + method);
|
||||
log.debug("DMSService.sendRequest: Sending request id=" + id + " method=" + method);
|
||||
}
|
||||
requestSocket.send(request);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
@@ -5,9 +5,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DgopService")
|
||||
|
||||
property int refCount: 0
|
||||
property int updateInterval: refCount > 0 ? 3000 : 30000
|
||||
@@ -643,7 +645,7 @@ Singleton {
|
||||
onStarted: dgopProcessPid = processId ?? 0
|
||||
onExited: exitCode => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("Dgop process failed with exit code:", exitCode);
|
||||
log.warn("Dgop process failed with exit code:", exitCode);
|
||||
isUpdating = false;
|
||||
}
|
||||
}
|
||||
@@ -654,8 +656,8 @@ Singleton {
|
||||
const data = JSON.parse(text.trim());
|
||||
parseData(data);
|
||||
} catch (e) {
|
||||
console.warn("Failed to parse dgop JSON:", e);
|
||||
console.warn("Raw text was:", text.substring(0, 200));
|
||||
log.warn("Failed to parse dgop JSON:", e);
|
||||
log.warn("Raw text was:", text.substring(0, 200));
|
||||
isUpdating = false;
|
||||
}
|
||||
}
|
||||
@@ -669,7 +671,7 @@ Singleton {
|
||||
running: false
|
||||
onExited: exitCode => {
|
||||
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 {
|
||||
@@ -679,7 +681,7 @@ Singleton {
|
||||
const data = JSON.parse(text.trim());
|
||||
parseData(data);
|
||||
} 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
|
||||
onExited: exitCode => {
|
||||
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 {
|
||||
@@ -702,7 +704,7 @@ Singleton {
|
||||
const data = JSON.parse(text.trim());
|
||||
parseData(data);
|
||||
} 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 {
|
||||
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
|
||||
onExited: exitCode => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("Failed to read /etc/os-release");
|
||||
log.warn("Failed to read /etc/os-release");
|
||||
}
|
||||
}
|
||||
stdout: StdioCollector {
|
||||
@@ -761,9 +763,9 @@ Singleton {
|
||||
// Prefer PRETTY_NAME, fallback to NAME
|
||||
const distroName = prettyName || name || "Linux";
|
||||
distribution = distroName;
|
||||
console.info("Detected distribution:", distroName);
|
||||
log.info("Detected distribution:", distroName);
|
||||
} catch (e) {
|
||||
console.warn("Failed to parse /etc/os-release:", e);
|
||||
log.warn("Failed to parse /etc/os-release:", e);
|
||||
distribution = "Linux";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DisplayService")
|
||||
|
||||
property bool brightnessAvailable: devices.length > 0
|
||||
property var devices: []
|
||||
@@ -247,7 +249,7 @@ Singleton {
|
||||
function setBrightness(percentage, device, suppressOsd) {
|
||||
const actualDevice = device === "" ? getDefaultDevice() : (device || currentDevice || getDefaultDevice());
|
||||
if (!actualDevice) {
|
||||
console.warn("DisplayService: No device selected for brightness change");
|
||||
log.warn("No device selected for brightness change");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -273,14 +275,14 @@ Singleton {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
const clampedValue = Math.max(minValue, Math.min(maxValue, percentage));
|
||||
|
||||
if (!DMSService.isConnected) {
|
||||
console.warn("DisplayService: Not connected to DMS");
|
||||
log.warn("Not connected to DMS");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -319,7 +321,7 @@ Singleton {
|
||||
|
||||
DMSService.sendRequest("brightness.setBrightness", params, response => {
|
||||
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");
|
||||
} else {
|
||||
ToastService.dismissCategory("brightness");
|
||||
@@ -453,7 +455,7 @@ Singleton {
|
||||
"enabled": true
|
||||
}, response => {
|
||||
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");
|
||||
nightModeEnabled = false;
|
||||
SessionData.setNightModeEnabled(false);
|
||||
@@ -481,7 +483,7 @@ Singleton {
|
||||
"enabled": false
|
||||
}, response => {
|
||||
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");
|
||||
} else {
|
||||
ToastService.dismissCategory("night-mode");
|
||||
@@ -505,7 +507,7 @@ Singleton {
|
||||
"sunset": null
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.error("DisplayService: Failed to clear manual times:", response.error);
|
||||
log.error("Failed to clear manual times:", response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -513,7 +515,7 @@ Singleton {
|
||||
"use": false
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.error("DisplayService: Failed to disable IP location:", response.error);
|
||||
log.error("Failed to disable IP location:", response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -522,7 +524,7 @@ Singleton {
|
||||
"high": temperature
|
||||
}, response => {
|
||||
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");
|
||||
} else {
|
||||
ToastService.dismissCategory("night-mode");
|
||||
@@ -564,7 +566,7 @@ Singleton {
|
||||
"use": false
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.error("DisplayService: Failed to disable IP location:", response.error);
|
||||
log.error("Failed to disable IP location:", response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -573,7 +575,7 @@ Singleton {
|
||||
"high": highTemp
|
||||
}, response => {
|
||||
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");
|
||||
return;
|
||||
}
|
||||
@@ -583,7 +585,7 @@ Singleton {
|
||||
"sunset": sunset
|
||||
}, response => {
|
||||
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");
|
||||
} else {
|
||||
ToastService.dismissCategory("night-mode");
|
||||
@@ -602,7 +604,7 @@ Singleton {
|
||||
"sunset": null
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.error("DisplayService: Failed to clear manual times:", response.error);
|
||||
log.error("Failed to clear manual times:", response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -611,7 +613,7 @@ Singleton {
|
||||
"high": highTemp
|
||||
}, response => {
|
||||
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");
|
||||
return;
|
||||
}
|
||||
@@ -621,7 +623,7 @@ Singleton {
|
||||
"use": true
|
||||
}, response => {
|
||||
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");
|
||||
} else {
|
||||
ToastService.dismissCategory("night-mode");
|
||||
@@ -632,7 +634,7 @@ Singleton {
|
||||
"use": false
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.error("DisplayService: Failed to disable IP location:", response.error);
|
||||
log.error("Failed to disable IP location:", response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -641,7 +643,7 @@ Singleton {
|
||||
"longitude": SessionData.longitude
|
||||
}, response => {
|
||||
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");
|
||||
} else {
|
||||
ToastService.dismissCategory("night-mode");
|
||||
@@ -649,7 +651,7 @@ Singleton {
|
||||
});
|
||||
});
|
||||
} 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) {
|
||||
gammaControlAvailable = false;
|
||||
automationAvailable = false;
|
||||
console.error("DisplayService: Gamma control not available:", response.error);
|
||||
log.error("Gamma control not available:", response.error);
|
||||
} else {
|
||||
gammaControlAvailable = true;
|
||||
automationAvailable = true;
|
||||
@@ -713,7 +715,7 @@ Singleton {
|
||||
"enabled": true
|
||||
}, enableResponse => {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -772,7 +774,7 @@ Singleton {
|
||||
|
||||
DMSService.sendRequest("brightness.rescan", null, response => {
|
||||
if (response.error) {
|
||||
console.error("DisplayService: Failed to rescan brightness devices:", response.error);
|
||||
log.error("Failed to rescan brightness devices:", response.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,9 +6,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DwlService")
|
||||
|
||||
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation))
|
||||
readonly property string mangoDmsDir: configDir + "/mango/dms"
|
||||
@@ -91,7 +93,7 @@ Singleton {
|
||||
const hasDwl = DMSService.capabilities.includes("dwl");
|
||||
if (hasDwl && !dwlAvailable) {
|
||||
dwlAvailable = true;
|
||||
console.info("DwlService: DWL capability detected");
|
||||
log.info("DWL capability detected");
|
||||
requestState();
|
||||
refreshOutputScales();
|
||||
} else if (!hasDwl) {
|
||||
@@ -130,7 +132,7 @@ Singleton {
|
||||
"toggleTagset": toggleTagset
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.warn("DwlService: setTags error:", response.error);
|
||||
log.warn("setTags error:", response.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -146,7 +148,7 @@ Singleton {
|
||||
"xorTags": xorTags
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.warn("DwlService: setClientTags error:", response.error);
|
||||
log.warn("setClientTags error:", response.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -161,7 +163,7 @@ Singleton {
|
||||
"index": index
|
||||
}, response => {
|
||||
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) {
|
||||
const output = getOutputState(outputName);
|
||||
if (!output || !output.tags) {
|
||||
console.log("toggleTag: no output or tags for", outputName);
|
||||
log.debug("toggleTag: no output or tags for", outputName);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -219,13 +221,13 @@ Singleton {
|
||||
const clickedMask = 1 << tagIndex;
|
||||
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) {
|
||||
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);
|
||||
} else {
|
||||
console.log("toggleTag: setting combined mask", newMask);
|
||||
log.debug("toggleTag: setting combined mask", newMask);
|
||||
setTags(outputName, newMask, 0);
|
||||
}
|
||||
}
|
||||
@@ -256,14 +258,14 @@ Singleton {
|
||||
}
|
||||
outputScales = newScales;
|
||||
} catch (e) {
|
||||
console.warn("DwlService: Failed to parse mmsg output:", e);
|
||||
log.warn("Failed to parse mmsg output:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: exitCode => {
|
||||
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) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("DwlService: Failed to write outputs config:", output);
|
||||
log.warn("Failed to write outputs config:", output);
|
||||
return;
|
||||
}
|
||||
console.info("DwlService: Generated outputs config at", outputsPath);
|
||||
log.info("Generated outputs config at", outputsPath);
|
||||
if (CompositorService.isDwl)
|
||||
reloadConfig();
|
||||
});
|
||||
@@ -345,7 +347,7 @@ Singleton {
|
||||
function reloadConfig() {
|
||||
Proc.runCommand("mango-reload", ["mmsg", "-d", "reload_config"], (output, exitCode) => {
|
||||
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) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("DwlService: Failed to write layout config:", output);
|
||||
log.warn("Failed to write layout config:", output);
|
||||
return;
|
||||
}
|
||||
console.info("DwlService: Generated layout config at", layoutPath);
|
||||
log.info("Generated layout config at", layoutPath);
|
||||
reloadConfig();
|
||||
});
|
||||
}
|
||||
@@ -407,13 +409,13 @@ borderpx=${borderSize}
|
||||
if (!CompositorService.isDwl)
|
||||
return;
|
||||
|
||||
console.log("DwlService: Generating cursor config...");
|
||||
log.debug("Generating cursor config...");
|
||||
|
||||
const settings = typeof SettingsData !== "undefined" ? SettingsData.cursorSettings : null;
|
||||
if (!settings) {
|
||||
Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => {
|
||||
if (exitCode !== 0)
|
||||
console.warn("DwlService: Failed to write cursor config:", output);
|
||||
log.warn("Failed to write cursor config:", output);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -426,7 +428,7 @@ borderpx=${borderSize}
|
||||
if (isDefaultConfig) {
|
||||
Proc.runCommand("mango-write-cursor", ["sh", "-c", `mkdir -p "${mangoDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => {
|
||||
if (exitCode !== 0)
|
||||
console.warn("DwlService: Failed to write cursor config:", output);
|
||||
log.warn("Failed to write cursor config:", output);
|
||||
});
|
||||
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) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("DwlService: Failed to write cursor config:", output);
|
||||
log.warn("Failed to write cursor config:", output);
|
||||
return;
|
||||
}
|
||||
console.info("DwlService: Generated cursor config at", cursorPath);
|
||||
log.info("Generated cursor config at", cursorPath);
|
||||
reloadConfig();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("ExtWorkspaceService")
|
||||
|
||||
property bool extWorkspaceAvailable: false
|
||||
property var groups: []
|
||||
@@ -49,13 +51,13 @@ Singleton {
|
||||
if (typeof CompositorService !== "undefined") {
|
||||
const useExtWorkspace = DMSService.forceExtWorkspace || (!CompositorService.isNiri && !CompositorService.isHyprland && !CompositorService.isDwl && !CompositorService.isSway && !CompositorService.isScroll && !CompositorService.isMiracle);
|
||||
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;
|
||||
return;
|
||||
}
|
||||
}
|
||||
extWorkspaceAvailable = true;
|
||||
console.info("ExtWorkspaceService: ext-workspace capability detected");
|
||||
log.info("ext-workspace capability detected");
|
||||
DMSService.addSubscription("extworkspace");
|
||||
requestState();
|
||||
} else if (!hasExtWorkspace) {
|
||||
@@ -78,9 +80,9 @@ Singleton {
|
||||
function handleStateUpdate(state) {
|
||||
groups = state.groups || [];
|
||||
if (groups.length === 0) {
|
||||
console.warn("ExtWorkspaceService: Received empty workspace groups from backend");
|
||||
log.warn("Received empty workspace groups from backend");
|
||||
} else {
|
||||
console.log("ExtWorkspaceService: Updated with", groups.length, "workspace groups");
|
||||
log.debug("Updated with", groups.length, "workspace groups");
|
||||
}
|
||||
stateChanged();
|
||||
}
|
||||
@@ -95,7 +97,7 @@ Singleton {
|
||||
"groupID": groupID
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.warn("ExtWorkspaceService: activateWorkspace error:", response.error);
|
||||
log.warn("activateWorkspace error:", response.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -110,7 +112,7 @@ Singleton {
|
||||
"groupID": groupID
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.warn("ExtWorkspaceService: deactivateWorkspace error:", response.error);
|
||||
log.warn("deactivateWorkspace error:", response.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -125,7 +127,7 @@ Singleton {
|
||||
"groupID": groupID
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.warn("ExtWorkspaceService: removeWorkspace error:", response.error);
|
||||
log.warn("removeWorkspace error:", response.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -140,7 +142,7 @@ Singleton {
|
||||
"name": name
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.warn("ExtWorkspaceService: createWorkspace error:", response.error);
|
||||
log.warn("createWorkspace error:", response.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -272,6 +274,6 @@ Singleton {
|
||||
return;
|
||||
}
|
||||
}
|
||||
console.warn("ExtWorkspaceService: workspace not found:", workspaceName);
|
||||
log.warn("workspace not found:", workspaceName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("FirstLaunchService")
|
||||
|
||||
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation)) + "/DankMaterialShell"
|
||||
readonly property string settingsPath: configDir + "/settings.json"
|
||||
@@ -77,10 +79,10 @@ Singleton {
|
||||
|
||||
if (result === "first") {
|
||||
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") {
|
||||
root.isFirstLaunch = false;
|
||||
console.info("FirstLaunchService: Existing user detected, silently creating marker");
|
||||
log.info("Existing user detected, silently creating marker");
|
||||
touchMarkerProcess.running = true;
|
||||
} else {
|
||||
root.isFirstLaunch = false;
|
||||
@@ -102,9 +104,9 @@ Singleton {
|
||||
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0) {
|
||||
console.info("FirstLaunchService: First launch marker created");
|
||||
log.info("First launch marker created");
|
||||
} else {
|
||||
console.warn("FirstLaunchService: Failed to create first launch marker");
|
||||
log.warn("Failed to create first launch marker");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("HyprlandService")
|
||||
|
||||
readonly property string configDir: Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation))
|
||||
readonly property string hyprDmsDir: configDir + "/hypr/dms"
|
||||
@@ -29,7 +31,7 @@ Singleton {
|
||||
function ensureWindowrulesConfig() {
|
||||
Proc.runCommand("hypr-ensure-windowrules", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && [ ! -f "${windowrulesPath}" ] && touch "${windowrulesPath}" || true`], (output, exitCode) => {
|
||||
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) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("HyprlandService: Failed to write outputs config:", output);
|
||||
log.warn("Failed to write outputs config:", output);
|
||||
return;
|
||||
}
|
||||
console.info("HyprlandService: Generated outputs config at", outputsPath);
|
||||
log.info("Generated outputs config at", outputsPath);
|
||||
if (CompositorService.isHyprland)
|
||||
reloadConfig();
|
||||
});
|
||||
@@ -171,7 +173,7 @@ Singleton {
|
||||
function reloadConfig() {
|
||||
Proc.runCommand("hyprctl-reload", ["hyprctl", "reload"], (output, exitCode) => {
|
||||
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) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("HyprlandService: Failed to write layout config:", output);
|
||||
log.warn("Failed to write layout config:", output);
|
||||
return;
|
||||
}
|
||||
console.info("HyprlandService: Generated layout config at", layoutPath);
|
||||
log.info("Generated layout config at", layoutPath);
|
||||
reloadConfig();
|
||||
});
|
||||
}
|
||||
@@ -264,7 +266,7 @@ decoration {
|
||||
if (!settings) {
|
||||
Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => {
|
||||
if (exitCode !== 0)
|
||||
console.warn("HyprlandService: Failed to write cursor config:", output);
|
||||
log.warn("Failed to write cursor config:", output);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -282,7 +284,7 @@ decoration {
|
||||
if (!hasTheme && !hasNonDefaultSize && !hasCursorSettings) {
|
||||
Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && : > "${cursorPath}"`], (output, exitCode) => {
|
||||
if (exitCode !== 0)
|
||||
console.warn("HyprlandService: Failed to write cursor config:", output);
|
||||
log.warn("Failed to write cursor config:", output);
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -313,7 +315,7 @@ decoration {
|
||||
|
||||
Proc.runCommand("hypr-write-cursor", ["sh", "-c", `mkdir -p "${hyprDmsDir}" && cat > "${cursorPath}" << 'EOF'\n${content}EOF`], (output, exitCode) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("HyprlandService: Failed to write cursor config:", output);
|
||||
log.warn("Failed to write cursor config:", output);
|
||||
return;
|
||||
}
|
||||
if (hasTheme)
|
||||
@@ -331,7 +333,7 @@ decoration {
|
||||
const fullName = wsId + " " + newName;
|
||||
Proc.runCommand("hyprland-rename-ws", ["hyprctl", "dispatch", "renameworkspace", String(wsId), fullName], (output, exitCode) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("HyprlandService: Failed to rename workspace:", output);
|
||||
log.warn("Failed to rename workspace:", output);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("IdleService")
|
||||
|
||||
readonly property bool idleMonitorAvailable: {
|
||||
try {
|
||||
@@ -82,7 +84,7 @@ Singleton {
|
||||
|
||||
function createIdleMonitors() {
|
||||
if (!idleMonitorAvailable) {
|
||||
console.info("IdleService: IdleMonitor not available, skipping creation");
|
||||
log.info("IdleMonitor not available, skipping creation");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -157,7 +159,7 @@ Singleton {
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn("IdleService: Error creating IdleMonitors:", e);
|
||||
log.warn("Error creating IdleMonitors:", e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,11 +183,11 @@ Singleton {
|
||||
onExternalInhibitActiveChanged: {
|
||||
if (externalInhibitActive) {
|
||||
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.inhibitReason = "External app: " + (apps || "unknown");
|
||||
} else {
|
||||
console.info("IdleService: External idle inhibit released");
|
||||
log.info("External idle inhibit released");
|
||||
SessionService.idleInhibited = false;
|
||||
SessionService.inhibitReason = "Keep system awake";
|
||||
}
|
||||
@@ -193,9 +195,9 @@ Singleton {
|
||||
|
||||
Component.onCompleted: {
|
||||
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 {
|
||||
console.info("IdleService: Initialized with idle monitoring support");
|
||||
log.info("Initialized with idle monitoring support");
|
||||
createIdleMonitors();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,14 +8,16 @@ import Quickshell.Io
|
||||
import Quickshell.Wayland
|
||||
// ! Even though qmlls says this is unused, it is wrong
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import "../Common/KeybindActions.js" as Actions
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("KeybindsService")
|
||||
|
||||
Component.onCompleted: {
|
||||
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 {
|
||||
root.cheatsheet = JSON.parse(text);
|
||||
} catch (e) {
|
||||
console.error("[KeybindsService] Failed to parse cheatsheet:", e);
|
||||
log.error("Failed to parse cheatsheet:", e);
|
||||
root.cheatsheet = {};
|
||||
}
|
||||
root.cheatsheetLoading = false;
|
||||
@@ -161,7 +163,7 @@ Singleton {
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0)
|
||||
return;
|
||||
console.warn("[KeybindsService] Cheatsheet load failed with code:", exitCode);
|
||||
log.warn("Cheatsheet load failed with code:", exitCode);
|
||||
root.cheatsheetLoading = false;
|
||||
}
|
||||
}
|
||||
@@ -176,7 +178,7 @@ Singleton {
|
||||
root._rawData = JSON.parse(text);
|
||||
root._processData();
|
||||
} catch (e) {
|
||||
console.error("[KeybindsService] Failed to parse binds:", e);
|
||||
log.error("Failed to parse binds:", e);
|
||||
}
|
||||
root.loading = false;
|
||||
}
|
||||
@@ -184,7 +186,7 @@ Singleton {
|
||||
|
||||
onExited: exitCode => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("[KeybindsService] Load process failed with code:", exitCode);
|
||||
log.warn("Load process failed with code:", exitCode);
|
||||
root.loading = false;
|
||||
}
|
||||
}
|
||||
@@ -206,7 +208,7 @@ Singleton {
|
||||
onExited: exitCode => {
|
||||
root.saving = false;
|
||||
if (exitCode !== 0) {
|
||||
console.error("[KeybindsService] Save failed with code:", exitCode);
|
||||
log.error("Save failed with code:", exitCode);
|
||||
root.bindSaveCompleted(false);
|
||||
return;
|
||||
}
|
||||
@@ -231,7 +233,7 @@ Singleton {
|
||||
|
||||
onExited: exitCode => {
|
||||
if (exitCode !== 0) {
|
||||
console.error("[KeybindsService] Remove failed with code:", exitCode);
|
||||
log.error("Remove failed with code:", exitCode);
|
||||
return;
|
||||
}
|
||||
root.lastError = "";
|
||||
@@ -255,7 +257,7 @@ Singleton {
|
||||
onExited: exitCode => {
|
||||
root.fixing = false;
|
||||
if (exitCode !== 0) {
|
||||
console.error("[KeybindsService] Fix failed with code:", exitCode);
|
||||
log.error("Fix failed with code:", exitCode);
|
||||
return;
|
||||
}
|
||||
root.lastError = "";
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,6 @@ pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
226
quickshell/Services/Log.qml
Normal file
226
quickshell/Services/Log.qml
Normal 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
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("MultimediaService")
|
||||
|
||||
property bool available: false
|
||||
|
||||
@@ -14,6 +15,7 @@ Singleton {
|
||||
const testObj = Qt.createQmlObject(`
|
||||
import QtQuick
|
||||
import QtMultimedia
|
||||
import qs.Services
|
||||
Item {}
|
||||
`, root, "MultimediaService.TestComponent");
|
||||
if (testObj) {
|
||||
@@ -29,7 +31,7 @@ Singleton {
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!detectAvailability()) {
|
||||
console.warn("MultimediaService: QtMultimedia not available");
|
||||
log.warn("QtMultimedia not available");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("MuxService")
|
||||
|
||||
property var sessions: []
|
||||
property bool loading: false
|
||||
@@ -34,32 +36,36 @@ Singleton {
|
||||
})
|
||||
|
||||
function getTerminalFlag(terminal) {
|
||||
return terminalFlags[terminal] ?? ["-e"]
|
||||
return terminalFlags[terminal] ?? ["-e"];
|
||||
}
|
||||
|
||||
readonly property string terminal: SessionData.resolveTerminal() || "ghostty"
|
||||
|
||||
function _terminalPrefix() {
|
||||
return [terminal].concat(getTerminalFlag(terminal))
|
||||
return [terminal].concat(getTerminalFlag(terminal));
|
||||
}
|
||||
|
||||
Process {
|
||||
id: tmuxCheckProcess
|
||||
command: ["which", "tmux"]
|
||||
running: false
|
||||
onExited: (code) => { root.tmuxAvailable = (code === 0) }
|
||||
onExited: code => {
|
||||
root.tmuxAvailable = (code === 0);
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: zellijCheckProcess
|
||||
command: ["which", "zellij"]
|
||||
running: false
|
||||
onExited: (code) => { root.zellijAvailable = (code === 0) }
|
||||
onExited: code => {
|
||||
root.zellijAvailable = (code === 0);
|
||||
}
|
||||
}
|
||||
|
||||
function checkAvailability() {
|
||||
tmuxCheckProcess.running = true
|
||||
zellijCheckProcess.running = true
|
||||
tmuxCheckProcess.running = true;
|
||||
zellijCheckProcess.running = true;
|
||||
}
|
||||
|
||||
Component.onCompleted: checkAvailability()
|
||||
@@ -72,141 +78,139 @@ Singleton {
|
||||
onStreamFinished: {
|
||||
try {
|
||||
if (root.muxType === "zellij")
|
||||
root._parseZellijSessions(text)
|
||||
root._parseZellijSessions(text);
|
||||
else
|
||||
root._parseTmuxSessions(text)
|
||||
root._parseTmuxSessions(text);
|
||||
} catch (e) {
|
||||
console.error("[MuxService] Error parsing sessions:", e)
|
||||
root.sessions = []
|
||||
log.error("Error parsing sessions:", e);
|
||||
root.sessions = [];
|
||||
}
|
||||
root.loading = false
|
||||
root.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
stderr: SplitParser {
|
||||
onRead: (line) => {
|
||||
onRead: line => {
|
||||
if (line.trim())
|
||||
console.error("[MuxService] stderr:", line)
|
||||
log.error("stderr:", line);
|
||||
}
|
||||
}
|
||||
|
||||
onExited: (code) => {
|
||||
onExited: code => {
|
||||
if (code !== 0 && code !== 1) {
|
||||
console.warn("[MuxService] Process exited with code:", code)
|
||||
root.sessions = []
|
||||
log.warn("Process exited with code:", code);
|
||||
root.sessions = [];
|
||||
}
|
||||
root.loading = false
|
||||
root.loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
function refreshSessions() {
|
||||
if (!root.currentMuxAvailable) {
|
||||
root.sessions = []
|
||||
return
|
||||
root.sessions = [];
|
||||
return;
|
||||
}
|
||||
|
||||
root.loading = true
|
||||
root.loading = true;
|
||||
|
||||
if (listProcess.running)
|
||||
listProcess.running = false
|
||||
listProcess.running = false;
|
||||
|
||||
if (root.muxType === "zellij")
|
||||
listProcess.command = ["zellij", "list-sessions", "--no-formatting"]
|
||||
listProcess.command = ["zellij", "list-sessions", "--no-formatting"];
|
||||
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 () {
|
||||
listProcess.running = true
|
||||
})
|
||||
listProcess.running = true;
|
||||
});
|
||||
}
|
||||
|
||||
function _isSessionExcluded(name) {
|
||||
var filter = SettingsData.muxSessionFilter.trim()
|
||||
var filter = SettingsData.muxSessionFilter.trim();
|
||||
if (filter.length === 0)
|
||||
return false
|
||||
var parts = filter.split(",")
|
||||
return false;
|
||||
var parts = filter.split(",");
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
var pattern = parts[i].trim()
|
||||
var pattern = parts[i].trim();
|
||||
if (pattern.length === 0)
|
||||
continue
|
||||
continue;
|
||||
if (pattern.startsWith("/") && pattern.endsWith("/") && pattern.length > 2) {
|
||||
try {
|
||||
var re = new RegExp(pattern.slice(1, -1))
|
||||
var re = new RegExp(pattern.slice(1, -1));
|
||||
if (re.test(name))
|
||||
return true
|
||||
return true;
|
||||
} catch (e) {}
|
||||
} else {
|
||||
if (name.toLowerCase() === pattern.toLowerCase())
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
function _parseTmuxSessions(output) {
|
||||
var sessionList = []
|
||||
var lines = output.trim().split('\n')
|
||||
var sessionList = [];
|
||||
var lines = output.trim().split('\n');
|
||||
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i].trim()
|
||||
var line = lines[i].trim();
|
||||
if (line.length === 0)
|
||||
continue
|
||||
|
||||
var parts = line.split('|')
|
||||
continue;
|
||||
var parts = line.split('|');
|
||||
if (parts.length >= 3 && !_isSessionExcluded(parts[0])) {
|
||||
sessionList.push({
|
||||
name: parts[0],
|
||||
windows: parts[1],
|
||||
attached: parts[2] === "1"
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
root.sessions = sessionList
|
||||
root.sessions = sessionList;
|
||||
}
|
||||
|
||||
function _parseZellijSessions(output) {
|
||||
var sessionList = []
|
||||
var lines = output.trim().split('\n')
|
||||
var sessionList = [];
|
||||
var lines = output.trim().split('\n');
|
||||
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var line = lines[i].trim()
|
||||
var line = lines[i].trim();
|
||||
if (line.length === 0)
|
||||
continue
|
||||
|
||||
var exited = line.includes("(EXITED")
|
||||
var bracketIdx = line.indexOf(" [")
|
||||
var name = (bracketIdx > 0 ? line.substring(0, bracketIdx) : line).trim()
|
||||
continue;
|
||||
var exited = line.includes("(EXITED");
|
||||
var bracketIdx = line.indexOf(" [");
|
||||
var name = (bracketIdx > 0 ? line.substring(0, bracketIdx) : line).trim();
|
||||
|
||||
if (!_isSessionExcluded(name)) {
|
||||
sessionList.push({
|
||||
name: name,
|
||||
windows: "N/A",
|
||||
attached: !exited
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
root.sessions = sessionList
|
||||
root.sessions = sessionList;
|
||||
}
|
||||
|
||||
function attachToSession(name) {
|
||||
if (SettingsData.muxUseCustomCommand && SettingsData.muxCustomCommand) {
|
||||
Quickshell.execDetached([Paths.expandTilde(SettingsData.muxCustomCommand), name])
|
||||
Quickshell.execDetached([Paths.expandTilde(SettingsData.muxCustomCommand), name]);
|
||||
} else if (root.muxType === "zellij") {
|
||||
Quickshell.execDetached(_terminalPrefix().concat(["zellij", "attach", name]))
|
||||
Quickshell.execDetached(_terminalPrefix().concat(["zellij", "attach", name]));
|
||||
} else {
|
||||
Quickshell.execDetached(_terminalPrefix().concat(["tmux", "attach", "-t", name]))
|
||||
Quickshell.execDetached(_terminalPrefix().concat(["tmux", "attach", "-t", name]));
|
||||
}
|
||||
}
|
||||
|
||||
function createSession(name) {
|
||||
if (SettingsData.muxUseCustomCommand && SettingsData.muxCustomCommand) {
|
||||
Quickshell.execDetached([Paths.expandTilde(SettingsData.muxCustomCommand), name])
|
||||
Quickshell.execDetached([Paths.expandTilde(SettingsData.muxCustomCommand), name]);
|
||||
} else if (root.muxType === "zellij") {
|
||||
Quickshell.execDetached(_terminalPrefix().concat(["zellij", "-s", name]))
|
||||
Quickshell.execDetached(_terminalPrefix().concat(["zellij", "-s", name]));
|
||||
} 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) {
|
||||
if (root.muxType === "zellij")
|
||||
return
|
||||
Quickshell.execDetached(["tmux", "rename-session", "-t", oldName, newName])
|
||||
Qt.callLater(refreshSessions)
|
||||
return;
|
||||
Quickshell.execDetached(["tmux", "rename-session", "-t", oldName, newName]);
|
||||
Qt.callLater(refreshSessions);
|
||||
}
|
||||
|
||||
function killSession(name) {
|
||||
if (root.muxType === "zellij") {
|
||||
Quickshell.execDetached(["zellij", "kill-session", name])
|
||||
Quickshell.execDetached(["zellij", "kill-session", name]);
|
||||
} else {
|
||||
Quickshell.execDetached(["tmux", "kill-session", "-t", name])
|
||||
Quickshell.execDetached(["tmux", "kill-session", "-t", name]);
|
||||
}
|
||||
Qt.callLater(refreshSessions)
|
||||
Qt.callLater(refreshSessions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("NetworkService")
|
||||
|
||||
property bool networkAvailable: activeService !== null
|
||||
property string backend: activeService?.backend ?? ""
|
||||
@@ -97,12 +99,12 @@ Singleton {
|
||||
readonly property string socketPath: Quickshell.env("DMS_SOCKET")
|
||||
|
||||
Component.onCompleted: {
|
||||
console.info("NetworkService: Initializing...");
|
||||
log.info("Initializing...");
|
||||
if (!socketPath || socketPath.length === 0) {
|
||||
console.info("NetworkService: DMS_SOCKET not set, using LegacyNetworkService");
|
||||
log.info("DMS_SOCKET not set, using LegacyNetworkService");
|
||||
useLegacyService();
|
||||
} 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() {
|
||||
if (!activeService && DMSNetworkService.networkAvailable) {
|
||||
console.info("NetworkService: Network capability detected, using DMSNetworkService");
|
||||
log.info("Network capability detected, using DMSNetworkService");
|
||||
activeService = DMSNetworkService;
|
||||
usingLegacy = false;
|
||||
console.info("NetworkService: Switched to DMSNetworkService, networkAvailable:", networkAvailable);
|
||||
log.info("Switched to DMSNetworkService, networkAvailable:", networkAvailable);
|
||||
connectSignals();
|
||||
} 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();
|
||||
}
|
||||
}
|
||||
@@ -126,7 +128,7 @@ Singleton {
|
||||
function useLegacyService() {
|
||||
activeService = LegacyNetworkService;
|
||||
usingLegacy = true;
|
||||
console.info("NetworkService: Switched to LegacyNetworkService, networkAvailable:", networkAvailable);
|
||||
log.info("Switched to LegacyNetworkService, networkAvailable:", networkAvailable);
|
||||
if (LegacyNetworkService.activate) {
|
||||
LegacyNetworkService.activate();
|
||||
}
|
||||
|
||||
@@ -6,9 +6,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("NiriService")
|
||||
|
||||
readonly property string socketPath: Quickshell.env("NIRI_SOCKET")
|
||||
|
||||
@@ -118,10 +120,10 @@ Singleton {
|
||||
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0) {
|
||||
console.info("NiriService: Generated layout config at", configPath);
|
||||
log.info("Generated layout config at", configPath);
|
||||
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 => {
|
||||
if (exitCode === 0) {
|
||||
console.info("NiriService: Generated alttab config at", alttabPath);
|
||||
log.info("Generated alttab config at", alttabPath);
|
||||
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 => {
|
||||
if (exitCode === 0) {
|
||||
console.info("NiriService: Generated wpblur config at", blurrulePath);
|
||||
log.info("Generated wpblur config at", blurrulePath);
|
||||
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 => {
|
||||
if (exitCode === 0) {
|
||||
console.info("NiriService: Generated cursor config at", cursorPath);
|
||||
log.info("Generated cursor config at", cursorPath);
|
||||
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);
|
||||
handleNiriEvent(event);
|
||||
} 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;
|
||||
Proc.runCommand("niri-fetch-outputs", ["niri", "msg", "-j", "outputs"], (output, exitCode) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("NiriService: Failed to fetch outputs, exit code:", exitCode);
|
||||
log.warn("Failed to fetch outputs, exit code:", exitCode);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const outputsData = JSON.parse(output);
|
||||
outputs = outputsData;
|
||||
console.info("NiriService: Loaded", Object.keys(outputsData).length, "outputs");
|
||||
log.info("Loaded", Object.keys(outputsData).length, "outputs");
|
||||
updateDisplayScales();
|
||||
if (windows.length > 0) {
|
||||
windows = sortWindowsByLayout(windows);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("NiriService: Failed to parse outputs:", e);
|
||||
log.warn("Failed to parse outputs:", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1076,7 +1078,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function doGenerateNiriLayoutConfig() {
|
||||
console.log("NiriService: Generating layout config...");
|
||||
log.debug("Generating layout config...");
|
||||
|
||||
const defaultRadius = typeof SettingsData !== "undefined" ? SettingsData.cornerRadius : 12;
|
||||
const defaultGaps = typeof SettingsData !== "undefined" ? Math.max(4, (SettingsData.barConfigs[0]?.spacing ?? 4)) : 4;
|
||||
@@ -1136,7 +1138,7 @@ Singleton {
|
||||
const path = niriDmsDir + "/" + name + ".kdl";
|
||||
Proc.runCommand("niri-ensure-" + name, ["sh", "-c", `mkdir -p "${niriDmsDir}" && [ ! -f "${path}" ] && touch "${path}" || true`], (output, exitCode) => {
|
||||
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() {
|
||||
console.log("NiriService: Generating wpblur config...");
|
||||
log.debug("Generating wpblur config...");
|
||||
|
||||
const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
|
||||
const niriDmsDir = configDir + "/niri/dms";
|
||||
@@ -1160,7 +1162,7 @@ Singleton {
|
||||
if (!CompositorService.isNiri)
|
||||
return;
|
||||
|
||||
console.log("NiriService: Generating cursor config...");
|
||||
log.debug("Generating cursor config...");
|
||||
|
||||
const configDir = Paths.strip(StandardPaths.writableLocation(StandardPaths.ConfigLocation));
|
||||
const niriDmsDir = configDir + "/niri/dms";
|
||||
@@ -1275,12 +1277,12 @@ Singleton {
|
||||
const fullCommand = commands.join(" && ");
|
||||
Proc.runCommand("niri-output-config", ["sh", "-c", fullCommand], (output, exitCode) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("NiriService: Failed to apply output config:", output);
|
||||
log.warn("Failed to apply output config:", output);
|
||||
if (callback)
|
||||
callback(false, output);
|
||||
return;
|
||||
}
|
||||
console.info("NiriService: Applied output config for", outputName);
|
||||
log.info("Applied output config for", outputName);
|
||||
fetchOutputs();
|
||||
if (callback)
|
||||
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) => {
|
||||
if (exitCode !== 0) {
|
||||
console.warn("NiriService: Failed to write outputs config:", output);
|
||||
log.warn("Failed to write outputs config:", output);
|
||||
return;
|
||||
}
|
||||
console.info("NiriService: Generated outputs config at", outputsPath);
|
||||
log.info("Generated outputs config at", outputsPath);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,11 @@ import QtCore
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("NotepadStorageService")
|
||||
|
||||
property int refCount: 0
|
||||
|
||||
@@ -39,7 +41,7 @@ Singleton {
|
||||
root.metadataLoaded = true
|
||||
root.validateTabs()
|
||||
} catch(e) {
|
||||
console.warn("Failed to parse notepad metadata:", e)
|
||||
log.warn("Failed to parse notepad metadata:", e)
|
||||
root.createDefaultTab()
|
||||
}
|
||||
}
|
||||
@@ -148,7 +150,7 @@ Singleton {
|
||||
callback: callback
|
||||
})
|
||||
} else {
|
||||
console.warn("Tab file does not exist:", fullPath)
|
||||
log.warn("Tab file does not exist:", fullPath)
|
||||
callback("")
|
||||
}
|
||||
}
|
||||
@@ -389,7 +391,7 @@ Singleton {
|
||||
}
|
||||
|
||||
onSaveFailed: {
|
||||
console.error("Failed to save tab content")
|
||||
log.error("Failed to save tab content")
|
||||
if (creationCallback) {
|
||||
creationCallback()
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@ import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Services.Notifications
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import "../Common/markdown2html.js" as Markdown2Html
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("NotificationService")
|
||||
|
||||
readonly property list<NotifWrapper> notifications: []
|
||||
readonly property list<NotifWrapper> allWrappers: []
|
||||
@@ -153,7 +155,7 @@ Singleton {
|
||||
historyAdapter.notifications = historyList;
|
||||
historyFileView.writeAdapter();
|
||||
} 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)
|
||||
saveHistory();
|
||||
} catch (e) {
|
||||
console.warn("NotificationService: load history failed:", e);
|
||||
log.warn("load history failed:", e);
|
||||
historyLoaded = true;
|
||||
}
|
||||
}
|
||||
@@ -403,7 +405,7 @@ Singleton {
|
||||
try {
|
||||
return new RegExp(pattern, "i").test(value);
|
||||
} catch (e) {
|
||||
console.warn("NotificationService: invalid notification rule regex:", pattern);
|
||||
log.warn("invalid notification rule regex:", pattern);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("PluginService")
|
||||
|
||||
property var availablePlugins: ({})
|
||||
property var loadedPlugins: ({})
|
||||
@@ -167,13 +168,13 @@ Singleton {
|
||||
const manifest = JSON.parse(raw)
|
||||
root._onManifestParsed(absPath, manifest, "${sourceTag}", ${mtimeEpochMs})
|
||||
} 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 }
|
||||
}
|
||||
fv.destroy()
|
||||
}
|
||||
onLoadFailed: (err) => {
|
||||
console.warn("PluginService: manifest load failed", absPath, err)
|
||||
log.warn("manifest load failed", absPath, err)
|
||||
fv.destroy()
|
||||
}
|
||||
}
|
||||
@@ -186,7 +187,7 @@ Singleton {
|
||||
|
||||
function _onManifestParsed(absPath, manifest, sourceTag, mtimeEpochMs) {
|
||||
if (!manifest || !manifest.id || !manifest.name || !manifest.component) {
|
||||
console.error("PluginService: invalid manifest fields:", absPath);
|
||||
log.error("invalid manifest fields:", absPath);
|
||||
knownManifests[absPath] = {
|
||||
mtime: mtimeEpochMs,
|
||||
source: sourceTag,
|
||||
@@ -269,7 +270,7 @@ Singleton {
|
||||
function loadPlugin(pluginId, bustCache) {
|
||||
const plugin = availablePlugins[pluginId];
|
||||
if (!plugin) {
|
||||
console.error("PluginService: Plugin not found:", pluginId);
|
||||
log.error("Plugin not found:", pluginId);
|
||||
pluginLoadFailed(pluginId, "Plugin not found");
|
||||
return false;
|
||||
}
|
||||
@@ -296,7 +297,7 @@ Singleton {
|
||||
url += "?t=" + Date.now();
|
||||
const comp = Qt.createComponent(url, Component.PreferSynchronous);
|
||||
if (comp.status === Component.Error) {
|
||||
console.error("PluginService: component error", pluginId, comp.errorString());
|
||||
log.error("component error", pluginId, comp.errorString());
|
||||
pluginLoadFailed(pluginId, comp.errorString());
|
||||
return false;
|
||||
}
|
||||
@@ -310,7 +311,7 @@ Singleton {
|
||||
"pluginService": root
|
||||
});
|
||||
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());
|
||||
return false;
|
||||
}
|
||||
@@ -339,7 +340,7 @@ Singleton {
|
||||
pluginLoaded(pluginId);
|
||||
return true;
|
||||
} catch (e) {
|
||||
console.error("PluginService: Error loading plugin:", pluginId, e.message);
|
||||
log.error("Error loading plugin:", pluginId, e.message);
|
||||
pluginLoadFailed(pluginId, e.message);
|
||||
return false;
|
||||
}
|
||||
@@ -348,7 +349,7 @@ Singleton {
|
||||
function unloadPlugin(pluginId) {
|
||||
const plugin = loadedPlugins[pluginId];
|
||||
if (!plugin) {
|
||||
console.warn("PluginService: Plugin not loaded:", pluginId);
|
||||
log.warn("Plugin not loaded:", pluginId);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -392,7 +393,7 @@ Singleton {
|
||||
pluginUnloaded(pluginId);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("PluginService: Error unloading plugin:", pluginId, "Error:", error.message);
|
||||
log.error("Error unloading plugin:", pluginId, "Error:", error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -705,7 +706,7 @@ Singleton {
|
||||
fv.setText(content);
|
||||
});
|
||||
} 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.exited.connect(function (exitCode) {
|
||||
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.running = true;
|
||||
return true;
|
||||
} else {
|
||||
console.error("PluginService: Failed to create mkdir process");
|
||||
log.error("Failed to create mkdir process");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("PolkitService")
|
||||
|
||||
readonly property bool disablePolkitIntegration: Quickshell.env("DMS_DISABLE_POLKIT") === "1"
|
||||
|
||||
@@ -17,6 +18,7 @@ Singleton {
|
||||
const qmlString = `
|
||||
import QtQuick
|
||||
import Quickshell.Services.Polkit
|
||||
import qs.Services
|
||||
|
||||
PolkitAgent {
|
||||
}
|
||||
@@ -24,10 +26,10 @@ Singleton {
|
||||
|
||||
agent = Qt.createQmlObject(qmlString, root, "PolkitService.Agent")
|
||||
polkitAvailable = true
|
||||
console.info("PolkitService: Initialized successfully")
|
||||
log.info("Initialized successfully")
|
||||
} catch (e) {
|
||||
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.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("PortalService")
|
||||
|
||||
property bool accountsServiceAvailable: false
|
||||
property string systemProfileImage: ""
|
||||
@@ -127,7 +129,7 @@ Singleton {
|
||||
"iconTheme": themeName
|
||||
}, response => {
|
||||
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 || ""
|
||||
}, response => {
|
||||
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();
|
||||
let userMessage = I18n.tr("Failed to set profile image");
|
||||
@@ -169,7 +171,7 @@ Singleton {
|
||||
if (socketPath && socketPath.length > 0) {
|
||||
checkDMSCapabilities();
|
||||
} else {
|
||||
console.info("PortalService: DMS_SOCKET not set");
|
||||
log.info("DMS_SOCKET not set");
|
||||
}
|
||||
colorSchemeDetector.running = true;
|
||||
}
|
||||
@@ -207,7 +209,7 @@ Singleton {
|
||||
checkAccountsService();
|
||||
checkSettingsPortal();
|
||||
} else {
|
||||
console.info("PortalService: freedesktop capability not available in DMS");
|
||||
log.info("freedesktop capability not available in DMS");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,9 +8,11 @@ import Quickshell.Hyprland
|
||||
import Quickshell.I3
|
||||
import Quickshell.Wayland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("SessionService")
|
||||
|
||||
property bool hasUwsm: false
|
||||
property bool isElogind: false
|
||||
@@ -64,15 +66,15 @@ Singleton {
|
||||
detectHibernateProcess.running = true;
|
||||
detectPrimeRunProcess.running = true;
|
||||
detectWtypeProcess.running = true;
|
||||
console.info("SessionService: Native inhibitor available:", nativeInhibitorAvailable);
|
||||
log.info("Native inhibitor available:", nativeInhibitorAvailable);
|
||||
if (!SettingsData.loginctlLockIntegration) {
|
||||
console.log("SessionService: loginctl lock integration disabled by user");
|
||||
log.debug("loginctl lock integration disabled by user");
|
||||
return;
|
||||
}
|
||||
if (socketPath && socketPath.length > 0) {
|
||||
checkDMSCapabilities();
|
||||
} 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)$'"]
|
||||
|
||||
onExited: function (exitCode) {
|
||||
console.log("SessionService: Elogind detection exited with code", exitCode);
|
||||
log.debug("Elogind detection exited with code", exitCode);
|
||||
isElogind = (exitCode === 0);
|
||||
}
|
||||
}
|
||||
@@ -396,7 +398,7 @@ Singleton {
|
||||
if (idleInhibited) {
|
||||
return;
|
||||
}
|
||||
console.log("SessionService: Enabling idle inhibit (native:", nativeInhibitorAvailable, ")");
|
||||
log.debug("Enabling idle inhibit (native:", nativeInhibitorAvailable, ")");
|
||||
idleInhibited = true;
|
||||
inhibitorChanged();
|
||||
}
|
||||
@@ -405,7 +407,7 @@ Singleton {
|
||||
if (!idleInhibited) {
|
||||
return;
|
||||
}
|
||||
console.log("SessionService: Disabling idle inhibit (native:", nativeInhibitorAvailable, ")");
|
||||
log.debug("Disabling idle inhibit (native:", nativeInhibitorAvailable, ")");
|
||||
idleInhibited = false;
|
||||
inhibitorChanged();
|
||||
}
|
||||
@@ -441,19 +443,19 @@ Singleton {
|
||||
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"];
|
||||
}
|
||||
|
||||
running: idleInhibited && !nativeInhibitorAvailable
|
||||
|
||||
onRunningChanged: {
|
||||
console.log("SessionService: Inhibit process running:", running, "(native:", nativeInhibitorAvailable, ")");
|
||||
log.debug("Inhibit process running:", running, "(native:", nativeInhibitorAvailable, ")");
|
||||
}
|
||||
|
||||
onExited: function (exitCode) {
|
||||
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;
|
||||
ToastService.showWarning("Idle inhibitor failed");
|
||||
}
|
||||
@@ -545,7 +547,7 @@ Singleton {
|
||||
}
|
||||
} else {
|
||||
loginctlAvailable = false;
|
||||
console.log("SessionService: loginctl capability not available in DMS");
|
||||
log.debug("loginctl capability not available in DMS");
|
||||
}
|
||||
|
||||
if (DMSService.capabilities.includes("dbus")) {
|
||||
@@ -574,7 +576,7 @@ Singleton {
|
||||
prepareForSleepSubscriptionPending = false;
|
||||
|
||||
if (response.error) {
|
||||
console.warn("SessionService: Failed to subscribe to PrepareForSleep:", response.error);
|
||||
log.warn("Failed to subscribe to PrepareForSleep:", response.error);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -621,9 +623,9 @@ Singleton {
|
||||
enabled: SettingsData.lockBeforeSuspend
|
||||
}, response => {
|
||||
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 {
|
||||
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
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
console.warn("SessionService: Failed to sync sleep inhibitor:", response.error);
|
||||
log.warn("Failed to sync sleep inhibitor:", response.error);
|
||||
} else {
|
||||
console.log("SessionService: Synced sleep inhibitor:", SettingsData.loginctlLockIntegration);
|
||||
log.debug("Synced sleep inhibitor:", SettingsData.loginctlLockIntegration);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,9 +5,11 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("SettingsSearchService")
|
||||
|
||||
property string query: ""
|
||||
property var results: []
|
||||
@@ -41,12 +43,12 @@ Singleton {
|
||||
root.indexLoaded = true;
|
||||
root._rebuildTranslationCache();
|
||||
} catch (e) {
|
||||
console.warn("SettingsSearchService: Failed to parse index:", e);
|
||||
log.warn("Failed to parse index:", e);
|
||||
root.settingsIndex = [];
|
||||
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) {
|
||||
|
||||
@@ -4,9 +4,11 @@ pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("VPNService")
|
||||
|
||||
readonly property bool available: DMSNetworkService.vpnAvailable
|
||||
|
||||
@@ -48,7 +50,7 @@ Singleton {
|
||||
DMSService.sendRequest("network.vpn.plugins", null, response => {
|
||||
pluginsLoading = false;
|
||||
if (response.error) {
|
||||
console.warn("VPNService: Failed to fetch plugins:", response.error);
|
||||
log.warn("Failed to fetch plugins:", response.error);
|
||||
return;
|
||||
}
|
||||
if (!response.result)
|
||||
|
||||
@@ -3,9 +3,11 @@ pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Services
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("WlrOutputService")
|
||||
|
||||
property bool wlrOutputAvailable: false
|
||||
property var outputs: []
|
||||
@@ -53,7 +55,7 @@ Singleton {
|
||||
const hasWlrOutput = DMSService.capabilities.includes("wlroutput");
|
||||
if (hasWlrOutput && !wlrOutputAvailable) {
|
||||
wlrOutputAvailable = true;
|
||||
console.info("WlrOutputService: wlr-output-management capability detected");
|
||||
log.info("wlr-output-management capability detected");
|
||||
requestState();
|
||||
return;
|
||||
}
|
||||
@@ -81,11 +83,11 @@ Singleton {
|
||||
serial = state.serial || 0;
|
||||
|
||||
if (outputs.length === 0) {
|
||||
console.warn("WlrOutputService: Received empty outputs list");
|
||||
log.warn("Received empty outputs list");
|
||||
} else {
|
||||
console.log("WlrOutputService: Updated with", outputs.length, "outputs, serial:", serial);
|
||||
log.debug("Updated with", outputs.length, "outputs, serial:", serial);
|
||||
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();
|
||||
@@ -112,9 +114,9 @@ Singleton {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("WlrOutputService: Applying configuration for", heads.length, "outputs");
|
||||
log.debug("Applying configuration for", heads.length, "outputs");
|
||||
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", {
|
||||
@@ -124,9 +126,9 @@ Singleton {
|
||||
const message = response.error || response.result?.message || "";
|
||||
|
||||
if (response.error) {
|
||||
console.warn("WlrOutputService: applyConfiguration error:", response.error);
|
||||
log.warn("applyConfiguration error:", response.error);
|
||||
} else {
|
||||
console.log("WlrOutputService: Configuration applied successfully");
|
||||
log.debug("Configuration applied successfully");
|
||||
}
|
||||
|
||||
configurationApplied(success, message);
|
||||
@@ -144,7 +146,7 @@ Singleton {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("WlrOutputService: Testing configuration for", heads.length, "outputs");
|
||||
log.debug("Testing configuration for", heads.length, "outputs");
|
||||
|
||||
DMSService.sendRequest("wlroutput.testConfiguration", {
|
||||
"heads": heads
|
||||
@@ -153,9 +155,9 @@ Singleton {
|
||||
const message = response.error || response.result?.message || "";
|
||||
|
||||
if (response.error) {
|
||||
console.warn("WlrOutputService: testConfiguration error:", response.error);
|
||||
log.warn("testConfiguration error:", response.error);
|
||||
} else {
|
||||
console.log("WlrOutputService: Configuration test passed");
|
||||
log.debug("Configuration test passed");
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
@@ -167,7 +169,7 @@ Singleton {
|
||||
function setOutputEnabled(outputName, enabled, callback) {
|
||||
const output = getOutput(outputName);
|
||||
if (!output) {
|
||||
console.warn("WlrOutputService: Output not found:", outputName);
|
||||
log.warn("Output not found:", outputName);
|
||||
if (callback) {
|
||||
callback(false, "Output not found");
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import qs.Services
|
||||
|
||||
PanelWindow {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DankOSD")
|
||||
|
||||
property string blurNamespace: "dms:osd"
|
||||
WlrLayershell.namespace: blurNamespace
|
||||
@@ -94,10 +95,10 @@ PanelWindow {
|
||||
WlrLayershell.layer: {
|
||||
switch (Quickshell.env("DMS_OSD_LAYER")) {
|
||||
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;
|
||||
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;
|
||||
case "top":
|
||||
return WlrLayershell.Top;
|
||||
|
||||
@@ -6,6 +6,7 @@ import qs.Services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("DankPopout")
|
||||
|
||||
property string layerNamespace: "dms:popout"
|
||||
property alias content: contentLoader.sourceComponent
|
||||
@@ -414,10 +415,10 @@ Item {
|
||||
WlrLayershell.layer: {
|
||||
switch (Quickshell.env("DMS_POPOUT_LAYER")) {
|
||||
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;
|
||||
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;
|
||||
case "overlay":
|
||||
return WlrLayershell.Overlay;
|
||||
|
||||
@@ -11,6 +11,7 @@ import "../Common/KeybindActions.js" as Actions
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("KeybindItem")
|
||||
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
LayoutMirroring.childrenInherit: true
|
||||
@@ -716,7 +717,7 @@ Item {
|
||||
|
||||
const key = KeyUtils.xkbKeyFromQtKey(qtKey);
|
||||
if (!key) {
|
||||
console.warn("[KeybindItem] Unknown key:", event.key, "mods:", event.modifiers);
|
||||
log.warn("Unknown key:", event.key, "mods:", event.modifiers);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,24 +3,25 @@ import qs.Services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
readonly property var log: Log.scoped("PluginGlobalVar")
|
||||
|
||||
required property string varName
|
||||
property var defaultValue: undefined
|
||||
|
||||
readonly property var value: {
|
||||
const pid = parent?.pluginId ?? ""
|
||||
const pid = parent?.pluginId ?? "";
|
||||
if (!pid || !PluginService.globalVars[pid]) {
|
||||
return defaultValue
|
||||
return defaultValue;
|
||||
}
|
||||
return PluginService.globalVars[pid][varName] ?? defaultValue
|
||||
return PluginService.globalVars[pid][varName] ?? defaultValue;
|
||||
}
|
||||
|
||||
function set(newValue) {
|
||||
const pid = parent?.pluginId ?? ""
|
||||
const pid = parent?.pluginId ?? "";
|
||||
if (pid) {
|
||||
PluginService.setGlobalVar(pid, varName, newValue)
|
||||
PluginService.setGlobalVar(pid, varName, newValue);
|
||||
} else {
|
||||
console.warn("PluginGlobalVar: Cannot set", varName, "- no pluginId from parent")
|
||||
log.warn("Cannot set", varName, "- no pluginId from parent");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user