use std::ops::Deref; use crate::{CosmicConfigEntry, Update}; use cosmic_settings_daemon::{ConfigProxy, CosmicSettingsDaemonProxy}; use futures_util::SinkExt; use iced_futures::futures::{future::pending, StreamExt}; pub async fn settings_daemon_proxy() -> zbus::Result> { let conn = zbus::Connection::session().await?; CosmicSettingsDaemonProxy::new(&conn).await } #[derive(Debug)] pub struct Watcher { proxy: ConfigProxy<'static>, } impl Deref for Watcher { type Target = ConfigProxy<'static>; fn deref(&self) -> &Self::Target { &self.proxy } } impl Watcher { pub async fn new_config( settings_daemon_proxy: &CosmicSettingsDaemonProxy<'static>, id: &str, version: u64, ) -> zbus::Result { let (path, name) = settings_daemon_proxy.watch_config(id, version).await?; ConfigProxy::builder(settings_daemon_proxy.connection()) .path(path)? .destination(name)? .build() .await .map(|proxy| Self { proxy }) } pub async fn new_state( settings_daemon_proxy: &CosmicSettingsDaemonProxy<'static>, id: &str, version: u64, ) -> zbus::Result { let (path, name) = settings_daemon_proxy.watch_state(id, version).await?; ConfigProxy::builder(settings_daemon_proxy.connection()) .path(path)? .destination(name)? .build() .await .map(|proxy| Self { proxy }) } } pub fn watcher_subscription( settings_daemon: CosmicSettingsDaemonProxy<'static>, config_id: &'static str, is_state: bool, ) -> iced_futures::Subscription> { let id = std::any::TypeId::of::(); iced_futures::subscription::channel((is_state, config_id, id), 5, move |mut tx| async move { let version = T::VERSION; let Ok(cosmic_config) = (if is_state { crate::Config::new_state(config_id, version) } else { crate::Config::new(config_id, version) }) else { pending::<()>().await; unreachable!(); }; let mut config = match T::get_entry(&cosmic_config) { Ok(config) => config, Err((errors, default)) => { if !errors.is_empty() { eprintln!("Error getting config: {config_id} {errors:?}"); } default } }; if let Err(err) = tx .send(Update { errors: Vec::new(), keys: Vec::new(), config: config.clone(), }) .await { eprintln!("Failed to send config: {err}"); } let watcher = if is_state { Watcher::new_state(&settings_daemon, config_id, version).await } else { Watcher::new_config(&settings_daemon, config_id, version).await }; let Ok(watcher) = watcher else { pending::<()>().await; unreachable!(); }; loop { let Ok(mut changes) = watcher.receive_changed().await else { pending::<()>().await; unreachable!(); }; while let Some(change) = changes.next().await { let Ok(args) = change.args() else { continue; }; let (errors, keys) = config.update_keys(&cosmic_config, &[args.key]); if !keys.is_empty() { if let Err(err) = tx .send(Update { errors, keys, config: config.clone(), }) .await { eprintln!("Failed to send config update: {err}"); } } } } }) }