309 lines
9.8 KiB
QML
309 lines
9.8 KiB
QML
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Wayland
|
|
import qs.Commons
|
|
import qs.Services
|
|
|
|
Variants {
|
|
id: backgroundVariants
|
|
model: Quickshell.screens
|
|
|
|
delegate: Loader {
|
|
|
|
required property ShellScreen modelData
|
|
|
|
active: Settings.isLoaded && modelData && Settings.data.wallpaper.enabled
|
|
|
|
sourceComponent: PanelWindow {
|
|
id: root
|
|
|
|
// Internal state management
|
|
property string transitionType: "fade"
|
|
property real transitionProgress: 0
|
|
|
|
readonly property real edgeSmoothness: Settings.data.wallpaper.transitionEdgeSmoothness
|
|
readonly property var allTransitions: WallpaperService.allTransitions
|
|
readonly property bool transitioning: transitionAnimation.running
|
|
|
|
// Wipe direction: 0=left, 1=right, 2=up, 3=down
|
|
property real wipeDirection: 0
|
|
|
|
// Disc
|
|
property real discCenterX: 0.5
|
|
property real discCenterY: 0.5
|
|
|
|
// Stripe
|
|
property real stripesCount: 16
|
|
property real stripesAngle: 0
|
|
|
|
// Used to debounce wallpaper changes
|
|
property string futureWallpaper: ""
|
|
|
|
// Fillmode default is "crop"
|
|
property real fillMode: 1.0
|
|
|
|
// On startup assign wallpaper immediately
|
|
Component.onCompleted: {
|
|
fillMode = WallpaperService.getFillModeUniform()
|
|
|
|
var path = modelData ? WallpaperService.getWallpaper(modelData.name) : ""
|
|
setWallpaperImmediate(path)
|
|
}
|
|
|
|
Connections {
|
|
target: Settings.data.wallpaper
|
|
function onFillModeChanged() {
|
|
fillMode = WallpaperService.getFillModeUniform()
|
|
}
|
|
}
|
|
|
|
// External state management
|
|
Connections {
|
|
target: WallpaperService
|
|
function onWallpaperChanged(screenName, path) {
|
|
if (screenName === modelData.name) {
|
|
|
|
// Update wallpaper display
|
|
// Set wallpaper immediately on startup
|
|
futureWallpaper = path
|
|
debounceTimer.restart()
|
|
}
|
|
}
|
|
}
|
|
|
|
color: Color.transparent
|
|
screen: modelData
|
|
WlrLayershell.layer: WlrLayer.Background
|
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
|
WlrLayershell.namespace: "quickshell-wallpaper"
|
|
|
|
anchors {
|
|
bottom: true
|
|
top: true
|
|
right: true
|
|
left: true
|
|
}
|
|
|
|
Timer {
|
|
id: debounceTimer
|
|
interval: 333
|
|
running: false
|
|
repeat: false
|
|
onTriggered: {
|
|
changeWallpaper()
|
|
}
|
|
}
|
|
|
|
Image {
|
|
id: currentWallpaper
|
|
source: ""
|
|
smooth: true
|
|
mipmap: false
|
|
visible: false
|
|
cache: false
|
|
// currentWallpaper should not be asynchronous to avoid flickering when swapping next to current.
|
|
asynchronous: false
|
|
}
|
|
|
|
Image {
|
|
id: nextWallpaper
|
|
source: ""
|
|
smooth: true
|
|
mipmap: false
|
|
visible: false
|
|
cache: false
|
|
asynchronous: true
|
|
}
|
|
|
|
// Fade or None transition shader
|
|
ShaderEffect {
|
|
id: fadeShader
|
|
anchors.fill: parent
|
|
visible: transitionType === "fade" || transitionType === "none"
|
|
|
|
property variant source1: currentWallpaper
|
|
property variant source2: nextWallpaper
|
|
property real progress: root.transitionProgress
|
|
|
|
// Fill mode properties
|
|
property real fillMode: root.fillMode
|
|
property real imageWidth1: source1.sourceSize.width
|
|
property real imageHeight1: source1.sourceSize.height
|
|
property real imageWidth2: source2.sourceSize.width
|
|
property real imageHeight2: source2.sourceSize.height
|
|
property real screenWidth: width
|
|
property real screenHeight: height
|
|
property vector4d fillColor: Qt.vector4d(0.0, 0.0, 0.0, 1.0) // Black
|
|
|
|
fragmentShader: Qt.resolvedUrl("../../Shaders/qsb/wp_fade.frag.qsb")
|
|
}
|
|
|
|
// Wipe transition shader
|
|
ShaderEffect {
|
|
id: wipeShader
|
|
anchors.fill: parent
|
|
visible: transitionType === "wipe"
|
|
|
|
property variant source1: currentWallpaper
|
|
property variant source2: nextWallpaper
|
|
property real progress: root.transitionProgress
|
|
property real smoothness: root.edgeSmoothness
|
|
property real direction: root.wipeDirection
|
|
|
|
// Fill mode properties
|
|
property real fillMode: root.fillMode
|
|
property real imageWidth1: source1.sourceSize.width
|
|
property real imageHeight1: source1.sourceSize.height
|
|
property real imageWidth2: source2.sourceSize.width
|
|
property real imageHeight2: source2.sourceSize.height
|
|
property real screenWidth: width
|
|
property real screenHeight: height
|
|
property vector4d fillColor: Qt.vector4d(0.0, 0.0, 0.0, 1.0) // Black
|
|
|
|
fragmentShader: Qt.resolvedUrl("../../Shaders/qsb/wp_wipe.frag.qsb")
|
|
}
|
|
|
|
// Disc reveal transition shader
|
|
ShaderEffect {
|
|
id: discShader
|
|
anchors.fill: parent
|
|
visible: transitionType === "disc"
|
|
|
|
property variant source1: currentWallpaper
|
|
property variant source2: nextWallpaper
|
|
property real progress: root.transitionProgress
|
|
property real smoothness: root.edgeSmoothness
|
|
property real aspectRatio: root.width / root.height
|
|
property real centerX: root.discCenterX
|
|
property real centerY: root.discCenterY
|
|
|
|
// Fill mode properties
|
|
property real fillMode: root.fillMode
|
|
property real imageWidth1: source1.sourceSize.width
|
|
property real imageHeight1: source1.sourceSize.height
|
|
property real imageWidth2: source2.sourceSize.width
|
|
property real imageHeight2: source2.sourceSize.height
|
|
property real screenWidth: width
|
|
property real screenHeight: height
|
|
property vector4d fillColor: Qt.vector4d(0.0, 0.0, 0.0, 1.0) // Black
|
|
|
|
fragmentShader: Qt.resolvedUrl("../../Shaders/qsb/wp_disc.frag.qsb")
|
|
}
|
|
|
|
// Diagonal stripes transition shader
|
|
ShaderEffect {
|
|
id: stripesShader
|
|
anchors.fill: parent
|
|
visible: transitionType === "stripes"
|
|
|
|
property variant source1: currentWallpaper
|
|
property variant source2: nextWallpaper
|
|
property real progress: root.transitionProgress
|
|
property real smoothness: root.edgeSmoothness
|
|
property real aspectRatio: root.width / root.height
|
|
property real stripeCount: root.stripesCount
|
|
property real angle: root.stripesAngle
|
|
|
|
// Fill mode properties
|
|
property real fillMode: root.fillMode
|
|
property real imageWidth1: source1.sourceSize.width
|
|
property real imageHeight1: source1.sourceSize.height
|
|
property real imageWidth2: source2.sourceSize.width
|
|
property real imageHeight2: source2.sourceSize.height
|
|
property real screenWidth: width
|
|
property real screenHeight: height
|
|
property vector4d fillColor: Qt.vector4d(0.0, 0.0, 0.0, 1.0) // Black
|
|
|
|
fragmentShader: Qt.resolvedUrl("../../Shaders/qsb/wp_stripes.frag.qsb")
|
|
}
|
|
|
|
// Animation for the transition progress
|
|
NumberAnimation {
|
|
id: transitionAnimation
|
|
target: root
|
|
property: "transitionProgress"
|
|
from: 0.0
|
|
to: 1.0
|
|
// The stripes shader feels faster visually, we make it a bit slower here.
|
|
duration: transitionType == "stripes" ? Settings.data.wallpaper.transitionDuration
|
|
* 1.6 : Settings.data.wallpaper.transitionDuration
|
|
easing.type: Easing.InOutCubic
|
|
onFinished: {
|
|
// Swap images after transition completes
|
|
currentWallpaper.source = nextWallpaper.source
|
|
nextWallpaper.source = ""
|
|
transitionProgress = 0.0
|
|
}
|
|
}
|
|
|
|
function startTransition() {
|
|
if (!transitioning && nextWallpaper.source != currentWallpaper.source) {
|
|
transitionAnimation.start()
|
|
}
|
|
}
|
|
|
|
function setWallpaperImmediate(source) {
|
|
transitionAnimation.stop()
|
|
transitionProgress = 0.0
|
|
currentWallpaper.source = source
|
|
nextWallpaper.source = ""
|
|
}
|
|
|
|
function setWallpaperWithTransition(source) {
|
|
if (source != currentWallpaper.source) {
|
|
|
|
if (transitioning) {
|
|
// We are interrupting a transition
|
|
transitionAnimation.stop()
|
|
transitionProgress = 0
|
|
currentWallpaper.source = nextWallpaper.source
|
|
nextWallpaper.source = ""
|
|
}
|
|
|
|
nextWallpaper.source = source
|
|
startTransition()
|
|
}
|
|
}
|
|
|
|
// Main method that actually trigger the wallpaper change
|
|
function changeWallpaper() {
|
|
// Get the transitionType from the settings
|
|
transitionType = Settings.data.wallpaper.transitionType
|
|
|
|
if (transitionType == "random") {
|
|
var index = Math.floor(Math.random() * allTransitions.length)
|
|
transitionType = allTransitions[index]
|
|
}
|
|
|
|
// Ensure the transition type really exists
|
|
if (transitionType !== "none" && !allTransitions.includes(transitionType)) {
|
|
transitionType = "fade"
|
|
}
|
|
|
|
//Logger.log("Background", "New wallpaper: ", futureWallpaper, "On:", modelData.name, "Transition:", transitionType)
|
|
switch (transitionType) {
|
|
case "none":
|
|
setWallpaperImmediate(futureWallpaper)
|
|
break
|
|
case "wipe":
|
|
wipeDirection = Math.random() * 4
|
|
setWallpaperWithTransition(futureWallpaper)
|
|
break
|
|
case "disc":
|
|
discCenterX = Math.random()
|
|
discCenterY = Math.random()
|
|
setWallpaperWithTransition(futureWallpaper)
|
|
break
|
|
case "stripes":
|
|
stripesCount = Math.round(Math.random() * 20 + 4)
|
|
stripesAngle = Math.random() * 360
|
|
setWallpaperWithTransition(futureWallpaper)
|
|
break
|
|
default:
|
|
setWallpaperWithTransition(futureWallpaper)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|