random-scripts/xwayland-game-wrapper

136 lines
3.9 KiB
Bash
Executable File

#!/usr/bin/env zsh
setopt rcquotes
# eprintf <format> [args...]
function eprintf {
printf "${@}" >&2
}
# die <format> [args...]
function die {
eprintf '\e[91mfatal\e[m: '"${1}\n" "${(@)@:2}"
exit 1
}
# print_help <argv[0]>
function print_help {
local exec_name="$(basename "${1}")"
printf 'usage: %s [OPTIONS...] <GAME> [ARGS...]\n' "${exec_name}"
printf 'Run a game inside an Xwayland session with a window manager. This\n'
printf 'is very similar to gamescope, except that there is a window\n'
printf 'involved. The default window manager is OpenBox.\n'
printf '\n'
printf ' -h Print this message, then exit.\n'
printf ' -w Specify the window manager to use. This argument to this option will be\n'
printf ' passed to "sh -c".\n'
printf ' -r Specify the resolution of the Xwayland display. This should in the form\n'
printf ' of ''WxH''. By default, the resolution of the currently focused output\n'
printf ' will be used.\n'
printf ' -d Specify the current desktop environment (or standalone Wayland\n'
printf ' compositor). This is used if -r is not specified to find the resolution.\n'
exit 0
}
# get_current_desktop
function get_current_desktop {
[[ -z "${XDG_CURRENT_DESKTOP}" ]] &&
die 'set $XDG_CURRENT_DESKTOP or pass -d top specify desktop'
eprintf 'Detected desktop: "%s"\n' "${XDG_CURRENT_DESKTOP}"
printf '%s' "${XDG_CURRENT_DESKTOP}"
}
# get_default_resolution [desktop]
function get_default_resolution {
case "${1}" in
'river')
local output="$(ristate -o |
jq -r '.outputs | keys.[] as $names |
{output: $names, focused: .[$names].focused} |
select(.focused) | .output')"
eprintf 'Detected output: %s\n' "${output}"
local resolution="$(wlr-randr --json |
jq -r --arg output "${output}" \
'.[] | select(.name == $output).modes.[] |
select(.current) | "\(.width)x\(.height)"')"
;;
*)
die 'unknown desktop session: "%s"' "${1}"
;;
esac
eprintf 'Detected resolution: %s\n' "${resolution}"
printf '%s\n' "${resolution}"
}
while getopts ':hw:r:d:' OPTOPT; do
case "${OPTOPT}" in
'h')
print_help "${0}"
;;
'w')
window_manager="${OPTARG}"
;;
'r')
resolution="${OPTARG}"
;;
'd')
current_desktop="${OPTARG}"
;;
':')
die 'option requires an argument: %s' "${OPTARG}"
;;
'?')
die 'unknown option: %s' "${OPTARG}"
;;
esac
done
(( "${OPTIND}" > ${#} )) && print_help "${0}"
shift $(( "${OPTIND}" - 1))
function {
emulate -L zsh
setopt errexit
[[ -v window_manager ]] ||
window_manager='openbox'
[[ -v current_desktop ]] ||
current_desktop="$(get_current_desktop 2>&3)"
[[ -v resolution ]] ||
resolution="$(get_default_resolution "${current_desktop}" 2>&3)"
} 3>&2
function on_sigchld {
eprintf 'Xwayland or window manager died! Exiting...\n'
kill %sh %Xwayland 2>/dev/null
wait ${cat_pid}
exit 1
}
trap on_sigchld CHLD
coproc Xwayland -fullscreen -geometry "${resolution}" -displayfd 1
local xwayland_display
read <&p xwayland_display
export DISPLAY=":${xwayland_display}"
unset WAYLAND_DISPLAY
eprintf 'Xwayland display: %s\n' "${DISPLAY}"
cat <&p >&2
let cat_pid="${!}"
sh -c "exec -- ${window_manager}" &
function {
emulate -L sh
eval "${@}"
} "${@}"
let child_error_code="${?}"
if (( ${child_error_code} )); then
printf 'Child exited with error code %d\n' "${child_error_code}"
fi
trap -
kill %sh %Xwayland
wait "${cat_pid}"
eprintf 'Child died! Exiting...\n'