The panel opened 38 pixels beneath the bar while its own comment said two. margins.top added Theme.barHeight to the gap, but an exclusiveZone of 0 means "reserve nothing, respect what others reserved" -- so the surface already began below the bar's 36px zone and the bar height was counted twice. The margin is now the gap alone, which also means the panel follows the bar: if the bar ever stops reserving space, this closes up against the top edge rather than hanging under nothing. Measured before and after against hyprctl layers: bar bottom at y=36, panel top from y=74 to y=38. Claude-Session: https://claude.ai/code/session_01BRvzt4H8XXLPVH5MyYdk9L
122 lines
3.8 KiB
QML
122 lines
3.8 KiB
QML
// The quick settings popover — GNOME's system menu (Super+S).
|
|
//
|
|
// A layer-shell surface rather than a PopupWindow because it needs keyboard
|
|
// focus for the wifi password field, and because the bar it hangs from is
|
|
// owned by a different module.
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Wayland
|
|
import Quickshell.Hyprland
|
|
import qs.config
|
|
import qs.services
|
|
import qs.widgets
|
|
|
|
PanelWindow {
|
|
id: root
|
|
|
|
visible: ShellState.quickSettingsOpen
|
|
color: "transparent"
|
|
|
|
// Hangs directly beneath the top-right status cluster. Two logical pixels
|
|
// preserve the Prism edge without making the surface feel detached.
|
|
//
|
|
// The margin is the gap ALONE, not the bar height plus the gap. An
|
|
// exclusiveZone of 0 means "reserve nothing, but respect what others
|
|
// reserved", so this surface already begins below the bar's 36px zone;
|
|
// adding the bar height here counted it twice and left the panel floating
|
|
// 38px under the bar instead of 2px. It also means the panel follows the
|
|
// bar on its own -- if the bar ever stops reserving space, this closes up
|
|
// against the top edge rather than hanging under nothing.
|
|
anchors.top: true
|
|
anchors.right: true
|
|
margins.top: Theme.controlCenterTopGap
|
|
margins.right: Theme.barSideMargin
|
|
exclusiveZone: 0
|
|
|
|
implicitWidth: Theme.controlCenterWidth
|
|
implicitHeight: panel.implicitHeight
|
|
readonly property string expandedSection: panel.expandedSection
|
|
|
|
function expand(name: string): void {
|
|
panel.expand(name);
|
|
}
|
|
|
|
// The `qs-popover` prefix is matched by a layerrule in hypr/rules.lua.
|
|
WlrLayershell.namespace: "qs-popover-quicksettings"
|
|
WlrLayershell.layer: WlrLayer.Overlay
|
|
// OnDemand rather than Exclusive: the panel must be able to take typing for
|
|
// the wifi password field, but must not steal it while merely visible.
|
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand
|
|
|
|
onVisibleChanged: {
|
|
if (root.visible) {
|
|
KdeConnect.refresh();
|
|
HomeAssistant.refresh();
|
|
// The daemon owns the power profile and anything on the system can
|
|
// change it, so the panel asks rather than trusting what it last saw.
|
|
PowerProfiles.refresh();
|
|
openAnim.restart();
|
|
} else {
|
|
panel.reset();
|
|
}
|
|
}
|
|
|
|
// Closes the panel when a click lands anywhere else on the desktop.
|
|
HyprlandFocusGrab {
|
|
windows: [root]
|
|
active: root.visible
|
|
onCleared: ShellState.close()
|
|
}
|
|
|
|
Rectangle {
|
|
id: surface
|
|
anchors.fill: parent
|
|
radius: Theme.popoverRadius
|
|
color: Theme.alpha(Theme.bgPopover, Theme.popoverAlpha)
|
|
border.width: 1
|
|
border.color: Theme.alpha(Theme.fg, 0.08)
|
|
|
|
// The prism edge — see widgets/PrismEdge.qml. Sits just inside the 1px
|
|
// border so the two don't fight for the same row of pixels.
|
|
PrismEdge {
|
|
anchors.top: parent.top
|
|
anchors.topMargin: 1
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
inset: parent.radius
|
|
}
|
|
|
|
transform: Scale {
|
|
id: openScale
|
|
origin.x: surface.width
|
|
origin.y: 0
|
|
xScale: 1
|
|
yScale: 1
|
|
}
|
|
|
|
// Escape reaches here by propagating up from whatever holds focus
|
|
// (usually the password field), so it works in every sub-state.
|
|
Item {
|
|
anchors.fill: parent
|
|
focus: true
|
|
Keys.onEscapePressed: ShellState.close()
|
|
|
|
QuickSettingsPanel {
|
|
id: panel
|
|
anchors.fill: parent
|
|
}
|
|
}
|
|
}
|
|
|
|
NumberAnimation {
|
|
id: openAnim
|
|
target: openScale
|
|
property: "yScale"
|
|
from: 0.94
|
|
to: 1.0
|
|
duration: Theme.durNormal
|
|
easing.type: Easing.OutCubic
|
|
}
|
|
}
|