diff --git a/src/app.rs b/src/app.rs index 44f4b0c..b8846de 100644 --- a/src/app.rs +++ b/src/app.rs @@ -416,6 +416,7 @@ pub enum Message { PendingPauseAll(bool), PermanentlyDelete(Option), Preview(Option), + ReloadMimeAppCache, ReorderTab(ReorderEvent), RescanRecents, RescanTrash, @@ -448,7 +449,6 @@ pub enum Message { Option>, ), TabView(Option, tab::View), - TerminalDefault(Box), TimeConfigChange(TimeConfig), ToggleContextPage(ContextPage), ToggleFoldersFirst, @@ -4221,6 +4221,9 @@ impl Application for App { let paths: Box<[_]> = self.selected_paths(entity_opt).collect(); return self.operation(Operation::RemoveFromRecents { paths }); } + Message::ReloadMimeAppCache => { + self.mime_app_cache.reload(); + } Message::RescanRecents => { return self.rescan_recents(); } @@ -4794,7 +4797,6 @@ impl Application for App { tab.refresh_cut(&paths); } } - Message::TerminalDefault(command) => {} Message::TimeConfigChange(time_config) => { self.config.tab.military_time = time_config.military_time; return self.update_config(); @@ -6775,6 +6777,22 @@ impl Application for App { }, ) }), + Subscription::run(|| { + eprintln!("loading mime app watcher"); + stream::channel( + 1, + |mut output: futures::channel::mpsc::Sender| async move { + mime_app::watch(move || { + futures::executor::block_on(async { + _ = output.send(Message::ReloadMimeAppCache).await; + }) + }) + .await; + + std::future::pending().await + }, + ) + }), Subscription::run_with(TypeId::of::(), |_| { stream::channel( 1, diff --git a/src/mime_app.rs b/src/mime_app.rs index c830ab7..706c80d 100644 --- a/src/mime_app.rs +++ b/src/mime_app.rs @@ -6,15 +6,64 @@ use bstr::{BString, ByteSlice, ByteVec}; use cosmic::desktop; use cosmic::widget; pub use mime_guess::Mime; +use notify_debouncer_full::notify; use rustc_hash::FxHashMap; use std::ffi::OsStr; use std::os::unix::ffi::OsStrExt; use std::path::{Path, PathBuf}; use std::sync::atomic::AtomicBool; use std::sync::{Arc, atomic}; -use std::time::Instant; +use std::time::{self, Instant}; use std::{fs, io, process}; +pub async fn watch(mut emitter: impl FnMut() + 'static + Send) { + let watcher_result = notify_debouncer_full::new_debouncer( + time::Duration::from_millis(250), + Some(time::Duration::from_millis(250)), + move |event_res: notify_debouncer_full::DebounceEventResult| { + let Ok(events) = event_res else { + return; + }; + + if events.iter().any(|event| { + event.kind.is_create() || event.kind.is_modify() || event.kind.is_remove() + }) { + emitter(); + } + }, + ); + + if let Ok(mut watcher) = watcher_result { + let system_paths = cosmic_mime_apps::list_paths(); + let local_paths = (|| { + let base_dirs = xdg::BaseDirectories::new(); + let Some(home) = base_dirs.get_config_home() else { + return Err(std::io::Error::other("XDG config home not set")); + }; + + let Ok(desktop) = std::env::var("XDG_CURRENT_DESKTOP") else { + return Err(std::io::Error::other("XDG_CURRENT_DESKTOP unset")); + }; + + let default_mimeapps = home.join("mimeapps.list"); + let desktop_mimeapps = + home.join([&desktop.to_ascii_lowercase(), "-mimeapps.list"].concat()); + + Ok([desktop_mimeapps, default_mimeapps]) + })() + .ok(); + + for path in system_paths + .iter() + .chain(local_paths.as_ref().into_iter().flatten()) + { + _ = watcher.watch(path.as_path(), notify::RecursiveMode::NonRecursive); + } + + std::future::pending().await + } +} + pub fn exec_to_command( exec: &str, entry_name: &str,