cosmic/theme/
portal.rs

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                        // Reset the attempts counter if we successfully received a change
97                        attempts = 0;
98                    }
99                }
100            }
101        })
102    })
103}