Files
Panama/config/dot/hypr/rules.lua
T
Gabriel Brown d96863b687 Convert British spellings to American across the repo
colour -> color, behaviour -> behavior, centre -> center, favourite ->
favorite, and about twenty other pairs, applied consistently across
comments, docs, error/UI copy, and a handful of QML identifiers that
used the British spelling as their actual name: SystemSettings'
serialiseValue/serialiseTable/normaliseGradient, Displays'
normaliseModes, Wallpaper's normalisePolicy, SettingsBackup's
serialiseHomeState, DateTime's ntpSynchronised property, Clipboard's
_normalise helper, and ShortcutCapture's cancelled signal (with its
onCancelled handler in ShortcutsPage.qml). Every call site and the two
tests that assert on the literal source text (settings-ownership and
settings-backup-live contracts) were updated in lockstep.

Left untouched: config/dot/espanso/match/packages/misspell-en/ is a
vendored third-party autocorrect dictionary -- its entries are typo
corrections, not our prose, and rewriting them would fight the
package's own purpose (and any future re-sync from upstream).

The already-American `favorites` property (Home page pinned
accessories) was never actually misspelled -- only nearby comments and
error strings said "favourites" -- so no data migration was needed
there.

Claude-Session: https://claude.ai/code/session_01E6TJUAh41HaP25MVHWkhRZ
2026-08-19 08:07:55 -04:00

208 lines
7.5 KiB
Lua

