1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-06 05:25:41 -05:00
Files
DankMaterialShell/quickshell/Services/WallpaperCyclingService.qml
2025-11-25 09:24:00 -05:00

456 lines
17 KiB
QML

pragma Singleton
pragma ComponentBehavior: Bound
import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import qs.Common
Singleton {
id: root
property bool cyclingActive: false
readonly property bool anyFullscreen: {
if (!ToplevelManager.toplevels?.values)
return false;
for (const toplevel of ToplevelManager.toplevels.values) {
if (toplevel.fullscreen)
return true;
}
return false;
}
property string cachedCyclingTime: SessionData.wallpaperCyclingTime
property int cachedCyclingInterval: SessionData.wallpaperCyclingInterval
property string lastTimeCheck: ""
property var monitorTimers: ({})
property var monitorLastTimeChecks: ({})
property var monitorProcesses: ({})
Component {
id: monitorTimerComponent
Timer {
property string targetScreen: ""
running: false
repeat: true
onTriggered: {
if (typeof WallpaperCyclingService !== "undefined" && targetScreen !== "" && !WallpaperCyclingService.anyFullscreen) {
WallpaperCyclingService.cycleNextForMonitor(targetScreen);
}
}
}
}
Component {
id: monitorProcessComponent
Process {
property string targetScreenName: ""
property string currentWallpaper: ""
property bool goToPrevious: false
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 wallpaperList = files.sort();
const currentPath = currentWallpaper;
let currentIndex = wallpaperList.findIndex(path => path === currentPath);
if (currentIndex === -1)
currentIndex = 0;
let targetIndex;
if (goToPrevious) {
targetIndex = currentIndex === 0 ? wallpaperList.length - 1 : currentIndex - 1;
} else {
targetIndex = (currentIndex + 1) % wallpaperList.length;
}
const targetWallpaper = wallpaperList[targetIndex];
if (targetWallpaper && targetWallpaper !== currentPath) {
if (targetScreenName) {
SessionData.setMonitorWallpaper(targetScreenName, targetWallpaper);
} else {
SessionData.setWallpaper(targetWallpaper);
}
}
}
}
}
}
}
Connections {
target: SessionData
function onWallpaperCyclingEnabledChanged() {
updateCyclingState();
}
function onWallpaperCyclingModeChanged() {
updateCyclingState();
}
function onWallpaperCyclingIntervalChanged() {
cachedCyclingInterval = SessionData.wallpaperCyclingInterval;
if (SessionData.wallpaperCyclingMode === "interval") {
updateCyclingState();
}
}
function onWallpaperCyclingTimeChanged() {
cachedCyclingTime = SessionData.wallpaperCyclingTime;
if (SessionData.wallpaperCyclingMode === "time") {
updateCyclingState();
}
}
function onPerMonitorWallpaperChanged() {
updateCyclingState();
}
function onMonitorCyclingSettingsChanged() {
updateCyclingState();
}
}
function updateCyclingState() {
if (SessionData.perMonitorWallpaper) {
stopCycling();
updatePerMonitorCycling();
} else if (SessionData.wallpaperCyclingEnabled && SessionData.wallpaperPath) {
startCycling();
stopAllMonitorCycling();
} else {
stopCycling();
stopAllMonitorCycling();
}
}
function updatePerMonitorCycling() {
if (typeof Quickshell === "undefined")
return;
var screens = Quickshell.screens;
for (var i = 0; i < screens.length; i++) {
var screenName = screens[i].name;
var settings = SessionData.getMonitorCyclingSettings(screenName);
var wallpaper = SessionData.getMonitorWallpaper(screenName);
if (settings.enabled && wallpaper && !wallpaper.startsWith("#")) {
startMonitorCycling(screenName, settings);
} else {
stopMonitorCycling(screenName);
}
}
}
function stopAllMonitorCycling() {
var screenNames = Object.keys(monitorTimers);
for (var i = 0; i < screenNames.length; i++) {
stopMonitorCycling(screenNames[i]);
}
}
function startCycling() {
if (SessionData.wallpaperCyclingMode === "interval") {
intervalTimer.interval = cachedCyclingInterval * 1000;
intervalTimer.start();
cyclingActive = true;
} else if (SessionData.wallpaperCyclingMode === "time") {
cyclingActive = true;
checkTimeBasedCycling();
}
}
function stopCycling() {
intervalTimer.stop();
cyclingActive = false;
}
function startMonitorCycling(screenName, settings) {
if (settings.mode === "interval") {
var timer = monitorTimers[screenName];
if (!timer && monitorTimerComponent && monitorTimerComponent.status === Component.Ready) {
var newTimers = Object.assign({}, monitorTimers);
newTimers[screenName] = monitorTimerComponent.createObject(root);
newTimers[screenName].targetScreen = screenName;
monitorTimers = newTimers;
timer = monitorTimers[screenName];
}
if (timer) {
timer.interval = settings.interval * 1000;
timer.start();
}
} else if (settings.mode === "time") {
var newChecks = Object.assign({}, monitorLastTimeChecks);
newChecks[screenName] = "";
monitorLastTimeChecks = newChecks;
}
}
function stopMonitorCycling(screenName) {
var timer = monitorTimers[screenName];
if (timer) {
timer.stop();
timer.destroy();
var newTimers = Object.assign({}, monitorTimers);
delete newTimers[screenName];
monitorTimers = newTimers;
}
var process = monitorProcesses[screenName];
if (process) {
process.destroy();
var newProcesses = Object.assign({}, monitorProcesses);
delete newProcesses[screenName];
monitorProcesses = newProcesses;
}
var newChecks = Object.assign({}, monitorLastTimeChecks);
delete newChecks[screenName];
monitorLastTimeChecks = newChecks;
}
function cycleToNextWallpaper(screenName, wallpaperPath) {
const currentWallpaper = wallpaperPath || SessionData.wallpaperPath;
if (!currentWallpaper)
return;
const wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/'));
if (screenName && monitorProcessComponent && monitorProcessComponent.status === Component.Ready) {
// Use per-monitor process
var process = monitorProcesses[screenName];
if (!process) {
var newProcesses = Object.assign({}, monitorProcesses);
newProcesses[screenName] = monitorProcessComponent.createObject(root);
monitorProcesses = newProcesses;
process = monitorProcesses[screenName];
}
if (process) {
process.command = ["sh", "-c", `ls -1 "${wallpaperDir}"/*.jpg "${wallpaperDir}"/*.jpeg "${wallpaperDir}"/*.png "${wallpaperDir}"/*.bmp "${wallpaperDir}"/*.gif "${wallpaperDir}"/*.webp 2>/dev/null | sort`];
process.targetScreenName = screenName;
process.currentWallpaper = currentWallpaper;
process.goToPrevious = false;
process.running = true;
}
} else {
// Use global process for fallback
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(screenName, wallpaperPath) {
const currentWallpaper = wallpaperPath || SessionData.wallpaperPath;
if (!currentWallpaper)
return;
const wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/'));
if (screenName && monitorProcessComponent && monitorProcessComponent.status === Component.Ready) {
// Use per-monitor process (same as next, but with prev flag)
var process = monitorProcesses[screenName];
if (!process) {
var newProcesses = Object.assign({}, monitorProcesses);
newProcesses[screenName] = monitorProcessComponent.createObject(root);
monitorProcesses = newProcesses;
process = monitorProcesses[screenName];
}
if (process) {
process.command = ["sh", "-c", `ls -1 "${wallpaperDir}"/*.jpg "${wallpaperDir}"/*.jpeg "${wallpaperDir}"/*.png "${wallpaperDir}"/*.bmp "${wallpaperDir}"/*.gif "${wallpaperDir}"/*.webp 2>/dev/null | sort`];
process.targetScreenName = screenName;
process.currentWallpaper = currentWallpaper;
process.goToPrevious = true;
process.running = true;
}
} else {
// Use global process for fallback
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;
}
}
function cycleNextManually() {
if (SessionData.wallpaperPath) {
cycleToNextWallpaper();
// Restart timers if cycling is active
if (cyclingActive && SessionData.wallpaperCyclingEnabled) {
if (SessionData.wallpaperCyclingMode === "interval") {
intervalTimer.interval = cachedCyclingInterval * 1000;
intervalTimer.restart();
}
}
}
}
function cyclePrevManually() {
if (SessionData.wallpaperPath) {
cycleToPrevWallpaper();
// Restart timers if cycling is active
if (cyclingActive && SessionData.wallpaperCyclingEnabled) {
if (SessionData.wallpaperCyclingMode === "interval") {
intervalTimer.interval = cachedCyclingInterval * 1000;
intervalTimer.restart();
}
}
}
}
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() {
if (anyFullscreen)
return;
const currentTime = Qt.formatTime(systemClock.date, "hh:mm");
if (!SessionData.perMonitorWallpaper) {
if (currentTime === cachedCyclingTime && currentTime !== lastTimeCheck) {
lastTimeCheck = currentTime;
cycleToNextWallpaper();
} else if (currentTime !== cachedCyclingTime) {
lastTimeCheck = "";
}
} else {
checkPerMonitorTimeBasedCycling(currentTime);
}
}
function checkPerMonitorTimeBasedCycling(currentTime) {
if (typeof Quickshell === "undefined")
return;
var screens = Quickshell.screens;
for (var i = 0; i < screens.length; i++) {
var screenName = screens[i].name;
var settings = SessionData.getMonitorCyclingSettings(screenName);
var wallpaper = SessionData.getMonitorWallpaper(screenName);
if (settings.enabled && settings.mode === "time" && wallpaper && !wallpaper.startsWith("#")) {
var lastCheck = monitorLastTimeChecks[screenName] || "";
if (currentTime === settings.time && currentTime !== lastCheck) {
var newChecks = Object.assign({}, monitorLastTimeChecks);
newChecks[screenName] = currentTime;
monitorLastTimeChecks = newChecks;
cycleNextForMonitor(screenName);
} else if (currentTime !== settings.time) {
var newChecks = Object.assign({}, monitorLastTimeChecks);
newChecks[screenName] = "";
monitorLastTimeChecks = newChecks;
}
}
}
}
Timer {
id: intervalTimer
interval: cachedCyclingInterval * 1000
running: false
repeat: true
onTriggered: {
if (anyFullscreen)
return;
cycleToNextWallpaper();
}
}
SystemClock {
id: systemClock
precision: SystemClock.Minutes
onDateChanged: {
if ((SessionData.wallpaperCyclingMode === "time" && cyclingActive) || SessionData.perMonitorWallpaper) {
checkTimeBasedCycling();
}
}
}
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 wallpaperList = files.sort();
const currentPath = cyclingProcess.currentWallpaper;
let currentIndex = wallpaperList.findIndex(path => path === currentPath);
if (currentIndex === -1)
currentIndex = 0;
const nextIndex = (currentIndex + 1) % wallpaperList.length;
const nextWallpaper = wallpaperList[nextIndex];
if (nextWallpaper && nextWallpaper !== currentPath) {
if (cyclingProcess.targetScreenName) {
SessionData.setMonitorWallpaper(cyclingProcess.targetScreenName, nextWallpaper);
} else {
SessionData.setWallpaper(nextWallpaper);
}
}
}
}
}
}
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 wallpaperList = files.sort();
const currentPath = prevCyclingProcess.currentWallpaper;
let currentIndex = wallpaperList.findIndex(path => path === currentPath);
if (currentIndex === -1)
currentIndex = 0;
const prevIndex = currentIndex === 0 ? wallpaperList.length - 1 : currentIndex - 1;
const prevWallpaper = wallpaperList[prevIndex];
if (prevWallpaper && prevWallpaper !== currentPath) {
if (prevCyclingProcess.targetScreenName) {
SessionData.setMonitorWallpaper(prevCyclingProcess.targetScreenName, prevWallpaper);
} else {
SessionData.setWallpaper(prevWallpaper);
}
}
}
}
}
}
}