diff --git a/plugins/opener/src/lib.rs b/plugins/opener/src/lib.rs index 1a8b6f0cb3..a35b94103e 100644 --- a/plugins/opener/src/lib.rs +++ b/plugins/opener/src/lib.rs @@ -58,7 +58,7 @@ impl Opener { /// - **Android / iOS**: Always opens using default program, unless `with` is provided as "inAppBrowser". #[cfg(desktop)] pub fn open_url(&self, url: impl Into, with: Option>) -> Result<()> { - crate::open::open( + crate::open::open_path( url.into(), with.map(Into::into).filter(|with| with != "inAppBrowser"), ) @@ -116,7 +116,7 @@ impl Opener { path: impl Into, with: Option>, ) -> Result<()> { - crate::open::open( + crate::open::open_path( path.into(), with.map(Into::into).filter(|with| with != "inAppBrowser"), ) diff --git a/plugins/opener/src/open.rs b/plugins/opener/src/open.rs index a3d46c508d..0b20414c4c 100644 --- a/plugins/opener/src/open.rs +++ b/plugins/opener/src/open.rs @@ -55,7 +55,97 @@ pub fn open_path, S: AsRef>(path: P, with: Option) -> cra let path = path.as_ref(); if with.is_none() { // Returns an IO error if not exists, and besides `exists()` is a shorthand for `metadata()` - _ = path.metadata()?; + let metadata = path.metadata()?; + + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + if metadata.is_dir() { + if let Ok(()) = open_dir_dbus(path) { + return Ok(()); + } + } } open(path, with) } + +/// Opens a dir with the default file manager via D-Bus. +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +fn open_dir_dbus(path: &Path) -> crate::Result<()> { + let connection = zbus::blocking::Connection::session()?; + + open_with_filemanager1(path, &connection) + .or_else(|e| open_with_open_uri_portal(path, &connection).map_err(|_| e)) +} + +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +fn open_with_filemanager1( + path: &Path, + connection: &zbus::blocking::Connection, +) -> crate::Result<()> { + let uri = + url::Url::from_file_path(path).map_err(|_| crate::Error::FailedToConvertPathToFileUrl)?; + + #[zbus::proxy( + interface = "org.freedesktop.FileManager1", + default_service = "org.freedesktop.FileManager1", + default_path = "/org/freedesktop/FileManager1" + )] + trait FileManager1 { + async fn ShowFolders(&self, uris: Vec<&str>, startup_id: &str) -> crate::Result<()>; + } + + let proxy = FileManager1ProxyBlocking::new(connection)?; + + proxy.ShowFolders(vec![uri.as_str()], "") +} + +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +fn open_with_open_uri_portal( + path: &Path, + connection: &zbus::blocking::Connection, +) -> crate::Result<()> { + use std::collections::HashMap; + let uri = + url::Url::from_file_path(path).map_err(|_| crate::Error::FailedToConvertPathToFileUrl)?; + + #[zbus::proxy( + interface = "org.freedesktop.portal.Desktop", + default_service = "org.freedesktop.portal.OpenURI", + default_path = "/org/freedesktop/portal/desktop" + )] + trait PortalDesktop { + async fn OpenDirectory( + &self, + parent_window: &str, + uri: &str, + options: HashMap<&str, &str>, + ) -> crate::Result<()>; + } + + let proxy = PortalDesktopProxyBlocking::new(connection)?; + + proxy.OpenDirectory("", uri.as_str(), HashMap::new()) +}