diff --git a/quickshell/Modules/DankBar/Widgets/Media.qml b/quickshell/Modules/DankBar/Widgets/Media.qml index 3a8f06261..13301edc9 100644 --- a/quickshell/Modules/DankBar/Widgets/Media.qml +++ b/quickshell/Modules/DankBar/Widgets/Media.qml @@ -317,9 +317,45 @@ BasePill { id: mediaText readonly property bool onScreen: Window.window?.visible ?? false property bool needsScrolling: implicitWidth > textContainer.width && SettingsData.scrollTitleEnabled + readonly property bool scrollActive: needsScrolling && textContainer.visible && onScreen && root._isPlaying + readonly property real maxScrollOffset: Math.max(0, implicitWidth - textContainer.width + 5) property real scrollOffset: 0 + property int scrollDirection: 1 + property real scrollHoldMs: 2000 property real textShift: 0 + function resetScroll() { + scrollOffset = 0; + scrollDirection = 1; + scrollHoldMs = 2000; + } + + function stepScroll(deltaMs) { + if (scrollHoldMs > 0) { + scrollHoldMs -= deltaMs; + return; + } + const next = scrollOffset + scrollDirection * deltaMs / 60; + if (next >= maxScrollOffset) { + scrollOffset = maxScrollOffset; + scrollDirection = -1; + scrollHoldMs = 2000; + return; + } + if (next <= 0) { + scrollOffset = 0; + scrollDirection = 1; + scrollHoldMs = 2000; + return; + } + scrollOffset = next; + } + + onScrollActiveChanged: { + if (!scrollActive) + resetScroll(); + } + anchors.verticalCenter: parent.verticalCenter text: textContainer.displayText font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale, root.barConfig?.maximizeWidgetText) @@ -329,52 +365,38 @@ BasePill { opacity: 1 onTextChanged: { - scrollOffset = 0; + resetScroll(); textShift = 0; - scrollTimer.reset(); textChangeAnimation.restart(); } - // Timer stepping, not NumberAnimation — a running animation commits frames every vsync (#2863) + // Timer stepping, not NumberAnimation — a running animation commits frames every vsync (#2863). + // When cava frames are already driving renders, scroll steps ride those ticks instead — + // two unsynchronized tick sources nearly double the surface commit rate (#2863). Timer { id: scrollTimer - readonly property real maxOffset: Math.max(0, mediaText.implicitWidth - textContainer.width + 5) - property int direction: 1 - property int holdTicks: 33 interval: 60 repeat: true - running: mediaText.needsScrolling && textContainer.visible && mediaText.onScreen && root._isPlaying - - function reset() { - mediaText.scrollOffset = 0; - direction = 1; - holdTicks = 33; - } - - onRunningChanged: { - if (!running) - reset(); - } + running: mediaText.scrollActive onTriggered: { - if (holdTicks > 0) { - holdTicks--; + if (cavaTickWatch.running) return; - } - const next = mediaText.scrollOffset + direction; - if (next >= maxOffset) { - mediaText.scrollOffset = maxOffset; - direction = -1; - holdTicks = 33; - return; - } - if (next <= 0) { - mediaText.scrollOffset = 0; - direction = 1; - holdTicks = 33; - return; - } - mediaText.scrollOffset = next; + mediaText.stepScroll(60); + } + } + + Timer { + id: cavaTickWatch + interval: 150 + } + + Connections { + target: CavaService + enabled: mediaText.scrollActive && SettingsData.audioVisualizerEnabled && CavaService.cavaAvailable + function onValuesChanged() { + cavaTickWatch.restart(); + mediaText.stepScroll(40); } }