use crate::OpenError;
use std::collections::HashMap;
use std::fs::File;
use std::os::fd::AsFd;
use std::path::Path;
use std::{error, fmt, io};
use url::Url;
use zbus::blocking::Connection;
pub(crate) fn reveal_with_dbus(path: &Path) -> Result<(), OpenError> {
let connection = Connection::session().map_err(dbus_to_open_error)?;
reveal_with_filemanager1(path, &connection)
.or_else(|_| reveal_with_open_uri_portal(path, &connection))
}
fn reveal_with_filemanager1(path: &Path, connection: &Connection) -> Result<(), OpenError> {
let uri = path_to_uri(path)?;
let proxy = FileManager1Proxy::new(connection).map_err(dbus_to_open_error)?;
proxy.show_items(&[uri], "").map_err(dbus_to_open_error)
}
fn reveal_with_open_uri_portal(path: &Path, connection: &Connection) -> Result<(), OpenError> {
let file = File::open(path).map_err(OpenError::Io)?;
let proxy = OpenURIProxy::new(connection).map_err(dbus_to_open_error)?;
proxy
.open_directory("", file.as_fd().into(), HashMap::new())
.map_err(dbus_to_open_error)
.map(|_| ())
}
fn path_to_uri(path: &Path) -> Result<Url, OpenError> {
let path = path.canonicalize().map_err(OpenError::Io)?;
Url::from_file_path(path).map_err(|_| uri_to_open_error())
}
fn uri_to_open_error() -> OpenError {
OpenError::Io(io::Error::new(
io::ErrorKind::InvalidInput,
FilePathToUriError,
))
}
fn dbus_to_open_error(error: zbus::Error) -> OpenError {
OpenError::Io(io::Error::other(error))
}
#[derive(Debug)]
struct FilePathToUriError;
impl fmt::Display for FilePathToUriError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "The given file path could not be converted to a URI")
}
}
impl error::Error for FilePathToUriError {}
#[zbus::proxy(
gen_async = false,
interface = "org.freedesktop.FileManager1",
default_service = "org.freedesktop.FileManager1",
default_path = "/org/freedesktop/FileManager1"
)]
trait FileManager1 {
fn show_items(&self, uris: &[Url], startup_id: &str) -> zbus::Result<()>;
}
#[zbus::proxy(
gen_async = false,
interface = "org.freedesktop.portal.OpenURI",
default_service = "org.freedesktop.portal.Desktop",
default_path = "/org/freedesktop/portal/desktop"
)]
pub trait OpenURI {
fn open_directory(
&self,
parent_window: &str,
fd: zbus::zvariant::Fd<'_>,
options: HashMap<&str, &zbus::zvariant::Value<'_>>,
) -> zbus::Result<zbus::zvariant::OwnedObjectPath>;
}