1
0
Fork 0
mirror of https://github.com/Zedfrigg/ironbar.git synced 2025-07-03 03:31:03 +02:00

refactor(tray): complete client rewrite

This commit is contained in:
Jake Stanger 2024-03-29 00:23:44 +00:00
parent c7b6ee8bc0
commit 004ea76da5
No known key found for this signature in database
GPG key ID: C51FC8F9CB0BEA61
9 changed files with 193 additions and 246 deletions

View file

@ -1,3 +1,4 @@
use crate::Ironbar;
use std::sync::Arc;
#[cfg(feature = "clipboard")]
@ -9,7 +10,7 @@ pub mod music;
#[cfg(feature = "notifications")]
pub mod swaync;
#[cfg(feature = "tray")]
pub mod system_tray;
pub mod tray;
#[cfg(feature = "upower")]
pub mod upower;
#[cfg(feature = "volume")]
@ -30,7 +31,7 @@ pub struct Clients {
#[cfg(feature = "notifications")]
notifications: Option<Arc<swaync::Client>>,
#[cfg(feature = "tray")]
tray: Option<Arc<system_tray::TrayEventReceiver>>,
tray: Option<Arc<tray::Client>>,
#[cfg(feature = "upower")]
upower: Option<Arc<zbus::fdo::PropertiesProxy<'static>>>,
#[cfg(feature = "volume")]
@ -85,11 +86,17 @@ impl Clients {
}
#[cfg(feature = "tray")]
pub fn tray(&mut self) -> Arc<system_tray::TrayEventReceiver> {
pub fn tray(&mut self) -> Arc<tray::Client> {
// TODO: Error handling here isn't great - should throw a user-friendly error
self.tray
.get_or_insert_with(|| {
Arc::new(crate::await_sync(async {
system_tray::create_client().await
let service_name =
format!("{}-{}", env!("CARGO_CRATE_NAME"), Ironbar::unique_id());
tray::Client::new(&service_name)
.await
.expect("to be able to start client")
}))
})
.clone()

View file

@ -1,127 +0,0 @@
use crate::{arc_mut, lock, register_client, send, spawn, Ironbar};
use color_eyre::Report;
use std::collections::BTreeMap;
use std::sync::{Arc, Mutex};
use system_tray::message::menu::TrayMenu;
use system_tray::message::tray::StatusNotifierItem;
use system_tray::message::{NotifierItemCommand, NotifierItemMessage};
use system_tray::StatusNotifierWatcher;
use tokio::sync::{broadcast, mpsc};
use tracing::{debug, error, trace};
type Tray = BTreeMap<String, (Box<StatusNotifierItem>, Option<TrayMenu>)>;
#[derive(Debug)]
pub struct TrayEventReceiver {
tx: mpsc::Sender<NotifierItemCommand>,
b_tx: broadcast::Sender<NotifierItemMessage>,
_b_rx: broadcast::Receiver<NotifierItemMessage>,
tray: Arc<Mutex<Tray>>,
}
impl TrayEventReceiver {
async fn new() -> system_tray::error::Result<Self> {
let id = format!("ironbar-{}", Ironbar::unique_id());
let (tx, rx) = mpsc::channel(16);
let (b_tx, b_rx) = broadcast::channel(64);
let tray = StatusNotifierWatcher::new(rx).await?;
let mut host = Box::pin(tray.create_notifier_host(&id)).await?;
let tray = arc_mut!(BTreeMap::new());
{
let b_tx = b_tx.clone();
let tray = tray.clone();
spawn(async move {
while let Ok(message) = host.recv().await {
trace!("Received message: {message:?}");
send!(b_tx, message.clone());
let mut tray = lock!(tray);
match message {
NotifierItemMessage::Update {
address,
item,
menu,
} => {
debug!("Adding/updating item with address '{address}'");
tray.insert(address, (item, menu));
}
NotifierItemMessage::Remove { address } => {
debug!("Removing item with address '{address}'");
tray.remove(&address);
}
}
}
Ok::<(), broadcast::error::SendError<NotifierItemMessage>>(())
});
}
Ok(Self {
tx,
b_tx,
_b_rx: b_rx,
tray,
})
}
pub fn subscribe(
&self,
) -> (
mpsc::Sender<NotifierItemCommand>,
broadcast::Receiver<NotifierItemMessage>,
) {
let tx = self.tx.clone();
let b_rx = self.b_tx.subscribe();
let tray = lock!(self.tray).clone();
for (address, (item, menu)) in tray {
let update = NotifierItemMessage::Update {
address,
item,
menu,
};
send!(self.b_tx, update);
}
(tx, b_rx)
}
}
/// Attempts to create a new `TrayEventReceiver` instance,
/// retrying a maximum of 10 times before panicking the thread.
pub async fn create_client() -> TrayEventReceiver {
const MAX_RETRIES: i32 = 10;
// sometimes this can fail
let mut retries = 0;
let value = loop {
retries += 1;
let tray = Box::pin(TrayEventReceiver::new()).await;
match tray {
Ok(tray) => break Some(tray),
Err(err) => error!(
"{:?}",
Report::new(err).wrap_err(format!(
"Failed to create StatusNotifierWatcher (attempt {retries})"
))
),
}
if retries == MAX_RETRIES {
break None;
}
};
value.expect("Failed to create StatusNotifierWatcher")
}
register_client!(TrayEventReceiver, tray);

4
src/clients/tray.rs Normal file
View file

@ -0,0 +1,4 @@
use crate::register_client;
pub use system_tray::client::Client;
register_client!(Client, tray);