diff --git a/quickshell/Common/SessionData.qml b/quickshell/Common/SessionData.qml index 3d2c5772..94956f48 100644 --- a/quickshell/Common/SessionData.qml +++ b/quickshell/Common/SessionData.qml @@ -58,6 +58,7 @@ Singleton { property string wallpaperPathDark: "" property var monitorWallpapersLight: ({}) property var monitorWallpapersDark: ({}) + property var monitorWallpaperFillModes: ({}) property string wallpaperTransition: "fade" readonly property var availableWallpaperTransitions: ["none", "fade", "wipe", "disc", "stripes", "iris bloom", "pixelate", "portal"] property var includedTransitions: availableWallpaperTransitions.filter(t => t !== "none") @@ -1094,11 +1095,7 @@ Singleton { wallpaperPath = isLightMode ? wallpaperPathLight : wallpaperPathDark; } - function getMonitorWallpaper(screenName) { - if (!perMonitorWallpaper) { - return wallpaperPath; - } - + function _findMonitorValue(map, screenName) { var screen = null; var screens = Quickshell.screens; for (var i = 0; i < screens.length; i++) { @@ -1108,52 +1105,72 @@ Singleton { } } - if (!screen) { - return monitorWallpapers[screenName] || wallpaperPath; + if (!screen) + return map[screenName]; + + if (map[screen.name] !== undefined) + return map[screen.name]; + if (screen.model && map[screen.model] !== undefined) + return map[screen.model]; + if (typeof SettingsData !== "undefined") { + var displayName = SettingsData.getScreenDisplayName(screen); + if (displayName && map[displayName] !== undefined) + return map[displayName]; + } + return undefined; + } + + function getMonitorWallpaper(screenName) { + if (!perMonitorWallpaper) + return wallpaperPath; + var value = _findMonitorValue(monitorWallpapers, screenName); + return value !== undefined ? value : wallpaperPath; + } + + function getMonitorWallpaperFillMode(screenName) { + var globalFillMode = (typeof SettingsData !== "undefined") ? SettingsData.wallpaperFillMode : "Fill"; + if (!perMonitorWallpaper) + return globalFillMode; + var value = _findMonitorValue(monitorWallpaperFillModes, screenName); + return value !== undefined ? value : globalFillMode; + } + + function setMonitorWallpaperFillMode(screenName, mode) { + var screen = null; + var screens = Quickshell.screens; + for (var i = 0; i < screens.length; i++) { + if (screens[i].name === screenName) { + screen = screens[i]; + break; + } } - if (monitorWallpapers[screen.name]) { - return monitorWallpapers[screen.name]; - } - if (screen.model && monitorWallpapers[screen.model]) { - return monitorWallpapers[screen.model]; + if (!screen) + return; + + var identifier = typeof SettingsData !== "undefined" ? SettingsData.getScreenDisplayName(screen) : screen.name; + + var newModes = {}; + for (var key in monitorWallpaperFillModes) { + var isThisScreen = key === screen.name || (screen.model && key === screen.model); + if (!isThisScreen) + newModes[key] = monitorWallpaperFillModes[key]; } - return wallpaperPath; + newModes[identifier] = mode; + monitorWallpaperFillModes = newModes; + saveSettings(); } function getMonitorCyclingSettings(screenName) { - var screen = null; - var screens = Quickshell.screens; - for (var i = 0; i < screens.length; i++) { - if (screens[i].name === screenName) { - screen = screens[i]; - break; - } - } - - if (!screen) { - return monitorCyclingSettings[screenName] || { - "enabled": false, - "mode": "interval", - "interval": 300, - "time": "06:00" - }; - } - - if (monitorCyclingSettings[screen.name]) { - return monitorCyclingSettings[screen.name]; - } - if (screen.model && monitorCyclingSettings[screen.model]) { - return monitorCyclingSettings[screen.model]; - } - - return { + var defaults = { "enabled": false, "mode": "interval", "interval": 300, "time": "06:00" }; + var value = _findMonitorValue(monitorCyclingSettings, screenName); + return value !== undefined ? value : defaults; } FileView { diff --git a/quickshell/Common/Theme.qml b/quickshell/Common/Theme.qml index 752554ed..02e0cf1c 100644 --- a/quickshell/Common/Theme.qml +++ b/quickshell/Common/Theme.qml @@ -45,11 +45,12 @@ Singleton { if (typeof SessionData === "undefined") return ""; + var monitors = SessionData.monitorWallpapers; if (SessionData.perMonitorWallpaper) { var screens = Quickshell.screens; if (screens.length > 0) { - var firstMonitorWallpaper = SessionData.getMonitorWallpaper(screens[0].name); - return firstMonitorWallpaper || SessionData.wallpaperPath; + var s = screens[0]; + return monitors[s.name] || (s.model ? monitors[s.model] : "") || SessionData.wallpaperPath; } } @@ -59,6 +60,7 @@ Singleton { if (typeof SessionData === "undefined") return ""; + var monitors = SessionData.monitorWallpapers; if (SessionData.perMonitorWallpaper) { var screens = Quickshell.screens; if (screens.length > 0) { @@ -72,12 +74,20 @@ Singleton { } } - if (!targetMonitorExists) { + if (!targetMonitorExists) targetMonitor = screens[0].name; + + var s = null; + for (var j = 0; j < screens.length; j++) { + if (screens[j].name === targetMonitor) { + s = screens[j]; + break; + } } - var targetMonitorWallpaper = SessionData.getMonitorWallpaper(targetMonitor); - return targetMonitorWallpaper || SessionData.wallpaperPath; + if (s) + return monitors[s.name] || (s.model ? monitors[s.model] : "") || SessionData.wallpaperPath; + return monitors[targetMonitor] || SessionData.wallpaperPath; } } diff --git a/quickshell/Common/settings/SessionSpec.js b/quickshell/Common/settings/SessionSpec.js index 220359c3..6f7c11f0 100644 --- a/quickshell/Common/settings/SessionSpec.js +++ b/quickshell/Common/settings/SessionSpec.js @@ -12,6 +12,7 @@ var SPEC = { wallpaperPathDark: { def: "" }, monitorWallpapersLight: { def: {} }, monitorWallpapersDark: { def: {} }, + monitorWallpaperFillModes: { def: {} }, wallpaperTransition: { def: "fade" }, includedTransitions: { def: ["fade", "wipe", "disc", "stripes", "iris bloom", "pixelate", "portal"] }, diff --git a/quickshell/Modules/BlurredWallpaperBackground.qml b/quickshell/Modules/BlurredWallpaperBackground.qml index 43171e69..6b58baee 100644 --- a/quickshell/Modules/BlurredWallpaperBackground.qml +++ b/quickshell/Modules/BlurredWallpaperBackground.qml @@ -189,7 +189,7 @@ Variants { smooth: true cache: true sourceSize: Qt.size(root.textureWidth, root.textureHeight) - fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SettingsData.wallpaperFillMode) + fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SessionData.getMonitorWallpaperFillMode(modelData.name)) } Image { @@ -201,7 +201,7 @@ Variants { smooth: true cache: true sourceSize: Qt.size(root.textureWidth, root.textureHeight) - fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SettingsData.wallpaperFillMode) + fillMode: root.getFillMode(SessionData.isGreeterMode ? GreetdSettings.wallpaperFillMode : SessionData.getMonitorWallpaperFillMode(modelData.name)) onStatusChanged: { if (status !== Image.Ready) diff --git a/quickshell/Modules/Lock/LockScreenContent.qml b/quickshell/Modules/Lock/LockScreenContent.qml index b2d66b98..e8ba84f5 100644 --- a/quickshell/Modules/Lock/LockScreenContent.qml +++ b/quickshell/Modules/Lock/LockScreenContent.qml @@ -166,7 +166,7 @@ Item { var currentWallpaper = SessionData.getMonitorWallpaper(screenName); return (currentWallpaper && !currentWallpaper.startsWith("#")) ? encodeFileUrl(currentWallpaper) : ""; } - fillMode: Theme.getFillMode(SettingsData.wallpaperFillMode) + fillMode: Theme.getFillMode(SessionData.getMonitorWallpaperFillMode(screenName)) smooth: true asynchronous: false cache: true diff --git a/quickshell/Modules/Settings/WallpaperTab.qml b/quickshell/Modules/Settings/WallpaperTab.qml index 9baf0a47..541d3b79 100644 --- a/quickshell/Modules/Settings/WallpaperTab.qml +++ b/quickshell/Modules/Settings/WallpaperTab.qml @@ -18,6 +18,26 @@ Item { var screens = Quickshell.screens; return screens.length > 0 ? screens[0].name : ""; } + property string currentWallpaper: { + if (!SessionData.perMonitorWallpaper) + return SessionData.wallpaperPath; + var map = SessionData.monitorWallpapers; + var screens = Quickshell.screens; + for (var i = 0; i < screens.length; i++) { + if (screens[i].name !== selectedMonitorName) + continue; + var screen = screens[i]; + if (map[screen.name] !== undefined) + return map[screen.name]; + if (screen.model && map[screen.model] !== undefined) + return map[screen.model]; + var displayName = SettingsData.getScreenDisplayName(screen); + if (displayName && map[displayName] !== undefined) + return map[displayName]; + break; + } + return SessionData.wallpaperPath; + } Component.onCompleted: { WallpaperCyclingService.cyclingActive; @@ -55,19 +75,22 @@ Item { radius: Theme.cornerRadius color: Theme.surfaceVariant - CachingImage { + Image { anchors.fill: parent anchors.margins: 1 - imagePath: { - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - return (currentWallpaper !== "" && !currentWallpaper.startsWith("#")) ? currentWallpaper : ""; + source: { + var wp = root.currentWallpaper; + if (wp === "" || wp.startsWith("#")) + return ""; + if (wp.startsWith("file://")) + wp = wp.substring(7); + return "file://" + wp.split('/').map(s => encodeURIComponent(s)).join('/'); } fillMode: Image.PreserveAspectCrop - visible: { - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - return currentWallpaper !== "" && !currentWallpaper.startsWith("#"); - } - maxCacheSize: 160 + visible: root.currentWallpaper !== "" && !root.currentWallpaper.startsWith("#") + sourceSize.width: 160 + sourceSize.height: 160 + asynchronous: true layer.enabled: true layer.effect: MultiEffect { maskEnabled: true @@ -81,14 +104,8 @@ Item { anchors.fill: parent anchors.margins: 1 radius: Theme.cornerRadius - 1 - color: { - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - return currentWallpaper.startsWith("#") ? currentWallpaper : "transparent"; - } - visible: { - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - return currentWallpaper !== "" && currentWallpaper.startsWith("#"); - } + color: root.currentWallpaper.startsWith("#") ? root.currentWallpaper : "transparent" + visible: root.currentWallpaper !== "" && root.currentWallpaper.startsWith("#") } Rectangle { @@ -106,10 +123,7 @@ Item { name: "image" size: Theme.iconSizeLarge + 8 color: Theme.surfaceVariantText - visible: { - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - return currentWallpaper === ""; - } + visible: root.currentWallpaper === "" } Rectangle { @@ -162,8 +176,7 @@ Item { onClicked: { if (!PopoutService.colorPickerModal) return; - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - PopoutService.colorPickerModal.selectedColor = currentWallpaper.startsWith("#") ? currentWallpaper : Theme.primary; + PopoutService.colorPickerModal.selectedColor = root.currentWallpaper.startsWith("#") ? root.currentWallpaper : Theme.primary; PopoutService.colorPickerModal.pickerTitle = "Choose Wallpaper Color"; PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) { if (SessionData.perMonitorWallpaper) { @@ -182,10 +195,7 @@ Item { height: 32 radius: 16 color: Qt.rgba(255, 255, 255, 0.9) - visible: { - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - return currentWallpaper !== ""; - } + visible: root.currentWallpaper !== "" DankIcon { anchors.centerIn: parent @@ -227,10 +237,7 @@ Item { anchors.verticalCenter: parent.verticalCenter StyledText { - text: { - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - return currentWallpaper ? currentWallpaper.split('/').pop() : "No wallpaper selected"; - } + text: root.currentWallpaper ? root.currentWallpaper.split('/').pop() : "No wallpaper selected" font.pixelSize: Theme.fontSizeLarge color: Theme.surfaceText elide: Text.ElideMiddle @@ -240,39 +247,27 @@ Item { } StyledText { - text: { - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - return currentWallpaper ? currentWallpaper : ""; - } + text: root.currentWallpaper font.pixelSize: Theme.fontSizeSmall color: Theme.surfaceVariantText elide: Text.ElideMiddle maximumLineCount: 1 width: parent.width horizontalAlignment: Text.AlignLeft - visible: { - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - return currentWallpaper !== ""; - } + visible: root.currentWallpaper !== "" } Row { anchors.left: parent.left spacing: Theme.spacingS layoutDirection: I18n.isRtl ? Qt.RightToLeft : Qt.LeftToRight - visible: { - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - return currentWallpaper !== ""; - } + visible: root.currentWallpaper !== "" DankActionButton { buttonSize: 32 iconName: "skip_previous" iconSize: Theme.iconSizeSmall - enabled: { - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - return currentWallpaper && !currentWallpaper.startsWith("#") && !currentWallpaper.startsWith("we"); - } + enabled: root.currentWallpaper && !root.currentWallpaper.startsWith("#") && !root.currentWallpaper.startsWith("we") opacity: enabled ? 1 : 0.5 backgroundColor: Theme.surfaceContainerHigh iconColor: Theme.surfaceText @@ -289,10 +284,7 @@ Item { buttonSize: 32 iconName: "skip_next" iconSize: Theme.iconSizeSmall - enabled: { - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - return currentWallpaper && !currentWallpaper.startsWith("#") && !currentWallpaper.startsWith("we"); - } + enabled: root.currentWallpaper && !root.currentWallpaper.startsWith("#") && !root.currentWallpaper.startsWith("we") opacity: enabled ? 1 : 0.5 backgroundColor: Theme.surfaceContainerHigh iconColor: Theme.surfaceText @@ -311,10 +303,7 @@ Item { Item { width: parent.width height: fillModeGroup.height - visible: { - var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath; - return currentWallpaper !== "" && !currentWallpaper.startsWith("#"); - } + visible: root.currentWallpaper !== "" && !root.currentWallpaper.startsWith("#") DankButtonGroup { id: fillModeGroup @@ -329,20 +318,39 @@ Item { textSize: Theme.fontSizeSmall checkEnabled: false currentIndex: { - return internalModes.indexOf(SettingsData.wallpaperFillMode); + var mode = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaperFillMode(selectedMonitorName) : SettingsData.wallpaperFillMode; + return internalModes.indexOf(mode); } onSelectionChanged: (index, selected) => { if (!selected) return; - SettingsData.set("wallpaperFillMode", internalModes[index]); + if (SessionData.perMonitorWallpaper) { + SessionData.setMonitorWallpaperFillMode(selectedMonitorName, internalModes[index]); + } else { + SettingsData.set("wallpaperFillMode", internalModes[index]); + } } Connections { target: SettingsData function onWallpaperFillModeChanged() { + if (SessionData.perMonitorWallpaper) + return; fillModeGroup.currentIndex = fillModeGroup.internalModes.indexOf(SettingsData.wallpaperFillMode); } } + + Connections { + target: root + function onSelectedMonitorNameChanged() { + if (!SessionData.perMonitorWallpaper) + return; + fillModeGroup.currentIndex = Qt.binding(() => { + var mode = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaperFillMode(selectedMonitorName) : SettingsData.wallpaperFillMode; + return fillModeGroup.internalModes.indexOf(mode); + }); + } + } } } diff --git a/quickshell/Modules/WallpaperBackground.qml b/quickshell/Modules/WallpaperBackground.qml index 6b4b2e66..174f8185 100644 --- a/quickshell/Modules/WallpaperBackground.qml +++ b/quickshell/Modules/WallpaperBackground.qml @@ -71,7 +71,7 @@ Variants { } property real transitionProgress: 0 - property real shaderFillMode: getFillMode(SettingsData.wallpaperFillMode) + property real shaderFillMode: getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name)) property vector4d fillColor: Qt.vector4d(0, 0, 0, 1) property real edgeSmoothness: 0.1 @@ -236,7 +236,7 @@ Variants { smooth: true cache: true sourceSize: Qt.size(root.textureWidth, root.textureHeight) - fillMode: root.getFillMode(SettingsData.wallpaperFillMode) + fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name)) } Image { @@ -249,7 +249,7 @@ Variants { smooth: true cache: true sourceSize: Qt.size(root.textureWidth, root.textureHeight) - fillMode: root.getFillMode(SettingsData.wallpaperFillMode) + fillMode: root.getFillMode(SessionData.getMonitorWallpaperFillMode(modelData.name)) onStatusChanged: { if (status !== Image.Ready)