From 44952654e8ed60c6189d6ff49789d678e5bea382 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Wed, 29 Jan 2025 17:29:45 +0100 Subject: ... --- accounts/gkleen@sif/niri/default.nix | 111 ++++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) (limited to 'accounts/gkleen@sif/niri/default.nix') 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 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")" active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")" - workspace_json="$(jq -c --arg active_output "$active_output" 'map(select(.output == $active_output and .name == null)) | sort_by(.idx) | .[0]' <<<"$workspaces_json")" + history_json="$(socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/niri-workspace-history.sock)" + 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")" [[ -n $workspace_json && $workspace_json != null ]] || exit 0 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET" ''; @@ -156,6 +157,113 @@ in { ]; }; + systemd.user.sockets.niri-workspace-history = { + Socket = { + ListenStream = "%t/niri-workspace-history.sock"; + SocketMode = "0600"; + }; + }; + systemd.user.services.niri-workspace-history = { + Unit = { + BindsTo = [ "niri.service" ]; + After = [ "niri.service" ]; + }; + Install = { + WantedBy = [ "niri.service" ]; + }; + Service = { + Type = "simple"; + Sockets = [ "niri-workspace-history.socket" ]; + ExecStart = pkgs.writers.writePython3 "niri-workspace-history" {} '' + import os + import socket + import json + import sys + from collections import defaultdict + from threading import Thread, Lock + from socketserver import StreamRequestHandler, ThreadingTCPServer + from contextlib import contextmanager + from io import TextIOWrapper + + + @contextmanager + def detaching(thing): + try: + yield thing + finally: + thing.detach() + + + workspace_history = defaultdict(list) + history_lock = Lock() + + + def monitor_niri(): + workspaces = list() + + def focus_workspace(output, workspace): + global workspace_history, history_lock + + with history_lock: + workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace] # noqa: E501 + print(json.dumps(workspace_history), file=sys.stderr) + + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + sock.connect(os.environ["NIRI_SOCKET"]) + sock.send(b"\"EventStream\"\n") + for line in sock.makefile(buffering=1, encoding='utf-8'): + if line_json := json.loads(line): + if "WorkspacesChanged" in line_json: + workspaces = line_json["WorkspacesChanged"]["workspaces"] + for ws in workspaces: + if ws["is_focused"]: + focus_workspace(ws["output"], ws["id"]) + if "WorkspaceActivated" in line_json: + for ws in workspaces: + if ws["id"] != line_json["WorkspaceActivated"]["id"]: + continue + focus_workspace(ws["output"], ws["id"]) + break + + + class RequestHandler(StreamRequestHandler): + def handle(self): + global workspace_history, history_lock + + with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out: # noqa: E501 + with history_lock: + json.dump(workspace_history, out) + + + class Server(ThreadingTCPServer): + def __init__(self): + ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False) # noqa: E501 + self.socket = socket.fromfd(3, self.address_family, self.socket_type) + + + def run_server(): + with Server() as server: + server.serve_forever() + + + niri = Thread(target=monitor_niri) + niri.daemon = True + niri.start() + + server_thread = Thread(target=run_server) + server_thread.daemon = True + server_thread.start() + + while True: + server_thread.join(timeout=0.5) + niri.join(timeout=0.5) + + if not (niri.is_alive() and server_thread.is_alive()): + break + ''; + }; + }; + programs.niri.settings = { prefer-no-csd = true; screenshot-path = "${config.home.homeDirectory}/screenshots"; @@ -209,6 +317,7 @@ in { animations = { slowdown = 0.5; + workspace-switch = null; }; layout = { -- cgit v1.2.3