noctalia-shell/Services/NiriService.qml

138 lines
4.4 KiB
QML

pragma Singleton
pragma ComponentBehavior
import QtQuick
import Quickshell
import Quickshell.Io
Singleton {
id: root
property var workspaces: []
property var windows: []
property int focusedWindowIndex: -1
property bool inOverview: false
property string focusedWindowTitle: "(No active window)"
function updateFocusedWindowTitle() {
if (focusedWindowIndex >= 0 && focusedWindowIndex < windows.length) {
focusedWindowTitle = windows[focusedWindowIndex].title || "(Unnamed window)"
} else {
focusedWindowTitle = "(No active window)"
}
}
onWindowsChanged: updateFocusedWindowTitle()
onFocusedWindowIndexChanged: updateFocusedWindowTitle()
Component.onCompleted: {
eventStream.running = true
}
Process {
id: workspaceProcess
running: false
command: ["niri", "msg", "--json", "workspaces"]
stdout: SplitParser {
onRead: function (line) {
try {
const workspacesData = JSON.parse(line)
const workspacesList = []
for (const ws of workspacesData) {
workspacesList.push({
"id": ws.id,
"idx": ws.idx,
"name": ws.name || "",
"output": ws.output || "",
"isFocused": ws.is_focused === true,
"isActive": ws.is_active === true,
"isUrgent": ws.is_urgent === true,
"isOccupied": ws.active_window_id ? true : false
})
}
workspacesList.sort((a, b) => {
if (a.output !== b.output) {
return a.output.localeCompare(b.output)
}
return a.id - b.id
})
root.workspaces = workspacesList
} catch (e) {
console.error("Failed to parse workspaces:", e, line)
}
}
}
}
Process {
id: eventStream
running: false
command: ["niri", "msg", "--json", "event-stream"]
stdout: SplitParser {
onRead: data => {
try {
const event = JSON.parse(data.trim())
if (event.WorkspacesChanged) {
workspaceProcess.running = true
} else if (event.WindowsChanged) {
try {
const windowsData = event.WindowsChanged.windows
const windowsList = []
for (const win of windowsData) {
windowsList.push({
"id": win.id,
"title": win.title || "",
"appId": win.app_id || "",
"workspaceId": win.workspace_id || null,
"isFocused": win.is_focused === true
})
}
windowsList.sort((a, b) => a.id - b.id)
root.windows = windowsList
for (var i = 0; i < windowsList.length; i++) {
if (windowsList[i].isFocused) {
root.focusedWindowIndex = i
break
}
}
} catch (e) {
console.error("Error parsing windows event:", e)
}
} else if (event.WorkspaceActivated) {
workspaceProcess.running = true
} else if (event.WindowFocusChanged) {
try {
const focusedId = event.WindowFocusChanged.id
if (focusedId) {
root.focusedWindowIndex = root.windows.findIndex(w => w.id === focusedId)
if (root.focusedWindowIndex < 0) {
root.focusedWindowIndex = 0
}
} else {
root.focusedWindowIndex = -1
}
} catch (e) {
console.error("Error parsing window focus event:", e)
}
} else if (event.OverviewOpenedOrClosed) {
try {
root.inOverview = event.OverviewOpenedOrClosed.is_open === true
} catch (e) {
console.error("Error parsing overview state:", e)
}
}
} catch (e) {
console.error("Error parsing event stream:", e, data)
}
}
}
}
}