Skip to content

Commit 09d1c65

Browse files
bitbloxhubpi with GPT-5.3-Codex
andcommitted
feat(lockscreen): add lockscreen-specific wallpaper target in unified wallpaper selector
Fixes #1641 Written mostly by an LLM since I don't know QML, works fine from my testing however. Currently there seems to be a 1-2s delay before loading the image with a custom lockscreen wallpaper set when locking, if anyone has any idea why or how to fix, please help! - add lockscreen wallpaper light/dark settings and service APIs - expose desktop vs lockscreen target tabs in Wallpaper panel - fallback to desktop wallpaper when lockscreen wallpaper unset - allow selector access when wallpaper management disabled via lockscreen override toggle Co-authored-by: pi with GPT-5.3-Codex <pi-gpt-5.3-codex@codex.local>
1 parent 6773c47 commit 09d1c65

11 files changed

Lines changed: 207 additions & 27 deletions

File tree

Assets/Translations/en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1438,6 +1438,8 @@
14381438
"compact-lockscreen-label": "Compact lock screen",
14391439
"enable-lockscreen-media-controls-description": "Show interactive media playback controls on the lock screen.",
14401440
"enable-lockscreen-media-controls-label": "Lock screen media controls",
1441+
"enable-lock-screen-wallpaper-description": "When desktop wallpaper management is disabled, keep lock screen wallpaper rendering enabled.",
1442+
"enable-lock-screen-wallpaper-label": "Enable lock screen wallpaper",
14411443
"lock-on-suspend-description": "Automatically lock the screen when suspending the system.",
14421444
"lock-on-suspend-label": "Lock on suspend",
14431445
"lock-screen-animations-description": "Enable or disable lockscreen animations.",
@@ -2082,6 +2084,8 @@
20822084
"apikey-placeholder": "Enter your Wallhaven API Key",
20832085
"appearance-dark-tab": "Dark",
20842086
"appearance-light-tab": "Light",
2087+
"target-desktop-tab": "Desktop",
2088+
"target-lock-screen-tab": "Lock screen",
20852089
"categories-anime": "Anime",
20862090
"categories-label": "Categories",
20872091
"categories-people": "People",

