diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-29 12:55:16 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-29 12:55:16 +0200 |
| commit | 700f4be432e2c0f54fd6708b6a085b1fb9dd6108 (patch) | |
| tree | cc58fc6caaf5c779c0b61094f6369a0eae2141d0 | |
| parent | 401cacb17fa2a5c756340be90d9a0b2c9c2e4a63 (diff) | |
| download | quickshell-700f4be432e2c0f54fd6708b6a085b1fb9dd6108.tar.gz quickshell-700f4be432e2c0f54fd6708b6a085b1fb9dd6108.zip | |
feat(sound): album art as the OSD background
When the current track has art, the volume OSD now draws it across the
whole panel, blurred (MultiEffect blur 0.5, default blurMax) and masked
to the panel's rounded corners, since clip only cuts to the bounding box.
The thumbnail in the track row stays sharp on top.
A dark scrim (Theme.base at 0.82) sits over the art. The palette is dark
and the text light, so a light cover made the panel unreadable, and more
blur did not fix that; only darkening did. The scrim is a sibling of the
MultiEffect, not a child: nested inside it, it did not paint at all, which
is why raising its alpha first appeared to change nothing.
Without art the panel keeps its translucent, compositor-frosted look.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | desktop/modules/sound/Osd.qml | 50 | ||||
| -rw-r--r-- | desktop/modules/sound/README.md | 6 |
2 files changed, 56 insertions, 0 deletions
diff --git a/desktop/modules/sound/Osd.qml b/desktop/modules/sound/Osd.qml index 4a5e4a2..2894d35 100644 --- a/desktop/modules/sound/Osd.qml +++ b/desktop/modules/sound/Osd.qml @@ -13,6 +13,7 @@ import Quickshell import Quickshell.Wayland import Quickshell.Services.Pipewire import QtQuick +import QtQuick.Effects import "../.." // The transient on-screen display. Unchanged in behaviour from volume-osd, @@ -82,6 +83,55 @@ Scope { border.width: 1 border.color: Qt.alpha(Theme.text, 0.12) + // Album art as the whole background, lightly blurred, when the + // player has any. It is opaque, so it hides the compositor's + // frosting; without art the panel keeps the translucent look. + // Inset by the border width so the border stays visible. + Image { + id: bgArt + anchors.fill: parent + anchors.margins: 1 + source: Player.active ? Player.artUrl : "" + cache: false + asynchronous: true + fillMode: Image.PreserveAspectCrop + visible: false + } + + // clip only cuts to the bounding box, so the corners come from a + // mask the size of the art with the panel's radius. + Rectangle { + id: bgMask + anchors.fill: bgArt + radius: parent.radius - 1 + layer.enabled: true + visible: false + } + + MultiEffect { + id: bgEffect + anchors.fill: bgArt + visible: bgArt.status === Image.Ready && bgArt.source != "" + source: bgArt + autoPaddingEnabled: false + blurEnabled: true + blur: 0.5 + maskEnabled: true + maskSource: bgMask + maskThresholdMin: 0.5 + maskSpreadAtMin: 1.0 + } + + // Keeps text and the accent bar legible on a bright cover. A + // sibling, not a child: nested inside the MultiEffect it did not + // paint, and a light cover showed through at full brightness. + Rectangle { + anchors.fill: bgArt + visible: bgEffect.visible + radius: bgMask.radius + color: Qt.alpha(Theme.base, 0.82) + } + HoverHandler { onHoveredChanged: root.hovered = hovered } diff --git a/desktop/modules/sound/README.md b/desktop/modules/sound/README.md index 72db235..d92d017 100644 --- a/desktop/modules/sound/README.md +++ b/desktop/modules/sound/README.md @@ -40,6 +40,12 @@ art, title, artist, and prev/play/next. With no player the panel is exactly the volume OSD, at its original size. A track change or a play/pause shows the panel too, so the row is not something you only see by touching the volume. +When the track has art, it also fills the whole panel as a blurred background +under a dark scrim (`Theme.base` at 0.82), and the thumbnail stays sharp in +the row. The palette is dark, so the scrim is what keeps text legible on a +light cover; blur alone did not. The art is opaque, so it hides the +compositor's frosting while it shows. Without art the panel is unchanged. + Hovering the panel freezes its fade so the buttons can be clicked; moving away starts the countdown again. Without a hover it behaves exactly as it did before there was anything clickable on it. It still takes no keyboard focus. |
