Compare commits

..

5 commits

8 changed files with 83 additions and 73 deletions

View file

@ -31,7 +31,7 @@ M.BarSection {
NumberAnimation {
target: root
property: "_blinkOpacity"
to: 0.2
to: 0.45
duration: 400
easing.type: Easing.InOutQuad
}

View file

@ -32,6 +32,11 @@ M.BarSection {
readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered
readonly property bool _showPanel: _anyHover || _pinned
property M.ProcessList _procs: M.ProcessList {
sortBy: "cpu"
active: root._showPanel
}
on_AnyHoverChanged: {
if (_anyHover)
_unpinTimer.stop();
@ -258,7 +263,7 @@ M.BarSection {
// Top processes by CPU
Repeater {
model: M.ProcessList.byCpu
model: root._procs.processes
delegate: Item {
required property var modelData

View file

@ -21,6 +21,11 @@ M.BarSection {
readonly property bool _anyHover: root._hovered || hoverPanel.panelHovered
readonly property bool _showPanel: _anyHover || _pinned
property M.ProcessList _procs: M.ProcessList {
sortBy: "mem"
active: root._showPanel
}
on_AnyHoverChanged: {
if (_anyHover)
_unpinTimer.stop();
@ -223,7 +228,7 @@ M.BarSection {
// Top processes by memory
Repeater {
model: M.ProcessList.byMem
model: root._procs.processes
delegate: Item {
required property var modelData

View file

@ -11,6 +11,29 @@ QtObject {
signal windowFocusChanged(var windowId)
signal windowOpenedOrChanged(var window)
property string focusedTitle: ""
property string focusedAppId: ""
property bool overviewOpen: false
property var _focusedProc: Process {
running: true
command: ["niri", "msg", "--json", "focused-window"]
stdout: StdioCollector {
onStreamFinished: {
try {
const w = JSON.parse(text);
if (w) {
root.focusedTitle = w.title || "";
root.focusedAppId = w.app_id || "";
} else {
root.focusedTitle = "";
root.focusedAppId = "";
}
} catch (e) {}
}
}
}
property var _eventStream: Process {
running: true
command: ["niri", "msg", "--json", "event-stream"]
@ -23,10 +46,24 @@ QtObject {
root.workspacesChanged(ev.WorkspacesChanged.workspaces);
else if (ev.WorkspaceActivated !== undefined)
root.workspaceActivated(ev.WorkspaceActivated.id, ev.WorkspaceActivated.focused);
else if (ev.WindowFocusChanged !== undefined)
else if (ev.WindowFocusChanged !== undefined) {
root.windowFocusChanged(ev.WindowFocusChanged.id);
else if (ev.WindowOpenedOrChanged !== undefined)
if (ev.WindowFocusChanged.id !== null)
root._focusedProc.running = true;
else {
root.focusedTitle = "";
root.focusedAppId = "";
}
} else if (ev.OverviewOpenedOrClosed !== undefined) {
root.overviewOpen = ev.OverviewOpenedOrClosed.is_open;
} else if (ev.WindowOpenedOrChanged !== undefined) {
root.windowOpenedOrChanged(ev.WindowOpenedOrChanged.window);
const w = ev.WindowOpenedOrChanged.window;
if (w.is_focused) {
root.focusedTitle = w.title || "";
root.focusedAppId = w.app_id || "";
}
}
} catch (e) {}
}
}

View file

@ -37,10 +37,18 @@ PanelWindow {
property color uC1: M.Theme.base0E
property color uC2: M.Theme.base09
// Wave animation: 6s sweep + 8s pause
Connections {
target: M.NiriIpc
function onOverviewOpenChanged() {
if (!M.NiriIpc.overviewOpen)
fx.uWavePhase = -200;
}
}
// Wave animation: 6s sweep + 8s pause, only while overview is open
SequentialAnimation on uWavePhase {
loops: Animation.Infinite
running: true
running: M.NiriIpc.overviewOpen
NumberAnimation {
from: -200
to: fx.width + 200

View file

@ -1,48 +1,43 @@
pragma Singleton
import QtQuick
import Quickshell.Io
import "." as M
QtObject {
id: root
property var byCpu: []
property var byMem: []
property string sortBy: "cpu" // "cpu" or "mem"
property int maxItems: 8
property bool active: false
property var processes: []
property Process _proc: Process {
id: proc
running: true
command: ["sh", "-c", "ps aux --sort=-%cpu 2>/dev/null | awk 'NR>1 && NR<=50 {cmd=$11; for(i=12;i<=NF&&i<=13;i++) cmd=cmd\" \"$i; print $1\"|\"$2\"|\"$3\"|\"$4\"|\"cmd}'"]
command: ["sh", "-c", "ps --no-headers -eo pid,pcpu,pmem,comm --sort=-%" + root.sortBy + " | head -" + root.maxItems]
stdout: StdioCollector {
onStreamFinished: {
const rows = [];
for (const line of text.trim().split("\n")) {
if (!line)
continue;
const p = line.split("|");
if (p.length < 5)
const p = line.trim().split(/\s+/);
if (p.length < 4)
continue;
const cmd = p[4].replace(/^.*\//, "");
rows.push({
"user": p[0],
"pid": parseInt(p[1]),
"cpu": parseFloat(p[2]),
"mem": parseFloat(p[3]),
"cmd": cmd || p[4]
"pid": parseInt(p[0]),
"cpu": parseFloat(p[1]),
"mem": parseFloat(p[2]),
"cmd": p.slice(3).join(" ")
});
}
root.byCpu = rows.slice().sort((a, b) => b.cpu - a.cpu).slice(0, root.maxItems);
root.byMem = rows.slice().sort((a, b) => b.mem - a.mem).slice(0, root.maxItems);
root.processes = rows;
}
}
}
property Timer _timer: Timer {
interval: 2000
running: true
running: root.active
repeat: true
onTriggered: proc.running = true
triggeredOnStart: true
onTriggered: root._proc.running = true
}
}

View file

@ -1,63 +1,23 @@
import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Io
import Quickshell.Widgets
import "." as M
M.BarSection {
id: root
spacing: M.Theme.moduleSpacing
visible: M.Modules.windowTitle.enable && root._title !== ""
visible: M.Modules.windowTitle.enable && M.NiriIpc.focusedTitle !== ""
tooltip: root._appId ? root._appId + "\n" + root._title : root._title
tooltip: M.NiriIpc.focusedAppId ? M.NiriIpc.focusedAppId + "\n" + M.NiriIpc.focusedTitle : M.NiriIpc.focusedTitle
property string _title: ""
property string _appId: ""
readonly property string _iconSource: {
if (!root._appId)
if (!M.NiriIpc.focusedAppId)
return "";
const entry = DesktopEntries.heuristicLookup(root._appId);
const entry = DesktopEntries.heuristicLookup(M.NiriIpc.focusedAppId);
return entry ? Quickshell.iconPath(entry.icon) : "";
}
// Initial state niri event-stream doesn't replay current focus
Process {
id: initProc
running: true
command: ["niri", "msg", "--json", "focused-window"]
stdout: StdioCollector {
onStreamFinished: {
try {
const w = JSON.parse(text);
if (w) {
root._title = w.title || "";
root._appId = w.app_id || "";
}
} catch (e) {}
}
}
}
// Live updates via shared NiriIpc singleton
Connections {
target: M.NiriIpc
function onWindowFocusChanged(windowId) {
if (windowId !== null)
initProc.running = true;
else {
root._title = "";
root._appId = "";
}
}
function onWindowOpenedOrChanged(window) {
if (window.is_focused) {
root._title = window.title || "";
root._appId = window.app_id || "";
}
}
}
IconImage {
visible: root._iconSource !== ""
source: root._iconSource
@ -71,7 +31,7 @@ M.BarSection {
}
M.BarLabel {
label: root._title
label: M.NiriIpc.focusedTitle
color: root.accentColor
elide: Text.ElideRight
anchors.verticalCenter: parent.verticalCenter

View file

@ -34,7 +34,7 @@ IdleInhibitor 1.0 IdleInhibitor.qml
Notifications 1.0 Notifications.qml
singleton NiriIpc 1.0 NiriIpc.qml
singleton SystemStats 1.0 SystemStats.qml
singleton ProcessList 1.0 ProcessList.qml
ProcessList 1.0 ProcessList.qml
singleton NotifService 1.0 NotifService.qml
NotifItem 1.0 NotifItem.qml
NotifPopup 1.0 NotifPopup.qml