112 lines
3.8 KiB
Rust
112 lines
3.8 KiB
Rust
//! 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<Vec<Application>, 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<String> = 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::<String>("Id").await else {
|
|
continue;
|
|
};
|
|
let title = proxy
|
|
.get_property::<String>("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<Message> {
|
|
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::<Vec<_>>()
|
|
})
|
|
.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()
|
|
}
|
|
}
|