Skip to content

Commit 1fe1aa5

Browse files
committed
fix(default-apps): missing and wrong associations
* update the cosmic-mime-apps crate with fixes to app association detection * actually use cosmic-mime-apps for significantly faster association lookups
1 parent 60a7de5 commit 1fe1aa5

3 files changed

Lines changed: 78 additions & 61 deletions

File tree

Cargo.lock

Lines changed: 4 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cosmic-settings/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ libcosmic.workspace = true
6363
iced_winit.workspace = true
6464
locale1 = { git = "https://github.com/pop-os/dbus-settings-bindings", optional = true }
6565
sysinfo = { version = "=0.38.0", optional = true }
66-
mime-apps = { package = "cosmic-mime-apps", git = "https://github.com/pop-os/cosmic-mime-apps", optional = true }
66+
mime-apps = { package = "cosmic-mime-apps", git = "https://github.com/pop-os/cosmic-mime-apps", features = ["tokio"], optional = true }
67+
# mime-apps = { package = "cosmic-mime-apps", path = "../../../cosmic-mime-apps", features = ["tokio"], optional = true }
6768
notify = "8.2.0"
6869
regex = "1.12.3"
6970
ron = "0.12"

cosmic-settings/src/pages/applications/default_apps.rs

Lines changed: 72 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,6 @@
22
// Copyright 2024 bbb651 <bar.ye651@gmail.com>
33
// SPDX-License-Identifier: GPL-3.0-only
44

5-
use std::borrow::Cow;
6-
use std::collections::{BTreeMap, BTreeSet};
7-
use std::path::{Path, PathBuf};
8-
use std::sync::Arc;
9-
105
use cosmic::iced::{Alignment, Length};
116
use cosmic::widget::{self, dropdown, icon, settings};
127
use cosmic::{Apply, Element, Task, surface};
@@ -17,8 +12,16 @@ use cosmic_settings_page::{self as page, Section, section};
1712
use freedesktop_desktop_entry::{
1813
DesktopEntry, Iter as DesktopEntryIter, default_paths, get_languages_from_env,
1914
};
15+
use mime::Mime;
2016
use mime_apps::App;
2117
use slotmap::SlotMap;
18+
use std::borrow::Cow;
19+
use std::collections::{BTreeMap, BTreeSet};
20+
use std::io::SeekFrom;
21+
use std::path::PathBuf;
22+
use std::str::FromStr;
23+
use std::sync::Arc;
24+
use tokio::io::{AsyncSeekExt, AsyncWriteExt};
2225

2326
const DROPDOWN_WEB_BROWSER: usize = 0;
2427
const DROPDOWN_FILE_MANAGER: usize = 1;
@@ -47,7 +50,7 @@ pub enum Category {
4750
#[derive(Clone, Debug)]
4851
pub enum Message {
4952
SetDefault(Category, usize),
50-
Update(CachedMimeApps),
53+
Update(Arc<CachedMimeApps>),
5154
Surface(surface::Action),
5255
}
5356

@@ -63,13 +66,11 @@ impl From<Message> for crate::pages::Message {
6366
}
6467
}
6568

66-
#[derive(Clone, Debug)]
69+
#[derive(Debug)]
6770
pub struct CachedMimeApps {
68-
pub list: mime_apps::List,
69-
pub local_list: mime_apps::List,
70-
pub apps: Vec<AppMeta>,
71-
pub known_mimes: BTreeSet<mime::Mime>,
72-
pub config_path: Box<Path>,
71+
local_list: Option<(mime_apps::List, tokio::fs::File)>,
72+
apps: Vec<AppMeta>,
73+
known_mimes: BTreeSet<mime::Mime>,
7374
}
7475

7576
#[derive(Clone, Debug)]
@@ -80,7 +81,7 @@ pub struct AppMeta {
8081
icons: Vec<icon::Handle>,
8182
}
8283

