Show OSD and sync touchpad steps when scrolling bar widgets (audio, monitor) (#6421)
* Show OSD and sync touchpad steps when scrolling bar widgets Scrolling the volume or brightness icon in the bar changed the value directly without ever calling omarchy-osd, so only the keyboard media keys showed the popup. On top of that, a touchpad's stream of many small wheel events per finger-drag wasn't matched to a mouse's single ±120 notch per click, so touchpad scrolling felt uncoordinated and uneven next to the keyboard/mouse behavior. - shell/plugins/panels/audio/Panel.qml: accumulate raw wheel delta and only apply a step once it crosses a full mouse-notch's worth, so touchpad and mouse move the volume in identical 5% increments, and ping the OSD each time a step actually lands. - shell/plugins/panels/monitor/Panel.qml: same accumulator for brightness, with a 5% floor so scrolling down can never blank the screen. - shell/plugins/osd/Osd.qml: animate the progress bar's width instead of snapping, so successive steps glide smoothly. * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Fix bar wheel OSD behavior * Normalize scaled wheel events --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: David Heinemeier Hansson <david@hey.com>
This commit is contained in:
co-authored by
Copilot Autofix powered by AI
David Heinemeier Hansson
parent
09b955dc75
commit
2093d1c9c7
@@ -17,6 +17,17 @@ QtObject {
|
|||||||
return clamp(value, 0, 1)
|
return clamp(value, 0, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function wheelSteps(accumulator, delta) {
|
||||||
|
// Some mouse/compositor combinations scale a single notch well beyond
|
||||||
|
// Qt's conventional 120 units. Keep one event to one step while still
|
||||||
|
// accumulating the smaller deltas emitted by touchpads.
|
||||||
|
delta = Math.max(-120, Math.min(120, delta))
|
||||||
|
if (accumulator * delta < 0) accumulator = 0
|
||||||
|
var total = accumulator + delta
|
||||||
|
var steps = total < 0 ? Math.ceil(total / 120) : Math.floor(total / 120)
|
||||||
|
return { steps: steps, remainder: total - steps * 120 }
|
||||||
|
}
|
||||||
|
|
||||||
// Compose a base color with an opacity. Accepts a color object or a hex
|
// Compose a base color with an opacity. Accepts a color object or a hex
|
||||||
// string; null/undefined yields transparent black at the requested alpha.
|
// string; null/undefined yields transparent black at the requested alpha.
|
||||||
function alpha(c, opacity) {
|
function alpha(c, opacity) {
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ Item {
|
|||||||
|
|
||||||
function show(iconName, rawMessage, rawValue, rawMax, rawProgressText, rawDuration) {
|
function show(iconName, rawMessage, rawValue, rawMax, rawProgressText, rawDuration) {
|
||||||
var next = OsdModel.stateForShow(iconName, rawMessage, rawValue, rawMax, rawProgressText, rawDuration)
|
var next = OsdModel.stateForShow(iconName, rawMessage, rawValue, rawMax, rawProgressText, rawDuration)
|
||||||
|
// Update before opening so a fresh OSD starts at its new value; only
|
||||||
|
// subsequent updates while it remains open animate the progress bar.
|
||||||
iconKey = next.iconKey
|
iconKey = next.iconKey
|
||||||
maxValue = next.maxValue
|
maxValue = next.maxValue
|
||||||
hasProgress = next.hasProgress
|
hasProgress = next.hasProgress
|
||||||
@@ -176,6 +178,11 @@ Item {
|
|||||||
height: parent.height
|
height: parent.height
|
||||||
width: parent.width * (root.hasProgress ? root.value / root.maxValue : 0)
|
width: parent.width * (root.hasProgress ? root.value / root.maxValue : 0)
|
||||||
color: Color.accent
|
color: Color.accent
|
||||||
|
|
||||||
|
Behavior on width {
|
||||||
|
enabled: root.opened
|
||||||
|
NumberAnimation { duration: 140; easing.type: Easing.OutCubic }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
|
|||||||
@@ -121,6 +121,9 @@ Panel {
|
|||||||
// selected while a tuning still exists.
|
// selected while a tuning still exists.
|
||||||
property string volumeSinkName: ""
|
property string volumeSinkName: ""
|
||||||
|
|
||||||
|
// Carry sub-notch touchpad deltas between wheel events.
|
||||||
|
property real wheelAccumulator: 0
|
||||||
|
|
||||||
readonly property var volumeSink: {
|
readonly property var volumeSink: {
|
||||||
if (volumeSinkName === "" || !sink) return sink
|
if (volumeSinkName === "" || !sink) return sink
|
||||||
if (volumeSinkName === String(sink.name)) return sink
|
if (volumeSinkName === String(sink.name)) return sink
|
||||||
@@ -395,13 +398,13 @@ Panel {
|
|||||||
if (selectedIndex < floor) selectedIndex = floor
|
if (selectedIndex < floor) selectedIndex = floor
|
||||||
}
|
}
|
||||||
|
|
||||||
function outputIcon() {
|
function outputIcon(volume) {
|
||||||
// Match the old Waybar pulseaudio glyph set. The Material Design speaker
|
// Match the old Waybar pulseaudio glyph set. The Material Design speaker
|
||||||
// icons render visually smaller in JetBrainsMono Nerd Font.
|
// icons render visually smaller in JetBrainsMono Nerd Font.
|
||||||
if (!sink || !sink.audio) return ""
|
if (!sink || !sink.audio) return ""
|
||||||
if (isHeadphones(sink)) return ""
|
if (isHeadphones(sink)) return ""
|
||||||
if (outputMuted) return ""
|
if (outputMuted) return ""
|
||||||
var v = outputVolume
|
var v = volume === undefined ? outputVolume : volume
|
||||||
if (v >= 0.67) return ""
|
if (v >= 0.67) return ""
|
||||||
if (v >= 0.34) return ""
|
if (v >= 0.34) return ""
|
||||||
if (v > 0) return ""
|
if (v > 0) return ""
|
||||||
@@ -421,8 +424,18 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setOutputVolume(v) {
|
function setOutputVolume(v) {
|
||||||
if (!sink || !sink.audio) return
|
if (!volumeSink || !volumeSink.audio) return outputVolume
|
||||||
volumeSink.audio.volume = Math.max(0, Math.min(1, v))
|
var volume = Math.max(0, Math.min(1, v))
|
||||||
|
volumeSink.audio.volume = volume
|
||||||
|
return volume
|
||||||
|
}
|
||||||
|
|
||||||
|
function showVolumeOsd(volume) {
|
||||||
|
if (!bar || !bar.shell) return
|
||||||
|
bar.shell.summon("omarchy.osd", JSON.stringify({
|
||||||
|
icon: outputIcon(volume),
|
||||||
|
value: Math.round(volume * 100)
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
function setInputVolume(v) {
|
function setInputVolume(v) {
|
||||||
@@ -625,8 +638,12 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onWheelMoved: function(delta) {
|
onWheelMoved: function(delta) {
|
||||||
var step = 0.05
|
if (!root.hasOutput) return
|
||||||
root.setOutputVolume(root.outputVolume + (delta > 0 ? step : -step))
|
var wheel = Util.wheelSteps(root.wheelAccumulator, delta)
|
||||||
|
root.wheelAccumulator = wheel.remainder
|
||||||
|
if (wheel.steps === 0) return
|
||||||
|
var volume = root.setOutputVolume(root.outputVolume + wheel.steps * 0.05)
|
||||||
|
root.showVolumeOsd(volume)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ Panel {
|
|||||||
property var displays: []
|
property var displays: []
|
||||||
property int enabledDisplayCount: 0
|
property int enabledDisplayCount: 0
|
||||||
|
|
||||||
|
// Carry sub-notch touchpad deltas between wheel events.
|
||||||
|
property real wheelAccumulator: 0
|
||||||
|
|
||||||
// Cursor model shared by keyboard and mouse. Sections:
|
// Cursor model shared by keyboard and mouse. Sections:
|
||||||
// "brightness" - single slider row, selectedIndex = -1 sentinel
|
// "brightness" - single slider row, selectedIndex = -1 sentinel
|
||||||
// (mirrors Audio's slider rows). Only present if a
|
// (mirrors Audio's slider rows). Only present if a
|
||||||
@@ -250,6 +253,14 @@ Panel {
|
|||||||
brightnessDebounce.restart()
|
brightnessDebounce.restart()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showBrightnessOsd(percent) {
|
||||||
|
if (!bar || !bar.shell) return
|
||||||
|
bar.shell.summon("omarchy.osd", JSON.stringify({
|
||||||
|
icon: "brightness",
|
||||||
|
value: percent
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
function normalizeScale(scale) {
|
function normalizeScale(scale) {
|
||||||
return Model.normalizeScale(scale)
|
return Model.normalizeScale(scale)
|
||||||
}
|
}
|
||||||
@@ -461,7 +472,12 @@ Panel {
|
|||||||
text: Quickshell.screens.length > 1 ? "" : ""
|
text: Quickshell.screens.length > 1 ? "" : ""
|
||||||
onPressed: function(b) { root.toggle() }
|
onPressed: function(b) { root.toggle() }
|
||||||
onWheelMoved: function(delta) {
|
onWheelMoved: function(delta) {
|
||||||
if (root.brightnessAvailable) root.setBrightness(root.brightnessPercent + (delta > 0 ? 5 : -5))
|
if (!root.brightnessAvailable) return
|
||||||
|
var wheel = Util.wheelSteps(root.wheelAccumulator, delta)
|
||||||
|
root.wheelAccumulator = wheel.remainder
|
||||||
|
if (wheel.steps === 0) return
|
||||||
|
root.setBrightness(root.brightnessPercent + wheel.steps * 5)
|
||||||
|
root.showBrightnessOsd(root.brightnessPercent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user