summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/dms/Modules/BlurredWallpaperBackground.qml
diff options
context:
space:
mode:
Diffstat (limited to 'raveos-hyprland-theme/theme-data/dms/Modules/BlurredWallpaperBackground.qml')
-rw-r--r--raveos-hyprland-theme/theme-data/dms/Modules/BlurredWallpaperBackground.qml332
1 files changed, 332 insertions, 0 deletions
diff --git a/raveos-hyprland-theme/theme-data/dms/Modules/BlurredWallpaperBackground.qml b/raveos-hyprland-theme/theme-data/dms/Modules/BlurredWallpaperBackground.qml
new file mode 100644
index 0000000..6a5c6e8
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/dms/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;
+ }
+ }
+ }
+ }
+}