//! Read tray applications through the existing watcher without becoming a host. use super::{Alignment, App, Element, Length, Message, Task, column, row, set}; use ferese_config::locale::text as t; #[derive(Clone, Debug)] pub struct Application { pub id: String, pub title: String, } async fn applications() -> Result, String> { let connection = zbus::Connection::session() .await .map_err(|e| e.to_string())?; let watcher = zbus::Proxy::new( &connection, "org.kde.StatusNotifierWatcher", "/StatusNotifierWatcher", "org.kde.StatusNotifierWatcher", ) .await .map_err(|e| e.to_string())?; let addresses: Vec = watcher .get_property("RegisteredStatusNotifierItems") .await .map_err(|e| e.to_string())?; let mut apps = Vec::new(); for address in addresses.into_iter().take(128) { let (name, path) = address .find('/') .map_or((address.as_str(), "/StatusNotifierItem"), |i| { (&address[..i], &address[i..]) }); let Ok(proxy) = zbus::Proxy::new(&connection, name, path, "org.kde.StatusNotifierItem").await else { continue; }; let Ok(id) = proxy.get_property::("Id").await else { continue; }; let title = proxy .get_property::("Title") .await .unwrap_or_else(|_| id.clone()); if !apps.iter().any(|a: &Application| a.id == id) { apps.push(Application { id, title }); } } apps.sort_by(|a, b| a.title.cmp(&b.title)); Ok(apps) } impl App { pub(super) fn load_tray_apps(&self) -> Task { cosmic::task::future(async { Message::TrayApps(applications().await.unwrap_or_default()) }) } pub(super) fn tray_application_controls(&self) -> Element<'_, Message> { let hidden = self .draft .item("status.tray.hidden_items") .and_then(serde_json::Value::as_array) .map(|a| { a.iter() .filter_map(|v| v.as_str().map(str::to_owned)) .collect::>() }) .unwrap_or_default(); let mut apps = self.tray_apps.clone(); for id in &hidden { if !apps.iter().any(|a| &a.id == id) { apps.push(Application { id: id.clone(), title: id.clone(), }); } } let mut out = column([]) .spacing(12) .push(self.panel_heading(t("Application icons"), 15.)); for app in apps { let visible = !hidden.contains(&app.id); let mut next = hidden.clone(); if visible { next.push(app.id); } else { next.retain(|id| id != &app.id); } out = out.push( row([]) .spacing(8) .align_y(Alignment::Center) .push(self.label(app.title, 13.).width(Length::Fill)) .push( ferese_theme::controls::switch( visible, super::visuals::Palette::from_resolved(&self.resolved.presented), ) .on_press(Message::Change(set( "status.tray.hidden_items", serde_json::json!(next), ))), ), ); } out.push(self.settings_button( t("Refresh applications"), "M3 10a8 8 0 1 1 1 7 M3 3v7h7", Some(Message::RefreshTrayApps), false, )) .into() } }