1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-24 13:32:50 -05:00

per-monitor wallpapers

This commit is contained in:
bbedward
2025-09-05 16:08:32 -04:00
parent 68157ca636
commit 8d674a4fdc
10 changed files with 494 additions and 71 deletions

View File

@@ -16,6 +16,8 @@ Singleton {
property string wallpaperPath: ""
property string wallpaperLastPath: ""
property string profileLastPath: ""
property bool perMonitorWallpaper: false
property var monitorWallpapers: ({})
property bool doNotDisturb: false
property bool nightModeEnabled: false
property int nightModeTemperature: 4500
@@ -56,6 +58,8 @@ Singleton {
wallpaperPath = settings.wallpaperPath !== undefined ? settings.wallpaperPath : ""
wallpaperLastPath = settings.wallpaperLastPath !== undefined ? settings.wallpaperLastPath : ""
profileLastPath = settings.profileLastPath !== undefined ? settings.profileLastPath : ""
perMonitorWallpaper = settings.perMonitorWallpaper !== undefined ? settings.perMonitorWallpaper : false
monitorWallpapers = settings.monitorWallpapers !== undefined ? settings.monitorWallpapers : {}
doNotDisturb = settings.doNotDisturb !== undefined ? settings.doNotDisturb : false
nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false
nightModeTemperature = settings.nightModeTemperature !== undefined ? settings.nightModeTemperature : 4500
@@ -104,6 +108,8 @@ Singleton {
"wallpaperPath": wallpaperPath,
"wallpaperLastPath": wallpaperLastPath,
"profileLastPath": profileLastPath,
"perMonitorWallpaper": perMonitorWallpaper,
"monitorWallpapers": monitorWallpapers,
"doNotDisturb": doNotDisturb,
"nightModeEnabled": nightModeEnabled,
"nightModeTemperature": nightModeTemperature,
@@ -318,6 +324,56 @@ Singleton {
saveSettings()
}
function setPerMonitorWallpaper(enabled) {
perMonitorWallpaper = enabled
// Disable automatic cycling when per-monitor mode is enabled
if (enabled && wallpaperCyclingEnabled) {
wallpaperCyclingEnabled = false
}
saveSettings()
// Refresh dynamic theming when per-monitor mode changes
if (typeof Theme !== "undefined") {
if (typeof SettingsData !== "undefined" && SettingsData.wallpaperDynamicTheming) {
Theme.switchTheme("dynamic")
Theme.extractColors()
}
Theme.generateSystemThemesFromCurrentTheme()
}
}
function setMonitorWallpaper(screenName, path) {
var newMonitorWallpapers = Object.assign({}, monitorWallpapers)
if (path && path !== "") {
newMonitorWallpapers[screenName] = path
} else {
delete newMonitorWallpapers[screenName]
}
monitorWallpapers = newMonitorWallpapers
saveSettings()
// Trigger dynamic theming if this is the first monitor and dynamic theming is enabled
if (typeof Theme !== "undefined" && typeof Quickshell !== "undefined") {
var screens = Quickshell.screens
if (screens.length > 0 && screenName === screens[0].name) {
if (typeof SettingsData !== "undefined" && SettingsData.wallpaperDynamicTheming) {
Theme.switchTheme("dynamic")
Theme.extractColors()
}
Theme.generateSystemThemesFromCurrentTheme()
}
}
}
function getMonitorWallpaper(screenName) {
if (!perMonitorWallpaper) {
return wallpaperPath
}
return monitorWallpapers[screenName] || wallpaperPath
}
function setLastBrightnessDevice(device) {
lastBrightnessDevice = device
saveSettings()
@@ -340,10 +396,17 @@ Singleton {
target: "wallpaper"
function get(): string {
if (root.perMonitorWallpaper) {
return "ERROR: Per-monitor mode enabled. Use getFor(screenName) instead."
}
return root.wallpaperPath || ""
}
function set(path: string): string {
if (root.perMonitorWallpaper) {
return "ERROR: Per-monitor mode enabled. Use setFor(screenName, path) instead."
}
if (!path) {
return "ERROR: No path provided"
}
@@ -360,10 +423,17 @@ Singleton {
function clear(): string {
root.setWallpaper("")
return "SUCCESS: Wallpaper cleared"
root.setPerMonitorWallpaper(false)
root.monitorWallpapers = {}
root.saveSettings()
return "SUCCESS: All wallpapers cleared"
}
function next(): string {
if (root.perMonitorWallpaper) {
return "ERROR: Per-monitor mode enabled. Use nextFor(screenName) instead."
}
if (!root.wallpaperPath) {
return "ERROR: No wallpaper set"
}
@@ -377,6 +447,10 @@ Singleton {
}
function prev(): string {
if (root.perMonitorWallpaper) {
return "ERROR: Per-monitor mode enabled. Use prevFor(screenName) instead."
}
if (!root.wallpaperPath) {
return "ERROR: No wallpaper set"
}
@@ -388,5 +462,70 @@ Singleton {
return "ERROR: Failed to cycle wallpaper: " + e.toString()
}
}
function getFor(screenName: string): string {
if (!screenName) {
return "ERROR: No screen name provided"
}
return root.getMonitorWallpaper(screenName) || ""
}
function setFor(screenName: string, path: string): string {
if (!screenName) {
return "ERROR: No screen name provided"
}
if (!path) {
return "ERROR: No path provided"
}
var absolutePath = path.startsWith("/") ? path : StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/" + path
try {
if (!root.perMonitorWallpaper) {
root.setPerMonitorWallpaper(true)
}
root.setMonitorWallpaper(screenName, absolutePath)
return "SUCCESS: Wallpaper set for " + screenName + " to " + absolutePath
} catch (e) {
return "ERROR: Failed to set wallpaper for " + screenName + ": " + e.toString()
}
}
function nextFor(screenName: string): string {
if (!screenName) {
return "ERROR: No screen name provided"
}
var currentWallpaper = root.getMonitorWallpaper(screenName)
if (!currentWallpaper) {
return "ERROR: No wallpaper set for " + screenName
}
try {
WallpaperCyclingService.cycleNextForMonitor(screenName)
return "SUCCESS: Cycling to next wallpaper for " + screenName
} catch (e) {
return "ERROR: Failed to cycle wallpaper for " + screenName + ": " + e.toString()
}
}
function prevFor(screenName: string): string {
if (!screenName) {
return "ERROR: No screen name provided"
}
var currentWallpaper = root.getMonitorWallpaper(screenName)
if (!currentWallpaper) {
return "ERROR: No wallpaper set for " + screenName
}
try {
WallpaperCyclingService.cyclePrevForMonitor(screenName)
return "SUCCESS: Cycling to previous wallpaper for " + screenName
} catch (e) {
return "ERROR: Failed to cycle wallpaper for " + screenName + ": " + e.toString()
}
}
}
}

View File

@@ -27,7 +27,20 @@ Singleton {
return url.startsWith("file://") ? url.substring(7) : url
}
readonly property string shellDir: Qt.resolvedUrl(".").toString().replace("file://", "").replace("/Common/", "")
readonly property string wallpaperPath: typeof SessionData !== "undefined" ? SessionData.wallpaperPath : ""
readonly property string wallpaperPath: {
if (typeof SessionData === "undefined") return ""
if (SessionData.perMonitorWallpaper) {
// Use first monitor's wallpaper for dynamic theming
var screens = Quickshell.screens
if (screens.length > 0) {
var firstMonitorWallpaper = SessionData.getMonitorWallpaper(screens[0].name)
return firstMonitorWallpaper || SessionData.wallpaperPath
}
}
return SessionData.wallpaperPath
}
property bool matugenAvailable: false
property bool gtkThemingEnabled: typeof SettingsData !== "undefined" ? SettingsData.gtkAvailable : false

View File

@@ -14,6 +14,7 @@ Item {
property string passwordBuffer: ""
property bool demoMode: false
property string screenName: ""
signal unlockRequested
@@ -57,17 +58,25 @@ Item {
Loader {
anchors.fill: parent
active: !SessionData.wallpaperPath || (SessionData.wallpaperPath && SessionData.wallpaperPath.startsWith("#"))
active: {
var currentWallpaper = SessionData.getMonitorWallpaper(screenName)
return !currentWallpaper || (currentWallpaper && currentWallpaper.startsWith("#"))
}
asynchronous: true
sourceComponent: DankBackdrop {}
sourceComponent: DankBackdrop {
screenName: root.screenName
}
}
Image {
id: wallpaperBackground
anchors.fill: parent
source: (SessionData.wallpaperPath && !SessionData.wallpaperPath.startsWith("#")) ? SessionData.wallpaperPath : ""
source: {
var currentWallpaper = SessionData.getMonitorWallpaper(screenName)
return (currentWallpaper && !currentWallpaper.startsWith("#")) ? currentWallpaper : ""
}
fillMode: Image.PreserveAspectCrop
smooth: true
asynchronous: false

View File

@@ -38,6 +38,7 @@ PanelWindow {
active: demoActive
sourceComponent: LockScreenContent {
demoMode: true
screenName: root.screen?.name ?? ""
onUnlockRequested: root.hideDemo()
}
}

View File

@@ -25,6 +25,7 @@ WlSessionLockSurface {
sourceComponent: LockScreenContent {
demoMode: false
passwordBuffer: root.sharedPasswordBuffer
screenName: root.screen?.name ?? ""
onUnlockRequested: root.unlock()
onPasswordBufferChanged: {
if (root.sharedPasswordBuffer !== passwordBuffer) {

View File

@@ -16,6 +16,10 @@ Item {
property var cachedFontFamilies: []
property var cachedMonoFamilies: []
property bool fontsEnumerated: false
property string selectedMonitorName: {
var screens = Quickshell.screens
return screens.length > 0 ? screens[0].name : ""
}
function enumerateFonts() {
var fonts = ["Default"]
@@ -137,9 +141,15 @@ Item {
CachingImage {
anchors.fill: parent
anchors.margins: 1
source: (SessionData.wallpaperPath !== "" && !SessionData.wallpaperPath.startsWith("#")) ? "file://" + SessionData.wallpaperPath : ""
source: {
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
return (currentWallpaper !== "" && !currentWallpaper.startsWith("#")) ? "file://" + currentWallpaper : ""
}
fillMode: Image.PreserveAspectCrop
visible: SessionData.wallpaperPath !== "" && !SessionData.wallpaperPath.startsWith("#")
visible: {
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
return currentWallpaper !== "" && !currentWallpaper.startsWith("#")
}
maxCacheSize: 160
layer.enabled: true
@@ -155,8 +165,14 @@ Item {
anchors.fill: parent
anchors.margins: 1
radius: Theme.cornerRadius - 1
color: SessionData.wallpaperPath.startsWith("#") ? SessionData.wallpaperPath : "transparent"
visible: SessionData.wallpaperPath !== "" && SessionData.wallpaperPath.startsWith("#")
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("#")
}
}
Rectangle {
@@ -175,7 +191,10 @@ Item {
name: "image"
size: Theme.iconSizeLarge + 8
color: Theme.surfaceVariantText
visible: SessionData.wallpaperPath === ""
visible: {
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
return currentWallpaper === ""
}
}
Rectangle {
@@ -242,7 +261,10 @@ Item {
height: 32
radius: 16
color: Qt.rgba(255, 255, 255, 0.9)
visible: SessionData.wallpaperPath !== ""
visible: {
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
return currentWallpaper !== ""
}
DankIcon {
anchors.centerIn: parent
@@ -255,10 +277,13 @@ Item {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: {
if (Theme.currentTheme === Theme.dynamic)
Theme.switchTheme("blue")
SessionData.clearWallpaper()
if (SessionData.perMonitorWallpaper) {
SessionData.setMonitorWallpaper(selectedMonitorName, "")
} else {
if (Theme.currentTheme === Theme.dynamic)
Theme.switchTheme("blue")
SessionData.clearWallpaper()
}
}
}
}
@@ -282,7 +307,10 @@ Item {
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: SessionData.wallpaperPath ? SessionData.wallpaperPath.split('/').pop() : "No wallpaper selected"
text: {
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
return currentWallpaper ? currentWallpaper.split('/').pop() : "No wallpaper selected"
}
font.pixelSize: Theme.fontSizeLarge
color: Theme.surfaceText
elide: Text.ElideMiddle
@@ -291,29 +319,48 @@ Item {
}
StyledText {
text: SessionData.wallpaperPath ? SessionData.wallpaperPath : ""
text: {
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
return currentWallpaper ? currentWallpaper : ""
}
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
elide: Text.ElideMiddle
maximumLineCount: 1
width: parent.width
visible: SessionData.wallpaperPath !== ""
visible: {
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
return currentWallpaper !== ""
}
}
Row {
spacing: Theme.spacingS
visible: SessionData.wallpaperPath !== ""
visible: {
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
return currentWallpaper !== ""
}
DankActionButton {
buttonSize: 32
iconName: "skip_previous"
iconSize: Theme.iconSizeSmall
enabled: SessionData.wallpaperPath && !SessionData.wallpaperPath.startsWith("#")
opacity: (SessionData.wallpaperPath && !SessionData.wallpaperPath.startsWith("#")) ? 1 : 0.5
enabled: {
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
return currentWallpaper && !currentWallpaper.startsWith("#")
}
opacity: {
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
return (currentWallpaper && !currentWallpaper.startsWith("#")) ? 1 : 0.5
}
backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5)
iconColor: Theme.surfaceText
onClicked: {
WallpaperCyclingService.cyclePrevManually()
if (SessionData.perMonitorWallpaper) {
WallpaperCyclingService.cyclePrevForMonitor(selectedMonitorName)
} else {
WallpaperCyclingService.cyclePrevManually()
}
}
}
@@ -321,19 +368,29 @@ Item {
buttonSize: 32
iconName: "skip_next"
iconSize: Theme.iconSizeSmall
enabled: SessionData.wallpaperPath && !SessionData.wallpaperPath.startsWith("#")
opacity: (SessionData.wallpaperPath && !SessionData.wallpaperPath.startsWith("#")) ? 1 : 0.5
enabled: {
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
return currentWallpaper && !currentWallpaper.startsWith("#")
}
opacity: {
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
return (currentWallpaper && !currentWallpaper.startsWith("#")) ? 1 : 0.5
}
backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5)
iconColor: Theme.surfaceText
onClicked: {
WallpaperCyclingService.cycleNextManually()
if (SessionData.perMonitorWallpaper) {
WallpaperCyclingService.cycleNextForMonitor(selectedMonitorName)
} else {
WallpaperCyclingService.cycleNextManually()
}
}
}
}
}
}
// Wallpaper Cycling Section - Full Width
// Per-Monitor Wallpaper Section - Full Width
Rectangle {
width: parent.width
height: 1
@@ -347,6 +404,97 @@ Item {
spacing: Theme.spacingM
visible: SessionData.wallpaperPath !== ""
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "monitor"
size: Theme.iconSize
color: SessionData.perMonitorWallpaper ? Theme.primary : Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
Column {
width: parent.width - Theme.iconSize - Theme.spacingM - perMonitorToggle.width - Theme.spacingM
spacing: Theme.spacingXS
anchors.verticalCenter: parent.verticalCenter
StyledText {
text: "Per-Monitor Wallpapers"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
}
StyledText {
text: "Set different wallpapers for each connected monitor"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
width: parent.width
}
}
DankToggle {
id: perMonitorToggle
anchors.verticalCenter: parent.verticalCenter
checked: SessionData.perMonitorWallpaper
onToggled: toggled => {
return SessionData.setPerMonitorWallpaper(toggled)
}
}
}
Column {
width: parent.width
spacing: Theme.spacingS
visible: SessionData.perMonitorWallpaper
leftPadding: Theme.iconSize + Theme.spacingM
StyledText {
text: "Monitor Selection:"
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
font.weight: Font.Medium
}
DankDropdown {
id: monitorDropdown
width: parent.width - parent.leftPadding
text: "Monitor"
description: "Select monitor to configure wallpaper"
currentValue: selectedMonitorName || "No monitors"
options: {
var screenNames = []
var screens = Quickshell.screens
for (var i = 0; i < screens.length; i++) {
screenNames.push(screens[i].name)
}
return screenNames
}
onValueChanged: value => {
selectedMonitorName = value
}
}
}
}
// Wallpaper Cycling Section - Full Width
Rectangle {
width: parent.width
height: 1
color: Theme.outline
opacity: 0.2
visible: SessionData.wallpaperPath !== "" && !SessionData.perMonitorWallpaper
}
Column {
width: parent.width
spacing: Theme.spacingM
visible: SessionData.wallpaperPath !== "" && !SessionData.perMonitorWallpaper
Row {
width: parent.width
spacing: Theme.spacingM
@@ -383,6 +531,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
checked: SessionData.wallpaperCyclingEnabled
enabled: !SessionData.perMonitorWallpaper
onToggled: toggled => {
return SessionData.setWallpaperCyclingEnabled(toggled)
}
@@ -1107,7 +1256,11 @@ Item {
browserType: "wallpaper"
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
onFileSelected: path => {
SessionData.setWallpaper(path)
if (SessionData.perMonitorWallpaper) {
SessionData.setMonitorWallpaper(selectedMonitorName, path)
} else {
SessionData.setWallpaper(path)
}
close()
}
onDialogClosed: {
@@ -1125,7 +1278,11 @@ Item {
pickerTitle: "Choose Wallpaper Color"
onColorSelected: selectedColor => {
SessionData.setWallpaperColor(selectedColor)
if (SessionData.perMonitorWallpaper) {
SessionData.setMonitorWallpaper(selectedMonitorName, selectedColor)
} else {
SessionData.setWallpaperColor(selectedColor)
}
}
}
}

View File

@@ -32,7 +32,7 @@ LazyLoader {
id: root
anchors.fill: parent
property string source: SessionData.wallpaperPath || ""
property string source: SessionData.getMonitorWallpaper(modelData.name) || ""
property bool isColorSource: source.startsWith("#")
property Image current: one
@@ -71,7 +71,9 @@ LazyLoader {
active: !root.source || root.isColorSource
asynchronous: true
sourceComponent: DankBackdrop {}
sourceComponent: DankBackdrop {
screenName: modelData.name
}
}
Img {

View File

@@ -42,10 +42,14 @@ Singleton {
updateCyclingState()
}
}
function onPerMonitorWallpaperChanged() {
updateCyclingState()
}
}
function updateCyclingState() {
if (SessionData.wallpaperCyclingEnabled && SessionData.wallpaperPath) {
if (SessionData.wallpaperCyclingEnabled && SessionData.wallpaperPath && !SessionData.perMonitorWallpaper) {
startCycling()
} else {
stopCycling()
@@ -68,23 +72,25 @@ Singleton {
cyclingActive = false
}
function cycleToNextWallpaper() {
if (!SessionData.wallpaperPath)
return
function cycleToNextWallpaper(screenName, wallpaperPath) {
const currentWallpaper = wallpaperPath || SessionData.wallpaperPath
if (!currentWallpaper) return
const wallpaperDir = SessionData.wallpaperPath.substring(
0, SessionData.wallpaperPath.lastIndexOf('/'))
const wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/'))
cyclingProcess.command = ["sh", "-c", `ls -1 "${wallpaperDir}"/*.jpg "${wallpaperDir}"/*.jpeg "${wallpaperDir}"/*.png "${wallpaperDir}"/*.bmp "${wallpaperDir}"/*.gif "${wallpaperDir}"/*.webp 2>/dev/null | sort`]
cyclingProcess.targetScreenName = screenName || ""
cyclingProcess.currentWallpaper = currentWallpaper
cyclingProcess.running = true
}
function cycleToPrevWallpaper() {
if (!SessionData.wallpaperPath)
return
function cycleToPrevWallpaper(screenName, wallpaperPath) {
const currentWallpaper = wallpaperPath || SessionData.wallpaperPath
if (!currentWallpaper) return
const wallpaperDir = SessionData.wallpaperPath.substring(
0, SessionData.wallpaperPath.lastIndexOf('/'))
const wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/'))
prevCyclingProcess.command = ["sh", "-c", `ls -1 "${wallpaperDir}"/*.jpg "${wallpaperDir}"/*.jpeg "${wallpaperDir}"/*.png "${wallpaperDir}"/*.bmp "${wallpaperDir}"/*.gif "${wallpaperDir}"/*.webp 2>/dev/null | sort`]
prevCyclingProcess.targetScreenName = screenName || ""
prevCyclingProcess.currentWallpaper = currentWallpaper
prevCyclingProcess.running = true
}
@@ -114,6 +120,24 @@ Singleton {
}
}
function cycleNextForMonitor(screenName) {
if (!screenName) return
var currentWallpaper = SessionData.getMonitorWallpaper(screenName)
if (currentWallpaper) {
cycleToNextWallpaper(screenName, currentWallpaper)
}
}
function cyclePrevForMonitor(screenName) {
if (!screenName) return
var currentWallpaper = SessionData.getMonitorWallpaper(screenName)
if (currentWallpaper) {
cycleToPrevWallpaper(screenName, currentWallpaper)
}
}
function checkTimeBasedCycling() {
const currentTime = Qt.formatTime(systemClock.date, "hh:mm")
@@ -146,29 +170,32 @@ Singleton {
Process {
id: cyclingProcess
property string targetScreenName: ""
property string currentWallpaper: ""
running: false
stdout: StdioCollector {
onStreamFinished: {
if (text && text.trim()) {
const files = text.trim().split('\n').filter(
file => file.length > 0)
if (files.length <= 1)
return
const files = text.trim().split('\n').filter(file => file.length > 0)
if (files.length <= 1) return
const wallpaperList = files.sort()
const currentPath = SessionData.wallpaperPath
let currentIndex = wallpaperList.findIndex(
path => path === currentPath)
if (currentIndex === -1)
currentIndex = 0
const currentPath = cyclingProcess.currentWallpaper
let currentIndex = wallpaperList.findIndex(path => path === currentPath)
if (currentIndex === -1) currentIndex = 0
// Get next wallpaper
const nextIndex = (currentIndex + 1) % wallpaperList.length
const nextWallpaper = wallpaperList[nextIndex]
if (nextWallpaper && nextWallpaper !== currentPath) {
SessionData.setWallpaper(nextWallpaper)
if (cyclingProcess.targetScreenName) {
SessionData.setMonitorWallpaper(cyclingProcess.targetScreenName, nextWallpaper)
} else {
SessionData.setWallpaper(nextWallpaper)
}
}
}
}
@@ -177,33 +204,36 @@ Singleton {
Process {
id: prevCyclingProcess
property string targetScreenName: ""
property string currentWallpaper: ""
running: false
stdout: StdioCollector {
onStreamFinished: {
if (text && text.trim()) {
const files = text.trim().split('\n').filter(
file => file.length > 0)
if (files.length <= 1)
return
const files = text.trim().split('\n').filter(file => file.length > 0)
if (files.length <= 1) return
const wallpaperList = files.sort()
const currentPath = SessionData.wallpaperPath
let currentIndex = wallpaperList.findIndex(
path => path === currentPath)
if (currentIndex === -1)
currentIndex = 0
const currentPath = prevCyclingProcess.currentWallpaper
let currentIndex = wallpaperList.findIndex(path => path === currentPath)
if (currentIndex === -1) currentIndex = 0
// Get previous wallpaper
const prevIndex = currentIndex
=== 0 ? wallpaperList.length - 1 : currentIndex - 1
const prevIndex = currentIndex === 0 ? wallpaperList.length - 1 : currentIndex - 1
const prevWallpaper = wallpaperList[prevIndex]
if (prevWallpaper && prevWallpaper !== currentPath) {
SessionData.setWallpaper(prevWallpaper)
if (prevCyclingProcess.targetScreenName) {
SessionData.setMonitorWallpaper(prevCyclingProcess.targetScreenName, prevWallpaper)
} else {
SessionData.setWallpaper(prevWallpaper)
}
}
}
}
}
}
}

View File

@@ -6,11 +6,15 @@ Item {
anchors.fill: parent
property bool isColorWallpaper: SessionData.wallpaperPath && SessionData.wallpaperPath.startsWith("#")
property string screenName: ""
property bool isColorWallpaper: {
var currentWallpaper = SessionData.getMonitorWallpaper(screenName)
return currentWallpaper && currentWallpaper.startsWith("#")
}
Rectangle {
anchors.fill: parent
color: isColorWallpaper ? SessionData.wallpaperPath : Theme.background
color: isColorWallpaper ? SessionData.getMonitorWallpaper(screenName) : Theme.background
}
Rectangle {

View File

@@ -238,23 +238,90 @@ qs -c dms ipc call inhibit enable
## Target: `wallpaper`
Wallpaper management and retrieval.
Wallpaper management and retrieval with support for per-monitor configurations.
### Functions
### Legacy Functions (Global Wallpaper Mode)
**`get`**
- Get current wallpaper path
- Returns: Full path to current wallpaper file
- Returns: Full path to current wallpaper file, or error if per-monitor mode is enabled
**`set <path>`**
- Set wallpaper to specified path
- Parameters: `path` - Absolute or relative path to image file
- Returns: Confirmation message or error
- Returns: Confirmation message or error if per-monitor mode is enabled
**`clear`**
- Clear all wallpapers and disable per-monitor mode
- Returns: Success confirmation
**`next`**
- Cycle to next wallpaper in the same directory
- Returns: Success confirmation or error if per-monitor mode is enabled
**`prev`**
- Cycle to previous wallpaper in the same directory
- Returns: Success confirmation or error if per-monitor mode is enabled
### Per-Monitor Functions
**`getFor <screenName>`**
- Get wallpaper path for specific monitor
- Parameters: `screenName` - Monitor name (e.g., "DP-2", "eDP-1")
- Returns: Full path to wallpaper file for the specified monitor
**`setFor <screenName> <path>`**
- Set wallpaper for specific monitor (automatically enables per-monitor mode)
- Parameters:
- `screenName` - Monitor name (e.g., "DP-2", "eDP-1")
- `path` - Absolute or relative path to image file
- Returns: Success confirmation with monitor and path info
**`nextFor <screenName>`**
- Cycle to next wallpaper for specific monitor
- Parameters: `screenName` - Monitor name (e.g., "DP-2", "eDP-1")
- Returns: Success confirmation
**`prevFor <screenName>`**
- Cycle to previous wallpaper for specific monitor
- Parameters: `screenName` - Monitor name (e.g., "DP-2", "eDP-1")
- Returns: Success confirmation
### Examples
**Global wallpaper mode:**
```bash
qs -c dms ipc call wallpaper get
qs -c dms ipc call wallpaper set /path/to/image.jpg
qs -c dms ipc call wallpaper next
qs -c dms ipc call wallpaper clear
```
**Per-monitor wallpaper mode:**
```bash
# Set different wallpapers for each monitor
qs -c dms ipc call wallpaper setFor DP-2 /path/to/image1.jpg
qs -c dms ipc call wallpaper setFor eDP-1 /path/to/image2.jpg
# Get wallpaper for specific monitor
qs -c dms ipc call wallpaper getFor DP-2
# Cycle wallpapers for specific monitor
qs -c dms ipc call wallpaper nextFor eDP-1
qs -c dms ipc call wallpaper prevFor DP-2
# Clear all wallpapers and return to global mode
qs -c dms ipc call wallpaper clear
```
**Error handling:**
When per-monitor mode is enabled, legacy functions will return helpful error messages:
```bash
qs -c dms ipc call wallpaper get
# Returns: "ERROR: Per-monitor mode enabled. Use getFor(screenName) instead."
qs -c dms ipc call wallpaper set /path/to/image.jpg
# Returns: "ERROR: Per-monitor mode enabled. Use setFor(screenName, path) instead."
```
## Target: `profile`