From 3e8842caf3f401390d95a16dc8977aa0e5ef25f6 Mon Sep 17 00:00:00 2001 From: hthienloc Date: Sun, 26 Jul 2026 18:29:10 +0700 Subject: [PATCH] feat(wallpaper): support random cycling order --- quickshell/Common/SessionData.qml | 38 +++++++++++++++++++ quickshell/Common/settings/SessionSpec.js | 1 + quickshell/Modules/Settings/WallpaperTab.qml | 27 +++++++++++++ .../Services/WallpaperCyclingService.qml | 23 +++++++++-- .../translations/settings_search_index.json | 27 +++++++++++++ 5 files changed, 113 insertions(+), 3 deletions(-) diff --git a/quickshell/Common/SessionData.qml b/quickshell/Common/SessionData.qml index 66305fde3..640ca9e58 100644 --- a/quickshell/Common/SessionData.qml +++ b/quickshell/Common/SessionData.qml @@ -144,6 +144,7 @@ Singleton { property var includedTransitions: availableWallpaperTransitions.filter(t => t !== "none") property bool wallpaperCyclingEnabled: false + property bool wallpaperCyclingRandom: false property string wallpaperCyclingMode: "interval" property int wallpaperCyclingInterval: 300 property string wallpaperCyclingTime: "06:00" @@ -649,6 +650,11 @@ Singleton { saveSettings(); } + function setWallpaperCyclingRandom(random) { + wallpaperCyclingRandom = random; + saveSettings(); + } + function setWallpaperCyclingMode(mode) { wallpaperCyclingMode = mode; saveSettings(); @@ -695,6 +701,37 @@ Singleton { saveSettings(); } + function setMonitorCyclingRandom(screenName, random) { + 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) { + log.warn("Screen not found"); + return; + } + + var identifier = typeof SettingsData !== "undefined" ? SettingsData.getScreenDisplayName(screen) : screen.name; + + var newSettings = {}; + for (var key in monitorCyclingSettings) { + var isThisScreen = key === screen.name || (screen.model && key === screen.model); + if (!isThisScreen) { + newSettings[key] = monitorCyclingSettings[key]; + } + } + + newSettings[identifier] = getMonitorCyclingSettings(screenName); + newSettings[identifier].random = random; + monitorCyclingSettings = newSettings; + saveSettings(); + } + function setMonitorCyclingMode(screenName, mode) { var screen = null; var screens = Quickshell.screens; @@ -1376,6 +1413,7 @@ Singleton { function getMonitorCyclingSettings(screenName) { var defaults = { "enabled": false, + "random": false, "mode": "interval", "interval": 300, "time": "06:00" diff --git a/quickshell/Common/settings/SessionSpec.js b/quickshell/Common/settings/SessionSpec.js index 56617ff98..cdc86a027 100644 --- a/quickshell/Common/settings/SessionSpec.js +++ b/quickshell/Common/settings/SessionSpec.js @@ -19,6 +19,7 @@ var SPEC = { includedTransitions: { def: ["fade", "wipe", "disc", "stripes", "iris bloom", "pixelate", "portal"] }, wallpaperCyclingEnabled: { def: false }, + wallpaperCyclingRandom: { def: false }, wallpaperCyclingMode: { def: "interval" }, wallpaperCyclingInterval: { def: 300 }, wallpaperCyclingTime: { def: "06:00" }, diff --git a/quickshell/Modules/Settings/WallpaperTab.qml b/quickshell/Modules/Settings/WallpaperTab.qml index 5fb5271cb..c1c6c5893 100644 --- a/quickshell/Modules/Settings/WallpaperTab.qml +++ b/quickshell/Modules/Settings/WallpaperTab.qml @@ -977,6 +977,33 @@ Item { } } + SettingsToggleRow { + id: randomToggle + tab: "wallpaper" + tags: ["cycling", "automatic", "random", "shuffle"] + settingKey: "wallpaperCyclingRandom" + width: parent.width - Theme.spacingM * 2 + text: I18n.tr("Random Order") + description: I18n.tr("Select a random wallpaper instead of cycling in alphabetical order") + checked: SessionData.perMonitorWallpaper ? SessionData.getMonitorCyclingSettings(selectedMonitorName).random : SessionData.wallpaperCyclingRandom + onToggled: toggled => { + if (SessionData.perMonitorWallpaper) { + SessionData.setMonitorCyclingRandom(selectedMonitorName, toggled); + } else { + SessionData.setWallpaperCyclingRandom(toggled); + } + } + + Connections { + target: root + function onSelectedMonitorNameChanged() { + randomToggle.checked = Qt.binding(() => { + return SessionData.perMonitorWallpaper ? SessionData.getMonitorCyclingSettings(selectedMonitorName).random : SessionData.wallpaperCyclingRandom; + }); + } + } + } + SettingsDropdownRow { id: intervalDropdown property var intervalOptions: [I18n.tr("5 seconds", "wallpaper interval"), I18n.tr("10 seconds", "wallpaper interval"), I18n.tr("15 seconds", "wallpaper interval"), I18n.tr("20 seconds", "wallpaper interval"), I18n.tr("25 seconds", "wallpaper interval"), I18n.tr("30 seconds", "wallpaper interval"), I18n.tr("35 seconds", "wallpaper interval"), I18n.tr("40 seconds", "wallpaper interval"), I18n.tr("45 seconds", "wallpaper interval"), I18n.tr("50 seconds", "wallpaper interval"), I18n.tr("55 seconds", "wallpaper interval"), I18n.tr("1 minute", "wallpaper interval"), I18n.tr("5 minutes", "wallpaper interval"), I18n.tr("15 minutes", "wallpaper interval"), I18n.tr("30 minutes", "wallpaper interval"), I18n.tr("1 hour", "wallpaper interval"), I18n.tr("1 hour 30 minutes", "wallpaper interval"), I18n.tr("2 hours", "wallpaper interval"), I18n.tr("3 hours", "wallpaper interval"), I18n.tr("4 hours", "wallpaper interval"), I18n.tr("6 hours", "wallpaper interval"), I18n.tr("8 hours", "wallpaper interval"), I18n.tr("12 hours", "wallpaper interval")] diff --git a/quickshell/Services/WallpaperCyclingService.qml b/quickshell/Services/WallpaperCyclingService.qml index 2d58230a3..e551d371c 100644 --- a/quickshell/Services/WallpaperCyclingService.qml +++ b/quickshell/Services/WallpaperCyclingService.qml @@ -230,11 +230,28 @@ Singleton { if (currentIndex === -1) currentIndex = 0; + let isRandom = false; + if (targetScreenName) { + isRandom = !!SessionData.getMonitorCyclingSettings(targetScreenName).random; + } else { + isRandom = !!SessionData.wallpaperCyclingRandom; + } + let targetIndex; - if (goToPrevious) { - targetIndex = currentIndex === 0 ? wallpaperList.length - 1 : currentIndex - 1; + if (isRandom) { + if (wallpaperList.length > 1) { + do { + targetIndex = Math.floor(Math.random() * wallpaperList.length); + } while (targetIndex === currentIndex); + } else { + targetIndex = 0; + } } else { - targetIndex = (currentIndex + 1) % wallpaperList.length; + if (goToPrevious) { + targetIndex = currentIndex === 0 ? wallpaperList.length - 1 : currentIndex - 1; + } else { + targetIndex = (currentIndex + 1) % wallpaperList.length; + } } const targetWallpaper = wallpaperList[targetIndex]; if (!targetWallpaper || targetWallpaper === currentPath) diff --git a/quickshell/translations/settings_search_index.json b/quickshell/translations/settings_search_index.json index bd8cfec69..d18adfb02 100644 --- a/quickshell/translations/settings_search_index.json +++ b/quickshell/translations/settings_search_index.json @@ -338,6 +338,33 @@ ], "icon": "palette" }, + { + "section": "wallpaperCyclingRandom", + "label": "Random Order", + "tabIndex": 0, + "category": "Personalization", + "keywords": [ + "alphabetical", + "appearance", + "automatic", + "background", + "bg", + "custom", + "customize", + "cycling", + "desktop", + "image", + "order", + "personal", + "personalization", + "picture", + "random", + "select", + "shuffle", + "wallpaper" + ], + "description": "Select a random wallpaper instead of cycling in alphabetical order" + }, { "section": "wallpaperTransition", "label": "Transition Effect",