Dotfiles/desktopenvs/hyprdrive/orbit-menu/actions.py

70 lines
2.5 KiB
Python

"""Side-effecting helpers shared by menu_tree.py's leaf actions.
Everything here fires-and-forgets via Gio.Subprocess (lib.proc.fire) so a click
never blocks the GTK main loop or the menu's close animation.
Per-window ops use two different mechanisms on purpose:
* focus / bring-here go through `hyprctl dispatch "hl.dsp...."` — hyprlua's own
Lua-eval dispatch layer, the same one astal-menu/ui/taskbar.py already uses in
production for exactly this (see its _focus/_pull).
* close / force-kill go through plain native Hyprland dispatchers (`closewindow
address:...`) and a bare `kill -9 <pid>`, which work regardless of the Lua
layer and don't require guessing whether hl.dsp.window exposes a close-by-
address form.
"""
from __future__ import annotations
from lib.proc import fire
def launch(cmd: str) -> None:
"""Run cmd via Hyprland's exec dispatcher — cmd may carry a `[tag ...]` /
`[workspace ...]` window-rule-on-launch prefix, same as binds.lua.
NB: `hyprctl dispatch` evaluates its argument as Lua here (hyprlua), so this
must go through `hl.dsp.exec_cmd(...)` — NOT the native `dispatch exec <cmd>`
form, which Lua parses as a syntax error and silently drops (see binds.lua's
`hl.dsp.exec_cmd("[tag +mixer] ...")`)."""
esc = cmd.replace("\\", "\\\\").replace('"', '\\"')
fire(["hyprctl", "dispatch", f'hl.dsp.exec_cmd("{esc}")'])
def hyprshutdown(post_cmd: str | None = None) -> None:
if post_cmd:
fire(["hyprshutdown", "-p", post_cmd])
else:
fire(["hyprshutdown"])
def _dispatch_lua(lua: str) -> None:
fire(["hyprctl", "dispatch", lua])
def focus_window(address: str) -> None:
_dispatch_lua(f'hl.dsp.focus({{ window = "address:{address}" }})')
def bring_here(address: str, active_ws: int) -> None:
_dispatch_lua(f'hl.dsp.window.move({{ window = "address:{address}", '
f'workspace = {active_ws} }})')
def send_to_workspace(address: str, workspace_id: int) -> None:
_dispatch_lua(f'hl.dsp.window.move({{ window = "address:{address}", '
f'workspace = {workspace_id}, silent = true }})')
def close_window(address: str) -> None:
fire(["hyprctl", "dispatch", "closewindow", f"address:{address}"])
def force_kill(pid: int) -> None:
fire(["kill", "-9", str(pid)])
def report_pid(pid: int, title: str) -> None:
fire(["wl-copy", str(pid)])
fire(["notify-send", "-a", "orbit-menu", f"PID {pid}",
f"{title} — copied to clipboard"])