Commit graph

50 commits

Author SHA1 Message Date
Breadway
6c4df8813c capsule: accept the open event breadbox can actually emit
An app may only publish inside its own bread.<app_id>.* namespace, so
breadbox (app id 'box') cannot emit bread.command.box.open — bread-client
refuses it and the redirect did nothing but log a warning. The capsule now
also subscribes to bread.box.open_requested, which is what breadbox emits.

bread.command.box.open is kept as well: that is the addressed-to-an-app
command form an external trigger (the bread CLI, a keybind, another app)
would legitimately send, so the capsule opens whether it was asked directly
or told by breadbox.
2026-08-31 15:45:25 +08:00
Breadway
a7db4d093d capsule: keep the drawer hidden when collapsed and pin the capsule width
Two rendering bugs, both from treating set_size_request as a maximum when it
is only a minimum.

The drawer was collapsed with set_size_request(-1, 0) but left visible. GTK
still allocates a visible box its natural height, and this layer-shell surface
has no fixed height, so the window grew to fit the entire results list: the
capsule rendered open at idle with a stray result row beneath it. It is now
hidden while collapsed, revealed in open_fn before the height animation, and
hidden again on the frame the collapse reaches zero so the close stays
animated rather than snapping shut.

The capsule's width came from set_default_width, which is only a preference a
wide child overrides. Combined with the results list propagating its natural
width, the pill stretched well past the theme's 480px. The width request is
now pinned, and the list no longer propagates width.
2026-08-31 15:45:25 +08:00
Breadway
e52c507f32 capsule: keyboard open, query modes, sections, and search-state geometry (phase 6c)
Completes the spotlight capsule (theme 04), THEME_SYSTEM_PLAN.md §7:

- Keyboard open (item A): a new launcher_command module subscribes to
  bread.command.box.open — only when the active theme's launcher is
  Embedded — and focuses launcher_entry on receipt, which the existing
  EventControllerFocus::connect_enter already turns into an open_fn()
  call, same path a mouse click into the entry takes. breadbox's own
  keybind-triggered launch now redirects to this same event under an
  embedded theme instead of stacking its overlay window on top (see the
  breadbox commit).

- Click-away scrim (item B): open_fn/close_fn now show/hide panel.rs's
  dismiss surface via the new show_capsule_dismiss/hide_dismiss, and
  panels.set_on_dismiss(close_fn) wires a click-away into the capsule's
  own close path. The scrim's clickable region starts at a fixed offset
  (capsule row height + the drawer's own maximum content height,
  DRAWER_MAX_HEIGHT_PX) rather than the drawer's live height, so it can
  never geometrically overlap a rendered result row regardless of
  breadbar-dismiss's overlay layer always rendering above the bar's own.

- Query modes (item C): connect_changed now runs bread_launcher::parse_query
  against the entry text and, when the parsed prefix is listed in
  [launcher].modes, swaps launcher_results.scroller for a new mode_list
  populated by populate_mode_list (calc result / filtered commands / an
  "open this URL" prompt). key_ctrl routes Up/Down/Return at whichever
  list is active; a `>`/`.` row's action runs through the new ModeAction
  enum (RunShell for a command's own fixed exec string, OpenUrl straight
  to xdg-open) so arbitrary typed text is never passed through a shell.

- Sections (item D): ResultsList::new's new `sections` bool is threaded
  from [launcher].sections.

- Search-state geometry (item E): root's own width now spring-animates
  between [launcher].width and .search_width (animate_capsule_width, same
  set_size_request-driven technique animate_drawer_height already uses),
  and a `.searching` class on root switches border-radius to
  .search_radius via a new CSS rule/transition in theme.rs.

Also fixes a real bug this surfaced: drawer_target_height was measuring
drawer_box itself, whose size_request is continuously overwritten by
animate_drawer_height's own tick callback — GTK clamps a widget's
measure() up to at least its own explicit size request, so switching from
the (tall) app list to a one-row calc result measured the PREVIOUS
frame's forced height instead of the new content's actual size. It now
sums each visible child's own natural height directly, which also fixes
the same latent issue for narrowing app-search results.

