diff options
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BlurredWallpaperBackground.qml')
| -rw-r--r-- | raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BlurredWallpaperBackground.qml | 332 |
1 files changed, 332 insertions, 0 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BlurredWallpaperBackground.qml b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BlurredWallpaperBackground.qml new file mode 100644 index 0000000..6a5c6e8 --- /dev/null +++ b/raveos-hyprland-theme/theme-data/DankMaterialShell/quickshell/Modules/BlurredWallpaperBackground.qml @@ -0,0 +1,332 @@ +import QtQuick +import QtQuick.Effects +import Quickshell +import Quickshell.Wayland +import qs.Common +import qs.Widgets +import qs.Services + +Variants { + model: { + if (SessionData.isGreeterMode) { + return Quickshell.screens; + } + return SettingsData.getFilteredScreens("wallpaper"); + } + + PanelWindow { + id: blurWallpaperWindow + + required property var modelData + + screen: modelData + + WlrLayershell.layer: WlrLayer.Background + WlrLayershell.namespace: "dms:blurwallpaper" + WlrLayershell.exclusionMode: ExclusionMode.Ignore + + anchors.top: true + anchors.bottom: true + anchors.left: true + anchors.right: true + + color: "transparent" + + mask: Region { + item: Item {} + } + + Item { + id: root + anchors.fill: parent + + function encodeFileUrl(path) { + if (!path) + return ""; + return "file://" + path.split('/').map(s => encodeURIComponent(s)).join('/'); + } + + property string source: SessionData.getMonitorWallpaper(modelData.name) || "" + property bool isColorSource: source.startsWith("#") + + Connections { + target: SessionData + function onIsLightModeChanged() { + if (SessionData.perModeWallpaper) { + var newSource = SessionData.getMonitorWallpaper(modelData.name) || ""; + if (newSource !== root.source) { + root.source = newSource; + } + } + } + } + + function getFillMode(modeName) { + switch (modeName) { + case "Stretch": + return Image.Stretch; + case "Fit": + case "PreserveAspectFit": + return Image.PreserveAspectFit; + case "Fill": + case "PreserveAspectCrop": + return Image.PreserveAspectCrop; + case "Tile": + return Image.Tile; + case "TileVertically": + return Image.TileVertically; + case "TileHorizontally": + return Image.TileHorizontally; + case "Pad": + return Image.Pad; + default: + return Image.PreserveAspectCrop; + } + } + + Component.onCompleted: { + if (typeof blurWallpaperWindow.updatesEnabled !== "undefined") + blurWallpaperWindow.updatesEnabled = Qt.binding(() => !root.source || root.effectActive || root._renderSettling || currentWallpaper.status === Image.Loading || nextWallpaper.status === Image.Loading); + isInitialized = true; + } + + property bool isInitialized: false + property real transitionProgress: 0 + readonly property bool transitioning: transitionAnimation.running + property bool effectActive: false + property bool _renderSettling: true + property bool useNextForEffect: false + + Connections { + target: currentWallpaper + function onStatusChanged() { + if (currentWallpaper.status !== Image.Ready && currentWallpaper.status !== Image.Error) + return; + root._renderSettling = true; + renderSettleTimer.restart(); + } + } + + Connections { + target: blurWallpaperWindow + function onWidthChanged() { + root._renderSettling = true; + renderSettleTimer.restart(); + } + function onHeightChanged() { + root._renderSettling = true; + renderSettleTimer.restart(); + } + } + + Connections { + target: Quickshell + function onScreensChanged() { + root._renderSettling = true; + renderSettleTimer.restart(); + } + } + + Timer { + id: renderSettleTimer + interval: 1000 + onTriggered: root._renderSettling = false + } + + onSourceChanged: { + if (!source || source.startsWith("#")) { + setWallpaperImmediate(""); + return; + } + + const formattedSource = source.startsWith("file://") ? source : encodeFileUrl(source); + + if (!isInitialized || !currentWallpaper.source) { + setWallpaperImmediate(formattedSource); + isInitialized = true; + return; + } + if (CompositorService.isNiri && SessionData.isSwitchingMode) { + setWallpaperImmediate(formattedSource); + return; + } + changeWallpaper(formattedSource); + } + + function setWallpaperImmediate(newSource) { + transitionAnimation.stop(); + root.transitionProgress = 0.0; + root.effectActive = false; + root._renderSettling = true; + renderSettleTimer.restart(); + currentWallpaper.source = newSource; + nextWallpaper.source = ""; + } + + function startTransition() { + root.useNextForEffect = true; + root.effectActive = true; + if (srcNext.scheduleUpdate) + srcNext.scheduleUpdate(); + transitionDelayTimer.start(); + } + + Timer { + id: transitionDelayTimer + interval: 16 + repeat: false + onTriggered: transitionAnimation.start() + } + + function changeWallpaper(newPath) { + if (newPath === currentWallpaper.source) + return; + if (!newPath || newPath.startsWith("#")) + return; + if (root.transitioning) { + transitionAnimation.stop(); + root.transitionProgress = 0; + root.effectActive = false; + root._renderSettling = true; + renderSettleTimer.restart(); + currentWallpaper.source = nextWallpaper.source; + nextWallpaper.source = ""; + } + if (!currentWallpaper.source) { + setWallpaperImmediate(newPath); + return; + } + + root._renderSettling = true; + renderSettleTimer.restart(); + + nextWallpaper.source = newPath; + + if (nextWallpaper.status === Image.Ready) + root.startTransition(); + } + + Loader { + anchors.fill: parent + active: !root.source || root.isColorSource + asynchronous: true + + sourceComponent: DankBackdrop { + screenName: modelData.name + } + } + + readonly property int maxTextureSize: 8192 + property int textureWidth: Math.min(modelData.width, maxTextureSize) + property int textureHeight: Math.min(modelData.height, maxTextureSize) + + Image { + id: currentWallpaper + anchors.fill: parent + visible: false + opacity: 1 + asynchronous: true + retainWhileLoading: true + smooth: true + cache: true + sourceSize: Qt.size(root.textureWidth, root.textureHeight) + fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SessionData.getMonitorWallpaperFillMode(modelData.name)) + } + + Image { + id: nextWallpaper + anchors.fill: parent + visible: false + opacity: 0 + asynchronous: true + retainWhileLoading: true + smooth: true + cache: true + sourceSize: Qt.size(root.textureWidth, root.textureHeight) + fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SessionData.getMonitorWallpaperFillMode(modelData.name)) + + onStatusChanged: { + if (status !== Image.Ready) + return; + if (!root.transitioning) { + root.startTransition(); + } + } + } + + ShaderEffectSource { + id: srcNext + sourceItem: root.effectActive ? nextWallpaper : null + hideSource: root.effectActive + live: root.effectActive + mipmap: false + recursive: false + textureSize: Qt.size(root.textureWidth, root.textureHeight) + } + + Rectangle { + id: dummyRect + width: 1 + height: 1 + visible: false + color: "transparent" + } + + ShaderEffectSource { + id: srcDummy + sourceItem: dummyRect + hideSource: true + live: false + mipmap: false + recursive: false + } + + Item { + id: blurredLayer + anchors.fill: parent + + MultiEffect { + anchors.fill: parent + source: currentWallpaper + visible: currentWallpaper.source !== "" + blurEnabled: true + blur: 0.8 + blurMax: 75 + opacity: 1 - root.transitionProgress + autoPaddingEnabled: false + } + + MultiEffect { + anchors.fill: parent + source: root.useNextForEffect ? srcNext : srcDummy + visible: nextWallpaper.source !== "" && root.useNextForEffect + blurEnabled: true + blur: 0.8 + blurMax: 75 + opacity: root.transitionProgress + autoPaddingEnabled: false + } + } + + NumberAnimation { + id: transitionAnimation + target: root + property: "transitionProgress" + from: 0.0 + to: 1.0 + duration: 1000 + easing.type: Easing.InOutCubic + onFinished: { + if (nextWallpaper.source && nextWallpaper.status === Image.Ready) + currentWallpaper.source = nextWallpaper.source; + root.useNextForEffect = false; + nextWallpaper.source = ""; + root.transitionProgress = 0.0; + root._renderSettling = true; + renderSettleTimer.restart(); + root.effectActive = false; + } + } + } + } +} |