xwayland-game-wrapper 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. #!/usr/bin/env zsh
  2. setopt rcquotes
  3. # eprintf <format> [args...]
  4. function eprintf {
  5. printf "${@}" >&2
  6. }
  7. # die <format> [args...]
  8. function die {
  9. eprintf '\e[91mfatal\e[m: '"${1}\n" "${(@)@:2}"
  10. exit 1
  11. }
  12. # print_help <argv[0]>
  13. function print_help {
  14. local exec_name="$(basename "${1}")"
  15. printf 'usage: %s [OPTIONS...] <GAME> [ARGS...]\n' "${exec_name}"
  16. printf 'Run a game inside an Xwayland session with a window manager. This\n'
  17. printf 'is very similar to gamescope, except that there is a window\n'
  18. printf 'involved. The default window manager is OpenBox.\n'
  19. printf '\n'
  20. printf ' -h Print this message, then exit.\n'
  21. printf ' -w Specify the window manager to use. This argument to this option will be\n'
  22. printf ' passed to "sh -c".\n'
  23. printf ' -r Specify the resolution of the Xwayland display. This should in the form\n'
  24. printf ' of ''WxH''. By default, the resolution of the currently focused output\n'
  25. printf ' will be used.\n'
  26. printf ' -d Specify the current desktop environment (or standalone Wayland\n'
  27. printf ' compositor). This is used if -r is not specified to find the resolution.\n'
  28. exit 0
  29. }
  30. # get_current_desktop
  31. function get_current_desktop {
  32. [[ -z "${XDG_CURRENT_DESKTOP}" ]] &&
  33. die 'set $XDG_CURRENT_DESKTOP or pass -d top specify desktop'
  34. eprintf 'Detected desktop: "%s"\n' "${XDG_CURRENT_DESKTOP}"
  35. printf '%s' "${XDG_CURRENT_DESKTOP}"
  36. }
  37. # get_default_resolution [desktop]
  38. function get_default_resolution {
  39. case "${1}" in
  40. 'river')
  41. local output="$(ristate -o |
  42. jq -r '.outputs | keys.[] as $names |
  43. {output: $names, focused: .[$names].focused} |
  44. select(.focused) | .output')"
  45. eprintf 'Detected output: %s\n' "${output}"
  46. local resolution="$(wlr-randr --json |
  47. jq -r --arg output "${output}" \
  48. '.[] | select(.name == $output).modes.[] |
  49. select(.current) | "\(.width)x\(.height)"')"
  50. ;;
  51. *)
  52. die 'unknown desktop session: "%s"' "${1}"
  53. ;;
  54. esac
  55. eprintf 'Detected resolution: %s\n' "${resolution}"
  56. printf '%s\n' "${resolution}"
  57. }
  58. while getopts ':hw:r:d:' OPTOPT; do
  59. case "${OPTOPT}" in
  60. 'h')
  61. print_help "${0}"
  62. ;;
  63. 'w')
  64. window_manager="${OPTARG}"
  65. ;;
  66. 'r')
  67. resolution="${OPTARG}"
  68. ;;
  69. 'd')
  70. current_desktop="${OPTARG}"
  71. ;;
  72. ':')
  73. die 'option requires an argument: %s' "${OPTARG}"
  74. ;;
  75. '?')
  76. die 'unknown option: %s' "${OPTARG}"
  77. ;;
  78. esac
  79. done
  80. (( "${OPTIND}" > ${#} )) && print_help "${0}"
  81. shift $(( "${OPTIND}" - 1))
  82. function {
  83. emulate -L zsh
  84. setopt errexit
  85. [[ -v window_manager ]] ||
  86. window_manager='openbox'
  87. [[ -v current_desktop ]] ||
  88. current_desktop="$(get_current_desktop 2>&3)"
  89. [[ -v resolution ]] ||
  90. resolution="$(get_default_resolution "${current_desktop}" 2>&3)"
  91. } 3>&2
  92. function on_sigchld {
  93. eprintf 'Xwayland or window manager died! Exiting...\n'
  94. kill %sh %Xwayland 2>/dev/null
  95. wait ${cat_pid}
  96. exit 1
  97. }
  98. trap on_sigchld CHLD
  99. coproc Xwayland -fullscreen -geometry "${resolution}" -displayfd 1
  100. local xwayland_display
  101. read <&p xwayland_display
  102. export DISPLAY=":${xwayland_display}"
  103. unset WAYLAND_DISPLAY
  104. eprintf 'Xwayland display: %s\n' "${DISPLAY}"
  105. cat <&p >&2
  106. let cat_pid="${!}"
  107. sh -c "exec -- ${window_manager}" &
  108. function {
  109. emulate -L sh
  110. eval "${@}"
  111. } "${@}"
  112. let child_error_code="${?}"
  113. if (( ${child_error_code} )); then
  114. printf 'Child exited with error code %d\n' "${child_error_code}"
  115. fi
  116. trap -
  117. kill %sh %Xwayland
  118. wait "${cat_pid}"
  119. eprintf 'Child died! Exiting...\n'