diff --git a/src/clients/compositor/mod.rs b/src/clients/compositor/mod.rs index ce8d749e..03719139 100644 --- a/src/clients/compositor/mod.rs +++ b/src/clients/compositor/mod.rs @@ -1,4 +1,4 @@ -use crate::{await_sync, register_client}; +use crate::{await_sync, register_fallible_client}; use cfg_if::cfg_if; use color_eyre::{Help, Report, Result}; use std::fmt::{Debug, Display, Formatter}; @@ -141,4 +141,4 @@ pub trait WorkspaceClient: Debug + Send + Sync { fn subscribe_workspace_change(&self) -> broadcast::Receiver; } -register_client!(dyn WorkspaceClient, workspaces); +register_fallible_client!(dyn WorkspaceClient, workspaces); diff --git a/src/clients/mod.rs b/src/clients/mod.rs index a3899b2b..f289c2c5 100644 --- a/src/clients/mod.rs +++ b/src/clients/mod.rs @@ -1,4 +1,5 @@ -use crate::Ironbar; +use crate::{await_sync, Ironbar}; +use color_eyre::Result; use std::sync::Arc; #[cfg(feature = "clipboard")] @@ -38,6 +39,8 @@ pub struct Clients { volume: Option>, } +pub type ClientResult = Result>; + impl Clients { pub(crate) fn new() -> Self { Self::default() @@ -59,13 +62,17 @@ impl Clients { } #[cfg(feature = "workspaces")] - pub fn workspaces(&mut self) -> Arc { - // TODO: Error handling here isn't great - should throw a user-friendly error & exit - self.workspaces - .get_or_insert_with(|| { - compositor::Compositor::create_workspace_client().expect("to be valid compositor") - }) - .clone() + pub fn workspaces(&mut self) -> ClientResult { + let client = match &self.workspaces { + Some(workspaces) => workspaces.clone(), + None => { + let client = compositor::Compositor::create_workspace_client()?; + self.workspaces.replace(client.clone()); + client + } + }; + + Ok(client) } #[cfg(feature = "music")] @@ -77,29 +84,35 @@ impl Clients { } #[cfg(feature = "notifications")] - pub fn notifications(&mut self) -> Arc { - self.notifications - .get_or_insert_with(|| { - Arc::new(crate::await_sync(async { swaync::Client::new().await })) - }) - .clone() + pub fn notifications(&mut self) -> ClientResult { + let client = match &self.notifications { + Some(client) => client.clone(), + None => { + let client = await_sync(async { swaync::Client::new().await })?; + let client = Arc::new(client); + self.notifications.replace(client.clone()); + client + } + }; + + Ok(client) } #[cfg(feature = "tray")] - pub fn tray(&mut self) -> Arc { - // 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 { - 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() + pub fn tray(&mut self) -> ClientResult { + let client = match &self.tray { + Some(client) => client.clone(), + None => { + let service_name = format!("{}-{}", env!("CARGO_CRATE_NAME"), Ironbar::unique_id()); + + let client = await_sync(async { tray::Client::new(&service_name).await })?; + let client = Arc::new(client); + self.tray.replace(client.clone()); + client + } + }; + + Ok(client) } #[cfg(feature = "upower")] @@ -126,6 +139,14 @@ pub trait ProvidesClient { fn provide(&self) -> Arc; } +/// Types implementing this trait +/// indicate that they provide a singleton client instance of type `T`, +/// which may fail to be created. +pub trait ProvidesFallibleClient { + /// Returns a singleton client instance of type `T`. + fn try_provide(&self) -> ClientResult; +} + /// Generates a `ProvidesClient` impl block on `WidgetContext` /// for the provided `$ty` (first argument) client type. /// @@ -148,3 +169,26 @@ macro_rules! register_client { } }; } + +/// Generates a `ProvidesClient` impl block on `WidgetContext` +/// for the provided `$ty` (first argument) client type. +/// +/// The implementation calls `$method` (second argument) +/// on the `Clients` struct to obtain the client instance. +/// +/// # Example +/// `register_client!(Client, clipboard);` +#[macro_export] +macro_rules! register_fallible_client { + ($ty:ty, $method:ident) => { + impl $crate::clients::ProvidesFallibleClient<$ty> + for $crate::modules::WidgetContext + where + TSend: Clone, + { + fn try_provide(&self) -> color_eyre::Result> { + self.ironbar.clients.borrow_mut().$method() + } + } + }; +} diff --git a/src/clients/swaync/mod.rs b/src/clients/swaync/mod.rs index c7d226ba..173cf735 100644 --- a/src/clients/swaync/mod.rs +++ b/src/clients/swaync/mod.rs @@ -1,6 +1,6 @@ mod dbus; -use crate::{register_client, send, spawn}; +use crate::{register_fallible_client, send, spawn}; use color_eyre::{Report, Result}; use dbus::SwayNcProxy; use serde::Deserialize; @@ -24,9 +24,9 @@ type GetSubscribeData = (bool, bool, u32, bool); impl From for Event { fn from((dnd, cc_open, count, inhibited): (bool, bool, u32, bool)) -> Self { Self { + count, dnd, cc_open, - count, inhibited, } } @@ -40,15 +40,13 @@ pub struct Client { } impl Client { - pub async fn new() -> Self { - let dbus = Box::pin(zbus::Connection::session()) - .await - .expect("failed to create connection to system bus"); + pub async fn new() -> Result { + let dbus = Box::pin(zbus::Connection::session()).await?; - let proxy = SwayNcProxy::new(&dbus).await.unwrap(); + let proxy = SwayNcProxy::new(&dbus).await?; let (tx, rx) = broadcast::channel(8); - let mut stream = proxy.receive_subscribe_v2().await.unwrap(); + let mut stream = proxy.receive_subscribe_v2().await?; { let tx = tx.clone(); @@ -62,7 +60,7 @@ impl Client { }); } - Self { proxy, tx, _rx: rx } + Ok(Self { proxy, tx, _rx: rx }) } pub fn subscribe(&self) -> broadcast::Receiver { @@ -85,4 +83,4 @@ impl Client { } } -register_client!(Client, notifications); +register_fallible_client!(Client, notifications); diff --git a/src/clients/tray.rs b/src/clients/tray.rs index 3b84815e..9315da0a 100644 --- a/src/clients/tray.rs +++ b/src/clients/tray.rs @@ -1,4 +1,4 @@ -use crate::register_client; +use crate::register_fallible_client; pub use system_tray::client::Client; -register_client!(Client, tray); +register_fallible_client!(Client, tray); diff --git a/src/ipc/server.rs b/src/ipc/server.rs index 776efe1d..aa74a610 100644 --- a/src/ipc/server.rs +++ b/src/ipc/server.rs @@ -129,7 +129,7 @@ impl Ipc { ironbar.reload_config(); for output in outputs { - match crate::load_output_bars(ironbar, application, output) { + match crate::load_output_bars(ironbar, application, &output) { Ok(mut bars) => ironbar.bars.borrow_mut().append(&mut bars), Err(err) => error!("{err:?}"), } diff --git a/src/modules/clipboard.rs b/src/modules/clipboard.rs index 6d53e401..ae34a032 100644 --- a/src/modules/clipboard.rs +++ b/src/modules/clipboard.rs @@ -13,7 +13,6 @@ use gtk::prelude::*; use gtk::{Button, EventBox, Image, Label, Orientation, RadioButton, Widget}; use serde::Deserialize; use std::collections::HashMap; -use std::sync::Arc; use tokio::sync::{broadcast, mpsc}; use tracing::{debug, error}; @@ -76,7 +75,7 @@ impl Module