From b4f505605c42dc92a3bbc1ad4683025ede1b222f Mon Sep 17 00:00:00 2001 From: Chintan Patel <216989679+Chintanpatel24@users.noreply.github.com> Date: Thu, 15 Oct 2026 22:46:04 +0530 Subject: [PATCH] fix(wallpaper,lifecycle,bar): support user wallpaper dir, ultra-fast switching, prevent app termination on restart, and add open-on-hover --- crates/agility-cli/src/main.rs | 84 +++++++++++++++---- crates/agilityd/src/modules/launcher.rs | 67 +++++++++++---- crates/agilityd/src/modules/theme.rs | 22 ++++- .../agility/Core/Services/SettingsService.qml | 5 ++ .../Core/Services/WallpaperManager.qml | 21 ++++- .../Modules/Bar/Components/BarButton.qml | 25 ++++++ .../Modules/Bar/Components/BatteryPill.qml | 21 ++++- .../Modules/Bar/Components/ClockButton.qml | 31 +++++++ .../Bar/Components/ControlCenterButton.qml | 20 +++++ .../Modules/Bar/Components/MediaButton.qml | 20 +++++ .../Modules/Bar/Components/NetworkPill.qml | 24 +++++- .../Bar/Components/NotificationsButton.qml | 20 +++++ .../Modules/Bar/Components/WeatherPill.qml | 20 +++++ .../Modules/Bar/Styles/Island/IslandClock.qml | 26 +++++- .../Settings/BarSettings/BarSettings.qml | 12 +++ .../WallpaperSelectorContent.qml | 17 +++- systemd/agility-shell.service | 2 +- 17 files changed, 394 insertions(+), 43 deletions(-) diff --git a/crates/agility-cli/src/main.rs b/crates/agility-cli/src/main.rs index d048813..fd10190 100644 --- a/crates/agility-cli/src/main.rs +++ b/crates/agility-cli/src/main.rs @@ -1695,23 +1695,48 @@ fn spawn_detached_exec(exec_cmd: &str, in_terminal: bool) -> bool { return false; } - let mut cmd = Command::new("sh"); - if in_terminal { - let term = if is_command_available("alacritty") { - "alacritty -e" - } else if is_command_available("kitty") { - "kitty -e" - } else if is_command_available("foot") { - "foot -e" - } else if is_command_available("xfce4-terminal") { - "xfce4-terminal -e" + let has_systemd_run = is_command_available("systemd-run"); + + let mut cmd = if has_systemd_run { + let mut c = Command::new("systemd-run"); + c.args(["--user", "--scope", "--slice=app.slice", "-q", "--"]); + if in_terminal { + let term = if is_command_available("alacritty") { + "alacritty" + } else if is_command_available("kitty") { + "kitty" + } else if is_command_available("foot") { + "foot" + } else if is_command_available("xfce4-terminal") { + "xfce4-terminal" + } else { + "xterm" + }; + c.args([term, "-e", "sh", "-c", &cleaned]); } else { - "xterm -e" - }; - cmd.args(["-c", &format!("{term} {cleaned} &")]); + c.args(["sh", "-c", &cleaned]); + } + c } else { - cmd.args(["-c", &format!("{cleaned} &")]); - } + let mut c = Command::new("sh"); + if in_terminal { + let term = if is_command_available("alacritty") { + "alacritty -e" + } else if is_command_available("kitty") { + "kitty -e" + } else if is_command_available("foot") { + "foot -e" + } else if is_command_available("xfce4-terminal") { + "xfce4-terminal -e" + } else { + "xterm -e" + }; + c.args(["-c", &format!("{term} {cleaned} &")]); + } else { + c.args(["-c", &format!("{cleaned} &")]); + } + c + }; #[cfg(unix)] { @@ -1756,10 +1781,14 @@ fn resolve_cli_wallpaper(path_str: &str) -> Option { let mut search_dirs = Vec::new(); if let Ok(home) = std::env::var("HOME") { + search_dirs.push(Path::new(&home).join(".local/share/agility-shell/wallpapers")); search_dirs.push(Path::new(&home).join(".config/agility-shell/wallpapers")); search_dirs.push(Path::new(&home).join("Pictures/Wallpapers")); search_dirs.push(Path::new(&home).join("Pictures")); } + if let Ok(data_home) = std::env::var("XDG_DATA_HOME") { + search_dirs.push(Path::new(&data_home).join("agility-shell/wallpapers")); + } search_dirs.push(Path::new("/usr/share/agility-shell/wallpapers").to_path_buf()); search_dirs.push(Path::new("wallpapers").to_path_buf()); @@ -1776,10 +1805,14 @@ fn resolve_cli_wallpaper(path_str: &str) -> Option { fn list_cli_wallpapers() -> Vec { let mut search_dirs = Vec::new(); if let Ok(home) = std::env::var("HOME") { + search_dirs.push(Path::new(&home).join(".local/share/agility-shell/wallpapers")); search_dirs.push(Path::new(&home).join(".config/agility-shell/wallpapers")); search_dirs.push(Path::new(&home).join("Pictures/Wallpapers")); search_dirs.push(Path::new(&home).join("Pictures")); } + if let Ok(data_home) = std::env::var("XDG_DATA_HOME") { + search_dirs.push(Path::new(&data_home).join("agility-shell/wallpapers")); + } search_dirs.push(Path::new("/usr/share/agility-shell/wallpapers").to_path_buf()); search_dirs.push(Path::new("wallpapers").to_path_buf()); @@ -1984,10 +2017,27 @@ async fn apply_cli_wallpaper( let _ = Command::new("awww-daemon").spawn(); } - // Dispatch awww img + // Dispatch awww img with ultra-fast bilinear filter and 60fps step if is_command_available("awww") { let mut cmd = Command::new("awww"); - cmd.args(["img", &abs_str, "--resize", "crop"]); + let t_type = transition.unwrap_or("grow"); + let dur_str = format!("{:.2}", duration.unwrap_or(0.2)); + cmd.args([ + "img", + &abs_str, + "--resize", + "crop", + "--filter", + "Bilinear", + "--transition-type", + t_type, + "--transition-duration", + &dur_str, + "--transition-step", + "180", + "--transition-fps", + "60", + ]); let _ = cmd.spawn(); } diff --git a/crates/agilityd/src/modules/launcher.rs b/crates/agilityd/src/modules/launcher.rs index 7368861..d8724c5 100644 --- a/crates/agilityd/src/modules/launcher.rs +++ b/crates/agilityd/src/modules/launcher.rs @@ -338,28 +338,63 @@ impl LauncherService { return false; } - let mut cmd = Command::new("sh"); - if in_terminal { - // Pick terminal emulator or fallback to standard x-terminal-emulator - let term = if which("alacritty") { - "alacritty -e" - } else if which("kitty") { - "kitty -e" - } else if which("foot") { - "foot -e" - } else if which("xfce4-terminal") { - "xfce4-terminal -e" + let has_systemd_run = which("systemd-run"); + + let mut cmd = if has_systemd_run { + let mut c = Command::new("systemd-run"); + c.args(["--user", "--scope", "--slice=app.slice", "-q", "--"]); + if in_terminal { + let term = if which("alacritty") { + "alacritty" + } else if which("kitty") { + "kitty" + } else if which("foot") { + "foot" + } else if which("xfce4-terminal") { + "xfce4-terminal" + } else { + "xterm" + }; + c.args([term, "-e", "sh", "-c", &cleaned]); } else { - "xterm -e" - }; - cmd.args(["-c", &format!("{term} {cleaned} &")]); + c.args(["sh", "-c", &cleaned]); + } + c } else { - cmd.args(["-c", &format!("{cleaned} &")]); + let mut c = Command::new("sh"); + if in_terminal { + let term = if which("alacritty") { + "alacritty -e" + } else if which("kitty") { + "kitty -e" + } else if which("foot") { + "foot -e" + } else if which("xfce4-terminal") { + "xfce4-terminal -e" + } else { + "xterm -e" + }; + c.args(["-c", &format!("{term} {cleaned} &")]); + } else { + c.args(["-c", &format!("{cleaned} &")]); + } + c + }; + + #[cfg(unix)] + { + use std::os::unix::process::CommandExt; + unsafe { + cmd.pre_exec(|| { + libc::setsid(); + Ok(()) + }); + } } match cmd.spawn() { Ok(_) => { - info!("Successfully launched application: {cleaned}"); + info!("Successfully launched application in isolated app.slice: {cleaned}"); true } Err(e) => { diff --git a/crates/agilityd/src/modules/theme.rs b/crates/agilityd/src/modules/theme.rs index 9687c86..2534e2d 100644 --- a/crates/agilityd/src/modules/theme.rs +++ b/crates/agilityd/src/modules/theme.rs @@ -55,10 +55,14 @@ pub fn resolve_wallpaper_path(path_str: &str) -> Option { let mut search_dirs = Vec::new(); if let Ok(home) = std::env::var("HOME") { + search_dirs.push(PathBuf::from(&home).join(".local/share/agility-shell/wallpapers")); search_dirs.push(PathBuf::from(&home).join(".config/agility-shell/wallpapers")); search_dirs.push(PathBuf::from(&home).join("Pictures/Wallpapers")); search_dirs.push(PathBuf::from(&home).join("Pictures")); } + if let Ok(data_home) = std::env::var("XDG_DATA_HOME") { + search_dirs.push(PathBuf::from(&data_home).join("agility-shell/wallpapers")); + } search_dirs.push(PathBuf::from("/usr/share/agility-shell/wallpapers")); search_dirs.push(PathBuf::from("wallpapers")); @@ -76,10 +80,14 @@ pub fn resolve_wallpaper_path(path_str: &str) -> Option { pub fn list_all_wallpapers() -> Vec { let mut search_dirs = Vec::new(); if let Ok(home) = std::env::var("HOME") { + search_dirs.push(PathBuf::from(&home).join(".local/share/agility-shell/wallpapers")); search_dirs.push(PathBuf::from(&home).join(".config/agility-shell/wallpapers")); search_dirs.push(PathBuf::from(&home).join("Pictures/Wallpapers")); search_dirs.push(PathBuf::from(&home).join("Pictures")); } + if let Ok(data_home) = std::env::var("XDG_DATA_HOME") { + search_dirs.push(PathBuf::from(&data_home).join("agility-shell/wallpapers")); + } search_dirs.push(PathBuf::from("/usr/share/agility-shell/wallpapers")); search_dirs.push(PathBuf::from("wallpapers")); @@ -300,7 +308,7 @@ impl ThemeService { // 1. Instantly dispatch wallpaper setter (awww / swww) in < 5ms let t_type = transition_type.unwrap_or("grow"); - let t_dur = duration.unwrap_or(0.25); + let t_dur = duration.unwrap_or(0.20); Self::dispatch_wallpaper_backend(&abs_str, t_type, t_dur); // Immediate responsive token return with new wallpaper @@ -624,10 +632,18 @@ impl ThemeService { let _ = Command::new("awww") .arg("img") .arg(path) + .arg("--resize") + .arg("crop") + .arg("--filter") + .arg("Bilinear") .arg("--transition-type") .arg(transition_type) .arg("--transition-duration") .arg(&dur_str) + .arg("--transition-step") + .arg("180") + .arg("--transition-fps") + .arg("60") .spawn(); return; } @@ -660,6 +676,10 @@ impl ThemeService { .arg(transition_type) .arg("--transition-duration") .arg(&dur_str) + .arg("--transition-step") + .arg("180") + .arg("--transition-fps") + .arg("60") .spawn(); return; } diff --git a/quickshell/agility/Core/Services/SettingsService.qml b/quickshell/agility/Core/Services/SettingsService.qml index cd74539..0191ac1 100644 --- a/quickshell/agility/Core/Services/SettingsService.qml +++ b/quickshell/agility/Core/Services/SettingsService.qml @@ -34,6 +34,7 @@ Item { property string pillPopupStyle: "center" property string pillWidgetLayout: "distributed" property bool barAutoHide: false + property bool barOpenOnHover: false property string barGlassMode: "solid" property int barGlassOpacity: 85 property bool appletActiveWindow: true @@ -291,6 +292,7 @@ Item { "pillPopupStyle": settingsService.pillPopupStyle, "pillWidgetLayout": settingsService.pillWidgetLayout, "barAutoHide": settingsService.barAutoHide, + "barOpenOnHover": settingsService.barOpenOnHover, "barGlassMode": settingsService.barGlassMode, "barGlassOpacity": settingsService.barGlassOpacity, "appletActiveWindow": settingsService.appletActiveWindow, @@ -490,6 +492,9 @@ cp ~/.cache/quickshell/settings_prefs.json /var/tmp/sddm-theme/settings_prefs.js if (prefs.barAutoHide !== undefined) settingsService.barAutoHide = Boolean(prefs.barAutoHide); + if (prefs.barOpenOnHover !== undefined) + settingsService.barOpenOnHover = Boolean(prefs.barOpenOnHover); + if (prefs.barGlassMode !== undefined) settingsService.barGlassMode = prefs.barGlassMode; if (prefs.barGlassOpacity !== undefined) diff --git a/quickshell/agility/Core/Services/WallpaperManager.qml b/quickshell/agility/Core/Services/WallpaperManager.qml index 57c79e0..091b840 100644 --- a/quickshell/agility/Core/Services/WallpaperManager.qml +++ b/quickshell/agility/Core/Services/WallpaperManager.qml @@ -20,6 +20,7 @@ QtObject { property bool enableTransitions: HyprlandService.wpEnableTransitions property bool autoShuffle: HyprlandService.wpAutoShuffle property int shuffleInterval: HyprlandService.wpShuffleInterval + property Process fastAwwwProc property Process wallpaperApplyProc property Process wallpaperSaveProc property Process wallpaperLoader @@ -49,8 +50,23 @@ QtObject { HyprlandService.wpAutoShuffle = false; SettingsService.saveSettings(); } + + // Fast path: Immediately apply wallpaper with awww directly (< 250ms visual switch) + fastAwwwProc.running = false; + fastAwwwProc.command = [ + "awww", "img", rawPath, + "--resize", "crop", + "--filter", "Bilinear", + "--transition-type", (enableTransitions && SystemInfoService.powerProfile !== "power-saver" && transitionType) ? transitionType : "grow", + "--transition-duration", "0.2", + "--transition-step", "180", + "--transition-fps", "60" + ]; + fastAwwwProc.startDetached(); + + // Daemon sync: extracts palette, generates blur, writes cache wallpaperApplyProc.running = false; - let cmd = ["agl", "wallpaper", rawPath]; + let cmd = ["agl", "wallpaper", rawPath, "--duration", "0.2"]; if (enableTransitions && SystemInfoService.powerProfile !== "power-saver" && transitionType) { cmd.push("--transition", transitionType); } @@ -83,6 +99,9 @@ QtObject { } } + fastAwwwProc: Process { + } + wallpaperApplyProc: Process { } diff --git a/quickshell/agility/Modules/Bar/Components/BarButton.qml b/quickshell/agility/Modules/Bar/Components/BarButton.qml index 974f6b5..0da4ef9 100644 --- a/quickshell/agility/Modules/Bar/Components/BarButton.qml +++ b/quickshell/agility/Modules/Bar/Components/BarButton.qml @@ -37,13 +37,38 @@ Rectangle { iconColor: (!root.hasBackground && mouseArea.containsMouse) ? Theme.accent : root.iconColor } + Timer { + id: hoverTimer + + interval: 160 + repeat: false + onTriggered: { + if (SettingsService.barOpenOnHover && mouseArea.containsMouse) { + if (root.widgetId !== "" && root.widgetId !== "powerMenu") { + if (!AppState.isWidgetOpen(root.widgetId)) + AppState.openWidget(root.widgetId); + } else if (root.widget && !root.widget.isOpen) { + root.widget.isOpen = true; + } + } + } + } + MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor + onEntered: { + if (SettingsService.barOpenOnHover) + hoverTimer.restart(); + } + onExited: { + hoverTimer.stop(); + } onClicked: { + hoverTimer.stop(); if (root.widgetId !== "") AppState.toggleWidget(root.widgetId); else if (root.widget) diff --git a/quickshell/agility/Modules/Bar/Components/BatteryPill.qml b/quickshell/agility/Modules/Bar/Components/BatteryPill.qml index 2c9323d..2855a50 100644 --- a/quickshell/agility/Modules/Bar/Components/BatteryPill.qml +++ b/quickshell/agility/Modules/Bar/Components/BatteryPill.qml @@ -80,13 +80,32 @@ Rectangle { } } + Timer { + id: hoverTimer + + interval: 160 + repeat: false + onTriggered: { + if (SettingsService.barOpenOnHover && root.isHovered && !AppState.isWidgetOpen("controlCenter")) { + AppState.openWidget("controlCenter"); + } + } + } + MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor - + onEntered: { + if (SettingsService.barOpenOnHover) + hoverTimer.restart(); + } + onExited: { + hoverTimer.stop(); + } onClicked: { + hoverTimer.stop(); AppState.toggleWidget("controlCenter"); } } diff --git a/quickshell/agility/Modules/Bar/Components/ClockButton.qml b/quickshell/agility/Modules/Bar/Components/ClockButton.qml index 41d21f0..d39ee6c 100644 --- a/quickshell/agility/Modules/Bar/Components/ClockButton.qml +++ b/quickshell/agility/Modules/Bar/Components/ClockButton.qml @@ -146,4 +146,35 @@ Rectangle { } + Timer { + id: hoverTimer + + interval: 160 + repeat: false + onTriggered: { + if (SettingsService.barOpenOnHover && clockMouseArea.containsMouse && !AppState.isWidgetOpen("clock")) { + AppState.openWidget("clock"); + } + } + } + + MouseArea { + id: clockMouseArea + + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onEntered: { + if (SettingsService.barOpenOnHover) + hoverTimer.restart(); + } + onExited: { + hoverTimer.stop(); + } + onClicked: { + hoverTimer.stop(); + AppState.toggleWidget("clock"); + } + } + } diff --git a/quickshell/agility/Modules/Bar/Components/ControlCenterButton.qml b/quickshell/agility/Modules/Bar/Components/ControlCenterButton.qml index 4d85f3d..4ec71e7 100644 --- a/quickshell/agility/Modules/Bar/Components/ControlCenterButton.qml +++ b/quickshell/agility/Modules/Bar/Components/ControlCenterButton.qml @@ -43,6 +43,18 @@ Rectangle { } + Timer { + id: hoverTimer + + interval: 160 + repeat: false + onTriggered: { + if (SettingsService.barOpenOnHover && root.isHovered && !root.isActive) { + AppState.openWidget("controlCenter"); + } + } + } + MouseArea { id: mouseArea @@ -50,7 +62,15 @@ Rectangle { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor + onEntered: { + if (SettingsService.barOpenOnHover) + hoverTimer.restart(); + } + onExited: { + hoverTimer.stop(); + } onClicked: { + hoverTimer.stop(); AppState.toggleWidget("controlCenter"); } } diff --git a/quickshell/agility/Modules/Bar/Components/MediaButton.qml b/quickshell/agility/Modules/Bar/Components/MediaButton.qml index fa8c37f..ccd7234 100644 --- a/quickshell/agility/Modules/Bar/Components/MediaButton.qml +++ b/quickshell/agility/Modules/Bar/Components/MediaButton.qml @@ -85,6 +85,18 @@ Rectangle { } } + Timer { + id: hoverTimer + + interval: 160 + repeat: false + onTriggered: { + if (SettingsService.barOpenOnHover && root.isHovered && root.hasMedia && !AppState.isWidgetOpen("music")) { + AppState.openWidget("music"); + } + } + } + MouseArea { id: mouseArea @@ -92,7 +104,15 @@ Rectangle { hoverEnabled: true cursorShape: Qt.PointingHandCursor acceptedButtons: Qt.LeftButton | Qt.RightButton + onEntered: { + if (SettingsService.barOpenOnHover && root.hasMedia) + hoverTimer.restart(); + } + onExited: { + hoverTimer.stop(); + } onClicked: (mouse) => { + hoverTimer.stop(); if (mouse.button === Qt.RightButton) { if (root.hasPlayer) MprisService.activePlayer.togglePlaying(); diff --git a/quickshell/agility/Modules/Bar/Components/NetworkPill.qml b/quickshell/agility/Modules/Bar/Components/NetworkPill.qml index 4a1730b..c862ee0 100644 --- a/quickshell/agility/Modules/Bar/Components/NetworkPill.qml +++ b/quickshell/agility/Modules/Bar/Components/NetworkPill.qml @@ -94,12 +94,34 @@ Rectangle { } } + Timer { + id: hoverTimer + + interval: 160 + repeat: false + onTriggered: { + if (SettingsService.barOpenOnHover && root.isHovered && !AppState.isWidgetOpen("controlCenter")) { + AppState.openWidget("controlCenter"); + } + } + } + MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor - onClicked: AppState.toggleWidget("controlCenter") + onEntered: { + if (SettingsService.barOpenOnHover) + hoverTimer.restart(); + } + onExited: { + hoverTimer.stop(); + } + onClicked: { + hoverTimer.stop(); + AppState.toggleWidget("controlCenter"); + } } RowLayout { diff --git a/quickshell/agility/Modules/Bar/Components/NotificationsButton.qml b/quickshell/agility/Modules/Bar/Components/NotificationsButton.qml index 3a9cec4..cb84238 100644 --- a/quickshell/agility/Modules/Bar/Components/NotificationsButton.qml +++ b/quickshell/agility/Modules/Bar/Components/NotificationsButton.qml @@ -41,6 +41,18 @@ Rectangle { } + Timer { + id: hoverTimer + + interval: 160 + repeat: false + onTriggered: { + if (SettingsService.barOpenOnHover && root.isHovered && !root.isActive) { + AppState.openWidget("notificationsCenter"); + } + } + } + MouseArea { id: mouseArea @@ -48,7 +60,15 @@ Rectangle { anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor + onEntered: { + if (SettingsService.barOpenOnHover) + hoverTimer.restart(); + } + onExited: { + hoverTimer.stop(); + } onClicked: { + hoverTimer.stop(); AppState.toggleWidget("notificationsCenter"); } } diff --git a/quickshell/agility/Modules/Bar/Components/WeatherPill.qml b/quickshell/agility/Modules/Bar/Components/WeatherPill.qml index 3e82137..3449523 100644 --- a/quickshell/agility/Modules/Bar/Components/WeatherPill.qml +++ b/quickshell/agility/Modules/Bar/Components/WeatherPill.qml @@ -56,13 +56,33 @@ Item { } } + Timer { + id: hoverTimer + + interval: 160 + repeat: false + onTriggered: { + if (SettingsService.barOpenOnHover && root.isHovered && !root.isCardOpen) { + AppState.openWidget("weather"); + } + } + } + MouseArea { id: mouseArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor + onEntered: { + if (SettingsService.barOpenOnHover) + hoverTimer.restart(); + } + onExited: { + hoverTimer.stop(); + } onClicked: { + hoverTimer.stop(); AppState.toggleWidget("weather"); } } diff --git a/quickshell/agility/Modules/Bar/Styles/Island/IslandClock.qml b/quickshell/agility/Modules/Bar/Styles/Island/IslandClock.qml index 48eb0fd..555a49b 100644 --- a/quickshell/agility/Modules/Bar/Styles/Island/IslandClock.qml +++ b/quickshell/agility/Modules/Bar/Styles/Island/IslandClock.qml @@ -96,11 +96,35 @@ Item { } + Timer { + id: hoverTimer + + interval: 160 + repeat: false + onTriggered: { + if (SettingsService.barOpenOnHover && clockMouseArea.containsMouse && !AppState.isWidgetOpen("clock")) { + AppState.openWidget("clock"); + } + } + } + MouseArea { + id: clockMouseArea anchors.fill: parent cursorShape: Qt.PointingHandCursor + hoverEnabled: true enabled: root.clickable - onClicked: AppState.toggleWidget("clock") + onEntered: { + if (SettingsService.barOpenOnHover) + hoverTimer.restart(); + } + onExited: { + hoverTimer.stop(); + } + onClicked: { + hoverTimer.stop(); + AppState.toggleWidget("clock"); + } } } diff --git a/quickshell/agility/Modules/Settings/BarSettings/BarSettings.qml b/quickshell/agility/Modules/Settings/BarSettings/BarSettings.qml index f1dcba3..d6259f2 100644 --- a/quickshell/agility/Modules/Settings/BarSettings/BarSettings.qml +++ b/quickshell/agility/Modules/Settings/BarSettings/BarSettings.qml @@ -47,6 +47,18 @@ AppContainer { } } + Divider { + } + + SettingToggle { + label: "Open on Hover" + description: "Automatically open menus and popups when hovering over bar widgets without needing to click" + checked: SettingsService.barOpenOnHover + onCheckedChanged: { + SettingsService.barOpenOnHover = checked; + } + } + } // ISLAND MODE WIDGETS diff --git a/quickshell/agility/Modules/WallpaperSelector/WallpaperSelectorContent.qml b/quickshell/agility/Modules/WallpaperSelector/WallpaperSelectorContent.qml index 0cc1243..4371ebd 100644 --- a/quickshell/agility/Modules/WallpaperSelector/WallpaperSelectorContent.qml +++ b/quickshell/agility/Modules/WallpaperSelector/WallpaperSelectorContent.qml @@ -187,9 +187,18 @@ Item { property var lines: [] - command: ["agl", "wallpaper", "list"] + command: ["sh", "-c", "agl wallpaper list 2>/dev/null; find ~/.local/share/agility-shell/wallpapers ~/.config/agility-shell/wallpapers ~/Pictures/Wallpapers -maxdepth 1 -type f \\( -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.png' -o -iname '*.webp' -o -iname '*.gif' \\) 2>/dev/null"] onExited: function(exitCode) { - let sortedLines = lines.sort(function(a, b) { + let seen = {}; + let uniqueLines = []; + for (let i = 0; i < lines.length; i++) { + let item = lines[i]; + if (!seen[item.rawPath]) { + seen[item.rawPath] = true; + uniqueLines.push(item); + } + } + let sortedLines = uniqueLines.sort(function(a, b) { return a.name.localeCompare(b.name); }); let changed = (sortedLines.length !== wallModel.count); @@ -203,8 +212,8 @@ Item { } if (changed || wallModel.count === 0) { wallModel.clear(); - for (let i = 0; i < sortedLines.length; i++) { - wallModel.append(sortedLines[i]); + for (let j = 0; j < sortedLines.length; j++) { + wallModel.append(sortedLines[j]); } filterWallpapers(searchField.text); } diff --git a/systemd/agility-shell.service b/systemd/agility-shell.service index 9d175d3..f11dcf1 100644 --- a/systemd/agility-shell.service +++ b/systemd/agility-shell.service @@ -11,7 +11,7 @@ Restart=on-failure RestartSec=1s Slice=session.slice TimeoutStopSec=3s -KillMode=mixed +KillMode=process [Install] WantedBy=graphical-session.target