Reverted experimental fix as game checks dll byte changes.
This commit is contained in:
@@ -44,6 +44,14 @@ def _select_game_window(
|
||||
return None
|
||||
|
||||
|
||||
def _protocols_without(
|
||||
protocols: Sequence[int],
|
||||
blocked_protocol: int,
|
||||
) -> tuple[int, ...]:
|
||||
"""Remove only the selected atom while preserving every other protocol."""
|
||||
return tuple(protocol for protocol in protocols if protocol != blocked_protocol)
|
||||
|
||||
|
||||
class GameboxRuntimeError(RuntimeError):
|
||||
"""Raised when the game command or X11 mapper cannot be started."""
|
||||
|
||||
@@ -127,6 +135,58 @@ class _X11:
|
||||
self.library.XMapRaised(self.display, window)
|
||||
self.library.XFlush(self.display)
|
||||
|
||||
def suppress_wm_ping(self, window: int) -> bool:
|
||||
"""Stop the WM hang prompt for one window, preserving its other protocols."""
|
||||
ping_atom = int(self.library.XInternAtom(self.display, b"_NET_WM_PING", 0))
|
||||
if ping_atom == 0:
|
||||
return False
|
||||
protocols = self._wm_protocols(window)
|
||||
if protocols is None:
|
||||
return False
|
||||
filtered_protocols = _protocols_without(protocols, ping_atom)
|
||||
if filtered_protocols == protocols:
|
||||
return True
|
||||
if filtered_protocols:
|
||||
protocol_values = (ctypes.c_ulong * len(filtered_protocols))(
|
||||
*filtered_protocols
|
||||
)
|
||||
status = self.library.XSetWMProtocols(
|
||||
self.display,
|
||||
window,
|
||||
protocol_values,
|
||||
len(filtered_protocols),
|
||||
)
|
||||
else:
|
||||
status = self.library.XSetWMProtocols(
|
||||
self.display,
|
||||
window,
|
||||
ctypes.POINTER(ctypes.c_ulong)(),
|
||||
0,
|
||||
)
|
||||
if status == 0:
|
||||
return False
|
||||
self.library.XSync(self.display, 0)
|
||||
return self._wm_protocols(window) == filtered_protocols
|
||||
|
||||
def _wm_protocols(self, window: int) -> tuple[int, ...] | None:
|
||||
protocols = ctypes.POINTER(ctypes.c_ulong)()
|
||||
protocol_count = ctypes.c_int()
|
||||
status = self.library.XGetWMProtocols(
|
||||
self.display,
|
||||
window,
|
||||
ctypes.byref(protocols),
|
||||
ctypes.byref(protocol_count),
|
||||
)
|
||||
if status == 0:
|
||||
return None
|
||||
try:
|
||||
return tuple(
|
||||
int(protocols[index]) for index in range(protocol_count.value)
|
||||
)
|
||||
finally:
|
||||
if protocols:
|
||||
self.library.XFree(ctypes.cast(protocols, ctypes.c_void_p))
|
||||
|
||||
def _remove_decorations(self, window: int) -> None:
|
||||
atom = self.library.XInternAtom(self.display, b"_MOTIF_WM_HINTS", 0)
|
||||
if atom == 0:
|
||||
@@ -205,8 +265,24 @@ class _X11:
|
||||
ctypes.c_int,
|
||||
]
|
||||
self.library.XChangeProperty.restype = ctypes.c_int
|
||||
self.library.XGetWMProtocols.argtypes = [
|
||||
ctypes.c_void_p,
|
||||
ctypes.c_ulong,
|
||||
ctypes.POINTER(ctypes.POINTER(ctypes.c_ulong)),
|
||||
ctypes.POINTER(ctypes.c_int),
|
||||
]
|
||||
self.library.XGetWMProtocols.restype = ctypes.c_int
|
||||
self.library.XSetWMProtocols.argtypes = [
|
||||
ctypes.c_void_p,
|
||||
ctypes.c_ulong,
|
||||
ctypes.POINTER(ctypes.c_ulong),
|
||||
ctypes.c_int,
|
||||
]
|
||||
self.library.XSetWMProtocols.restype = ctypes.c_int
|
||||
self.library.XMapRaised.argtypes = [ctypes.c_void_p, ctypes.c_ulong]
|
||||
self.library.XMapRaised.restype = ctypes.c_int
|
||||
self.library.XSync.argtypes = [ctypes.c_void_p, ctypes.c_int]
|
||||
self.library.XSync.restype = ctypes.c_int
|
||||
self.library.XFlush.argtypes = [ctypes.c_void_p]
|
||||
self.library.XFlush.restype = ctypes.c_int
|
||||
self.library.XFree.argtypes = [ctypes.c_void_p]
|
||||
@@ -215,11 +291,46 @@ class _X11:
|
||||
self.library.XCloseDisplay.restype = ctypes.c_int
|
||||
|
||||
|
||||
def _prepare_game_window(
|
||||
mapper: _X11,
|
||||
window: int,
|
||||
*,
|
||||
borderless: bool,
|
||||
suppress_wm_ping: bool,
|
||||
) -> None:
|
||||
if suppress_wm_ping:
|
||||
try:
|
||||
ping_suppressed = mapper.suppress_wm_ping(window)
|
||||
except Exception as exc:
|
||||
print(
|
||||
f"Warning: could not suppress game-window hang warnings ({exc}); "
|
||||
"continuing normally",
|
||||
file=sys.stderr,
|
||||
flush=True,
|
||||
)
|
||||
else:
|
||||
if ping_suppressed:
|
||||
print(
|
||||
"Game-window hang warnings suppressed for this launch.",
|
||||
file=sys.stderr,
|
||||
flush=True,
|
||||
)
|
||||
else:
|
||||
print(
|
||||
"Warning: could not verify game-window hang-warning "
|
||||
"suppression; continuing normally",
|
||||
file=sys.stderr,
|
||||
flush=True,
|
||||
)
|
||||
mapper.map_window(window, borderless=borderless)
|
||||
|
||||
|
||||
def run_game_window(
|
||||
command: Sequence[str],
|
||||
window_title: str = WINDOW_TITLE,
|
||||
*,
|
||||
borderless: bool = False,
|
||||
suppress_wm_ping: bool = False,
|
||||
) -> int:
|
||||
if not command:
|
||||
raise GameboxRuntimeError("game command cannot be empty")
|
||||
@@ -270,7 +381,12 @@ def run_game_window(
|
||||
and game_window_created_at is not None
|
||||
and now - game_window_created_at >= WINDOW_READY_DELAY_SECONDS
|
||||
):
|
||||
mapper.map_window(game_window, borderless=borderless)
|
||||
_prepare_game_window(
|
||||
mapper,
|
||||
game_window,
|
||||
borderless=borderless,
|
||||
suppress_wm_ping=suppress_wm_ping,
|
||||
)
|
||||
print(
|
||||
f"Game window ready: {game_title or window_title}",
|
||||
file=sys.stderr,
|
||||
@@ -285,7 +401,12 @@ def run_game_window(
|
||||
flush=True,
|
||||
)
|
||||
if game_window is not None:
|
||||
mapper.map_window(game_window, borderless=borderless)
|
||||
_prepare_game_window(
|
||||
mapper,
|
||||
game_window,
|
||||
borderless=borderless,
|
||||
suppress_wm_ping=suppress_wm_ping,
|
||||
)
|
||||
return int(process.wait())
|
||||
finally:
|
||||
mapper.close()
|
||||
@@ -295,6 +416,7 @@ def main(argv: Sequence[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--window-title", default=WINDOW_TITLE)
|
||||
parser.add_argument("--borderless", action="store_true")
|
||||
parser.add_argument("--suppress-wm-ping", action="store_true")
|
||||
parser.add_argument("command", nargs=argparse.REMAINDER)
|
||||
arguments = parser.parse_args(argv)
|
||||
command = arguments.command
|
||||
@@ -305,6 +427,7 @@ def main(argv: Sequence[str] | None = None) -> int:
|
||||
command,
|
||||
arguments.window_title,
|
||||
borderless=arguments.borderless,
|
||||
suppress_wm_ping=arguments.suppress_wm_ping,
|
||||
)
|
||||
except (GameboxRuntimeError, OSError) as exc:
|
||||
print(f"Error: {exc}", file=sys.stderr)
|
||||
|
||||
Reference in New Issue
Block a user