The bounding-box height was computed from other.height + other.height
instead of other.height + other.y, so the combined damage rectangle sent
to the compositor was wrong whenever a widget's drawn area changed.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The release profile builds with panic = "abort", so a panic in any helper
thread took the whole dashboard down:
- backlight: WalkDir yields /sys/class/backlight itself, so detect() was
always true and new() picked the class dir as the device, then panicked
reading brightness. Use min_depth(1) and tolerate read errors.
- battery: detect() only checked that UPower's DisplayDevice answered,
which it does on every machine; use IsPresent. The monitor thread now
returns an error instead of unwrapping, and publishes its first reading.
- pulseaudio: a failed connection panicked ("damn"); clicks before the
first sink query unwrapped a None channel map. Both are now handled, and
the connect loop no longer busy-spins.
- bar widget: don't underflow when narrower than the label column.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
set(), end() and move_cursor() used the byte length of the input as the
cursor bound while append/backspace/delete/clear_* index a grapheme table.
Any non-ASCII input (æøå, emoji) followed by End or typing past the end
indexed out of bounds and, with panic = "abort" in release, killed wldash.
While here:
- clamp Up so the selection can't run past the last row (every widget now
reports its row count), and make mouse selection underflow-safe
- strip all desktop-entry field codes from Exec (%i %c %k ... and %% -> %),
not just %f/%F/%u/%U
- report a failed spawn instead of panicking
- size the highlight colour table by chars, matching the drawing code
Adds unit tests for the prompt and the field-code stripping.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>