fix(default-apps): additional missing apps

This commit is contained in:
Michael Aaron Murphy 2026-06-01 21:12:53 +02:00 committed by Michael Murphy
parent 2e83e56c09
commit de5e16d360
3 changed files with 93 additions and 123 deletions

26
Cargo.lock generated
View file

@ -288,7 +288,7 @@ version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
dependencies = [ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.60.2",
] ]
[[package]] [[package]]
@ -299,7 +299,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"once_cell_polyfill", "once_cell_polyfill",
"windows-sys 0.61.2", "windows-sys 0.60.2",
] ]
[[package]] [[package]]
@ -1471,7 +1471,7 @@ dependencies = [
[[package]] [[package]]
name = "cosmic-mime-apps" name = "cosmic-mime-apps"
version = "0.2.0" version = "0.2.0"
source = "git+https://github.com/pop-os/cosmic-mime-apps#a95c8043a7b41ca3c143a1fad5b3b8a5a3411008" source = "git+https://github.com/pop-os/cosmic-mime-apps#8fc81e8857e46c018ea21ab985aaf30ac853c007"
dependencies = [ dependencies = [
"freedesktop-desktop-entry", "freedesktop-desktop-entry",
"futures-util", "futures-util",
@ -2173,7 +2173,7 @@ dependencies = [
"libc", "libc",
"option-ext", "option-ext",
"redox_users", "redox_users",
"windows-sys 0.61.2", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -2357,7 +2357,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.61.2", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -4148,7 +4148,7 @@ dependencies = [
"portable-atomic", "portable-atomic",
"portable-atomic-util", "portable-atomic-util",
"serde_core", "serde_core",
"windows-sys 0.61.2", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -4490,7 +4490,7 @@ version = "1.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a1886916523694cd6ea3d175f03a1e5010699a2a4cc13696d83d7bea1d80638" checksum = "7a1886916523694cd6ea3d175f03a1e5010699a2a4cc13696d83d7bea1d80638"
dependencies = [ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -5188,7 +5188,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -6564,7 +6564,7 @@ dependencies = [
"errno", "errno",
"libc", "libc",
"linux-raw-sys 0.12.1", "linux-raw-sys 0.12.1",
"windows-sys 0.61.2", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -6994,7 +6994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.61.2", "windows-sys 0.60.2",
] ]
[[package]] [[package]]
@ -7236,7 +7236,7 @@ dependencies = [
"getrandom 0.4.2", "getrandom 0.4.2",
"once_cell", "once_cell",
"rustix 1.1.4", "rustix 1.1.4",
"windows-sys 0.61.2", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -7636,7 +7636,7 @@ checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
dependencies = [ dependencies = [
"memoffset", "memoffset",
"tempfile", "tempfile",
"windows-sys 0.61.2", "windows-sys 0.60.2",
] ]
[[package]] [[package]]
@ -8353,7 +8353,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.48.0",
] ]
[[package]] [[package]]

View file

@ -64,7 +64,6 @@ iced_winit.workspace = true
locale1 = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true } locale1 = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
sysinfo = { version = "=0.38.0", optional = true } sysinfo = { version = "=0.38.0", optional = true }
mime-apps = { package = "cosmic-mime-apps", git = "https://github.com/pop-os/cosmic-mime-apps", features = ["tokio"], optional = true } mime-apps = { package = "cosmic-mime-apps", git = "https://github.com/pop-os/cosmic-mime-apps", features = ["tokio"], optional = true }
# mime-apps = { package = "cosmic-mime-apps", path = "../../../cosmic-mime-apps", features = ["tokio"], optional = true }
notify = "8.2.0" notify = "8.2.0"
regex = "1.12.3" regex = "1.12.3"
ron = "0.12" ron = "0.12"

View file

@ -9,14 +9,11 @@ use cosmic_config::{ConfigGet, ConfigSet};
use cosmic_settings_config::shortcuts::SystemActions; use cosmic_settings_config::shortcuts::SystemActions;
use cosmic_settings_config::shortcuts::action::System; use cosmic_settings_config::shortcuts::action::System;
use cosmic_settings_page::{self as page, Section, section}; use cosmic_settings_page::{self as page, Section, section};
use freedesktop_desktop_entry::{ use freedesktop_desktop_entry::{DesktopEntry, default_paths, get_languages_from_env};
DesktopEntry, Iter as DesktopEntryIter, default_paths, get_languages_from_env,
};
use mime::Mime; use mime::Mime;
use mime_apps::App;
use slotmap::SlotMap; use slotmap::SlotMap;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::BTreeSet;
use std::io::SeekFrom; use std::io::SeekFrom;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
@ -76,7 +73,7 @@ pub struct CachedMimeApps {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct AppMeta { pub struct AppMeta {
selected: Option<usize>, selected: Option<usize>,
app_ids: Vec<String>, app_ids: Vec<Box<str>>,
apps: Vec<String>, apps: Vec<String>,
icons: Vec<icon::Handle>, icons: Vec<icon::Handle>,
} }
@ -126,7 +123,7 @@ impl page::Page<crate::pages::Message> for Page {
let mut list = mime_apps::List::default(); let mut list = mime_apps::List::default();
list.load_from_paths(&mime_apps::list_paths()); list.load_from_paths(&mime_apps::list_paths());
let assocs = mime_apps::associations::by_app(&list); let assocs = mime_apps::associations::load_from_disk(&list);
let apps = vec![ let apps = vec![
load_defaults(&list, &assocs, &["x-scheme-handler/http"]), load_defaults(&list, &assocs, &["x-scheme-handler/http"]),
@ -135,12 +132,12 @@ impl page::Page<crate::pages::Message> for Page {
load_defaults( load_defaults(
&list, &list,
&assocs, &assocs,
&["audio/mpeg", "application/ogg", "audio/x-flac"], &["audio/mpeg", "application/ogg", "audio/x-flac", "video/mp4"],
), ),
load_defaults(&list, &assocs, &["video/mp4"]), load_defaults(&list, &assocs, &["video/mp4"]),
load_defaults(&list, &assocs, &["image/png"]), load_defaults(&list, &assocs, &["image/png"]),
load_defaults(&list, &assocs, &["text/calendar"]), load_defaults(&list, &assocs, &["text/calendar"]),
load_terminal_apps(&assocs).await, load_terminal_apps(&list, &assocs).await,
load_defaults(&list, &assocs, &["text/plain"]), load_defaults(&list, &assocs, &["text/plain"]),
]; ];
@ -413,64 +410,69 @@ fn assign_default_terminal(config: &cosmic_config::Config, appid: &str) {
fn load_defaults( fn load_defaults(
list: &mime_apps::List, list: &mime_apps::List,
assocs: &BTreeMap<Arc<str>, Arc<App>>, assocs: &mime_apps::Associations,
for_mimes: &[&str], for_mimes: &[&str],
) -> AppMeta { ) -> AppMeta {
let mut unsorted = Vec::new(); let mut unsorted = Vec::new();
let mut current_app = None; let mut default_app = None;
for for_mime in for_mimes { for for_mime in for_mimes {
let Ok(mime) = Mime::from_str(for_mime) else { let Ok(mime) = Mime::from_str(for_mime) else {
return AppMeta { continue;
selected: None,
app_ids: Vec::new(),
apps: Vec::new(),
icons: Vec::new(),
};
}; };
let current_app_entry = dbg!( for default in list.default_app_for(&mime).into_iter().flatten() {
list.default_app_for(&mime) let appid = default.strip_suffix(".desktop").unwrap_or(default.as_ref());
.and_then(|entries| entries.first())
);
tracing::info!(target: "default-apps", ?mime, ?current_app_entry, "entry for mime"); tracing::info!(target: "default-apps", ?mime, appid, "entry for mime");
let current_appid = current_app_entry if default_app.is_none() {
.as_ref() default_app = assocs.by_app_id.get(appid);
.and_then(|entry| entry.strip_suffix(".desktop")); if default_app.is_some() {
break;
if unsorted.is_empty() { }
current_app = current_appid.and_then(|appid| assocs.get(appid)); }
} }
unsorted.extend( for (appid, app) in mime_apps::apps_for_mime(&mime, assocs) {
mime_apps::apps_for_mime(&mime, assocs) if app.icon.is_none() {
.map(|(app_id, app)| (app_id.clone(), app.clone())), continue;
); }
if unsorted.iter().any(|(id, _)| id == appid) {
continue;
}
unsorted.push((appid.clone(), app.clone()));
}
} }
unsorted.sort_unstable_by_key(|(_, app)| app.name.clone()); unsorted.sort_unstable_by_key(|(_, app)| app.name.clone());
unsorted.dedup_by_key(|(app_id, _)| app_id.clone());
let mut selected = None; let mut selected = None;
let mut app_ids = Vec::new(); let mut app_ids = Vec::new();
let mut apps = Vec::new(); let mut apps = Vec::new();
let mut icons = Vec::new(); let mut icons = Vec::new();
for (id, (appid, app)) in unsorted.iter().enumerate() { let mut id = 0;
if let Some(current_app) = current_app for (appid, app) in unsorted.iter() {
&& app.name.as_ref() == current_app.name.as_ref() let Some(icon) = app.icon.as_deref() else {
continue;
};
if let Some(default_app) = default_app
&& app.name.as_ref() == default_app.name.as_ref()
{ {
selected = Some(id); selected = Some(id);
} }
app_ids.push(appid.as_ref().into()); app_ids.push(appid.as_ref().into());
apps.push(app.name.as_ref().into()); apps.push(app.name.as_ref().into());
icons.push(if app.icon.starts_with('/') { icons.push(if icon.starts_with('/') {
icon::from_path(PathBuf::from(app.icon.as_ref())) icon::from_path(PathBuf::from(icon))
} else { } else {
icon::from_name(app.icon.as_ref()).size(20).handle() icon::from_name(icon).size(20).handle()
}); });
id += 1;
} }
AppMeta { AppMeta {
@ -481,86 +483,55 @@ fn load_defaults(
} }
} }
async fn xdg_mime_query_default(mime_type: &str) -> Option<String> { async fn load_terminal_apps(list: &mime_apps::List, assocs: &mime_apps::Associations) -> AppMeta {
let output = tokio::process::Command::new("xdg-mime")
.args(["query", "default", mime_type])
.output()
.await
.ok()?;
if !output.status.success() {
return None;
}
String::from_utf8(output.stdout)
.ok()
.map(|string| string.trim().to_owned())
}
async fn load_terminal_apps(assocs: &BTreeMap<Arc<str>, Arc<App>>) -> AppMeta {
let mut terminals = Vec::new();
let mut current_app = None;
// Get the current default terminal if set
let current_entry = xdg_mime_query_default("x-scheme-handler/terminal").await;
let current_appid = current_entry
.as_ref()
.and_then(|entry| entry.strip_suffix(".desktop"));
// Also check x-terminal-emulator
if current_app.is_none() {
let current_entry = xdg_mime_query_default("application/x-terminal-emulator").await;
let current_appid = current_entry
.as_ref()
.and_then(|entry| entry.strip_suffix(".desktop"));
if let Some(appid) = current_appid {
current_app = assocs.get(appid).cloned();
}
}
// Scan desktop entries for terminal applications
for path in DesktopEntryIter::new(default_paths()) {
if let Ok(bytes) = std::fs::read_to_string(&path)
&& let Ok(entry) = DesktopEntry::from_str(&path, &bytes, None::<&[&str]>)
{
// Check if it's a terminal application
if entry
.categories()
.map(|cats| cats.contains(&"TerminalEmulator"))
.unwrap_or(false)
{
let id = entry.id();
if let Some(app) = assocs.get(id) {
if current_appid.as_ref().map(|c| *c == id).unwrap_or(false) {
current_app = Some(app.clone());
}
terminals.push((Arc::from(id), app.clone()));
}
}
}
}
terminals.sort_unstable_by_key(|(_, app): &(Arc<str>, Arc<App>)| app.name.clone());
terminals.dedup_by(|a, b| a.0 == b.0);
let mut selected = None; let mut selected = None;
let mut app_ids = Vec::new(); let mut app_ids = Vec::new();
let mut apps = Vec::new(); let mut apps = Vec::new();
let mut icons = Vec::new(); let mut icons = Vec::new();
for (id, (appid, app)) in terminals.iter().enumerate() { let mut terminals: Vec<_> = assocs
if let Some(ref current_app) = current_app .apps
&& app.name.as_ref() == current_app.name.as_ref() .iter()
{ .filter(|app| app.is_terminal && app.icon.is_some())
.collect();
terminals.sort_unstable_by_key(|app| app.name.clone());
'outer: for for_mime in [
"x-scheme-handler/terminal",
"application/x-terminal-emulator",
] {
let Ok(mime) = Mime::from_str(for_mime) else {
continue;
};
for default in list.default_app_for(&mime).into_iter().flatten() {
let appid = default.strip_suffix(".desktop").unwrap_or(default.as_ref());
for (id, app) in terminals.iter().enumerate() {
if app.appid.as_ref() == appid {
selected = Some(id);
break 'outer;
}
}
}
}
for (id, app) in terminals.into_iter().enumerate() {
let Some(icon) = app.icon.as_deref() else {
continue;
};
if selected.is_none() && app.appid.as_ref() == "com.system76.CosmicTerm" {
selected = Some(id); selected = Some(id);
} }
app_ids.push(appid.to_string()); app_ids.push(app.appid.clone());
apps.push(app.name.as_ref().into()); apps.push(app.name.as_ref().into());
icons.push(if app.icon.starts_with('/') { icons.push(if icon.starts_with('/') {
icon::from_path(PathBuf::from(app.icon.as_ref())) icon::from_path(PathBuf::from(icon))
} else { } else {
icon::from_name(app.icon.as_ref()).size(20).handle() icon::from_name(icon).size(20).handle()
}); });
} }