added quickshell config
This commit is contained in:
25
dotfiles/.config/quickshell/config/Appearance.qml
Normal file
25
dotfiles/.config/quickshell/config/Appearance.qml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
readonly property string fontFamily: "Noto Sans"
|
||||||
|
readonly property string iconFontFamily: "Material Symbols Outlined"
|
||||||
|
// Material Symbols is a variable font. Left unset, glyphs fall back to the
|
||||||
|
// font's default optical size (24px), which is tuned for larger rendering
|
||||||
|
// and makes some icons (e.g. "lock") look heavier/bigger than others when
|
||||||
|
// drawn small — pin "opsz" near the actual render size to keep icons
|
||||||
|
// visually consistent. See Appearance.iconSize for the matching pixelSize.
|
||||||
|
readonly property var iconFontAxes: ({ "FILL": 0, "wght": 400, "GRAD": 0, "opsz": 20 })
|
||||||
|
readonly property int iconSize: 16
|
||||||
|
|
||||||
|
readonly property int fontSize: 13
|
||||||
|
readonly property int fontSizeSmall: 11
|
||||||
|
|
||||||
|
readonly property int radius: 14
|
||||||
|
readonly property int radiusSmall: 8
|
||||||
|
|
||||||
|
readonly property int barHeight: 34
|
||||||
|
readonly property int spacing: 10
|
||||||
|
|
||||||
|
readonly property int animationDuration: 150
|
||||||
|
}
|
||||||
59
dotfiles/.config/quickshell/config/Colors.qml
Normal file
59
dotfiles/.config/quickshell/config/Colors.qml
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
|
||||||
|
// Wallpaper-driven palette, sourced from pywal's ~/.cache/wal/colors.json.
|
||||||
|
// Run `wal -i /path/to/wallpaper.png` to (re)generate it — this file watches
|
||||||
|
// the cache and updates live, no shell restart needed. Until that's been run
|
||||||
|
// once, everything falls back to a hand-picked dark palette below.
|
||||||
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property bool active: _parsed !== null
|
||||||
|
property var _parsed: null
|
||||||
|
|
||||||
|
// --- Fallback palette (used until pywal has run) ---
|
||||||
|
readonly property color fallbackBg: "#1a1b26"
|
||||||
|
readonly property color fallbackFg: "#c0caf5"
|
||||||
|
readonly property var fallbackPalette: [
|
||||||
|
"#15161e", "#f7768e", "#9ece6a", "#e0af68",
|
||||||
|
"#7aa2f7", "#bb9af7", "#7dcfff", "#a9b1d6",
|
||||||
|
"#414868", "#f7768e", "#9ece6a", "#e0af68",
|
||||||
|
"#7aa2f7", "#bb9af7", "#7dcfff", "#c0caf5"
|
||||||
|
]
|
||||||
|
|
||||||
|
function paletteColor(i) {
|
||||||
|
if (_parsed && _parsed.colors)
|
||||||
|
return _parsed.colors["color" + i] || fallbackPalette[i]
|
||||||
|
return fallbackPalette[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property color background: _parsed && _parsed.special ? _parsed.special.background : fallbackBg
|
||||||
|
readonly property color foreground: _parsed && _parsed.special ? _parsed.special.foreground : fallbackFg
|
||||||
|
readonly property color primary: paletteColor(4)
|
||||||
|
// Named primaryText (not "onPrimary") because QML treats any "onXxx"
|
||||||
|
// identifier as a signal handler slot, not a regular property.
|
||||||
|
readonly property color primaryText: background
|
||||||
|
readonly property color urgent: paletteColor(1)
|
||||||
|
readonly property color muted: paletteColor(8)
|
||||||
|
readonly property color surface: Qt.lighter(background, 1.35)
|
||||||
|
|
||||||
|
// QtObject has no default property, so the FileView is attached via a
|
||||||
|
// property assignment rather than as a plain child element.
|
||||||
|
readonly property FileView _walFile: FileView {
|
||||||
|
path: Quickshell.env("HOME") + "/.cache/wal/colors.json"
|
||||||
|
watchChanges: true
|
||||||
|
onLoaded: {
|
||||||
|
try {
|
||||||
|
root._parsed = JSON.parse(text())
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Colors: failed to parse pywal cache:", e)
|
||||||
|
root._parsed = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onLoadFailed: (error) => {
|
||||||
|
root._parsed = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
dotfiles/.config/quickshell/config/qmldir
Normal file
3
dotfiles/.config/quickshell/config/qmldir
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
module config
|
||||||
|
singleton Colors 1.0 Colors.qml
|
||||||
|
singleton Appearance 1.0 Appearance.qml
|
||||||
13
dotfiles/.config/quickshell/modules/bar/ActiveWindow.qml
Normal file
13
dotfiles/.config/quickshell/modules/bar/ActiveWindow.qml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.maximumWidth: 320
|
||||||
|
elide: Text.ElideRight
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: Colors.muted
|
||||||
|
text: Hyprland.activeToplevel ? Hyprland.activeToplevel.title : ""
|
||||||
|
}
|
||||||
55
dotfiles/.config/quickshell/modules/bar/Bar.qml
Normal file
55
dotfiles/.config/quickshell/modules/bar/Bar.qml
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: bar
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: true
|
||||||
|
left: true
|
||||||
|
right: true
|
||||||
|
}
|
||||||
|
implicitHeight: Appearance.barHeight
|
||||||
|
exclusiveZone: implicitHeight
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
WlrLayershell.layer: WlrLayer.Top
|
||||||
|
WlrLayershell.namespace: "quickshell:bar"
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Colors.background
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
leftMargin: Appearance.spacing
|
||||||
|
}
|
||||||
|
spacing: Appearance.spacing
|
||||||
|
Workspaces { screen: bar.screen }
|
||||||
|
ActiveWindow {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Clock {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors {
|
||||||
|
right: parent.right
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
rightMargin: Appearance.spacing
|
||||||
|
}
|
||||||
|
spacing: Appearance.spacing
|
||||||
|
Tray {}
|
||||||
|
NetworkIndicator {}
|
||||||
|
BluetoothIndicator {}
|
||||||
|
Volume {}
|
||||||
|
PowerButton {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell.Bluetooth
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
implicitWidth: label.implicitWidth + 4
|
||||||
|
implicitHeight: Appearance.barHeight
|
||||||
|
|
||||||
|
readonly property var adapter: Bluetooth.defaultAdapter
|
||||||
|
readonly property bool anyConnected: {
|
||||||
|
if (!adapter) return false
|
||||||
|
const devices = adapter.devices.values
|
||||||
|
for (let i = 0; i < devices.length; i++) {
|
||||||
|
if (devices[i].connected) return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
anchors.centerIn: parent
|
||||||
|
font.family: Appearance.iconFontFamily
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 16
|
||||||
|
color: (root.adapter && root.adapter.enabled) ? Colors.foreground : Colors.muted
|
||||||
|
text: {
|
||||||
|
if (!root.adapter || !root.adapter.enabled) return "bluetooth_disabled"
|
||||||
|
return root.anyConnected ? "bluetooth_connected" : "bluetooth"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: if (root.adapter) root.adapter.enabled = !root.adapter.enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
18
dotfiles/.config/quickshell/modules/bar/Clock.qml
Normal file
18
dotfiles/.config/quickshell/modules/bar/Clock.qml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import QtQuick
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: root
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSize
|
||||||
|
font.bold: true
|
||||||
|
color: Colors.foreground
|
||||||
|
text: Qt.formatDateTime(new Date(), "ddd d MMM hh:mm")
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
interval: 1000
|
||||||
|
running: true
|
||||||
|
repeat: true
|
||||||
|
onTriggered: root.text = Qt.formatDateTime(new Date(), "ddd d MMM hh:mm")
|
||||||
|
}
|
||||||
|
}
|
||||||
35
dotfiles/.config/quickshell/modules/bar/NetworkIndicator.qml
Normal file
35
dotfiles/.config/quickshell/modules/bar/NetworkIndicator.qml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell.Networking
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
implicitWidth: label.implicitWidth + 4
|
||||||
|
implicitHeight: Appearance.barHeight
|
||||||
|
|
||||||
|
readonly property var connectedDevice: {
|
||||||
|
const devices = Networking.devices.values
|
||||||
|
for (let i = 0; i < devices.length; i++) {
|
||||||
|
if (devices[i].connected)
|
||||||
|
return devices[i]
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
anchors.centerIn: parent
|
||||||
|
font.family: Appearance.iconFontFamily
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 16
|
||||||
|
color: root.connectedDevice ? Colors.foreground : Colors.muted
|
||||||
|
text: {
|
||||||
|
if (!root.connectedDevice)
|
||||||
|
return "wifi_off"
|
||||||
|
return root.connectedDevice.type === DeviceType.Wired ? "settings_ethernet" : "wifi"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(follow-up): wire this up to a network panel (SSID list, connect/forget)
|
||||||
|
// once the control center lands.
|
||||||
|
}
|
||||||
114
dotfiles/.config/quickshell/modules/bar/PowerButton.qml
Normal file
114
dotfiles/.config/quickshell/modules/bar/PowerButton.qml
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
implicitWidth: label.implicitWidth + 4
|
||||||
|
implicitHeight: Appearance.barHeight
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
anchors.centerIn: parent
|
||||||
|
font.family: Appearance.iconFontFamily
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 16
|
||||||
|
color: Colors.foreground
|
||||||
|
text: "power_settings_new"
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: menu.visible = !menu.visible
|
||||||
|
}
|
||||||
|
|
||||||
|
Process { id: proc }
|
||||||
|
|
||||||
|
PopupWindow {
|
||||||
|
id: menu
|
||||||
|
visible: false
|
||||||
|
color: "transparent"
|
||||||
|
implicitWidth: 170
|
||||||
|
implicitHeight: list.model.length * 32 + (list.model.length - 1) * 2 + 16
|
||||||
|
|
||||||
|
anchor {
|
||||||
|
item: root
|
||||||
|
edges: Edges.Bottom | Edges.Right
|
||||||
|
gravity: Edges.Bottom | Edges.Left
|
||||||
|
margins.top: 4
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: Appearance.radius
|
||||||
|
color: Colors.surface
|
||||||
|
border.color: Colors.muted
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 8
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: list
|
||||||
|
model: [
|
||||||
|
// "iconSize" is optional — omit it to use the 15px default below.
|
||||||
|
// Material Symbols glyphs aren't all the same visual weight at a
|
||||||
|
// given size (a padlock silhouette reads bulkier than a thin arrow),
|
||||||
|
// so nudge individual icons here to balance them by eye.
|
||||||
|
{ label: "Lock", icon: "lock", iconSize: 13, cmd: ["hyprlock"] },
|
||||||
|
{ label: "Log out", icon: "logout", cmd: ["hyprctl", "dispatch", "exit"] },
|
||||||
|
{ label: "Reboot", icon: "restart_alt", cmd: ["systemctl", "reboot"] },
|
||||||
|
{ label: "Shut down", icon: "power_settings_new", cmd: ["systemctl", "poweroff"] }
|
||||||
|
]
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
id: entry
|
||||||
|
required property var modelData
|
||||||
|
width: parent ? parent.width : 0
|
||||||
|
height: 32
|
||||||
|
radius: Appearance.radiusSmall
|
||||||
|
color: entryMouse.containsMouse ? Colors.primary : "transparent"
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.leftMargin: 8
|
||||||
|
spacing: 8
|
||||||
|
Text {
|
||||||
|
Layout.preferredWidth: 20
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
text: entry.modelData.icon
|
||||||
|
font.family: Appearance.iconFontFamily
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: entry.modelData.iconSize || 15
|
||||||
|
color: entryMouse.containsMouse ? Colors.primaryText : Colors.foreground
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
text: entry.modelData.label
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSize
|
||||||
|
color: entryMouse.containsMouse ? Colors.primaryText : Colors.foreground
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: entryMouse
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
proc.command = entry.modelData.cmd
|
||||||
|
proc.running = true
|
||||||
|
menu.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
dotfiles/.config/quickshell/modules/bar/Tray.qml
Normal file
32
dotfiles/.config/quickshell/modules/bar/Tray.qml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Services.SystemTray
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
spacing: Appearance.spacing * 0.6
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: SystemTray.items
|
||||||
|
|
||||||
|
delegate: IconImage {
|
||||||
|
id: trayIcon
|
||||||
|
required property var modelData
|
||||||
|
implicitWidth: 16
|
||||||
|
implicitHeight: 16
|
||||||
|
source: modelData.icon
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
onClicked: (mouse) => {
|
||||||
|
if (mouse.button === Qt.LeftButton)
|
||||||
|
trayIcon.modelData.activate()
|
||||||
|
else
|
||||||
|
trayIcon.modelData.secondaryActivate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
dotfiles/.config/quickshell/modules/bar/Volume.qml
Normal file
43
dotfiles/.config/quickshell/modules/bar/Volume.qml
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import QtQuick
|
||||||
|
import Quickshell.Services.Pipewire
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
implicitWidth: label.implicitWidth + 4
|
||||||
|
implicitHeight: Appearance.barHeight
|
||||||
|
|
||||||
|
readonly property var sink: Pipewire.defaultAudioSink
|
||||||
|
readonly property real vol: (sink && sink.audio) ? sink.audio.volume : 0
|
||||||
|
readonly property bool muted: (sink && sink.audio) ? sink.audio.muted : false
|
||||||
|
|
||||||
|
PwObjectTracker { objects: root.sink ? [root.sink] : [] }
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: label
|
||||||
|
anchors.centerIn: parent
|
||||||
|
font.family: Appearance.iconFontFamily
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 16
|
||||||
|
color: Colors.foreground
|
||||||
|
text: {
|
||||||
|
if (root.muted || root.vol <= 0) return "volume_off"
|
||||||
|
if (root.vol < 0.5) return "volume_down"
|
||||||
|
return "volume_up"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
acceptedButtons: Qt.LeftButton
|
||||||
|
onClicked: if (root.sink && root.sink.audio) root.sink.audio.muted = !root.sink.audio.muted
|
||||||
|
|
||||||
|
onWheel: (wheel) => {
|
||||||
|
if (!root.sink || !root.sink.audio) return
|
||||||
|
const step = 0.05
|
||||||
|
const delta = wheel.angleDelta.y > 0 ? step : -step
|
||||||
|
root.sink.audio.volume = Math.max(0, Math.min(1, root.sink.audio.volume + delta))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
dotfiles/.config/quickshell/modules/bar/Workspaces.qml
Normal file
44
dotfiles/.config/quickshell/modules/bar/Workspaces.qml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell.Hyprland
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: root
|
||||||
|
property var screen
|
||||||
|
|
||||||
|
spacing: 4
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: Hyprland.workspaces
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
id: pill
|
||||||
|
required property var modelData
|
||||||
|
visible: modelData.monitor && root.screen && modelData.monitor.name === root.screen.name
|
||||||
|
|
||||||
|
implicitWidth: 26
|
||||||
|
implicitHeight: 22
|
||||||
|
radius: Appearance.radiusSmall
|
||||||
|
color: modelData.urgent ? Colors.urgent
|
||||||
|
: modelData.active ? Colors.primary
|
||||||
|
: "transparent"
|
||||||
|
|
||||||
|
Behavior on color { ColorAnimation { duration: Appearance.animationDuration } }
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: modelData.name
|
||||||
|
font.family: Appearance.fontFamily
|
||||||
|
font.pixelSize: Appearance.fontSizeSmall
|
||||||
|
color: modelData.active ? Colors.primaryText : Colors.foreground
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: Hyprland.dispatch("workspace " + modelData.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
78
dotfiles/.config/quickshell/modules/osd/VolumeOsd.qml
Normal file
78
dotfiles/.config/quickshell/modules/osd/VolumeOsd.qml
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import Quickshell
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Services.Pipewire
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import "../../config"
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: osd
|
||||||
|
visible: false
|
||||||
|
color: "transparent"
|
||||||
|
exclusiveZone: 0
|
||||||
|
|
||||||
|
anchors { bottom: true }
|
||||||
|
margins.bottom: 70
|
||||||
|
|
||||||
|
implicitWidth: 240
|
||||||
|
implicitHeight: 54
|
||||||
|
|
||||||
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
|
WlrLayershell.namespace: "quickshell:osd"
|
||||||
|
|
||||||
|
readonly property var sink: Pipewire.defaultAudioSink
|
||||||
|
PwObjectTracker { objects: osd.sink ? [osd.sink] : [] }
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: hideTimer
|
||||||
|
interval: 1400
|
||||||
|
onTriggered: osd.visible = false
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: osd.sink ? osd.sink.audio : null
|
||||||
|
function onVolumeChanged() { osd.visible = true; hideTimer.restart() }
|
||||||
|
function onMutedChanged() { osd.visible = true; hideTimer.restart() }
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: Appearance.radius
|
||||||
|
color: Colors.surface
|
||||||
|
border.color: Colors.muted
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 14
|
||||||
|
spacing: 12
|
||||||
|
|
||||||
|
Text {
|
||||||
|
font.family: Appearance.iconFontFamily
|
||||||
|
font.variableAxes: Appearance.iconFontAxes
|
||||||
|
font.pixelSize: 18
|
||||||
|
color: Colors.foreground
|
||||||
|
text: {
|
||||||
|
const audio = osd.sink ? osd.sink.audio : null
|
||||||
|
if (!audio || audio.muted || audio.volume <= 0) return "volume_off"
|
||||||
|
return audio.volume < 0.5 ? "volume_down" : "volume_up"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
height: 6
|
||||||
|
radius: 3
|
||||||
|
color: Colors.muted
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
height: parent.height
|
||||||
|
radius: 3
|
||||||
|
color: Colors.primary
|
||||||
|
width: parent.width * (osd.sink && osd.sink.audio ? osd.sink.audio.volume : 0)
|
||||||
|
Behavior on width { NumberAnimation { duration: Appearance.animationDuration } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
dotfiles/.config/quickshell/shell.qml
Normal file
16
dotfiles/.config/quickshell/shell.qml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import Quickshell
|
||||||
|
import "./modules/bar"
|
||||||
|
import "./modules/osd"
|
||||||
|
|
||||||
|
ShellRoot {
|
||||||
|
Variants {
|
||||||
|
model: Quickshell.screens
|
||||||
|
|
||||||
|
Bar {
|
||||||
|
required property var modelData
|
||||||
|
screen: modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VolumeOsd {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user