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:
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -38,6 +38,7 @@ PanelWindow {
|
||||
active: demoActive
|
||||
sourceComponent: LockScreenContent {
|
||||
demoMode: true
|
||||
screenName: root.screen?.name ?? ""
|
||||
onUnlockRequested: root.hideDemo()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ WlSessionLockSurface {
|
||||
sourceComponent: LockScreenContent {
|
||||
demoMode: false
|
||||
passwordBuffer: root.sharedPasswordBuffer
|
||||
screenName: root.screen?.name ?? ""
|
||||
onUnlockRequested: root.unlock()
|
||||
onPasswordBufferChanged: {
|
||||
if (root.sharedPasswordBuffer !== passwordBuffer) {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
75
docs/IPC.md
75
docs/IPC.md
@@ -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`
|
||||
|
||||
Reference in New Issue
Block a user