Desktop & Dock becomes Shell — Bar, Dock, Control Center, Tiling, Workspaces — the home for everything Quickshell draws. The settings- management cluster moves to System as Sync & Backup, Appearance's Shell tab dissolves, and 24-hour time finally lives on Date & Time, which always owned it. The bar gets what it never had: a way to survive the wallpaper. A second neutral text family (follow theme, or forced light or dark), a one-layer shadow under every glyph, and a gradient scrim for wallpapers nothing else survives — all off by default, pixel-identical until asked. Widgets earn toggles (weather, media, clipboard, calendar countdown), the vitals cluster stops leaving a dead pill behind, and Control Center's sections learn to step aside. The dock graduates from MVP: a context menu with window rows, pin, unpin, quit and new-window; scroll an icon to cycle its windows; drag to reorder on the dock itself; hover previews with one-shot captures; and "Add App to Dock" in the launcher. Three real bugs died en route — menus that slid away with the autohide, a readonly-property crash on every menu open, and a drag that drifted half a slot per icon on side docks. The pinned-apps editor in Settings becomes a drag strip. 166 contracts; the full suite is green except two live display and switcher tests that cannot run behind a locked session — re-verified on unlock. Claude-Session: https://claude.ai/code/session_01Ms2FbjQy31TVf3CEvQhGM8
183 lines
5.8 KiB
QML
183 lines
5.8 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 {}
|
|
|
|
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()
|
|
}
|
|
}
|
|
}
|
|
}
|