diff options
| -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; |
