diff --git a/umu/umu_run.py b/umu/umu_run.py index a0082306a..be55df98a 100755 --- a/umu/umu_run.py +++ b/umu/umu_run.py @@ -335,6 +335,7 @@ def build_command( opts: list[str] = [], ) -> tuple[Path | str, ...]: """Build the command to be executed.""" + shim: Path = local.joinpath("umu-shim") proton: Path = Path(env["PROTONPATH"], "proton") entry_point: Path = local.joinpath("umu") @@ -373,6 +374,7 @@ def build_command( "--verb", env["PROTON_VERB"], "--", + shim, proton, env["PROTON_VERB"], env["EXE"], diff --git a/umu/umu_runtime.py b/umu/umu_runtime.py index 556bd2b67..b339eae46 100644 --- a/umu/umu_runtime.py +++ b/umu/umu_runtime.py @@ -33,6 +33,44 @@ has_data_filter: bool = False +def create_shim(file_path: Path | None = None): + """Create a shell script shim at the specified file path. + + This script sets the DISPLAY environment variable if certain conditions + are met and executes the passed command. + + Args: + file_path (Path, optional): The path where the shim script will be created. + Defaults to UMU_LOCAL.joinpath("umu-shim"). + + """ + # Set the default path if none is provided + if file_path is None: + file_path = UMU_LOCAL.joinpath("umu-shim") + # Define the content of the shell script + script_content = """#!/bin/sh + + if [ "${XDG_CURRENT_DESKTOP}" = "gamescope" ] || [ "${XDG_SESSION_DESKTOP}" = "gamescope" ]; then + # Check if STEAM_MULTIPLE_XWAYLANDS is set to 1 + if [ "${STEAM_MULTIPLE_XWAYLANDS}" = "1" ]; then + # Check if DISPLAY is set, if not, set it to ":1" + if [ -z "${DISPLAY}" ]; then + export DISPLAY=":1" + fi + fi + fi + + # Execute the passed command + "$@" + """ + + # Write the script content to the specified file path + with file_path.open('w') as file: + file.write(script_content) + + # Make the script executable + file_path.chmod(0o700) + def _install_umu( json: dict[str, Any], thread_pool: ThreadPoolExecutor, @@ -177,6 +215,7 @@ def _install_umu( # Rename _v2-entry-point log.debug("Renaming: _v2-entry-point -> umu") UMU_LOCAL.joinpath("_v2-entry-point").rename(UMU_LOCAL.joinpath("umu")) + create_shim() # Validate the runtime after moving the files check_runtime(UMU_LOCAL, json) @@ -368,6 +407,10 @@ def _update_umu( rmtree(str(runtime)) log.debug("Released file lock '%s'", lock.lock_file) + # Restore shim + if not local.joinpath("umu-shim").exists(): + create_shim() + log.console("steamrt is up to date") @@ -474,6 +517,9 @@ def check_runtime(src: Path, json: dict[str, Any]) -> int: return ret log.console(f"{runtime.name}: mtree is OK") + if not UMU_LOCAL.joinpath("umu-shim").exists(): + create_shim() + return ret @@ -491,3 +537,6 @@ def _restore_umu( return _install_umu(json, thread_pool, client_session) log.debug("Released file lock '%s'", lock.lock_file) + + if not UMU_LOCAL.joinpath("umu-shim").exists(): + create_shim() diff --git a/umu/umu_test.py b/umu/umu_test.py index 97f7e687a..120d7405a 100644 --- a/umu/umu_test.py +++ b/umu/umu_test.py @@ -1299,6 +1299,10 @@ def test_build_command(self): # Mock the proton file Path(self.test_file, "proton").touch() + # Mock the shim file + shim_path = Path(self.test_local_share, "umu-shim") + shim_path.touch() + with ( patch("sys.argv", ["", self.test_exe]), ThreadPoolExecutor() as thread_pool, @@ -1350,10 +1354,10 @@ def test_build_command(self): ) self.assertEqual( len(test_command), - 7, - f"Expected 7 elements, received {len(test_command)}", + 8, + f"Expected 8 elements, received {len(test_command)}", ) - entry_point, opt1, verb, opt2, proton, verb2, exe = [*test_command] + entry_point, opt1, verb, opt2, shim, proton, verb2, exe = [*test_command] # The entry point dest could change. Just check if there's a value self.assertTrue(entry_point, "Expected an entry point") self.assertIsInstance( @@ -1362,6 +1366,8 @@ def test_build_command(self): self.assertEqual(opt1, "--verb", "Expected --verb") self.assertEqual(verb, self.test_verb, "Expected a verb") self.assertEqual(opt2, "--", "Expected --") + self.assertIsInstance(shim, os.PathLike, "Expected shim to be PathLike") + self.assertEqual(shim, shim_path, "Expected the shim file") self.assertIsInstance(proton, os.PathLike, "Expected proton to be PathLike") self.assertEqual( proton, diff --git a/umu/umu_test_plugins.py b/umu/umu_test_plugins.py index b7cd3d149..1e63020d4 100644 --- a/umu/umu_test_plugins.py +++ b/umu/umu_test_plugins.py @@ -332,6 +332,10 @@ def test_build_command_toml(self): Path(self.test_file + "/proton").touch() Path(toml_path).touch() + # Mock the shim file + shim_path = Path(self.test_local_share, "umu-shim") + shim_path.touch() + with Path(toml_path).open(mode="w", encoding="utf-8") as file: file.write(toml_str) @@ -380,7 +384,7 @@ def test_build_command_toml(self): test_command = umu_run.build_command(self.env, self.test_local_share) # Verify contents of the command - entry_point, opt1, verb, opt2, proton, verb2, exe = [*test_command] + entry_point, opt1, verb, opt2, shim, proton, verb2, exe = [*test_command] # The entry point dest could change. Just check if there's a value self.assertTrue(entry_point, "Expected an entry point") self.assertIsInstance( @@ -389,6 +393,8 @@ def test_build_command_toml(self): self.assertEqual(opt1, "--verb", "Expected --verb") self.assertEqual(verb, self.test_verb, "Expected a verb") self.assertEqual(opt2, "--", "Expected --") + self.assertIsInstance(shim, os.PathLike, "Expected shim to be PathLike") + self.assertEqual(shim, shim_path, "Expected the shim file") self.assertIsInstance(proton, os.PathLike, "Expected proton to be PathLike") self.assertEqual( proton,