joeylib2/scripts/lib/wineGate.sh
2026-10-13 14:01:46 -05:00

110 lines
3.6 KiB
Bash

# Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License.
# See LICENSE.md for license information.
# SPDX-License-Identifier: MIT
#
# Shared by the Win32 gates (scripts/bench-win32.sh, scripts/verify-win32-*.sh)
# and joey-run: run a Win32 program (make win32) under Wine on a private Xvfb
# display with a private Wine prefix, so nothing reaches ~/.wine. Source after
# joeyEnv.sh. (Win16 programs run on Windows 3.11 in DOSBox instead:
# scripts/lib/win16Gate.sh.)
#
# wineNeed exit 2 unless Wine is installed
# wineEnv PREFIX Wine's environment for the prefix PREFIX, quiet;
# Wine makes the prefix when it first runs
# winePrefix WORK a prefix under WORK, made and settled before
# anything runs in it (a program started alongside
# Wine's first-run setup got no sound for its first
# seconds); sets WINEPREFIX
# wineStart WORK a display, then winePrefix WORK; sets DISPLAY,
# WINEPREFIX and WINE_XVFB_PID
# wineComPort N PATH the prefix's COMn opens the Unix device PATH (a pty
# a gate's peer or joey-run's socat made), and its
# wineserver is started; before wineRun
# wineRun EXE [ARGS...] start EXE in the background; sets WINE_PID
# wineWindow TITLE print the X window titled TITLE (waits for it)
# wineStop stop the program, the prefix's wineserver and the
# display
WINE_PID=""
WINE_XVFB_PID=""
WINE_WINDOW_TRIES=60
wineNeed() {
joeyNeed WINE wine
}
wineEnv() {
mkdir -p "$1"
export WINEPREFIX="$1"
export WINEDEBUG=-all
# No Mono or Gecko install prompts in a fresh prefix.
export WINEDLLOVERRIDES="mscoree,mshtml="
}
winePrefix() {
wineEnv "$1/prefix"
"$WINE" wineboot --init > "$1/wineboot.log" 2>&1
"$(dirname "$WINE")/wineserver" -w
}
wineStart() {
export DISPLAY=":$((RANDOM % 400 + 1800))"
Xvfb "$DISPLAY" -screen 0 1280x1024x24 -nolisten tcp > /dev/null 2>&1 &
WINE_XVFB_PID=$!
sleep 1
winePrefix "$1"
}
# Wine's mount manager makes dosdevices/comN from HKLM\Software\Wine\Ports
# when Wine starts (a link made by hand is refused, access denied), so the
# key is set and Wine restarted. The new wineserver is started here, its
# output in a log: it opens the pty itself and, a daemon with no terminal,
# makes it its own, so when the far end closes the pty it gets SIGHUP and
# prints every object it holds (megabytes), which must not land where the
# program's output goes.
wineComPort() {
printf 'REGEDIT4\r\n\r\n[HKEY_LOCAL_MACHINE\\Software\\Wine\\Ports]\r\n"COM%s"="%s"\r\n' "$1" "$2" > "$WINEPREFIX/../ports.reg"
"$WINE" regedit /S "$WINEPREFIX/../ports.reg"
"$(dirname "$WINE")/wineserver" -k
"$(dirname "$WINE")/wineserver" -w
"$(dirname "$WINE")/wineserver" > "$WINEPREFIX/../wineserver.log" 2>&1
}
wineRun() {
"$WINE" "$@" > "$WINEPREFIX/../wine.log" 2>&1 &
WINE_PID=$!
}
wineWindow() {
local tries
local win
for ((tries = 0; tries < WINE_WINDOW_TRIES; tries++)); do
win="$(xdotool search --name "^$1\$" 2>/dev/null | head -1)"
if [ -n "$win" ]; then
printf '%s\n' "$win"
return 0
fi
sleep 1
done
return 1
}
wineStop() {
joeyStop "$WINE_PID"
WINE_PID=""
if [ -n "${WINEPREFIX:-}" ]; then
"$(dirname "$WINE")/wineserver" -k 2> /dev/null || true
fi
if [ -n "$WINE_XVFB_PID" ]; then
kill "$WINE_XVFB_PID" 2> /dev/null || true
WINE_XVFB_PID=""
fi
}