diff --git a/src/bar.rs b/src/bar.rs index c800b7d..e8d3b89 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -7,6 +7,8 @@ use gtk::prelude::*; use gtk::{Application, ApplicationWindow, Orientation}; use tracing::{debug, info}; +/// Creates a new window for a bar, +/// sets it up and adds its widgets. pub fn create_bar( app: &Application, monitor: &Monitor, @@ -53,6 +55,7 @@ pub fn create_bar( Ok(()) } +/// Loads the configured modules onto a bar. fn load_modules( left: >k::Box, center: >k::Box, @@ -101,6 +104,8 @@ fn load_modules( Ok(()) } +/// Adds modules into a provided GTK box, +/// which should be one of its left, center or right containers. fn add_modules(content: >k::Box, modules: Vec, info: &ModuleInfo) -> Result<()> { macro_rules! add_module { ($module:expr, $name:literal) => {{ @@ -127,6 +132,7 @@ fn add_modules(content: >k::Box, modules: Vec, info: &ModuleInfo Ok(()) } +/// Sets up GTK layer shell for a provided aplication window. fn setup_layer_shell(win: &ApplicationWindow, monitor: &Monitor, position: &BarPosition) { gtk_layer_shell::init_for_window(win); gtk_layer_shell::set_monitor(win, monitor); diff --git a/src/collection.rs b/src/collection.rs index 4ecdc1c..40581ce 100644 --- a/src/collection.rs +++ b/src/collection.rs @@ -11,6 +11,7 @@ pub struct Collection { } impl Collection { + /// Creates a new empty collection. pub const fn new() -> Self { Self { keys: vec![], @@ -18,6 +19,7 @@ impl Collection { } } + /// Inserts a new key/value pair at the end of the collection. pub fn insert(&mut self, key: TKey, value: TData) { self.keys.push(key); self.values.push(value); @@ -25,6 +27,8 @@ impl Collection { assert_eq!(self.keys.len(), self.values.len()); } + /// Gets a reference of the value for the specified key + /// if it exists in the collection. pub fn get(&self, key: &TKey) -> Option<&TData> { let index = self.keys.iter().position(|k| k == key); match index { @@ -33,6 +37,8 @@ impl Collection { } } + /// Gets a mutable reference for the value with the specified key + /// if it exists in the collection. pub fn get_mut(&mut self, key: &TKey) -> Option<&mut TData> { let index = self.keys.iter().position(|k| k == key); match index { @@ -41,6 +47,9 @@ impl Collection { } } + /// Removes the key/value from the collection + /// if it exists + /// and returns the removed value. pub fn remove(&mut self, key: &TKey) -> Option { assert_eq!(self.keys.len(), self.values.len()); @@ -53,26 +62,32 @@ impl Collection { } } + /// Gets the length of the collection. pub fn len(&self) -> usize { self.keys.len() } + /// Gets a reference to the first value in the collection. pub fn first(&self) -> Option<&TData> { self.values.first() } + /// Gets the values as a slice. pub fn as_slice(&self) -> &[TData] { self.values.as_slice() } + /// Checks whether the collection is empty. pub fn is_empty(&self) -> bool { self.keys.is_empty() } + /// Gets an iterator for the collection. pub fn iter(&self) -> Iter<'_, TData> { self.values.iter() } + /// Gets a mutable iterator for the collection pub fn iter_mut(&mut self) -> IterMut<'_, TData> { self.values.iter_mut() } diff --git a/src/config.rs b/src/config.rs index 2be7cb0..47bd52f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -71,6 +71,8 @@ const fn default_bar_height() -> i32 { } impl Config { + /// Attempts to load the config file from file, + /// parse it and return a new instance of `Self`. pub fn load() -> Result { let config_path = if let Ok(config_path) = env::var("IRONBAR_CONFIG") { let path = PathBuf::from(config_path); @@ -87,6 +89,10 @@ impl Config { Self::load_file(&config_path) } + /// Attempts to discover the location of the config file + /// by checking each valid format's extension. + /// + /// Returns the path of the first valid match, if any. fn try_find_config() -> Result { let config_dir = config_dir().wrap_err("Failed to locate user config dir")?; @@ -110,6 +116,8 @@ impl Config { } } + /// Loads the config file at the specified path + /// and parses it into `Self` based on its extension. fn load_file(path: &Path) -> Result { let file = fs::read(path).wrap_err("Failed to read config file")?; let extension = path diff --git a/src/icon.rs b/src/icon.rs index 6a240b6..31fdfbf 100644 --- a/src/icon.rs +++ b/src/icon.rs @@ -86,6 +86,10 @@ enum IconLocation { File(PathBuf), } +/// Attempts to get the location of an icon. +/// +/// Handles icons that are part of a GTK theme, icons specified as path +/// and icons for steam games. fn get_icon_location(theme: &IconTheme, app_id: &str, size: i32) -> Option { let has_icon = theme .lookup_icon(app_id, size, IconLookupFlags::empty()) diff --git a/src/logging.rs b/src/logging.rs index f0cb3bf..bdbf5ee 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -26,6 +26,10 @@ impl<'a> MakeWriter<'a> for MakeFileWriter { } } +/// Installs tracing into the current application. +/// +/// The returned `WorkerGuard` must remain in scope +/// for the lifetime of the application for logging to file to work. pub fn install_tracing() -> Result { let fmt_layer = fmt::layer().with_target(true); let filter_layer = EnvFilter::try_from_default_env().or_else(|_| EnvFilter::try_new("info"))?; diff --git a/src/main.rs b/src/main.rs index 477ff8f..058e9ea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -95,6 +95,7 @@ async fn main() -> Result<()> { Ok(()) } +/// Creates each of the bars across each of the (configured) outputs. fn create_bars(app: &Application, display: &Display, config: &Config) -> Result<()> { let outputs = { let sway = get_client(); @@ -120,6 +121,7 @@ fn create_bars(app: &Application, display: &Display, config: &Config) -> Result< info!("Creating bar on '{}'", monitor_name); + // TODO: Could we use an Arc here to avoid cloning? config.monitors.as_ref().map_or_else( || create_bar(app, &monitor, monitor_name, config.clone()), |config| { diff --git a/src/modules/focused.rs b/src/modules/focused.rs index f69334d..1933f14 100644 --- a/src/modules/focused.rs +++ b/src/modules/focused.rs @@ -10,13 +10,17 @@ use tokio::task::spawn_blocking; #[derive(Debug, Deserialize, Clone)] pub struct FocusedModule { + /// Whether to show icon on the bar. #[serde(default = "crate::config::default_true")] show_icon: bool, + /// Whether to show app name on the bar. #[serde(default = "crate::config::default_true")] show_title: bool, + /// Icon size in pixels. #[serde(default = "default_icon_size")] icon_size: i32, + /// GTK icon theme to use. icon_theme: Option, } diff --git a/src/modules/launcher/mod.rs b/src/modules/launcher/mod.rs index 6f340dc..ee9e4c9 100644 --- a/src/modules/launcher/mod.rs +++ b/src/modules/launcher/mod.rs @@ -17,12 +17,17 @@ use tokio::task::spawn_blocking; #[derive(Debug, Deserialize, Clone)] pub struct LauncherModule { + /// List of app IDs (or classes) to always show regardles of open state, + /// in the order specified. favorites: Option>, + /// Whether to show application names on the bar. #[serde(default = "crate::config::default_false")] show_names: bool, + /// Whether to show application icons on the bar. #[serde(default = "crate::config::default_true")] show_icons: bool, + /// Name of the GTK icon theme to use. icon_theme: Option, } diff --git a/src/modules/mpd/mod.rs b/src/modules/mpd/mod.rs index a9ae7b2..3ebe15c 100644 --- a/src/modules/mpd/mod.rs +++ b/src/modules/mpd/mod.rs @@ -23,15 +23,20 @@ use tracing::error; #[derive(Debug, Deserialize, Clone)] pub struct MpdModule { + /// TCP or Unix socket address. #[serde(default = "default_socket")] host: String, + /// Format of current song info to display on the bar. #[serde(default = "default_format")] format: String, + /// Icon to display when playing. #[serde(default = "default_icon_play")] icon_play: Option, + /// Icon to display when paused. #[serde(default = "default_icon_pause")] icon_pause: Option, + /// Path to root of music directory. #[serde(default = "default_music_dir")] music_dir: PathBuf, } diff --git a/src/modules/script.rs b/src/modules/script.rs index 16d9855..5ca937a 100644 --- a/src/modules/script.rs +++ b/src/modules/script.rs @@ -10,7 +10,9 @@ use tracing::{error, instrument}; #[derive(Debug, Deserialize, Clone)] pub struct ScriptModule { + /// Path to script to execute. path: String, + /// Time in milliseconds between executions. #[serde(default = "default_interval")] interval: u64, } diff --git a/src/modules/sysinfo.rs b/src/modules/sysinfo.rs index 3b59902..d947007 100644 --- a/src/modules/sysinfo.rs +++ b/src/modules/sysinfo.rs @@ -11,6 +11,7 @@ use tokio::time::sleep; #[derive(Debug, Deserialize, Clone)] pub struct SysInfoModule { + /// List of formatting strings. format: Vec, } diff --git a/src/modules/workspaces.rs b/src/modules/workspaces.rs index f5f6319..a66945b 100644 --- a/src/modules/workspaces.rs +++ b/src/modules/workspaces.rs @@ -13,8 +13,10 @@ use tracing::{debug, trace}; #[derive(Debug, Deserialize, Clone)] pub struct WorkspacesModule { + /// Map of actual workspace names to custom names. name_map: Option>, + /// Whether to display icons for all monitors. #[serde(default = "crate::config::default_false")] all_monitors: bool, } diff --git a/src/popup.rs b/src/popup.rs index cd4f093..83f2c43 100644 --- a/src/popup.rs +++ b/src/popup.rs @@ -11,6 +11,9 @@ pub struct Popup { } impl Popup { + /// Creates a new popup window. + /// This includes setting up gtk-layer-shell + /// and an empty `gtk::Box` container. pub fn new( name: &str, app: &Application, diff --git a/src/style.rs b/src/style.rs index 8c143e8..4f930c6 100644 --- a/src/style.rs +++ b/src/style.rs @@ -9,6 +9,11 @@ use std::time::Duration; use tokio::spawn; use tracing::{error, info}; +/// Attempts to load CSS file at the given path +/// and attach if to the current GTK application. +/// +/// Installs a file watcher and reloads CSS when +/// write changes are detected on the file. pub fn load_css(style_path: PathBuf) { let provider = CssProvider::new(); diff --git a/src/sway/mod.rs b/src/sway/mod.rs index d38e45c..dd8eeac 100644 --- a/src/sway/mod.rs +++ b/src/sway/mod.rs @@ -55,11 +55,13 @@ pub struct SwayOutput { pub name: String, } +type Broadcaster = Arc>>; + pub struct SwayClient { client: ksway::Client, - workspace_bc: Arc>>, - window_bc: Arc>>, + workspace_bc: Broadcaster, + window_bc: Broadcaster, } impl SwayClient { @@ -189,15 +191,20 @@ pub fn get_client() -> Arc> { Arc::clone(&CLIENT) } +/// Crossbeam channel wrapper +/// which sends messages to all receivers. pub struct UnboundedBroadcast { channels: Vec>, } impl UnboundedBroadcast { + /// Creates a new broadcaster. pub const fn new() -> Self { Self { channels: vec![] } } + /// Creates a new sender/receiver pair. + /// The sender is stored locally and the receiver is returned. pub fn subscribe(&mut self) -> Receiver { let (tx, rx) = crossbeam_channel::unbounded(); @@ -206,6 +213,7 @@ impl UnboundedBroadcast { rx } + /// Attempts to send a messsge to all receivers. pub fn send(&self, message: T) -> Result<(), crossbeam_channel::SendError> { for c in &self.channels { c.send(message.clone())?; diff --git a/src/sway/node.rs b/src/sway/node.rs index ce17dd6..b1ef182 100644 --- a/src/sway/node.rs +++ b/src/sway/node.rs @@ -3,6 +3,9 @@ use color_eyre::Result; use ksway::IpcCommand; impl SwayNode { + /// Gets either the `app_id` or `class` + /// depending on whether this is a native Wayland + /// or xwayland application. pub fn get_id(&self) -> &str { self.app_id.as_ref().map_or_else( || { @@ -17,11 +20,15 @@ impl SwayNode { ) } + /// Checks whether this application + /// is running under xwayland. pub fn is_xwayland(&self) -> bool { self.shell == Some(String::from("xwayland")) } } +/// Recursively checks the provided node for any child application nodes. +/// Returns a list of any found application nodes. fn check_node(node: SwayNode, window_nodes: &mut Vec) { if node.name.is_some() && (node.node_type == "con" || node.node_type == "floating_con") { window_nodes.push(node); @@ -37,6 +44,7 @@ fn check_node(node: SwayNode, window_nodes: &mut Vec) { } impl SwayClient { + /// Gets a flat vector of all currently open windows. pub fn get_open_windows(&mut self) -> Result> { let root_node = self.ipc(IpcCommand::GetTree)?; let root_node = serde_json::from_slice(&root_node)?;