16 Commits
Author SHA1 Message Date
Bendik Aagaard LynghaugandClaude Fable 5.1 4f055935d4 backlight: run without a backlight device instead of panicking (0.4.3)
Release / package (x86_64, /var/local/cargo-target/iris-cargo-home, bare, /usr/bin/sccache, /var/local/rustup, /var/local/cargo-target) (push) Successful in 43s
Release / package (aarch64, , aarch64, , , ) (push) Successful in 2m20s
A config carrying a !backlight widget on a machine with nothing under
/sys/class/backlight (a laptop config on a desktop) hit
expect("did not find backlight device") in Backlight::new, which with
panic = "abort" killed wldash before a window appeared.

The device path is now Option<PathBuf>. A missing device, or a
configured `device` name that does not exist, prints one line on stderr
and leaves the widget in place so layout indices stay aligned: it
renders empty, skips sysfs reads and writes, and ignores clicks.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-05 13:54:13 +02:00
Bendik Aagaard LynghaugandClaude Fable 5.1 63179b9c47 fonts: fall back to fontconfig when a pinned font path is missing (0.4.2)
Release / package (x86_64, /var/local/cargo-target/iris-cargo-home, bare, /usr/bin/sccache, /var/local/rustup, /var/local/cargo-target) (push) Failing after 0s
Release / package (aarch64, , aarch64, , , ) (push) Failing after 1s
A config generated on one machine pinned
/usr/share/fonts/google-noto/NotoSans-Regular.ttf; on another host the
same package installs under fonts/noto, so the shared config made the
fontloader thread panic ("Font file not found") and, with panic =
"abort", kill wldash before a window appeared.

resolve_font_path() now uses a pinned path only if the file exists,
otherwise asks fontconfig for the name (what fc-match does) and says so
on stderr. find_font() and FontLoader::from_path() return errors
instead of unwrapping, and an unresolvable font exits with one clear
line. Generated configs leave font_paths unset so names resolve per
machine; pinning remains possible by hand.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 09:50:02 +00:00
Bendik Aagaard LynghaugandClaude Fable 5.1 d1df30d6d0 release 0.4.1
Release / package (x86_64, /var/local/cargo-target/iris-cargo-home, bare, /usr/bin/sccache, /var/local/rustup, /var/local/cargo-target) (push) Successful in 42s
Release / package (aarch64, , aarch64, , , ) (push) Successful in 2m14s
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 09:42:49 +00:00
Bendik Aagaard LynghaugandClaude Fable 5.1 9953865128 launcher: scan desktop files directly, keep state in XDG_STATE_HOME
The desktop-entry cache lived in $XDG_CACHE_HOME/wldash/desktop.json.
On an NFS-shared home that is a remote read and write on every start
(unless the session happens to export a machine-local XDG_CACHE_HOME),
and it went stale whenever a package was installed until someone ran
--desktop-refresh. Scanning the applications directories takes a few
milliseconds over local /usr/share and already happened on a background
thread, so the cache bought nothing: drop it, along with simd-json and
the serde derives on Desktop. --desktop-refresh stays as a no-op so old
key bindings keep working.

Calculator history and the prompt saved on Escape are state, not cache:
they move to $XDG_STATE_HOME/wldash (~/.local/state), written only on
Enter/Escape, and the old cache location is still read as a fallback.

With the serde derives gone, two Desktop fields were unused; use them:
Type=Link entries now open their URL with xdg-open, and Terminal=true
entries run under $TERMINAL -e when it is set.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 09:33:12 +00:00
Bendik Aagaard LynghaugandClaude Fable 5.1 03a3c681b0 packaging: PKGBUILD, changelog and tag-driven release workflow (0.4.0)
Release / package (x86_64, /var/local/cargo-target/iris-cargo-home, bare, /usr/bin/sccache, /var/local/rustup, /var/local/cargo-target) (push) Successful in 1m12s
Release / package (aarch64, , aarch64, , , ) (push) Successful in 2m31s
Same shape as uhhm/gdo: a v* tag runs makepkg on the x86_64 (ergo,
"bare") and aarch64 (klokka) runners, uploads to the [uhhm] Arch
registry under namespace bl, and creates a release with the changelog
section as notes. The tag must agree with PKGBUILD's pkgver and
Cargo.toml's version. Without a REGISTRY_TOKEN secret the publish step
warns and skips so the build is still verified.

