git.lucas.co / cce-files
file manager
git clone https://git.lucas.co/cce-files.git

commit2260501645882758801018f2201fd0a204d7bf46
parent2516e35ca0
authorLucas Galante <[email protected]>
date2026-08-16 11:51
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