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

docs: add some rustdoc comments throughout

This commit is contained in:
Jake Stanger 2022-08-28 16:57:41 +01:00
parent 5d319e91f2
commit 78e30b39fe
16 changed files with 84 additions and 2 deletions

View file

@ -7,6 +7,8 @@ use gtk::prelude::*;
use gtk::{Application, ApplicationWindow, Orientation}; use gtk::{Application, ApplicationWindow, Orientation};
use tracing::{debug, info}; use tracing::{debug, info};
/// Creates a new window for a bar,
/// sets it up and adds its widgets.
pub fn create_bar( pub fn create_bar(
app: &Application, app: &Application,
monitor: &Monitor, monitor: &Monitor,
@ -53,6 +55,7 @@ pub fn create_bar(
Ok(()) Ok(())
} }
/// Loads the configured modules onto a bar.
fn load_modules( fn load_modules(
left: &gtk::Box, left: &gtk::Box,
center: &gtk::Box, center: &gtk::Box,
@ -101,6 +104,8 @@ fn load_modules(
Ok(()) Ok(())
} }
/// Adds modules into a provided GTK box,
/// which should be one of its left, center or right containers.
fn add_modules(content: &gtk::Box, modules: Vec<ModuleConfig>, info: &ModuleInfo) -> Result<()> { fn add_modules(content: &gtk::Box, modules: Vec<ModuleConfig>, info: &ModuleInfo) -> Result<()> {
macro_rules! add_module { macro_rules! add_module {
($module:expr, $name:literal) => {{ ($module:expr, $name:literal) => {{
@ -127,6 +132,7 @@ fn add_modules(content: &gtk::Box, modules: Vec<ModuleConfig>, info: &ModuleInfo
Ok(()) Ok(())
} }
/// Sets up GTK layer shell for a provided aplication window.
fn setup_layer_shell(win: &ApplicationWindow, monitor: &Monitor, position: &BarPosition) { fn setup_layer_shell(win: &ApplicationWindow, monitor: &Monitor, position: &BarPosition) {
gtk_layer_shell::init_for_window(win); gtk_layer_shell::init_for_window(win);
gtk_layer_shell::set_monitor(win, monitor); gtk_layer_shell::set_monitor(win, monitor);

View file

@ -11,6 +11,7 @@ pub struct Collection<TKey, TData> {
} }
impl<TKey: PartialEq, TData> Collection<TKey, TData> { impl<TKey: PartialEq, TData> Collection<TKey, TData> {
/// Creates a new empty collection.
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
keys: vec![], keys: vec![],
@ -18,6 +19,7 @@ impl<TKey: PartialEq, TData> Collection<TKey, TData> {
} }
} }
/// Inserts a new key/value pair at the end of the collection.
pub fn insert(&mut self, key: TKey, value: TData) { pub fn insert(&mut self, key: TKey, value: TData) {
self.keys.push(key); self.keys.push(key);
self.values.push(value); self.values.push(value);
@ -25,6 +27,8 @@ impl<TKey: PartialEq, TData> Collection<TKey, TData> {
assert_eq!(self.keys.len(), self.values.len()); 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> { pub fn get(&self, key: &TKey) -> Option<&TData> {
let index = self.keys.iter().position(|k| k == key); let index = self.keys.iter().position(|k| k == key);
match index { match index {
@ -33,6 +37,8 @@ impl<TKey: PartialEq, TData> Collection<TKey, TData> {
} }
} }
/// 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> { pub fn get_mut(&mut self, key: &TKey) -> Option<&mut TData> {
let index = self.keys.iter().position(|k| k == key); let index = self.keys.iter().position(|k| k == key);
match index { match index {
@ -41,6 +47,9 @@ impl<TKey: PartialEq, TData> Collection<TKey, TData> {
} }
} }
/// Removes the key/value from the collection
/// if it exists
/// and returns the removed value.
pub fn remove(&mut self, key: &TKey) -> Option<TData> { pub fn remove(&mut self, key: &TKey) -> Option<TData> {
assert_eq!(self.keys.len(), self.values.len()); assert_eq!(self.keys.len(), self.values.len());
@ -53,26 +62,32 @@ impl<TKey: PartialEq, TData> Collection<TKey, TData> {
} }
} }
/// Gets the length of the collection.
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.keys.len() self.keys.len()
} }
/// Gets a reference to the first value in the collection.
pub fn first(&self) -> Option<&TData> { pub fn first(&self) -> Option<&TData> {
self.values.first() self.values.first()
} }
/// Gets the values as a slice.
pub fn as_slice(&self) -> &[TData] { pub fn as_slice(&self) -> &[TData] {
self.values.as_slice() self.values.as_slice()
} }
/// Checks whether the collection is empty.
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.keys.is_empty() self.keys.is_empty()
} }
/// Gets an iterator for the collection.
pub fn iter(&self) -> Iter<'_, TData> { pub fn iter(&self) -> Iter<'_, TData> {
self.values.iter() self.values.iter()
} }
/// Gets a mutable iterator for the collection
pub fn iter_mut(&mut self) -> IterMut<'_, TData> { pub fn iter_mut(&mut self) -> IterMut<'_, TData> {
self.values.iter_mut() self.values.iter_mut()
} }

View file

@ -71,6 +71,8 @@ const fn default_bar_height() -> i32 {
} }
impl Config { impl Config {
/// Attempts to load the config file from file,
/// parse it and return a new instance of `Self`.
pub fn load() -> Result<Self> { pub fn load() -> Result<Self> {
let config_path = if let Ok(config_path) = env::var("IRONBAR_CONFIG") { let config_path = if let Ok(config_path) = env::var("IRONBAR_CONFIG") {
let path = PathBuf::from(config_path); let path = PathBuf::from(config_path);
@ -87,6 +89,10 @@ impl Config {
Self::load_file(&config_path) 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<PathBuf> { fn try_find_config() -> Result<PathBuf> {
let config_dir = config_dir().wrap_err("Failed to locate user config dir")?; 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<Self> { fn load_file(path: &Path) -> Result<Self> {
let file = fs::read(path).wrap_err("Failed to read config file")?; let file = fs::read(path).wrap_err("Failed to read config file")?;
let extension = path let extension = path

View file

@ -86,6 +86,10 @@ enum IconLocation {
File(PathBuf), 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<IconLocation> { fn get_icon_location(theme: &IconTheme, app_id: &str, size: i32) -> Option<IconLocation> {
let has_icon = theme let has_icon = theme
.lookup_icon(app_id, size, IconLookupFlags::empty()) .lookup_icon(app_id, size, IconLookupFlags::empty())

View file

@ -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<WorkerGuard> { pub fn install_tracing() -> Result<WorkerGuard> {
let fmt_layer = fmt::layer().with_target(true); let fmt_layer = fmt::layer().with_target(true);
let filter_layer = EnvFilter::try_from_default_env().or_else(|_| EnvFilter::try_new("info"))?; let filter_layer = EnvFilter::try_from_default_env().or_else(|_| EnvFilter::try_new("info"))?;

View file

@ -95,6 +95,7 @@ async fn main() -> Result<()> {
Ok(()) Ok(())
} }
/// Creates each of the bars across each of the (configured) outputs.
fn create_bars(app: &Application, display: &Display, config: &Config) -> Result<()> { fn create_bars(app: &Application, display: &Display, config: &Config) -> Result<()> {
let outputs = { let outputs = {
let sway = get_client(); let sway = get_client();
@ -120,6 +121,7 @@ fn create_bars(app: &Application, display: &Display, config: &Config) -> Result<
info!("Creating bar on '{}'", monitor_name); info!("Creating bar on '{}'", monitor_name);
// TODO: Could we use an Arc<Config> here to avoid cloning?
config.monitors.as_ref().map_or_else( config.monitors.as_ref().map_or_else(
|| create_bar(app, &monitor, monitor_name, config.clone()), || create_bar(app, &monitor, monitor_name, config.clone()),
|config| { |config| {

View file

@ -10,13 +10,17 @@ use tokio::task::spawn_blocking;
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
pub struct FocusedModule { pub struct FocusedModule {
/// Whether to show icon on the bar.
#[serde(default = "crate::config::default_true")] #[serde(default = "crate::config::default_true")]
show_icon: bool, show_icon: bool,
/// Whether to show app name on the bar.
#[serde(default = "crate::config::default_true")] #[serde(default = "crate::config::default_true")]
show_title: bool, show_title: bool,
/// Icon size in pixels.
#[serde(default = "default_icon_size")] #[serde(default = "default_icon_size")]
icon_size: i32, icon_size: i32,
/// GTK icon theme to use.
icon_theme: Option<String>, icon_theme: Option<String>,
} }

View file

@ -17,12 +17,17 @@ use tokio::task::spawn_blocking;
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
pub struct LauncherModule { pub struct LauncherModule {
/// List of app IDs (or classes) to always show regardles of open state,
/// in the order specified.
favorites: Option<Vec<String>>, favorites: Option<Vec<String>>,
/// Whether to show application names on the bar.
#[serde(default = "crate::config::default_false")] #[serde(default = "crate::config::default_false")]
show_names: bool, show_names: bool,
/// Whether to show application icons on the bar.
#[serde(default = "crate::config::default_true")] #[serde(default = "crate::config::default_true")]
show_icons: bool, show_icons: bool,
/// Name of the GTK icon theme to use.
icon_theme: Option<String>, icon_theme: Option<String>,
} }

View file

@ -23,15 +23,20 @@ use tracing::error;
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
pub struct MpdModule { pub struct MpdModule {
/// TCP or Unix socket address.
#[serde(default = "default_socket")] #[serde(default = "default_socket")]
host: String, host: String,
/// Format of current song info to display on the bar.
#[serde(default = "default_format")] #[serde(default = "default_format")]
format: String, format: String,
/// Icon to display when playing.
#[serde(default = "default_icon_play")] #[serde(default = "default_icon_play")]
icon_play: Option<String>, icon_play: Option<String>,
/// Icon to display when paused.
#[serde(default = "default_icon_pause")] #[serde(default = "default_icon_pause")]
icon_pause: Option<String>, icon_pause: Option<String>,
/// Path to root of music directory.
#[serde(default = "default_music_dir")] #[serde(default = "default_music_dir")]
music_dir: PathBuf, music_dir: PathBuf,
} }

View file

@ -10,7 +10,9 @@ use tracing::{error, instrument};
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
pub struct ScriptModule { pub struct ScriptModule {
/// Path to script to execute.
path: String, path: String,
/// Time in milliseconds between executions.
#[serde(default = "default_interval")] #[serde(default = "default_interval")]
interval: u64, interval: u64,
} }

View file

@ -11,6 +11,7 @@ use tokio::time::sleep;
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
pub struct SysInfoModule { pub struct SysInfoModule {
/// List of formatting strings.
format: Vec<String>, format: Vec<String>,
} }

View file

@ -13,8 +13,10 @@ use tracing::{debug, trace};
#[derive(Debug, Deserialize, Clone)] #[derive(Debug, Deserialize, Clone)]
pub struct WorkspacesModule { pub struct WorkspacesModule {
/// Map of actual workspace names to custom names.
name_map: Option<HashMap<String, String>>, name_map: Option<HashMap<String, String>>,
/// Whether to display icons for all monitors.
#[serde(default = "crate::config::default_false")] #[serde(default = "crate::config::default_false")]
all_monitors: bool, all_monitors: bool,
} }

View file

@ -11,6 +11,9 @@ pub struct Popup {
} }
impl Popup { impl Popup {
/// Creates a new popup window.
/// This includes setting up gtk-layer-shell
/// and an empty `gtk::Box` container.
pub fn new( pub fn new(
name: &str, name: &str,
app: &Application, app: &Application,

View file

@ -9,6 +9,11 @@ use std::time::Duration;
use tokio::spawn; use tokio::spawn;
use tracing::{error, info}; 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) { pub fn load_css(style_path: PathBuf) {
let provider = CssProvider::new(); let provider = CssProvider::new();

View file

@ -55,11 +55,13 @@ pub struct SwayOutput {
pub name: String, pub name: String,
} }
type Broadcaster<T> = Arc<Mutex<UnboundedBroadcast<T>>>;
pub struct SwayClient { pub struct SwayClient {
client: ksway::Client, client: ksway::Client,
workspace_bc: Arc<Mutex<UnboundedBroadcast<WorkspaceEvent>>>, workspace_bc: Broadcaster<WorkspaceEvent>,
window_bc: Arc<Mutex<UnboundedBroadcast<WindowEvent>>>, window_bc: Broadcaster<WindowEvent>,
} }
impl SwayClient { impl SwayClient {
@ -189,15 +191,20 @@ pub fn get_client() -> Arc<Mutex<SwayClient>> {
Arc::clone(&CLIENT) Arc::clone(&CLIENT)
} }
/// Crossbeam channel wrapper
/// which sends messages to all receivers.
pub struct UnboundedBroadcast<T> { pub struct UnboundedBroadcast<T> {
channels: Vec<crossbeam_channel::Sender<T>>, channels: Vec<crossbeam_channel::Sender<T>>,
} }
impl<T: 'static + Clone + Send + Sync> UnboundedBroadcast<T> { impl<T: 'static + Clone + Send + Sync> UnboundedBroadcast<T> {
/// Creates a new broadcaster.
pub const fn new() -> Self { pub const fn new() -> Self {
Self { channels: vec![] } 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<T> { pub fn subscribe(&mut self) -> Receiver<T> {
let (tx, rx) = crossbeam_channel::unbounded(); let (tx, rx) = crossbeam_channel::unbounded();
@ -206,6 +213,7 @@ impl<T: 'static + Clone + Send + Sync> UnboundedBroadcast<T> {
rx rx
} }
/// Attempts to send a messsge to all receivers.
pub fn send(&self, message: T) -> Result<(), crossbeam_channel::SendError<T>> { pub fn send(&self, message: T) -> Result<(), crossbeam_channel::SendError<T>> {
for c in &self.channels { for c in &self.channels {
c.send(message.clone())?; c.send(message.clone())?;

View file

@ -3,6 +3,9 @@ use color_eyre::Result;
use ksway::IpcCommand; use ksway::IpcCommand;
impl SwayNode { 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 { pub fn get_id(&self) -> &str {
self.app_id.as_ref().map_or_else( 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 { pub fn is_xwayland(&self) -> bool {
self.shell == Some(String::from("xwayland")) 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<SwayNode>) { fn check_node(node: SwayNode, window_nodes: &mut Vec<SwayNode>) {
if node.name.is_some() && (node.node_type == "con" || node.node_type == "floating_con") { if node.name.is_some() && (node.node_type == "con" || node.node_type == "floating_con") {
window_nodes.push(node); window_nodes.push(node);
@ -37,6 +44,7 @@ fn check_node(node: SwayNode, window_nodes: &mut Vec<SwayNode>) {
} }
impl SwayClient { impl SwayClient {
/// Gets a flat vector of all currently open windows.
pub fn get_open_windows(&mut self) -> Result<Vec<SwayNode>> { pub fn get_open_windows(&mut self) -> Result<Vec<SwayNode>> {
let root_node = self.ipc(IpcCommand::GetTree)?; let root_node = self.ipc(IpcCommand::GetTree)?;
let root_node = serde_json::from_slice(&root_node)?; let root_node = serde_json::from_slice(&root_node)?;