diff --git a/komorebi-bar/src/main.rs b/komorebi-bar/src/main.rs index 30e24225..ab7f5e0e 100644 --- a/komorebi-bar/src/main.rs +++ b/komorebi-bar/src/main.rs @@ -1,402 +1,7 @@ -mod bar; -mod config; -mod os; -pub use komorebi_bar_core::platform; -pub use komorebi_bar_core::render; -pub use komorebi_bar_core::selected_frame; -pub use komorebi_bar_core::ui; -mod widgets; +//! `komorebi-bar`, the status bar of komorebi. The code of each platform is in a module of its own. -use crate::bar::Komobar; -use crate::config::KomobarConfig; -use crate::config::Position; -use crate::config::PositionConfig; -use clap::Parser; -use config::MonitorConfigOrIndex; -use eframe::egui::ViewportBuilder; -use font_loader::system_fonts; -use hotwatch::EventKind; -use hotwatch::Hotwatch; -use komorebi_client::PathExt; -use komorebi_client::SocketMessage; -use komorebi_client::SubscribeOptions; -use komorebi_client::replace_env_in_path; -use std::io::BufReader; -use std::io::Read; -use std::path::PathBuf; -use std::sync::atomic::Ordering; -use std::time::Duration; -use tracing_subscriber::EnvFilter; -use windows::Win32::Foundation::HWND; -use windows::Win32::Foundation::LPARAM; -use windows::Win32::System::Threading::GetCurrentProcessId; -use windows::Win32::System::Threading::GetCurrentThreadId; -use windows::Win32::UI::HiDpi::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2; -use windows::Win32::UI::HiDpi::SetProcessDpiAwarenessContext; -use windows::Win32::UI::WindowsAndMessaging::EnumThreadWindows; -use windows::Win32::UI::WindowsAndMessaging::GetWindowThreadProcessId; -use windows_core::BOOL; - -pub use komorebi_bar_core::statics::*; - -#[derive(Parser)] -#[clap(name = "komorebi-bar", author, about, version)] -struct Opts { - /// Print the JSON schema of the configuration file and exit - #[clap(long)] - schema: bool, - /// Print a list of fonts available on this system and exit - #[clap(long)] - fonts: bool, - /// Path to a JSON or YAML configuration file - #[clap(short, long)] - #[clap(value_parser = replace_env_in_path)] - config: Option, - /// Write an example komorebi.bar.json to disk - #[clap(long)] - quickstart: bool, - /// Print a list of aliases that can be renamed to canonical variants - #[clap(long)] - #[clap(hide = true)] - aliases: bool, -} - -extern "system" fn enum_window(hwnd: HWND, lparam: LPARAM) -> BOOL { - unsafe { - let mut process_id = 0; - GetWindowThreadProcessId(hwnd, Some(&mut process_id)); - - if process_id == GetCurrentProcessId() { - *(lparam.0 as *mut HWND) = hwnd; - BOOL::from(false) // Stop enumeration - } else { - BOOL::from(true) // Continue enumeration - } - } -} - -fn process_hwnd() -> Option { - unsafe { - let mut hwnd = HWND::default(); - let _ = EnumThreadWindows( - GetCurrentThreadId(), - Some(enum_window), - LPARAM(&mut hwnd as *mut HWND as isize), - ); - - if hwnd.0 as isize == 0 { - None - } else { - Some(hwnd.0 as isize) - } - } -} - -pub enum KomorebiEvent { - Notification(Box), - Reconnect, -} +mod windows; fn main() -> color_eyre::Result<()> { - komorebi_bar_core::platform::install(&os::WindowsBar); - - unsafe { SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) }?; - - let opts: Opts = Opts::parse(); - - #[cfg(feature = "schemars")] - if opts.schema { - print!( - "{}", - komorebi_bar_core::schema::generated_text::( - komorebi_bar_core::schema::SchemaPlatform::Windows - ) - ); - std::process::exit(0); - } - - if opts.fonts { - for font in system_fonts::query_all() { - println!("{font}"); - } - - std::process::exit(0); - } - - if std::env::var("RUST_LIB_BACKTRACE").is_err() { - unsafe { - std::env::set_var("RUST_LIB_BACKTRACE", "1"); - } - } - - color_eyre::install()?; - - if std::env::var("RUST_LOG").is_err() { - unsafe { - std::env::set_var("RUST_LOG", "info"); - } - } - - tracing::subscriber::set_global_default( - tracing_subscriber::fmt::Subscriber::builder() - .with_env_filter(EnvFilter::from_default_env()) - .finish(), - )?; - - let home_dir: PathBuf = std::env::var("KOMOREBI_CONFIG_HOME").map_or_else( - |_| dirs::home_dir().expect("there is no home directory"), - |home_path| { - let home = home_path.replace_env(); - - assert!( - home.is_dir(), - "$Env:KOMOREBI_CONFIG_HOME is set to '{home_path}', which is not a valid directory" - ); - - home - }, - ); - - if opts.quickstart { - let komorebi_bar_json = include_str!("../../docs/komorebi.bar.example.json").to_string(); - std::fs::write(home_dir.join("komorebi.bar.json"), komorebi_bar_json)?; - println!( - "Example komorebi.bar.json file written to {}", - home_dir.display() - ); - - std::process::exit(0); - } - - let default_config_path = home_dir.join("komorebi.bar.json"); - - let config_path = opts.config.or_else(|| { - default_config_path - .is_file() - .then_some(default_config_path.clone()) - }); - - let mut config = match config_path { - None => { - let komorebi_bar_json = - include_str!("../../docs/komorebi.bar.example.json").to_string(); - - std::fs::write(&default_config_path, komorebi_bar_json)?; - tracing::info!( - "created example configuration file: {}", - default_config_path.display() - ); - - KomobarConfig::read(&default_config_path)? - } - Some(ref config) => { - if !opts.aliases { - tracing::info!("found configuration file: {}", config.display()); - } - - KomobarConfig::read(config)? - } - }; - - let config_path = config_path.unwrap_or(default_config_path); - - if opts.aliases { - KomobarConfig::aliases(&std::fs::read_to_string(&config_path)?); - std::process::exit(0); - } - - let state = serde_json::from_str::(&komorebi_client::send_query( - &SocketMessage::State, - )?)?; - - let (usr_monitor_index, work_area_offset) = match &config.monitor { - Some(MonitorConfigOrIndex::MonitorConfig(monitor_config)) => { - (monitor_config.index, monitor_config.work_area_offset) - } - Some(MonitorConfigOrIndex::Index(idx)) => (*idx, None), - None => (0, None), - }; - - let monitor_index = state - .monitor_usr_idx_map - .get(&usr_monitor_index) - .map_or(usr_monitor_index, |i| *i); - - MONITOR_RIGHT.store( - state.monitors.elements()[monitor_index].size.right, - Ordering::SeqCst, - ); - - MONITOR_TOP.store( - state.monitors.elements()[monitor_index].size.top, - Ordering::SeqCst, - ); - - MONITOR_LEFT.store( - state.monitors.elements()[monitor_index].size.left, - Ordering::SeqCst, - ); - - MONITOR_INDEX.store(monitor_index, Ordering::SeqCst); - - match config.position { - None => { - config.position = Some(PositionConfig { - start: Some(Position { - x: state.monitors.elements()[monitor_index].size.left as f32, - y: state.monitors.elements()[monitor_index].size.top as f32, - }), - end: Some(Position { - x: state.monitors.elements()[monitor_index].size.right as f32, - y: 50.0, - }), - }) - } - Some(ref mut position) => { - if position.start.is_none() { - position.start = Some(Position { - x: state.monitors.elements()[monitor_index].size.left as f32, - y: state.monitors.elements()[monitor_index].size.top as f32, - }); - } - - if position.end.is_none() { - position.end = Some(Position { - x: state.monitors.elements()[monitor_index].size.right as f32, - y: 50.0, - }) - } - } - } - - let viewport_builder = ViewportBuilder::default() - .with_decorations(false) - .with_transparent(true) - .with_taskbar(false); - - let native_options = eframe::NativeOptions { - viewport: viewport_builder, - ..Default::default() - }; - - if let Some(rect) = &work_area_offset { - komorebi_client::send_message(&SocketMessage::MonitorWorkAreaOffset(monitor_index, *rect))?; - tracing::info!("work area offset applied to monitor: {}", monitor_index); - } - - let (tx_gui, rx_gui) = crossbeam_channel::unbounded(); - let (tx_config, rx_config) = crossbeam_channel::unbounded(); - - let mut hotwatch = Hotwatch::new()?; - let config_path_cl = config_path.clone(); - - hotwatch.watch(config_path, move |event| match event.kind { - EventKind::Modify(_) | EventKind::Remove(_) => match KomobarConfig::read(&config_path_cl) { - Ok(updated) => { - tracing::info!("configuration file updated: {}", config_path_cl.display()); - - if let Err(error) = tx_config.send(updated) { - tracing::error!("could not send configuration update to gui: {error}") - } - } - Err(error) => { - tracing::error!("{error}"); - } - }, - _ => {} - })?; - - tracing::info!("watching configuration file for changes"); - - eframe::run_native( - "komorebi-bar", - native_options, - Box::new(|cc| { - let ctx_repainter = cc.egui_ctx.clone(); - std::thread::spawn(move || loop { - std::thread::sleep(Duration::from_secs(1)); - ctx_repainter.request_repaint(); - }); - - let ctx_komorebi = cc.egui_ctx.clone(); - std::thread::spawn(move || { - let subscriber_name = format!("komorebi-bar-{}", random_word::get(random_word::Lang::En)); - - let listener = komorebi_client::subscribe_with_options(&subscriber_name, SubscribeOptions { - filter_state_changes: true, - }) - .expect("could not subscribe to komorebi notifications"); - - tracing::info!("subscribed to komorebi notifications: \"{}\"", subscriber_name); - - for client in listener.incoming() { - match client { - Ok(subscription) => { - match subscription.set_read_timeout(Some(Duration::from_secs(1))) { - Ok(()) => {} - Err(error) => tracing::error!("{}", error), - } - let mut buffer = Vec::new(); - let mut reader = BufReader::new(subscription); - - // this is when we know a shutdown has been sent - if matches!(reader.read_to_end(&mut buffer), Ok(0)) { - tracing::info!("disconnected from komorebi"); - - // keep trying to reconnect to komorebi - while komorebi_client::send_message( - &SocketMessage::AddSubscriberSocket(subscriber_name.clone()), - ) - .is_err() - { - std::thread::sleep(Duration::from_secs(1)); - } - - tracing::info!("reconnected to komorebi"); - - if let Err(error) = tx_gui.send(KomorebiEvent::Reconnect) { - tracing::error!("could not send komorebi reconnect event to gui thread: {error}") - } - - ctx_komorebi.request_repaint(); - continue; - } - - match String::from_utf8(buffer) { - Ok(notification_string) => { - match serde_json::from_str::( - ¬ification_string, - ) { - Ok(notification) => { - tracing::debug!("received notification from komorebi"); - - if let Err(error) = tx_gui.send(KomorebiEvent::Notification(Box::new(notification))) { - tracing::error!("could not send komorebi notification update to gui thread: {error}") - } - - ctx_komorebi.request_repaint(); - } - Err(error) => { - tracing::error!("could not deserialize komorebi notification: {error}"); - } - } - } - Err(error) => { - tracing::error!( - "komorebi notification string was invalid utf8: {error}" - ) - } - } - } - Err(error) => { - tracing::error!("{error}"); - } - } - } - }); - - Ok(Box::new(Komobar::new(cc, rx_gui, rx_config, config))) - }), - ) - .map_err(|error| color_eyre::eyre::Error::msg(error.to_string())) + windows::main() } diff --git a/komorebi-bar/src/bar.rs b/komorebi-bar/src/windows/bar.rs similarity index 97% rename from komorebi-bar/src/bar.rs rename to komorebi-bar/src/windows/bar.rs index c54125db..717e058c 100644 --- a/komorebi-bar/src/bar.rs +++ b/komorebi-bar/src/windows/bar.rs @@ -1,29 +1,29 @@ -use crate::AUTO_SELECT_FILL_COLOUR; -use crate::AUTO_SELECT_TEXT_COLOUR; -use crate::BAR_HEIGHT; -use crate::DEFAULT_PADDING; -use crate::KomorebiEvent; -use crate::MAX_LABEL_WIDTH; -use crate::MONITOR_LEFT; -use crate::MONITOR_RIGHT; -use crate::MONITOR_TOP; -use crate::config::KomobarConfig; -use crate::config::KomobarTheme; -use crate::config::MonitorConfigOrIndex; -use crate::config::Position; -use crate::config::PositionConfig; -use crate::config::get_individual_spacing; -use crate::process_hwnd; -use crate::render::Color32Ext; -use crate::render::Grouping; -use crate::render::RenderConfig; -use crate::render::RenderExt; -use crate::take_widget_clicked; -use crate::widgets::komorebi::Komorebi; -use crate::widgets::komorebi::MonitorInfo; -use crate::widgets::widget::BarWidget; -use crate::widgets::widget::WidgetConfig; -use crate::widgets::widget::WidgetConfigExt; +use crate::windows::AUTO_SELECT_FILL_COLOUR; +use crate::windows::AUTO_SELECT_TEXT_COLOUR; +use crate::windows::BAR_HEIGHT; +use crate::windows::DEFAULT_PADDING; +use crate::windows::KomorebiEvent; +use crate::windows::MAX_LABEL_WIDTH; +use crate::windows::MONITOR_LEFT; +use crate::windows::MONITOR_RIGHT; +use crate::windows::MONITOR_TOP; +use crate::windows::config::KomobarConfig; +use crate::windows::config::KomobarTheme; +use crate::windows::config::MonitorConfigOrIndex; +use crate::windows::config::Position; +use crate::windows::config::PositionConfig; +use crate::windows::config::get_individual_spacing; +use crate::windows::process_hwnd; +use crate::windows::render::Color32Ext; +use crate::windows::render::Grouping; +use crate::windows::render::RenderConfig; +use crate::windows::render::RenderExt; +use crate::windows::take_widget_clicked; +use crate::windows::widgets::komorebi::Komorebi; +use crate::windows::widgets::komorebi::MonitorInfo; +use crate::windows::widgets::widget::BarWidget; +use crate::windows::widgets::widget::WidgetConfig; +use crate::windows::widgets::widget::WidgetConfigExt; use color_eyre::eyre; use crossbeam_channel::Receiver; use crossbeam_channel::TryRecvError; @@ -1086,7 +1086,7 @@ impl eframe::App for Komobar { CentralPanel::default().frame(frame).show(ctx, |ui| { // Variable to store command to execute after widgets are rendered // This allows widgets to mark clicks as consumed before bar processes them - let mut pending_command: Option = None; + let mut pending_command: Option = None; if let Some(mouse_config) = &self.config.mouse { let command = if ui diff --git a/komorebi-bar/src/config.rs b/komorebi-bar/src/windows/config.rs similarity index 100% rename from komorebi-bar/src/config.rs rename to komorebi-bar/src/windows/config.rs diff --git a/komorebi-bar/src/windows/mod.rs b/komorebi-bar/src/windows/mod.rs new file mode 100644 index 00000000..58e6d745 --- /dev/null +++ b/komorebi-bar/src/windows/mod.rs @@ -0,0 +1,401 @@ +mod bar; +mod config; +mod os; +pub use komorebi_bar_core::render; +pub use komorebi_bar_core::selected_frame; +pub use komorebi_bar_core::ui; +mod widgets; + +use crate::windows::bar::Komobar; +use crate::windows::config::KomobarConfig; +use crate::windows::config::Position; +use crate::windows::config::PositionConfig; +use clap::Parser; +use config::MonitorConfigOrIndex; +use eframe::egui::ViewportBuilder; +use font_loader::system_fonts; +use hotwatch::EventKind; +use hotwatch::Hotwatch; +use komorebi_client::PathExt; +use komorebi_client::SocketMessage; +use komorebi_client::SubscribeOptions; +use komorebi_client::replace_env_in_path; +use std::io::BufReader; +use std::io::Read; +use std::path::PathBuf; +use std::sync::atomic::Ordering; +use std::time::Duration; +use tracing_subscriber::EnvFilter; +use windows::Win32::Foundation::HWND; +use windows::Win32::Foundation::LPARAM; +use windows::Win32::System::Threading::GetCurrentProcessId; +use windows::Win32::System::Threading::GetCurrentThreadId; +use windows::Win32::UI::HiDpi::DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2; +use windows::Win32::UI::HiDpi::SetProcessDpiAwarenessContext; +use windows::Win32::UI::WindowsAndMessaging::EnumThreadWindows; +use windows::Win32::UI::WindowsAndMessaging::GetWindowThreadProcessId; +use windows_core::BOOL; + +pub use komorebi_bar_core::statics::*; + +#[derive(Parser)] +#[clap(name = "komorebi-bar", author, about, version)] +struct Opts { + /// Print the JSON schema of the configuration file and exit + #[clap(long)] + schema: bool, + /// Print a list of fonts available on this system and exit + #[clap(long)] + fonts: bool, + /// Path to a JSON or YAML configuration file + #[clap(short, long)] + #[clap(value_parser = replace_env_in_path)] + config: Option, + /// Write an example komorebi.bar.json to disk + #[clap(long)] + quickstart: bool, + /// Print a list of aliases that can be renamed to canonical variants + #[clap(long)] + #[clap(hide = true)] + aliases: bool, +} + +extern "system" fn enum_window(hwnd: HWND, lparam: LPARAM) -> BOOL { + unsafe { + let mut process_id = 0; + GetWindowThreadProcessId(hwnd, Some(&mut process_id)); + + if process_id == GetCurrentProcessId() { + *(lparam.0 as *mut HWND) = hwnd; + BOOL::from(false) // Stop enumeration + } else { + BOOL::from(true) // Continue enumeration + } + } +} + +fn process_hwnd() -> Option { + unsafe { + let mut hwnd = HWND::default(); + let _ = EnumThreadWindows( + GetCurrentThreadId(), + Some(enum_window), + LPARAM(&mut hwnd as *mut HWND as isize), + ); + + if hwnd.0 as isize == 0 { + None + } else { + Some(hwnd.0 as isize) + } + } +} + +pub enum KomorebiEvent { + Notification(Box), + Reconnect, +} + +pub fn main() -> color_eyre::Result<()> { + komorebi_bar_core::platform::install(&os::WindowsBar); + + unsafe { SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) }?; + + let opts: Opts = Opts::parse(); + + #[cfg(feature = "schemars")] + if opts.schema { + print!( + "{}", + komorebi_bar_core::schema::generated_text::( + komorebi_bar_core::schema::SchemaPlatform::Windows + ) + ); + std::process::exit(0); + } + + if opts.fonts { + for font in system_fonts::query_all() { + println!("{font}"); + } + + std::process::exit(0); + } + + if std::env::var("RUST_LIB_BACKTRACE").is_err() { + unsafe { + std::env::set_var("RUST_LIB_BACKTRACE", "1"); + } + } + + color_eyre::install()?; + + if std::env::var("RUST_LOG").is_err() { + unsafe { + std::env::set_var("RUST_LOG", "info"); + } + } + + tracing::subscriber::set_global_default( + tracing_subscriber::fmt::Subscriber::builder() + .with_env_filter(EnvFilter::from_default_env()) + .finish(), + )?; + + let home_dir: PathBuf = std::env::var("KOMOREBI_CONFIG_HOME").map_or_else( + |_| dirs::home_dir().expect("there is no home directory"), + |home_path| { + let home = home_path.replace_env(); + + assert!( + home.is_dir(), + "$Env:KOMOREBI_CONFIG_HOME is set to '{home_path}', which is not a valid directory" + ); + + home + }, + ); + + if opts.quickstart { + let komorebi_bar_json = include_str!("../../../docs/komorebi.bar.example.json").to_string(); + std::fs::write(home_dir.join("komorebi.bar.json"), komorebi_bar_json)?; + println!( + "Example komorebi.bar.json file written to {}", + home_dir.display() + ); + + std::process::exit(0); + } + + let default_config_path = home_dir.join("komorebi.bar.json"); + + let config_path = opts.config.or_else(|| { + default_config_path + .is_file() + .then_some(default_config_path.clone()) + }); + + let mut config = match config_path { + None => { + let komorebi_bar_json = + include_str!("../../../docs/komorebi.bar.example.json").to_string(); + + std::fs::write(&default_config_path, komorebi_bar_json)?; + tracing::info!( + "created example configuration file: {}", + default_config_path.display() + ); + + KomobarConfig::read(&default_config_path)? + } + Some(ref config) => { + if !opts.aliases { + tracing::info!("found configuration file: {}", config.display()); + } + + KomobarConfig::read(config)? + } + }; + + let config_path = config_path.unwrap_or(default_config_path); + + if opts.aliases { + KomobarConfig::aliases(&std::fs::read_to_string(&config_path)?); + std::process::exit(0); + } + + let state = serde_json::from_str::(&komorebi_client::send_query( + &SocketMessage::State, + )?)?; + + let (usr_monitor_index, work_area_offset) = match &config.monitor { + Some(MonitorConfigOrIndex::MonitorConfig(monitor_config)) => { + (monitor_config.index, monitor_config.work_area_offset) + } + Some(MonitorConfigOrIndex::Index(idx)) => (*idx, None), + None => (0, None), + }; + + let monitor_index = state + .monitor_usr_idx_map + .get(&usr_monitor_index) + .map_or(usr_monitor_index, |i| *i); + + MONITOR_RIGHT.store( + state.monitors.elements()[monitor_index].size.right, + Ordering::SeqCst, + ); + + MONITOR_TOP.store( + state.monitors.elements()[monitor_index].size.top, + Ordering::SeqCst, + ); + + MONITOR_LEFT.store( + state.monitors.elements()[monitor_index].size.left, + Ordering::SeqCst, + ); + + MONITOR_INDEX.store(monitor_index, Ordering::SeqCst); + + match config.position { + None => { + config.position = Some(PositionConfig { + start: Some(Position { + x: state.monitors.elements()[monitor_index].size.left as f32, + y: state.monitors.elements()[monitor_index].size.top as f32, + }), + end: Some(Position { + x: state.monitors.elements()[monitor_index].size.right as f32, + y: 50.0, + }), + }) + } + Some(ref mut position) => { + if position.start.is_none() { + position.start = Some(Position { + x: state.monitors.elements()[monitor_index].size.left as f32, + y: state.monitors.elements()[monitor_index].size.top as f32, + }); + } + + if position.end.is_none() { + position.end = Some(Position { + x: state.monitors.elements()[monitor_index].size.right as f32, + y: 50.0, + }) + } + } + } + + let viewport_builder = ViewportBuilder::default() + .with_decorations(false) + .with_transparent(true) + .with_taskbar(false); + + let native_options = eframe::NativeOptions { + viewport: viewport_builder, + ..Default::default() + }; + + if let Some(rect) = &work_area_offset { + komorebi_client::send_message(&SocketMessage::MonitorWorkAreaOffset(monitor_index, *rect))?; + tracing::info!("work area offset applied to monitor: {}", monitor_index); + } + + let (tx_gui, rx_gui) = crossbeam_channel::unbounded(); + let (tx_config, rx_config) = crossbeam_channel::unbounded(); + + let mut hotwatch = Hotwatch::new()?; + let config_path_cl = config_path.clone(); + + hotwatch.watch(config_path, move |event| match event.kind { + EventKind::Modify(_) | EventKind::Remove(_) => match KomobarConfig::read(&config_path_cl) { + Ok(updated) => { + tracing::info!("configuration file updated: {}", config_path_cl.display()); + + if let Err(error) = tx_config.send(updated) { + tracing::error!("could not send configuration update to gui: {error}") + } + } + Err(error) => { + tracing::error!("{error}"); + } + }, + _ => {} + })?; + + tracing::info!("watching configuration file for changes"); + + eframe::run_native( + "komorebi-bar", + native_options, + Box::new(|cc| { + let ctx_repainter = cc.egui_ctx.clone(); + std::thread::spawn(move || loop { + std::thread::sleep(Duration::from_secs(1)); + ctx_repainter.request_repaint(); + }); + + let ctx_komorebi = cc.egui_ctx.clone(); + std::thread::spawn(move || { + let subscriber_name = format!("komorebi-bar-{}", random_word::get(random_word::Lang::En)); + + let listener = komorebi_client::subscribe_with_options(&subscriber_name, SubscribeOptions { + filter_state_changes: true, + }) + .expect("could not subscribe to komorebi notifications"); + + tracing::info!("subscribed to komorebi notifications: \"{}\"", subscriber_name); + + for client in listener.incoming() { + match client { + Ok(subscription) => { + match subscription.set_read_timeout(Some(Duration::from_secs(1))) { + Ok(()) => {} + Err(error) => tracing::error!("{}", error), + } + let mut buffer = Vec::new(); + let mut reader = BufReader::new(subscription); + + // this is when we know a shutdown has been sent + if matches!(reader.read_to_end(&mut buffer), Ok(0)) { + tracing::info!("disconnected from komorebi"); + + // keep trying to reconnect to komorebi + while komorebi_client::send_message( + &SocketMessage::AddSubscriberSocket(subscriber_name.clone()), + ) + .is_err() + { + std::thread::sleep(Duration::from_secs(1)); + } + + tracing::info!("reconnected to komorebi"); + + if let Err(error) = tx_gui.send(KomorebiEvent::Reconnect) { + tracing::error!("could not send komorebi reconnect event to gui thread: {error}") + } + + ctx_komorebi.request_repaint(); + continue; + } + + match String::from_utf8(buffer) { + Ok(notification_string) => { + match serde_json::from_str::( + ¬ification_string, + ) { + Ok(notification) => { + tracing::debug!("received notification from komorebi"); + + if let Err(error) = tx_gui.send(KomorebiEvent::Notification(Box::new(notification))) { + tracing::error!("could not send komorebi notification update to gui thread: {error}") + } + + ctx_komorebi.request_repaint(); + } + Err(error) => { + tracing::error!("could not deserialize komorebi notification: {error}"); + } + } + } + Err(error) => { + tracing::error!( + "komorebi notification string was invalid utf8: {error}" + ) + } + } + } + Err(error) => { + tracing::error!("{error}"); + } + } + } + }); + + Ok(Box::new(Komobar::new(cc, rx_gui, rx_config, config))) + }), + ) + .map_err(|error| color_eyre::eyre::Error::msg(error.to_string())) +} diff --git a/komorebi-bar/src/os.rs b/komorebi-bar/src/windows/os.rs similarity index 96% rename from komorebi-bar/src/os.rs rename to komorebi-bar/src/windows/os.rs index 1dcffa38..5ba8990c 100644 --- a/komorebi-bar/src/os.rs +++ b/komorebi-bar/src/windows/os.rs @@ -1,4 +1,4 @@ -use crate::widgets::ImageIcon; +use crate::windows::widgets::ImageIcon; use egui_phosphor::regular::CALENDAR_DOTS; use komorebi_bar_core::platform::BarPlatform; use komorebi_bar_core::platform::SystemTool; @@ -40,7 +40,7 @@ impl BarPlatform for WindowsBar { } fn exec_shell_command(&self, command: &str) -> color_eyre::Result<()> { - crate::bar::exec_powershell(command) + crate::windows::bar::exec_powershell(command) } fn send_komorebi_message(&self, message: &SocketMessage) -> io::Result<()> { diff --git a/komorebi-bar/src/widgets/keyboard.rs b/komorebi-bar/src/windows/widgets/keyboard.rs similarity index 97% rename from komorebi-bar/src/widgets/keyboard.rs rename to komorebi-bar/src/windows/widgets/keyboard.rs index ee27da88..1a03c4e9 100644 --- a/komorebi-bar/src/widgets/keyboard.rs +++ b/komorebi-bar/src/windows/widgets/keyboard.rs @@ -1,7 +1,7 @@ -use crate::config::LabelPrefix; +use crate::windows::config::LabelPrefix; pub use komorebi_bar_core::widgets::platform_config::KeyboardConfig; -use crate::render::RenderConfig; -use crate::widgets::widget::BarWidget; +use crate::windows::render::RenderConfig; +use crate::windows::widgets::widget::BarWidget; use color_eyre::eyre; use eframe::egui::Align; use eframe::egui::Context; diff --git a/komorebi-bar/src/widgets/komorebi.rs b/komorebi-bar/src/windows/widgets/komorebi.rs similarity index 98% rename from komorebi-bar/src/widgets/komorebi.rs rename to komorebi-bar/src/windows/widgets/komorebi.rs index 1dba3200..d2ca4793 100644 --- a/komorebi-bar/src/widgets/komorebi.rs +++ b/komorebi-bar/src/windows/widgets/komorebi.rs @@ -1,14 +1,14 @@ use super::ImageIcon; -use crate::MAX_LABEL_WIDTH; -use crate::MONITOR_INDEX; -use crate::config::DisplayFormat; -use crate::config::DisplayFormat::*; -use crate::config::WorkspacesDisplayFormat; -use crate::render::RenderConfig; -use crate::selected_frame::SelectableFrame; -use crate::ui::CustomUi; -use crate::widgets::komorebi_layout::KomorebiLayoutExt; -use crate::widgets::widget::BarWidget; +use crate::windows::MAX_LABEL_WIDTH; +use crate::windows::MONITOR_INDEX; +use crate::windows::config::DisplayFormat; +use crate::windows::config::DisplayFormat::*; +use crate::windows::config::WorkspacesDisplayFormat; +use crate::windows::render::RenderConfig; +use crate::windows::selected_frame::SelectableFrame; +use crate::windows::ui::CustomUi; +use crate::windows::widgets::komorebi_layout::KomorebiLayoutExt; +use crate::windows::widgets::widget::BarWidget; use eframe::egui::Align; use eframe::egui::Color32; use eframe::egui::Context; diff --git a/komorebi-bar/src/widgets/media.rs b/komorebi-bar/src/windows/widgets/media.rs similarity index 97% rename from komorebi-bar/src/widgets/media.rs rename to komorebi-bar/src/windows/widgets/media.rs index 5c371b61..5d1be1b6 100644 --- a/komorebi-bar/src/widgets/media.rs +++ b/komorebi-bar/src/windows/widgets/media.rs @@ -1,11 +1,11 @@ -use crate::MAX_LABEL_WIDTH; -use crate::bar::Alignment; -use crate::config::MediaDisplayFormat; +use crate::windows::MAX_LABEL_WIDTH; +use crate::windows::bar::Alignment; +use crate::windows::config::MediaDisplayFormat; pub use komorebi_bar_core::widgets::platform_config::MediaConfig; -use crate::render::RenderConfig; -use crate::selected_frame::SelectableFrame; -use crate::ui::CustomUi; -use crate::widgets::widget::BarWidget; +use crate::windows::render::RenderConfig; +use crate::windows::selected_frame::SelectableFrame; +use crate::windows::ui::CustomUi; +use crate::windows::widgets::widget::BarWidget; use eframe::egui::Align; use eframe::egui::Context; use eframe::egui::Label; diff --git a/komorebi-bar/src/widgets/mod.rs b/komorebi-bar/src/windows/widgets/mod.rs similarity index 100% rename from komorebi-bar/src/widgets/mod.rs rename to komorebi-bar/src/windows/widgets/mod.rs diff --git a/komorebi-bar/src/widgets/network.rs b/komorebi-bar/src/windows/widgets/network.rs similarity index 99% rename from komorebi-bar/src/widgets/network.rs rename to komorebi-bar/src/windows/widgets/network.rs index 35dd3022..eb6e588d 100644 --- a/komorebi-bar/src/widgets/network.rs +++ b/komorebi-bar/src/windows/widgets/network.rs @@ -1,12 +1,12 @@ -use crate::bar::Alignment; +use crate::windows::bar::Alignment; pub use komorebi_bar_core::widgets::network_config::DefaultInterfaceConfig; pub use komorebi_bar_core::widgets::network_config::InterfaceDisplayType; pub use komorebi_bar_core::widgets::network_config::NetworkConfig; pub use komorebi_bar_core::widgets::network_config::NetworkSelectConfig; -use crate::config::LabelPrefix; -use crate::render::RenderConfig; -use crate::selected_frame::SelectableFrame; -use crate::widgets::widget::BarWidget; +use crate::windows::config::LabelPrefix; +use crate::windows::render::RenderConfig; +use crate::windows::selected_frame::SelectableFrame; +use crate::windows::widgets::widget::BarWidget; use eframe::egui::Align; use eframe::egui::Color32; use eframe::egui::Context; diff --git a/komorebi-bar/src/widgets/systray.rs b/komorebi-bar/src/windows/widgets/systray.rs similarity index 99% rename from komorebi-bar/src/widgets/systray.rs rename to komorebi-bar/src/windows/widgets/systray.rs index 230f2a5c..d96073af 100644 --- a/komorebi-bar/src/widgets/systray.rs +++ b/komorebi-bar/src/windows/widgets/systray.rs @@ -2,11 +2,11 @@ use super::ICONS_CACHE; use super::ImageIcon; use super::ImageIconId; use super::rgba_to_color_image; -use crate::bar::Alignment; -use crate::mark_widget_clicked; -use crate::render::RenderConfig; -use crate::selected_frame::SelectableFrame; -use crate::widgets::widget::BarWidget; +use crate::windows::bar::Alignment; +use crate::windows::mark_widget_clicked; +use crate::windows::render::RenderConfig; +use crate::windows::selected_frame::SelectableFrame; +use crate::windows::widgets::widget::BarWidget; use crossbeam_channel::Receiver; use crossbeam_channel::Sender; use crossbeam_channel::unbounded; diff --git a/komorebi-bar/src/widgets/widget.rs b/komorebi-bar/src/windows/widgets/widget.rs similarity index 70% rename from komorebi-bar/src/widgets/widget.rs rename to komorebi-bar/src/windows/widgets/widget.rs index 9f62748f..603ad931 100644 --- a/komorebi-bar/src/widgets/widget.rs +++ b/komorebi-bar/src/windows/widgets/widget.rs @@ -1,16 +1,16 @@ -use crate::widgets::applications::Applications; -use crate::widgets::battery::Battery; -use crate::widgets::cpu::Cpu; -use crate::widgets::date::Date; -use crate::widgets::keyboard::Keyboard; -use crate::widgets::komorebi::Komorebi; -use crate::widgets::media::Media; -use crate::widgets::memory::Memory; -use crate::widgets::network::Network; -use crate::widgets::storage::Storage; -use crate::widgets::systray::Systray; -use crate::widgets::time::Time; -use crate::widgets::update::Update; +use crate::windows::widgets::applications::Applications; +use crate::windows::widgets::battery::Battery; +use crate::windows::widgets::cpu::Cpu; +use crate::windows::widgets::date::Date; +use crate::windows::widgets::keyboard::Keyboard; +use crate::windows::widgets::komorebi::Komorebi; +use crate::windows::widgets::media::Media; +use crate::windows::widgets::memory::Memory; +use crate::windows::widgets::network::Network; +use crate::windows::widgets::storage::Storage; +use crate::windows::widgets::systray::Systray; +use crate::windows::widgets::time::Time; +use crate::windows::widgets::update::Update; pub use komorebi_bar_core::widgets::widget::BarWidget; pub use komorebi_bar_core::widgets::widget::WidgetConfig;