Calculate open with apps, when xdg feature is enabled

This commit is contained in:
Jeremy Soller 2024-03-01 13:20:47 -07:00
parent 88eb934564
commit 18e847abb8
No known key found for this signature in database
GPG key ID: D02FD439211AF56F
6 changed files with 208 additions and 33 deletions

View file

@ -20,6 +20,8 @@ mod mime_icon;
mod mouse_area;
mod operation;
mod tab;
#[cfg(feature = "xdg")]
mod xdg;
pub fn home_dir() -> PathBuf {
match dirs::home_dir() {

View file

@ -32,6 +32,8 @@ use std::{
time::{Duration, Instant},
};
#[cfg(feature = "xdg")]
use crate::xdg::{mime_apps, DesktopEntryData};
use crate::{
app::Action,
config::{IconSizes, TabConfig},
@ -261,6 +263,11 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec<Item> {
icon_handle_grid,
icon_handle_list,
icon_handle_list_condensed,
#[cfg(feature = "xdg")]
open_with: mime_guess
.first()
.map(|mime| mime_apps(&mime))
.unwrap_or_default(),
thumbnail_res_opt: match mime_guess.first() {
Some(mime) if mime.type_() == "image" => None,
_ => Some(Err(())),
@ -295,7 +302,7 @@ pub fn scan_path(tab_path: &PathBuf, sizes: IconSizes) -> Vec<Item> {
not(target_os = "android")
)
)))]
pub fn scan_trash() -> Vec<Item> {
pub fn scan_trash(_sizes: IconSizes) -> Vec<Item> {
log::warn!("viewing trash not supported on this platform");
Vec::new()
}
@ -351,6 +358,8 @@ pub fn scan_trash(sizes: IconSizes) -> Vec<Item> {
icon_handle_grid,
icon_handle_list,
icon_handle_list_condensed,
#[cfg(feature = "xdg")]
open_with: Vec::new(),
thumbnail_res_opt: Some(Err(())),
button_id: widget::Id::unique(),
pos_opt: Cell::new(None),
@ -458,6 +467,8 @@ pub struct Item {
pub icon_handle_grid: widget::icon::Handle,
pub icon_handle_list: widget::icon::Handle,
pub icon_handle_list_condensed: widget::icon::Handle,
#[cfg(feature = "xdg")]
pub open_with: Vec<DesktopEntryData>,
pub thumbnail_res_opt: Option<Result<image::RgbaImage, ()>>,
pub button_id: widget::Id,
pub pos_opt: Cell<Option<(usize, usize)>>,
@ -544,20 +555,22 @@ impl Item {
impl fmt::Debug for Item {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Item")
.field("name", &self.name)
.field("metadata", &self.metadata)
.field("hidden", &self.hidden)
.field("path", &self.path)
.field("mime_guess", &self.mime_guess)
// icon_handles
// thumbnail_res_opt
.field("button_id", &self.button_id)
.field("pos_opt", &self.pos_opt)
.field("rect_opt", &self.rect_opt)
.field("selected", &self.selected)
.field("click_time", &self.click_time)
.finish()
let mut d = f.debug_struct("Item");
d.field("name", &self.name);
d.field("metadata", &self.metadata);
d.field("hidden", &self.hidden);
d.field("path", &self.path);
d.field("mime_guess", &self.mime_guess);
// icon_handles
#[cfg(feature = "xdg")]
d.field("open_with", &self.open_with);
// thumbnail_res_opt
d.field("button_id", &self.button_id);
d.field("pos_opt", &self.pos_opt);
d.field("rect_opt", &self.rect_opt);
d.field("selected", &self.selected);
d.field("click_time", &self.click_time);
d.finish()
}
}

58
src/xdg/mime_app.rs Normal file
View file

@ -0,0 +1,58 @@
// Copyright 2023 System76 <info@system76.com>
// SPDX-License-Identifier: GPL-3.0-only
pub use cosmic::desktop::DesktopEntryData;
use cosmic::desktop::{load_applications, Mime};
use once_cell::sync::Lazy;
use std::{collections::HashMap, sync::Mutex, time::Instant};
pub struct MimeAppCache {
cache: HashMap<Mime, Vec<DesktopEntryData>>,
empty: Vec<DesktopEntryData>,
}
impl MimeAppCache {
pub fn new() -> Self {
let mut mime_app_cache = Self {
cache: HashMap::new(),
empty: Vec::new(),
};
mime_app_cache.reload();
mime_app_cache
}
pub fn reload(&mut self) {
let start = Instant::now();
self.cache.clear();
//TODO: get proper locale?
let locale = None;
for app in load_applications(locale, false) {
for mime_type in app.mime_types.iter() {
self.cache
.entry(mime_type.clone())
.or_insert_with(|| Vec::with_capacity(1))
.push(app.clone());
}
}
for apps in self.cache.values_mut() {
apps.sort_by(|a, b| lexical_sort::natural_lexical_cmp(&a.name, &b.name));
}
let elapsed = start.elapsed();
log::info!("loaded mime app cache in {:?}", elapsed);
}
pub fn get(&self, key: &Mime) -> &Vec<DesktopEntryData> {
self.cache.get(&key).unwrap_or_else(|| &self.empty)
}
}
static MIME_APP_CACHE: Lazy<Mutex<MimeAppCache>> = Lazy::new(|| Mutex::new(MimeAppCache::new()));
pub fn mime_apps(mime: &Mime) -> Vec<DesktopEntryData> {
let mime_app_cache = MIME_APP_CACHE.lock().unwrap();
mime_app_cache.get(mime).clone()
}

5
src/xdg/mod.rs Normal file
View file

@ -0,0 +1,5 @@
// Copyright 2023 System76 <info@system76.com>
// SPDX-License-Identifier: GPL-3.0-only
pub mod mime_app;
pub use mime_app::*;