Files
komorebi/docs/dev/bar-unification.md
LGUG2Z e0e0f49714 docs(dev): old paths in the analysis notes carry the new ones
seam, core-model, settings, rule-matching, bar-unification, e2e-to-unit and known-issues are
measurements and decision logs written for the old directories. They keep their history; each
gets a "Paths (cutover stack)" note under the title that maps the old names (komorebi/,
komorebi-for-kde/komorebi/, komorebi-for-mac/komorebi/, nix/, docs/, schema files) to the new
ones and says the 0.1.x numbers are history. The seam.md tree table, the test file paths in
e2e-to-unit.md and known-issues.md (files that exist and are named as current) and the
bar-e2e.md schema path now name the files where they are.

Not rewritten: the line numbers, measurements and "at the time" statements. Not touched:
backend-switch.md (no old paths), build-and-test.md and flake.md (flake-one).

Verified: the files named as current exist (komorebi-linux/tests/*.rs); relative links resolve.
2026-11-05 15:03:27 -08:00

15 KiB

One komorebi-bar for Windows and macOS

Status (wip-cand4): B0-B3 done (one komorebi-bar package, a module per platform, schema views); B4 (merging the rendering code) not done and cannot be shown mechanical without a screen; macOS bar never rendered by these changes.

Paths (cutover stack): this document was written before the directories were renamed and keeps the paths of its time. Now: komorebi/ is komorebi-windows/, komorebi-for-kde/komorebi/ is komorebi-linux/, komorebi-for-mac/komorebi/ is komorebi-macos/, komorebi-for-kde/komorebi-hotkeys/ is komorebi-hotkeys/, komorebi-for-kde/nix/ and komorebi-for-mac/nix/ are nix/linux/ and nix/macos/, komorebi-for-kde/docs/ and komorebi-for-mac/docs/ are docs/linux/ and docs/macos/, schema*.json are in schemas/{windows,linux,macos}/, and every package is at version 0.2.0 (the 0.1.x numbers below are history).

Status at the revision that adds this file. Everything below was measured on this tree with diff (counts are lines that differ, </> lines of diff, hunks in parentheses). Nothing here was rendered: the bars cannot run on Linux. Gates that did run are named; the ones that did not are listed at the end.

KDE has no bar: komorebi-for-kde has no komorebi-bar package and no schema.bar.json. The plan below is for two platforms; a KDE bar would add a third shell and a third schema view.

What exists

  • crates/komorebi-bar-core (4,592 lines): the code both bars share, one copy each. selected_frame, ui, statics, alignment, render, config (the leaf types and the whole KomobarConfig with the mouse options), the widgets applications, battery, cpu, date, memory, storage, time, update, komorebi_layout, the icon cache (widgets/icons.rs), all widget configuration types (komorebi_config, network_config, platform_config for keyboard, media and systray), WidgetConfig with a variant for every widget, the BarWidget trait, platform (BarPlatform, SystemTool, a once-installed global) and schema (per-platform views, see below).
  • BarPlatform hooks: open_system_tool, latest_release_api_url, calendar_icon, command_icon, exec_shell_command, send_komorebi_message, send_komorebi_batch.
  • Two shells, komorebi-bar (Windows, root workspace, version 0.1.42) and komorebi-for-mac/komorebi-bar (own workspace, own Cargo.lock, own flake, version 0.1.1). Each keeps main.rs, bar.rs, os.rs, the one-line config.rs, and the widgets whose runtime differs: komorebi.rs, network.rs, and on Windows keyboard.rs, media.rs, systray.rs. widgets/widget.rs is only WidgetConfigExt (config -> widget).
  • The schema oracle regenerates the macOS file natively (tests/schema_oracle.rs, module generated); the Windows file is still checked by the out-of-tree harness because three descriptions read differently when compiled for Windows.

Why one package is not possible yet (the structural blocker)

The two trees are two Cargo workspaces with two lockfiles and two flakes. A package belongs to one workspace, so a single komorebi-bar that builds on both platforms needs one workspace first: the Windows root Cargo.toml and komorebi-for-mac/Cargo.toml merged, one Cargo.lock, one version (0.1.42 vs 0.1.0), one komorebi-client (the two lib.rs differ in 150 lines: Windows re-exports the daemon crate and State/Window/Workspace, macOS has its own types) and windows/objc2 dependencies under [target.'cfg(...)'.dependencies]. That is a repository-level cutover (the plan's "final naming of the outputs and the unified app/devShell is a cutover decision"), not a bar change. Until then the bars share the crate and converge, they do not merge. Everything in this stack is ordered so the merge later is a package move.

The schema is solved: views of one union

schema.bar.json differs between the platforms in 40 hunks (5,381 lines of 9,091 / 3,774). Analysed by definition (jq over $defs):

  • 42 definitions exist only on Windows: all reachable only through MouseConfig (which holds a SocketMessage, hence the closure) and the Keyboard/Media/Systray widgets. Removing the mouse property and the three widget variants and pruning unreachable definitions removes all 42.
  • 14 differences remain in the 55 shared definitions, all text or default: root description (macOS names its own schema URL), height default 50 vs 50.0, the margin and padding examples (10 vs 10.0, a sentence about defaults, a trailing comma), show_icon (deprecated flag and backticks), KomorebiLayout (untagged anyOf on Windows, externally tagged oneOf on macOS), NetworkConfig.default_interface_options (Windows only), four storage descriptions (C:\ vs /), TimeConfig.changing_icon (default: false only on macOS), TimeFormat title of Custom (macOS says Default, a mislabel), the WidgetConfig variants above.

komorebi_bar_core::schema holds this as data (schema/changes.rs, 16 changes) in the same design as komorebi-config: the union is the Windows text, view_of applies a platform's changes and prunes. tests/schema_oracle.rs proves that the macOS view of the checked-in Windows file is byte-identical to komorebi-for-mac/schema.bar.json, that the Windows view is the identity, and that views are idempotent. Both bars print --schema through their view (schema::generated_text), so the files and nix/komorebi-bar-options.nix do not change when code is converged onto the Windows spelling.

The out-of-tree harness (S/bar2/regen.sh, real bar sources over the real komorebi-protocol/komorebi-config) regenerates both files on Linux. Since config.rs moved, the in-repo oracle regenerates the macOS file itself (generated tests); only Windows needs the harness.

What is still per platform (measured at this tip)

file win / mac lines differing what differs and why it is not moved
widgets/komorebi.rs 940 / 986 136 (17) Two things. (1) Real rendering differences: macOS wraps show_label and the "all icons" painter in a Frame with a margin and a minimum height (bar.show_label(...), a method, vs an associated function on Windows), 1.0 vs 1.0_f32. Taking either spelling is a visual change on the other platform: needs a screen. (2) The conversion from the daemon state: Windows uses komorebi_client::{State, Window, Workspace, Container} (hwnd, title(), process_id(), windows-icons), macOS its own client types (details.title, details.icon_path, icns_to_rgba, device, no Layout::Custom). A State-to-snapshot split (WindowInfo/MonitorInfo of komorebi-backend as the carrier) is not clean yet: the macOS and Windows komorebi_client State are different types, the bar subscribes to the daemons with different notification shapes, and I cannot test either subscription here. Not attempted.
widgets/network.rs 598 / 578 82 (19) Windows reads default_interface_options (friendly name, IPv4, IPv6), macOS does not (the config type is shared and macOS logs a warning); std::sync::Mutex (poisoning handled) vs parking_lot; netdev 0.46 vs 0.40 and a different interface match key (friendly name vs name); cmd.exe /C ncpa vs open x-apple.... Functional on macOS: BEHAVIOUR, needs a Mac. Known difference, left as is.
bar.rs 1,399 / 1,105 444 (35) Windows: PowerShell session (exec_powershell, behind the hook), hwnd, virtual-desktop restore/minimize, position_bar through komorebi_client::Window, CJK font fallbacks, scale_factor, the Windows mouse handling. macOS: unboxed notification type, window shadow and level. Not behaviour-preserving without a screen.
main.rs 402 / 388 92 (14) process_hwnd/enum_window, DPI awareness, set_read_timeout; macOS activation policy and window level (AppKit), config dir ~/.config/komorebi. Window and viewport setup belongs behind BarPlatform hooks (init_process, viewport_builder, after_creation), not written: it cannot be exercised here.
os.rs 83 / 60 71 (14) the platform implementations themselves; stays per platform (cfg(target_os) modules after the merge).
widgets/widget.rs, widgets/mod.rs 41 / 49, 22 / 19 20, 5 WidgetConfigExt (macOS builds a no-op Unsupported for the three Windows-only widgets) and the module lists.

Windows-only and not shared: widgets/keyboard.rs (167), media.rs (322), systray.rs (1,205); their config types are in the core. The macOS copies of keyboard and media were dead and are deleted.

Known macOS/Windows differences that were kept (D-coord-1)

  • network.rs: see above. The macOS bar ignores default_interface_options.
  • Windows-only config keys are accepted on macOS and skipped with a logged warning (BEHAVIOUR on macOS, as for StaticConfig): Keyboard, Media and Systray widgets (widgets::widget::warn_unsupported), the mouse options and the network default_interface_options. Before, the first group failed to deserialize and rejected the whole config, the other two were ignored silently.
  • macOS commands that spawn programs that do not exist there are preserved, not fixed: SystemTool::PowerSettings (battery click) spawns cmd.exe /C start ms-settings:..., SystemTool::Url (update click) spawns explorer.exe, and UserCommand::launch_if_ready of the applications widget spawns cmd /C <command> in both bars. update.rs still has a second GitHub API URL for the Windows repository. The macOS spawns live in komorebi-for-mac/komorebi-bar/src/os.rs; the storage click is SystemTool::StorageLocation and each shell spawns what it spawned before.
  • KomorebiLayout is #[serde(untagged)] in both bars now (the macOS source converged; the macOS schema view restores the macOS text). Its Deserialize is hand-written and nothing in the bar serializes it, so this changes only the derived schema and Serialize. The coordinator said to leave it alone; it is a separate revision (mac-bar: converge komorebi.rs config text and komorebi_layout.rs) and can be dropped, at the price of keeping KomorebiLayout and its widget in the shells.

The merged package layout (for the coordinator's workspace merge)

Not done and not prepared in the tree (no workspace or lockfile structure was changed). When the root workspace and komorebi-for-mac are merged the bar should look like this:

  • Package komorebi-bar (one, in komorebi-bar/) plus crates/komorebi-bar-core as today. Version: the workspace version. The macOS tree's komorebi-bar 0.1.1 and the v0.1.0 text in its schema description are a view concern (schema/changes.rs), not a package one.
  • src/main.rs (shared: the argument parsing, config read, --schema, the event loop shell) and src/bar.rs split into src/bar/mod.rs (shared Komobar) with #[cfg(target_os = "windows")] mod windows; and #[cfg(target_os = "macos")] mod macos; for the window handle, DPI, activation policy, window level, position and the PowerShell session. src/os.rs becomes src/os/{windows,macos}.rs (the BarPlatform implementations, selected by cfg(target_os) and installed first thing in main). Windows-only widgets (keyboard, media, systray) are #[cfg(target_os = "windows")] modules; komorebi.rs and network.rs stay two files (komorebi/{windows,macos}.rs behind one widgets::komorebi facade) until the snapshot split.
  • Cargo.toml: windows, windows-core, windows-icons*, systray-util, font-loader under [target.'cfg(windows)'.dependencies]; objc2, objc2-app-kit, raw-window-handle, icns under [target.'cfg(target_os = "macos")'.dependencies]; netdev has two versions (0.46, 0.40): pick one when network.rs converges, until then a target-specific rename (netdev-win, netdev-mac). komorebi-client: one crate (the two differ in 150 lines). Features: schemars as now (it forwards to the core). No new feature per platform: the platform is cfg(target_os).
  • Schema: the checked-in files stay (schema.bar.json, komorebi-for-mac/schema.bar.json, or one directory for both after the merge). --schema prints the view of the running platform (SchemaPlatform from cfg(target_os)); a --schema-for <platform> flag would let one host regenerate both, as the Windows union is the Windows text. Windows' three platform-dependent descriptions (protocol PathBuf, themes) need the Windows target to regenerate, so the Windows file is only verifiable on Windows or with the harness.
  • Lock files: the macOS Cargo.lock folds into the root one; the lines this stack added to both (image, komorebi-config, komorebi-layouts, komorebi-protocol, komorebi-themes, tracing, lazy_static, color-eyre for bar-core) are the same crates in both, so the merge adds no new versions beyond netdev and starship-battery/sysinfo (already unified here).
  • Nix: komorebi-for-mac/nix/komorebi-bar-options.nix is generated from the macOS file and does not change; the two flakes' extractBinary "komorebi-bar" become one derivation per system.

The plan, in order

  1. Done: schema views and oracle; storage, time, applications, komorebi layout widget, icon cache, all widget config types, WidgetConfig, config.rs moved; hooks for platform spawns, the shell session and the komorebi client.
  2. Not done, needs a screen or a Mac: bar.rs/main.rs window code behind BarPlatform (init_process, viewport_builder, after_creation, position/DPI/activation), then Komobar<P> and the shared app body into the core.
  3. Not done, needs the snapshot split: komorebi.rs. It needs State-to-snapshot conversion per platform and one renderer; the frame/margin difference must be decided by looking at both.
  4. Decision for network.rs: converge on the Windows widget (macOS gains friendly-name, IPv4/IPv6 and the netdev bump) or keep two.
  5. Workspace merge (above), then the two shells collapse into one package.
  6. The oracle then compares generated text with the files for both platforms.

What to check by hand

Windows (coordinator, screenshot e2e): the bar starts; the storage, time, applications (icons from executables), komorebi layout (click opens the options, choosing one changes the layout, Monocle/Floating toggles, paused) and komorebi workspaces widgets render; a click on storage opens Explorer on the drive; a config with mouse options and a Systray/Keyboard/Media widget still works (this is the Windows path through the moved config.rs, WidgetConfig and the exec_shell_command hook: a Command mouse message must still reach the PowerShell session); komorebi-bar --schema equals schema.bar.json.

macOS (also in the section for docs/dev/macos-handcheck.md): the bar starts with your real config; the time widget renders (format variants, changing_icon); clicking a storage widget opens the mounted volume in Finder (open <path>); the komorebi layout widget click works as before; a config that contains a Keyboard, Media or Systray widget, a mouse block, or default_interface_options under Network starts the bar and logs one warning per item (before: the widget case failed to load the config); komorebi-bar --schema equals komorebi-for-mac/schema.bar.json; the battery and update clicks still fail the way they did (preserved, one-function fix in os.rs).