PolkitPanel replaces BarPanel as the dialog's chrome. Deliberately not a
subclass or a fork: most of BarPanel is density machinery — summary slot,
animated height, state pair, transitions — that a modal never uses, and
inheriting it would tie the dialog's look to a component whose real job is the
rail, so every restyle here would have to be justified against the panels up
there. It keeps the shell's silhouette (cut corners with detached accent caps,
the accent rules, the header strip) and drops the rail's tick decoration.
ESC closes the rail. The bar had no keyboard focus at all, so this adds it,
gated by the shell rather than left to the compositor to arbitrate between two
exclusive surfaces — that resolves by stacking and would invert silently the
day the layers change:
grabsKeyboard: shell.expanded && !polkit.prompting
so ESC dismisses the prompt while one is open and closes the rail afterwards.
Verified by instrumenting the handoff: expanded -> true, prompt open -> false,
prompt dismissed -> true, collapsed -> false. Note the rail now takes EXCLUSIVE
keyboard focus while expanded, which is the cost of answering a keypress the
user has not aimed at anything.
The dialog sits a third of the way down rather than centred, panel centre on
the third so it grows symmetrically as the message wraps, floored at a margin
so a tall prompt on a short output cannot be pushed off the top.
Also carries the backdrop tuning: dim 0.75 -> 0.65, gridOpacity 0.15 -> 0.10,
crossOpacity 0.45 -> 0.15, now that the scrim is used by the prompt as well as
the rail.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GAq2kKCLazZmrKvkd3akud
Moves PolkitPrompt from shell.qml into HyprChromeShell. Whether a prompt is
open is shell state by the same rule as the screen and the layer pair: two
surfaces read it.
The prompt no longer carries a backdrop of its own. There is one
ChromeBackdrop per output and a prompt raises them all, so a prompt over an
already-expanded rail reuses the scrim that is there rather than stacking a
second one on it, and a prompt over a collapsed rail expands that same scrim
from its bar-height band to the whole output.
The layer pair now keys off `scrimUp` (expanded OR prompting) rather than off
the density, which keeps bar and backdrop exactly one level apart in every
state. A prompt over a collapsed rail raises both: BACKGROUND sits under
ordinary windows so a scrim there dims nothing, and the bar has to stay one
above the scrim or the shell dims its own chrome. The rail is raised but
stays collapsed — its layer answers to the scrim, its height to `expanded`.
Outputs the rail does not live on get a scrim only while a prompt is up; a
modal that dims one monitor and leaves the others lit does not read as modal.
Expanding the rail still dims only the rail's screen, which is the existing
behaviour and the right one.
The dialog follows Hyprland.focusedMonitor rather than the rail's screen — a
password prompt belongs where the user is looking — matched by name against
Quickshell.screens, falling back to the rail's screen rather than to nothing.
SUPER A is frozen while a prompt is open, and dropped rather than queued, so
the rail does not spring open the moment the dialog goes.
Verified on two monitors via hyprctl layers, both densities, plus the toggle
block with an odd number of presses (two cancel out and prove nothing).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GAq2kKCLazZmrKvkd3akud
A chamfer with no neighbour behind it now carries the corner it removed,
put back OUTSIDE the panel as a detached accent triangle. capGap is the
perpendicular distance from the cut, hence the per-axis shift of capGap
over root 2: the cap moves along the cut's normal, not along an axis.
The trace joining two caps belongs to the RAIL, not the panel — the run it
draws is the gap BETWEEN two panels, which no panel can see. HyprChromeBar
filters the row down to panels (a slack Item has no `rightChamfer`, so
spacers drop out, and dropping them is exactly what makes a trace span
them), then joins each right cap to the next left cap: straight, one 45°
step at the midpoint of the gap, straight. It meets the middle of each
cap's outward face rather than its tip.
TestPanel is a staging slot between two spacers. It counts seconds since
load, which is the cheapest proof the panel is live, and standing alone it
exercises a cap and a trace at both ends — something a rail of butted
panels never does.
Restructures the module in the same commit, since the moves and the edits
above land in the same files: folders are PascalCase, the bar and its
widgets moved under Widgets/Bar, and DebugWindow takes the HyprChrome Theme
instead of the legacy one. The two singletons are identical today, so that
is not a visual fix — it is a palette edit reaching the debug stage in
future. Rename detection needs -M40% to follow HyprChromeBar, which grew
past the default similarity threshold.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U19X5LGTxtq4pb4jdNVivv