295 lines
11 KiB
QML
295 lines
11 KiB
QML
//@ 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
|
|
}
|
|
}
|
|
}
|