refactor(bar): the Windows bar is a module of the komorebi-bar package (move)

komorebi-bar/src/{bar,config,os}.rs and widgets/ move to komorebi-bar/src/windows/, main.rs to
windows/mod.rs (pub fn main); src/main.rs is a four-line caller. Mechanical edits only: crate:: becomes
crate::windows:: (all sites), the include_str! path gets one more ../, and the unused root re-export
of komorebi_bar_core::platform is dropped (the main installs the platform by its full path). This
prepares one package with a module per platform; behaviour is the same code.

Gates run: Windows clippy --all-targets -D warnings PASS; bar-core schema oracle (3 unit + 6) PASS; the
S/bar2 harness (real bar sources, regen.sh, updated to read src/windows) regenerates schema.bar.json for
Windows (9091 lines) and macOS (3774 lines) byte-identical to the checked-in files; tools/e2e-needed
says the bar is not an input of the e2e binaries. Not run: the bar itself, the screenshot gate (owed).
This commit is contained in:
LGUG2Z committed 2026-10-31 12:41:00 -07:00
1 parent b558acbe17
commit 146cd7ff54
12 files changed
+476 -470

No files matched your search

+3 -398
View File
@@ -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<PathBuf>,
/// 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<isize> {
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<komorebi_client::Notification>),
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::<KomobarConfig>(
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::State>(&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::<komorebi_client::Notification>(
&notification_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()
}
@@ -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<crate::config::MouseMessage> = None;
let mut pending_command: Option<crate::windows::config::MouseMessage> = None;
if let Some(mouse_config) = &self.config.mouse {
let command = if ui
File renamed without changes.
+401
View File
@@ -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<PathBuf>,
/// 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<isize> {
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<komorebi_client::Notification>),
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::<KomobarConfig>(
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::State>(&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::<komorebi_client::Notification>(
&notification_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()))
}
@@ -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<()> {
@@ -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;
@@ -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;
@@ -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;
File renamed without changes.
@@ -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;
@@ -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;
@@ -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;