From 16b44f83193fdf2b45a80b952b9cba6249aee3a5 Mon Sep 17 00:00:00 2001 From: loathingKernel <142770+loathingKernel@users.noreply.github.com> Date: Tue, 17 Feb 2026 22:17:14 +0200 Subject: [PATCH 1/2] ProtonSettings: reset forms if there are no compatibility tools available If the folders we are search for tools disappear, or if there are no compatible runtimes availabe, the compatibility tool will be unpopulated. This will result in the form to remain stuck at `"Don't use a compatibility tool"` while keeping the wine form disabled at the same time. To fix the symptoms of this, in the case of compatibility tools being empty, manually execute the procedure to unselect any compatibility tool. This fixes just the symptoms, Rare will still not revert to an available tool if the configured one is not found, requiring user interaction to select a new compat tool. Fixes: https://github.com/RareDevs/Rare/issues/688 --- rare/components/tabs/settings/widgets/proton.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rare/components/tabs/settings/widgets/proton.py b/rare/components/tabs/settings/widgets/proton.py index 4e73a75e4..6b86de424 100644 --- a/rare/components/tabs/settings/widgets/proton.py +++ b/rare/components/tabs/settings/widgets/proton.py @@ -111,6 +111,8 @@ def showEvent(self, a0: QShowEvent) -> None: tools = steam.find_tools() for tool in tools: self.tool_combo.addItem(tool.name, tool) + if not tools: + self._on_tool_changed(0) try: wrapper = next( filter( @@ -142,8 +144,8 @@ def showEvent(self, a0: QShowEvent) -> None: return super().showEvent(a0) @Slot(int) - def _on_tool_changed(self, index): - steam_tool: Union[steam.ProtonTool, steam.CompatibilityTool] = self.tool_combo.itemData(index, Qt.ItemDataRole.UserRole) + def _on_tool_changed(self, index: int): + steam_tool: Union[steam.ProtonTool, steam.CompatibilityTool, None] = self.tool_combo.itemData(index, Qt.ItemDataRole.UserRole) steam_environ = steam.get_steam_environment(steam_tool, self.compat_edit.text()) library_paths = steam_environ["STEAM_COMPAT_LIBRARY_PATHS"] if "STEAM_COMPAT_LIBRARY_PATHS" in steam_environ else "" From d71d9f78534664d80536f741615736299e669002 Mon Sep 17 00:00:00 2001 From: loathingKernel <142770+loathingKernel@users.noreply.github.com> Date: Tue, 17 Feb 2026 22:31:52 +0200 Subject: [PATCH 2/2] compat: add miniproton skeleton script --- rare/utils/compat/miniproton.py | 87 +++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 rare/utils/compat/miniproton.py diff --git a/rare/utils/compat/miniproton.py b/rare/utils/compat/miniproton.py new file mode 100644 index 000000000..a5eeeab8e --- /dev/null +++ b/rare/utils/compat/miniproton.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 + +import os +import subprocess +import sys +from getpass import getuser +from pathlib import Path +from typing import Any, Dict, List + + +def log(msg: Any): + sys.stderr.write(str(msg) + "\n") + sys.stderr.flush() + + +def run_proc(args: List, env: Dict): + return subprocess.call(args, env=env, stderr=sys.stderr, stdout=sys.stdout) + + +if __name__ == "__main__": + if "STEAM_COMPAT_DATA_PATH" not in os.environ: + log("No compat data path?") + sys.exit(1) + + wine_bin = "/usr/bin/wine" + wineserver_bin = "/usr/bin/wineserver" + + compat_data = Path(os.environ["STEAM_COMPAT_DATA_PATH"]).resolve(strict=False) + compat_data.mkdir(parents=True, exist_ok=True) + compat_data.joinpath("creation_sync_guard").touch(exist_ok=True) + compat_data.joinpath("tracked_files").touch(exist_ok=True) + + wine_prefix = compat_data.joinpath("pfx").resolve(strict=False) + if not wine_prefix.exists(): + wine_prefix.mkdir(parents=True, exist_ok=True) + + dlls = { + "d3d8": "n,b", + "d3d9": "n,b", + "dxgi": "n,b", + "d3d10core": "n,b", + "d3d11": "n,b", + "d3d12": "n,b;", + "d3d12core": "n,b", + } + dlloverrides = ";".join(("=".join((k , v)) for k, v in dlls.items())) + dlloverrides = ";".join((os.environ.get("WINEDLLOVERRIDES", ""), dlloverrides)) + + env = { + "WINE": wine_bin, + "WINEPREFIX": wine_prefix.as_posix(), + "WINEDLLOVERRIDES": dlloverrides, + } + log(env) + + local_env = os.environ.copy() + local_env.update(env) + + #determine mode + rc = 0 + if sys.argv[1] == "run": + #start target app + rc = run_proc([wine_bin] + sys.argv[2:], local_env) + elif sys.argv[1] == "waitforexitandrun": + #wait for wineserver to shut down + run_proc([wineserver_bin, "-w"], local_env) + #then run + rc = run_proc([wine_bin] + sys.argv[2:], local_env) + elif sys.argv[1] == "runinprefix": + rc = run_proc([wine_bin] + sys.argv[2:], local_env) + elif sys.argv[1] == "getcompatpath": + #linux -> windows path + path = subprocess.check_output([wine_bin, "winepath", "-w", sys.argv[2]], env=local_env, stderr=sys.stderr) + sys.stdout.buffer.write(path) + sys.stdout.buffer.flush() + sys.stderr.buffer.flush() + elif sys.argv[1] == "getnativepath": + #windows -> linux path + path = subprocess.check_output([wine_bin, "winepath", sys.argv[2]], env=local_env, stderr=sys.stderr) + sys.stdout.buffer.write(path) + sys.stdout.buffer.flush() + sys.stderr.buffer.flush() + else: + log("Need a verb.") + sys.exit(1) + + sys.exit(rc)