No description
  • Rust 99.8%
  • Shell 0.2%
Find a file
2026-10-14 09:48:04 +08:00
.forgejo/workflows ci: isolate the stable release index checkout 2026-10-02 17:25:47 +08:00
assets Polish the control panel, notification history and satellite placement 2026-09-26 12:50:41 +08:00
ci ci: make the bread-ecosystem clone in ci/build.sh race-free 2026-09-29 16:47:14 +08:00
docs fix: resolve BAR-56 review findings on notification preferences 2026-10-13 22:07:25 +08:00
src style: format notification preference extras for rustfmt 2026-10-14 09:10:40 +08:00
.gitignore ci: build dev track and PR checks against dependency main via bread-ecosystem's dev-deps.sh 2026-09-26 22:32:52 +08:00
AGENTS.md ci: build dev track and PR checks against dependency main via bread-ecosystem's dev-deps.sh 2026-09-26 22:32:52 +08:00
bakery.toml Pin ecosystem crates off floating main; bakery pulls bread 2026-08-15 21:40:24 +08:00
Cargo.lock fix(deps): bump bread-ecosystem to v0.8.1-rc.2 to stop the widget observer leak (BAR-58) 2026-10-07 22:34:42 +08:00
Cargo.toml fix(deps): bump bread-ecosystem to v0.8.1-rc.2 to stop the widget observer leak (BAR-58) 2026-10-07 22:34:42 +08:00
CONTRIBUTING.md ci: build dev track and PR checks against dependency main via bread-ecosystem's dev-deps.sh 2026-09-26 22:32:52 +08:00
LICENSE Prepare repo for public GitHub release 2026-05-19 12:30:12 +08:00
README.md Reword pywal mentions across remaining bread apps and docs 2026-09-27 08:32:52 +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
  • History of the last 50 notifications (app, summary, truncated body, time). Loaded from and saved to $XDG_STATE_HOME/breadbar/history.json (typically ~/.local/state/breadbar/history.json). Toggle by right-clicking the bar's ☰ menu button (left-click still opens the control panel), by breadbar --history (Hyprland: bind = SUPER, N, exec, breadbar --history), or by D-Bus dev.breadway.Bar.ToggleHistory on org.freedesktop.Notifications at /dev/breadway/Bar.

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 bread-theme's own palette cache (falling back to a pywal colors.json if present for compatibility), and bread-theme's built-in bread-toned default palette if neither is found
  • 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

Palette integration

breadbar reads the current palette 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;
}

Multi-monitor note: style.css is one display-global override. Named palette tokens in it (@accent, @on-bg, …) resolve against the primary monitor's palette, not the per-monitor palette of the bar a rule paints. If your monitors run different wallpapers/accents, use literal hex in style.css for a result that's identical everywhere, and leave per-monitor accent colouring to the generated per-output stylesheet.

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 + dev.breadway.Bar history IPC
src/notifications/popup.rs Layer-shell popup window and card stack
src/notifications/history.rs Bounded history (last 50, persisted under XDG state) and layer-shell history window
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