fix(quickshell): tie up loose ends from the popout composition refactor
The composition + composable-popouts refactor (450580a,89988c1) left three rough edges: - 6 popouts still read the removed PopoutState.currentName in their `shown` gate (undefined === "x" → permanently false), so wifi scan, bluetooth discovery, threshold reread, governor refresh, toast-silence and tray drill-down reset never fired again. Only the current component is ever instantiated, so `hasCurrent` alone is the correct gate. - ModuleBox stopped self-hiding when empty: the Battery box on a desktop (no battery) and an empty tray rendered a bare rounded pill. Gate the shared container on `inner.implicitWidth > 0` so the fix covers both. - CLAUDE.md customization example missed `import Quickshell` (unloadable as written) and called a Row's rejected centerIn anchor "harmless" (Row warns at runtime and ignores it).
This commit is contained in:
@@ -53,6 +53,7 @@ quickshell is the **default bar and notification daemon**, spawned by niri as `q
|
||||
```qml
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell // ShellRoot, Variants, Quickshell.screens
|
||||
import "file:///etc/xdg/quickshell/moonarch" // Theme + Bar/ModuleBox/… via the qmldir
|
||||
ShellRoot {
|
||||
Variants { model: Quickshell.screens
|
||||
@@ -62,7 +63,7 @@ quickshell is the **default bar and notification daemon**, spawned by niri as `q
|
||||
}
|
||||
}
|
||||
```
|
||||
`ModuleBox` wraps its content in a `Row`, so a direct child using `anchors.centerIn: parent` is harmless — `Row` manages horizontal position and ignores the anchor (no binding loop). Vertical centering via `anchors.verticalCenter` still works.
|
||||
`ModuleBox` wraps its content in a `Row` (and self-hides when its content collapses to zero width). Do **not** anchor a direct child with `anchors.centerIn: parent` — a `Row` rejects horizontal child anchors with a runtime warning (`QML Row: Cannot specify … centerIn anchors for items inside Row`) and ignores them. There is no binding loop (the `Row` sizes from children's implicit sizes, not `childrenRect`), but the centering silently does nothing. Center vertically with `anchors.verticalCenter: parent.verticalCenter` instead.
|
||||
|
||||
- **qmldir** exposes the singletons/components for the cross-dir `import`. It is **generated** from the `.qml` files; regenerate when adding components:
|
||||
```sh
|
||||
|
||||
@@ -58,7 +58,7 @@ PopoutPanel {
|
||||
|
||||
// The popout instance persists across reopens; re-read the threshold on each open so an
|
||||
// external change (terminal, or another screen's popout) is reflected.
|
||||
readonly property bool shown: root.popouts && root.popouts.hasCurrent && root.popouts.currentName === "battery"
|
||||
readonly property bool shown: root.popouts && root.popouts.hasCurrent
|
||||
onShownChanged: if (root.shown)
|
||||
limitFile.reload()
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ PopoutPanel {
|
||||
|
||||
// Content stays loaded even when closed (for the slide animation), so gate discovery on this
|
||||
// popout actually being the shown one rather than on component lifecycle.
|
||||
readonly property bool shown: root.popouts && root.popouts.hasCurrent && root.popouts.currentName === "bluetooth"
|
||||
readonly property bool shown: root.popouts && root.popouts.hasCurrent
|
||||
// Only write when it actually differs — BlueZ warns "already in progress" on a redundant start.
|
||||
function syncDiscovery() {
|
||||
if (root.adapter && root.adapter.discovering !== root.shown)
|
||||
|
||||
@@ -10,7 +10,7 @@ PopoutPanel {
|
||||
panelWidth: 200
|
||||
|
||||
// Reflect an out-of-band switch (walker menu) whenever the popout becomes the shown one.
|
||||
readonly property bool shown: root.popouts && root.popouts.hasCurrent && root.popouts.currentName === "cpugov"
|
||||
readonly property bool shown: root.popouts && root.popouts.hasCurrent
|
||||
onShownChanged: if (root.shown)
|
||||
CpuGovService.refresh()
|
||||
|
||||
|
||||
@@ -6,14 +6,19 @@ Rectangle {
|
||||
id: root
|
||||
default property alias data: inner.data
|
||||
|
||||
// Self-hide when empty: a module whose content collapses to zero width
|
||||
// (e.g. Battery on a desktop, tray with no SNI items) must not leave a bare pill.
|
||||
visible: inner.implicitWidth > 0
|
||||
implicitWidth: inner.implicitWidth + Theme.modulePadH * 2
|
||||
implicitHeight: Theme.barHeight - Theme.moduleMarginV * 2
|
||||
color: Theme.moduleBg
|
||||
radius: Theme.radius
|
||||
|
||||
// A Row derives its implicit size from the children's implicit sizes
|
||||
// instead of childrenRect, and rejects horizontal child anchors — so a
|
||||
// child using anchors.centerIn can no longer feed back into the size.
|
||||
// A Row derives its implicit size from the children's implicit sizes instead
|
||||
// of childrenRect, so a child can no longer feed back into the size. Note a Row
|
||||
// rejects a child's horizontal anchors (left/right/horizontalCenter/fill/centerIn)
|
||||
// with a runtime warning and ignores them — center a child with
|
||||
// anchors.verticalCenter, not anchors.centerIn.
|
||||
Row {
|
||||
id: inner
|
||||
anchors.centerIn: parent
|
||||
|
||||
@@ -28,7 +28,7 @@ PopoutPanel {
|
||||
|
||||
// Content stays loaded even when closed (for the slide animation), so gate scanning on this
|
||||
// popout actually being the shown one rather than on component lifecycle.
|
||||
readonly property bool shown: root.popouts && root.popouts.hasCurrent && root.popouts.currentName === "network"
|
||||
readonly property bool shown: root.popouts && root.popouts.hasCurrent
|
||||
onShownChanged: if (root.wifiDev)
|
||||
root.wifiDev.scannerEnabled = root.shown
|
||||
Component.onCompleted: if (root.wifiDev)
|
||||
|
||||
@@ -45,7 +45,7 @@ PopoutPanel {
|
||||
|
||||
// Opening the center silences pending toasts (they stay in history). Gated on `shown`
|
||||
// — the popout instance persists across reopens, so Component.onCompleted alone fires only once.
|
||||
readonly property bool shown: root.popouts && root.popouts.hasCurrent && root.popouts.currentName === "notifications"
|
||||
readonly property bool shown: root.popouts && root.popouts.hasCurrent
|
||||
function silencePending() {
|
||||
for (const i of NotifService.list)
|
||||
i.popup = false;
|
||||
|
||||
@@ -14,9 +14,9 @@ StackView {
|
||||
implicitWidth: currentItem ? currentItem.implicitWidth : 0
|
||||
implicitHeight: currentItem ? currentItem.implicitHeight : 0
|
||||
|
||||
// The popout instance persists across reopens (Loader keyed on currentName), so reset the
|
||||
// The popout instance persists across reopens (Loader keyed on currentComponent), so reset the
|
||||
// drill-down to the top level whenever the tray popout becomes shown again.
|
||||
readonly property bool shown: root.popouts && root.popouts.hasCurrent && root.popouts.currentName === "tray"
|
||||
readonly property bool shown: root.popouts && root.popouts.hasCurrent
|
||||
onShownChanged: if (root.shown)
|
||||
root.pop(null, StackView.Immediate)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user