mirror of
https://github.com/Zedfrigg/ironbar.git
synced 2025-07-02 11:11:04 +02:00
refactor: begin restructuring core code to better encapsulate
This is a first pass towards trying to structure things a bit better, with data generally encapsulated under a single hierarchical tree, rather than lots of globals all over the place. Lots of work is still required. The plan is that with this and some more work, #291 should become a lot easier to sort.
This commit is contained in:
parent
08e354e019
commit
b2fa19ab6c
14 changed files with 490 additions and 415 deletions
255
src/main.rs
255
src/main.rs
|
@ -1,12 +1,15 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::cell::RefCell;
|
||||
use std::env;
|
||||
use std::future::Future;
|
||||
use std::path::PathBuf;
|
||||
use std::process::exit;
|
||||
use std::rc::Rc;
|
||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
||||
use std::sync::mpsc;
|
||||
#[cfg(feature = "ipc")]
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
#[cfg(feature = "cli")]
|
||||
|
@ -14,9 +17,11 @@ use clap::Parser;
|
|||
use color_eyre::eyre::Result;
|
||||
use color_eyre::Report;
|
||||
use dirs::config_dir;
|
||||
use glib::PropertySet;
|
||||
use gtk::gdk::Display;
|
||||
use gtk::prelude::*;
|
||||
use gtk::Application;
|
||||
use lazy_static::lazy_static;
|
||||
use tokio::runtime::Handle;
|
||||
use tokio::task::{block_in_place, spawn_blocking};
|
||||
use tracing::{debug, error, info, warn};
|
||||
|
@ -24,10 +29,11 @@ use universal_config::ConfigLoader;
|
|||
|
||||
use clients::wayland;
|
||||
|
||||
use crate::bar::create_bar;
|
||||
use crate::bar::{create_bar, Bar};
|
||||
use crate::config::{Config, MonitorConfig};
|
||||
use crate::error::ExitCode;
|
||||
use crate::global_state::GlobalState;
|
||||
#[cfg(feature = "ipc")]
|
||||
use crate::ironvar::VariableManager;
|
||||
use crate::style::load_css;
|
||||
|
||||
mod bar;
|
||||
|
@ -39,7 +45,6 @@ mod config;
|
|||
mod desktop_file;
|
||||
mod dynamic_value;
|
||||
mod error;
|
||||
mod global_state;
|
||||
mod gtk_helpers;
|
||||
mod image;
|
||||
#[cfg(feature = "ipc")]
|
||||
|
@ -52,7 +57,6 @@ mod modules;
|
|||
mod popup;
|
||||
mod script;
|
||||
mod style;
|
||||
mod unique_id;
|
||||
|
||||
const GTK_APP_ID: &str = "dev.jstanger.ironbar";
|
||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
@ -61,103 +65,160 @@ const VERSION: &str = env!("CARGO_PKG_VERSION");
|
|||
async fn main() {
|
||||
let _guard = logging::install_logging();
|
||||
|
||||
let global_state = Rc::new(RefCell::new(GlobalState::new()));
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "cli")] {
|
||||
run_with_args(global_state).await;
|
||||
run_with_args().await;
|
||||
} else {
|
||||
start_ironbar(global_state);
|
||||
start_ironbar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "cli")]
|
||||
async fn run_with_args(global_state: Rc<RefCell<GlobalState>>) {
|
||||
async fn run_with_args() {
|
||||
let args = cli::Args::parse();
|
||||
|
||||
match args.command {
|
||||
Some(command) => {
|
||||
let ipc = ipc::Ipc::new(global_state);
|
||||
let ipc = ipc::Ipc::new();
|
||||
match ipc.send(command).await {
|
||||
Ok(res) => cli::handle_response(res),
|
||||
Err(err) => error!("{err:?}"),
|
||||
};
|
||||
}
|
||||
None => start_ironbar(global_state),
|
||||
None => start_ironbar(),
|
||||
}
|
||||
}
|
||||
|
||||
fn start_ironbar(global_state: Rc<RefCell<GlobalState>>) {
|
||||
info!("Ironbar version {}", VERSION);
|
||||
info!("Starting application");
|
||||
static COUNTER: AtomicUsize = AtomicUsize::new(1);
|
||||
|
||||
let app = Application::builder().application_id(GTK_APP_ID).build();
|
||||
let _ = wayland::get_client(); // force-init
|
||||
#[cfg(feature = "ipc")]
|
||||
lazy_static! {
|
||||
static ref VARIABLE_MANAGER: Arc<RwLock<VariableManager>> = arc_rw!(VariableManager::new());
|
||||
}
|
||||
|
||||
let running = Rc::new(Cell::new(false));
|
||||
#[derive(Debug)]
|
||||
pub struct Ironbar {
|
||||
bars: Rc<RefCell<Vec<Bar>>>,
|
||||
}
|
||||
|
||||
app.connect_activate(move |app| {
|
||||
if running.get() {
|
||||
info!("Ironbar already running, returning");
|
||||
return;
|
||||
impl Ironbar {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
bars: Rc::new(RefCell::new(vec![])),
|
||||
}
|
||||
}
|
||||
|
||||
running.set(true);
|
||||
fn start(self) {
|
||||
info!("Ironbar version {}", VERSION);
|
||||
info!("Starting application");
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "ipc")] {
|
||||
let ipc = ipc::Ipc::new(global_state.clone());
|
||||
ipc.start(app);
|
||||
let app = Application::builder().application_id(GTK_APP_ID).build();
|
||||
|
||||
let running = AtomicBool::new(false);
|
||||
|
||||
let instance = Rc::new(self);
|
||||
|
||||
// force start wayland client ahead of ui
|
||||
let wl = wayland::get_client();
|
||||
lock!(wl).roundtrip();
|
||||
|
||||
app.connect_activate(move |app| {
|
||||
if running.load(Ordering::Relaxed) {
|
||||
info!("Ironbar already running, returning");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
load_interface(app, &global_state);
|
||||
running.set(true);
|
||||
|
||||
let style_path = env::var("IRONBAR_CSS").ok().map_or_else(
|
||||
|| {
|
||||
config_dir().map_or_else(
|
||||
|| {
|
||||
let report = Report::msg("Failed to locate user config dir");
|
||||
error!("{:?}", report);
|
||||
exit(ExitCode::CreateBars as i32);
|
||||
},
|
||||
|dir| dir.join("ironbar").join("style.css"),
|
||||
)
|
||||
},
|
||||
PathBuf::from,
|
||||
);
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "ipc")] {
|
||||
let ipc = ipc::Ipc::new();
|
||||
ipc.start(app, instance.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if style_path.exists() {
|
||||
load_css(style_path);
|
||||
}
|
||||
*instance.bars.borrow_mut() = load_interface(app);
|
||||
|
||||
let (tx, rx) = mpsc::channel();
|
||||
let style_path = env::var("IRONBAR_CSS").ok().map_or_else(
|
||||
|| {
|
||||
config_dir().map_or_else(
|
||||
|| {
|
||||
let report = Report::msg("Failed to locate user config dir");
|
||||
error!("{:?}", report);
|
||||
exit(ExitCode::CreateBars as i32);
|
||||
},
|
||||
|dir| dir.join("ironbar").join("style.css"),
|
||||
)
|
||||
},
|
||||
PathBuf::from,
|
||||
);
|
||||
|
||||
#[cfg(feature = "ipc")]
|
||||
let ipc_path = ipc.path().to_path_buf();
|
||||
spawn_blocking(move || {
|
||||
rx.recv().expect("to receive from channel");
|
||||
if style_path.exists() {
|
||||
load_css(style_path);
|
||||
}
|
||||
|
||||
info!("Shutting down");
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
#[cfg(feature = "ipc")]
|
||||
ipc::Ipc::shutdown(ipc_path);
|
||||
let ipc_path = ipc.path().to_path_buf();
|
||||
spawn_blocking(move || {
|
||||
rx.recv().expect("to receive from channel");
|
||||
|
||||
exit(0);
|
||||
info!("Shutting down");
|
||||
|
||||
#[cfg(feature = "ipc")]
|
||||
ipc::Ipc::shutdown(ipc_path);
|
||||
|
||||
exit(0);
|
||||
});
|
||||
|
||||
ctrlc::set_handler(move || tx.send(()).expect("Could not send signal on channel."))
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
|
||||
// TODO: Start wayland client - listen for outputs
|
||||
// All bar loading should happen as an event response to this
|
||||
});
|
||||
|
||||
ctrlc::set_handler(move || tx.send(()).expect("Could not send signal on channel."))
|
||||
.expect("Error setting Ctrl-C handler");
|
||||
});
|
||||
// Ignore CLI args
|
||||
// Some are provided by swaybar_config but not currently supported
|
||||
app.run_with_args(&Vec::<&str>::new());
|
||||
}
|
||||
|
||||
// Ignore CLI args
|
||||
// Some are provided by swaybar_config but not currently supported
|
||||
app.run_with_args(&Vec::<&str>::new());
|
||||
/// Gets a `usize` ID value that is unique to the entire Ironbar instance.
|
||||
/// This is just a static `AtomicUsize` that increments every time this function is called.
|
||||
pub fn unique_id() -> usize {
|
||||
COUNTER.fetch_add(1, Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// Gets the `Ironvar` manager singleton.
|
||||
#[cfg(feature = "ipc")]
|
||||
#[must_use]
|
||||
pub fn variable_manager() -> Arc<RwLock<VariableManager>> {
|
||||
VARIABLE_MANAGER.clone()
|
||||
}
|
||||
|
||||
/// Gets a clone of a bar by its unique name.
|
||||
///
|
||||
/// Since the bar contains mostly GTK objects,
|
||||
/// the clone is cheap enough to not worry about.
|
||||
#[must_use]
|
||||
pub fn bar_by_name(&self, name: &str) -> Option<Bar> {
|
||||
self.bars
|
||||
.borrow()
|
||||
.iter()
|
||||
.find(|&bar| bar.name() == name)
|
||||
.cloned()
|
||||
}
|
||||
}
|
||||
|
||||
fn start_ironbar() {
|
||||
let ironbar = Ironbar::new();
|
||||
ironbar.start();
|
||||
}
|
||||
|
||||
/// Loads the Ironbar config and interface.
|
||||
pub fn load_interface(app: &Application, global_state: &Rc<RefCell<GlobalState>>) {
|
||||
pub fn load_interface(app: &Application) -> Vec<Bar> {
|
||||
let display = Display::default().map_or_else(
|
||||
|| {
|
||||
let report = Report::msg("Failed to get default GTK display");
|
||||
|
@ -185,7 +246,7 @@ pub fn load_interface(app: &Application, global_state: &Rc<RefCell<GlobalState>>
|
|||
|
||||
#[cfg(feature = "ipc")]
|
||||
if let Some(ironvars) = config.ironvar_defaults.take() {
|
||||
let variable_manager = ironvar::get_variable_manager();
|
||||
let variable_manager = Ironbar::variable_manager();
|
||||
for (k, v) in ironvars {
|
||||
if write_lock!(variable_manager).set(k.clone(), v).is_err() {
|
||||
warn!("Ignoring invalid ironvar: '{k}'");
|
||||
|
@ -193,21 +254,20 @@ pub fn load_interface(app: &Application, global_state: &Rc<RefCell<GlobalState>>
|
|||
}
|
||||
}
|
||||
|
||||
if let Err(err) = create_bars(app, &display, &config, global_state) {
|
||||
error!("{:?}", err);
|
||||
exit(ExitCode::CreateBars as i32);
|
||||
match create_bars(app, &display, &config) {
|
||||
Ok(bars) => {
|
||||
debug!("Created {} bars", bars.len());
|
||||
bars
|
||||
}
|
||||
Err(err) => {
|
||||
error!("{:?}", err);
|
||||
exit(ExitCode::CreateBars as i32);
|
||||
}
|
||||
}
|
||||
|
||||
debug!("Created bars");
|
||||
}
|
||||
|
||||
/// Creates each of the bars across each of the (configured) outputs.
|
||||
fn create_bars(
|
||||
app: &Application,
|
||||
display: &Display,
|
||||
config: &Config,
|
||||
global_state: &Rc<RefCell<GlobalState>>,
|
||||
) -> Result<()> {
|
||||
fn create_bars(app: &Application, display: &Display, config: &Config) -> Result<Vec<Bar>> {
|
||||
let wl = wayland::get_client();
|
||||
let outputs = lock!(wl).get_outputs();
|
||||
|
||||
|
@ -216,6 +276,7 @@ fn create_bars(
|
|||
|
||||
let num_monitors = display.n_monitors();
|
||||
|
||||
let mut all_bars = vec![];
|
||||
for i in 0..num_monitors {
|
||||
let monitor = display
|
||||
.monitor(i)
|
||||
|
@ -228,33 +289,35 @@ fn create_bars(
|
|||
continue;
|
||||
};
|
||||
|
||||
config.monitors.as_ref().map_or_else(
|
||||
|| {
|
||||
info!("Creating bar on '{}'", monitor_name);
|
||||
create_bar(app, &monitor, monitor_name, config.clone(), global_state)
|
||||
},
|
||||
|config| {
|
||||
let config = config.get(monitor_name);
|
||||
match &config {
|
||||
Some(MonitorConfig::Single(config)) => {
|
||||
info!("Creating bar on '{}'", monitor_name);
|
||||
create_bar(app, &monitor, monitor_name, config.clone(), global_state)
|
||||
}
|
||||
Some(MonitorConfig::Multiple(configs)) => {
|
||||
for config in configs {
|
||||
info!("Creating bar on '{}'", monitor_name);
|
||||
create_bar(app, &monitor, monitor_name, config.clone(), global_state)?;
|
||||
}
|
||||
let mut bars = match config
|
||||
.monitors
|
||||
.as_ref()
|
||||
.and_then(|config| config.get(monitor_name))
|
||||
{
|
||||
Some(MonitorConfig::Single(config)) => {
|
||||
vec![create_bar(
|
||||
app,
|
||||
&monitor,
|
||||
monitor_name.to_string(),
|
||||
config.clone(),
|
||||
)?]
|
||||
}
|
||||
Some(MonitorConfig::Multiple(configs)) => configs
|
||||
.iter()
|
||||
.map(|config| create_bar(app, &monitor, monitor_name.to_string(), config.clone()))
|
||||
.collect::<Result<_>>()?,
|
||||
None => vec![create_bar(
|
||||
app,
|
||||
&monitor,
|
||||
monitor_name.to_string(),
|
||||
config.clone(),
|
||||
)?],
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => Ok(()),
|
||||
}
|
||||
},
|
||||
)?;
|
||||
all_bars.append(&mut bars);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(all_bars)
|
||||
}
|
||||
|
||||
/// Blocks on a `Future` until it resolves.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue