Commit graph

17 commits

Author SHA1 Message Date
Breadway
7ec232b86d bread-capture: one command for every app, flags for a single one
Plain `bread-capture` with no flags now captures every known app's every
view in one run — each binary resolved by its own bare name via $PATH,
same as invoking it directly by name would (so an installed bread
ecosystem needs nothing but `bread-capture` to regenerate every
screenshot). Previously --app-path was required, so there was no way to
run more than one app per invocation.

--app <name> restricts to a single app (resolved via $PATH, no path
needed); --app-path still works alone too, inferring which app by its
file stem exactly as before. --view <name> further restricts to one
view — apps without a matching view are silently skipped rather than
treated as an error, since view names naturally don't overlap across
apps in a multi-app run, but an unmatched --view in a single-app run (or
one that matches nothing across every selected app) is still a real
error.
2026-07-29 21:54:46 +08:00
Breadway
94feaa6f9b bread-capture: add bos-settings' 24 sidebar-section views to target registry 2026-07-29 21:45:18 +08:00
Breadway
669ca64284 bread-capture: add breadhelp's troubleshoot-wizard view to target registry 2026-07-29 21:37:33 +08:00
Breadway
271555fb80 bread-capture: add breadpad's reminder + reminder-snooze views to target registry 2026-07-29 21:32:44 +08:00
Breadway
c0b489fa67 bread-capture: add breadman's 11 additional views to target registry 2026-07-29 17:27:12 +08:00
Breadway
64cc17905d bread-capture: add breadbar's 8 new views to target registry 2026-07-29 17:17:35 +08:00
Breadway
e3df426996 bread-capture: rainbow-gradient isolation background instead of flat color
A solid background can't reveal whether a surface that's supposed to be
translucent (breadbox/breadclip/breadsearch's full-screen overlay
windows, breadbar's alpha-blended notification/OSD surfaces) is actually
compositing as translucent — a flat color showing through a flat color
still just looks flat. Generates a diagonal rainbow gradient (full hue
sweep, via the `image` crate) sized exactly to the capture canvas and
sets it as Sway's output background instead.

Needed installing swaybg (the external helper Sway's `output ... bg`
config directive shells out to) — without it the bg command silently
no-ops and the canvas stays black, which is why the first attempt at
this looked identical to the old flat-color version.
2026-07-29 17:02:09 +08:00
Breadway
cdcb931f37 bread-capture: add bos-settings to target registry 2026-07-29 16:48:01 +08:00
Breadway
af796253e9 bread-capture: add breadman to target registry 2026-07-29 16:37:14 +08:00
Breadway
1ce5514939 bread-capture: add breadhelp to target registry 2026-07-29 11:49:33 +08:00
Breadway
03749787c5 bread-capture: add breadpad to target registry 2026-07-29 11:44:00 +08:00
Breadway
f06ba904b7 bread-capture: add breadsearch to target registry 2026-07-29 11:40:28 +08:00
Breadway
231f71e586 bread-capture: add breadclip to target registry 2026-07-29 11:37:17 +08:00
Breadway
21099065c4 bread-capture: generalize target registry, fix Drop-skipped-on-exit leak
Replaces the breadbar-only hardcoded view list with a registry keyed by
app name (--app-name, defaulting to --app-path's file stem) so wiring up
each new app just means adding one entry, not touching the CLI shape.

Also fixes a real leak found while testing breadbox against this:
std::process::exit() on the failure path skipped every destructor,
including Isolation's Drop — so a failed capture run (or, more subtly,
*any* run against an app whose view list didn't match yet, which is
exactly what happened testing this) permanently orphaned the headless
Sway process and its wayland-N/.lock socket pair. main() now returns
ExitCode instead of calling process::exit directly, so Drop always runs.
2026-07-29 11:33:06 +08:00
Breadway
d059d99437 bread-capture: switch capture isolation to headless Sway
Nested Hyprland worked but had real limits: the outer compositor decided
the nested window's pixel size (needing an outer-session float+resize
dispatch per capture), occluded surfaces got no frame callbacks (so grim
hung unless the nested window was also focused/raised), and there was no
way to fully suppress a brief real, visible flash of that window on the
operator's desktop.

wlroots' WLR_BACKENDS=headless (Sway, not Hyprland, is built on wlroots
directly) has a genuine headless backend: no seat/DRM-master claim, no
window anywhere, ever. Confirmed empirically: zero visible footprint,
both zwlr_layer_shell_v1 and zwlr_screencopy_manager_v1 present, grim
completes instantly with no focus dance needed.

This drops the Hyprland-specific plumbing that no longer applies:
- bread-screenshots now exposes one compositor-agnostic capture_region
  primitive instead of capture_layer/capture_output, since the isolated
  canvas size is always known up front rather than queried via hyprctl.
- bread-utils::hypr loses the Monitor scale/transform/logical_size and
  Layer/find_layer additions that only existed to support that querying.
- bread-capture's isolation module spawns headless Sway instead of a
  nested Hyprland instance, and passes --width/--height through to the
  target app so it knows the canvas size without asking anyone.

Also fixes a socket leak in isolation teardown: killing the compositor
(Hyprland or Sway) doesn't unlink the wayland-N/.lock files it created,
so every capture run was orphaning a socket pair in the runtime dir.
Drop now removes them explicitly.
2026-07-29 11:15:41 +08:00
Breadway
bcd57b7b54 bread-capture: isolate captures in a throwaway nested Hyprland instance
Captures now run inside a dedicated nested Hyprland session by default
(--no-isolate to opt out), so nothing on the operator's live desktop can
leak into a screenshot and the capture never flashes across their screen
either. The nested instance nests as a Wayland client of the outer session
(true headless was ruled out empirically: this machine's real GPU/output is
already claimed by the live session, and only one process can hold logind's
seat at a time), gets floated/exact-resized/focused via one-shot outer-session
hyprctl dispatches targeted by pid, and has Hyprland's default background/
logo and startup warning overlays disabled via config so captures come out
clean. Focusing turned out to be load-bearing, not cosmetic: an occluded
nested window never gets frame callbacks from the outer compositor, so grim
run inside it hangs forever waiting on a ready event that never comes.
2026-07-23 16:22:24 +08:00
Breadway
007082374d Add bread-screenshots + bread-capture: foundation for UI screenshot tooling
New bread-screenshots crate captures a layer-shell surface (by namespace+pid,
to disambiguate from an already-running instance) or the whole focused
output via grim, using bread-utils::hypr/proc. bread-utils::Monitor gains a
scale field and logical_size() so output geometry accounts for HiDPI/
transform, matching breadshot's proven math. bread-utils::hypr gains
find_layer() over hyprctl layers -j.

bread-capture is a small orchestrator that drives an app's --screenshot mode
and collects the resulting PNGs; hardcoded to breadbar's two views for now.
2026-07-23 14:15:49 +08:00