From 26e223c4f0fa084c9e810fed3c146a105ee19f9f Mon Sep 17 00:00:00 2001 From: Frederic Laing Date: Mon, 17 Nov 2025 08:58:28 +0100 Subject: [PATCH 1/3] fix metadata, thumbnails and gallery view for locally mounted drives --- src/app.rs | 6 +++++- src/mounter/gvfs.rs | 21 ++++++++++++++++++++- src/mounter/mod.rs | 8 ++++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/app.rs b/src/app.rs index d6f673b..8074c34 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1543,7 +1543,11 @@ impl App { b = b.text(item.name()).data(MounterData(key, item.clone())); let uri = item.uri(); if let Some(path) = item.path() { - b = b.data(Location::Network(uri, item.name(), Some(path))); + if item.is_remote() { + b = b.data(Location::Network(uri, item.name(), Some(path))); + } else { + b = b.data(Location::Path(path)); + } } else if !uri.is_empty() { b = b.data(Location::Network(uri, item.name(), None)); } diff --git a/src/mounter/gvfs.rs b/src/mounter/gvfs.rs index 4d2a44d..25f299f 100644 --- a/src/mounter/gvfs.rs +++ b/src/mounter/gvfs.rs @@ -33,15 +33,28 @@ fn items(monitor: &gio::VolumeMonitor, sizes: IconSizes) -> MounterItems { let mut items: MounterItems = (monitor.mounts().into_iter()) .enumerate() .map(|(i, mount)| { + let root = MountExt::root(&mount); + let is_remote = root + .query_filesystem_info( + gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE, + gio::Cancellable::NONE, + ) + .ok() + .and_then(|info| { + Some(info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE)) + }) + .unwrap_or(true); // Default to remote if query fails + MounterItem::Gvfs(Item { uri: mount.root().uri().into(), kind: ItemKind::Mount, index: i, name: mount.name().into(), is_mounted: true, + is_remote, icon_opt: gio_icon_to_path(&MountExt::icon(&mount), sizes.grid()), icon_symbolic_opt: gio_icon_to_path(&MountExt::symbolic_icon(&mount), 16), - path_opt: MountExt::root(&mount).path(), + path_opt: root.path(), }) }) .collect(); @@ -61,6 +74,7 @@ fn items(monitor: &gio::VolumeMonitor, sizes: IconSizes) -> MounterItems { index: i, name: volume.name().into(), is_mounted: false, + is_remote: false, icon_opt: gio_icon_to_path(&VolumeExt::icon(&volume), sizes.grid()), icon_symbolic_opt: gio_icon_to_path(&VolumeExt::symbolic_icon(&volume), 16), path_opt: None, @@ -266,6 +280,7 @@ pub struct Item { index: usize, name: String, is_mounted: bool, + is_remote: bool, icon_opt: Option, icon_symbolic_opt: Option, path_opt: Option, @@ -280,6 +295,10 @@ impl Item { self.is_mounted } + pub const fn is_remote(&self) -> bool { + self.is_remote + } + pub fn uri(&self) -> String { self.uri.clone() } diff --git a/src/mounter/mod.rs b/src/mounter/mod.rs index caaba72..098b2b3 100644 --- a/src/mounter/mod.rs +++ b/src/mounter/mod.rs @@ -90,6 +90,14 @@ impl MounterItem { Self::None => unreachable!(), } } + + pub fn is_remote(&self) -> bool { + match self { + #[cfg(feature = "gvfs")] + Self::Gvfs(item) => item.is_remote(), + Self::None => unreachable!(), + } + } } pub type MounterItems = Vec; From 0fc65966818131ea7fc3b4fe1a027c86aaff0ace Mon Sep 17 00:00:00 2001 From: Frederic Laing Date: Mon, 17 Nov 2025 09:06:02 +0100 Subject: [PATCH 2/3] directly navigate to the mounted drive after mounting them with a click on the sidebar --- src/app.rs | 10 ++++++++++ src/mounter/gvfs.rs | 25 ++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/app.rs b/src/app.rs index 8074c34..32ba25a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3092,6 +3092,16 @@ impl Application for App { Message::MountResult(mounter_key, item, res) => match res { Ok(true) => { log::info!("connected to {item:?}"); + // Automatically navigate to the mounted location + if let Some(path) = item.path() { + let location = if item.is_remote() { + Location::Network(item.uri(), item.name(), Some(path)) + } else { + Location::Path(path) + }; + let message = Message::TabMessage(None, tab::Message::Location(location)); + return self.update(message); + } } Ok(false) => { log::info!("cancelled connection to {item:?}"); diff --git a/src/mounter/gvfs.rs b/src/mounter/gvfs.rs index 25f299f..9c720c0 100644 --- a/src/mounter/gvfs.rs +++ b/src/mounter/gvfs.rs @@ -408,6 +408,7 @@ impl Gvfs { let mount_op = mount_op(name.to_string(), event_tx.clone()); let event_tx = event_tx.clone(); let mounter_item = mounter_item.clone(); + let volume_for_callback = volume.clone(); VolumeExt::mount( &volume, gio::MountMountFlags::NONE, @@ -415,7 +416,29 @@ impl Gvfs { gio::Cancellable::NONE, move |res| { log::info!("mount {name}: result {res:?}"); - event_tx.send(Event::MountResult(mounter_item, match res { + // Update the mounter_item with mount information after successful mount + let mut updated_item = mounter_item.clone(); + if res.is_ok() { + if let MounterItem::Gvfs(ref mut item) = updated_item { + if let Some(mount) = volume_for_callback.get_mount() { + let root = MountExt::root(&mount); + item.path_opt = root.path(); + item.is_mounted = true; + // Query if remote + item.is_remote = root + .query_filesystem_info( + gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE, + gio::Cancellable::NONE, + ) + .ok() + .and_then(|info| { + Some(info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE)) + }) + .unwrap_or(true); + } + } + } + event_tx.send(Event::MountResult(updated_item, match res { Ok(()) => { _ = complete_tx.send(Ok(())); Ok(true) From c8f25472a7b49b1539c29e761129e120757d8599 Mon Sep 17 00:00:00 2001 From: Frederic Laing Date: Mon, 17 Nov 2025 09:27:26 +0100 Subject: [PATCH 3/3] extend remote location filesystem detection filter --- src/mounter/gvfs.rs | 4 +--- src/tab.rs | 31 +++++++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/src/mounter/gvfs.rs b/src/mounter/gvfs.rs index 9c720c0..be49048 100644 --- a/src/mounter/gvfs.rs +++ b/src/mounter/gvfs.rs @@ -40,9 +40,7 @@ fn items(monitor: &gio::VolumeMonitor, sizes: IconSizes) -> MounterItems { gio::Cancellable::NONE, ) .ok() - .and_then(|info| { - Some(info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE)) - }) + .and_then(|info| Some(info.boolean(gio::FILE_ATTRIBUTE_FILESYSTEM_REMOTE))) .unwrap_or(true); // Default to remote if query fails MounterItem::Gvfs(Item { diff --git a/src/tab.rs b/src/tab.rs index 98f7738..7ae864c 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -540,11 +540,34 @@ pub fn fs_kind(metadata: &Metadata) -> FsKind { let major = major_str.parse::().ok()?; let minor = minor_str.parse::().ok()?; let dev = libc::makedev(major, minor); - //TODO: make sure this list is exhaustive + // Network and distributed filesystem types + // Based on common remote filesystem types found in /proc/mounts let kind = match mount_info.fs_type.as_str() { - "cifs" | "fuse.rclone" | "fuse.sshfs" | "nfs" | "nfs4" | "smb" - | "smb2" => FsKind::Remote, + // SMB/CIFS variants + "cifs" | "smb" | "smb2" | "smbfs" => FsKind::Remote, + + // NFS variants + "nfs" | "nfs4" => FsKind::Remote, + + // FUSE-based remote filesystems + "fuse.rclone" | "fuse.sshfs" | "fuse.davfs2" | "fuse.ceph" + | "fuse.glusterfs" | "fuse.s3fs" | "fuse.goofys" | "fuse.gcsfuse" + | "fuse.afp" | "fuse.afpfs" => FsKind::Remote, + + // Other network protocols + "afs" | "coda" | "ncpfs" | "davfs" | "davfs2" | "shfs" => { + FsKind::Remote + } + + // Cluster/distributed filesystems + "ceph" | "glusterfs" | "lustre" | "gfs" | "gfs2" | "ocfs2" => { + FsKind::Remote + } + + // GVFS (GNOME Virtual File System) "fuse.gvfsd-fuse" => FsKind::Gvfs, + + // Everything else is local _ => FsKind::Local, }; Some((dev, kind)) @@ -622,7 +645,7 @@ fn display_name_for_file(path: &Path, name: &str, get_from_gvfs: bool, is_deskto ); } else if get_from_gvfs { #[cfg(feature = "gvfs")] - return Item::display_name(glib::filename_display_name(path).as_str()) + return Item::display_name(glib::filename_display_name(path).as_str()); } Item::display_name(name) }