Files
Panama/config/dot/quickshell/modules/bar/Bar.qml
T

185 lines
5.9 KiB
QML

// The top bar: edge-to-edge system chrome with no surface of its own. Content
// floats directly over the desktop, while individual controls still provide
// hover and press feedback. The entire bar is a hit target so the top-left
// corner remains a dependable workspace-scroll gesture.
//
// Instantiate one per screen:
//
// Variants {
// model: Quickshell.screens
// Bar {}
// }
//
// Layout mirrors GNOME's: workspaces + vitals left, clock + weather center,
// media + tray + status cluster right.
import Quickshell
import Quickshell.Wayland
import QtQuick
import QtQuick.Effects
import qs.config
import qs.modules.clipboard
import qs.modules.focus
PanelWindow {
id: root
// Set by Variants. Left as a plain property (not `required`) so the bar can
// also be instantiated standalone on the default screen while testing.
property var modelData: null
// Raised when the status cluster is clicked; the shell wires this to the
// quick settings panel, which this module does not own.
signal requestQuickSettings
// Bound by the shell when an idle inhibitor is held, so the cluster can
// show the caffeine glyph.
property alias idleInhibited: statusCluster.idleInhibited
screen: root.modelData
anchors {
top: true
left: true
right: true
}
// PanelWindow defaults to an opaque white background.
color: "transparent"
implicitHeight: Theme.barHeight
exclusiveZone: Theme.barHeight
// Stable namespace for compositor inspection and shell diagnostics.
WlrLayershell.namespace: "qs-bar"
WlrLayershell.layer: WlrLayer.Top
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
// The full-width region is intentional: unlike a floating island, a menu
// bar owns the screen edge. In particular, Workspaces starts at x=0 and
// spans the full height so scrolling at the literal corner always works.
mask: Region {
item: barContent
}
// A scrim for wallpapers the bar cannot win against on tone alone. Drawn
// behind the content rows, fading out downward so the bar still has no
// hard edge of its own — the point is to darken what is under the text,
// not to give the bar a surface. Static: a gradient that never changes
// costs one paint, and this one has nothing to animate.
Rectangle {
anchors.fill: parent
visible: Settings.barBackdrop
gradient: Gradient {
GradientStop {
position: 0.0
color: Theme.alpha("#0c0e18", 0.55)
}
GradientStop {
position: 1.0
color: "transparent"
}
}
}
Item {
id: barContent
anchors.fill: parent
// One shadow for the whole bar rather than one per widget: the content
// is flattened into a single layer and the halo is drawn under it, so
// every glyph and label picks it up and nothing has to opt in. Off by
// default — it only earns its layer on a busy wallpaper.
layer.enabled: Settings.barTextShadow
layer.effect: MultiEffect {
shadowEnabled: true
shadowColor: "#0a0c14"
shadowBlur: 0.6
shadowVerticalOffset: 1
}
// ── Left ────────────────────────────────────────────────────────────
Row {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.itemSpacing
Workspaces {
anchors.verticalCenter: parent.verticalCenter
screen: root.screen
}
AgentUsageWidget {
anchors.verticalCenter: parent.verticalCenter
}
VitalsWidget {
anchors.verticalCenter: parent.verticalCenter
}
}
// ── Center ──────────────────────────────────────────────────────────
Row {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
spacing: 2
Clock {
anchors.verticalCenter: parent.verticalCenter
}
WeatherWidget {
anchors.verticalCenter: parent.verticalCenter
}
}
// ── Right ───────────────────────────────────────────────────────────
Row {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.itemSpacing
CalendarIndicator {
anchors.verticalCenter: parent.verticalCenter
}
HealthIndicator {
anchors.verticalCenter: parent.verticalCenter
}
ActivityIndicator {
anchors.verticalCenter: parent.verticalCenter
}
WallpaperIndicator {
anchors.verticalCenter: parent.verticalCenter
}
FocusIndicator {
anchors.verticalCenter: parent.verticalCenter
}
MediaWidget {
anchors.verticalCenter: parent.verticalCenter
}
ClipboardWidget {
anchors.verticalCenter: parent.verticalCenter
}
Tray {
anchors.verticalCenter: parent.verticalCenter
}
StatusCluster {
id: statusCluster
anchors.verticalCenter: parent.verticalCenter
onRequestQuickSettings: root.requestQuickSettings()
}
}
}
}