summaryrefslogtreecommitdiff
path: root/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2025-08-30 22:07:54 +0200
committerGregor Kleen <gkleen@yggdrasil.li>2025-08-30 22:07:54 +0200
commit45a1316bf1df6ec32a133f8e648bbac0bbc988d6 (patch)
tree4b268e50fef8c0f61e64a2685cb51f421d9e7fc8 /accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml
parentc3a8a171734bfeced58f4611365e85a6daed7db9 (diff)
downloadnixos-45a1316bf1df6ec32a133f8e648bbac0bbc988d6.tar
nixos-45a1316bf1df6ec32a133f8e648bbac0bbc988d6.tar.gz
nixos-45a1316bf1df6ec32a133f8e648bbac0bbc988d6.tar.bz2
nixos-45a1316bf1df6ec32a133f8e648bbac0bbc988d6.tar.xz
nixos-45a1316bf1df6ec32a133f8e648bbac0bbc988d6.zip
...
Diffstat (limited to 'accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml')
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml190
1 files changed, 190 insertions, 0 deletions
diff --git a/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml b/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml
new file mode 100644
index 00000000..914152e1
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml
@@ -0,0 +1,190 @@
1pragma Singleton
2
3import Quickshell
4import Quickshell.Io
5import QtQuick
6
7Singleton {
8 id: root
9
10 property var workspaces: []
11 property var outputs: {}
12 property var keyboardLayouts: {}
13 property var windows: []
14 readonly property string socketPath: Quickshell.env("NIRI_SOCKET")
15
16 onKeyboardLayoutsChanged: {
17 console.log(JSON.stringify(keyboardLayouts));
18 }
19
20 function refreshOutputs() {
21 commandSocket.sendCommand("Outputs", data => {
22 outputs = data.Ok.Outputs;
23 });
24 }
25
26 function sendCommand(command, callback) {
27 commandSocket.sendCommand(command, callback);
28 }
29
30 Socket {
31 id: eventStreamSocket
32 path: root.socketPath
33 connected: true
34
35 onConnectionStateChanged: {
36 if (connected) {
37 write('"EventStream"\n')
38 }
39 }
40
41 parser: SplitParser {
42 onRead: line => {
43 try {
44 const event = JSON.parse(line)
45
46 // console.log(JSON.stringify(event))
47
48 if (event.WorkspacesChanged) {
49 root.workspaces = event.WorkspacesChanged.workspaces
50 root.refreshOutputs();
51 } else if (event.WorkspaceActivated)
52 eventWorkspaceActivated(event.WorkspaceActivated);
53 else if (event.WorkspaceUrgencyChanged)
54 eventWorkspaceUrgencyChanged(event.WorkspaceUrgencyChanged);
55 else if (event.WorkspaceActiveWindowChanged)
56 eventWorkspaceActiveWindowChanged(event.WorkspaceActiveWindowChanged);
57 else if (event.KeyboardLayoutsChanged)
58 root.keyboardLayouts = event.KeyboardLayoutsChanged.keyboard_layouts;
59 else if (event.KeyboardLayoutSwitched)
60 root.keyboardLayouts = Object.assign({}, root.keyboardLayouts, {"current_idx": event.KeyboardLayoutSwitched.idx });
61 else if (event.WindowsChanged)
62 root.windows = event.WindowsChanged.windows
63 else if (event.WindowOpenedOrChanged)
64 eventWindowOpenedOrChanged(event.WindowOpenedOrChanged);
65 else if (event.WindowClosed)
66 eventWindowClosed(event.WindowClosed);
67 else if (event.WindowFocusChanged)
68 eventWindowFocusChanged(event.WindowFocusChanged);
69 else if (event.WindowUrgencyChanged)
70 eventWindowUrgencyChanged(event.WindowUrgencyChanged);
71 else if (event.WindowLayoutsChanged)
72 eventWindowLayoutsChanged(event.WindowLayoutsChanged);
73 } catch (e) {
74 console.warn("NiriService: Failed to parse event:", line, e)
75 }
76 }
77 }
78 }
79
80 Socket {
81 id: commandSocket
82 path: root.socketPath
83 connected: true
84
85 property var awaitingAnswer: null
86 property var cmdQueue: []
87
88 parser: SplitParser {
89 onRead: line => {
90 if (commandSocket.awaitingAnswer === null)
91 return;
92
93 try {
94 const response = JSON.parse(line);
95 commandSocket.awaitingAnswer.callback(response);
96 commandSocket.awaitingAnswer = null;
97 } catch (e) {
98 console.warn("NiriService: Failed to parse response:", line, e)
99 }
100 commandSocket._handleQueue();
101 }
102 }
103
104 onCmdQueueChanged: {
105 _handleQueue();
106 }
107 onAwaitingAnswerChanged: {
108 _handleQueue();
109 }
110
111 function _handleQueue() {
112 if (cmdQueue.length <= 0 || awaitingAnswer !== null)
113 return;
114
115 let localQueue = Array.from(cmdQueue);
116 awaitingAnswer = localQueue.shift();
117 cmdQueue = localQueue;
118 write(JSON.stringify(awaitingAnswer.command) + '\n');
119 }
120
121 function sendCommand(command, callback) {
122 cmdQueue = Array.from(cmdQueue).concat([{ "command": command, "callback": callback }])
123 }
124 }
125
126 function eventWorkspaceActivated(data) {
127 let relevant_output = null;
128 Array.from(root.workspaces).forEach(ws => {
129 if (data.id === ws.id)
130 relevant_output = ws.output;
131 });
132 root.workspaces = Array.from(root.workspaces).map(ws => {
133 if (ws.output === relevant_output) {
134 ws.is_active = false;
135 ws.is_focused = false;
136 }
137 if (data.id === ws.id) {
138 ws.is_active = true;
139 ws.is_focused = data.focused;
140 }
141 return ws;
142 });
143 }
144 function eventWorkspaceUrgencyChanged(data) {
145 root.workspaces = Array.from(root.workspaces).map(ws => {
146 if (data.id == ws.id)
147 ws.is_urgent = data.urgent;
148 return ws;
149 });
150 }
151 function eventWorkspaceActiveWindowChanged(data) {
152 root.workspaces = Array.from(root.workspaces).map(ws => {
153 if (data.workspace_id === ws.id)
154 ws.active_window_id = data.active_window_id;
155 return ws;
156 });
157 }
158 function eventWindowOpenedOrChanged(data) {
159 root.windows = Array.from(root.windows).map(win => {
160 if (win.id === data.window.id)
161 return data.window;
162 return win;
163 });
164 }
165 function eventWindowClosed(data) {
166 root.windows = Array.from(root.windows).filter(win => win.id !== data.id);
167 }
168 function eventWindowFocusChanged(data) {
169 root.windows = Array.from(root.windows).map(win => {
170 win.is_focused = win.id === data.id;
171 return win;
172 });
173 }
174 function eventWindowUrgencyChanged(data) {
175 root.windows = Array.from(root.windows).map(win => {
176 if (win.id === data.id)
177 win.is_urgent = data.urgent;
178 return win;
179 });
180 }
181 function eventWindowLayoutsChanged(data) {
182 root.windows = Array.from(root.windows).map(win => {
183 Array.from(data.changes).forEach(change => {
184 if (win.id === change[0])
185 win.layout = change[1];
186 });
187 return win;
188 });
189 }
190}