Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 162 additions & 31 deletions qubes-i3-sensible-terminal
Original file line number Diff line number Diff line change
@@ -1,35 +1,166 @@
#!/bin/sh
set -eu
#!/usr/bin/bash --posix

# Set POSIX-compliant mode to make bash and certain utils more predictable.
# Bash-specific features are still used, that's intentional
POSIXLY_CORRECT=1
set -o posix
readonly POSIXLY_CORRECT
export POSIXLY_CORRECT

# Set IFS explicitly. POSIX does not enforce whether IFS should be inherited
# from the environment, so it's safer to set it explicitly
IFS=$' \t\n'
export IFS

# Exit on errors and unset variables
set -eEu

declare -r GUIVM_TERMINAL="i3-sensible-terminal"
declare -r DOMU_TERMINAL="qubes-run-terminal"
declare -r DOMU_CONSOLE="qvm-console-dispvm"


print_usage()
{
cat << USAGE >&2
Usage: $(basename "$0") [--console] [--user USER]

Options:
-h, --help print this usage information
-c, --console launch disposable console instead of terminal
-u, --user run terminal as specified user
USAGE
return 0
}


main() {
cmd=""
case "${1-}" in
console) cmd="$1";;
"");;
*) printf '%s\n' "Invalid argument" >&2; exit 1;;
esac

guivm_terminal=i3-sensible-terminal
domU_terminal=qubes-run-terminal
domU_console=qvm-console-dispvm
id="$(xprop -root _NET_ACTIVE_WINDOW)"
id="${id##* }"
vm="$(xprop -id "$id" | grep '_QUBES_VMNAME(STRING)')" || true
if test -z "$vm"; then
exec "$guivm_terminal"
fi
vm="${vm#*\"}"
vm="${vm%\"*}"

if test "$cmd" = "console"; then
exec "$domU_console" -- "$vm"
fi

if command -v qrexec-client >/dev/null; then
exec qrexec-client -e -d "$vm" -- \
"DEFAULT:QUBESRPC qubes.StartApp+$domU_terminal $vm"
fi
exec qvm-run --no-gui --service -- "$vm" qubes.StartApp+"$domU_terminal"
# Get ID of active window
local id
id="$(xprop -root _NET_ACTIVE_WINDOW)"
id="${id##* }"
declare -r id

local vm
vm="$(xprop -id "$id" | grep '_QUBES_VMNAME(STRING)')" || true

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
vm="$(xprop -id "$id" | grep '_QUBES_VMNAME(STRING)')" || true
vm="$(xprop -id "$id" '_QUBES_VMNAME')" || true

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried this approach and ran into an issue. It looks like xprop emits both outputs and error messages to stdout, disregarding stderr. Unless there's a way to make it work properly (or I'm mistaken), I feel like the post-processing of the output with grep would be the better approach, sadly.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very weird behavior. To test, make it fail by focusing a dom0 window before running the script, notice that redirecting stderr to dev null doesn't hide errors.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, I also get an error here when running the script on xfce. Apparently, Xfce sets two window IDs in the _NET_ACTIVE_WINDOW property, the second one being 0x0. And xprop fails on it, making the script always assume it's dom0.
But it does work correctly for me on i3.


if test -z "$vm"
then
case "$arg_user" in
DEFAULT)
exec -- "$GUIVM_TERMINAL"
;;
*)
exec -- sudo -n -u "$arg_user" -- "$GUIVM_TERMINAL"
;;
esac
fi

vm="${vm#*\"}"
vm="${vm%\"*}"
declare -r vm

# Launch console for VM (hvc)
if test "$arg_console" = "true"
then
exec -- "$DOMU_CONSOLE" -- "$vm"
fi

if command -v qrexec-client >/dev/null
then
exec -- qrexec-client -e -d "$vm" -- \
"$arg_user:QUBESRPC qubes.StartApp+$DOMU_TERMINAL $vm"
fi

# Else, if qrexec-client can't be used (e.g. in a GUIVM), use qvm-run instead
case "$arg_user" in
DEFAULT)
exec qvm-run --no-gui --service -- "$vm" qubes.StartApp+"$DOMU_TERMINAL"
;;
*)
exec qvm-run --no-gui --service -u "$arg_user" -- "$vm" qubes.StartApp+"$DOMU_TERMINAL"
;;
esac
}

main "$@"

# Adapted from https://stackoverflow.com/a/29754866
parse_options()
{
declare -g arg_user="DEFAULT"
declare -g arg_console=""

if [ $# -lt 1 ]
then
return
fi
# Check whether getopt version is "enhanced"
# shellcheck disable=SC2251
! getopt --test >/dev/null
if [[ ${PIPESTATUS[0]} -ne 4 ]]
then
printf '%s\n' 'This script requires getopt enhanced to work properly' >&2
exit 2
fi

# Set available options
declare -r LONGOPTS=help,console,user:
declare -r OPTIONS=hcu:

# Get arguments from "$@" using getopt
IFS=" " read -r -a PARSED <<< "$(getopt --options=$OPTIONS --longoptions=$LONGOPTS --name "$0" -- "$@")"
eval set -- "${PARSED[*]}"

# Write to argument variables
while true
do
case "$1" in
-h|--help)
print_usage
exit 0
;;
-u|--user)
arg_user="$2"
shift 2
;;
-c|--console)
arg_console="true"
shift
;;
--)
shift
break
;;
*)
printf '%s\n' "$(basename "$0"): Invalid argument" >&2
print_usage
exit 2
;;
esac
done

# Handle positional arguments ($1, $2, …)
if [ $# -gt 0 ]
then
case "${1-}" in
console)
arg_console="true"
printf '%s\n' "$(basename "$0"): Positional arguments are deprecated and will be removed in the future. Use --console instead" >&2
;;
*)
printf '%s\n' "$(basename "$0"): Invalid argument" >&2
print_usage
exit 2
;;
esac
fi

declare -gr arg_user
declare -gr arg_console

return
}


parse_options "$@"
main
Empty file modified qubes-i3-xdg-autostart
100644 → 100755
Empty file.
Empty file modified qubes-i3status.py
100644 → 100755
Empty file.