import QtQuick import Quickshell import Quickshell.Wayland import Quickshell.Io import Quickshell.Services.Mpris import Quickshell.Services.Pipewire import "." as D import "../services" as S import "../applets" as C import "../modules" as M PanelWindow { id: root required property var screen visible: _winVisible color: "transparent" property bool _winVisible: false WlrLayershell.layer: S.DockState.mode === "pinned" ? WlrLayer.Top : WlrLayer.Overlay WlrLayershell.exclusiveZone: S.DockState.mode === "pinned" ? _dockWidth : 0 WlrLayershell.namespace: "nova-dock" anchors.top: true anchors.right: true anchors.bottom: true // Counteract the bar's exclusive zone so the dock extends to the top of the screen margins.top: -S.Theme.barHeight readonly property int _dockWidth: S.Modules.dock.width ?? 300 readonly property var _applets: S.Modules.dock.applets ?? {} readonly property color _accent: S.Theme.base0C implicitWidth: _dockWidth // Set reserved width for bar/corners when pinned onVisibleChanged: { if (S.DockState.mode === "pinned") S.DockState.reservedWidth = _dockWidth; } Connections { target: S.DockState function onModeChanged() { if (S.DockState.mode === "pinned") S.DockState.reservedWidth = root._dockWidth; } } // Slide animation - managed manually so window stays visible during hide property real _slideX: _dockWidth Connections { target: S.DockState function onOpenChanged() { if (S.DockState.open) { root._winVisible = true; _hideAnim.stop(); if (S.Theme.reducedMotion) { root._slideX = 0; } else { _showAnim.start(); } } else { _showAnim.stop(); if (S.Theme.reducedMotion) { root._slideX = root._dockWidth; root._winVisible = false; } else { _hideAnim.start(); } } } } NumberAnimation { id: _showAnim target: root property: "_slideX" to: 0 duration: 200 easing.type: Easing.OutCubic } NumberAnimation { id: _hideAnim target: root property: "_slideX" to: root._dockWidth duration: 200 easing.type: Easing.OutCubic onFinished: root._winVisible = false } // Overlay mode: close when cursor leaves HoverHandler { id: _dockHover onHoveredChanged: { if (!hovered && S.DockState.mode === "overlay") _overlayCloseTimer.restart(); else _overlayCloseTimer.stop(); } } Timer { id: _overlayCloseTimer interval: 200 onTriggered: if (S.DockState.mode === "overlay") S.DockState.close() } // Background - fully opaque when pinned, semi-transparent in overlay Rectangle { id: _bg anchors.fill: parent color: S.Theme.base00 opacity: S.DockState.mode === "pinned" ? 1.0 : Math.max(S.Theme.barOpacity, 0.85) transform: Translate { x: root._slideX } } // Left edge line - marks the virtual screen edge, matches bar border width. // Uses base09 (rightmost bar gradient color). Rectangle { anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom width: 1 color: S.Theme.base09 opacity: _bg.opacity transform: Translate { x: root._slideX } } // Content - inset past the edge line + gap Flickable { id: _flickable anchors.fill: parent anchors.leftMargin: S.Theme.groupSpacing + 1 contentHeight: _column.height clip: true boundsBehavior: Flickable.StopAtBounds transform: Translate { x: root._slideX } Column { id: _column width: root._dockWidth spacing: 8 topPadding: 8 bottomPadding: 8 leftPadding: 8 rightPadding: 8 // Clock D.DockCard { visible: root._applets.clock ?? true icon: "\uF017" title: "Clock" accentColor: root._accent width: parent.width - 16 C.ClockApplet { width: parent.width accentColor: root._accent currentDate: _clock.date } } // CPU D.DockCard { id: _cpuCard visible: root._applets.cpu ?? true icon: "\uF2DB" title: "CPU" accentColor: root._accent width: parent.width - 16 C.CpuApplet { width: parent.width cores: S.SystemStats.cpuCores coreMaxFreq: S.SystemStats.cpuCoreMaxFreq coreTypes: S.SystemStats.cpuCoreTypes processes: _cpuProcs.processes accentColor: root._accent active: _cpuCard.expanded } } // GPU D.DockCard { visible: (root._applets.gpu ?? true) && S.SystemStats.gpuAvailable icon: "\uEB4C" title: "GPU" accentColor: root._accent width: parent.width - 16 C.GpuApplet { width: parent.width active: parent.expanded accentColor: root._accent } } // Memory D.DockCard { id: _memCard visible: root._applets.memory ?? true icon: "\uEFC5" title: "Memory" accentColor: root._accent width: parent.width - 16 C.MemoryApplet { width: parent.width percent: S.SystemStats.memPercent usedGb: S.SystemStats.memUsedGb totalGb: S.SystemStats.memTotalGb availGb: S.SystemStats.memAvailGb cachedGb: S.SystemStats.memCachedGb buffersGb: S.SystemStats.memBuffersGb processes: _memProcs.processes accentColor: root._accent active: _memCard.expanded } } // Temperature D.DockCard { visible: root._applets.temperature ?? true icon: "\uF2C9" title: "Temperature" accentColor: root._accent width: parent.width - 16 C.TemperatureApplet { width: parent.width temp: S.SystemStats.tempCelsius warm: S.Modules.temperature.warm || 80 hot: S.Modules.temperature.hot || 90 history: S.SystemStats.tempHistory devices: S.SystemStats.tempDevices accentColor: root._accent deviceFilter: S.Modules.temperature.device || "" active: parent.expanded } } // Disk D.DockCard { visible: root._applets.disk ?? true icon: "\uF0C9" title: "Disk" accentColor: root._accent width: parent.width - 16 C.DiskApplet { width: parent.width mounts: S.SystemStats.diskMounts accentColor: root._accent } } // Battery D.DockCard { visible: (root._applets.battery ?? true) && S.BatteryService.available icon: "\uDB80\uDC84" title: "Battery" accentColor: root._accent width: parent.width - 16 C.BatteryApplet { width: parent.width active: parent.expanded accentColor: root._accent } } // Network D.DockCard { visible: root._applets.network ?? true icon: "\uF1EB" title: "Network" accentColor: root._accent width: parent.width - 16 C.NetworkApplet { width: parent.width accentColor: root._accent active: parent.expanded } } // Bluetooth D.DockCard { visible: (root._applets.bluetooth ?? true) && S.BluetoothService.state !== "unavailable" icon: "\uF294" title: "Bluetooth" accentColor: root._accent width: parent.width - 16 C.BluetoothApplet { width: parent.width accentColor: root._accent active: parent.expanded } } // Volume D.DockCard { visible: root._applets.volume ?? true icon: "\uF028" title: "Sound" accentColor: root._accent width: parent.width - 16 C.VolumeApplet { width: parent.width sink: Pipewire.defaultAudioSink sinkList: root._sinkList streamList: root._streamList accentColor: root._accent } } // Backlight D.DockCard { visible: (root._applets.backlight ?? true) && S.BacklightService.available icon: "\uF185" title: "Brightness" accentColor: root._accent width: parent.width - 16 C.BacklightApplet { width: parent.width percent: S.BacklightService.percent accentColor: root._accent onSetPercent: pct => S.BacklightService.setPercent(pct) } } // Weather D.DockCard { visible: (root._applets.weather ?? true) && S.WeatherService.available icon: S.WeatherService.icon title: "Weather" accentColor: root._accent width: parent.width - 16 C.WeatherApplet { width: parent.width accentColor: root._accent } } // Now Playing D.DockCard { visible: (root._applets.mpris ?? true) && S.MprisService.player !== null icon: "\uF04B" title: "Now Playing" accentColor: root._accent width: parent.width - 16 C.MprisApplet { width: parent.width player: S.MprisService.player players: S.MprisService.players playing: S.MprisService.playing accentColor: root._accent cachedArt: S.MprisService.cachedArt playerIdx: S.MprisService.playerIdx onPlayerSwitched: idx => S.MprisService.switchPlayer(idx) } } // Notifications D.DockCard { visible: root._applets.notifications ?? true icon: "\uDB80\uDC9C" title: "Notifications" accentColor: root._accent width: parent.width - 16 C.NotifApplet { width: parent.width contentWidth: root._dockWidth - 16 accentColor: root._accent } } // Power D.DockCard { visible: root._applets.power ?? true icon: "\uF011" title: "Power" accentColor: root._accent width: parent.width - 16 C.PowerApplet { width: parent.width accentColor: root._accent onRunCommand: cmd => { _runner.command = cmd; _runner.running = true; } onDismiss: S.DockState.close() } } } } // Shared resources SystemClock { id: _clock precision: SystemClock.Seconds } M.ProcessList { id: _cpuProcs sortBy: "cpu" active: _cpuCard.expanded && S.DockState.open } M.ProcessList { id: _memProcs sortBy: "mem" active: _memCard.expanded && S.DockState.open } PwObjectTracker { objects: [Pipewire.defaultAudioSink, ...root._streamList] } readonly property var _sinkList: { const sinks = []; if (Pipewire.nodes) { for (const node of Pipewire.nodes.values) if (!node.isStream && node.isSink) sinks.push(node); } return sinks; } readonly property var _streamList: { const streams = []; if (Pipewire.nodes) { for (const node of Pipewire.nodes.values) if (node.isStream && node.audio) streams.push(node); } return streams; } Process { id: _runner } }