1
0
Fork 0
mirror of https://github.com/Zedfrigg/ironbar.git synced 2025-04-20 11:54:23 +02:00
ironbar/src/main.rs

184 lines
5.3 KiB
Rust
Raw Normal View History

2022-08-14 14:30:13 +01:00
mod bar;
mod bridge_channel;
2022-08-14 14:30:13 +01:00
mod config;
2022-08-14 20:40:11 +01:00
mod icon;
mod logging;
2022-08-14 14:30:13 +01:00
mod modules;
mod popup;
mod script;
2022-08-14 14:30:13 +01:00
mod style;
2022-08-14 20:40:11 +01:00
mod sway;
mod wayland;
2022-08-14 14:30:13 +01:00
use crate::bar::create_bar;
use crate::config::{Config, MonitorConfig};
2022-08-14 14:30:13 +01:00
use crate::style::load_css;
use color_eyre::eyre::Result;
use color_eyre::Report;
2022-08-14 14:30:13 +01:00
use dirs::config_dir;
use gtk::gdk::Display;
2022-08-14 14:30:13 +01:00
use gtk::prelude::*;
use gtk::Application;
use std::future::Future;
use std::path::PathBuf;
use std::process::exit;
2022-10-16 13:54:48 +01:00
use std::{env, panic};
use tokio::runtime::Handle;
use tokio::task::block_in_place;
use crate::logging::install_tracing;
2022-10-16 13:54:48 +01:00
use tracing::{debug, error, info};
use wayland::WaylandClient;
const VERSION: &str = env!("CARGO_PKG_VERSION");
2022-08-14 14:30:13 +01:00
#[repr(i32)]
2022-10-16 13:54:48 +01:00
enum ErrorCode {
GtkDisplay = 1,
CreateBars = 2,
Config = 3,
}
2022-08-14 14:30:13 +01:00
#[tokio::main]
async fn main() -> Result<()> {
// Disable backtraces by default
if env::var("RUST_LIB_BACKTRACE").is_err() {
env::set_var("RUST_LIB_BACKTRACE", "0");
}
// keep guard in scope
// otherwise file logging drops
let _guard = install_tracing()?;
let hook_builder = color_eyre::config::HookBuilder::default();
let (panic_hook, eyre_hook) = hook_builder.into_hooks();
eyre_hook.install()?;
// custom hook allows tracing_appender to capture panics
panic::set_hook(Box::new(move |panic_info| {
2022-10-16 13:54:48 +01:00
error!("{}", panic_hook.panic_report(panic_info));
}));
info!("Ironbar version {}", VERSION);
info!("Starting application");
let wayland_client = wayland::get_client().await;
2022-08-14 14:30:13 +01:00
let app = Application::builder()
.application_id("dev.jstanger.ironbar")
2022-08-14 14:30:13 +01:00
.build();
app.connect_activate(move |app| {
let display = Display::default().map_or_else(
|| {
let report = Report::msg("Failed to get default GTK display");
error!("{:?}", report);
2022-10-16 13:54:48 +01:00
exit(ErrorCode::GtkDisplay as i32)
},
|display| display,
);
let config = match Config::load() {
Ok(config) => config,
Err(err) => {
error!("{:?}", err);
2022-10-16 13:54:48 +01:00
exit(ErrorCode::Config as i32)
}
};
debug!("Loaded config file");
2022-10-10 21:59:44 +01:00
if let Err(err) = create_bars(app, &display, wayland_client, &config) {
error!("{:?}", err);
2022-10-16 13:54:48 +01:00
exit(ErrorCode::CreateBars as i32);
2022-08-14 14:30:13 +01:00
}
debug!("Created bars");
let style_path = env::var("IRONBAR_CSS")
.ok()
.map(PathBuf::from)
.unwrap_or_else(|| {
config_dir().map_or_else(
|| {
let report = Report::msg("Failed to locate user config dir");
error!("{:?}", report);
exit(ErrorCode::CreateBars as i32);
},
|dir| dir.join("ironbar").join("style.css"),
)
});
2022-08-14 14:30:13 +01:00
if style_path.exists() {
load_css(style_path);
}
});
// Ignore CLI args
// Some are provided by swaybar_config but not currently supported
app.run_with_args(&Vec::<&str>::new());
Ok(())
}
/// Creates each of the bars across each of the (configured) outputs.
2022-10-10 21:59:44 +01:00
fn create_bars(
app: &Application,
display: &Display,
wl: &WaylandClient,
config: &Config,
) -> Result<()> {
let outputs = wl.outputs.as_slice();
debug!("Received {} outputs from Wayland", outputs.len());
debug!("Outputs: {:?}", outputs);
2022-08-25 21:53:57 +01:00
let num_monitors = display.n_monitors();
for i in 0..num_monitors {
let monitor = display.monitor(i).ok_or_else(|| Report::msg("GTK and Sway are reporting a different set of outputs - this is a severe bug and should never happen"))?;
let output = outputs.get(i as usize).ok_or_else(|| Report::msg("GTK and Sway are reporting a different set of outputs - this is a severe bug and should never happen"))?;
let monitor_name = &output.name;
// TODO: Could we use an Arc<Config> or `Cow<Config>` here to avoid cloning?
config.monitors.as_ref().map_or_else(
|| {
info!("Creating bar on '{}'", monitor_name);
create_bar(app, &monitor, monitor_name, config.clone())
},
|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())
}
Some(MonitorConfig::Multiple(configs)) => {
for config in configs {
info!("Creating bar on '{}'", monitor_name);
create_bar(app, &monitor, monitor_name, config.clone())?;
}
Ok(())
}
_ => Ok(()),
}
},
)?;
}
Ok(())
2022-08-14 14:30:13 +01:00
}
/// Blocks on a `Future` until it resolves.
///
/// This is not an `async` operation
/// so can be used outside of an async function.
///
/// Do note it must be called from within a Tokio runtime still.
///
/// Use sparingly! Prefer async functions wherever possible.
pub fn await_sync<F: Future>(f: F) -> F::Output {
block_in_place(|| Handle::current().block_on(f))
}