diff --git a/xwayland-game-wrapper b/xwayland-game-wrapper new file mode 100755 index 0000000..9f26a64 --- /dev/null +++ b/xwayland-game-wrapper @@ -0,0 +1,127 @@ +#!/usr/bin/env zsh + +setopt rcquotes + +# eprintf [args...] +function eprintf { + printf "${@}" >&2 +} + +# die [args...] +function die { + eprintf '\e[91mfatal\e[m: '"${1}\n" "${(@)@:2}" + exit 1 +} + +# print_help +function print_help { + printf 'usage: %s [OPTIONS...] [ARGS...]\n' "${1}" + 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 "${1}" + ;; + '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 +shift $(( "${OPTIND}" - 1)) + +{ + set -e + [[ -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}" & + +${@} +trap - +kill %sh %Xwayland + +wait "${cat_pid}" + +eprintf 'Child died! Exiting...\n'