use std::{
path::{Path, PathBuf},
process::Command,
};
use freedesktop_desktop_entry as fde;
use mime::Mime;
use url::Url;
use crate::{Result, exec::ExecParser};
#[derive(Clone, Debug)]
pub struct App {
pub appid: Box<str>,
pub name: Box<str>,
pub comment: Option<Box<str>>,
pub icon: Option<Box<str>>,
pub path: Box<Path>,
}
impl App {
pub fn open_url(&self, url: Url) -> Result<u32> {
log::info!(
"Opening URL '{}' with application '{}'",
url,
self.path.display()
);
let locales = fde::get_languages_from_env();
let de = fde::DesktopEntry::from_path(self.path.clone(), Some(&locales))?;
let (cmd, args) = ExecParser::new(&de, &locales).parse_with_uris(&[url.as_str()])?;
log::debug!("Executing command: '{}' with args: {:?}", cmd, args);
let program = Command::new(cmd).args(args).spawn()?;
Ok(program.id())
}
pub fn handlers_for_scheme(
scheme: &str,
locales: Option<Vec<String>>,
search_paths: Option<Vec<PathBuf>>,
) -> Result<Vec<Self>> {
let locales = locales.unwrap_or_else(fde::get_languages_from_env);
let search_paths = search_paths.unwrap_or_else(|| fde::default_paths().collect());
log::debug!(
"Searching for applications handling scheme '{}' in paths: {:?}",
scheme,
search_paths
);
let entries = fde::Iter::new(search_paths.into_iter()).entries(Some(&locales));
let scheme_handler_mime = format!("x-scheme-handler/{}", scheme)
.as_str()
.parse::<Mime>()?;
let apps = entries
.filter(|de| {
de.mime_type()
.is_some_and(|mime| mime.contains(&scheme_handler_mime.essence_str()))
})
.map(|entry| Self::from_desktop_entry(entry, &locales))
.collect::<Vec<_>>();
log::info!(
"Found {} applications with support for '{}'",
apps.len(),
scheme_handler_mime
);
Ok(apps)
}
pub fn from_desktop_entry<L: AsRef<str>>(de: fde::DesktopEntry, locales: &[L]) -> Self {
let appid: Box<str> = de.appid.clone().into();
let name = de
.name(locales)
.map(|name| name.into())
.unwrap_or_else(|| appid.clone());
Self {
appid,
name,
comment: de.comment(locales).map(|comment| comment.into()),
icon: de.icon().map(|icon| icon.into()),
path: de.path.into(),
}
}
}