OriginWineWorker: Execute during launch and properly resolve paths for Wine
This commit is contained in:
parent
d399382afd
commit
92346e11d0
6 changed files with 60 additions and 24 deletions
|
@ -1,6 +1,6 @@
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
|
||||||
from PyQt5.QtCore import QSettings, Qt, pyqtSlot, QThreadPool
|
from PyQt5.QtCore import QSettings, Qt, pyqtSlot
|
||||||
from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget, QScrollArea, QFrame
|
from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget, QScrollArea, QFrame
|
||||||
|
|
||||||
from rare.models.game import RareGame
|
from rare.models.game import RareGame
|
||||||
|
@ -11,7 +11,6 @@ from rare.shared import (
|
||||||
ImageManagerSingleton,
|
ImageManagerSingleton,
|
||||||
)
|
)
|
||||||
from rare.shared import RareCore
|
from rare.shared import RareCore
|
||||||
from rare.shared.workers.wine_resolver import OriginWineWorker
|
|
||||||
from rare.widgets.library_layout import LibraryLayout
|
from rare.widgets.library_layout import LibraryLayout
|
||||||
from rare.widgets.sliding_stack import SlidingStackedWidget
|
from rare.widgets.sliding_stack import SlidingStackedWidget
|
||||||
from .game_info import GameInfoTabs
|
from .game_info import GameInfoTabs
|
||||||
|
@ -155,9 +154,6 @@ class GamesTab(QStackedWidget):
|
||||||
self.filter_games(self.active_filter)
|
self.filter_games(self.active_filter)
|
||||||
self.update_count_games_label()
|
self.update_count_games_label()
|
||||||
|
|
||||||
worker = OriginWineWorker(self.core, self.rcore.origin_games)
|
|
||||||
QThreadPool.globalInstance().start(worker)
|
|
||||||
|
|
||||||
def add_library_widget(self, rgame: RareGame):
|
def add_library_widget(self, rgame: RareGame):
|
||||||
try:
|
try:
|
||||||
icon_widget, list_widget = self.library_controller.add_game(rgame)
|
icon_widget, list_widget = self.library_controller.add_game(rgame)
|
||||||
|
|
|
@ -248,7 +248,7 @@ class GameInfo(QWidget, SideTabContents):
|
||||||
self.ui.lbl_install_size.setEnabled(bool(self.rgame.install_size))
|
self.ui.lbl_install_size.setEnabled(bool(self.rgame.install_size))
|
||||||
self.ui.install_size.setEnabled(bool(self.rgame.install_size))
|
self.ui.install_size.setEnabled(bool(self.rgame.install_size))
|
||||||
self.ui.install_size.setText(
|
self.ui.install_size.setText(
|
||||||
format_size(self.rgame.igame.install_size) if self.rgame.install_size else "N/A"
|
format_size(self.rgame.install_size) if self.rgame.install_size else "N/A"
|
||||||
)
|
)
|
||||||
|
|
||||||
self.ui.lbl_install_path.setEnabled(bool(self.rgame.install_path))
|
self.ui.lbl_install_path.setEnabled(bool(self.rgame.install_path))
|
||||||
|
|
|
@ -21,6 +21,7 @@ from .workers import (
|
||||||
FetchWorker,
|
FetchWorker,
|
||||||
GamesWorker,
|
GamesWorker,
|
||||||
NonAssetWorker,
|
NonAssetWorker,
|
||||||
|
OriginWineWorker,
|
||||||
SavesWorker,
|
SavesWorker,
|
||||||
EntitlementsWorker,
|
EntitlementsWorker,
|
||||||
)
|
)
|
||||||
|
@ -48,6 +49,7 @@ class RareCore(QObject):
|
||||||
|
|
||||||
self.__games_fetched: bool = False
|
self.__games_fetched: bool = False
|
||||||
self.__non_asset_fetched: bool = False
|
self.__non_asset_fetched: bool = False
|
||||||
|
self.__origin_resolved: bool = False
|
||||||
self.__saves_fetched: bool = False
|
self.__saves_fetched: bool = False
|
||||||
self.__entitlements_fetched: bool = False
|
self.__entitlements_fetched: bool = False
|
||||||
|
|
||||||
|
@ -276,6 +278,9 @@ class RareCore(QObject):
|
||||||
self.__add_games_and_dlcs(games, dlc_dict)
|
self.__add_games_and_dlcs(games, dlc_dict)
|
||||||
self.__non_asset_fetched = True
|
self.__non_asset_fetched = True
|
||||||
status = "Loaded games without assets"
|
status = "Loaded games without assets"
|
||||||
|
if res_type == FetchWorker.Result.ORIGIN:
|
||||||
|
self.__origin_resolved = True
|
||||||
|
status = "Resolved Origin installation status"
|
||||||
if res_type == FetchWorker.Result.SAVES:
|
if res_type == FetchWorker.Result.SAVES:
|
||||||
saves, _ = result
|
saves, _ = result
|
||||||
for save in saves:
|
for save in saves:
|
||||||
|
@ -291,6 +296,7 @@ class RareCore(QObject):
|
||||||
fetched = [
|
fetched = [
|
||||||
self.__games_fetched,
|
self.__games_fetched,
|
||||||
self.__non_asset_fetched,
|
self.__non_asset_fetched,
|
||||||
|
self.__origin_resolved,
|
||||||
self.__saves_fetched,
|
self.__saves_fetched,
|
||||||
self.__entitlements_fetched,
|
self.__entitlements_fetched,
|
||||||
]
|
]
|
||||||
|
@ -307,6 +313,7 @@ class RareCore(QObject):
|
||||||
def fetch(self):
|
def fetch(self):
|
||||||
self.__games_fetched: bool = False
|
self.__games_fetched: bool = False
|
||||||
self.__non_asset_fetched: bool = False
|
self.__non_asset_fetched: bool = False
|
||||||
|
self.__origin_resolved: bool = False
|
||||||
self.__saves_fetched: bool = False
|
self.__saves_fetched: bool = False
|
||||||
self.__entitlements_fetched: bool = False
|
self.__entitlements_fetched: bool = False
|
||||||
|
|
||||||
|
@ -325,9 +332,16 @@ class RareCore(QObject):
|
||||||
else:
|
else:
|
||||||
self.__saves_fetched = True
|
self.__saves_fetched = True
|
||||||
|
|
||||||
|
def resolve_origin(self):
|
||||||
|
origin_worker = OriginWineWorker(self.__core, self.__args, self.origin_games)
|
||||||
|
origin_worker.signals.result.connect(self.handle_result)
|
||||||
|
QThreadPool.globalInstance().start(origin_worker)
|
||||||
|
|
||||||
|
|
||||||
def fetch_extra(self):
|
def fetch_extra(self):
|
||||||
non_asset_worker = NonAssetWorker(self.__core, self.__args)
|
non_asset_worker = NonAssetWorker(self.__core, self.__args)
|
||||||
non_asset_worker.signals.result.connect(self.handle_result)
|
non_asset_worker.signals.result.connect(self.handle_result)
|
||||||
|
non_asset_worker.signals.finished.connect(self.resolve_origin)
|
||||||
QThreadPool.globalInstance().start(non_asset_worker)
|
QThreadPool.globalInstance().start(non_asset_worker)
|
||||||
|
|
||||||
entitlements_worker = EntitlementsWorker(self.__core, self.__args)
|
entitlements_worker = EntitlementsWorker(self.__core, self.__args)
|
||||||
|
|
|
@ -3,4 +3,5 @@ from .install_info import InstallInfoWorker
|
||||||
from .move import MoveWorker
|
from .move import MoveWorker
|
||||||
from .uninstall import UninstallWorker
|
from .uninstall import UninstallWorker
|
||||||
from .verify import VerifyWorker
|
from .verify import VerifyWorker
|
||||||
|
from .wine_resolver import OriginWineWorker
|
||||||
from .worker import Worker, QueueWorker
|
from .worker import Worker, QueueWorker
|
||||||
|
|
|
@ -16,6 +16,7 @@ class FetchWorker(Worker):
|
||||||
class Result(IntEnum):
|
class Result(IntEnum):
|
||||||
GAMES = 1
|
GAMES = 1
|
||||||
NON_ASSET = 2
|
NON_ASSET = 2
|
||||||
|
ORIGIN = 3
|
||||||
SAVES = 5
|
SAVES = 5
|
||||||
ENTITLEMENTS = 6
|
ENTITLEMENTS = 6
|
||||||
|
|
||||||
|
|
|
@ -2,16 +2,18 @@ import os
|
||||||
import platform
|
import platform
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
|
from argparse import Namespace
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from typing import Union, Iterator
|
from typing import Union, Iterator
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSignal, QObject, QRunnable
|
from PyQt5.QtCore import pyqtSignal, QObject
|
||||||
|
|
||||||
from rare.lgndr.core import LegendaryCore
|
from rare.lgndr.core import LegendaryCore
|
||||||
from rare.models.game import RareGame
|
from rare.models.game import RareGame
|
||||||
from rare.models.pathspec import PathSpec
|
from rare.models.pathspec import PathSpec
|
||||||
from rare.utils.misc import read_registry, path_size, format_size
|
from rare.utils.misc import read_registry, path_size, format_size
|
||||||
|
from .fetch import FetchWorker
|
||||||
from .worker import Worker
|
from .worker import Worker
|
||||||
|
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
|
@ -35,9 +37,9 @@ class WineResolver(Worker):
|
||||||
self.wine_env["DISPLAY"] = ""
|
self.wine_env["DISPLAY"] = ""
|
||||||
|
|
||||||
self.wine_binary = core.lgd.config.get(
|
self.wine_binary = core.lgd.config.get(
|
||||||
app_name,
|
app_name, "wine_executable", fallback=core.lgd.config.get(
|
||||||
"wine_executable",
|
"default", "wine_executable", fallback="wine"
|
||||||
fallback=core.lgd.config.get("default", "wine_executable", fallback="wine"),
|
)
|
||||||
)
|
)
|
||||||
self.winepath_binary = os.path.join(os.path.dirname(self.wine_binary), "winepath")
|
self.winepath_binary = os.path.join(os.path.dirname(self.wine_binary), "winepath")
|
||||||
self.path = PathSpec(core, app_name).cook(path)
|
self.path = PathSpec(core, app_name).cook(path)
|
||||||
|
@ -82,19 +84,15 @@ class WineResolver(Worker):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
class OriginWineWorker(QRunnable):
|
class OriginWineWorker(FetchWorker):
|
||||||
def __init__(self, core: LegendaryCore, games: Union[Iterator[RareGame], RareGame]):
|
def __init__(self, core: LegendaryCore, args: Namespace, games: Union[Iterator[RareGame], RareGame]):
|
||||||
super().__init__()
|
super(OriginWineWorker, self).__init__(core, args)
|
||||||
self.setAutoDelete(True)
|
|
||||||
|
|
||||||
self.__cache: dict[str, ConfigParser] = {}
|
self.__cache: dict[str, ConfigParser] = {}
|
||||||
if isinstance(games, RareGame):
|
if isinstance(games, RareGame):
|
||||||
games = [games]
|
games = [games]
|
||||||
|
|
||||||
self.games = games
|
self.games = games
|
||||||
self.core = core
|
|
||||||
|
|
||||||
def run(self) -> None:
|
def run_real(self) -> None:
|
||||||
t = time.time()
|
t = time.time()
|
||||||
for rgame in self.games:
|
for rgame in self.games:
|
||||||
if not rgame.is_origin:
|
if not rgame.is_origin:
|
||||||
|
@ -109,16 +107,41 @@ class OriginWineWorker(QRunnable):
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
install_dir = windows_helpers.query_registry_value(winreg.HKEY_LOCAL_MACHINE, reg_path, "Install Dir")
|
install_dir = windows_helpers.query_registry_value(winreg.HKEY_LOCAL_MACHINE, reg_path, "Install Dir")
|
||||||
else:
|
else:
|
||||||
wine_prefix = self.core.lgd.config.get(rgame.app_name, "wine_prefix",
|
wine_prefix = self.core.lgd.config.get(
|
||||||
fallback=os.path.expanduser("~/.wine"))
|
rgame.app_name, "wine_prefix", fallback=self.core.lgd.config.get(
|
||||||
reg = self.__cache.get(wine_prefix) or read_registry("system.reg", wine_prefix)
|
"default", "wine_prefix", fallback=os.path.expanduser("~/.wine")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
reg = self.__cache.get(wine_prefix, None) or read_registry("system.reg", wine_prefix)
|
||||||
self.__cache[wine_prefix] = reg
|
self.__cache[wine_prefix] = reg
|
||||||
|
|
||||||
# TODO: find a better solution
|
reg_path = reg_path.replace("SOFTWARE", "Software").replace("WOW6432Node", "Wow6432Node")
|
||||||
reg_path = reg_path.replace("\\", "\\\\") \
|
# lk: split and rejoin the registry path to avoid slash expansion
|
||||||
.replace("SOFTWARE", "Software").replace("WOW6432Node", "Wow6432Node")
|
reg_path = "\\\\".join([x for x in reg_path.split("\\") if bool(x)])
|
||||||
|
|
||||||
install_dir = reg.get(reg_path, '"Install Dir"', fallback=None)
|
install_dir = reg.get(reg_path, '"Install Dir"', fallback=None)
|
||||||
|
if install_dir:
|
||||||
|
wine = self.core.lgd.config.get(
|
||||||
|
rgame.app_name, "wine_executable", fallback=self.core.lgd.config.get(
|
||||||
|
"default", "wine_executable", fallback="wine"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
winepath = os.path.join(os.path.dirname(wine), "winepath")
|
||||||
|
wine_env = os.environ.copy()
|
||||||
|
wine_env.update(self.core.get_app_environment(rgame.app_name))
|
||||||
|
wine_env["WINEDLLOVERRIDES"] = "winemenubuilder=d;mscoree=d;mshtml=d;"
|
||||||
|
wine_env["DISPLAY"] = ""
|
||||||
|
install_dir = install_dir.strip().strip('"')
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
[winepath, "-u", install_dir],
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE,
|
||||||
|
env=wine_env,
|
||||||
|
shell=False,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
out, err = proc.communicate()
|
||||||
|
install_dir = os.path.realpath(out.strip())
|
||||||
if install_dir:
|
if install_dir:
|
||||||
if os.path.exists(install_dir):
|
if os.path.exists(install_dir):
|
||||||
size = path_size(install_dir)
|
size = path_size(install_dir)
|
||||||
|
@ -126,4 +149,5 @@ class OriginWineWorker(QRunnable):
|
||||||
logger.debug(f"Found Origin game {rgame.title} ({install_dir}, {format_size(size)})")
|
logger.debug(f"Found Origin game {rgame.title} ({install_dir}, {format_size(size)})")
|
||||||
else:
|
else:
|
||||||
logger.warning(f"Found Origin game {rgame.title} ({install_dir} does not exist)")
|
logger.warning(f"Found Origin game {rgame.title} ({install_dir} does not exist)")
|
||||||
|
self.signals.result.emit((), FetchWorker.Result.ORIGIN)
|
||||||
logger.info(f"Origin registry worker finished in {time.time() - t}s")
|
logger.info(f"Origin registry worker finished in {time.time() - t}s")
|
||||||
|
|
Loading…
Reference in a new issue