-- ─────────────────────────────────────────────────────────────────────────────
-- Window, workspace and layer rules
--
-- Rules evaluate top to bottom, last match wins -- but every NAMED rule is
-- evaluated before every anonymous one, so a named rule can never override an
-- anonymous rule further down. Names are used sparingly here for that reason.
--
-- Matching is Google RE2 (no backtracking). Prefix a pattern with "negative:"
-- to invert it.
-- ─────────────────────────────────────────────────────────────────────────────
-- ── Upstream sanity rules ───────────────────────────────────────────────────
hl.window_rule({
name = "suppress-maximize-events",
match = { class = ".*" },
suppress_event = "maximize",
})
hl.window_rule({
name = "fix-xwayland-drags",
match = {
class = "^$",
title = "^$",
xwayland = true,
float = true,
fullscreen = false,
pin = false,
},
no_focus = true,
})
-- ── Floating apps ───────────────────────────────────────────────────────────
-- Carried over from the Forge windows.json override list, minus entries for
-- apps that are no longer installed.
hl.window_rule({
match = {
class = "^(jetbrains-toolbox|zoom|Cider|Hidamari|com\\.mattjakeman\\.ExtensionManager)$",
},
float = true,
})
hl.window_rule({
match = { class = "^([Bb]itwarden|com\\.bitwarden\\.desktop)$" },
float = true,
})
hl.window_rule({
match = { class = "^(com\\.nextcloud\\.desktopclient\\.nextcloud|Nextcloud)$" },
float = true,
})
hl.window_rule({
match = { class = "^(org\\.gnome\\.Calculator|gnome-calculator)$" },
float = true,
size = { 400, 600 },
center = true,
})
hl.window_rule({
match = { class = "^(mpv|io\\.mpv\\.Mpv)$" },
float = true,
-- Video should never be blurred or dimmed behind another window.
no_blur = true,
no_dim = true,
})
hl.window_rule({
match = { class = "^(com\\.spotify\\.Client|Spotify)$" },
float = true,
})
-- Settings-style utility windows and pickers: float and center, like GNOME did.
hl.window_rule({
match = { class = "^(pavucontrol|org\\.pulseaudio\\.pavucontrol|nm-connection-editor|blueman-manager|org\\.gnome\\.Settings)$" },
float = true,
size = { "monitor_w * 0.45", "monitor_h * 0.6" },
center = true,
})
-- Portal dialogs (file chooser, screen share picker) should always float.
hl.window_rule({
match = { class = "^(xdg-desktop-portal-gtk|org\\.freedesktop\\.impl\\.portal\\.desktop\\.gtk|hyprland-share-picker)$" },
float = true,
center = true,
})
hl.window_rule({
match = { title = "^(Open File|Save File|Save As|Open Folder|Select a File|Choose Files)$" },
float = true,
center = true,
})
-- Polkit prompt.
hl.window_rule({
match = { class = "^(hyprpolkitagent|polkit-gnome-authentication-agent-1)$" },
float = true,
center = true,
})
-- ── Gaming ──────────────────────────────────────────────────────────────────
-- content = "game" is the keystone: misc.vrr = 3, render.direct_scanout = 2 and
-- cursor.no_break_fs_vrr = 2 all key off it. Blur, animation, shadow and dim are
-- all disabled so the compositor gets out of the way entirely.
hl.window_rule({
match = { class = "^(steam_app_\\d+|gamescope|lutris|net\\.lutris\\.Lutris|com\\.heroicgameslauncher\\.hgl|Minecraft.*|moonlight|com\\.moonlight_stream\\.Moonlight)$" },
content = "game",
immediate = true,
no_blur = true,
no_anim = true,
no_shadow = true,
no_dim = true,
})
-- Steam itself is a normal window, but its transient popups are a mess.
hl.window_rule({
match = { class = "^steam$", title = "^(Friends List|Steam Settings|Special Offer.*)$" },
float = true,
})
-- Fullscreen video in a browser also benefits from no blur / no dim.
hl.window_rule({
match = { fullscreen = true },
no_blur = true,
no_dim = true,
})
-- ── Workspace rules ─────────────────────────────────────────────────────────
-- Deliberately NO "smart gaps".
--
-- The usual trick is to strip gaps, border and rounding when a workspace holds
-- a single tiled window (`workspace = "w[tv1]"` + matching window rules). It
-- was here and it was wrong for this setup: the common case is one window on a
-- workspace, so the desktop spent most of its time square-cornered and
-- edge-to-edge -- the opposite of the intended look. Gaps and rounding are
-- constant now, however many windows are open.
-- ── Layer rules (Quickshell surfaces) ───────────────────────────────────────
-- Namespaces are set in QML via WlrLayershell.namespace; keep these regexes and
-- those strings in sync. `hyprctl layers` lists what is actually live.
--
-- The bar intentionally has no rule: it is a transparent edge-to-edge input
-- surface, not glass. Its individual controls paint their own hover feedback.
-- Keeping a full-width blur rule here would spend compositor work on pixels
-- the bar does not draw.
hl.layer_rule({
name = "qs-dock",
match = { namespace = "^qs-dock$" },
blur = true,
ignore_alpha = 0.3,
})
-- Popovers: calendar, quick settings, notification center, tray menus.
hl.layer_rule({
name = "qs-popover",
match = { namespace = "^qs-popover" },
blur = true,
blur_popups = true,
ignore_alpha = 0.2,
})
-- Overview, capture and local screen-reading UI dim the desktop behind them.
hl.layer_rule({
name = "qs-overlay",
match = { namespace = "^qs-(overview|capture|screen-intelligence)$" },
blur = true,
ignore_alpha = 0.4,
dim_around = true,
no_screen_share = true,
})
-- Notification toasts. Blurred like every other shell surface -- without this
-- the cards are a near-transparent fill sitting directly on the wallpaper and
-- read as washed out rather than as glass.
--
-- no_anim because the toasts animate themselves in QML, and no_screen_share so
-- they don't leak into OBS or Sunshine streams.
hl.layer_rule({
name = "qs-notifications",
match = { namespace = "^qs-notifications$" },
blur = true,
ignore_alpha = 0.15,
no_anim = true,
no_screen_share = true,
})
-- Signal Glass provides its own event-driven motion, so the compositor only
-- supplies the material blur and privacy behavior.
hl.layer_rule({
name = "qs-signal-glass",
match = { namespace = "^qs-signal-glass$" },
blur = true,
ignore_alpha = 0.15,
no_anim = true,
no_screen_share = true,
})
-- The launcher blurs and dims whatever is behind it.
hl.layer_rule({
name = "launcher",
match = { namespace = "^(vicinae|wofi)$" },
blur = true,
ignore_alpha = 0.5,
dim_around = true,
})
return true