Clean up mime app handling and make it possible to set default application, part of #325
This commit is contained in:
parent
691719ade7
commit
ceab7835ad
37 changed files with 306 additions and 114 deletions
104
src/mime_app.rs
104
src/mime_app.rs
|
|
@ -5,9 +5,8 @@
|
|||
use cosmic::desktop;
|
||||
use cosmic::widget;
|
||||
pub use mime_guess::Mime;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::{
|
||||
cmp::Ordering, collections::HashMap, env, ffi::OsString, path::PathBuf, process, sync::Mutex,
|
||||
cmp::Ordering, collections::HashMap, env, ffi::OsString, fs, io, path::PathBuf, process,
|
||||
time::Instant,
|
||||
};
|
||||
|
||||
|
|
@ -52,6 +51,13 @@ impl MimeApp {
|
|||
}
|
||||
}
|
||||
|
||||
// This allows usage of MimeApp in a dropdown
|
||||
impl AsRef<str> for MimeApp {
|
||||
fn as_ref(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "desktop")]
|
||||
impl From<&desktop::DesktopEntryData> for MimeApp {
|
||||
fn from(app: &desktop::DesktopEntryData) -> Self {
|
||||
|
|
@ -82,6 +88,7 @@ fn filename_eq(path_opt: &Option<PathBuf>, filename: &str) -> bool {
|
|||
|
||||
pub struct MimeAppCache {
|
||||
cache: HashMap<Mime, Vec<MimeApp>>,
|
||||
icons: HashMap<Mime, Vec<widget::icon::Handle>>,
|
||||
terminals: Vec<MimeApp>,
|
||||
}
|
||||
|
||||
|
|
@ -89,6 +96,7 @@ impl MimeAppCache {
|
|||
pub fn new() -> Self {
|
||||
let mut mime_app_cache = Self {
|
||||
cache: HashMap::new(),
|
||||
icons: HashMap::new(),
|
||||
terminals: Vec::new(),
|
||||
};
|
||||
mime_app_cache.reload();
|
||||
|
|
@ -106,6 +114,7 @@ impl MimeAppCache {
|
|||
let start = Instant::now();
|
||||
|
||||
self.cache.clear();
|
||||
self.icons.clear();
|
||||
self.terminals.clear();
|
||||
|
||||
//TODO: get proper locale?
|
||||
|
|
@ -254,37 +263,88 @@ impl MimeAppCache {
|
|||
});
|
||||
}
|
||||
|
||||
// Copy icons to special cache
|
||||
//TODO: adjust dropdown API so this is no longer needed
|
||||
for (mime, apps) in self.cache.iter() {
|
||||
self.icons.insert(
|
||||
mime.clone(),
|
||||
apps.iter().map(|app| app.icon.clone()).collect(),
|
||||
);
|
||||
}
|
||||
|
||||
let elapsed = start.elapsed();
|
||||
log::info!("loaded mime app cache in {:?}", elapsed);
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &Mime) -> Vec<MimeApp> {
|
||||
self.cache.get(key).map_or_else(Vec::new, |x| x.clone())
|
||||
pub fn get(&self, key: &Mime) -> &[MimeApp] {
|
||||
static EMPTY: Vec<MimeApp> = Vec::new();
|
||||
self.cache.get(key).unwrap_or_else(|| &EMPTY)
|
||||
}
|
||||
}
|
||||
|
||||
static MIME_APP_CACHE: Lazy<Mutex<MimeAppCache>> = Lazy::new(|| Mutex::new(MimeAppCache::new()));
|
||||
pub fn icons(&self, key: &Mime) -> &[widget::icon::Handle] {
|
||||
static EMPTY: Vec<widget::icon::Handle> = Vec::new();
|
||||
self.icons.get(key).unwrap_or_else(|| &EMPTY)
|
||||
}
|
||||
|
||||
pub fn mime_apps(mime: &Mime) -> Vec<MimeApp> {
|
||||
let mime_app_cache = MIME_APP_CACHE.lock().unwrap();
|
||||
mime_app_cache.get(mime)
|
||||
}
|
||||
pub fn terminal(&self) -> Option<&MimeApp> {
|
||||
//TODO: consider rules in https://github.com/Vladimir-csp/xdg-terminal-exec
|
||||
|
||||
pub fn terminal() -> Option<MimeApp> {
|
||||
let mime_app_cache = MIME_APP_CACHE.lock().unwrap();
|
||||
// Look for and return preferred terminals
|
||||
//TODO: fallback order beyond cosmic-term?
|
||||
for id in &["com.system76.CosmicTerm"] {
|
||||
for terminal in self.terminals.iter() {
|
||||
if &terminal.id == id {
|
||||
return Some(terminal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: consider rules in https://github.com/Vladimir-csp/xdg-terminal-exec
|
||||
// Return whatever was the first terminal found
|
||||
self.terminals.first()
|
||||
}
|
||||
|
||||
// Look for and return preferred terminals
|
||||
//TODO: fallback order beyond cosmic-term?
|
||||
for id in &["com.system76.CosmicTerm"] {
|
||||
for terminal in mime_app_cache.terminals.iter() {
|
||||
if &terminal.id == id {
|
||||
return Some(terminal.clone());
|
||||
#[cfg(not(feature = "desktop"))]
|
||||
pub fn set_default(&mut self, mime: Mime, id: String) {
|
||||
log::warn!(
|
||||
"failed to set default handler for {mime:?} to {id:?}: desktop feature not enabled"
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(feature = "desktop")]
|
||||
pub fn set_default(&mut self, mime: Mime, mut id: String) {
|
||||
let Some(path) = cosmic_mime_apps::local_list_path() else {
|
||||
log::warn!("failed to find mimeapps.list path");
|
||||
return;
|
||||
};
|
||||
|
||||
let mut list = cosmic_mime_apps::List::default();
|
||||
match fs::read_to_string(&path) {
|
||||
Ok(string) => {
|
||||
list.load_from(&string);
|
||||
}
|
||||
Err(err) => {
|
||||
if err.kind() != io::ErrorKind::NotFound {
|
||||
log::warn!("failed to read {path:?}: {err}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let suffix = ".desktop";
|
||||
if !id.ends_with(suffix) {
|
||||
id.push_str(suffix);
|
||||
}
|
||||
list.set_default_app(mime, id);
|
||||
|
||||
let mut string = list.to_string();
|
||||
string.push('\n');
|
||||
match fs::write(&path, string) {
|
||||
Ok(()) => {
|
||||
self.reload();
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("failed to write {path:?}: {err}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return whatever was the first terminal found
|
||||
mime_app_cache.terminals.first().cloned()
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue