diff options
| author | srdusr <[email protected]> | 2025-08-17 01:54:00 +0200 |
|---|---|---|
| committer | srdusr <[email protected]> | 2025-08-17 01:54:00 +0200 |
| commit | b8376bd631a72f7484c24663699a7d4c813f600e (patch) | |
| tree | c8c84725e3c66598df3f619dd96aa69b6eede26e /crates/wayland/src/desktop_icons.rs | |
| parent | bd6aadf4d166c05f22f1ab6cdfe2e815e071f162 (diff) | |
| download | srdwm-b8376bd631a72f7484c24663699a7d4c813f600e.tar.gz srdwm-b8376bd631a72f7484c24663699a7d4c813f600e.zip | |
Fix desktop icons v1 regressions: bar overlap, wrong order; add proper menus
Live testing found v1 genuinely broken, not just rough:
1. Icons weren't rendering reliably at all - ensure_desktop_icons only
ever computed the grid's origin once, on whichever render pass
happened to be first. AGS's own top bar registers its exclusive zone
after that first pass, so origin got permanently baked in at the
pre-bar geometry. Confirmed live via a temporary diagnostic log.
Fixed by re-deriving origin from the primary monitor's current
geometry on every call instead of just the first.
2. Fixed icons (Home/Computer/Trash) always sorted before real files --
confirmed wrong via direct question. The whole list now sorts
alphabetically by label, case-insensitive, fixed icons included.
3. "Set as Wallpaper" was the wrong feature: removed entirely
(DesktopMenuAction::SetWallpaper, general.wallpaper_command,
is_image_path). The user wants that handled by their real file
manager once opened, not reimplemented here.
Also adds real menu functionality per "where are all the options":
Rename (inline text edit, new CompState::renaming_icon field and
keyboard redirect mirroring NativeLock::password's existing precedent),
Delete (moves to ~/.local/share/Trash per the freedesktop.org spec, new
trash.rs module, same-filesystem case, no confirmation - this is the
reversible move-to-trash, not a permanent delete), Empty Trash on the
Trash icon, and Open Terminal Here / Open in File Manager on the
bare-desktop menu (new general.terminal config key).
133 wayland-crate tests (up from 106), full workspace build and clippy
clean.
Diffstat (limited to 'crates/wayland/src/desktop_icons.rs')
| -rw-r--r-- | crates/wayland/src/desktop_icons.rs | 52 |
1 files changed, 33 insertions, 19 deletions
diff --git a/crates/wayland/src/desktop_icons.rs b/crates/wayland/src/desktop_icons.rs index 470a965..4ba54f4 100644 --- a/crates/wayland/src/desktop_icons.rs +++ b/crates/wayland/src/desktop_icons.rs @@ -85,17 +85,6 @@ fn desktop_dir(home: &Path) -> PathBuf { home.join("Desktop") } -/// `$XDG_DATA_HOME/Trash/files`, else `~/.local/share/Trash/files` - the -/// freedesktop.org Trash spec's home-filesystem trash directory. Only the -/// same-filesystem case is handled anywhere in this codebase (see this -/// feature's own plan doc for why the per-mountpoint `.Trash-$uid` -/// fallback is out of scope for now); this is purely where the Trash -/// desktop icon opens to, nothing currently moves a file into it. -fn trash_files_dir(home: &Path) -> PathBuf { - let data_home = std::env::var("XDG_DATA_HOME").map(PathBuf::from).unwrap_or_else(|_| home.join(".local/share")); - data_home.join("Trash/files") -} - /// Rebuilds the full icon list from the real filesystem: the three fixed /// icons first, then one per direct, non-hidden entry of `~/Desktop` /// (creating that directory if it doesn't exist yet, matching how a real @@ -132,7 +121,7 @@ pub(crate) fn rescan(saved: &HashMap<String, (i32, i32)>, rows_per_column: i32) id: "trash".to_string(), label: "Trash".to_string(), kind: IconKind::Trash, - target: home_dir().map(|h| trash_files_dir(&h)).unwrap_or_else(|| PathBuf::from("/")), + target: home_dir().map(|h| crate::trash::files_dir(&h)).unwrap_or_else(|| PathBuf::from("/")), cell: (0, 0), selected: false, }, @@ -141,7 +130,7 @@ pub(crate) fn rescan(saved: &HashMap<String, (i32, i32)>, rows_per_column: i32) let desktop = desktop_dir(&home); if std::fs::create_dir_all(&desktop).is_ok() { if let Ok(entries) = std::fs::read_dir(&desktop) { - let mut files: Vec<(String, bool)> = entries + let files: Vec<(String, bool)> = entries .filter_map(|e| e.ok()) .filter_map(|e| { let name = e.file_name().to_string_lossy().into_owned(); @@ -152,7 +141,6 @@ pub(crate) fn rescan(saved: &HashMap<String, (i32, i32)>, rows_per_column: i32) Some((name, is_dir)) }) .collect(); - files.sort_by(|a, b| a.0.cmp(&b.0)); for (name, is_dir) in files { let target = desktop.join(&name); icons.push(DesktopIcon { @@ -167,6 +155,14 @@ pub(crate) fn rescan(saved: &HashMap<String, (i32, i32)>, rows_per_column: i32) } } } + // One alphabetical list, fixed icons included - not fixed-three-then- + // files. Confirmed directly: the fixed shortcuts shouldn't always come + // first just because they're synthetic rather than real files. + // Case-insensitive so "computer"/"Computer" and a real lowercase + // filename interleave the way a user actually expects, not by raw + // byte value (which would put every uppercase name before any + // lowercase one). + icons.sort_by_key(|a| a.label.to_lowercase()); assign_cells(&mut icons, saved, rows_per_column); icons } @@ -212,12 +208,30 @@ mod tests { use super::*; #[test] - fn fixed_icons_always_come_first_in_a_stable_order() { + fn the_three_fixed_icons_sort_alphabetically_among_themselves() { + // Reported live, confirmed via direct question: fixed icons must + // NOT always come before real files just because they're + // synthetic - the whole list sorts by label together. This + // checks that sort using only the three fixed icons (present on + // any machine, unlike a specific `~/Desktop` file), whose labels + // - "Computer", "Home", "Trash" - already happen to be in + // alphabetical order, so a correct sort leaves them exactly + // where `rescan` built them. let icons = rescan(&HashMap::new(), 10); - assert!(icons.len() >= 3, "at least the three fixed icons"); - assert_eq!(icons[0].id, "home"); - assert_eq!(icons[1].id, "computer"); - assert_eq!(icons[2].id, "trash"); + let fixed: Vec<&str> = icons.iter().filter(|i| matches!(i.kind, IconKind::Home | IconKind::Computer | IconKind::Trash)).map(|i| i.label.as_str()).collect(); + assert_eq!(fixed, vec!["Computer", "Home", "Trash"]); + } + + #[test] + fn sorting_is_case_insensitive_and_covers_the_whole_list() { + let mut icons = [ + DesktopIcon { id: "zebra".into(), label: "zebra".into(), kind: IconKind::File, target: PathBuf::new(), cell: (0, 0), selected: false }, + DesktopIcon { id: "Home".into(), label: "Home".into(), kind: IconKind::Home, target: PathBuf::new(), cell: (0, 0), selected: false }, + DesktopIcon { id: "apple".into(), label: "apple".into(), kind: IconKind::File, target: PathBuf::new(), cell: (0, 0), selected: false }, + ]; + icons.sort_by_key(|a| a.label.to_lowercase()); + let labels: Vec<&str> = icons.iter().map(|i| i.label.as_str()).collect(); + assert_eq!(labels, vec!["apple", "Home", "zebra"], "a fixed icon's label interleaves with real filenames, not always first"); } #[test] |