refactor(bar-core): add the BarPlatform hooks with the Windows and macOS implementations

komorebi_bar_core::platform holds what the widgets need from the operating system and differs between the bars: BarPlatform { open_system_tool, latest_release_api_url, calendar_icon }, the SystemTool enum (task manager, power settings, network settings, a URL) and install()/platform(), a once-set global the shell fills first thing in main() (a widget calls platform() when it is clicked or built, never before main). Each bar gets an os.rs with its implementation (main.rs re-exports the core module as crate::platform, so shared files can say crate::platform::platform()): Windows spawns exactly the commands the widgets spawn today (cmd.exe /C taskmgr.exe, cmd.exe /C start ms-settings:batterysaver, cmd.exe /C ncpa, explorer.exe <url>); macOS maps TaskManager to open -a 'Activity Monitor' and network settings to open x-apple.systempreferences:... as memory.rs and network.rs do today, and keeps the commands the shared files spawn on macOS today for the rest (cmd.exe taskmgr.exe for cpu, cmd.exe start ms-settings:batterysaver for battery, explorer.exe for a URL), which are broken there: a one-line fix per tool in os.rs, not part of this change.

Nothing calls the hooks yet: the next revisions switch the widgets over, one concern each.

Verified: Windows cargo clippy --workspace --locked --all-targets -D warnings clean; macOS fake-CC cargo check --locked --workspace --all-targets finished, 0 errors (6 bar warnings, unchanged); native cargo test -p komorebi-bar-core 3 unit + 2 oracle passed; rustfmt --check clean on the new files and both main.rs. No widget calls the hooks yet, so no behaviour changes.
This commit is contained in:
LGUG2Z committed 2026-10-31 01:37:54 -07:00
1 parent 98f9e184a2
commit 086833af96
6 files changed
+122

No files matched your search

+2
View File
@@ -16,3 +16,5 @@ pub mod config;
pub mod render;
pub mod widgets;
pub mod platform;
+48
View File
@@ -0,0 +1,48 @@
//! What the widgets need from the operating system and what differs between the bars.
//!
//! A shell implements [`BarPlatform`] and calls [`install`] first thing in `main`; the widgets
//! reach it through [`platform`] when they are built or clicked.
use std::io;
use std::sync::OnceLock;
/// A tool the bar opens when a widget is clicked.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SystemTool {
/// The task manager (Task Manager, Activity Monitor)
TaskManager,
/// The operating system's power and battery settings
PowerSettings,
/// The operating system's network settings
NetworkSettings,
/// A URL, in the default browser
Url(String),
}
pub trait BarPlatform: Send + Sync {
/// Opens a tool; the result is whether it could be started.
fn open_system_tool(&self, tool: SystemTool) -> io::Result<()>;
/// The GitHub API URL that says which release of this platform's komorebi is the latest.
fn latest_release_api_url(&self) -> &'static str;
/// The glyph the date widget shows as its calendar icon.
fn calendar_icon(&self) -> &'static str;
}
static PLATFORM: OnceLock<&'static dyn BarPlatform> = OnceLock::new();
/// Sets the platform of the process. The first call wins; a second one is ignored.
pub fn install(platform: &'static dyn BarPlatform) {
let _ = PLATFORM.set(platform);
}
/// # Panics
///
/// Panics if [`install`] has not been called: a shell must install its platform before it builds
/// a widget.
pub fn platform() -> &'static dyn BarPlatform {
*PLATFORM
.get()
.expect("komorebi_bar_core::platform::install must be called first thing in main")
}
+4
View File
@@ -1,5 +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;
@@ -96,6 +98,8 @@ pub enum KomorebiEvent {
}
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();
+29
View File
@@ -0,0 +1,29 @@
use egui_phosphor::regular::CALENDAR_DOTS;
use komorebi_bar_core::platform::BarPlatform;
use komorebi_bar_core::platform::SystemTool;
use std::io;
use std::process::Command;
pub struct WindowsBar;
impl BarPlatform for WindowsBar {
fn open_system_tool(&self, tool: SystemTool) -> io::Result<()> {
match tool {
SystemTool::TaskManager => Command::new("cmd.exe").args(["/C", "taskmgr.exe"]).spawn(),
SystemTool::PowerSettings => Command::new("cmd.exe")
.args(["/C", "start", "ms-settings:batterysaver"])
.spawn(),
SystemTool::NetworkSettings => Command::new("cmd.exe").args(["/C", "ncpa"]).spawn(),
SystemTool::Url(url) => Command::new("explorer.exe").args([url]).spawn(),
}
.map(|_| ())
}
fn latest_release_api_url(&self) -> &'static str {
"https://api.github.com/repos/LGUG2Z/komorebi/releases/latest"
}
fn calendar_icon(&self) -> &'static str {
CALENDAR_DOTS
}
}
@@ -1,5 +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;
@@ -63,6 +65,8 @@ pub enum KomorebiEvent {
}
fn main() -> eyre::Result<()> {
komorebi_bar_core::platform::install(&os::MacBar);
let opts: Opts = Opts::parse();
#[cfg(feature = "schemars")]
+35
View File
@@ -0,0 +1,35 @@
use egui_phosphor::regular::CALENDAR;
use komorebi_bar_core::platform::BarPlatform;
use komorebi_bar_core::platform::SystemTool;
use std::io;
use std::process::Command;
pub struct MacBar;
impl BarPlatform for MacBar {
fn open_system_tool(&self, tool: SystemTool) -> io::Result<()> {
match tool {
SystemTool::TaskManager => Command::new("open")
.args(["-a", "Activity Monitor"])
.spawn(),
// cmd.exe does not exist on macOS: this is what the battery widget does today
SystemTool::PowerSettings => Command::new("cmd.exe")
.args(["/C", "start", "ms-settings:batterysaver"])
.spawn(),
SystemTool::NetworkSettings => Command::new("open")
.args(["x-apple.systempreferences:com.apple.Network-Settings.extension"])
.spawn(),
// explorer.exe does not exist on macOS: this is what the update widget does today
SystemTool::Url(url) => Command::new("explorer.exe").args([url]).spawn(),
}
.map(|_| ())
}
fn latest_release_api_url(&self) -> &'static str {
"https://api.github.com/repos/LGUG2Z/komorebi-for-mac/releases/latest"
}
fn calendar_icon(&self) -> &'static str {
CALENDAR
}
}