From 02b6cda87277612dab136cd9a097bbaecab3633d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 22 Apr 2024 09:54:00 -0600 Subject: [PATCH] Add mounter abstraction, enable minimal GVfs support --- Cargo.lock | 124 +++++++++++++++++++++++++++++++++++++------- Cargo.toml | 4 +- debian/control | 1 + examples/gvfs.rs | 25 +++++++++ src/app.rs | 31 +++++++++++ src/lib.rs | 1 + src/mounter/gvfs.rs | 54 +++++++++++++++++++ src/mounter/mod.rs | 33 ++++++++++++ 8 files changed, 254 insertions(+), 19 deletions(-) create mode 100644 examples/gvfs.rs create mode 100644 src/mounter/gvfs.rs create mode 100644 src/mounter/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 81f9b1f..a2d95e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -510,8 +510,8 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "251e0b7d90e33e0ba930891a505a9a35ece37b2dd37a14f3ffc306c13b980009" dependencies = [ - "glib-sys", - "gobject-sys", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", "system-deps", ] @@ -1099,6 +1099,7 @@ dependencies = [ "fork", "freedesktop_entry_parser", "fs_extra", + "gio", "i18n-embed", "i18n-embed-fl", "image", @@ -2092,9 +2093,9 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", + "gio-sys 0.18.1", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", "system-deps", ] @@ -2107,9 +2108,9 @@ checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", + "gio-sys 0.18.1", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", "pango-sys", "pkg-config", @@ -2193,19 +2194,50 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "gio" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f91a0518c2ec539f099d3f945ab2d6a83ec372a9ef40a21906343b191182845" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys 0.19.0", + "glib", + "libc", + "pin-project-lite", + "smallvec", + "thiserror", +] + [[package]] name = "gio-sys" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" dependencies = [ - "glib-sys", - "gobject-sys", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", "system-deps", "winapi", ] +[[package]] +name = "gio-sys" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcf8e1d9219bb294636753d307b030c1e8a032062cba74f493c431a5c8b81ce4" +dependencies = [ + "glib-sys 0.19.0", + "gobject-sys 0.19.0", + "libc", + "system-deps", + "windows-sys 0.52.0", +] + [[package]] name = "gl_generator" version = "0.14.0" @@ -2223,6 +2255,41 @@ version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5418c17512bdf42730f9032c74e1ae39afc408745ebb2acf72fbc4691c17945" +[[package]] +name = "glib" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1407b2ce171e654720be10d57d4054d3ff2f10a13d5b37e6819b41439832f7" +dependencies = [ + "bitflags 2.5.0", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys 0.19.0", + "glib-macros", + "glib-sys 0.19.0", + "gobject-sys 0.19.0", + "libc", + "memchr", + "smallvec", + "thiserror", +] + +[[package]] +name = "glib-macros" +version = "0.19.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bba315e8ce8aa59631545358450f4962557e89b5f7db7442e7153b47037f71" +dependencies = [ + "heck 0.5.0", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.58", +] + [[package]] name = "glib-sys" version = "0.18.1" @@ -2233,6 +2300,16 @@ dependencies = [ "system-deps", ] +[[package]] +name = "glib-sys" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630f097773d7c7a0bb3258df4e8157b47dc98bbfa0e60ad9ab56174813feced4" +dependencies = [ + "libc", + "system-deps", +] + [[package]] name = "glob" version = "0.3.1" @@ -2277,7 +2354,18 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" dependencies = [ - "glib-sys", + "glib-sys 0.18.1", + "libc", + "system-deps", +] + +[[package]] +name = "gobject-sys" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e2b1080b9418dd0c58b498da3a5c826030343e0ef07bde6a955d28de54979" +dependencies = [ + "glib-sys 0.19.0", "libc", "system-deps", ] @@ -2350,9 +2438,9 @@ dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", + "gio-sys 0.18.1", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", "pango-sys", "system-deps", @@ -3789,8 +3877,8 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" dependencies = [ - "glib-sys", - "gobject-sys", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "libc", "system-deps", ] @@ -4286,8 +4374,8 @@ dependencies = [ "ashpd 0.6.8", "block", "dispatch", - "glib-sys", - "gobject-sys", + "glib-sys 0.18.1", + "gobject-sys 0.18.0", "gtk-sys", "js-sys", "log", diff --git a/Cargo.toml b/Cargo.toml index 9203426..1a81774 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ dirs = "5.0.1" env_logger = "0.11" freedesktop_entry_parser = { version = "1.3", optional = true } fs_extra = "1.3" +gio = { version = "0.19", optional = true } image = "0.24" once_cell = "1.19" open = "5.0.2" @@ -49,8 +50,9 @@ version = "0.2.1" features = ["serde"] [features] -default = ["desktop", "wgpu"] +default = ["desktop", "gvfs", "wgpu"] desktop = ["libcosmic/desktop", "dep:freedesktop_entry_parser", "dep:xdg"] +gvfs = ["dep:gio"] wgpu = ["libcosmic/wgpu"] [profile.dev] diff --git a/debian/control b/debian/control index e2328d9..eb35d32 100644 --- a/debian/control +++ b/debian/control @@ -6,6 +6,7 @@ Build-Depends: debhelper-compat (=13), git, just (>= 1.13.0), + libglib2.0-dev, pkg-config, rust-all, Standards-Version: 4.6.2 diff --git a/examples/gvfs.rs b/examples/gvfs.rs new file mode 100644 index 0000000..5ba3f4c --- /dev/null +++ b/examples/gvfs.rs @@ -0,0 +1,25 @@ +use gio::prelude::*; + +fn main() { + let monitor = gio::VolumeMonitor::get(); + for drive in monitor.connected_drives() { + println!("Drive: {}", drive.name()); + for volume in drive.volumes() { + println!(" Volume: {}", volume.name()); + if let Some(mount) = volume.get_mount() { + println!(" Mount: {}", mount.name()); + } + } + } + + for mount in monitor.mounts() { + println!("Mount: {}", mount.name()); + } + + for volume in monitor.volumes() { + println!("Volume: {}", volume.name()); + if let Some(mount) = volume.get_mount() { + println!(" Mount: {}", mount.name()); + } + } +} diff --git a/src/app.rs b/src/app.rs index 33f27f9..4f99010 100644 --- a/src/app.rs +++ b/src/app.rs @@ -48,6 +48,7 @@ use crate::{ fl, home_dir, key_bind::key_binds, menu, mime_app, + mounter::{mounters, Mounters}, operation::Operation, spawn_detached::spawn_detached, tab::{self, HeadingOptions, ItemMetadata, Location, Tab}, @@ -268,6 +269,7 @@ pub struct App { dialog_text_input: widget::Id, key_binds: HashMap, modifiers: Modifiers, + mounters: Mounters, pending_operation_id: u64, pending_operations: BTreeMap, complete_operations: BTreeMap, @@ -727,6 +729,34 @@ impl Application for App { .data(Location::Trash) }); + //TODO: dynamic mount list + let mounters = mounters(); + for (mounter_name, mounter) in mounters.iter() { + println!("Mounter {}", mounter_name); + match mounter.items() { + Ok(items) => { + for item in items { + let name = item.name(); + println!(" - {}", name); + let icon = item.icon(16); + let dir_opt = item.path(); + nav_model = nav_model.insert(move |mut b| { + b = b + .text(name.clone()) + .icon(widget::icon::icon(icon.clone()).size(16)); + match &dir_opt { + Some(dir) => b.data(Location::Path(dir.clone())), + None => b, + } + }); + } + } + Err(err) => { + log::warn!("failed to get items: {}", err); + } + } + } + let mut app = App { core, nav_model: nav_model.build(), @@ -741,6 +771,7 @@ impl Application for App { dialog_text_input: widget::Id::unique(), key_binds: key_binds(), modifiers: Modifiers::empty(), + mounters, pending_operation_id: 0, pending_operations: BTreeMap::new(), complete_operations: BTreeMap::new(), diff --git a/src/lib.rs b/src/lib.rs index 9b612de..f180df0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ mod localize; mod menu; mod mime_app; pub mod mime_icon; +mod mounter; mod mouse_area; mod operation; mod spawn_detached; diff --git a/src/mounter/gvfs.rs b/src/mounter/gvfs.rs new file mode 100644 index 0000000..423eb7d --- /dev/null +++ b/src/mounter/gvfs.rs @@ -0,0 +1,54 @@ +use cosmic::widget; +use gio::prelude::*; +use gio::{Mount, ThemedIcon, Volume, VolumeMonitor}; +use std::{error::Error, path::PathBuf}; + +use super::{Mounter, MounterItem, MounterItems}; + +pub struct Gvfs { + monitor: VolumeMonitor, +} + +impl Gvfs { + pub fn new() -> Self { + let monitor = VolumeMonitor::get(); + Self { monitor } + } +} + +impl Mounter for Gvfs { + fn items(&self) -> Result> { + let mut items = MounterItems::new(); + for mount in self.monitor.mounts() { + items.push(Box::new(mount)); + } + Ok(items) + } +} + +impl MounterItem for Mount { + fn name(&self) -> String { + MountExt::name(self).to_string() + } + + fn icon(&self, size: u16) -> widget::icon::Handle { + let icon = MountExt::symbolic_icon(self); + if let Some(themed_icon) = icon.downcast_ref::() { + for name in themed_icon.names() { + let named = widget::icon::from_name(name.as_str()).size(size); + if let Some(path) = named.path() { + return widget::icon::from_path(path); + } + } + } + + //TODO: handle more gio icon types + widget::icon::from_name("folder-symbolic") + .size(size) + .handle() + } + + fn path(&self) -> Option { + MountExt::root(self).path() + } +} diff --git a/src/mounter/mod.rs b/src/mounter/mod.rs new file mode 100644 index 0000000..3029783 --- /dev/null +++ b/src/mounter/mod.rs @@ -0,0 +1,33 @@ +use cosmic::widget; +use std::error::Error; +use std::{collections::BTreeMap, path::PathBuf, sync::Arc}; + +#[cfg(feature = "gvfs")] +mod gvfs; + +pub trait MounterItem { + fn name(&self) -> String; + fn icon(&self, size: u16) -> widget::icon::Handle; + fn path(&self) -> Option; +} + +pub type MounterItems = Vec>; + +pub trait Mounter { + fn items(&self) -> Result>; +} + +pub type MounterKey = &'static str; +pub type MounterMap = BTreeMap>; +pub type Mounters = Arc; + +pub fn mounters() -> Mounters { + let mut mounters = MounterMap::new(); + + #[cfg(feature = "gvfs")] + { + mounters.insert("gvfs", Box::new(gvfs::Gvfs::new())); + } + + Mounters::new(mounters) +}