mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-24 20:15:21 -04:00
shader-based scrolling wallpaper mode (#1802)
* feat: parallax-scroll wallpaper Add a `Scrolling` wallpaper fill mode that translates the wallpaper crop with the active workspace — like Android home-screen parallax, but along niri's vertical workspace axis. The image is scaled to cover the screen on its non-scroll axis, and the active workspace index drives a fractional offset into the cropped overflow along the scroll axis. Scroll position is spring-animated CPU-side and handed to a minimal single-texture shader as a UV offset. Per-monitor scroll position is published into SessionData so the lock screen renders the same crop as the active workspace, keeping visual continuity across lock/unlock. Two implementation details worth calling out for review: - QSG_USE_SIMPLE_ANIMATION_DRIVER=1 is exported to the spawned quickshell process. The default animation driver advances in fixed ~16ms steps, capping the scroll at 60Hz and desyncing it from compositor motion on high-refresh displays; the simple driver advances by real elapsed time, restoring native-refresh pacing. Removing it visibly regresses to 60Hz. - The wallpaper survives wl_output rebind cycles (e.g. OLED image-cleaning on DPMS soft-off), which otherwise leave a stuck or void background. Recovery re-anchors the scroll target on output-lifecycle signals, rebuilds the ShaderEffect against the current render context, and re-attaches the wallpaper-layer surface on unlock for parallax-active monitors — guarded against lock state so the shader gets reliable frame hints. * simplify bindings and gate lock screen shader in a loader --------- Co-authored-by: bbedward <bbedward@gmail.com>
This commit is contained in:
@@ -200,21 +200,22 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
Loader {
|
||||
id: wallpaperBackground
|
||||
|
||||
anchors.fill: parent
|
||||
source: {
|
||||
var currentWallpaper = SessionData.getMonitorWallpaper(screenName);
|
||||
return (currentWallpaper && !currentWallpaper.startsWith("#")) ? encodeFileUrl(currentWallpaper) : "";
|
||||
}
|
||||
fillMode: Theme.getFillMode(SessionData.getMonitorWallpaperFillMode(screenName))
|
||||
smooth: true
|
||||
asynchronous: false
|
||||
cache: true
|
||||
visible: source !== ""
|
||||
layer.enabled: true
|
||||
|
||||
readonly property string wallpaperSource: {
|
||||
var w = SessionData.getMonitorWallpaper(screenName);
|
||||
return (w && !w.startsWith("#")) ? encodeFileUrl(w) : "";
|
||||
}
|
||||
readonly property string fillModeName: SessionData.getMonitorWallpaperFillMode(screenName)
|
||||
|
||||
active: wallpaperSource !== ""
|
||||
asynchronous: false
|
||||
|
||||
sourceComponent: fillModeName === "Scrolling" ? scrollWallpaperComp : plainWallpaperComp
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: MultiEffect {
|
||||
autoPaddingEnabled: false
|
||||
blurEnabled: true
|
||||
@@ -231,6 +232,60 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: plainWallpaperComp
|
||||
Image {
|
||||
source: wallpaperBackground.wallpaperSource
|
||||
fillMode: Theme.getFillMode(wallpaperBackground.fillModeName)
|
||||
smooth: true
|
||||
cache: true
|
||||
asynchronous: false
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: scrollWallpaperComp
|
||||
Item {
|
||||
Image {
|
||||
id: scrollSource
|
||||
anchors.fill: parent
|
||||
visible: false
|
||||
source: wallpaperBackground.wallpaperSource
|
||||
asynchronous: false
|
||||
cache: true
|
||||
}
|
||||
|
||||
ShaderEffectSource {
|
||||
id: scrollSrc
|
||||
sourceItem: scrollSource
|
||||
hideSource: true
|
||||
live: false
|
||||
}
|
||||
|
||||
ShaderEffect {
|
||||
anchors.fill: parent
|
||||
|
||||
readonly property var scrollPos: SessionData.getMonitorScrollPosition(screenName)
|
||||
|
||||
property variant source1: scrollSrc
|
||||
property variant source2: scrollSrc
|
||||
property real progress: 0.0
|
||||
property real fillMode: Theme.getShaderFillMode(wallpaperBackground.fillModeName)
|
||||
property real scrollX: scrollPos.scrollX
|
||||
property real scrollY: scrollPos.scrollY
|
||||
property real imageWidth1: scrollSource.implicitWidth > 0 ? scrollSource.implicitWidth : 1
|
||||
property real imageHeight1: scrollSource.implicitHeight > 0 ? scrollSource.implicitHeight : 1
|
||||
property real imageWidth2: imageWidth1
|
||||
property real imageHeight2: imageHeight1
|
||||
property real screenWidth: width > 0 ? width : 1
|
||||
property real screenHeight: height > 0 ? height : 1
|
||||
property vector4d fillColor: Qt.vector4d(0, 0, 0, 1)
|
||||
|
||||
fragmentShader: Qt.resolvedUrl("../../Shaders/qsb/wp_fade.frag.qsb")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "black"
|
||||
@@ -764,7 +819,7 @@ Item {
|
||||
property string text: root.passwordBuffer
|
||||
property int cursorPosition: text.length
|
||||
|
||||
signal accepted()
|
||||
signal accepted
|
||||
|
||||
function clampCursorPosition() {
|
||||
cursorPosition = Math.max(0, Math.min(cursorPosition, text.length));
|
||||
|
||||
Reference in New Issue
Block a user