summaryrefslogtreecommitdiff
path: root/accounts/gkleen@sif/niri/default.nix
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2025-01-29 17:29:45 +0100
committerGregor Kleen <gkleen@yggdrasil.li>2025-01-29 17:29:45 +0100
commit44952654e8ed60c6189d6ff49789d678e5bea382 (patch)
tree60a5b81bc73f3defb29c2b9a134bff8b7fe36780 /accounts/gkleen@sif/niri/default.nix
parent06768b562ed4e6db85b3fdf0530b136b37511a1f (diff)
downloadnixos-44952654e8ed60c6189d6ff49789d678e5bea382.tar
nixos-44952654e8ed60c6189d6ff49789d678e5bea382.tar.gz
nixos-44952654e8ed60c6189d6ff49789d678e5bea382.tar.bz2
nixos-44952654e8ed60c6189d6ff49789d678e5bea382.tar.xz
nixos-44952654e8ed60c6189d6ff49789d678e5bea382.zip
...
Diffstat (limited to 'accounts/gkleen@sif/niri/default.nix')
-rw-r--r--accounts/gkleen@sif/niri/default.nix111
1 files changed, 110 insertions, 1 deletions
diff --git a/accounts/gkleen@sif/niri/default.nix b/accounts/gkleen@sif/niri/default.nix
index bfc32254..ca2dfeff 100644
--- a/accounts/gkleen@sif/niri/default.nix
+++ b/accounts/gkleen@sif/niri/default.nix
@@ -89,7 +89,8 @@ let
89 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")" 89 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
90 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")" 90 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")"
91 91
92 workspace_json="$(jq -c --arg active_output "$active_output" 'map(select(.output == $active_output and .name == null)) | sort_by(.idx) | .[0]' <<<"$workspaces_json")" 92 history_json="$(socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/niri-workspace-history.sock)"
93 workspace_json="$(jq -c --arg active_output "$active_output" --argjson history "$history_json" 'map(select(.output == $active_output and .name == null)) | map({"value": ., "history_idx": ((. as $workspace | ($history[$active_output] | index($workspace | .id))) as $active_idx | if $active_idx then $active_idx else ($history[$active_output] | length) + 1 end)}) | sort_by(.history_idx, .value.idx) | map(.value) | .[0]' <<<"$workspaces_json")"
93 [[ -n $workspace_json && $workspace_json != null ]] || exit 0 94 [[ -n $workspace_json && $workspace_json != null ]] || exit 0
94 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET" 95 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
95 ''; 96 '';
@@ -156,6 +157,113 @@ in {
156 ]; 157 ];
157 }; 158 };
158 159
160 systemd.user.sockets.niri-workspace-history = {
161 Socket = {
162 ListenStream = "%t/niri-workspace-history.sock";
163 SocketMode = "0600";
164 };
165 };
166 systemd.user.services.niri-workspace-history = {
167 Unit = {
168 BindsTo = [ "niri.service" ];
169 After = [ "niri.service" ];
170 };
171 Install = {
172 WantedBy = [ "niri.service" ];
173 };
174 Service = {
175 Type = "simple";
176 Sockets = [ "niri-workspace-history.socket" ];
177 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" {} ''
178 import os
179 import socket
180 import json
181 import sys
182 from collections import defaultdict
183 from threading import Thread, Lock
184 from socketserver import StreamRequestHandler, ThreadingTCPServer
185 from contextlib import contextmanager
186 from io import TextIOWrapper
187
188
189 @contextmanager
190 def detaching(thing):
191 try:
192 yield thing
193 finally:
194 thing.detach()
195
196
197 workspace_history = defaultdict(list)
198 history_lock = Lock()
199
200
201 def monitor_niri():
202 workspaces = list()
203
204 def focus_workspace(output, workspace):
205 global workspace_history, history_lock
206
207 with history_lock:
208 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace] # noqa: E501
209 print(json.dumps(workspace_history), file=sys.stderr)
210
211 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
212 sock.connect(os.environ["NIRI_SOCKET"])
213 sock.send(b"\"EventStream\"\n")
214 for line in sock.makefile(buffering=1, encoding='utf-8'):
215 if line_json := json.loads(line):
216 if "WorkspacesChanged" in line_json:
217 workspaces = line_json["WorkspacesChanged"]["workspaces"]
218 for ws in workspaces:
219 if ws["is_focused"]:
220 focus_workspace(ws["output"], ws["id"])
221 if "WorkspaceActivated" in line_json:
222 for ws in workspaces:
223 if ws["id"] != line_json["WorkspaceActivated"]["id"]:
224 continue
225 focus_workspace(ws["output"], ws["id"])
226 break
227
228
229 class RequestHandler(StreamRequestHandler):
230 def handle(self):
231 global workspace_history, history_lock
232
233 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out: # noqa: E501
234 with history_lock:
235 json.dump(workspace_history, out)
236
237
238 class Server(ThreadingTCPServer):
239 def __init__(self):
240 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False) # noqa: E501
241 self.socket = socket.fromfd(3, self.address_family, self.socket_type)
242
243
244 def run_server():
245 with Server() as server:
246 server.serve_forever()
247
248
249 niri = Thread(target=monitor_niri)
250 niri.daemon = True
251 niri.start()
252
253 server_thread = Thread(target=run_server)
254 server_thread.daemon = True
255 server_thread.start()
256
257 while True:
258 server_thread.join(timeout=0.5)
259 niri.join(timeout=0.5)
260
261 if not (niri.is_alive() and server_thread.is_alive()):
262 break
263 '';
264 };
265 };
266
159 programs.niri.settings = { 267 programs.niri.settings = {
160 prefer-no-csd = true; 268 prefer-no-csd = true;
161 screenshot-path = "${config.home.homeDirectory}/screenshots"; 269 screenshot-path = "${config.home.homeDirectory}/screenshots";
@@ -209,6 +317,7 @@ in {
209 317
210 animations = { 318 animations = {
211 slowdown = 0.5; 319 slowdown = 0.5;
320 workspace-switch = null;
212 }; 321 };
213 322
214 layout = { 323 layout = {