pipewire service, lock-aware applets, cpu overall chart, security comments
This commit is contained in:
parent
e7bf175169
commit
8628b4b27b
13 changed files with 183 additions and 208 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import "../services" as S
|
import "../services" as S
|
||||||
|
|
||||||
|
// NOT safe for lock screen - can toggle bluetooth power and connect/disconnect devices
|
||||||
Column {
|
Column {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ Column {
|
||||||
required property color accentColor
|
required property color accentColor
|
||||||
|
|
||||||
property bool active: true
|
property bool active: true
|
||||||
property bool locked: false
|
|
||||||
|
|
||||||
property bool _coreActive: false
|
property bool _coreActive: false
|
||||||
onActiveChanged: {
|
onActiveChanged: {
|
||||||
|
|
@ -141,37 +140,26 @@ Column {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overall CPU utilization chart
|
Separator {}
|
||||||
Item {
|
|
||||||
width: root.width
|
|
||||||
height: 44
|
|
||||||
|
|
||||||
Text {
|
// Overall CPU utilization
|
||||||
id: _totalLabel
|
InfoRow {
|
||||||
anchors.left: parent.left
|
label: "Total"
|
||||||
anchors.leftMargin: 12
|
value: S.SystemStats.cpuUsage + "% @ " + S.SystemStats.cpuFreqGhz.toFixed(2) + " GHz"
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
valueColor: S.Theme.loadColor(S.SystemStats.cpuUsage)
|
||||||
text: S.SystemStats.cpuUsage + "%"
|
|
||||||
color: S.Theme.loadColor(S.SystemStats.cpuUsage)
|
|
||||||
font.pixelSize: S.Theme.fontSize - 1
|
|
||||||
font.family: S.Theme.fontFamily
|
|
||||||
font.bold: true
|
|
||||||
width: 32
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SparklineCanvas {
|
SparklineCanvas {
|
||||||
anchors.left: _totalLabel.right
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: 6
|
anchors.leftMargin: 12
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: 12
|
anchors.rightMargin: 12
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
height: 32
|
height: 32
|
||||||
history: root._cpuHistory
|
history: root._cpuHistory
|
||||||
strokeColor: root.accentColor
|
strokeColor: root.accentColor
|
||||||
colorAt: v => S.Theme.loadColor(v)
|
colorAt: v => S.Theme.loadColor(v)
|
||||||
active: root.active
|
active: root.active
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
property var _cpuHistory: []
|
property var _cpuHistory: []
|
||||||
Connections {
|
Connections {
|
||||||
|
|
@ -184,10 +172,15 @@ Column {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process list - hidden on lock screen (exposes running process names)
|
||||||
|
Column {
|
||||||
|
visible: !S.LockService.locked
|
||||||
|
width: root.width
|
||||||
|
|
||||||
Separator {}
|
Separator {}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: root.width
|
width: parent.width
|
||||||
height: 18
|
height: 18
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
|
@ -213,7 +206,6 @@ Column {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Top processes by CPU
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: root.processes
|
model: root.processes
|
||||||
|
|
||||||
|
|
@ -252,4 +244,5 @@ Column {
|
||||||
width: 1
|
width: 1
|
||||||
height: 4
|
height: 4
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,10 +101,15 @@ Column {
|
||||||
active: root.active
|
active: root.active
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Process list - hidden on lock screen (exposes running process names)
|
||||||
|
Column {
|
||||||
|
visible: !S.LockService.locked
|
||||||
|
width: root.width
|
||||||
|
|
||||||
Separator {}
|
Separator {}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
width: root.width
|
width: parent.width
|
||||||
height: 18
|
height: 18
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
|
|
@ -130,7 +135,6 @@ Column {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Top processes by memory
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: root.processes
|
model: root.processes
|
||||||
|
|
||||||
|
|
@ -169,4 +173,5 @@ Column {
|
||||||
width: 1
|
width: 1
|
||||||
height: 4
|
height: 4
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import "../services" as S
|
import "../services" as S
|
||||||
|
|
||||||
|
// NOT safe for lock screen - can toggle wifi and connect/disconnect networks
|
||||||
Column {
|
Column {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ import Quickshell
|
||||||
import "../services" as S
|
import "../services" as S
|
||||||
import "../modules" as M
|
import "../modules" as M
|
||||||
|
|
||||||
|
// NOT safe for lock screen - notification contents may be sensitive,
|
||||||
|
// can dismiss/clear notifications and toggle DND
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import "../services" as S
|
import "../services" as S
|
||||||
|
|
||||||
|
// NOT safe for lock screen - executes system commands (shutdown, reboot, logout, suspend)
|
||||||
Column {
|
Column {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,9 @@ import "../services" as S
|
||||||
Column {
|
Column {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property var sink
|
|
||||||
required property var sinkList
|
|
||||||
required property var streamList
|
|
||||||
required property color accentColor
|
required property color accentColor
|
||||||
|
|
||||||
|
readonly property var sink: S.PipewireService.sink
|
||||||
property real volume: sink?.audio?.volume ?? 0
|
property real volume: sink?.audio?.volume ?? 0
|
||||||
property bool muted: sink?.audio?.muted ?? false
|
property bool muted: sink?.audio?.muted ?? false
|
||||||
readonly property string volumeIcon: muted ? "\uF026" : (volume > 0.5 ? "\uF028" : (volume > 0 ? "\uF027" : "\uF026"))
|
readonly property string volumeIcon: muted ? "\uF026" : (volume > 0.5 ? "\uF028" : (volume > 0 ? "\uF027" : "\uF026"))
|
||||||
|
|
@ -95,14 +93,15 @@ Column {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device + stream list
|
// Device + stream list (hidden on lock screen)
|
||||||
Column {
|
Column {
|
||||||
id: deviceList
|
id: deviceList
|
||||||
|
visible: !S.LockService.locked
|
||||||
width: root.width
|
width: root.width
|
||||||
|
|
||||||
// Output devices - only shown when more than one exists
|
// Output devices - only shown when more than one exists
|
||||||
Column {
|
Column {
|
||||||
visible: root.sinkList.length > 1
|
visible: S.PipewireService.sinks.length > 1
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
|
||||||
Separator {}
|
Separator {}
|
||||||
|
|
@ -119,7 +118,7 @@ Column {
|
||||||
}
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: root.sinkList
|
model: S.PipewireService.sinks
|
||||||
|
|
||||||
delegate: HoverableListItem {
|
delegate: HoverableListItem {
|
||||||
required property var modelData
|
required property var modelData
|
||||||
|
|
@ -149,11 +148,11 @@ Column {
|
||||||
|
|
||||||
// Streams section
|
// Streams section
|
||||||
Separator {
|
Separator {
|
||||||
visible: root.streamList.length > 0
|
visible: S.PipewireService.streams.length > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
visible: root.streamList.length > 0
|
visible: S.PipewireService.streams.length > 0
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: visible ? 24 : 0
|
height: visible ? 24 : 0
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
|
@ -165,7 +164,7 @@ Column {
|
||||||
}
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: root.streamList
|
model: S.PipewireService.streams
|
||||||
|
|
||||||
delegate: Item {
|
delegate: Item {
|
||||||
id: streamEntry
|
id: streamEntry
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import Quickshell.Services.Mpris
|
import Quickshell.Services.Mpris
|
||||||
import Quickshell.Services.Pipewire
|
|
||||||
import "." as D
|
import "." as D
|
||||||
import "../services" as S
|
import "../services" as S
|
||||||
import "../applets" as C
|
import "../applets" as C
|
||||||
|
|
@ -325,9 +324,6 @@ PanelWindow {
|
||||||
|
|
||||||
C.VolumeApplet {
|
C.VolumeApplet {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
sink: Pipewire.defaultAudioSink
|
|
||||||
sinkList: root._sinkList
|
|
||||||
streamList: root._streamList
|
|
||||||
accentColor: root._accent
|
accentColor: root._accent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -430,30 +426,6 @@ PanelWindow {
|
||||||
active: _memCard.expanded && S.DockState.open
|
active: _memCard.expanded && S.DockState.open
|
||||||
}
|
}
|
||||||
|
|
||||||
PwObjectTracker {
|
|
||||||
objects: [Pipewire.defaultAudioSink, ...root._streamList]
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property var _sinkList: {
|
|
||||||
const sinks = [];
|
|
||||||
if (Pipewire.nodes) {
|
|
||||||
for (const node of Pipewire.nodes.values)
|
|
||||||
if (!node.isStream && node.isSink)
|
|
||||||
sinks.push(node);
|
|
||||||
}
|
|
||||||
return sinks;
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property var _streamList: {
|
|
||||||
const streams = [];
|
|
||||||
if (Pipewire.nodes) {
|
|
||||||
for (const node of Pipewire.nodes.values)
|
|
||||||
if (node.isStream && node.audio)
|
|
||||||
streams.push(node);
|
|
||||||
}
|
|
||||||
return streams;
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: _runner
|
id: _runner
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell.Services.Pipewire
|
|
||||||
import "../services" as S
|
import "../services" as S
|
||||||
import "../applets" as C
|
import "../applets" as C
|
||||||
|
|
||||||
|
|
@ -91,11 +90,7 @@ Item {
|
||||||
color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.7)
|
color: Qt.rgba(S.Theme.base01.r, S.Theme.base01.g, S.Theme.base01.b, 0.7)
|
||||||
border.color: Qt.rgba(S.Theme.base03.r, S.Theme.base03.g, S.Theme.base03.b, 0.3)
|
border.color: Qt.rgba(S.Theme.base03.r, S.Theme.base03.g, S.Theme.base03.b, 0.3)
|
||||||
border.width: 1
|
border.width: 1
|
||||||
visible: (S.Modules.lock.volume ?? true) && Pipewire.defaultAudioSink !== null
|
visible: (S.Modules.lock.volume ?? true) && S.PipewireService.sink !== null
|
||||||
|
|
||||||
PwObjectTracker {
|
|
||||||
objects: [Pipewire.defaultAudioSink]
|
|
||||||
}
|
|
||||||
|
|
||||||
C.VolumeApplet {
|
C.VolumeApplet {
|
||||||
id: _volumeContent
|
id: _volumeContent
|
||||||
|
|
@ -103,9 +98,6 @@ Item {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.topMargin: 8
|
anchors.topMargin: 8
|
||||||
sink: Pipewire.defaultAudioSink
|
|
||||||
sinkList: []
|
|
||||||
streamList: []
|
|
||||||
accentColor: S.Theme.base0E
|
accentColor: S.Theme.base0E
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Services.Pipewire
|
|
||||||
import "." as M
|
import "." as M
|
||||||
import "../services" as S
|
import "../services" as S
|
||||||
import "../applets" as C
|
import "../applets" as C
|
||||||
|
|
@ -15,43 +14,15 @@ M.BarModule {
|
||||||
panelComponent: Component {
|
panelComponent: Component {
|
||||||
C.VolumeApplet {
|
C.VolumeApplet {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
sink: root.sink
|
|
||||||
sinkList: root._sinkList
|
|
||||||
streamList: root._streamList
|
|
||||||
accentColor: root.accentColor
|
accentColor: root.accentColor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PwObjectTracker {
|
readonly property real volume: S.PipewireService.volume
|
||||||
objects: [Pipewire.defaultAudioSink, ...root._streamList]
|
readonly property bool muted: S.PipewireService.muted
|
||||||
}
|
|
||||||
|
|
||||||
readonly property var sink: Pipewire.defaultAudioSink
|
|
||||||
readonly property real volume: sink?.audio?.volume ?? 0
|
|
||||||
readonly property bool muted: sink?.audio?.muted ?? false
|
|
||||||
readonly property string _volumeIcon: muted ? "\uF026" : (volume > 0.5 ? "\uF028" : (volume > 0 ? "\uF027" : "\uF026"))
|
readonly property string _volumeIcon: muted ? "\uF026" : (volume > 0.5 ? "\uF028" : (volume > 0 ? "\uF027" : "\uF026"))
|
||||||
readonly property color _volumeColor: muted ? S.Theme.base04 : root.accentColor
|
readonly property color _volumeColor: muted ? S.Theme.base04 : root.accentColor
|
||||||
|
|
||||||
readonly property var _sinkList: {
|
|
||||||
const sinks = [];
|
|
||||||
if (Pipewire.nodes) {
|
|
||||||
for (const node of Pipewire.nodes.values)
|
|
||||||
if (!node.isStream && node.isSink)
|
|
||||||
sinks.push(node);
|
|
||||||
}
|
|
||||||
return sinks;
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly property var _streamList: {
|
|
||||||
const streams = [];
|
|
||||||
if (Pipewire.nodes) {
|
|
||||||
for (const node of Pipewire.nodes.values)
|
|
||||||
if (node.isStream && node.audio)
|
|
||||||
streams.push(node);
|
|
||||||
}
|
|
||||||
return streams;
|
|
||||||
}
|
|
||||||
|
|
||||||
property bool _volumeInit: false
|
property bool _volumeInit: false
|
||||||
property bool _mutedInit: false
|
property bool _mutedInit: false
|
||||||
|
|
||||||
|
|
@ -85,9 +56,9 @@ M.BarModule {
|
||||||
|
|
||||||
WheelHandler {
|
WheelHandler {
|
||||||
onWheel: event => {
|
onWheel: event => {
|
||||||
if (!root.sink?.audio)
|
if (!S.PipewireService.sink?.audio)
|
||||||
return;
|
return;
|
||||||
root.sink.audio.volume = Math.max(0, root.sink.audio.volume + (event.angleDelta.y > 0 ? 0.05 : -0.05));
|
S.PipewireService.sink.audio.volume = Math.max(0, S.PipewireService.sink.audio.volume + (event.angleDelta.y > 0 ? 0.05 : -0.05));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ QtObject {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property bool enabled: S.Modules.lock.enable
|
readonly property bool enabled: S.Modules.lock.enable
|
||||||
|
property bool locked: false
|
||||||
property string sessionPath: ""
|
property string sessionPath: ""
|
||||||
|
|
||||||
// Lock/unlock requests from logind
|
// Lock/unlock requests from logind
|
||||||
|
|
@ -15,10 +16,10 @@ QtObject {
|
||||||
signal unlockRequested
|
signal unlockRequested
|
||||||
|
|
||||||
// Set logind LockedHint
|
// Set logind LockedHint
|
||||||
function setLockedHint(locked) {
|
function setLockedHint(isLocked) {
|
||||||
if (!sessionPath)
|
if (!sessionPath)
|
||||||
return;
|
return;
|
||||||
_lockedHint._locked = locked;
|
root.locked = isLocked;
|
||||||
_lockedHint.running = true;
|
_lockedHint.running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,7 +83,6 @@ QtObject {
|
||||||
|
|
||||||
// Set logind LockedHint
|
// Set logind LockedHint
|
||||||
property Process _lockedHint: Process {
|
property Process _lockedHint: Process {
|
||||||
property bool _locked: false
|
command: ["busctl", "call", "--system", "org.freedesktop.login1", root.sessionPath || "/org/freedesktop/login1/session/auto", "org.freedesktop.login1.Session", "SetLockedHint", "b", root.locked ? "true" : "false"]
|
||||||
command: ["busctl", "call", "--system", "org.freedesktop.login1", root.sessionPath || "/org/freedesktop/login1/session/auto", "org.freedesktop.login1.Session", "SetLockedHint", "b", _locked ? "true" : "false"]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
36
shell/services/PipewireService.qml
Normal file
36
shell/services/PipewireService.qml
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import Quickshell.Services.Pipewire
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property var sink: Pipewire.defaultAudioSink
|
||||||
|
readonly property real volume: sink?.audio?.volume ?? 0
|
||||||
|
readonly property bool muted: sink?.audio?.muted ?? false
|
||||||
|
|
||||||
|
readonly property var sinks: {
|
||||||
|
const list = [];
|
||||||
|
if (Pipewire.nodes) {
|
||||||
|
for (const node of Pipewire.nodes.values)
|
||||||
|
if (!node.isStream && node.isSink)
|
||||||
|
list.push(node);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property var streams: {
|
||||||
|
const list = [];
|
||||||
|
if (Pipewire.nodes) {
|
||||||
|
for (const node of Pipewire.nodes.values)
|
||||||
|
if (node.isStream && node.audio)
|
||||||
|
list.push(node);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
property PwObjectTracker _tracker: PwObjectTracker {
|
||||||
|
objects: [Pipewire.defaultAudioSink, ...root.streams]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,7 @@ singleton MprisService 1.0 MprisService.qml
|
||||||
singleton NetworkService 1.0 NetworkService.qml
|
singleton NetworkService 1.0 NetworkService.qml
|
||||||
singleton NiriIpc 1.0 NiriIpc.qml
|
singleton NiriIpc 1.0 NiriIpc.qml
|
||||||
singleton NotifService 1.0 NotifService.qml
|
singleton NotifService 1.0 NotifService.qml
|
||||||
|
singleton PipewireService 1.0 PipewireService.qml
|
||||||
singleton PowerProfileService 1.0 PowerProfileService.qml
|
singleton PowerProfileService 1.0 PowerProfileService.qml
|
||||||
singleton ScreenshotService 1.0 ScreenshotService.qml
|
singleton ScreenshotService 1.0 ScreenshotService.qml
|
||||||
singleton SleepService 1.0 SleepService.qml
|
singleton SleepService 1.0 SleepService.qml
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue