//@ pragma UseQApplication import QtQuick import Quickshell import Quickshell.Wayland import Quickshell.Io import "bar" import "launcher" import "widgets/bgDate" import "widgets/sidebar" import "polkit" import "config" as Cfg ShellRoot { id: root Component.onCompleted: { Qt.application.organization = "quickshell" Qt.application.name = "quickshell" } readonly property bool isTop: Cfg.Config.barPosition === "top" property color frameBackground: Cfg.Config.theme.bgFrame property color frameBorderColor: Cfg.Config.theme.frameBorder // ── Sidebar (Widget Panel) ─────────────────────────────────────────── Variants { model: Quickshell.screens Sidebar { modelData: modelData Component.onCompleted: modelData.sidebar = this } } // ── Polkit Agent ───────────────────────────────────────────────────────── Loader { active: Cfg.Config.enablePolkit source: Qt.resolvedUrl("polkit/Polkit.qml") } // ── Spacing Gap: Top / Bottom ──────────────────────────────────────── Variants { model: Cfg.Config.frameVariant === "bar" ? [] : Quickshell.screens PanelWindow { required property var modelData screen: modelData anchors { top: !root.isTop bottom: root.isTop left: true right: true } implicitHeight: Cfg.Config.margin color: "transparent" WlrLayershell.layer: WlrLayer.Top WlrLayershell.exclusiveZone: Cfg.Config.margin mask: Region {} } } // ── Spacing Gap: Left ──────────────────────────────────────────────── Variants { model: Cfg.Config.frameVariant === "bar" ? [] : Quickshell.screens PanelWindow { required property var modelData screen: modelData anchors { left: true; top: true; bottom: true } implicitWidth: Cfg.Config.margin color: "transparent" WlrLayershell.layer: WlrLayer.Top WlrLayershell.exclusiveZone: Cfg.Config.margin mask: Region {} } } // ── Spacing Gap: Right ─────────────────────────────────────────────── Variants { model: Cfg.Config.frameVariant === "bar" ? [] : Quickshell.screens PanelWindow { required property var modelData screen: modelData anchors { right: true; top: true; bottom: true } implicitWidth: Cfg.Config.margin color: "transparent" WlrLayershell.layer: WlrLayer.Top WlrLayershell.exclusiveZone: Cfg.Config.margin mask: Region {} } } // ── Wallpaper ──────────────────────────────────────────────────────── Variants { model: Quickshell.screens PanelWindow { required property var modelData screen: modelData color: "transparent" anchors { top: true; bottom: true; left: true; right: true } WlrLayershell.layer: WlrLayer.Background WlrLayershell.namespace: "main-shell-wallpaper" WlrLayershell.exclusiveZone: -1 mask: Region {} Image { anchors.fill: parent source: { var p = Cfg.Config.theme.wallpaper if (!p) return "" return p.startsWith("file://") ? p : "file://" + p } fillMode: Image.PreserveAspectCrop asynchronous: true } } } // ── Center Clock (bgDate Widget) ───────────────────────────────────── Variants { model: Cfg.Config.enableBgDate ? Quickshell.screens : [] BgDate { modelData: modelData } } // ── Frame ──────────────────────────────────────────────────────────── Variants { model: Quickshell.screens PanelWindow { required property var modelData screen: modelData color: "transparent" anchors { top: true; bottom: true; left: true; right: true } WlrLayershell.layer: WlrLayer.Top WlrLayershell.namespace: "main-shell-frame" WlrLayershell.exclusiveZone: -1 mask: Region {} Canvas { id: frameCanvas anchors.fill: parent opacity: 0 scale: 0.98 Component.onCompleted: startupAnimation.start() ParallelAnimation { id: startupAnimation NumberAnimation { target: frameCanvas; property: "opacity" from: 0; to: 1; duration: 500 easing.type: Easing.OutCubic } NumberAnimation { target: frameCanvas; property: "scale" from: 0.98; to: 1.0; duration: 600 easing.type: Easing.OutBack } } onPaint: { var ctx = getContext("2d") ctx.clearRect(0, 0, width, height) if (Cfg.Config.frameVariant === "bar") { var barW = width - Cfg.Config.margin * 2 var barH = Cfg.Config.barHeight var barX = Cfg.Config.margin var barY = root.isTop ? Cfg.Config.frameBarPadTop : height - Cfg.Config.frameBarPadBottom - barH var r = Math.min(Cfg.Config.radius, barH / 2) ctx.fillStyle = root.frameBackground ctx.beginPath() ctx.moveTo(barX + r, barY) ctx.lineTo(barX + barW - r, barY) ctx.arcTo(barX + barW, barY, barX + barW, barY + r, r) ctx.lineTo(barX + barW, barY + barH - r) ctx.arcTo(barX + barW, barY + barH, barX + barW - r, barY + barH, r) ctx.lineTo(barX + r, barY + barH) ctx.arcTo(barX, barY + barH, barX, barY + barH - r, r) ctx.lineTo(barX, barY + r) ctx.arcTo(barX, barY, barX + r, barY, r) ctx.closePath() ctx.fill() if (Cfg.Config.frameBorderWidth > 0) { ctx.lineWidth = Cfg.Config.frameBorderWidth ctx.strokeStyle = root.frameBorderColor ctx.stroke() } return } var mT = root.isTop ? Cfg.Config.barHeight : Cfg.Config.margin var mB = root.isTop ? Cfg.Config.margin : Cfg.Config.barHeight var r = Cfg.Config.radius var cw = width - Cfg.Config.margin * 2 var ch = height - mT - mB var x = Cfg.Config.margin var y = mT ctx.fillStyle = root.frameBackground ctx.fillRect(0, 0, width, mT) ctx.fillRect(0, height - mB, width, mB) ctx.fillRect(0, mT, x, ch) ctx.fillRect(x + cw, mT, width - (x + cw), ch) ctx.beginPath() ctx.moveTo(x, y) ctx.lineTo(x + r, y) ctx.arc(x + r, y + r, r, -Math.PI / 2, Math.PI, true) ctx.closePath() ctx.fill() ctx.beginPath() ctx.moveTo(x + cw, y) ctx.lineTo(x + cw - r, y) ctx.arc(x + cw - r, y + r, r, -Math.PI / 2, 0, false) ctx.closePath() ctx.fill() ctx.beginPath() ctx.moveTo(x + cw, y + ch) ctx.lineTo(x + cw, y + ch - r) ctx.arc(x + cw - r, y + ch - r, r, 0, Math.PI / 2, false) ctx.closePath() ctx.fill() ctx.beginPath() ctx.moveTo(x, y + ch) ctx.lineTo(x + r, y + ch) ctx.arc(x + r, y + ch - r, r, Math.PI / 2, Math.PI, false) ctx.closePath() ctx.fill() ctx.lineWidth = Cfg.Config.frameBorderWidth ctx.strokeStyle = root.frameBorderColor ctx.beginPath() ctx.moveTo(x + r, y) ctx.lineTo(x + cw - r, y) ctx.arcTo(x + cw, y, x + cw, y + r, r) ctx.stroke() ctx.beginPath() ctx.moveTo(x + cw, y + r) ctx.lineTo(x + cw, y + ch - r) ctx.arcTo(x + cw, y + ch, x + cw - r, y + ch, r) ctx.stroke() ctx.beginPath() ctx.moveTo(x + cw - r, y + ch) ctx.lineTo(x + r, y + ch) ctx.arcTo(x, y + ch, x, y + ch - r, r) ctx.stroke() ctx.beginPath() ctx.moveTo(x, y + ch - r) ctx.lineTo(x, y + r) ctx.arcTo(x, y, x + r, y, r) ctx.stroke() } Connections { target: root function onFrameBackgroundChanged() { frameCanvas.requestPaint() } function onFrameBorderColorChanged() { frameCanvas.requestPaint() } } } } } // ── Launcher ───────────────────────────────────────────────────────── Variants { model: Quickshell.screens Launcher { required property var modelData screen: modelData isTop: root.isTop Component.onCompleted: modelData.launcher = this } } // ── Bar ────────────────────────────────────────────────────────────── Variants { model: Quickshell.screens Bar { screen: modelData isTop: root.isTop } } }