summaryrefslogtreecommitdiff
path: root/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml')
-rw-r--r--accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml203
1 files changed, 203 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..58201bd2
--- /dev/null
+++ b/accounts/gkleen@sif/shell/quickshell/Services/NiriService.qml
@@ -0,0 +1,203 @@
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 function refreshOutputs() {
17 commandSocket.sendCommand("Outputs", data => {
18 outputs = data.Ok.Outputs;
19 });
20 }
21
22 function sendCommand(command, callback) {
23 commandSocket.sendCommand(command, callback);
24 }
25
26 Socket {
27 id: eventStreamSocket
28 path: root.socketPath
29 connected: true
30
31 property bool acked: false
32
33 onConnectionStateChanged: {
34 if (connected) {
35 acked = false;
36 write('"EventStream"\n');
37 }
38 }
39
40 parser: SplitParser {
41 onRead: line => {
42 try {
43 const event = JSON.parse(line)
44
45 // console.log(JSON.stringify(event))
46
47 if (event.WorkspacesChanged) {
48 root.workspaces = event.WorkspacesChanged.workspaces
49 root.refreshOutputs();
50 } else if (event.WorkspaceActivated)
51 eventWorkspaceActivated(event.WorkspaceActivated);
52 else if (event.WorkspaceUrgencyChanged)
53 eventWorkspaceUrgencyChanged(event.WorkspaceUrgencyChanged);
54 else if (event.WorkspaceActiveWindowChanged)
55 eventWorkspaceActiveWindowChanged(event.WorkspaceActiveWindowChanged);
56 else if (event.KeyboardLayoutsChanged)
57 root.keyboardLayouts = event.KeyboardLayoutsChanged.keyboard_layouts;
58 else if (event.KeyboardLayoutSwitched)
59 root.keyboardLayouts = Object.assign({}, root.keyboardLayouts, {"current_idx": event.KeyboardLayoutSwitched.idx });
60 else if (event.WindowsChanged)
61 root.windows = event.WindowsChanged.windows
62 else if (event.WindowOpenedOrChanged)
63 eventWindowOpenedOrChanged(event.WindowOpenedOrChanged);
64 else if (event.WindowClosed)
65 eventWindowClosed(event.WindowClosed);
66 else if (event.WindowFocusChanged)
67 eventWindowFocusChanged(event.WindowFocusChanged);
68 else if (event.WindowUrgencyChanged)
69 eventWindowUrgencyChanged(event.WindowUrgencyChanged);
70 else if (event.WindowLayoutsChanged)
71 eventWindowLayoutsChanged(event.WindowLayoutsChanged);
72 else if (event.WindowFocusTimestampChanged)
73 eventWindowFocusTimestampChanged(event.WindowFocusTimestampChanged);
74 else if (event.Ok && !eventStreamSocket.acked) { eventStreamSocket.acked = true; }
75 else if (event.OverviewOpenedOrClosed) {}
76 else if (event.ConfigLoaded) {}
77 else
78 console.log(JSON.stringify(event));
79 } catch (e) {
80 console.warn("NiriService: Failed to parse event:", line, e)
81 }
82 }
83 }
84 }
85
86 Socket {
87 id: commandSocket
88 path: root.socketPath
89 connected: true
90
91 property var awaitingAnswer: null
92 property var cmdQueue: []
93
94 parser: SplitParser {
95 onRead: line => {
96 if (commandSocket.awaitingAnswer === null)
97 return;
98
99 try {
100 const response = JSON.parse(line);
101 commandSocket.awaitingAnswer.callback(response);
102 commandSocket.awaitingAnswer = null;
103 } catch (e) {
104 console.warn("NiriService: Failed to parse response:", line, e)
105 }
106 commandSocket._handleQueue();
107 }
108 }
109
110 onCmdQueueChanged: {
111 _handleQueue();
112 }
113 onAwaitingAnswerChanged: {
114 _handleQueue();
115 }
116
117 function _handleQueue() {
118 if (cmdQueue.length <= 0 || awaitingAnswer !== null)
119 return;
120
121 let localQueue = Array.from(cmdQueue);
122 awaitingAnswer = localQueue.shift();
123 cmdQueue = localQueue;
124 write(JSON.stringify(awaitingAnswer.command) + '\n');
125 }
126
127 function sendCommand(command, callback) {
128 cmdQueue = Array.from(cmdQueue).concat([{ "command": command, "callback": callback }])
129 }
130 }
131
132 function eventWorkspaceActivated(data) {
133 let relevant_output = null;
134 Array.from(root.workspaces).forEach(ws => {
135 if (data.id === ws.id)
136 relevant_output = ws.output;
137 });
138 root.workspaces = Array.from(root.workspaces).map(ws => {
139 if (data.focused)
140 ws.is_focused = false;
141 if (ws.output === relevant_output)
142 ws.is_active = false;
143 if (data.id === ws.id) {
144 ws.is_active = true;
145 ws.is_focused = data.focused;
146 }
147 return ws;
148 });
149 }
150 function eventWorkspaceUrgencyChanged(data) {
151 root.workspaces = Array.from(root.workspaces).map(ws => {
152 if (data.id == ws.id)
153 ws.is_urgent = data.urgent;
154 return ws;
155 });
156 }
157 function eventWorkspaceActiveWindowChanged(data) {
158 root.workspaces = Array.from(root.workspaces).map(ws => {
159 if (data.workspace_id === ws.id)
160 ws.active_window_id = data.active_window_id;
161 return ws;
162 });
163 }
164 function eventWindowOpenedOrChanged(data) {
165 root.windows = Array.from(root.windows).map(win => {
166 if (data.window.is_focused)
167 win.is_focused = false;
168 return win;
169 }).filter(win => win.id !== data.window.id).concat([data.window]);
170 }
171 function eventWindowClosed(data) {
172 root.windows = Array.from(root.windows).filter(win => win.id !== data.id);
173 }
174 function eventWindowFocusChanged(data) {
175 root.windows = Array.from(root.windows).map(win => {
176 win.is_focused = win.id === data.id;
177 return win;
178 });
179 }
180 function eventWindowUrgencyChanged(data) {
181 root.windows = Array.from(root.windows).map(win => {
182 if (win.id === data.id)
183 win.is_urgent = data.urgent;
184 return win;
185 });
186 }
187 function eventWindowLayoutsChanged(data) {
188 root.windows = Array.from(root.windows).map(win => {
189 Array.from(data.changes).forEach(change => {
190 if (win.id === change[0])
191 win.layout = change[1];
192 });
193 return win;
194 });
195 }
196 function eventWindowFocusTimestampChanged(data) {
197 root.windows = Array.from(root.windows).map(win => {
198 if (win.id === data.id)
199 win.focus_timestamp = data.focus_timestamp;
200 return win;
201 });
202 }
203}