file manager
git clone https://git.lucas.co/cce-files.git
feat: claim inode/directory, and open a directory given on argv
The desktop entry declared no MimeType, so cce-files was never offered as the File Manager default — the settings app builds that dropdown from entries claiming the category's types. It now claims inode/directory and takes %f.
Declaring the type obliges the app to honor it, and it did not: new() parsed only --select/--save/--select-dir and ignored a positional path entirely, so opening a folder would have launched at the remembered directory instead of the one clicked — a default that looks wired up and quietly does the wrong thing. A positional path is now read (flags skipped, so --select /tmp works too) and issues the initial ReadDirectory directly; that lands in the same DirectoryLoaded handler the last-dir restore reaches, so current_dir and the breadcrumb settle identically. An unresolvable path falls back to the remembered directory, and a file opens its containing directory.
Verified in a headless shadow session: cce-files /etc opens with /etc listed and breadcrumb set, rather than the saved directory.
Co-Authored-By: Claude <[email protected]>
cce-files.desktop | 6 ++++--
src/main.rs | 24 ++++++++++++++++++++++--
2 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/cce-files.desktop b/cce-files.desktop
index 5402d1a..c08f632 100644
--- a/cce-files.desktop
+++ b/cce-files.desktop
@@ -2,8 +2,10 @@
Type=Application
Name=Files
Comment=File browser
-Exec=cce-files
+Exec=cce-files %f
Icon=cce-files
-Categories=System;FileManager;
+Categories=System;FileTools;FileManager;
Terminal=false
+StartupNotify=true
StartupWMClass=cce-files
+MimeType=inode/directory;
diff --git a/src/main.rs b/src/main.rs
index 461ca91..039ce5d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1023,6 +1023,20 @@ impl Application for FilesystemApp {
let save_mode = args.iter().any(|arg| arg == "--save");
let select_mode = save_mode || args.iter().any(|arg| arg == "--select" || arg == "--select-dir");
+ // A positional path opens there instead of the remembered directory.
+ // This is what `Exec=cce-files %f` passes as the inode/directory
+ // handler; without it the desktop entry could claim the type but
+ // always land on the last-visited dir, ignoring the folder clicked.
+ // Flags are skipped rather than just args[1], so `--select /tmp`
+ // works. A path that does not resolve falls through to the last dir,
+ // and a file opens its containing directory.
+ let start_dir = args
+ .iter()
+ .skip(1)
+ .find(|a| !a.starts_with("--"))
+ .and_then(|a| std::fs::canonicalize(a).ok())
+ .and_then(|p| if p.is_dir() { Some(p) } else { p.parent().map(|q| q.to_path_buf()) });
+
cce_ui::scale::set_scale_factor(1.0);
let browse = pages::browse::BrowseState::default();
@@ -1088,8 +1102,14 @@ impl Application for FilesystemApp {
};
- // Start initial directory loading via FsService
- app.fs_service.send(services::fs::FsRequest::ReadLastDir);
+ // Start initial directory loading via FsService. ReadDirectory lands in
+ // the same DirectoryLoaded handler ReadLastDir eventually reaches, so an
+ // argv path just skips the restore step; current_dir and the breadcrumb
+ // are set when the load completes either way.
+ match start_dir {
+ Some(dir) => app.fs_service.send(services::fs::FsRequest::ReadDirectory(dir)),
+ None => app.fs_service.send(services::fs::FsRequest::ReadLastDir),
+ }
// NOTE: do not call rebuild_layout() here. This value is moved out of new()
// into the engine, which changes its address; the container/splitter widgets