83-
#[derive(Clone, Debug, Default)]
84+
#[derive(Debug, Default)]
8485
pub struct Page {
8586
on_enter_handle: Option<cosmic::iced::task::Handle>,
8687
mime_apps: Option<CachedMimeApps>,
@@ -113,41 +114,32 @@ impl page::Page<crate::pages::Message> for Page {
113114
}
114115

115116
let (task, on_enter_handle) = Task::future(async move {
117+
let local_list = mime_apps::load_user_mimeapps().await.ok();
116118
let mut list = mime_apps::List::default();
117119
list.load_from_paths(&mime_apps::list_paths());
118-
119-
let mut local_list = mime_apps::List::default();
120-
121-
if let Some(path) = mime_apps::local_list_path()
122-
&& let Ok(buffer) = std::fs::read_to_string(&path)
123-
{
124-
local_list.load_from(&buffer);
125-
}
126-
127-
let assocs = mime_apps::associations::by_app();
120+
let assocs = mime_apps::associations::by_app(&list);
128121

129122
let apps = vec![
130-
load_defaults(&assocs, &["x-scheme-handler/http"]).await,
131-
load_defaults(&assocs, &["inode/directory"]).await,
132-
load_defaults(&assocs, &["x-scheme-handler/mailto"]).await,
133-
load_defaults(&assocs, &["audio/mp3", "application/ogg", "video/mp4"]).await,
134-
load_defaults(&assocs, &["video/mp4"]).await,
135-
load_defaults(&assocs, &["image/png"]).await,
136-
load_defaults(&assocs, &["text/calendar"]).await,
123+
load_defaults(&list, &assocs, &["x-scheme-handler/http"]),
124+
load_defaults(&list, &assocs, &["inode/directory"]),
125+
load_defaults(&list, &assocs, &["x-scheme-handler/mailto"]),
126+
load_defaults(
127+
&list,
128+
&assocs,
129+
&["audio/mpeg", "application/ogg", "audio/x-flac"],
130+
),
131+
load_defaults(&list, &assocs, &["video/mp4"]),
132+
load_defaults(&list, &assocs, &["image/png"]),
133+
load_defaults(&list, &assocs, &["text/calendar"]),
137134
load_terminal_apps(&assocs).await,
138-
load_defaults(&assocs, &["text/plain"]).await,
135+
load_defaults(&list, &assocs, &["text/plain"]),
139136
];
140137

141-
Message::Update(CachedMimeApps {
138+
Message::Update(Arc::new(CachedMimeApps {
142139
apps,
143-
list,
144140
local_list,
145141
known_mimes: mime_apps::mime_info::mime_types(),
146-
config_path: dirs::config_dir()
147-
.expect("config dir not found")
148-
.join("mimeapps.list")
149-
.into(),
150-
})
142+
}))
151143
.into()
152144
})
153145
.abortable();
@@ -188,6 +180,7 @@ impl Page {
188180
"application/ogg",
189181
"application/x-cue",
190182
"application/x-ogg",
183+
"audio/mpeg",
191184
"audio/mp3",
192185
"x-content/audio-cdda",
193186
])
@@ -238,7 +231,7 @@ impl Page {
238231

239232
let meta = &mut mime_apps.apps[category_id];
240233

241-
if meta.selected != Some(id) {
234+
if meta.selected.is_none_or(|selected| selected != id) {
242235
meta.selected = Some(id);
243236
let appid = &meta.app_ids[id];
244237

@@ -249,24 +242,36 @@ impl Page {
249242
assign_default_terminal(config, appid);
250243
}
251244

252-
for mime in mime_types {
253-
if let Ok(mime) = mime.parse() {
254-
mime_apps
255-
.local_list
256-
.set_default_app(mime, [appid, ".desktop"].concat());
257-
};
245+
if let Some((local_list, local_file)) = mime_apps.local_list.as_mut() {
246+
for mime in mime_types {
247+
if let Ok(mime) = mime.parse() {
248+
tracing::info!(target: "default-apps", ?mime, appid, "setting default for mime");
249+
local_list.set_default_app(mime, [appid, ".desktop"].concat());
250+
};
251+
}
252+
253+
let mut buffer = local_list.to_string();
254+
buffer.push('\n');
255+
256+
if let Ok(mut local_file) =
257+
futures::executor::block_on(local_file.try_clone())
258+
{
259+
tokio::spawn(async move {
260+
tracing::debug!(target: "default-apps", buffer, "writing to mimeapps config");
261+
_ = local_file.seek(SeekFrom::Start(0)).await;
262+
_ = local_file.set_len(buffer.len() as u64).await;
263+
_ = local_file.write_all(buffer.as_bytes()).await;
264+
_ = local_file.flush().await;
265+
_ = local_file.seek(SeekFrom::Start(0)).await;
266+
_ = tokio::process::Command::new("update-desktop-database")
267+
.status()
268+
.await;
269+
});
270+
}
258271
}
259-
260-
let mut buffer = mime_apps.local_list.to_string();
261-
buffer.push('\n');
262-
263-
_ = std::fs::write(&mime_apps.config_path, buffer);
264-
_ = std::process::Command::new("update-desktop-database").status();
265272
}
266273
}
267-
Message::Update(mime_apps) => {
268-
self.mime_apps = Some(mime_apps);
269-
}
274+
Message::Update(mime_apps) => self.mime_apps = Arc::into_inner(mime_apps),
270275
Message::Surface(a) => {
271276
return cosmic::task::message(crate::app::Message::Surface(a));
272277
}
@@ -286,7 +291,7 @@ fn app_item(meta: &AppMeta, label: String, category: Category) -> widget::FlexRo
286291
} else {
287292
dropdown::popup_dropdown(
288293
&meta.apps,
289-
meta.selected,
294+
Some(meta.selected.unwrap_or(0)),
290295
move |id| Message::SetDefault(category, id),
291296
cosmic::iced::window::Id::RESERVED,
292297
Message::Surface,
@@ -393,12 +398,16 @@ fn assign_default_terminal(config: &cosmic_config::Config, appid: &str) {
393398
}
394399
}
395400

396-
async fn load_defaults(assocs: &BTreeMap<Arc<str>, Arc<App>>, for_mimes: &[&str]) -> AppMeta {
401+
fn load_defaults(
402+
list: &mime_apps::List,
403+
assocs: &BTreeMap<Arc<str>, Arc<App>>,
404+
for_mimes: &[&str],
405+
) -> AppMeta {
397406
let mut unsorted = Vec::new();
398407
let mut current_app = None;
399408

400409
for for_mime in for_mimes {
401-
let Ok(mime) = for_mime.parse() else {
410+
let Ok(mime) = Mime::from_str(for_mime) else {
402411
return AppMeta {
403412
selected: None,
404413
app_ids: Vec::new(),
@@ -407,7 +416,12 @@ async fn load_defaults(assocs: &BTreeMap<Arc<str>, Arc<App>>, for_mimes: &[&str]
407416
};
408417
};
409418

410-
let current_app_entry = xdg_mime_query_default(for_mime).await;
419+
let current_app_entry = dbg!(
420+
list.default_app_for(&mime)
421+
.and_then(|entries| entries.first())
422+
);
423+
424+
tracing::info!(target: "default-apps", ?mime, ?current_app_entry, "entry for mime");
411425
let current_appid = current_app_entry
412426
.as_ref()
413427
.and_then(|entry| entry.strip_suffix(".desktop"));

0 commit comments

Comments
 (0)