1use ashpd::desktop::Color;
2use ashpd::desktop::settings::{ColorScheme, Contrast};
3use iced::futures::{self, FutureExt, SinkExt, StreamExt, select};
4use iced_futures::stream;
5use tracing::error;
6
7#[derive(Debug, Clone)]
8pub enum Desktop {
9 Accent(Color),
10 ColorScheme(ColorScheme),
11 Contrast(Contrast),
12}
13
14#[cold]
15pub fn desktop_settings() -> iced_futures::Subscription<Desktop> {
16 iced_futures::Subscription::run(|| {
17 stream::channel(10, |mut tx: futures::channel::mpsc::Sender<Desktop>| {
18 async move {
19 let mut attempts = 0;
20 loop {
21 let Ok(settings) = ashpd::desktop::settings::Settings::new().await else {
22 error!("Failed to create the settings proxy");
23 #[cfg(feature = "tokio")]
24 ::tokio::time::sleep(::tokio::time::Duration::from_secs(
25 2_u64.pow(attempts),
26 ))
27 .await;
28 #[cfg(not(feature = "tokio"))]
29 {
30 futures::future::pending::<()>().await;
31 unreachable!();
32 }
33 attempts += 1;
34 continue;
35 };
36
37 match settings.color_scheme().await {
38 Ok(color_scheme) => {
39 let _ = tx.send(Desktop::ColorScheme(color_scheme)).await;
40 }
41 Err(err) => error!("Failed to get the color scheme {err:?}"),
42 };
43 match settings.contrast().await {
44 Ok(contrast) => {
45 let _ = tx.send(Desktop::Contrast(contrast)).await;
46 }
47 Err(err) => error!("Failed to get the contrast {err:?}"),
48 };
49
50 let mut color_scheme_stream =
51 settings.receive_color_scheme_changed().await.ok();
52 if color_scheme_stream.is_none() {
53 error!("Failed to receive color scheme changes");
54 }
55
56 let mut contrast_stream = settings.receive_contrast_changed().await.ok();
57 if contrast_stream.is_none() {
58 error!("Failed to receive contrast changes");
59 }
60
61 loop {
62 if color_scheme_stream.is_none() && contrast_stream.is_none() {
63 break;
64 }
65 let next_color_scheme = async {
66 if let Some(s) = color_scheme_stream.as_mut() {
67 return s.next().await;
68 }
69 futures::future::pending().await
70 };
71
72 let next_contrast = async {
73 if let Some(s) = contrast_stream.as_mut() {
74 return s.next().await;
75 }
76 futures::future::pending().await
77 };
78
79 select! {
80 s = next_color_scheme.fuse() => {
81 if let Some(s) = s {
82 _ = tx.send(Desktop::ColorScheme(s)).await;
83 } else {
84 color_scheme_stream = None;
85 }
86 },
87
88 c = next_contrast.fuse() => {
89 if let Some(c) = c {
90 _ = tx.send(Desktop::Contrast(c)).await;
91 } else {
92 contrast_stream = None;
93 }
94 }
95 };
96 attempts = 0;
98 }
99 }
100 }
101 })
102 })
103}