Programmatic clean qube shutdown

I’m writing a utility script which given a qube name will execute a graceful exit of likely processes followed by qvm-shutdown. Several of my app qubes are simple non-disposable hosts of browser + terminals, and this script is mostly intended for that simple case, so it doesn’t need to be too clever.

Both bash and zsh exit gracefully upon SIGHUP, so for them:

qvm-run --pass-io $QUBE 'pkill --signal HUP -x "\<bash\>"' || true
qvm-run --pass-io $QUBE 'pkill --signal HUP -x "\<zsh\>"' || true

(I think the -x helps isolate the signal to interactive shells- imperfectly, but good enough)

Google Chrome appears to make a clean exit upon SIGTERM, so:

qvm-run --pass-io $QUBE 'pgrep -x chrome >/dev/null 2>&1 && pkill --oldest --signal TERM -x chrome' || true

Firefox also:

qvm-run --pass-io $QUBE 'pgrep firefox >/dev/null 2>&1 && pkill --oldest --signal TERM firefox' || true

Tor Browser is trickier. If I kill it in the same way as for Firefox, I get a warning popup after the browser exits. I can circumvent this by first killing the torbrowser parent process, but the workaround makes the whole approach feel skeevy and I wish for a more robust solution.

I was thinking I could simulate a normal, user-initiated exit by sending a Ctrl-Q key with xdotool from dom0:

xdotool search --onlyvisible --class "${QUBE}.*Tor Browser" key --window '%1' ctrl+q

Alas, though the search works the key appears to be ignored by the browser window. Maybe it would work running xdotool within the qube itself, but not all these qubes have xdotool installed (notably e.g. whonix-workstation-17).

Does someone have advice for a better way to programmatically exit Tor Browser specifically, or browsers more generally, or app VMs even more generally?

I found this QoL post linking to this script:

And I tested that Tor Browser similarly can be exited by way of a local xdotool invocation:

[app-qube]$ xdotool search --onlyvisible --name 'Tor Browser' key --window '%1' ctrl+q

But I’d still prefer philosophically to leave the Whonix template unmodified, no additional xdotool package. It’s unfortunate that sending the Ctrl-Q to the remote window on dom0 doesn’t appear to propagate the key to the app qube’s X session.