-
-
Notifications
You must be signed in to change notification settings - Fork 116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Event stream IPC #453
Event stream IPC #453
Conversation
Hi, when is this planned to be merged? |
No plan yet, this is just scaffolding for now. It's in a too early of a state to get help from others on specific tasks. |
Has that changed yet? I'd be happy to pick up some work too if needed |
I was fairly busy with uni; I think I am about to have sorted most of it out though so I will look into this more soon. |
Update, I did some more sketching out. Now, the following events are implemented: I was able to make a Waybar workspace indicator with the following Python script: #!/usr/bin/python3
import json
import os
import sys
from socket import AF_UNIX, SHUT_WR, socket
niri_socket = socket(AF_UNIX)
niri_socket.connect(os.environ["NIRI_SOCKET"])
file = niri_socket.makefile("rw")
file.write('"EventStream"')
file.flush()
niri_socket.shutdown(SHUT_WR)
output = None
if len(sys.argv) > 1:
output = sys.argv[1]
workspaces = {}
def print_workspaces():
vals = workspaces.values()
if output is not None:
vals = filter(lambda ws: ws["output"] == output, vals)
vals = sorted(vals, key=lambda ws: ws["idx"])
text = "\n".join(("" if ws["is_active"] else "" for ws in vals))
print(json.dumps({"text": text}), flush=True)
for line in file:
event = json.loads(line)
if changed := event.get("WorkspacesChanged"):
workspaces = {ws["id"]: ws for ws in changed["workspaces"]}
print_workspaces()
elif switched := event.get("WorkspaceSwitched"):
for ws in workspaces.values():
if ws["output"] == switched["output"]:
ws["is_active"] = ws["id"] == switched["id"]
print_workspaces() (Note the And this is the custom module setup: "custom/workspaces": {
"exec": "~/source/py/niri-ipc/workspaces.py \"$WAYBAR_OUTPUT_NAME\"",
"return-type": "json"
}, |
I started implementing built-in support in Waybar using this event stream draft PR. You can try my fork here: https://github.com/YaLTeR/Waybar/tree/niri niri-waybar-workspaces.mp4So far I added |
Pushed a breaking change to the IPC to differentiate between active and focused workspaces, Waybar fork also updated. New Python script: #!/usr/bin/python3
import json
import os
import sys
from socket import AF_UNIX, SHUT_WR, socket
niri_socket = socket(AF_UNIX)
niri_socket.connect(os.environ["NIRI_SOCKET"])
file = niri_socket.makefile("rw")
file.write('"EventStream"')
file.flush()
niri_socket.shutdown(SHUT_WR)
output = None
if len(sys.argv) > 1:
output = sys.argv[1]
workspaces = {}
def print_workspaces():
vals = workspaces.values()
if output is not None:
vals = filter(lambda ws: ws["output"] == output, vals)
vals = sorted(vals, key=lambda ws: ws["idx"])
text = "\n".join(("" if ws["is_active"] else "" for ws in vals))
print(json.dumps({"text": text}), flush=True)
for line in file:
event = json.loads(line)
if changed := event.get("WorkspacesChanged"):
workspaces = {ws["id"]: ws for ws in changed["workspaces"]}
print_workspaces()
elif focused := event.get("WorkspaceFocused"):
ws_output = workspaces[focused["id"]]["output"]
for ws in workspaces.values():
got_focused = ws["id"] == focused["id"]
if ws["output"] == ws_output:
ws["is_active"] = got_focused
ws["is_focused"] = got_focused
print_workspaces()
elif activated := event.get("WorkspaceActivated"):
ws_output = workspaces[activated["id"]]["output"]
for ws in workspaces.values():
if ws["output"] == ws_output:
ws["is_active"] = ws["id"] == activated["id"]
print_workspaces() |
Pushed another breaking change, along with an implementation of Window events:
Waybar fork is updated to use this, and also I implemented a This completes my sketching so far; I'm fairly sure that this is enough IPC to cover the remaining window icon support in the workspaces Waybar module (I'm too lazy to implement that), and anything past that should be fairly straightforward to add without breaking changes. That said, I'd like others to take a look at this before merging, give it a try with Waybar or by implementing their own scripts, in case I missed something important. Newest Python workspaces script: #!/usr/bin/python3
import json
import os
import sys
from socket import AF_UNIX, SHUT_WR, socket
niri_socket = socket(AF_UNIX)
niri_socket.connect(os.environ["NIRI_SOCKET"])
file = niri_socket.makefile("rw")
file.write('"EventStream"')
file.flush()
niri_socket.shutdown(SHUT_WR)
output = None
if len(sys.argv) > 1:
output = sys.argv[1]
workspaces = {}
def print_workspaces():
vals = workspaces.values()
if output is not None:
vals = filter(lambda ws: ws["output"] == output, vals)
vals = sorted(vals, key=lambda ws: ws["idx"])
text = "\n".join(("" if ws["is_active"] else "" for ws in vals))
print(json.dumps({"text": text}), flush=True)
for line in file:
event = json.loads(line)
if changed := event.get("WorkspacesChanged"):
workspaces = {ws["id"]: ws for ws in changed["workspaces"]}
print_workspaces()
elif activated := event.get("WorkspaceActivated"):
focused = activated["focused"]
ws_output = workspaces[activated["id"]]["output"]
for ws in workspaces.values():
got_activated = ws["id"] == activated["id"]
if ws["output"] == ws_output:
ws["is_active"] = got_activated
if focused:
ws["is_focused"] = got_activated
print_workspaces() |
Deleting the test because it only made sense when no-animation was special cased.
Let's see if anyone complains.
It's not added to clap because there's no convenient mutually-exclusive argument enum derive yet (to have either the current <REFERENCE> or an --id <ID>). It's not added to config parsing because I don't see how it could be useful there. As such, it's only accessible through raw IPC.
Some basic scaffolding for an event stream IPC.
Changed the client to read only a single line worth of response.
This mirrors how the server works, and will be necessary to tell apart further messages. Events will arrive at one per line.
Added
Request::EventStream
that replies withResponse::Handled
and then proceeds to write oneEvent
per line as they occur.Events will be designed in such a way that the initial burst will synchronize the current state to the client, then subsequent events will modify that state in a consistent way. E.g. the initial burst of events will create all current outputs and workspaces.
Compositor-side, event stream clients have a buffer of events for sending. If this buffer runs too large (the client hanged and isn't reading), this client will be dropped. This is kinda similar to what Wayland itself does.
The events are all subject to change until this PR is merged. Currently only the WindowFocused is actually implemented, and I'm planning to change its type too.