diff options
author | Gregor Kleen <gkleen@yggdrasil.li> | 2025-05-14 13:30:26 +0200 |
---|---|---|
committer | Gregor Kleen <gkleen@yggdrasil.li> | 2025-05-14 13:30:26 +0200 |
commit | 5818cc9c1ecb5e0df7cb1aac154edf6d855ee986 (patch) | |
tree | d8b2b38d9d253b9da6fc692456d2e9ece88b6bff | |
parent | f50a110e2120177d692b61493cb9c58f908cfff8 (diff) | |
download | nixos-5818cc9c1ecb5e0df7cb1aac154edf6d855ee986.tar nixos-5818cc9c1ecb5e0df7cb1aac154edf6d855ee986.tar.gz nixos-5818cc9c1ecb5e0df7cb1aac154edf6d855ee986.tar.bz2 nixos-5818cc9c1ecb5e0df7cb1aac154edf6d855ee986.tar.xz nixos-5818cc9c1ecb5e0df7cb1aac154edf6d855ee986.zip |
...
-rw-r--r-- | accounts/gkleen@sif/niri/default.nix | 88 |
1 files changed, 49 insertions, 39 deletions
diff --git a/accounts/gkleen@sif/niri/default.nix b/accounts/gkleen@sif/niri/default.nix index 7254b7ed..3f506d52 100644 --- a/accounts/gkleen@sif/niri/default.nix +++ b/accounts/gkleen@sif/niri/default.nix | |||
@@ -245,7 +245,7 @@ in { | |||
245 | Service = { | 245 | Service = { |
246 | Type = "simple"; | 246 | Type = "simple"; |
247 | Sockets = [ "niri-workspace-history.socket" ]; | 247 | Sockets = [ "niri-workspace-history.socket" ]; |
248 | ExecStart = pkgs.writers.writePython3 "niri-workspace-history" {} '' | 248 | ExecStart = pkgs.writers.writePython3 "niri-workspace-history" { flakeIgnore = ["E501"]; } '' |
249 | import os | 249 | import os |
250 | import socket | 250 | import socket |
251 | import json | 251 | import json |
@@ -274,7 +274,7 @@ in { | |||
274 | 274 | ||
275 | def focus_workspace(output, workspace): | 275 | def focus_workspace(output, workspace): |
276 | with history_lock: | 276 | with history_lock: |
277 | workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace] # noqa: E501 | 277 | workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace] |
278 | # print(json.dumps(workspace_history), file=sys.stderr) | 278 | # print(json.dumps(workspace_history), file=sys.stderr) |
279 | 279 | ||
280 | sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) | 280 | sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
@@ -297,14 +297,14 @@ in { | |||
297 | 297 | ||
298 | class RequestHandler(StreamRequestHandler): | 298 | class RequestHandler(StreamRequestHandler): |
299 | def handle(self): | 299 | def handle(self): |
300 | with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out: # noqa: E501 | 300 | with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out: |
301 | with history_lock: | 301 | with history_lock: |
302 | json.dump(workspace_history, out) | 302 | json.dump(workspace_history, out) |
303 | 303 | ||
304 | 304 | ||
305 | class Server(ThreadingTCPServer): | 305 | class Server(ThreadingTCPServer): |
306 | def __init__(self): | 306 | def __init__(self): |
307 | ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False) # noqa: E501 | 307 | ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False) |
308 | self.socket = socket.fromfd(3, self.address_family, self.socket_type) | 308 | self.socket = socket.fromfd(3, self.address_family, self.socket_type) |
309 | 309 | ||
310 | 310 | ||
@@ -349,45 +349,55 @@ in { | |||
349 | outputs = None | 349 | outputs = None |
350 | only = {'HDMI-A-1': {'bmr'}, 'eDP-1': {'vid'}} | 350 | only = {'HDMI-A-1': {'bmr'}, 'eDP-1': {'vid'}} |
351 | 351 | ||
352 | with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as cmd_sock, socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as sock: | ||
353 | cmd_sock.connect(os.environ["NIRI_SOCKET"]) | ||
354 | with cmd_sock.makefile(mode='w', buffering=1, encoding='utf-8') as fh: | ||
355 | sock.connect(os.environ["NIRI_SOCKET"]) | ||
356 | sock.send(b"\"EventStream\"\n") | ||
357 | for line in sock.makefile(buffering=1, encoding='utf-8'): | ||
358 | workspaces = None | ||
359 | if line_json := json.loads(line): | ||
360 | if "WorkspacesChanged" in line_json: | ||
361 | workspaces = line_json["WorkspacesChanged"]["workspaces"] | ||
362 | |||
363 | if workspaces is None: | ||
364 | continue | ||
365 | 352 | ||
366 | old_outputs = outputs | 353 | class Niri(socket.socket): |
367 | outputs = {ws["output"] for ws in workspaces} | 354 | def __init__(self): |
368 | if old_outputs is None: | 355 | super().__init__(socket.AF_UNIX, socket.SOCK_STREAM) |
369 | print("Initial outputs: {}".format(outputs), file=sys.stderr) | 356 | super().connect(os.environ["NIRI_SOCKET"]) |
370 | continue | 357 | self.fh = super().makefile(mode='rw', buffering=1, encoding='utf-8') |
358 | |||
359 | def cmd(self, obj): | ||
360 | print(json.dumps(obj, separators=(',', ':')), flush=True, file=self.fh) | ||
361 | |||
362 | def event_stream(self): | ||
363 | self.cmd("EventStream") | ||
364 | return self.fh | ||
371 | 365 | ||
372 | new_outputs = outputs - old_outputs | ||
373 | if not new_outputs: | ||
374 | continue | ||
375 | print("New outputs: {}".format(new_outputs), file=sys.stderr) | ||
376 | 366 | ||
377 | relevant_workspaces = list(filter(lambda ws: (ws["name"] is not None) or (ws["active_window_id"] is not None), workspaces)) | 367 | with Niri() as niri, Niri().event_stream() as niri_stream: |
378 | target_output = next(iter(outputs - set(only.keys()))) | 368 | for line in niri_stream: |
379 | if not target_output: | 369 | workspaces = None |
370 | if line_json := json.loads(line): | ||
371 | if "WorkspacesChanged" in line_json: | ||
372 | workspaces = line_json["WorkspacesChanged"]["workspaces"] | ||
373 | |||
374 | if workspaces is None: | ||
375 | continue | ||
376 | |||
377 | old_outputs = outputs | ||
378 | outputs = {ws["output"] for ws in workspaces} | ||
379 | if old_outputs is None: | ||
380 | print("Initial outputs: {}".format(outputs), file=sys.stderr) | ||
381 | continue | ||
382 | |||
383 | new_outputs = outputs - old_outputs | ||
384 | if not new_outputs: | ||
385 | continue | ||
386 | print("New outputs: {}".format(new_outputs), file=sys.stderr) | ||
387 | |||
388 | relevant_workspaces = list(filter(lambda ws: (ws["name"] is not None) or (ws["active_window_id"] is not None), workspaces)) | ||
389 | target_output = next(iter(outputs - set(only.keys()))) | ||
390 | if not target_output: | ||
391 | continue | ||
392 | for ws in relevant_workspaces: | ||
393 | ws_ident = ws["name"] if ws["name"] is not None else (ws["output"], ws["idx"]) | ||
394 | if ws["output"] not in set(only.keys()): | ||
395 | continue | ||
396 | if ws_ident in only[ws["output"]]: | ||
380 | continue | 397 | continue |
381 | for ws in relevant_workspaces: | 398 | |
382 | ws_ident = ws["name"] if ws["name"] is not None else (ws["output"], ws["idx"]) | 399 | print("{} -> {}".format(ws_ident, target_output), file=sys.stderr) |
383 | if ws["output"] not in set(only.keys()): | 400 | niri.cmd({"Action": {"MoveWorkspaceToMonitor": {"reference": {"Id": ws["id"]}, "output": target_output}}}) |
384 | continue | ||
385 | if ws_ident in only[ws["output"]]: | ||
386 | continue | ||
387 | |||
388 | print("{} -> {}".format(ws_ident, target_output), file=sys.stderr) | ||
389 | cmd = json.dumps({"Action": {"MoveWorkspaceToMonitor": {"reference": {"Id": ws["id"]}, "output": target_output}}}, separators=(',', ':')) | ||
390 | print(cmd, flush=True, file=fh) | ||
391 | ''; | 401 | ''; |
392 | Restart = "on-failure"; | 402 | Restart = "on-failure"; |
393 | RestartSec = 10; | 403 | RestartSec = 10; |