From 93838353573233b5584b106eb897a37f8a4e63ac Mon Sep 17 00:00:00 2001 From: Lemmy Date: Fri, 6 Feb 2026 22:48:33 -0500 Subject: [PATCH 1/4] sysstat: dont scan for thermalzone gpus unless dgpu monitoring is on --- Services/System/SystemStatService.qml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Services/System/SystemStatService.qml b/Services/System/SystemStatService.qml index 5736ede0f..9ee97bebe 100644 --- a/Services/System/SystemStatService.qml +++ b/Services/System/SystemStatService.qml @@ -1319,16 +1319,17 @@ Singleton { // Priority (when dGPU monitoring enabled): NVIDIA > AMD dGPU > Intel Arc > AMD iGPU // Priority (when dGPU monitoring disabled): AMD iGPU only (discrete GPUs skipped to preserve D3cold) function selectBestGpu() { + const dgpuEnabled = Settings.data.systemMonitor.enableDgpuMonitoring; + if (root.foundGpuSensors.length === 0) { // No hwmon GPU sensors found, try thermal_zone fallback - if (root.gpuThermalZonePath === "" && root.gpuThermalZonePaths.length === 0) { + if (dgpuEnabled && root.gpuThermalZonePath === "" && root.gpuThermalZonePaths.length === 0) { // Thermal zone scanner hasn't found GPU zones yet; start a scan thermalZoneScanner.startScan(); } return; } - const dgpuEnabled = Settings.data.systemMonitor.enableDgpuMonitoring; let best = null; for (var i = 0; i < root.foundGpuSensors.length; i++) { From 80f35bf8026bd27387abd2f711bb43cd93f0b771 Mon Sep 17 00:00:00 2001 From: Lysec Date: Sat, 7 Feb 2026 10:43:47 +0100 Subject: [PATCH 2/4] gtk-refresh: check for existing adw-gtk3 theme, else skip setting it (#1713) --- Scripts/python/src/theming/gtk-refresh.py | 33 +++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/Scripts/python/src/theming/gtk-refresh.py b/Scripts/python/src/theming/gtk-refresh.py index 43c1b4ab1..18f409d6d 100644 --- a/Scripts/python/src/theming/gtk-refresh.py +++ b/Scripts/python/src/theming/gtk-refresh.py @@ -17,6 +17,29 @@ async def run_command(*args): return stdout.decode().strip() +def theme_exists(theme_name: str) -> bool: + """Check if a GTK theme exists in common locations.""" + search_paths = [ + Path.home() / ".themes", + Path.home() / ".local/share/themes", + Path("/usr/share/themes"), + Path("/usr/local/share/themes"), + ] + + # Add paths from XDG_DATA_DIRS + xdg_data_dirs = os.environ.get("XDG_DATA_DIRS", "") + if xdg_data_dirs: + for path in xdg_data_dirs.split(":"): + if path: + search_paths.append(Path(path) / "themes") + + for base_path in search_paths: + if (base_path / theme_name).is_dir(): + return True + + return False + + async def apply_gtk3_colors(config_dir: Path): gtk3_dir = config_dir / "gtk-3.0" colors_file = gtk3_dir / "noctalia.css" @@ -66,16 +89,22 @@ async def refresh_theme(): else: target_theme = "adw-gtk3-dark" + theme_available = theme_exists(target_theme) + if not theme_available: + print(f"Theme '{target_theme}' not found, skipping GTK theme set") + if has_gsettings: schemas = await run_command("gsettings", "list-schemas") if schemas and "org.gnome.desktop.interface" in schemas: await run_command("gsettings", "set", "org.gnome.desktop.interface", "color-scheme", f"prefer-{mode}") - await run_command("gsettings", "set", "org.gnome.desktop.interface", "gtk-theme", f"{target_theme}") + if theme_available: + await run_command("gsettings", "set", "org.gnome.desktop.interface", "gtk-theme", f"{target_theme}") return if has_dconf: await run_command("dconf", "write", "/org/gnome/desktop/interface/color-scheme", f"'prefer-{mode}'") - await run_command("dconf", "write", "/org/gnome/desktop/interface/gtk-theme", f"'{target_theme}'") + if theme_available: + await run_command("dconf", "write", "/org/gnome/desktop/interface/gtk-theme", f"'{target_theme}'") async def get_config_dir() -> Path: From b56f3bd363e5a582bf0cfab4d00faaf0e5fc5d0b Mon Sep 17 00:00:00 2001 From: Lysec Date: Sat, 7 Feb 2026 11:00:44 +0100 Subject: [PATCH 3/4] SessionMenu: properly run custom commands via IPC (fix #1708) --- Assets/Translations/en.json | 2 +- .../Launcher/Providers/SessionProvider.qml | 13 ++----- Modules/Panels/SessionMenu/SessionMenu.qml | 20 +--------- Services/Compositor/CompositorService.qml | 39 ++++++++++++++++++- 4 files changed, 43 insertions(+), 31 deletions(-) diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index 707a16cb1..1d7fc289e 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -1889,4 +1889,4 @@ "poor": "Poor" } } -} +} \ No newline at end of file diff --git a/Modules/Panels/Launcher/Providers/SessionProvider.qml b/Modules/Panels/Launcher/Providers/SessionProvider.qml index 8752e23f0..1d614c12f 100644 --- a/Modules/Panels/Launcher/Providers/SessionProvider.qml +++ b/Modules/Panels/Launcher/Providers/SessionProvider.qml @@ -141,20 +141,13 @@ Item { launcher.close(); Qt.callLater(() => { - executeAction(action, command); + executeAction(action); }); }; } - function executeAction(action, command) { - // If custom command is defined, execute it - if (command && command.trim() !== "") { - Logger.i("SessionProvider", "Executing custom command for action:", action, "Command:", command); - Quickshell.execDetached(["sh", "-c", command]); - return; - } - - // Otherwise, use default behavior + function executeAction(action) { + // Default behavior or custom command handled by CompositorService switch (action) { case "lock": if (PanelService.lockScreen && !PanelService.lockScreen.active) { diff --git a/Modules/Panels/SessionMenu/SessionMenu.qml b/Modules/Panels/SessionMenu/SessionMenu.qml index 809ee98c1..aea8b0aa3 100644 --- a/Modules/Panels/SessionMenu/SessionMenu.qml +++ b/Modules/Panels/SessionMenu/SessionMenu.qml @@ -211,25 +211,7 @@ SmartPanel { // Stop timer but don't reset other properties yet countdownTimer.stop(); - // Find the option to check for custom command - var option = null; - for (var i = 0; i < powerOptions.length; i++) { - if (powerOptions[i].action === action) { - option = powerOptions[i]; - break; - } - } - - // If custom command is defined, execute it - if (option && option.command && option.command.trim() !== "") { - Logger.i("SessionMenu", "Executing custom command for action:", action, "Command:", option.command); - Quickshell.execDetached(["sh", "-c", option.command]); - cancelTimer(); - root.close(); - return; - } - - // Otherwise, use default behavior + // Use default behavior or custom command handled by CompositorService switch (action) { case "lock": // Access lockScreen via PanelService diff --git a/Services/Compositor/CompositorService.qml b/Services/Compositor/CompositorService.qml index 9c57752ef..817b5b5e1 100644 --- a/Services/Compositor/CompositorService.qml +++ b/Services/Compositor/CompositorService.qml @@ -425,10 +425,35 @@ Singleton { } } + // Session management helper for custom commands + function getCustomCommand(action) { + const powerOptions = Settings.data.sessionMenu.powerOptions || []; + for (let i = 0; i < powerOptions.length; i++) { + const option = powerOptions[i]; + if (option.action === action && option.enabled && option.command && option.command.trim() !== "") { + return option.command.trim(); + } + } + return ""; + } + + function executeSessionAction(action, defaultCommand) { + const customCommand = getCustomCommand(action); + if (customCommand) { + Logger.i("Compositor", `Executing custom command for action: ${action} Command: ${customCommand}`); + Quickshell.execDetached(["sh", "-c", customCommand]); + return true; + } + return false; + } + // Session management function logout() { + Logger.i("Compositor", "Logout requested"); + if (executeSessionAction("logout")) + return; + if (backend && backend.logout) { - Logger.i("Compositor", "Logout requested"); backend.logout(); } else { Logger.w("Compositor", "No backend available for logout"); @@ -437,6 +462,9 @@ Singleton { function shutdown() { Logger.i("Compositor", "Shutdown requested"); + if (executeSessionAction("shutdown")) + return; + HooksService.executeSessionHook("shutdown", () => { Quickshell.execDetached(["sh", "-c", "systemctl poweroff || loginctl poweroff"]); }); @@ -444,6 +472,9 @@ Singleton { function reboot() { Logger.i("Compositor", "Reboot requested"); + if (executeSessionAction("reboot")) + return; + HooksService.executeSessionHook("reboot", () => { Quickshell.execDetached(["sh", "-c", "systemctl reboot || loginctl reboot"]); }); @@ -451,11 +482,17 @@ Singleton { function suspend() { Logger.i("Compositor", "Suspend requested"); + if (executeSessionAction("suspend")) + return; + Quickshell.execDetached(["sh", "-c", "systemctl suspend || loginctl suspend"]); } function hibernate() { Logger.i("Compositor", "Hibernate requested"); + if (executeSessionAction("hibernate")) + return; + Quickshell.execDetached(["sh", "-c", "systemctl hibernate || loginctl hibernate"]); } From 1447a499112ee962443d33966c381207c5b5db5b Mon Sep 17 00:00:00 2001 From: Lysec Date: Sat, 7 Feb 2026 12:14:48 +0100 Subject: [PATCH 4/4] OSD: add guard check for root & proper cleanup for brightness --- Modules/OSD/OSD.qml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Modules/OSD/OSD.qml b/Modules/OSD/OSD.qml index 50de42614..e4caa3d3e 100644 --- a/Modules/OSD/OSD.qml +++ b/Modules/OSD/OSD.qml @@ -177,6 +177,9 @@ Variants { } function onBrightnessChanged(newBrightness) { + if (!root) + return; + root.currentBrightness = newBrightness; // Don't show OSD if brightness panel is open var brightnessPanel = PanelService.getPanel("brightnessPanel", root.modelData); @@ -327,6 +330,18 @@ Variants { } } + Component.onDestruction: { + if (typeof BrightnessService !== "undefined" && BrightnessService.monitors) { + for (var i = 0; i < BrightnessService.monitors.length; i++) { + try { + BrightnessService.monitors[i].brightnessUpdated.disconnect(onBrightnessChanged); + } catch (e) { + // Ignore errors if already disconnected or not connected + } + } + } + } + // Visual Component sourceComponent: PanelWindow { id: panel