added quickshell
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
pragma Singleton
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Services.Pipewire
|
||||
|
||||
// Live audio state straight from PipeWire, so the bar and OSD react the instant
|
||||
// a volume key is pressed rather than on the next poll.
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property PwNode sink: Pipewire.defaultAudioSink
|
||||
readonly property PwNode source: Pipewire.defaultAudioSource
|
||||
|
||||
// Binding node.audio.* only works while the node is tracked.
|
||||
PwObjectTracker {
|
||||
objects: [root.sink, root.source].filter(n => n !== null)
|
||||
}
|
||||
|
||||
readonly property bool ready: sink !== null && sink.audio !== null
|
||||
|
||||
readonly property real volume: sink?.audio?.volume ?? 0
|
||||
readonly property bool muted: sink?.audio?.muted ?? true
|
||||
readonly property int volumePercent: Math.round(volume * 100)
|
||||
readonly property string sinkName: sink?.nickname || sink?.description || sink?.name || "No output"
|
||||
|
||||
readonly property real micVolume: source?.audio?.volume ?? 0
|
||||
readonly property bool micMuted: source?.audio?.muted ?? true
|
||||
readonly property int micPercent: Math.round(micVolume * 100)
|
||||
readonly property string sourceName: source?.nickname || source?.description || source?.name || "No input"
|
||||
|
||||
// Every sink on the box, for the output picker in the audio popout.
|
||||
readonly property var sinks: Pipewire.nodes.values.filter(n =>
|
||||
n.isSink && !n.isStream && n.audio !== null)
|
||||
|
||||
// Application streams, for the per-app mixer.
|
||||
readonly property var streams: Pipewire.nodes.values.filter(n =>
|
||||
n.isStream && n.audio !== null && n.isSink === false)
|
||||
|
||||
PwObjectTracker {
|
||||
objects: root.streams
|
||||
}
|
||||
|
||||
signal volumeBumped()
|
||||
signal micBumped()
|
||||
|
||||
onVolumePercentChanged: volumeBumped()
|
||||
onMutedChanged: volumeBumped()
|
||||
onMicPercentChanged: micBumped()
|
||||
onMicMutedChanged: micBumped()
|
||||
|
||||
function setVolume(v: real) {
|
||||
if (!sink?.audio) return;
|
||||
sink.audio.volume = Math.max(0, Math.min(1.5, v));
|
||||
}
|
||||
|
||||
function changeVolume(delta: real) {
|
||||
setVolume(volume + delta);
|
||||
}
|
||||
|
||||
function toggleMute() {
|
||||
if (!sink?.audio) return;
|
||||
sink.audio.muted = !sink.audio.muted;
|
||||
}
|
||||
|
||||
function setMicVolume(v: real) {
|
||||
if (!source?.audio) return;
|
||||
source.audio.volume = Math.max(0, Math.min(1.5, v));
|
||||
}
|
||||
|
||||
function toggleMicMute() {
|
||||
if (!source?.audio) return;
|
||||
source.audio.muted = !source.audio.muted;
|
||||
}
|
||||
|
||||
function setSink(node: PwNode) {
|
||||
Pipewire.preferredDefaultAudioSink = node;
|
||||
}
|
||||
|
||||
function streamName(node: PwNode): string {
|
||||
if (!node) return "";
|
||||
return node.properties?.["application.name"]
|
||||
|| node.properties?.["media.name"]
|
||||
|| node.nickname
|
||||
|| node.description
|
||||
|| node.name;
|
||||
}
|
||||
|
||||
// Nerd Font glyph for the current output level.
|
||||
readonly property string icon: {
|
||||
if (muted) return "";
|
||||
if (volumePercent === 0) return "";
|
||||
if (volumePercent < 34) return "";
|
||||
if (volumePercent < 67) return "";
|
||||
return "";
|
||||
}
|
||||
|
||||
readonly property string micIcon: micMuted ? "" : ""
|
||||
}
|
||||
Reference in New Issue
Block a user