Two ways wl-pick could fail to appear at all, both fixed.
A second instance hung with no window and had to be killed: sway answers a
capture request for a toplevel another client is already capturing with
silence, and the wait for it was unbounded. Every wait before the overlay is
interactive now has a deadline, and a tile that never arrives is drawn as a
bare label. Losing the keyboard grab for good also ends a run, so a second
wl-pick replaces the first rather than stranding it on screen.
Starting wl-pick from a shell with a stale SWAYSOCK failed outright. The
running compositor's socket is now found in XDG_RUNTIME_DIR when the
environment's path does not connect.
Sizing is now specified as caps rather than as a thumbnail size: max-width
and max-height bound the overlay, max-columns and max-rows bound the grid
inside it, and a thumbnail is simply the one divided by the other. A
thumbnail is therefore the same size whether one window is open or thirty.
Rows past max-rows scroll, with a scrollbar, PgUp/PgDn, and the selection
kept in view. Tiles scrolled out of sight are unmapped, so live capture
skips them.
timeout = 0 now means no timeout instead of an immediate deadline.
Minor, not patch: colours and sizing move into a config file and the grid
scrolls, so behaviour people could depend on has changed shape.
- ~/.config/wl-pick/config sets colours, border, thumbnail size and the
flags, as flat `key = value` lines; a flag still beats the file.
- Sizes take sway's units. 70ppt is a percentage of the display the grid
appears on, resolved per run, so one config suits monitors of different
sizes. The overlay maps on the focused display explicitly, at that
display's scale, rather than taking the largest scale in use.
- Give only tile-width and the height follows the display's aspect, which
is roughly the shape of the windows on it.
- More rows than fit now scroll, with a scrollbar, PgUp/PgDn, and the
selection always revealed. Tiles out of view are unmapped and skipped
by live capture.
Also corrects rust-version, which said 1.88 while cosmic-text has needed
1.89 all along: cargo was resolving 0.1.1 against a floor its own
dependency could not meet, and said so if you looked. It now locks
cleanly.
The published 0.1.0 defaults the label font to Berkeley Mono, which falls
back to a non-monospaced face on any machine that does not have it. That
is a defect for every user but one, so it is a patch release rather than a
new feature: no flag was added, removed or renamed.
Also silences a lint that arrived with Rust 1.98. Clippy suggests
`as_chunks` in place of `chunks_exact`, but that API is newer than the
1.88 this crate declares as its minimum, so taking the suggestion would
break the builds the manifest promises to support.
wlgrid described the shape of the thing rather than what it is for, and
the shape is the least interesting part now that it doesn't focus
anything: it shows you what is running and reports which one you pointed
at. wl-pick says that.
The wl- prefix rather than wlr- is deliberate. The capture path is
entirely upstream ext- protocols (ext-image-copy-capture,
ext-image-capture-source, ext-foreign-toplevel-list); the only
wlroots-flavoured piece is layer-shell, which KDE, niri and labwc
implement too. What actually keeps this from running on other
compositors is the sway IPC dependency, not wlroots, so wlr- would
promise a portability that isn't there. Hyphenated because the ecosystem
hyphenates when the suffix is a real word — wl-clipboard, wl-mirror,
wl-screenrec — and reserves the smushed form for coinages like wlsunset.
Also renames the layer-shell namespace and the memfd labels, which show
up in compositor debugging.
"title · app" centred under each thumbnail, in the same font the rofi
theme used (Berkeley Mono at pango's "small"), with the selected tile's
label inverted onto the yellow the way rofi's element background did.
Long titles are ellipsised to the cell width.
Text comes from cosmic-text, which brings real shaping. The catch is
cost: building a font system and rasterising the first glyphs takes
~55ms, nearly doubling a 65ms startup. But the capture phase is ~55ms of
sitting blocked while the compositor copies pixels, so labels are shaped
on a worker thread started before the captures and joined after them.
The measured labels phase is now 0.0ms — it costs nothing in wall clock.
Two thirds of that font cost was FontSystem::new() scanning all 1793
system faces, which even new_with_fonts() does. So the database is built
by hand: the user's own font directories first, since they are small,
and the full system scan only when the family isn't found there. An
unknown family still resolves, because that fallback is exactly the
system scan (verified: --font "No Such Font" renders in Noto).
--hide-labels restores the icon-only grid, and --font/--font-size make
the family and size settable. Adds a test that a label actually puts
pixels on the surface, one for ellipsising, and one pinning the label row
into the element geometry.
A switcher to replace a wlthumbs + rofi pipeline, with the same look
(gruvbox, ceil(sqrt(n)) columns capped at 4, 16:9 tiles, a yellow
selection filling the element padding) but no thumbnails anywhere.
Each window is captured straight into a wl_shm buffer that is handed to
its own wl_subsurface, with wp_viewporter giving the compositor the
rectangle to scale it into. So there is no PNG encode, no scaler, no
full-resolution bitmap in this process, and the capture buffers are never
even mapped here — the compositor writes those pages and samples them
again for display. Opens in ~65ms for 8 windows (55ms of which is the
compositor reading pixels back out of the GPU) and holds ~9MB of RSS.
All capture sessions are opened before a single roundtrip and every frame
goes in flight together, the same batching wlthumbs uses, because the
readback is bandwidth-bound rather than latency-bound.
sway remains the source of truth: the window list, the con_ids and the
focusing all come from its IPC socket, joined to the Wayland side by
foreign_toplevel_identifier. Navigation reads raw evdev keycodes so it is
layout-independent, which does mean virtual-keyboard clients that invent
their own keymap can't drive it; that resolves when filtering brings xkb.
Labels, type-to-filter and live previews are next.