feat(qt): two Wallpaper background modes, with the desktop's picture or your own

"Dynamic background" gains "Wallpaper" and "Wallpaper, blurred". The
picture is the desktop's wallpaper — Plasma's appletsrc (the containment
on screen 0, image plugin only; a wallpaper package resolves to its
largest bitmap, a slideshow folder to its first image), GNOME through
gsettings (the dark variant under a dark scheme), Windows' current
TranscodedWallpaper, macOS through System Events — or an image the user
picks (Settings > Appearance > Background image), which outranks it. The
resolved path and its mtime are memoised, so the frequent refreshes
(session entry, a mode switch, the window coming to the front) republish
nothing while the file holds.

"Wallpaper, blurred" sends the picture through the same atmosphere pass
Blurred art gives the cover, held still. "Wallpaper" shows the part of
the wallpaper that lies behind the window, lightly blurred under the
half-alpha chrome, at most a screen-sized texture: the window's place on
the screen comes from Qt where the platform tells it (X11, macOS,
Windows); Wayland hides window positions, so there the crop is centred
until the Plasma window-management protocol is wired. Neither mode waits
for a playing track. Six new strings in eight catalogs.

cc
This commit is contained in:
vicrodh committed 2026-09-14 01:54:57 -06:00
1 parent 7167866286
commit 47b5c14d32
18 files changed
+825 -3

No files matched your search

+49
View File
@@ -121,6 +121,55 @@ Rectangle {
opacity: root.veilStrength
}
// Mode 3 — Wallpaper: the desktop wallpaper, the part of it that lies
// BEHIND this window (where the platform tells the window its place:
// X11, macOS, Windows — Wayland hides it, so a centred crop stands in),
// lightly blurred under the half-alpha chrome. Static: it costs a frame
// only when the window moves or resizes (shell/WallpaperField.qml).
// Mode 4 — Wallpaper, blurred: the wallpaper through the SAME atmosphere
// pass Blurred art gives the cover, held still (no transport to follow).
// Neither waits for a playing track (QbzTheme.ambientOn).
readonly property bool wallpaperModeOn: root.ambientOn && QbzShell.ambientMode === 3
readonly property bool wallpaperBlurOn: root.ambientOn && QbzShell.ambientMode === 4
WallpaperField {
anchors.fill: parent
visible: root.wallpaperModeOn
source: root.wallpaperModeOn ? QbzShell.wallpaperUrl : ""
hostWindow: root.hostWindow
blur: 0.35
dim: theme.isDark ? QbzShell.ambientDim : 0.0
}
Rectangle {
anchors.fill: parent
visible: root.wallpaperModeOn && !theme.isDark
color: theme.surfaceMain
opacity: root.veilStrength
}
ImmersiveAtmosphere {
anchors.fill: parent
visible: root.wallpaperBlurOn
source: root.wallpaperBlurOn ? QbzShell.wallpaperAtmosphereUrl : ""
animated: false
dim: theme.isDark ? QbzShell.ambientDim : 0.0
}
Rectangle {
anchors.fill: parent
visible: root.wallpaperBlurOn && !theme.isDark
color: theme.surfaceMain
opacity: root.veilStrength
}
// The wallpaper can change while QBZ runs: re-resolve when the window
// comes back to the front (wallpaper_qt memoises path + mtime, so a
// wallpaper that did not change republishes nothing).
Connections {
target: root.hostWindow
ignoreUnknownSignals: true
function onActiveChanged() {
if (root.hostWindow && root.hostWindow.active && QbzShell.ambientMode >= 3)
QbzShell.refreshWallpaper()
}
}
// The host ApplicationWindow (custom chrome: drag / maximize / resize).
property var hostWindow: null
@@ -0,0 +1,73 @@
// WallpaperField — the desktop wallpaper behind the window (2026-09-14): the
// part of it that lies UNDER this window, so moving the window slides the
// picture the way a translucent window would, lightly blurred beneath the
// half-alpha chrome. Nothing animates: it costs a frame only when the window
// moves or resizes, and a screen-sized texture at most (`sourceSize` caps the
// decode — a 3x-upscaled wallpaper never reaches the GPU whole).
//
// WHERE THE WINDOW IS. X11, macOS and Windows report the window's position;
// Wayland hides it from clients by design, so there the crop is centred on
// the screen until the Plasma window-management protocol is wired
// (wallpaper_qt.rs header). `hostWindow` is the ApplicationWindow.
import QtQuick
import QtQuick.Window
import QtQuick.Effects
Item {
id: root
/// file:// URL of the wallpaper (QbzShell.wallpaperUrl).
property string source: ""
property var hostWindow: null
/// MultiEffect blur amount, 0 = crisp.
property real blur: 0.0
/// Darkening on top (the dark-theme legibility veil).
property real dim: 0.0
clip: true
readonly property bool positionKnown: root.hostWindow !== null
&& Qt.platform.pluginName !== "wayland"
readonly property real screenW: Math.max(1, Screen.width)
readonly property real screenH: Math.max(1, Screen.height)
// The window's origin inside its screen; centred when unknown.
readonly property real offX: root.positionKnown
? root.hostWindow.x - Screen.virtualX
: Math.max(0, (root.screenW - root.width) / 2)
readonly property real offY: root.positionKnown
? root.hostWindow.y - Screen.virtualY
: Math.max(0, (root.screenH - root.height) / 2)
Image {
id: picture
source: root.source
x: -root.offX
y: -root.offY
width: root.screenW
height: root.screenH
fillMode: Image.PreserveAspectCrop
asynchronous: true
cache: false
sourceSize.width: Math.round(root.screenW * Screen.devicePixelRatio)
sourceSize.height: Math.round(root.screenH * Screen.devicePixelRatio)
smooth: true
}
MultiEffect {
visible: root.blur > 0 && picture.status === Image.Ready
source: picture
x: picture.x
y: picture.y
width: picture.width
height: picture.height
autoPaddingEnabled: false
blurEnabled: true
blur: root.blur
blurMax: 48
}
Rectangle {
anchors.fill: parent
color: "#000000"
opacity: root.dim
}
}