screenshot.rs gains two new views (capsule-sections, capsule-calc) to
exercise D and C's calc path.
2026-08-31 15:45:25 +08:00
Breadway
c68ed0d7e9 panel: extend the dismiss-scrim pattern for the capsule's click-away (item B)
PanelSet's shared breadbar-dismiss surface already handles click-away for
the wifi/control/media popovers; this adds the pieces the capsule needs to
reuse it rather than a second mechanism: an extra on_dismiss callback
invoked alongside hide_all() on every dismiss click, and
show_capsule_dismiss/hide_dismiss, which show the scrim with its
clickable region starting at a caller-given top margin instead of the
popover default.

That margin matters: breadbar-dismiss's layer (overlay) always renders
above the bar's own (top), so if its clickable region ever reached up
into where the drawer is actually drawn, it would swallow clicks meant
for a result row instead of the click-away. The capsule's own call site
(main.rs, not part of this commit) always passes a margin sized to the
drawer's maximum possible height, never its live one, so this can never
happen regardless of how tall the drawer currently is.

Not yet wired into the capsule's open/close — PanelSet's three new
methods are unused until that follow-up commit, hence the transient
dead_code warnings.
2026-08-31 15:45:25 +08:00
Breadway
33181a7461 capsule: capture key events before the entry consumes Return
EventControllerKey defaults to PropagationPhase::Bubble. GtkEntry handles
Return in the target phase itself — emitting activate and returning TRUE —
which stops propagation before a bubble-phase controller runs. The capsule's
Enter-to-launch handler was therefore never reached: the selected app never
launched, with no error, because the keypress was consumed upstream.

Capture phase puts the controller ahead of the entry for the keys it claims
(Return/Up/Down/Escape); everything else still Proceeds to the entry so
normal text input is unaffected.
2026-08-31 15:45:25 +08:00
Breadway
2694dc0e13 capsule: clamp drawer collapse height and warn once per dropped widget
The drawer's spring easing overshoots past t=1.0 by design — the bounce is
the point on expand. On collapse (from=content height, to=0) that same
overshoot carried the interpolated value below zero, and set_size_request
hard-asserts height >= -1, so a GTK-CRITICAL fired once per frame for the
whole 360ms close. Clamp to 0 rather than -1: -1 is GTK's use-natural-height
sentinel, which is not what a closing drawer wants.

reconcile_widgets re-ran its undeliverable-widget warning on every reconcile,
and breadd re-pushes specs continuously for any timer-driven widget, so a
one-off diagnostic became unbounded log spam under a theme whose slots don't
name that widget's placement. Warn once per widget id instead.
2026-08-31 15:45:25 +08:00
Breadway
88c1bb0b07 bar/workspaces: unit-test the dots width-index mapping
The isolated screenshot harness has no Hyprland IPC (bread-capture's
isolation.rs), so it can never exercise a nonzero window count and prove
dot widths visually. Pulled the count->dot_widths-index mapping out of
make_dot_button as dot_width_index(), a pure function with no GTK
dependency, and unit-tested it directly (0/1/2 pass through, 3+ collapses
onto index 3, negative counts clamp instead of underflowing the array
index) as the stand-in for that visual proof.
2026-08-31 15:45:25 +08:00
Breadway
1fb10a10cd bar: implement spotlight's embedded launcher capsule (Phase 6b)
- New bread-launcher dep (gtk feature), pinned tag v0.7.4 with a dev-only
  [patch] entry alongside bread-theme's.
- Wire the drawer slot (plan §2/§7): root becomes a vbox whose first row is
  the existing CenterBox and whose second is drawer_box, appended via the
  same ModuleRegistry::for_each_in_slot pattern left/centre/right already
  use. Empty for liquid-motion/glass-workbench (zero children, zero size);
  theme.rs's window.breadbar > centerbox selector becomes > box > centerbox
  to follow the new nesting, byte-identical CSS for both existing themes.
- modules.workspaces.style = dots: bar::workspaces::make_dot_button, width
  from modules.workspaces.dot_widths, wired as a third rebuild_buttons arm.
- New launcher_entry (plain GtkEntry) and launcher_results
  (bread_launcher::gtk::ResultsList, sharing breadbox's cache/history via
  bread_launcher::LAUNCHER_APP) modules, built unconditionally and placed
  only when a theme's [bar.slots] names them (spotlight today).
