tabbed-casilda/tabbed-run
Andrew Hamilton 7a35873e60 Run tabbed-run commands via exec so they block like a normal foreground command
tabbed-run now requests a new tab, blocks for a reply containing the tab id
and the compositor's Wayland socket path, then execs the command with
WAYLAND_DISPLAY pointing at the new tab.  The command's stdout/stderr and
exit status stay in the invoking tab.  Each compositor gets a stable socket
path under XDG_RUNTIME_DIR; startup tabs still use spawn_async against that
path.
2026-08-13 12:36:19 +10:00

49 lines
1.4 KiB
Python
Executable file

#!/usr/bin/env python3
import os
import socket
import sys
from tabbed_protocol import serialize, parse_reply
ctrl = os.environ.get("TABBED_CASILDA_CTRL")
if not ctrl:
print(
"tabbed-run: TABBED_CASILDA_CTRL not set (run inside a tabbed-casilda terminal)",
file=sys.stderr,
)
sys.exit(1)
if len(sys.argv) < 2:
print("usage: tabbed-run COMMAND [ARGS...]", file=sys.stderr)
sys.exit(1)
creator_id = os.environ.get("TABBED_CASILDA_TAB_ID", "")
payload = serialize(creator_id, sys.argv[1:])
try:
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
s.connect(ctrl)
s.sendall(payload)
data = b""
while True:
chunk = s.recv(4096)
if not chunk:
break
data += chunk
except OSError as e:
print(f"tabbed-run: cannot reach host: {e}", file=sys.stderr)
sys.exit(1)
tab_id, socket_path = parse_reply(data.decode())
if not socket_path:
print("tabbed-run: no socket path in reply from host", file=sys.stderr)
sys.exit(1)
env = dict(os.environ)
env["WAYLAND_DISPLAY"] = socket_path
env["TABBED_CASILDA_TAB_ID"] = str(tab_id) if tab_id is not None else ""
env["G_APPLICATION_NON_UNIQUE"] = "1"
try:
os.execvpe(sys.argv[1], sys.argv[1:], env)
except OSError as e:
print(f"tabbed-run: cannot exec {sys.argv[1]}: {e}", file=sys.stderr)
sys.exit(127)