2022-08-14 14:30:13 +01:00
mod bar ;
2022-09-25 22:49:00 +01:00
mod bridge_channel ;
2022-08-14 14:30:13 +01:00
mod config ;
2022-08-14 20:40:11 +01:00
mod icon ;
2022-08-21 23:36:07 +01:00
mod logging ;
2022-08-14 14:30:13 +01:00
mod modules ;
mod popup ;
2022-10-16 22:16:48 +01:00
mod script ;
2022-08-14 14:30:13 +01:00
mod style ;
2022-08-14 20:40:11 +01:00
mod sway ;
2022-09-27 20:24:16 +01:00
mod wayland ;
2022-08-14 14:30:13 +01:00
use crate ::bar ::create_bar ;
2022-08-15 17:06:42 +01:00
use crate ::config ::{ Config , MonitorConfig } ;
2022-08-14 14:30:13 +01:00
use crate ::style ::load_css ;
2022-08-21 23:36:07 +01:00
use color_eyre ::eyre ::Result ;
use color_eyre ::Report ;
2022-08-14 14:30:13 +01:00
use dirs ::config_dir ;
2022-08-21 23:36:07 +01:00
use gtk ::gdk ::Display ;
2022-08-14 14:30:13 +01:00
use gtk ::prelude ::* ;
2022-08-21 23:36:07 +01:00
use gtk ::Application ;
2022-09-25 22:49:00 +01:00
use std ::future ::Future ;
2022-11-01 13:25:46 +00:00
use std ::path ::PathBuf ;
2022-08-21 23:36:07 +01:00
use std ::process ::exit ;
2022-10-16 13:54:48 +01:00
use std ::{ env , panic } ;
2022-09-25 22:49:00 +01:00
use tokio ::runtime ::Handle ;
use tokio ::task ::block_in_place ;
2022-08-21 23:36:07 +01:00
use crate ::logging ::install_tracing ;
2022-10-16 13:54:48 +01:00
use tracing ::{ debug , error , info } ;
2022-10-04 23:26:07 +01:00
use wayland ::WaylandClient ;
2022-08-21 23:36:07 +01:00
const VERSION : & str = env! ( " CARGO_PKG_VERSION " ) ;
2022-08-14 14:30:13 +01:00
2022-10-16 12:58:11 +01:00
#[ repr(i32) ]
2022-10-16 13:54:48 +01:00
enum ErrorCode {
GtkDisplay = 1 ,
CreateBars = 2 ,
Config = 3 ,
2022-10-16 12:58:11 +01:00
}
2022-08-14 14:30:13 +01:00
#[ tokio::main ]
2022-08-21 23:36:07 +01:00
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 ( ) ? ;
2022-10-16 13:42:35 +01:00
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 ) ) ;
2022-10-16 13:42:35 +01:00
} ) ) ;
2022-08-21 23:36:07 +01:00
info! ( " Ironbar version {} " , VERSION ) ;
info! ( " Starting application " ) ;
2022-10-04 23:26:07 +01:00
let wayland_client = wayland ::get_client ( ) . await ;
2022-08-14 14:30:13 +01:00
let app = Application ::builder ( )
2022-08-21 23:36:07 +01:00
. application_id ( " dev.jstanger.ironbar " )
2022-08-14 14:30:13 +01:00
. build ( ) ;
2022-08-14 16:23:41 +01:00
app . connect_activate ( move | app | {
2022-09-25 22:49:00 +01:00
let display = Display ::default ( ) . map_or_else (
| | {
2022-08-21 23:36:07 +01:00
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 )
2022-09-25 22:49:00 +01:00
} ,
| display | display ,
) ;
2022-08-21 23:36:07 +01:00
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 )
2022-08-21 23:36:07 +01:00
}
} ;
debug! ( " Loaded config file " ) ;
2022-10-10 21:59:44 +01:00
if let Err ( err ) = create_bars ( app , & display , wayland_client , & config ) {
2022-08-21 23:36:07 +01:00
error! ( " {:?} " , err ) ;
2022-10-16 13:54:48 +01:00
exit ( ErrorCode ::CreateBars as i32 ) ;
2022-08-14 14:30:13 +01:00
}
2022-08-21 23:36:07 +01:00
debug! ( " Created bars " ) ;
2022-11-05 17:32:42 +00:00
let style_path = env ::var ( " IRONBAR_CSS " ) . ok ( ) . map_or_else (
| | {
2022-11-01 13:25:46 +00:00
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-11-05 17:32:42 +00:00
} ,
PathBuf ::from ,
) ;
2022-08-14 14:30:13 +01:00
if style_path . exists ( ) {
load_css ( style_path ) ;
}
} ) ;
2022-08-22 23:08:41 +01:00
// Ignore CLI args
// Some are provided by swaybar_config but not currently supported
app . run_with_args ( & Vec ::< & str > ::new ( ) ) ;
2022-08-21 23:36:07 +01:00
Ok ( ( ) )
}
2022-08-28 16:57:41 +01:00
/// 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 < ( ) > {
2022-10-04 23:26:07 +01:00
let outputs = wl . outputs . as_slice ( ) ;
2022-08-25 21:53:42 +01:00
2022-09-27 20:24:16 +01:00
debug! ( " Received {} outputs from Wayland " , outputs . len ( ) ) ;
2022-10-16 12:57:37 +01:00
debug! ( " Outputs: {:?} " , outputs ) ;
2022-08-25 21:53:57 +01:00
2022-08-21 23:36:07 +01:00
let num_monitors = display . n_monitors ( ) ;
for i in 0 .. num_monitors {
2022-10-15 15:36:23 +01:00
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 " ) ) ? ;
2022-10-04 23:26:07 +01:00
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 ;
2022-08-21 23:36:07 +01:00
2022-09-25 22:49:00 +01:00
// TODO: Could we use an Arc<Config> or `Cow<Config>` here to avoid cloning?
2022-08-21 23:36:07 +01:00
config . monitors . as_ref ( ) . map_or_else (
2022-10-16 12:57:37 +01:00
| | {
info! ( " Creating bar on '{}' " , monitor_name ) ;
create_bar ( app , & monitor , monitor_name , config . clone ( ) )
} ,
2022-08-21 23:36:07 +01:00
| config | {
let config = config . get ( monitor_name ) ;
match & config {
Some ( MonitorConfig ::Single ( config ) ) = > {
2022-10-15 15:36:23 +01:00
info! ( " Creating bar on '{}' " , monitor_name ) ;
2022-08-21 23:36:07 +01:00
create_bar ( app , & monitor , monitor_name , config . clone ( ) )
}
Some ( MonitorConfig ::Multiple ( configs ) ) = > {
for config in configs {
2022-10-15 15:36:23 +01:00
info! ( " Creating bar on '{}' " , monitor_name ) ;
2022-08-21 23:36:07 +01:00
create_bar ( app , & monitor , monitor_name , config . clone ( ) ) ? ;
}
Ok ( ( ) )
}
_ = > Ok ( ( ) ) ,
}
} ,
) ? ;
}
Ok ( ( ) )
2022-08-14 14:30:13 +01:00
}
2022-09-25 22:49:00 +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 ) )
}