Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions assets/systemd/dms.service
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Requisite=graphical-session.target
[Service]
Type=dbus
BusName=org.freedesktop.Notifications
# Use elapsed-time animation driver for high refresh rate support (240Hz+)
Environment=QSG_USE_SIMPLE_ANIMATION_DRIVER=1
ExecStart=/usr/bin/dms run --session
ExecReload=/usr/bin/pkill -USR1 -x dms
Restart=on-failure
Expand Down
10 changes: 10 additions & 0 deletions core/cmd/dms/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,11 @@ func runShellInteractive(session bool) {
if os.Getenv("QT_QPA_PLATFORM") == "" {
cmd.Env = append(cmd.Env, "QT_QPA_PLATFORM=wayland;xcb")
}
// Use elapsed-time animation driver for high refresh rate support (240Hz+)
// Without this, Qt's vsync-based animation driver locks FrameAnimation to 60Hz
if os.Getenv("QSG_USE_SIMPLE_ANIMATION_DRIVER") == "" {
cmd.Env = append(cmd.Env, "QSG_USE_SIMPLE_ANIMATION_DRIVER=1")
}

cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
Expand Down Expand Up @@ -452,6 +457,11 @@ func runShellDaemon(session bool) {
if os.Getenv("QT_QPA_PLATFORM") == "" {
cmd.Env = append(cmd.Env, "QT_QPA_PLATFORM=wayland;xcb")
}
// Use elapsed-time animation driver for high refresh rate support (240Hz+)
// Without this, Qt's vsync-based animation driver locks FrameAnimation to 60Hz
if os.Getenv("QSG_USE_SIMPLE_ANIMATION_DRIVER") == "" {
cmd.Env = append(cmd.Env, "QSG_USE_SIMPLE_ANIMATION_DRIVER=1")
}

devNull, err := os.OpenFile("/dev/null", os.O_RDWR, 0)
if err != nil {
Expand Down
20 changes: 20 additions & 0 deletions quickshell/Common/SessionData.qml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,26 @@ Singleton {
property var monitorWallpapersLight: ({})
property var monitorWallpapersDark: ({})
property var monitorWallpaperFillModes: ({})

// Map: screenName -> { scrollX, scrollY } (0-100 range, like workspace percentage)
property var monitorScrollPositions: ({})

function setMonitorScrollPosition(screenName, scrollX, scrollY) {
var newPositions = Object.assign({}, monitorScrollPositions);
newPositions[screenName] = { scrollX: scrollX, scrollY: scrollY };
monitorScrollPositions = newPositions;
}

function getMonitorScrollPosition(screenName) {
return monitorScrollPositions[screenName] || { scrollX: 50, scrollY: 50 };
}

function clearMonitorScrollPosition(screenName) {
var newPositions = Object.assign({}, monitorScrollPositions);
delete newPositions[screenName];
monitorScrollPositions = newPositions;
}

property string wallpaperTransition: "fade"
readonly property var availableWallpaperTransitions: ["none", "fade", "wipe", "disc", "stripes", "iris bloom", "pixelate", "portal"]
property var includedTransitions: availableWallpaperTransitions.filter(t => t !== "none")
Expand Down
17 changes: 17 additions & 0 deletions quickshell/Common/Theme.qml
Original file line number Diff line number Diff line change
Expand Up @@ -1618,6 +1618,23 @@ Singleton {
}
}

// Returns numeric fillMode value for shader use (matches shader calculateUV logic)
function getShaderFillMode(modeName) {
switch (modeName) {
case "Stretch": return 0;
case "Fit":
case "PreserveAspectFit": return 1;
case "Fill":
case "PreserveAspectCrop": return 2;
case "Tile": return 3;
case "TileVertically": return 4;
case "TileHorizontally": return 5;
case "Pad": return 6;
case "Scrolling": return 7;
default: return 2;
}
}

function snap(value, dpr) {
const s = dpr || 1;
return Math.round(value * s) / s;
Expand Down
42 changes: 36 additions & 6 deletions quickshell/Modules/Lock/LockScreenContent.qml
Original file line number Diff line number Diff line change
Expand Up @@ -159,20 +159,50 @@ Item {
}

Image {
id: wallpaperBackground

id: wallpaperSource
visible: false
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
}

ShaderEffectSource {
id: srcWallpaper
sourceItem: wallpaperSource
hideSource: true
live: false
}

ShaderEffect {
id: wallpaperBackground
anchors.fill: parent
visible: wallpaperSource.source !== ""

property variant source1: srcWallpaper
property variant source2: srcWallpaper // Same source for lock screen (no transition)
property real progress: 0.0

readonly property string fillModeName: SessionData.getMonitorWallpaperFillMode(screenName)
readonly property var scrollPos: SessionData.getMonitorScrollPosition(screenName)

property real fillMode: Theme.getShaderFillMode(fillModeName)
property real scrollX: scrollPos.scrollX
property real scrollY: scrollPos.scrollY
property real imageWidth1: wallpaperSource.implicitWidth > 0 ? wallpaperSource.implicitWidth : 1
property real imageHeight1: wallpaperSource.implicitHeight > 0 ? wallpaperSource.implicitHeight : 1
property real imageWidth2: wallpaperSource.implicitWidth > 0 ? wallpaperSource.implicitWidth : 1
property real imageHeight2: wallpaperSource.implicitHeight > 0 ? wallpaperSource.implicitHeight : 1
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")

layer.enabled: true
layer.effect: MultiEffect {
autoPaddingEnabled: false
blurEnabled: true
Expand Down
4 changes: 2 additions & 2 deletions quickshell/Modules/Settings/WallpaperTab.qml
Original file line number Diff line number Diff line change
Expand Up @@ -307,9 +307,9 @@ Item {

DankButtonGroup {
id: fillModeGroup
property var internalModes: ["Stretch", "Fit", "Fill", "Tile", "TileVertically", "TileHorizontally", "Pad"]
property var internalModes: ["Stretch", "Fit", "Fill", "Scrolling", "Tile", "TileVertically", "TileHorizontally", "Pad"]
anchors.horizontalCenter: parent.horizontalCenter
model: [I18n.tr("Stretch", "wallpaper fill mode"), I18n.tr("Fit", "wallpaper fill mode"), I18n.tr("Fill", "wallpaper fill mode"), I18n.tr("Tile", "wallpaper fill mode"), I18n.tr("Tile V", "wallpaper fill mode"), I18n.tr("Tile H", "wallpaper fill mode"), I18n.tr("Pad", "wallpaper fill mode")]
model: [I18n.tr("Stretch", "wallpaper fill mode"), I18n.tr("Fit", "wallpaper fill mode"), I18n.tr("Fill", "wallpaper fill mode"), I18n.tr("Scroll", "wallpaper fill mode"), I18n.tr("Tile", "wallpaper fill mode"), I18n.tr("Tile V", "wallpaper fill mode"), I18n.tr("Tile H", "wallpaper fill mode"), I18n.tr("Pad", "wallpaper fill mode")]
selectionMode: "single"
buttonHeight: 28
minButtonWidth: 48
Expand Down
Loading
Loading