Assets/settings-default.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@
192192
},
193193
"wallpaper": {
194194
"enabled": true,
195+
"enableLockScreenWallpaper": false,
195196
"overviewEnabled": false,
196197
"directory": "",
197198
"monitorDirectories": [],
@@ -200,6 +201,8 @@
200201
"viewMode": "single",
201202
"setWallpaperOnAllMonitors": true,
202203
"linkLightAndDarkWallpapers": true,
204+
"lockScreenWallpaperLight": "",
205+
"lockScreenWallpaperDark": "",
203206
"fillMode": "crop",
204207
"fillColor": "#000000",
205208
"useSolidColor": false,

Assets/settings-search-index.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,6 +1709,18 @@
17091709
"!Settings.data.general.compactLockScreen"
17101710
]
17111711
},
1712+
{
1713+
"labelKey": "panels.lock-screen.enable-lock-screen-wallpaper-label",
1714+
"descriptionKey": "panels.lock-screen.enable-lock-screen-wallpaper-description",
1715+
"widget": "NToggle",
1716+
"tab": 11,
1717+
"tabLabel": "panels.lock-screen.title",
1718+
"subTab": 0,
1719+
"subTabLabel": "common.appearance",
1720+
"visibleWhen": [
1721+
"!Settings.data.wallpaper.enabled"
1722+
]
1723+
},
17121724
{
17131725
"labelKey": "panels.lock-screen.lock-screen-animations-label",
17141726
"descriptionKey": "panels.lock-screen.lock-screen-animations-description",

Commons/Settings.qml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ Singleton {
405405
// wallpaper
406406
property JsonObject wallpaper: JsonObject {
407407
property bool enabled: true
408+
property bool enableLockScreenWallpaper: false
408409
property bool overviewEnabled: false
409410
property string directory: ""
410411
property list<var> monitorDirectories: []
@@ -413,6 +414,8 @@ Singleton {
413414
property string viewMode: "single" // "single" | "recursive" | "browse"
414415
property bool setWallpaperOnAllMonitors: true
415416
property bool linkLightAndDarkWallpapers: true
417+
property string lockScreenWallpaperLight: ""
418+
property string lockScreenWallpaperDark: ""
416419
property string fillMode: "crop"
417420
property color fillColor: "#000000"
418421
property bool useSolidColor: false

Modules/Bar/Widgets/WallpaperSelector.qml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ NIconButton {
3232

3333
readonly property string iconColorKey: widgetSettings.iconColor !== undefined ? widgetSettings.iconColor : widgetMetadata.iconColor
3434

35-
enabled: Settings.data.wallpaper.enabled
35+
enabled: Settings.data.wallpaper.enabled || Settings.data.wallpaper.enableLockScreenWallpaper
3636
baseSize: Style.getCapsuleHeightForScreen(screen?.name)
3737
applyUiScale: false
3838
customRadius: Style.radiusL

Modules/LockScreen/LockScreenBackground.qml

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Item {
1313
// Cached wallpaper path - exposed for parent components
1414
property string resolvedWallpaperPath: ""
1515
property color tintColor: Settings.data.colorSchemes.darkMode ? Color.mSurface : Color.mOnSurface
16+
readonly property bool lockScreenWallpaperEnabled: Settings.data.wallpaper.enabled || Settings.data.wallpaper.enableLockScreenWallpaper
1617

1718
required property var screen
1819

@@ -43,6 +44,19 @@ Item {
4344
Qt.callLater(requestCachedWallpaper);
4445
}
4546
}
47+
function onLockScreenWallpaperChanged(path) {
48+
Qt.callLater(requestCachedWallpaper);
49+
}
50+
}
51+
52+
Connections {
53+
target: Settings.data.wallpaper
54+
function onEnabledChanged() {
55+
Qt.callLater(requestCachedWallpaper);
56+
}
57+
function onEnableLockScreenWallpaperChanged() {
58+
Qt.callLater(requestCachedWallpaper);
59+
}
4660
}
4761

4862
// Listen for display scale changes
@@ -60,13 +74,18 @@ Item {
6074
return;
6175
}
6276

77+
if (!lockScreenWallpaperEnabled) {
78+
resolvedWallpaperPath = "";
79+
return;
80+
}
81+
6382
// Check for solid color mode first
6483
if (Settings.data.wallpaper.useSolidColor) {
6584
resolvedWallpaperPath = "";
6685
return;
6786
}
6887

69-
const originalPath = WallpaperService.getWallpaper(screen.name) || "";
88+
const originalPath = WallpaperService.getLockScreenWallpaper(screen.name) || "";
7089
if (originalPath === "") {
7190
resolvedWallpaperPath = "";
7291
return;
@@ -91,14 +110,11 @@ Item {
91110
return;
92111
}
93112

94-
// Don't set resolvedWallpaperPath until cache is ready
95-
// This prevents loading the original huge image
113+
// Show original immediately, then swap to cached when ready
114+
resolvedWallpaperPath = originalPath
96115
ImageCacheService.getLarge(originalPath, targetWidth, targetHeight, function (cachedPath, success) {
97116
if (success) {
98117
resolvedWallpaperPath = cachedPath;
99-
} else {
100-
// Only fall back to original if caching failed
101-
resolvedWallpaperPath = originalPath;
102118
}
103119
});
104120
}
@@ -111,7 +127,7 @@ Item {
111127

112128
Image {
113129
id: lockBgImage
114-
visible: source !== "" && Settings.data.wallpaper.enabled && !Settings.data.wallpaper.useSolidColor && (!PowerProfileService.noctaliaPerformanceMode || !Settings.data.noctaliaPerformance.disableWallpaper)
130+
visible: source !== "" && lockScreenWallpaperEnabled && !Settings.data.wallpaper.useSolidColor && (!PowerProfileService.noctaliaPerformanceMode || !Settings.data.noctaliaPerformance.disableWallpaper)
115131
anchors.fill: parent
116132
fillMode: Image.PreserveAspectCrop
117133
source: resolvedWallpaperPath

Modules/Panels/ControlCenter/Widgets/WallpaperSelector.qml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import qs.Widgets
77
NIconButtonHot {
88
property ShellScreen screen
99

10-
enabled: Settings.data.wallpaper.enabled
10+
enabled: Settings.data.wallpaper.enabled || Settings.data.wallpaper.enableLockScreenWallpaper
1111
icon: "wallpaper-selector"
1212
tooltipText: I18n.tr("wallpaper.panel.title")
1313
onClicked: PanelService.getPanel("wallpaperPanel", screen)?.toggle()

Modules/Panels/Settings/Tabs/LockScreen/AppearanceSubTab.qml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ ColumnLayout {
8585
defaultValue: Settings.getDefaultValue("general.enableLockScreenMediaControls")
8686
}
8787

88+
NToggle {
89+
label: I18n.tr("panels.lock-screen.enable-lock-screen-wallpaper-label")
90+
description: I18n.tr("panels.lock-screen.enable-lock-screen-wallpaper-description")
91+
checked: Settings.data.wallpaper.enableLockScreenWallpaper
92+
onToggled: checked => Settings.data.wallpaper.enableLockScreenWallpaper = checked
93+
visible: !Settings.data.wallpaper.enabled
94+
defaultValue: Settings.getDefaultValue("wallpaper.enableLockScreenWallpaper")
95+
}
96+
8897
NToggle {
8998
label: I18n.tr("panels.lock-screen.lock-screen-animations-label")
9099
description: I18n.tr("panels.lock-screen.lock-screen-animations-description")

Modules/Panels/Settings/Tabs/Wallpaper/GeneralSubTab.qml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ ColumnLayout {
2626
}
2727

2828
ColumnLayout {
29-
enabled: Settings.data.wallpaper.enabled
29+
enabled: Settings.data.wallpaper.enabled || Settings.data.wallpaper.enableLockScreenWallpaper
3030
spacing: Style.marginL
3131
Layout.fillWidth: true
3232

Modules/Panels/Wallpaper/WallpaperPanel.qml

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -141,10 +141,10 @@ SmartPanel {
141141
property var currentScreen: Quickshell.screens[currentScreenIndex]
142142
property string filterText: ""
143143
property int appearanceTabIndex: 0
144+
property int wallpaperTargetTabIndex: 0 // 0 = desktop, 1 = lock screen
144145
readonly property bool headerScreensStripAvailable: !Settings.data.wallpaper.setWallpaperOnAllMonitors || Settings.data.wallpaper.enableMultiMonitorDirectories
145146
readonly property bool headerDevicesButtonVisible: Quickshell.screens.length > 1 || Settings.data.wallpaper.enableMultiMonitorDirectories
146147
property alias screenRepeater: screenRepeater
147-
148148
Component.onCompleted: {
149149
root.contentItem = panelContent;
150150
}
@@ -182,6 +182,13 @@ SmartPanel {
182182
}
183183
}
184184

185+
function getSelectedTargetWallpaper(screenName) {
186+
if (wallpaperTargetTabIndex === 1) {
187+
return WallpaperService.getLockScreenWallpaper(screenName);
188+
}
189+
return WallpaperService.getWallpaperPathForSlot(screenName, WallpaperService.wallpaperSelectionAppearance);
190+
}
191+
185192
color: "transparent"
186193

187194
// Wallhaven settings popup
@@ -222,6 +229,7 @@ SmartPanel {
222229
wallhavenView.gridView.currentIndex = -1;
223230
}
224231
panelContent.appearanceTabIndex = Settings.data.colorSchemes.darkMode ? 1 : 0;
232+
panelContent.wallpaperTargetTabIndex = (!Settings.data.wallpaper.enabled && Settings.data.wallpaper.enableLockScreenWallpaper) ? 1 : 0;
225233
WallpaperService.wallpaperSelectionAppearance = panelContent.appearanceTabIndex === 1 ? "dark" : "light";
226234
// Give initial focus to search input
227235
Qt.callLater(() => {
@@ -297,7 +305,7 @@ SmartPanel {
297305
}
298306

299307
NIconButton {
300-
visible: Settings.data.wallpaper.enabled
308+
visible: Settings.data.wallpaper.enabled || Settings.data.wallpaper.enableLockScreenWallpaper
301309
icon: "dark-mode"
302310
tooltipText: Settings.data.wallpaper.linkLightAndDarkWallpapers ? I18n.tr("wallpaper.panel.header-separate-light-dark-tooltip") : I18n.tr("wallpaper.panel.header-link-light-dark-tooltip")
303311
baseSize: Style.baseWidgetSize * 0.8
@@ -350,7 +358,7 @@ SmartPanel {
350358

351359
NTabBar {
352360
id: appearanceTabBar
353-
visible: Settings.data.wallpaper.enabled && !Settings.data.wallpaper.linkLightAndDarkWallpapers
361+
visible: (Settings.data.wallpaper.enabled || Settings.data.wallpaper.enableLockScreenWallpaper) && !Settings.data.wallpaper.linkLightAndDarkWallpapers
354362
Layout.fillWidth: true
355363
currentIndex: panelContent.appearanceTabIndex
356364
spacing: Style.marginM
@@ -377,6 +385,39 @@ SmartPanel {
377385
}
378386
}
379387

388+
NTabBar {
389+
id: wallpaperTargetTabBar
390+
visible: Settings.data.wallpaper.enabled || Settings.data.wallpaper.enableLockScreenWallpaper
391+
Layout.fillWidth: true
392+
currentIndex: panelContent.wallpaperTargetTabIndex
393+
spacing: Style.marginM
394+
distributeEvenly: true
395+
396+
onCurrentIndexChanged: {
397+
if (currentIndex < 0) {
398+
return;
399+
}
400+
panelContent.wallpaperTargetTabIndex = currentIndex;
401+
for (var i = 0; i < screenRepeater.count; i++) {
402+
let item = screenRepeater.itemAt(i);
403+
if (item && item.refreshWallpaperScreenData) {
404+
item.refreshWallpaperScreenData();
405+
}
406+
}
407+
}
408+
409+
NTabButton {
410+
text: I18n.tr("wallpaper.panel.target-desktop-tab")
411+
tabIndex: 0
412+
checked: wallpaperTargetTabBar.currentIndex === 0
413+
}
414+
NTabButton {
415+
text: I18n.tr("wallpaper.panel.target-lock-screen-tab")
416+
tabIndex: 1
417+
checked: wallpaperTargetTabBar.currentIndex === 1
418+
}
419+
}
420+
380421
NTabBar {
381422
id: screenTabBar
382423
visible: panelContent.headerScreensStripAvailable
@@ -829,12 +870,17 @@ SmartPanel {
829870
target: WallpaperService
830871
function onWallpaperChanged(screenName, path) {
831872
if (targetScreen !== null && screenName === targetScreen.name) {
832-
currentWallpaper = WallpaperService.getWallpaperPathForSlot(targetScreen.name, WallpaperService.wallpaperSelectionAppearance);
873+
currentWallpaper = panelContent.getSelectedTargetWallpaper(targetScreen.name);
874+
}
875+
}
876+
function onLockScreenWallpaperChanged(path) {
877+
if (targetScreen !== null) {
878+
currentWallpaper = panelContent.getSelectedTargetWallpaper(targetScreen.name);
833879
}
834880
}
835881
function onWallpaperSelectionAppearanceChanged() {
836882
if (targetScreen !== null) {
837-
currentWallpaper = WallpaperService.getWallpaperPathForSlot(targetScreen.name, WallpaperService.wallpaperSelectionAppearance);
883+
currentWallpaper = panelContent.getSelectedTargetWallpaper(targetScreen.name);
838884
updateFiltered(false);
839885
}
840886
}
@@ -869,7 +915,7 @@ SmartPanel {
869915
return;
870916
}
871917

872-
currentWallpaper = WallpaperService.getWallpaperPathForSlot(targetScreen.name, WallpaperService.wallpaperSelectionAppearance);
918+
currentWallpaper = panelContent.getSelectedTargetWallpaper(targetScreen.name);
873919

874920
if (isBrowseMode) {
875921
// In browse mode, scan current directory for both files and directories
@@ -899,12 +945,15 @@ SmartPanel {
899945
if (isDirectory) {
900946
WallpaperService.setBrowsePath(targetScreen.name, path);
901947
} else {
902-
var screen = Settings.data.wallpaper.setWallpaperOnAllMonitors ? undefined : targetScreen.name;
903-
WallpaperService.changeWallpaper(path, screen, WallpaperService.wallpaperSelectionAppearance);
904-
WallpaperService.applyFavoriteTheme(path, screen, WallpaperService.wallpaperSelectionAppearance);
948+
if (panelContent.wallpaperTargetTabIndex === 1) {
949+
WallpaperService.changeLockScreenWallpaper(path, WallpaperService.wallpaperSelectionAppearance);
950+
} else {
951+
var screen = Settings.data.wallpaper.setWallpaperOnAllMonitors ? undefined : targetScreen.name;
952+
WallpaperService.changeWallpaper(path, screen, WallpaperService.wallpaperSelectionAppearance);
953+
WallpaperService.applyFavoriteTheme(path, screen, WallpaperService.wallpaperSelectionAppearance);
954+
}
905955
}
906956
}
907-
908957
// Helper function to cycle view modes
909958
function cycleViewMode() {
910959
var mode = Settings.data.wallpaper.viewMode;
@@ -1922,13 +1971,17 @@ SmartPanel {
19221971
if (typeof WallhavenService !== "undefined") {
19231972
WallhavenService.downloadWallpaper(wallpaper, function (success, localPath) {
19241973
if (success) {
1925-
var whScreen = Settings.data.wallpaper.setWallpaperOnAllMonitors ? undefined : Quickshell.screens[currentScreenIndex].name;
1926-
if (!Settings.data.wallpaper.setWallpaperOnAllMonitors && currentScreenIndex < Quickshell.screens.length) {
1927-
WallpaperService.changeWallpaper(localPath, Quickshell.screens[currentScreenIndex].name, WallpaperService.wallpaperSelectionAppearance);
1974+
if (panelContent.wallpaperTargetTabIndex === 1) {
1975+
WallpaperService.changeLockScreenWallpaper(localPath, WallpaperService.wallpaperSelectionAppearance);
19281976
} else {
1929-
WallpaperService.changeWallpaper(localPath, undefined, WallpaperService.wallpaperSelectionAppearance);
1977+
var whScreen = Settings.data.wallpaper.setWallpaperOnAllMonitors ? undefined : Quickshell.screens[currentScreenIndex].name;
1978+
if (!Settings.data.wallpaper.setWallpaperOnAllMonitors && currentScreenIndex < Quickshell.screens.length) {
1979+
WallpaperService.changeWallpaper(localPath, Quickshell.screens[currentScreenIndex].name, WallpaperService.wallpaperSelectionAppearance);
1980+
} else {
1981+
WallpaperService.changeWallpaper(localPath, undefined, WallpaperService.wallpaperSelectionAppearance);
1982+
}
1983+
WallpaperService.applyFavoriteTheme(localPath, whScreen, WallpaperService.wallpaperSelectionAppearance);
19301984
}
1931-
WallpaperService.applyFavoriteTheme(localPath, whScreen, WallpaperService.wallpaperSelectionAppearance);
19321985
}
19331986
});
19341987
}

0 commit comments

Comments
 (0)