No description
Find a file
Breadway be0b54e1ea Pin ecosystem crates off floating main; bakery pulls bread
bread-theme moves to git.breadway.dev v0.7.1. bread-utils and
bread-screenshots pin ecosystem origin/main (v0.7.1 has no
BreadClient::request and predates the screenshots crate). bread-shared
pins bread v0.8.0-rc.1 — latest existing tag with widget wire types
(v0.7.0 has none; v0.8.0 was never cut).

bakery.toml sets bread_deps = ["bread"] so the daemon is installed
alongside the bar. CLAUDE.md records the single-trunk workflow and
the bar / notifications / OSD / widgets split.
2026-08-15 21:40:24 +08:00
.forgejo/workflows CI: single-trunk model — dev triggers on main, beta becomes RC-tag-triggered 2026-07-31 11:05:29 +08:00
assets Design refresh: new icon assets, bluetooth popover, notification urgency styling, RAM/power draw in control panel 2026-07-17 14:36:33 +08:00
src breadbar: give the wifi add-network dialog proper CSD + rounded corners 2026-07-30 19:02:39 +08:00
.gitignore Pin ecosystem crates off floating main; bakery pulls bread 2026-08-15 21:40:24 +08:00
bakery.toml Pin ecosystem crates off floating main; bakery pulls bread 2026-08-15 21:40:24 +08:00
Cargo.lock Pin ecosystem crates off floating main; bakery pulls bread 2026-08-15 21:40:24 +08:00
Cargo.toml Pin ecosystem crates off floating main; bakery pulls bread 2026-08-15 21:40:24 +08:00
CLAUDE.md Pin ecosystem crates off floating main; bakery pulls bread 2026-08-15 21:40:24 +08:00
CONTRIBUTING.md CONTRIBUTING.md: document single-trunk + RC-tag release model 2026-07-31 11:08:41 +08:00
LICENSE Prepare repo for public GitHub release 2026-05-19 12:30:12 +08:00
README.md Pin ecosystem crates off floating main; bakery pulls bread 2026-08-15 21:40:24 +08:00

breadbar

Minimal status bar and notification daemon for Hyprland on Wayland.

A single Rust binary that provides a full-width top bar, a D-Bus notification daemon, a volume/brightness OSD, and an SNI system tray housed in a control panel popover.

Features

Status bar (anchored to the top of every monitor via gtk4-layer-shell):

  • Left: live workspace buttons sourced from Hyprland IPC, active workspace highlighted
  • Centre: media widget (track/artist from playerctl, click to open prev/play-pause/next controls; hidden when no player is active, lingers up to 30 minutes after the last pause) + clock (HH:MM, updates at the top of each minute)
  • Right: CPU%, RAM, power draw (W), battery level + AC indicator, Bluetooth icon (click to open blueman-manager), WiFi SSID with signal-strength icon (click for details popover), hamburger control panel button

WiFi popover (click the WiFi area):

  • Shows current SSID, IP address, and internet/Tailscale connectivity status via breadcrumbs status
  • Lists saved breadcrumbs profiles for one-click switching
  • Shows nearby SSIDs from breadcrumbs scan-list (saved networks are clickable to join)
  • Degrades gracefully if breadcrumbs is not installed

Control panel (hamburger button on the right):

  • Volume slider (reads/writes via wpctl, up to 150%)
  • Brightness slider (reads/writes via brightnessctl)
  • Live CPU%, GPU%, and network throughput (download/upload)
  • Audio output selector (lists PulseAudio sinks via pactl, switching takes effect immediately)
  • System tray (SNI): apps that register with org.kde.StatusNotifierWatcher appear as icon buttons
  • Power buttons: lock (breadlock), suspend, reboot, poweroff

Notification daemon:

  • Implements org.freedesktop.Notifications (D-Bus) — works with any standard sender (notify-send, etc.)
  • Popups appear top-right, stack vertically, auto-dismiss after the sender-specified timeout (default 5 s)
  • Supports CloseNotification and replaces_id

Volume/brightness OSD:

  • Overlay window at the bottom of the screen, auto-dismisses after 2 s
  • Appears automatically on any pactl sink-change event or sysfs backlight change

Theming:

  • Uses bread-theme for palette loading; reads ~/.cache/wal/colors.json (pywal) if present, falls back to a Catppuccin Mocha palette
  • User CSS override: ~/.config/breadbar/style.css
  • Send SIGHUP to reload the theme at runtime (integrates with wallpaper-change hooks)

Dependencies

Runtime (required):

  • GTK4 (≥ 4.12)
  • gtk4-layer-shell
  • iw — for WiFi SSID/signal (iw dev <iface> link)
  • wpctl (WirePlumber) — volume read/write
  • pactl (PipeWire-Pulse) — audio sink listing and OSD volume events
  • brightnessctl — brightness read/write
  • A running Hyprland compositor
  • D-Bus session bus

Runtime (optional, degrade gracefully if absent):

  • playerctl — media widget; hidden if no player is found
  • breadcrumbs — WiFi popover enrichment (profiles, internet/Tailscale status); basic SSID/signal still shown without it
  • blueman-manager — opened when the Bluetooth icon is clicked; Bluetooth state still shown without it

Bluetooth state is read from /sys/class/rfkill and BlueZ D-Bus and degrades gracefully if unavailable.

Building

cargo build --release

The binary is at target/release/breadbar.

Requirements: Rust 1.77+ (uses LazyLock), a GTK4 development environment (libgtk-4-dev / gtk4 package).

On Arch Linux:

sudo pacman -S gtk4 gtk4-layer-shell wireplumber pipewire-pulse brightnessctl iw
cargo build --release

Running

./target/release/breadbar

Typically launched from your Hyprland config:

exec-once = /path/to/breadbar

breadbar claims org.freedesktop.Notifications on the session D-Bus on startup. If another notification daemon is already running, startup will fail — stop the other daemon first.

Theming

pywal integration

breadbar reads ~/.cache/wal/colors.json automatically (via bread-theme). To reload after a wallpaper change:

pkill -HUP breadbar

Or hook it into your wallpaper script:

wal -i /path/to/wallpaper.jpg
pkill -HUP breadbar

Custom CSS

Drop a ~/.config/breadbar/style.css file and send SIGHUP to reload. This CSS is applied at a higher priority than the generated palette so you can override anything.

Example — change the font size:

* {
    font-size: 13px;
}

Architecture

Module Responsibility
src/main.rs GTK4 app entry point, widget tree, relm4 component
src/bar/workspaces.rs Hyprland IPC event stream, workspace buttons
src/bar/clock.rs Minute-tick clock
src/bar/stats.rs Polling loop: CPU, RAM, power, battery, Bluetooth, WiFi
src/bar/media.rs playerctl polling, media widget and controls popover
src/bar/wifi.rs WiFi details popover, breadcrumbs profile/scan integration
src/bar/control.rs Control panel data: volume (wpctl), brightness (brightnessctl), sinks (pactl)
src/bar/tray.rs org.kde.StatusNotifierWatcher D-Bus service, SNI item rendering
src/notifications/mod.rs org.freedesktop.Notifications zbus service
src/notifications/popup.rs Layer-shell popup window and card stack
src/osd.rs Volume/brightness on-screen display
src/widgets/ Live Lua widgets from breadd (BreadClient + WidgetSpec)
src/theme.rs bread-theme palette loading, GTK CSS provider injection

Stats are polled every 2 seconds. Bluetooth and WiFi are sampled every 16 seconds and cached in between to avoid hammering D-Bus and iw.

License

MIT