126 lines
4 KiB
Rust
126 lines
4 KiB
Rust
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<CosmicSettingsDaemonProxy<'static>> {
|
|
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<Self> {
|
|
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<Self> {
|
|
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<T: CosmicConfigEntry + Send + Sync + Default + 'static + Clone>(
|
|
settings_daemon: CosmicSettingsDaemonProxy<'static>,
|
|
config_id: &'static str,
|
|
is_state: bool,
|
|
) -> iced_futures::Subscription<Update<T>> {
|
|
let id = std::any::TypeId::of::<T>();
|
|
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}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|