- Capsule expand/collapse: typing/focus opens the drawer and animates its
  height via bread_theme::anim::spring_to; Up/Down move the selection,
  Enter launches (do_launch + record_launch) and collapses, Escape collapses
  and releases keyboard focus (on_demand ties to GTK's own focus-widget
  state, so releasing GTK focus hands the compositor keyboard back).
- window.width now wires Width::Px into set_default_width (previously
  unconsumed — Fill-anchored themes never needed it, the capsule does).
- Two new --screenshot views: capsule-collapsed, capsule-expanded (the
  latter focuses launcher_entry, types a query, and captures bar height +
  the drawer's actual settled height rather than a guessed constant).

cargo check/clippy: no new warnings (same two pre-existing: dead_code on
system_stats_box/cpu_pair/mem_pair/pwr_pair, from_* on workspaces.rs).
cargo test: 18/18 unchanged.
2026-08-31 15:45:25 +08:00
Breadway
df6b568cc1 bar: implement glass-workbench's three module variants (Phase 5)
Wires modules.workspaces.style/modules.clock.style into the bar for real
(Phase 3 shipped the schema but only ever consumed trail/flip), and adds
cpu/ram as bar modules, so glass-workbench (bread-theme) renders correctly
while liquid-motion's default path is untouched:

- workspaces: "pill" never calls WorkspaceTrail::place/stretch (the trail
  overlay stays invisible) and honours modules.workspaces.show_empty for
  real, rendering unoccupied non-active workspaces dimmed via CSS instead
  of filtering them out of the row. "trail" keeps the exact pre-existing
  filter/place/stretch behaviour regardless of show_empty.
- clock: "plain" registers a plain date+time label (date_lbl, built but
  never parented until now, plus a new clock_plain_lbl) instead of the
  per-digit flip box. "flip" is untouched.
- cpu/ram: two new bar chips (bar_cpu_pair/bar_ram_pair, bar_cpu_lbl/
  bar_ram_lbl) fed by the same AppInput::StatsUpdate data as the control
  panel's cpu_pair/mem_pair. Separate instances rather than reparenting
  the panel's own pair — a GTK widget can only have one parent, and
  reparenting would pull them out of the control panel's sys-grid, which
  no theme asked to change.

theme.rs::load_css() now branches on tokens.bar_border() (full-border
island vs. flush bar's bottom-only hairline) and modules.workspaces.style
(dimmed/translucent trail-fill buttons vs. solid-accent-fill pills), and
unconditionally gains .clock-plain/.clock-plain-time rules. The trail/flip
branches reproduce today's CSS byte-for-byte.

Verification (bread-capture, isolated headless-Sway harness):
- Noise floor: same baseline binary against itself varies from AE=0 (same
  capture minute) up to ~1900px (an in-flight digit-flip/clock-tick or a
  live Wi-Fi scan straddling two captures) and ~39000px on control-panel
  (live hardware sensors) — all pre-existing, not introduced by this change.
- Regression: this binary vs. the pre-Phase-5 baseline, captured in the
  same clock-minute to remove the dominant noise source, is AE=0 (bit-for-
  bit identical) on the bar view under the default liquid-motion theme.
- glass-workbench (BREAD_SHELL_THEME=glass-workbench): bar view is
  1920x36 (flush, no margin) vs. liquid-motion's 1920x56 (12px margin +
  44px island), square corners vs. liquid-motion's rounded island, plain
  "Mon 24/08 23:24" clock, and cpu/ram/wifi/battery/control chips with no
  media widget — matches demo 02. The isolated Sway capture harness has no
  live Hyprland IPC, so it reports zero workspaces under both themes
  (pre-existing, unrelated to this change) — the pill fill/dim CSS itself
  is exercised by code review and the trail-untouched regression result,
  not by a captured pixel with visible buttons.

cargo test: 18/18 passing (breadbar), no new clippy/cargo-check warnings
beyond the two pre-existing ones this task named up front.
2026-08-31 15:45:25 +08:00
Breadway
8d80a05d9b bar: route Lua widgets to any [bar.slots] slot, not just four fixed spots
Phase 3b of the shell theme system. A slot list entry can now be
`widget:<key>`, where `<key>` is either a WidgetPlacement alias
(right_of_workspaces, left_of_clock, right_of_clock, left_of_stats, tray)
or a Lua module name. ModuleRegistry::for_each_in_slot creates each
widget container on demand at its slot position; reconcile_widgets routes
each WidgetSpec by module name first, falling back to its placement
alias, and logs+drops (never panics) a spec with no matching container.

bread_shared::widget::WidgetPlacement stays untouched — it's still the
wire type breadd sends, unmodified and unshadowed; only the container
map that placement now resolves through is theme-driven.
2026-08-31 15:45:25 +08:00
Breadway
c5f7dd1ee3 bar: assemble modules from [bar.slots] instead of a fixed source order
Adds ModuleRegistry (src/bar/slots.rs), mapping each [bar.slots] module
name (workspaces/media/clock/volume/wifi/battery/control) to its
already-built widget. main.rs now registers the seven modules once
they're constructed, then walks ShellTheme::slots() to append them
into the left/centre/right containers in theme order instead of a
hardcoded sequence. An unknown module name in a theme manifest is
logged and skipped rather than panicking.

The Lua-declared widget_* containers keep their fixed interleave
(right-of-workspaces, left/right-of-clock, left-of-stats) — that's
Phase 3b, not this change.
2026-08-31 15:45:25 +08:00
Breadway
bbb1a6c8d2 Drive bar/window geometry and CSS tokens from the shell theme manifest
breadbar no longer hardcodes BAR_HEIGHT/BAR_MARGIN_TOP/BAR_MARGIN_SIDES/
CHIP_HEIGHT/ICON_PX or the root window's layer-shell setup: it loads
bread_theme:🐚:ShellTheme once (theme::shell_theme(), cached in a
thread-local) and reads bar.window (anchors, margin, exclusive zone,
keyboard mode - now set explicitly instead of relying on the library
default) plus tokens.{icon_px,chip_height} from it everywhere those used
to be literals.

The four satellite surfaces (breadbar-osd, breadbar-notif, breadbar-panel,
breadbar-dismiss) now get their anchor/margin/width/layer from the
manifest's [surfaces.*] table via a small new surface::apply() helper,
narrowly scoped to the three anchor shapes those surfaces actually use.
The pre-existing 8px gap between the panel's top margin and the dismiss
scrim's is preserved exactly (and now commented) rather than "fixed".

theme.rs's load_css() keeps its ~250 lines of hand-written breadbar CSS
(notifications, wifi popover, control panel, media widget) but now reads
its five radius/pad locals and the two easing curves (spring vs
spring_settle - hover/settle transitions were previously miscategorized
as the overshoot curve in the constant audit; the actual code already
used the settle curve there, confirmed against src) from theme tokens
instead of hardcoding them.

Also wires bread_theme:🐚:watch() so editing the active theme's
theme.toml/extra.css hot-reloads CSS tokens without a restart, same as
a pywal palette change already does. Window-spec values still need a
restart per the plan (read once at window-construction time).

Verified pixel-identical: captured all 10 breadbar --screenshot views
(bar, control-panel, connectivity-wifi/bluetooth, media-popover,
notification/-critical, osd-volume/-brightness, wifi-add-dialog) via
bread-capture's isolated headless-Sway harness against both the
pre-change and post-change binaries; every view diffs byte-identical
at the decoded-pixel level.
2026-08-31 15:45:25 +08:00
Breadway
297207a7aa notifications: stop toast popups from stealing focus or blocking clicks
All checks were successful
dev release / build (push) Successful in 1m42s
Toasts never grab keyboard focus and pass every pointer event through
to whatever's underneath, via an empty layer-shell input region.
2026-08-24 13:11:20 +08:00
Breadway
9c4205b1b2 clippy: fix char-comparison and map_or lints
All checks were successful
dev release / build (push) Successful in 1m52s
(cherry picked from commit 2e393082a744fe85f1ca1f8c6af48ce288e64b6c)
2026-08-23 14:57:51 +08:00
Breadway
e4c12e9b62 Add audio output switching and fix the workspace trail
All checks were successful
dev release / build (push) Successful in 1m33s
The control panel lists PipeWire sinks and sets the default, moving
playing streams so the change is immediate. The workspace pill starts
on switch without a layout wait, measures against the Fixed host so it
stays centered on the digit, and ignores row-wide bounds that used to
stretch it across several chips.
2026-08-16 14:04:05 +08:00
Breadway
96d666b3cb Fix CI: ship panel.rs and the workspace trail helper
Some checks failed
dev release / build (push) Failing after 9s
mod panel and stretch_geom_on were referenced on main but not
committed, so --locked release builds failed.
2026-08-16 13:45:59 +08:00
Breadway
1806c6f912 Bind each bar to its output palette and finish the island chrome
Some checks failed
dev release / build (push) Failing after 3m37s
One layer-shell window per Hyprland output now loads that output's
bread-theme palette. Notifications, history, and OSD follow the
monitor they appear on. Pin bread-theme to v0.7.4.
2026-08-16 13:23:31 +08:00
Breadway
62c6dd5ea3 Adopt bread_utils::screenshot_cli for --screenshot flags
All checks were successful
dev release / build (push) Successful in 1m22s
Replace the local settle delay, canvas defaults, and pair-validation
error path with bread-utils v0.7.2. Clap parsing stays in-tree.
2026-08-16 00:27:46 +08:00
Breadway
110f0cd3df Add notification actions and inline reply
Some checks failed
check / check (push) Failing after 10s
dev release / build (push) Successful in 1m0s
Parse FDO action pairs onto popup buttons, emit ActionInvoked on
click (default action on the body), and show an inline-reply field
when senders request it. Closing still emits NotificationClosed.
History persist is unchanged.
2026-08-16 00:26:06 +08:00
Breadway
4fddad510f Persist notification history to XDG state
All checks were successful
dev release / build (push) Successful in 1m32s
2026-08-15 23:11:28 +08:00
Breadway
465088dc55 Add notification history; pin ecosystem crates to v0.7.2
All checks were successful
dev release / build (push) Successful in 1m25s
Keep a bounded in-memory history (last 50) and a layer-shell window
listing app, summary, truncated body, and time. Toggle with
`breadbar --history` or D-Bus `dev.breadway.Bar.ToggleHistory`.

Pin bread-theme, bread-utils, and bread-screenshots to tag v0.7.2.
bread-shared stays on bread v0.8.0-rc.1.
2026-08-15 22:54:04 +08:00
Breadway
c53d504208 breadbar: give the wifi add-network dialog proper CSD + rounded corners
Was a bare gtk4::Window with no titlebar — GTK4's own minimal CSD
fallback for that case is a flat bar with plain system-font title text
and square corners, which is what actually made this look like a stray
window from a different decade next to the rest of the (rounded,
borderless) ecosystem. Now sets a real HeaderBar (which picks up the
window's existing title automatically) and gives the dialog + headerbar
matching rounded corners and dark theming via the existing
.wifi-add-dialog CSS class.

Also switched the Connect button off "suggested-action": GTK4's bundled
theme special-cases that exact class name for a native OS-accent-colour
feature that isn't a normal CSS rule and doesn't yield to any
background-color override this stylesheet adds, confirmed empirically
(a much more specific selector had zero effect). Moved to
"confirm-button", the same accent-button convention breadman/breadpad
already use.

Known residual issue, not resolved here: the Connect button still
doesn't render the accent colour even via "confirm-button" — narrowed
down to *some* button-specific styling quirk in this one dialog (window-
level rules like the rounded corners and dark background apply
correctly; a maximally-obvious magenta test rule on the same selector
also failed to render, ruling out a color-value mistake specifically),
but not root-caused further. Left as a known follow-up rather than
blocking the CSD fix, which was the actual ask.

Also removed two `cursor: pointer` CSS properties (on .clickable and
.media-widget) that GTK4 doesn't support as a CSS property at all — was
logging "Theme parser error: No property named cursor" on every
startup, doing nothing functionally either way.
2026-07-30 19:02:39 +08:00
Breadway
566aeeed8b breadbar: capture every view, not just bar/control-panel
breadbar is "a bar + the notification daemon + the OSD" — the screenshot
mode only covered the bar and its control-panel popover, missing seven
more distinct surfaces: the WiFi/Bluetooth connectivity popover (both
tabs), the media-controls popover, the standalone notification window
(both normal and critical urgency), the standalone OSD window (volume
and brightness), and the wifi add-network dialog. All ten views are now
--screenshot targets.

Two real refactors needed to make the standalone notification/OSD
windows screenshot-able at all, not just bigger match arms:

- Both windows are built deep inside an async task (`run_osd`/
  `popup::run`), only reachable after the real event loop starts — no
  window handle ever existed for a caller to hook `connect_map` on before
  that. Window construction is now synchronous in `osd::spawn`/
  `notifications::spawn`, handed to the async loop as a parameter instead
  of created inside it.

- Screenshot mode seeds each with one fixed sample event (SampleKind) via
  the same channel the real pactl/backlight/D-Bus sources feed, instead
  of waiting for real hardware/dbus activity. For notifications
  specifically this also means skipping the real
  org.freedesktop.Notifications D-Bus registration entirely in screenshot
  mode — claiming that well-known name would just race the real breadbar
  (if running) for it, for no benefit, since nothing external needs to
  reach a screenshot-only instance.

show_add_network_dialog gained an `on_build` hook (called before
`.present()`, the only point `connect_map` can still catch the map) so
screenshot mode can capture it without changing its one real call site's
behavior — and its `anchor` parameter widened from `&Button` to
`&impl IsA<Widget>` since the screenshot path anchors off a
`ToggleButton`, not a `Button`.
2026-07-29 17:17:17 +08:00
Breadway
ac6ccfe88a Add --screenshot CLI mode for automated capture
Renders a single view ("bar" or "control-panel"), captures it via
bread-screenshots, then exits — driven by bread-ecosystem's bread-capture
orchestrator, or runnable standalone for one-off captures.

Waits on GTK's map signal (plus a short settle delay) before capturing
rather than guessing a fixed sleep upfront: the control-panel view in
particular needs the popover's autohide disabled (a programmatic popup()
has no input-event serial to grab the Wayland seat with) and a longer
settle window so the CPU/RAM/PWR/GPU/network stats — populated by a
2-second background poller, not the popover's own open — have had at
least one full cycle to fill in before the capture fires.

--width/--height match whatever canvas bread-capture's isolation sizes
the compositor to, so the "bar" view's geometry doesn't depend on
querying anything at capture time.

Needs RelmApp::with_args(vec![]) (GLib's own arg parser otherwise rejects
--screenshot/--output before clap ever sees them) and
allow_multiple_instances(true) for screenshot runs specifically, since
GApplication is single-instance by default and this machine typically
already has a real breadbar running.
2026-07-29 11:15:57 +08:00
Breadway
552d771e15 fix: honor x-canonical-private-synchronous hint for notification replacement
notify-send-based senders (e.g. breadcrumbs) fire a new process per
notification, so replaces_id is always 0 — they instead tag related
notifications with the x-canonical-private-synchronous hint and expect
the daemon to replace whatever's currently showing from that app. We
weren't honoring it, so a persistent (Expire::Never) critical
notification like breadcrumbs' "no Wi-Fi adapter" during a suspend
transition could never be superseded by a later notification, leaving
it stuck until breadbar was restarted. Fixes #2.
2026-07-23 10:12:52 +08:00
Breadway
175af5d483 Will change this commit message to mean something later
Some checks failed
dev release / build (push) Failing after 2s
2026-07-22 19:53:51 +08:00
Breadway
15f2b111f1 random commit message, read it yourself
All checks were successful
dev release / build (push) Successful in 1m34s
2026-07-22 11:44:24 +08:00
Breadway
2cd2fbc7f6 Merge branch 'fix/audit-findings' into dev
# Conflicts:
#	assets/icons-needed.txt
#	src/main.rs
#	src/notifications/mod.rs
#	src/notifications/popup.rs
2026-07-17 14:39:23 +08:00
Breadway
86432d718a Design refresh: new icon assets, bluetooth popover, notification urgency styling, RAM/power draw in control panel
Adds real SVG icon assets replacing the icons-needed.txt checklist,
a bluetooth popover module, per-notification urgency (CSS-styled),
and app-name/summary dedup in notification cards. Rounds out the
control panel's stats section with RAM and power draw alongside the
existing CPU/GPU/net rows.
2026-07-17 14:36:33 +08:00
Breadway
1f2d58d97f breadbar: reconnect Hyprland event stream, fix notification spec violations, point lock button at breadlock
- src/bar/workspaces.rs: the Hyprland EventStream loop exited permanently
  on the first Err/end-of-stream (Hyprland restart/reload, IPC hiccup),
  freezing every workspace button for the bar's remaining life. Now wrapped
  in a reconnect loop with capped exponential backoff, re-syncing workspace
  state on every reconnect
- src/notifications/mod.rs + popup.rs: three spec deviations fixed —
  expire_timeout=0 now means never-expire instead of being coerced to 5s
  (and a critical-urgency notification with no explicit timeout also
  persists by default); NotificationClosed is now emitted with the correct
  reason code whenever a notification actually goes away (expiry or an
  explicit CloseNotification call); replaces_id no longer races its
  auto-dismiss timer against the replacement's, via a per-id generation
  counter checked before a stale timer is allowed to dismiss anything
- src/main.rs + README.md + assets/icons-needed.txt: lock button (and its
  docs) now invoke breadlock instead of hyprlock, the thing breadlock was
  built to replace
- src/notifications/mod.rs: added 4 unit tests for the new expire_timeout/
  urgency mapping (pulled into a pure compute_expire() for testability) —
  this crate had zero test coverage before
2026-07-17 08:40:32 +08:00
Breadway
e8d5fd5a52 Set layer-shell namespace to breadbar, bump version to 0.2.4
Some checks failed
Mirror to GitHub / mirror (push) Successful in 39s
Build and publish package / package (push) Failing after 5m4s
release / build (push) Successful in 6m33s
2026-07-10 18:04:31 +08:00
Breadway
8471cc02fe Make unsaved Nearby networks clickable, add password-entry dialog
Some checks failed
Mirror to GitHub / mirror (push) Successful in 1m14s
Build and publish package / package (push) Failing after 33s
release / build (push) Successful in 1m24s
Rows for scanned networks not yet in breadcrumbs' saved config were
both dimmed and disabled (set_sensitive(false)), so there was no way
to add them from the popover. They now stay visually dimmed via the
existing wifi-popover-row-unsaved style but remain clickable, opening
a small password dialog that saves + joins the network via
`breadcrumbs add` + `breadcrumbs join`.
2026-07-10 13:37:56 +08:00
Breadway
db5db79471 CI: migrate release workflow from GitHub Actions to Forgejo Actions
All checks were successful
Mirror to GitHub / mirror (push) Successful in 27s
GitHub Actions self-hosted runners need per-repo registration on a
personal account; Forgejo Actions' runner already serves every repo
with zero setup. Moves release publishing there (dl.breadway.dev stays
the primary bakery target; GitHub release upload is kept as the
fallback via an explicit token, since Forgejo Actions has no ambient
GITHUB_TOKEN) and adds a mirror workflow to keep GitHub in sync
automatically.
2026-07-03 14:10:01 +08:00
Breadway
31b2d10909 chore: repo cleanup for v0.2.0
All checks were successful
Mirror to GitHub / mirror (push) Successful in 32s
- Fix read_cpu_temp loop: ok()? was aborting iteration on unreadable hwmon
  entries instead of continuing to the next; use let Ok(...) else continue
- Fix osd.rs: replace stdout.unwrap() with defensive let-else guard
- PKGBUILD: bump pkgver to 0.2.0, replace libpulse dep with wireplumber +
  pipewire-pulse + brightnessctl (actual runtime tools used)
- bakery.toml: same dep fix as PKGBUILD
- Cargo.toml: fix repository URL casing (breadway -> Breadway)
- theme.rs: add wifi-popover-row-unsaved opacity rule
2026-06-24 07:05:07 +08:00
Breadway
3ae3eff59e Release 0.2.0: media widget, wifi popover, control panel 2026-06-24 06:43:52 +08:00
Breadway
0893724e5f Fix illegible text on light pywal palettes + hot-reload
Use bread-theme 0.2.7's luminance-picked ink (@on-*) for text on coloured
backgrounds: the active workspace pill and notification cards previously kept the
pywal foreground, which vanished when those slots came out light. Drop the
blanket label colour rule (it overrode the per-surface ink on child labels).

Switch to bread_theme::gtk::apply_app_css so the bar recolours live on
`bread-theme reload` instead of only at startup.
2026-06-17 12:40:52 +08:00
Breadway
0cb27ec1c4 theme: load the shared bread-theme stylesheet
Call bread_theme::gtk::apply_shared() before breadbar's own rules so fonts,
palette, and generic widgets come from the one ecosystem stylesheet (and
recolour live). Keep only breadbar-specific CSS (bar window, workspace
buttons, stats, notifications, OSD). Bump bread-theme dep to v0.2.6.
2026-06-16 16:56:52 +08:00
Breadway
1959a86157 Default workspace-button rounding to 0
Some checks failed
Mirror to GitHub / mirror (push) Successful in 31s
Build and publish package / package (push) Failing after 3m55s
2026-06-15 18:51:42 +08:00
Breadway
b098178058 Embed SVG assets and rasterise with resvg
Some checks failed
Mirror to GitHub / mirror (push) Successful in 33s
Build and publish package / package (push) Failing after 3m10s
The packaged binary panicked on startup ("svg load: Unrecognized image file
format"): asset SVGs were referenced by their build-time CARGO_MANIFEST_DIR
path (absent on an installed system, so read_to_string returned empty bytes),
and gdk::Texture::from_bytes can no longer decode SVG since librsvg dropped its
gdk-pixbuf loader.

- include_str! the SVGs into the binary (no runtime asset files)
- rasterise via resvg/tiny-skia into a gdk::MemoryTexture (no system loader)
2026-06-14 19:36:38 +08:00
Breadway
44a8d95887 feat: add system tray (StatusNotifierWatcher / SNI)
Some checks failed
release / build (push) Failing after 3s
Implements org.kde.StatusNotifierWatcher as a D-Bus service so apps
like Nextcloud can register their tray icons. Icons are rendered from
SNI ARGB pixmaps (falling back to icon-name theme lookup), click calls
Activate(0,0), and NameOwnerChanged cleans up ghost icons when an app
exits. Styling follows the Bread Design System (4px tertiary radius,
xs/sm spacing, opacity transitions).

Also fixes a latent infinite-loop risk in osd.rs (.flatten → .map_while)
and syncs the notifications server version string to CARGO_PKG_VERSION.
2026-06-11 22:31:25 +08:00
Breadway
4b66efa87c Refactor theme onto bread-theme; add bakery.toml and release workflow
- Cargo.toml: depend on bread-theme (path dep for local dev, git dep for
  production) with gtk feature; remove local theme dependencies
- src/theme.rs: replace local pywal/Catppuccin impl with bread_theme::gtk
  helpers; local bar-specific CSS is preserved
- bakery.toml: describes breadbar for bakery install
- release.yml: builds on hestia self-hosted runner, publishes binary to
  dl.breadway.dev and GitHub Releases on v* tags
2026-06-06 22:31:10 +08:00
Breadway
4a3604f78a Fixes 2026-05-19 12:31:26 +08:00
Breadway
e233750b24 General Dev 2026-05-18 23:01:52 +08:00
Breadway
255be18ca2 nvm actual init commit 2026-05-17 13:17:31 +08:00
Breadway
633467b6f2 Initial commit 2026-05-17 13:13:37 +08:00
Breadway
3100ee0591 step 8-10: notification daemon (zbus), popup window, SIGHUP theme reload 2026-05-17 08:50:08 +08:00
Breadway
f1b471652b step 6+7: live clock, CPU/MEM/power/battery/WiFi stats poller 2026-05-17 08:40:35 +08:00
Breadway
241e3bc2cb step 5: live Hyprland workspace buttons via EventStream 2026-05-17 08:34:31 +08:00
Breadway
542cbae939 step 3+4: pywal theme loader, three-section CenterBox layout 2026-05-17 01:00:32 +08:00
Breadway
1bbe9a2929 scaffold: Cargo.toml, module stubs, layer-shell window (step 1+2) 2026-05-17 00:38:19 +08:00