pragma ComponentBehavior: Bound import Quickshell import Quickshell.Hyprland import Quickshell.Wayland import qs.HyprChrome.Widgets.Bar import qs.HyprChrome.Widgets // The hyprchrome shell: owns everything the rail's surfaces have to agree on, // and instantiates them. // // State lives here rather than in any one surface because more than one of them // reads it, and a second reader is what turns a local property into shared // state. Three things qualify so far: // // * which monitor the shell lives on — every surface has to pick the same one // * the density — the whole rail expands and collapses as one, so the toggle // and the shortcut that drives it belong to the shell, not to the bar // * the layer PAIR — the backdrop must sit exactly one layer below the bar in // both densities. Two surfaces on the same layer stack by creation order, // which is not something to rely on; one layer apart is a guarantee. Split // across two files those two assignments drifted apart and the scrim ended // up over the bar, so they are derived together here and passed down. // // A future widget joins by taking `targetScreen` and `expanded` the same way. Scope { id: shell // Monitor the rail lives on. Falls back to the FIRST connected screen when // the name matches nothing, so the bar still appears on a single-monitor // session or after a cable swap (DebugWindow falls back to the last one // instead — it wants the secondary). property string screenName: "DP-2" // Quickshell.screens is a QML list, not a JS array — no .find() on it. readonly property var targetScreen: { const screens = Quickshell.screens; if (screens.length === 0) return null; for (let i = 0; i < screens.length; i++) { if (screens[i].name === shell.screenName) return screens[i]; } return screens[0]; } // Density is a property of the SHELL: every panel follows it, so the whole // rail expands and collapses as one. Panels keep their own animation; only // the decision is centralised here. property bool expanded: false function toggle() { shell.expanded = !shell.expanded; } // Expanded the rail is over everything; collapsed it drops below ordinary // windows. BOTTOM rather than BACKGROUND for the collapsed bar: it is the // lowest level that still leaves a layer underneath for the backdrop, and // it keeps the rail off the wallpaper's own level. readonly property int barLayer: shell.expanded ? WlrLayer.Overlay : WlrLayer.Bottom readonly property int backdropLayer: shell.expanded ? WlrLayer.Top : WlrLayer.Background // SUPER A — see hosts/terra/home/hyprland.nix. GlobalShortcut { name: "chrome" description: "Expand or collapse the hyprchrome bar" onPressed: shell.toggle() } // Backdrop first: it is a layer below the bar, so stacking does not depend // on creation order, but keeping the declaration order the same as the // visual order costs nothing. ChromeBackdrop { screen: shell.targetScreen active: shell.expanded wlrLayer: shell.backdropLayer // Collapsed, the scrim only backs the rail, so it needs the band the // rail occupies. contentHeight is the SETTLED height for the current // state — it jumps once per toggle rather than tracking the panels // frame by frame, so the backdrop animates the change itself instead of // chasing a value that is already being animated. barHeight: bar.contentHeight } HyprChromeBar { id: bar screen: shell.targetScreen // Set here, not from the window's own `screen`: reading that inside // `visible` is circular — a hidden window has no screen to report. visible: shell.targetScreen !== null expanded: shell.expanded wlrLayer: shell.barLayer } }