Version jumps to 0.4.0 because upstream already tagged v0.2.1 and
v0.3.0 on this history before the rewrite reset Cargo.toml to 0.2.0.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 09:28:22 +00:00
Bendik Aagaard LynghaugandClaude Fable 5.1 1c6a536026 clippy: clean up all warnings
Mostly `cargo clippy --fix`: needless borrows, redundant field names,
match -> if let, io::Error::other, Option::filter/map, let chains, c""
literals. By hand: drop unused impl lifetimes, a type alias for the
font preload map, Iterator::find in next_buffer, contains_key, and
allow new_ret_no_self where constructors intentionally return the
boxed/generic wrapper type.

No functional change; tests and release build unchanged.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 09:20:25 +00:00
Bendik Aagaard LynghaugandClaude Fable 5.1 42ffe9c492 cargo fmt
Pure formatting, no functional change.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 09:16:15 +00:00
Bendik Aagaard LynghaugandClaude Fable 5.1 856f8d8bf4 readme: document the fork and /etc/wldash/config.yml precedence
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 09:15:57 +00:00
Bendik Aagaard LynghaugandClaude Fable 5.1 eea3a78140 main: clear error messages and exit codes instead of panics
Missing/invalid config, unwritable config target, failed Wayland connect
and bad arguments now print one line to stderr and exit 1 rather than
panicking with "uh" or a serde backtrace.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 09:15:56 +00:00
Bendik Aagaard LynghaugandClaude Fable 5.1 8c319cffc6 keyboard/state: handle repeat rate 0, let widgets see Escape
- wl_keyboard.repeat_info with rate 0 means "no repeat"; we divided by it.
- an unknown keymap format hit unreachable!() instead of being ignored.
- raw keycode 1 (Escape) returned before widgets were dispatched, so the
  launcher's Escape handler (which saves the prompt for Ctrl+R) never ran.
  Dispatch first, then fall back to quitting.
- always lay out on the first layer-surface configure, even when the
  compositor hands us exactly the placeholder dimensions.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 09:15:56 +00:00
Bendik Aagaard LynghaugandClaude Fable 5.1 450a20bf63 widget: fix Geometry::expand using other.height twice
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>
2026-10-03 09:15:55 +00:00
Bendik Aagaard LynghaugandClaude Fable 5.1 6af81b587c buffer: switch to memmap2, destroy shm pools, never underflow refcounts
memmap 0.7 is unmaintained (RUSTSEC-2020-0077); memmap2 is a drop-in
replacement. Drop the unused shlex dependency.

Each resize created a new wl_shm_pool that was never destroyed; keep the
pool on the buffer and destroy it with it. A wl_buffer.release for a
buffer we didn't consider acquired used to underflow refcnt and wedge
rendering. Fix the lifetime-elision warnings while here.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 09:15:54 +00:00
Bendik Aagaard LynghaugandClaude Fable 5.1 c033335912 widgets: stop aborting on machines without backlight/battery/pulseaudio
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>
2026-10-03 09:15:54 +00:00
Bendik Aagaard LynghaugandClaude Fable 5.1 01af00b5ea desktop: hash entries the same way they compare, only parse *.desktop
Desktop derived Hash over every field but PartialEq compared only the
name, violating the Hash/Eq contract the launcher's HashMap relies on
(clippy denies this by default, so `cargo clippy` failed to build).

Also skip directories and files without a .desktop extension (mimeinfo
cache, .directory files, ...) and stop unwrapping non-UTF-8 paths.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-03 09:15:53 +00:00
Bendik Aagaard LynghaugandClaude Fable 5.1 2bed8b7fac launcher: make the prompt cursor consistently grapheme-based
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>
2026-10-03 09:15:53 +00:00
Bendik Aagaard LynghaugandClaude Opus 4.8 1367bd8591 config: prefer machine-local /etc/wldash/config.yml when present
On a shared (NFS-roamed) home, ~/.config/wldash/config.yml is identical on
every machine. Prefer a host-specific /etc/wldash/config.yml when it exists so
each machine can keep its own layout without conflicting; --config still
overrides both. Enables the 'factor host-specific config to /etc' pattern for
shared-home fleets.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-16 14:16:22 +02:00