1
0
Fork 0
mirror of synced 2024-06-02 02:34:40 +12:00

Wine: Set environment through flatpak-spawn arguments

Partially fixes #305
This commit is contained in:
loathingKernel 2023-09-03 01:38:42 +03:00
parent 909c3cbdc1
commit 45ad3e2632
No known key found for this signature in database
GPG key ID: CE0C72D0B53821FD
4 changed files with 74 additions and 49 deletions

View file

@ -68,7 +68,7 @@ class PreLaunchThread(QRunnable):
if launch_args.pre_launch_command:
proc = get_configured_process()
proc.setProcessEnvironment(launch_args.env)
proc.setProcessEnvironment(launch_args.environment)
self.signals.started_pre_launch_command.emit()
proc.start(launch_args.pre_launch_command[0], launch_args.pre_launch_command[1:])
if launch_args.pre_launch_wait:
@ -119,6 +119,7 @@ class RareLauncher(RareApp):
def __init__(self, args: InitArgs):
super(RareLauncher, self).__init__(args, f"{type(self).__name__}_{args.app_name}_{{0}}.log")
self.socket: Optional[QLocalSocket] = None
self._hook.deleteLater()
self._hook = RareLauncherException(self, args, self)
@ -126,7 +127,11 @@ class RareLauncher(RareApp):
self.no_sync_on_exit = False
self.args = args
self.core = LegendaryCore()
self.rgame = RareGameSlim(self.core, self.core.get_game(args.app_name))
game = self.core.get_game(args.app_name)
if not game:
self.logger.error(f"Game {args.app_name} not found. Exiting")
QApplication.exit(1)
self.rgame = RareGameSlim(self.core, game)
lang = self.settings.value("language", self.core.language_code, type=str)
self.load_translator(lang)
@ -242,13 +247,14 @@ class RareLauncher(RareApp):
)
self.stop()
@pyqtSlot(object)
def launch_game(self, args: LaunchArgs):
# should never happen
if not args:
self.stop()
return
if self.console:
self.console.set_env(args.env)
self.console.set_env(args.environment)
self.start_time = time.time()
if args.is_origin_game:
@ -256,9 +262,9 @@ class RareLauncher(RareApp):
self.stop() # stop because it is no subprocess
return
if args.cwd:
self.game_process.setWorkingDirectory(args.cwd)
self.game_process.setProcessEnvironment(args.env)
if args.working_directory:
self.game_process.setWorkingDirectory(args.working_directory)
self.game_process.setProcessEnvironment(args.environment)
# send start message after process started
self.game_process.started.connect(lambda: self.send_message(
StateChangedModel(
@ -268,8 +274,8 @@ class RareLauncher(RareApp):
))
if self.rgame.app_name in DETACHED_APP_NAMES and platform.system() == "Windows":
self.game_process.deleteLater()
subprocess.Popen([args.executable] + args.args, cwd=args.cwd,
env={i: args.env.value(i) for i in args.env.keys()})
subprocess.Popen([args.executable] + args.arguments, cwd=args.working_directory,
env={i: args.environment.value(i) for i in args.environment.keys()})
if self.console:
self.console.log("Launching game detached")
self.stop()
@ -277,13 +283,13 @@ class RareLauncher(RareApp):
if self.args.dry_run:
self.logger.info("Dry run activated")
if self.console:
self.console.log(f"{args.executable} {' '.join(args.args)}")
self.console.log(f"{args.executable} {' '.join(args.arguments)}")
self.console.log(f"Do not start {self.rgame.app_name}")
self.console.accept_close = True
print(args.executable, " ".join(args.args))
print(args.executable, " ".join(args.arguments))
self.stop()
return
self.game_process.start(args.executable, args.args)
self.game_process.start(args.executable, args.arguments)
def error_occurred(self, error_str: str):
self.logger.warning(error_str)

View file

@ -44,9 +44,9 @@ class InitArgs(Namespace):
@dataclass
class LaunchArgs:
executable: str = ""
args: List[str] = None
cwd: str = None
env: QProcessEnvironment = None
arguments: List[str] = None
working_directory: str = None
environment: QProcessEnvironment = None
pre_launch_command: str = ""
pre_launch_wait: bool = False
is_origin_game: bool = False # only for windows to launch as url
@ -60,7 +60,7 @@ def get_origin_params(core: LegendaryCore, app_name, offline: bool,
origin_uri = core.get_origin_uri(app_name, offline)
if platform.system() == "Windows":
launch_args.executable = origin_uri
launch_args.args = []
launch_args.arguments = []
# only set it here true, because on linux it is a launch command like every other game
launch_args.is_origin_game = True
return launch_args
@ -71,12 +71,19 @@ def get_origin_params(core: LegendaryCore, app_name, offline: bool,
command.append(origin_uri)
env = core.get_app_environment(app_name)
launch_args.env = QProcessEnvironment.systemEnvironment()
if os.environ.get("container") == "flatpak":
flatpak_command = ["flatpak-spawn", "--host"]
for name, value in env.items():
flatpak_command.append(f"--env={name}={value}")
command = flatpak_command.extend(command)
launch_args.environment = QProcessEnvironment.systemEnvironment()
for name, value in env.items():
launch_args.env.insert(name, value)
launch_args.environment.insert(name, value)
launch_args.executable = command[0]
launch_args.args = command[1:]
launch_args.arguments = command[1:]
return launch_args
@ -100,10 +107,12 @@ def get_game_params(core: LegendaryCore, igame: InstalledGame, args: InitArgs,
app_name=igame.app_name, offline=args.offline
)
full_params = list()
full_params = []
if os.environ.get("container") == "flatpak":
full_params.extend(["flatpak-spawn", "--host"])
for name, value in params.environment.items():
full_params.append(f"--env={name}={value}")
full_params.extend(params.launch_command)
full_params.append(
@ -114,12 +123,12 @@ def get_game_params(core: LegendaryCore, igame: InstalledGame, args: InitArgs,
full_params.extend(params.user_parameters)
launch_args.executable = full_params[0]
launch_args.args = full_params[1:]
launch_args.arguments = full_params[1:]
launch_args.env = QProcessEnvironment.systemEnvironment()
launch_args.environment = QProcessEnvironment.systemEnvironment()
for name, value in params.environment.items():
launch_args.env.insert(name, value)
launch_args.cwd = params.working_directory
launch_args.environment.insert(name, value)
launch_args.working_directory = params.working_directory
return launch_args

View file

@ -38,7 +38,7 @@ class WineResolver(Worker):
# pylint: disable=E1136
self.signals.result_ready[str].emit("")
return
if not os.path.exists(self.wine_exec) or not os.path.exists(wine.winepath(self.wine_exec)):
if not os.path.exists(self.wine_exec):
# pylint: disable=E1136
self.signals.result_ready[str].emit("")
return
@ -82,28 +82,33 @@ class OriginWineWorker(QRunnable):
wine_env = wine.environ(self.core, rgame.app_name)
wine_exec = wine.wine(self.core, rgame.app_name)
# lk: this is the original way of gettijng the path by parsing "system.reg"
wine_prefix = wine.prefix(self.core, rgame.app_name)
reg = self.__cache.get(wine_prefix, None) or wine.read_registry("system.reg", wine_prefix)
self.__cache[wine_prefix] = reg
use_wine = False
if not use_wine:
# lk: this is the original way of gettijng the path by parsing "system.reg"
wine_prefix = wine.prefix(self.core, rgame.app_name)
reg = self.__cache.get(wine_prefix, None) or wine.read_registry("system.reg", wine_prefix)
self.__cache[wine_prefix] = reg
reg_path = reg_path.replace("SOFTWARE", "Software").replace("WOW6432Node", "Wow6432Node")
# lk: split and rejoin the registry path to avoid slash expansion
reg_path = "\\\\".join([x for x in reg_path.split("\\") if bool(x)])
reg_path = reg_path.replace("SOFTWARE", "Software").replace("WOW6432Node", "Wow6432Node")
# lk: split and rejoin the registry path to avoid slash expansion
reg_path = "\\\\".join([x for x in reg_path.split("\\") if bool(x)])
install_dir = reg.get(reg_path, f'"{reg_key}"', fallback=None)
install_dir = reg.get(reg_path, f'"{reg_key}"', fallback=None)
else:
# lk: this is the alternative way of getting the path by using wine itself
install_dir = wine.query_reg_key(wine_exec, wine_env, f"HKLM\\{reg_path}", reg_key)
# lk: this is the alternative way of getting the path by using wine itself
# install_dir = wine.query_reg_key(wine_exec, wine_env, f"HKLM\\{reg_path}", reg_key)
logger.debug("Found Wine install directory %s", install_dir)
if install_dir:
install_dir = wine.convert_to_unix_path(wine_exec, wine_env, install_dir)
logger.debug("Found Unix install directory %s", install_dir)
if install_dir:
if os.path.isdir(install_dir):
install_size = path_size(install_dir)
rgame.set_origin_attributes(install_dir, install_size)
logger.debug(f"Found Origin game {rgame.title} ({install_dir}, {format_size(install_size)})")
logger.debug(f"Origin game {rgame.title} ({install_dir}, {format_size(install_size)})")
else:
logger.warning(f"Found Origin game {rgame.title} ({install_dir} does not exist)")
logger.info(f"Origin registry worker finished in {time.time() - t}s")
logger.warning(f"Origin game {rgame.title} ({install_dir} does not exist)")
logger.info(f"Origin worker finished in {time.time() - t}s")

View file

@ -2,10 +2,13 @@ import os
import shutil
import subprocess
from configparser import ConfigParser
from logging import getLogger
from typing import Mapping, Dict, List, Tuple
from rare.lgndr.core import LegendaryCore
logger = getLogger("Wine")
# this is a copied function from legendary.utils.wine_helpers, but registry file can be specified
def read_registry(registry: str, wine_pfx: str) -> ConfigParser:
@ -21,16 +24,22 @@ def read_registry(registry: str, wine_pfx: str) -> ConfigParser:
def execute(cmd: List, wine_env: Mapping) -> Tuple[str, str]:
if os.environ.get("container") == "flatpak":
cmd = ["flatpak-spawn", "--host"] + cmd
flatpak_cmd = ["flatpak-spawn", "--host"]
for name, value in wine_env.items():
flatpak_cmd.append(f"--env={name}={value}")
cmd = flatpak_cmd + cmd
proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
env=wine_env,
# Use the current environment if we are in flatpak or our own if we are on host
# In flatpak our environment is passed through `flatpak-spawn` arguments
env=os.environ.copy() if os.environ.get("container") == "flatpak" else wine_env,
shell=False,
text=True,
)
return proc.communicate()
res = proc.communicate()
return res
def resolve_path(wine_exec: str, wine_env: Mapping, path: str) -> str:
@ -65,18 +74,11 @@ def convert_to_windows_path(wine_exec: str, wine_env: Mapping, path: str) -> str
def convert_to_unix_path(wine_exec: str, wine_env: Mapping, path: str) -> str:
path = path.strip().strip('"')
cmd = [winepath(wine_exec), "-u", path]
cmd = [wine_exec, "winepath.exe", "-u", path]
out, err = execute(cmd, wine_env)
return os.path.realpath(out.strip())
def winepath(wine_exec: str) -> str:
_winepath = os.path.join(os.path.dirname(wine_exec), "winepath")
if not os.path.isfile(_winepath):
return ""
return _winepath
def wine(core: LegendaryCore, app_name: str = "default") -> str:
_wine = core.lgd.config.get(
app_name, "wine_executable", fallback=core.lgd.config.get(
@ -87,8 +89,11 @@ def wine(core: LegendaryCore, app_name: str = "default") -> str:
def environ(core: LegendaryCore, app_name: str = "default") -> Dict:
_environ = os.environ.copy()
# Get a clean environment if we are in flatpak, this environment will be pass
# to `flatpak-spawn`, otherwise use the system's.
_environ = {} if os.environ.get("container") == "flatpak" else os.environ.copy()
_environ.update(core.get_app_environment(app_name))
_environ["WINEDEBUG"] = "-all"
_environ["WINEDLLOVERRIDES"] = "winemenubuilder=d;mscoree=d;mshtml=d;"
_environ["DISPLAY"] = ""
return _environ