mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-02 03:28:28 -04:00
431 lines
14 KiB
QML
431 lines
14 KiB
QML
pragma Singleton
|
|
pragma ComponentBehavior: Bound
|
|
|
|
import QtCore
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import Quickshell.Wayland
|
|
import qs.Common
|
|
import qs.Services
|
|
|
|
Singleton {
|
|
id: root
|
|
|
|
property bool cyclingActive: false
|
|
readonly property bool fullscreenShowing: {
|
|
if (!ToplevelManager.toplevels?.values)
|
|
return false;
|
|
for (const toplevel of ToplevelManager.toplevels.values) {
|
|
if (toplevel.fullscreen && toplevel.activated)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
readonly property bool shouldPauseCycling: fullscreenShowing || SessionService.locked
|
|
readonly property bool serverSchedulingAvailable: DMSService.capabilities.includes("wallpaper")
|
|
property real lastCycleSeq: -1
|
|
property var monitorProcesses: ({})
|
|
|
|
Connections {
|
|
target: DMSService
|
|
|
|
function onWallpaperCycleUpdate(data) {
|
|
if (!data)
|
|
return;
|
|
const seq = data.cycleSeq || 0;
|
|
if (lastCycleSeq < 0) {
|
|
lastCycleSeq = seq;
|
|
return;
|
|
}
|
|
if (seq <= lastCycleSeq)
|
|
return;
|
|
lastCycleSeq = seq;
|
|
if (shouldPauseCycling)
|
|
return;
|
|
const target = data.target || "";
|
|
if (target === "") {
|
|
cycleToNextWallpaper();
|
|
} else {
|
|
cycleNextForMonitor(target);
|
|
}
|
|
}
|
|
|
|
function onCapabilitiesReceived() {
|
|
lastCycleSeq = -1;
|
|
updateCyclingState();
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: SessionData
|
|
|
|
function onWallpaperCyclingEnabledChanged() {
|
|
updateCyclingState();
|
|
}
|
|
|
|
function onWallpaperCyclingModeChanged() {
|
|
updateCyclingState();
|
|
}
|
|
|
|
function onWallpaperCyclingIntervalChanged() {
|
|
updateCyclingState();
|
|
}
|
|
|
|
function onWallpaperCyclingTimeChanged() {
|
|
updateCyclingState();
|
|
}
|
|
|
|
function onPerMonitorWallpaperChanged() {
|
|
updateCyclingState();
|
|
}
|
|
|
|
function onMonitorCyclingSettingsChanged() {
|
|
updateCyclingState();
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: SessionService
|
|
|
|
function onSessionUnlocked() {
|
|
updateCyclingState();
|
|
}
|
|
}
|
|
|
|
function updateCyclingState() {
|
|
cyclingActive = serverSchedulingAvailable && (SessionData.wallpaperCyclingEnabled || SessionData.perMonitorWallpaper);
|
|
pushConfigToServer();
|
|
}
|
|
|
|
function buildServerConfig() {
|
|
var monitors = {};
|
|
if (SessionData.perMonitorWallpaper && typeof Quickshell !== "undefined") {
|
|
var screens = Quickshell.screens;
|
|
for (var i = 0; i < screens.length; i++) {
|
|
var name = screens[i].name;
|
|
var s = SessionData.getMonitorCyclingSettings(name);
|
|
var wp = SessionData.getMonitorWallpaper(name);
|
|
monitors[name] = {
|
|
"enabled": !!(s.enabled && wp && !wp.startsWith("#")),
|
|
"mode": s.mode || "interval",
|
|
"intervalSec": s.interval || 300,
|
|
"time": s.time || "06:00"
|
|
};
|
|
}
|
|
}
|
|
return {
|
|
"perMonitor": SessionData.perMonitorWallpaper,
|
|
"global": {
|
|
"enabled": !!(SessionData.wallpaperCyclingEnabled && SessionData.wallpaperPath),
|
|
"mode": SessionData.wallpaperCyclingMode,
|
|
"intervalSec": SessionData.wallpaperCyclingInterval,
|
|
"time": SessionData.wallpaperCyclingTime
|
|
},
|
|
"monitors": monitors
|
|
};
|
|
}
|
|
|
|
function pushConfigToServer() {
|
|
if (!serverSchedulingAvailable)
|
|
return;
|
|
DMSService.sendRequest("wallpaper.setConfig", {
|
|
"config": buildServerConfig()
|
|
}, null);
|
|
}
|
|
|
|
function findCommand(wallpaperDir) {
|
|
return ["sh", "-c", `find -L "${wallpaperDir}" -maxdepth 1 -type f \\( -iname "*.jpg" -o -iname "*.jpeg" -o -iname "*.png" -o -iname "*.bmp" -o -iname "*.gif" -o -iname "*.webp" -o -iname "*.jxl" -o -iname "*.avif" -o -iname "*.heif" -o -iname "*.exr" \\) 2>/dev/null | sort`];
|
|
}
|
|
|
|
function monitorProcessFor(screenName) {
|
|
var process = monitorProcesses[screenName];
|
|
if (process)
|
|
return process;
|
|
var newProcesses = Object.assign({}, monitorProcesses);
|
|
process = monitorProcessComponent.createObject(root);
|
|
newProcesses[screenName] = process;
|
|
monitorProcesses = newProcesses;
|
|
return process;
|
|
}
|
|
|
|
function cycle(screenName, wallpaperPath, goToPrevious) {
|
|
const currentWallpaper = wallpaperPath || SessionData.wallpaperPath;
|
|
if (!currentWallpaper)
|
|
return;
|
|
const wallpaperDir = currentWallpaper.substring(0, currentWallpaper.lastIndexOf('/'));
|
|
|
|
if (screenName && monitorProcessComponent.status === Component.Ready) {
|
|
var process = monitorProcessFor(screenName);
|
|
process.command = findCommand(wallpaperDir);
|
|
process.targetScreenName = screenName;
|
|
process.currentWallpaper = currentWallpaper;
|
|
process.goToPrevious = goToPrevious;
|
|
process.running = true;
|
|
return;
|
|
}
|
|
|
|
var globalProcess = goToPrevious ? prevCyclingProcess : cyclingProcess;
|
|
globalProcess.command = findCommand(wallpaperDir);
|
|
globalProcess.targetScreenName = screenName || "";
|
|
globalProcess.currentWallpaper = currentWallpaper;
|
|
globalProcess.running = true;
|
|
}
|
|
|
|
function cycleToNextWallpaper(screenName, wallpaperPath) {
|
|
cycle(screenName, wallpaperPath, false);
|
|
}
|
|
|
|
function cycleToPrevWallpaper(screenName, wallpaperPath) {
|
|
cycle(screenName, wallpaperPath, true);
|
|
}
|
|
|
|
function resetScheduleAfterManual() {
|
|
if (!serverSchedulingAvailable)
|
|
return;
|
|
DMSService.sendRequest("wallpaper.trigger", {
|
|
"target": ""
|
|
}, null);
|
|
}
|
|
|
|
function cycleNextManually() {
|
|
if (!SessionData.wallpaperPath)
|
|
return;
|
|
cycleToNextWallpaper();
|
|
resetScheduleAfterManual();
|
|
}
|
|
|
|
function cyclePrevManually() {
|
|
if (!SessionData.wallpaperPath)
|
|
return;
|
|
cycleToPrevWallpaper();
|
|
resetScheduleAfterManual();
|
|
}
|
|
|
|
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 applyCycledWallpaper(text, currentPath, targetScreenName, goToPrevious) {
|
|
if (!text || !text.trim())
|
|
return;
|
|
const files = text.trim().split('\n').filter(file => file.length > 0);
|
|
if (files.length <= 1)
|
|
return;
|
|
const wallpaperList = files.sort();
|
|
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)
|
|
return;
|
|
|
|
if (targetScreenName) {
|
|
SessionData.setMonitorWallpaper(targetScreenName, targetWallpaper);
|
|
} else {
|
|
SessionData.setWallpaper(targetWallpaper);
|
|
}
|
|
}
|
|
|
|
Component {
|
|
id: monitorProcessComponent
|
|
Process {
|
|
property string targetScreenName: ""
|
|
property string currentWallpaper: ""
|
|
property bool goToPrevious: false
|
|
running: false
|
|
stdout: StdioCollector {
|
|
onStreamFinished: root.applyCycledWallpaper(text, currentWallpaper, targetScreenName, goToPrevious)
|
|
}
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: cyclingProcess
|
|
property string targetScreenName: ""
|
|
property string currentWallpaper: ""
|
|
property bool goToPrevious: false
|
|
running: false
|
|
stdout: StdioCollector {
|
|
onStreamFinished: root.applyCycledWallpaper(text, cyclingProcess.currentWallpaper, cyclingProcess.targetScreenName, cyclingProcess.goToPrevious)
|
|
}
|
|
}
|
|
|
|
Process {
|
|
id: prevCyclingProcess
|
|
property string targetScreenName: ""
|
|
property string currentWallpaper: ""
|
|
property bool goToPrevious: true
|
|
running: false
|
|
stdout: StdioCollector {
|
|
onStreamFinished: root.applyCycledWallpaper(text, prevCyclingProcess.currentWallpaper, prevCyclingProcess.targetScreenName, prevCyclingProcess.goToPrevious)
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: SessionData
|
|
|
|
function onLoaded() {
|
|
root.updateCyclingState();
|
|
}
|
|
}
|
|
|
|
IpcHandler {
|
|
target: "wallpaper"
|
|
|
|
function get(): string {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
return "ERROR: Per-monitor mode enabled. Use getFor(screenName) instead.";
|
|
}
|
|
return SessionData.wallpaperPath || "";
|
|
}
|
|
|
|
function set(path: string): string {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
return "ERROR: Per-monitor mode enabled. Use setFor(screenName, path) instead.";
|
|
}
|
|
|
|
if (!path) {
|
|
return "ERROR: No path provided";
|
|
}
|
|
|
|
var absolutePath = path.startsWith("/") ? path : StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/" + path;
|
|
|
|
try {
|
|
SessionData.setWallpaper(absolutePath);
|
|
return "SUCCESS: Wallpaper set to " + absolutePath;
|
|
} catch (e) {
|
|
return "ERROR: Failed to set wallpaper: " + e.toString();
|
|
}
|
|
}
|
|
|
|
function clear(): string {
|
|
SessionData.setWallpaper("");
|
|
SessionData.setPerMonitorWallpaper(false);
|
|
SessionData.monitorWallpapers = {};
|
|
SessionData.saveSettings();
|
|
return "SUCCESS: All wallpapers cleared";
|
|
}
|
|
|
|
function next(): string {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
return "ERROR: Per-monitor mode enabled. Use nextFor(screenName) instead.";
|
|
}
|
|
|
|
if (!SessionData.wallpaperPath) {
|
|
return "ERROR: No wallpaper set";
|
|
}
|
|
|
|
try {
|
|
root.cycleNextManually();
|
|
return "SUCCESS: Cycling to next wallpaper";
|
|
} catch (e) {
|
|
return "ERROR: Failed to cycle wallpaper: " + e.toString();
|
|
}
|
|
}
|
|
|
|
function prev(): string {
|
|
if (SessionData.perMonitorWallpaper) {
|
|
return "ERROR: Per-monitor mode enabled. Use prevFor(screenName) instead.";
|
|
}
|
|
|
|
if (!SessionData.wallpaperPath) {
|
|
return "ERROR: No wallpaper set";
|
|
}
|
|
|
|
try {
|
|
root.cyclePrevManually();
|
|
return "SUCCESS: Cycling to previous wallpaper";
|
|
} catch (e) {
|
|
return "ERROR: Failed to cycle wallpaper: " + e.toString();
|
|
}
|
|
}
|
|
|
|
function getFor(screenName: string): string {
|
|
if (!screenName) {
|
|
return "ERROR: No screen name provided";
|
|
}
|
|
return SessionData.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 (!SessionData.perMonitorWallpaper) {
|
|
SessionData.setPerMonitorWallpaper(true);
|
|
}
|
|
SessionData.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 = SessionData.getMonitorWallpaper(screenName);
|
|
if (!currentWallpaper) {
|
|
return "ERROR: No wallpaper set for " + screenName;
|
|
}
|
|
|
|
try {
|
|
root.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 = SessionData.getMonitorWallpaper(screenName);
|
|
if (!currentWallpaper) {
|
|
return "ERROR: No wallpaper set for " + screenName;
|
|
}
|
|
|
|
try {
|
|
root.cyclePrevForMonitor(screenName);
|
|
return "SUCCESS: Cycling to previous wallpaper for " + screenName;
|
|
} catch (e) {
|
|
return "ERROR: Failed to cycle wallpaper for " + screenName + ": " + e.toString();
|
|
}
|
|
}
|
|
}
|
|
}
|