fix(hyprland): migrate window rules to Hyprland 0.53+ syntax
Some checks failed
Check / eval (push) Has been cancelled

The default desktop showed a red Hyprland config-error banner on every
boot, occluding the Waybar. Root cause: Hyprland 0.53 rewrote window
rules — the `windowrulev2` keyword is a hard error and the old
rule-first order (`float, class:^…$`) no longer parses, so the float
rules were not applying either. Confirmed against the Hyprland 0.55.4
source (`handleWindowrule`): each comma field is now `<keyword> <value>`,
so effects carry a value and matchers take a `match:` prefix.

Migrated the 7-rule block to `float 1, match:class ^…$` form.

Verified: V0 nix flake check --no-build; built the generated
hyprland.conf; V2 theme-shot re-render — banner gone, themed Waybar
renders. Journal + MEMORY gotcha added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Bernardo Magri
2026-07-09 18:24:55 +01:00
parent 5c875542d0
commit ed7fd93e16
3 changed files with 38 additions and 9 deletions

View File

@@ -17,6 +17,23 @@ Template:
--- ---
## 2026-07-09 — Fix Hyprland windowrule config-error banner (windowrule 0.53 migration)
- **Task:** bug tripped over while doing #45 (VM Boreal verify) — the default
desktop showed a red Hyprland config-error banner on every boot, occluding
the Waybar.
- **Did:** Root-caused via the theme-shot harness + Hyprland 0.55.4 source
(`handleWindowrule`): Hyprland 0.53 rewrote window rules — `windowrulev2` is a
hard error and the old rule-first `float, class:^…$` order no longer parses
(so the float rules weren't even applying). Migrated the 7-rule block in
`modules/home/hyprland.nix` to the new hyprlang grammar `<effect> <value>,
match:<prop> ^…$` (e.g. `float 1, match:class ^…$`).
- **Verified:** V0 `nix flake check --no-build` green; built the generated
`hyprland.conf` and confirmed emitted lines; **V2** theme-shot re-render —
banner gone, themed Waybar now renders (violet accent, GeistMono clock).
- **Pending:** none for the fix. A cheap `checks.*` that greps the generated
conf for the dead rule-first pattern could lock it (PROPOSED).
- **Next suggestion:** finish #45 (capture boreal preview.png), then #46.
## 2026-07-09 — Default theme → Boreal (item #42) ## 2026-07-09 — Default theme → Boreal (item #42)
- **Task:** NEXT #42 — distro default theme Tokyo Night → Boreal (`VISION § B` / v1.0 bar). - **Task:** NEXT #42 — distro default theme Tokyo Night → Boreal (`VISION § B` / v1.0 bar).
- **Did:** Seeded `theme-state.json` + `templates/downstream/theme-state.json` from `themes/boreal.json` (incl. border + settings). Eval fallbacks: `theme.nix` preset → boreal.json; plymouth + live ISO splash hex fallbacks; theme-shot / theme-sync examples; TESTING/RECOVERY wording. - **Did:** Seeded `theme-state.json` + `templates/downstream/theme-state.json` from `themes/boreal.json` (incl. border + settings). Eval fallbacks: `theme.nix` preset → boreal.json; plymouth + live ISO splash hex fallbacks; theme-shot / theme-sync examples; TESTING/RECOVERY wording.

View File

@@ -103,6 +103,11 @@ iteration would otherwise rediscover.
- Update order matters downstream: `sys-update` (lock) before - Update order matters downstream: `sys-update` (lock) before
`home-update`, or desktop changes are silently skipped against the old `home-update`, or desktop changes are silently skipped against the old
lock (README § 3). lock (README § 3).
- Hyprland 0.53 rewrote window rules: `windowrulev2` is a hard error and
the old rule-first `float, class:^…$` no longer parses — both surface a
red config-error banner on the default desktop. Hyprlang legacy form is
now `<effect> <value>, match:<prop> ^…$` (e.g. `float 1, match:class ^…$`);
effects carry a value, matchers take `match:` (§ windowrule migration).
- grub `loadfont`s every `.pf2` in a theme dir — reuse a bundled DejaVu - grub `loadfont`s every `.pf2` in a theme dir — reuse a bundled DejaVu
rather than shipping fonts (§ Distro branding). rather than shipping fonts (§ Distro branding).
- The Claude Code harness drops machine-local files into the repo - The Claude Code harness drops machine-local files into the repo

View File

@@ -459,7 +459,14 @@ in
# Window rules — float + center small config/utility dialogs that # Window rules — float + center small config/utility dialogs that
# tile awkwardly. Normal-priority list like `bind`/`exec-once` below, # tile awkwardly. Normal-priority list like `bind`/`exec-once` below,
# so a downstream `windowrule = [...]` concatenates rather than # so a downstream `windowrule = [...]` concatenates rather than
# replaces. Class regexes use `(?i)` and tolerate the XWayland # replaces. Syntax is the post-0.53 rule rewrite (hyprlang legacy
# parser, `handleWindowrule`): each comma field is `<keyword>
# <value>`, so effects carry a value (`float 1`, `center 1`, `size
# W H`) and matchers take a `match:` prefix (`match:class ^…$`).
# The old rule-first form (`float, class:^…$`) and the
# `windowrulev2` key are both hard errors now (red config-error
# banner on every session start — seen in the capture harness).
# Class regexes use `(?i)` and tolerate the XWayland
# `.…-wrapped` binary-name form. # `.…-wrapped` binary-name form.
# #
# Conservative set on purpose (item 41): only windows the distro # Conservative set on purpose (item 41): only windows the distro
@@ -468,21 +475,21 @@ in
# prompt (hyprpolkitagent exposes no discoverable class) and GTK # prompt (hyprpolkitagent exposes no discoverable class) and GTK
# file-chooser portals. A dead rule is harmless, but guessing a class # file-chooser portals. A dead rule is harmless, but guessing a class
# is worse than leaving it for a verified pass. # is worse than leaving it for a verified pass.
windowrulev2 = [ windowrule = [
# Audio mixer (item 35): right-click the Waybar volume module. # Audio mixer (item 35): right-click the Waybar volume module.
"float, class:^(com\\.saivert\\.pwvucontrol|org\\.pulseaudio\\.pavucontrol|pavucontrol)$" "float 1, match:class ^(com\\.saivert\\.pwvucontrol|org\\.pulseaudio\\.pavucontrol|pavucontrol)$"
"center, class:^(com\\.saivert\\.pwvucontrol|org\\.pulseaudio\\.pavucontrol|pavucontrol)$" "center 1, match:class ^(com\\.saivert\\.pwvucontrol|org\\.pulseaudio\\.pavucontrol|pavucontrol)$"
# Bluetooth manager (blueman) + CUPS printer admin. # Bluetooth manager (blueman) + CUPS printer admin.
"float, class:(?i)^(\\.?blueman-(manager|adapters)(-wrapped)?|\\.?system-config-printer(-wrapped)?)$" "float 1, match:class (?i)^(\\.?blueman-(manager|adapters)(-wrapped)?|\\.?system-config-printer(-wrapped)?)$"
"center, class:(?i)^(\\.?blueman-(manager|adapters)(-wrapped)?|\\.?system-config-printer(-wrapped)?)$" "center 1, match:class (?i)^(\\.?blueman-(manager|adapters)(-wrapped)?|\\.?system-config-printer(-wrapped)?)$"
# Calendar popup (item 42): the Waybar clock's on-click runs # Calendar popup (item 42): the Waybar clock's on-click runs
# nomarchy-calendar → calcurse in a ghostty window tagged with a # nomarchy-calendar → calcurse in a ghostty window tagged with a
# distinct --class, so it floats centered instead of tiling. # distinct --class, so it floats centered instead of tiling.
"float, class:^(com\\.nomarchy\\.calendar)$" "float 1, match:class ^(com\\.nomarchy\\.calendar)$"
"size 60% 65%, class:^(com\\.nomarchy\\.calendar)$" "size 60% 65%, match:class ^(com\\.nomarchy\\.calendar)$"
"center, class:^(com\\.nomarchy\\.calendar)$" "center 1, match:class ^(com\\.nomarchy\\.calendar)$"
]; ];
# Rendered from ./keybinds.nix (the cheatsheet reads the same list), # Rendered from ./keybinds.nix (the cheatsheet reads the same list),