mirror of
https://github.com/lutris/lutris
synced 2024-09-15 22:09:55 +00:00
Run black on modules with Flake8 warnings
This commit is contained in:
parent
ca415467f9
commit
c1412140bf
|
@ -163,20 +163,33 @@ class Game(GObject.Object):
|
|||
)
|
||||
self.runner = self._get_runner()
|
||||
if self.discord_presence.available:
|
||||
self.discord_presence.client_id = self.config.system_config.get("discord_client_id") or DEFAULT_DISCORD_CLIENT_ID
|
||||
self.discord_presence.game_name = self.config.system_config.get("discord_custom_game_name") or self.name
|
||||
self.discord_presence.show_runner = self.config.system_config.get("discord_show_runner", True)
|
||||
self.discord_presence.runner_name = self.config.system_config.get("discord_custom_runner_name") or self.runner_name
|
||||
self.discord_presence.rpc_enabled = self.config.system_config.get("discord_rpc_enabled", True)
|
||||
self.discord_presence.client_id = (
|
||||
self.config.system_config.get("discord_client_id")
|
||||
or DEFAULT_DISCORD_CLIENT_ID
|
||||
)
|
||||
self.discord_presence.game_name = (
|
||||
self.config.system_config.get("discord_custom_game_name") or self.name
|
||||
)
|
||||
self.discord_presence.show_runner = self.config.system_config.get(
|
||||
"discord_show_runner", True
|
||||
)
|
||||
self.discord_presence.runner_name = (
|
||||
self.config.system_config.get("discord_custom_runner_name")
|
||||
or self.runner_name
|
||||
)
|
||||
self.discord_presence.rpc_enabled = self.config.system_config.get(
|
||||
"discord_rpc_enabled", True
|
||||
)
|
||||
|
||||
def set_desktop_compositing(self, enable):
|
||||
"""Enables or disables compositing"""
|
||||
if enable:
|
||||
system.execute(self.start_compositor, shell=True)
|
||||
else:
|
||||
self.start_compositor, self.stop_compositor = (
|
||||
display.get_compositor_commands()
|
||||
)
|
||||
(
|
||||
self.start_compositor,
|
||||
self.stop_compositor,
|
||||
) = display.get_compositor_commands()
|
||||
if not (self.compositor_disabled or not self.stop_compositor):
|
||||
system.execute(self.stop_compositor, shell=True)
|
||||
self.compositor_disabled = True
|
||||
|
@ -252,7 +265,11 @@ class Game(GObject.Object):
|
|||
dialogs.ErrorDialog(
|
||||
"Runtime currently updating", "Game might not work as expected"
|
||||
)
|
||||
if "wine" in self.runner_name and not wine.get_system_wine_version() and not LINUX_SYSTEM.is_flatpak:
|
||||
if (
|
||||
"wine" in self.runner_name
|
||||
and not wine.get_system_wine_version()
|
||||
and not LINUX_SYSTEM.is_flatpak
|
||||
):
|
||||
|
||||
# TODO find a reference to the root window or better yet a way not
|
||||
# to have Gtk dependent code in this class.
|
||||
|
@ -265,12 +282,12 @@ class Game(GObject.Object):
|
|||
if not self.runner:
|
||||
dialogs.ErrorDialog("Invalid game configuration: Missing runner")
|
||||
self.state = self.STATE_STOPPED
|
||||
self.emit('game-stop')
|
||||
self.emit("game-stop")
|
||||
return
|
||||
|
||||
if not self.prelaunch():
|
||||
self.state = self.STATE_STOPPED
|
||||
self.emit('game-stop')
|
||||
self.emit("game-stop")
|
||||
return
|
||||
|
||||
self.emit("game-start")
|
||||
|
@ -298,7 +315,7 @@ class Game(GObject.Object):
|
|||
logger.error("Game prelaunch unsuccessful")
|
||||
dialogs.ErrorDialog("An error prevented the game from running")
|
||||
self.state = self.STATE_STOPPED
|
||||
self.emit('game-stop')
|
||||
self.emit("game-stop")
|
||||
return
|
||||
system_config = self.runner.system_config
|
||||
self.original_outputs = sorted(
|
||||
|
@ -309,7 +326,7 @@ class Game(GObject.Object):
|
|||
if "error" in gameplay_info:
|
||||
self.show_error_message(gameplay_info)
|
||||
self.state = self.STATE_STOPPED
|
||||
self.emit('game-stop')
|
||||
self.emit("game-stop")
|
||||
return
|
||||
logger.debug("Launching %s: %s", self.name, gameplay_info)
|
||||
logger.debug("Game info: %s", json.dumps(gameplay_info, indent=2))
|
||||
|
@ -394,7 +411,7 @@ class Game(GObject.Object):
|
|||
xephyr_resolution + "x" + xephyr_depth,
|
||||
"-glamor",
|
||||
"-reset",
|
||||
"-terminate"
|
||||
"-terminate",
|
||||
]
|
||||
if system_config.get("xephyr_fullscreen"):
|
||||
xephyr_command.append("-fullscreen")
|
||||
|
@ -427,7 +444,9 @@ class Game(GObject.Object):
|
|||
if strangle_cmd:
|
||||
launch_arguments = [strangle_cmd, fps_limit] + launch_arguments
|
||||
else:
|
||||
logger.warning("libstrangle is not available on this system, FPS limiter disabled")
|
||||
logger.warning(
|
||||
"libstrangle is not available on this system, FPS limiter disabled"
|
||||
)
|
||||
|
||||
prefix_command = system_config.get("prefix_command") or ""
|
||||
if prefix_command:
|
||||
|
@ -452,7 +471,7 @@ class Game(GObject.Object):
|
|||
"%s" % terminal
|
||||
)
|
||||
self.state = self.STATE_STOPPED
|
||||
self.emit('game-stop')
|
||||
self.emit("game-stop")
|
||||
return
|
||||
|
||||
# Env vars
|
||||
|
@ -471,10 +490,7 @@ class Game(GObject.Object):
|
|||
env["LD_PRELOAD"] = ":".join(
|
||||
[
|
||||
path
|
||||
for path in [
|
||||
env.get("LD_PRELOAD"),
|
||||
"libgamemodeauto.so",
|
||||
]
|
||||
for path in [env.get("LD_PRELOAD"), "libgamemodeauto.so",]
|
||||
if path
|
||||
]
|
||||
)
|
||||
|
@ -495,7 +511,7 @@ class Game(GObject.Object):
|
|||
"env": env,
|
||||
"terminal": terminal,
|
||||
"include_processes": include_processes,
|
||||
"exclude_processes": exclude_processes
|
||||
"exclude_processes": exclude_processes,
|
||||
}
|
||||
|
||||
if system_config.get("disable_compositor"):
|
||||
|
@ -541,7 +557,7 @@ class Game(GObject.Object):
|
|||
|
||||
def stop_game(self):
|
||||
self.state = self.STATE_STOPPED
|
||||
self.emit('game-stop')
|
||||
self.emit("game-stop")
|
||||
if not self.timer.finished:
|
||||
self.timer.end()
|
||||
self.playtime += self.timer.duration / 3600
|
||||
|
|
|
@ -25,12 +25,12 @@ class RunnerInstallDialog(Dialog):
|
|||
self.set_default_size(width, height)
|
||||
|
||||
self.runner = runner
|
||||
|
||||
|
||||
self.label = Gtk.Label("Waiting for response from %s" % (settings.SITE_URL))
|
||||
self.vbox.pack_start(self.label, False, False, 18)
|
||||
|
||||
|
||||
# Display a wait icon.
|
||||
self.spinner = Gtk.Spinner()
|
||||
self.spinner = Gtk.Spinner()
|
||||
self.vbox.pack_start(self.spinner, False, False, 18)
|
||||
self.spinner.show()
|
||||
self.spinner.start()
|
||||
|
@ -54,7 +54,7 @@ class RunnerInstallDialog(Dialog):
|
|||
for child_widget in self.vbox.get_children():
|
||||
if child_widget.get_name() not in "GtkBox":
|
||||
child_widget.destroy()
|
||||
|
||||
|
||||
label = Gtk.Label("%s version management" % self.runner_info["name"])
|
||||
self.vbox.add(label)
|
||||
self.runner_store = self.get_store()
|
||||
|
@ -166,6 +166,7 @@ class RunnerInstallDialog(Dialog):
|
|||
if self.runner == "wine":
|
||||
logger.debug("Clearing wine version cache")
|
||||
from lutris.util.wine.wine import get_wine_versions
|
||||
|
||||
get_wine_versions.cache_clear()
|
||||
|
||||
def install_runner(self, row):
|
||||
|
@ -227,6 +228,7 @@ class RunnerInstallDialog(Dialog):
|
|||
if self.runner == "wine":
|
||||
logger.debug("Clearing wine version cache")
|
||||
from lutris.util.wine.wine import get_wine_versions
|
||||
|
||||
get_wine_versions.cache_clear()
|
||||
|
||||
def on_destroy(self, _dialog, _data=None):
|
||||
|
|
|
@ -17,6 +17,7 @@ from lutris.util.jobs import AsyncCall
|
|||
|
||||
from lutris.util import http
|
||||
from lutris.util import datapath
|
||||
|
||||
# from lutris.util.steam.watcher import SteamWatcher
|
||||
|
||||
from lutris.services import get_services_synced_at_startup, steam
|
||||
|
@ -103,9 +104,9 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
GObject.add_emission_hook(Game, "game-updated", self.on_game_updated)
|
||||
GObject.add_emission_hook(Game, "game-removed", self.on_game_updated)
|
||||
GObject.add_emission_hook(Game, "game-started", self.on_game_started)
|
||||
GObject.add_emission_hook(GenericPanel,
|
||||
"running-game-selected",
|
||||
self.game_selection_changed)
|
||||
GObject.add_emission_hook(
|
||||
GenericPanel, "running-game-selected", self.game_selection_changed
|
||||
)
|
||||
self.connect("delete-event", self.on_window_delete)
|
||||
if self.maximized:
|
||||
self.maximize()
|
||||
|
@ -267,12 +268,16 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
|
||||
@property
|
||||
def left_side_panel_visible(self):
|
||||
show_left_panel = settings.read_setting("left_side_panel_visible").lower() != "false"
|
||||
show_left_panel = (
|
||||
settings.read_setting("left_side_panel_visible").lower() != "false"
|
||||
)
|
||||
return show_left_panel or self.sidebar_visible
|
||||
|
||||
@property
|
||||
def right_side_panel_visible(self):
|
||||
show_right_panel = settings.read_setting("right_side_panel_visible").lower() != "false"
|
||||
show_right_panel = (
|
||||
settings.read_setting("right_side_panel_visible").lower() != "false"
|
||||
)
|
||||
return show_right_panel or self.sidebar_visible
|
||||
|
||||
@property
|
||||
|
@ -290,7 +295,10 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
|
||||
@property
|
||||
def show_installed_first(self):
|
||||
return settings.read_setting("show_installed_first", default="false").lower() == "true"
|
||||
return (
|
||||
settings.read_setting("show_installed_first", default="false").lower()
|
||||
== "true"
|
||||
)
|
||||
|
||||
@property
|
||||
def view_sorting(self):
|
||||
|
@ -316,6 +324,7 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
|
||||
def sync_services(self):
|
||||
"""Sync local lutris library with current Steam games and desktop games"""
|
||||
|
||||
def full_sync(syncer_cls):
|
||||
syncer = syncer_cls()
|
||||
games = syncer.load()
|
||||
|
@ -374,7 +383,9 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
def set_dark_theme(self):
|
||||
"""Enables or disbales dark theme"""
|
||||
gtksettings = Gtk.Settings.get_default()
|
||||
gtksettings.set_property("gtk-application-prefer-dark-theme", self.use_dark_theme)
|
||||
gtksettings.set_property(
|
||||
"gtk-application-prefer-dark-theme", self.use_dark_theme
|
||||
)
|
||||
|
||||
def get_view(self, view_type):
|
||||
"""Return the appropriate widget for the current view"""
|
||||
|
@ -477,7 +488,9 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
self.set_show_installed_state(self.filter_installed)
|
||||
self.view.show_all()
|
||||
|
||||
self.zoom_adjustment.props.value = list(IMAGE_SIZES.keys()).index(self.icon_type)
|
||||
self.zoom_adjustment.props.value = list(IMAGE_SIZES.keys()).index(
|
||||
self.icon_type
|
||||
)
|
||||
|
||||
self.set_viewtype_icon(view_type)
|
||||
settings.write_setting("view_type", view_type)
|
||||
|
@ -485,7 +498,7 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
def set_viewtype_icon(self, view_type):
|
||||
self.viewtype_icon.set_from_icon_name(
|
||||
"view-%s-symbolic" % ("list" if view_type == "grid" else "grid"),
|
||||
Gtk.IconSize.BUTTON
|
||||
Gtk.IconSize.BUTTON,
|
||||
)
|
||||
|
||||
def sync_library(self):
|
||||
|
@ -550,19 +563,14 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
self.application.launch(game)
|
||||
else:
|
||||
InstallerWindow(
|
||||
parent=self,
|
||||
game_slug=game.slug,
|
||||
application=self.application,
|
||||
parent=self, game_slug=game.slug, application=self.application,
|
||||
)
|
||||
|
||||
@GtkTemplate.Callback
|
||||
def on_disconnect(self, *_args):
|
||||
"""Callback from user disconnect"""
|
||||
dlg = dialogs.QuestionDialog(
|
||||
{
|
||||
"question": "Do you want to log out from Lutris?",
|
||||
"title": "Log out?",
|
||||
}
|
||||
{"question": "Do you want to log out from Lutris?", "title": "Log out?",}
|
||||
)
|
||||
if dlg.result != Gtk.ResponseType.YES:
|
||||
return
|
||||
|
@ -596,8 +604,10 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
if self.application.running_games.get_n_items():
|
||||
dlg = dialogs.QuestionDialog(
|
||||
{
|
||||
"question": ("Some games are still running. "
|
||||
"Are you sure you want to quit Lutris?"),
|
||||
"question": (
|
||||
"Some games are still running. "
|
||||
"Are you sure you want to quit Lutris?"
|
||||
),
|
||||
"title": "Quit Lutris?",
|
||||
}
|
||||
)
|
||||
|
@ -688,8 +698,7 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
self.search_mode = "website"
|
||||
self.search_entry.set_placeholder_text("Search Lutris.net")
|
||||
self.search_entry.set_icon_from_icon_name(
|
||||
Gtk.EntryIconPosition.PRIMARY,
|
||||
"folder-download-symbolic"
|
||||
Gtk.EntryIconPosition.PRIMARY, "folder-download-symbolic"
|
||||
)
|
||||
self.game_store.search_mode = True
|
||||
self.search_games(self.search_terms)
|
||||
|
@ -697,8 +706,7 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
self.search_mode = "local"
|
||||
self.search_entry.set_placeholder_text("Filter the list of games")
|
||||
self.search_entry.set_icon_from_icon_name(
|
||||
Gtk.EntryIconPosition.PRIMARY,
|
||||
"system-search-symbolic"
|
||||
Gtk.EntryIconPosition.PRIMARY, "system-search-symbolic"
|
||||
)
|
||||
self.search_games("")
|
||||
|
||||
|
@ -764,7 +772,9 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
self.game_actions.set_game(game=game)
|
||||
self.game_panel = GamePanel(self.game_actions)
|
||||
self.game_panel.connect("panel-closed", self.on_panel_closed)
|
||||
self.view.contextual_menu.connect("shortcut-edited", self.game_panel.on_shortcut_edited)
|
||||
self.view.contextual_menu.connect(
|
||||
"shortcut-edited", self.game_panel.on_shortcut_edited
|
||||
)
|
||||
self.game_scrolled.add(self.game_panel)
|
||||
return True
|
||||
|
||||
|
@ -822,7 +832,9 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
self.actions["view-sorting"].set_state(GLib.Variant.new_string(key))
|
||||
settings.write_setting("view_sorting", key)
|
||||
|
||||
self.actions["view-sorting-ascending"].set_state(GLib.Variant.new_boolean(ascending))
|
||||
self.actions["view-sorting-ascending"].set_state(
|
||||
GLib.Variant.new_boolean(ascending)
|
||||
)
|
||||
settings.write_setting("view_sorting_ascending", bool(ascending))
|
||||
|
||||
def on_left_side_panel_state_change(self, action, value):
|
||||
|
@ -831,20 +843,22 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
left_side_panel_visible = value.get_boolean()
|
||||
settings.write_setting("left_side_panel_visible", bool(left_side_panel_visible))
|
||||
self.sidebar_revealer.set_reveal_child(left_side_panel_visible)
|
||||
#Retrocompatibility with sidebar_visible : if we change the new attribute, we must set the old one to false
|
||||
# Retrocompatibility with sidebar_visible : if we change the new attribute, we must set the old one to false
|
||||
if self.sidebar_visible:
|
||||
settings.write_setting("sidebar_visible","false")
|
||||
settings.write_setting("sidebar_visible", "false")
|
||||
|
||||
def on_right_side_panel_state_change(self, action, value):
|
||||
"""Callback to handle right side panel toggle"""
|
||||
action.set_state(value)
|
||||
right_side_panel_visible = value.get_boolean()
|
||||
settings.write_setting("right_side_panel_visible", bool(right_side_panel_visible))
|
||||
settings.write_setting(
|
||||
"right_side_panel_visible", bool(right_side_panel_visible)
|
||||
)
|
||||
self.panel_revealer.set_reveal_child(right_side_panel_visible)
|
||||
self.game_scrolled.set_visible(right_side_panel_visible)
|
||||
#Retrocompatibility with sidebar_visible : if we change the new attribute, we must set the old one to false
|
||||
# Retrocompatibility with sidebar_visible : if we change the new attribute, we must set the old one to false
|
||||
if self.sidebar_visible:
|
||||
settings.write_setting("sidebar_visible","false")
|
||||
settings.write_setting("sidebar_visible", "false")
|
||||
|
||||
def on_sidebar_changed(self, widget):
|
||||
row = widget.get_selected_row()
|
||||
|
@ -864,8 +878,12 @@ class LutrisWindow(Gtk.ApplicationWindow):
|
|||
self.invalidate_game_filter()
|
||||
|
||||
def show_invalid_credential_warning(self):
|
||||
dialogs.ErrorDialog("Could not connect to your Lutris account. Please sign in again.")
|
||||
dialogs.ErrorDialog(
|
||||
"Could not connect to your Lutris account. Please sign in again."
|
||||
)
|
||||
|
||||
def show_library_sync_error(self):
|
||||
dialogs.ErrorDialog("Failed to retrieve game library. "
|
||||
"There might be some problems contacting lutris.net")
|
||||
dialogs.ErrorDialog(
|
||||
"Failed to retrieve game library. "
|
||||
"There might be some problems contacting lutris.net"
|
||||
)
|
||||
|
|
|
@ -729,7 +729,7 @@ class ScriptInterpreter(CommandsMixin):
|
|||
|
||||
def revert(self):
|
||||
"""Revert installation in case of an error"""
|
||||
logger.debug("Install cancelled")
|
||||
logger.info("Cancelling installation of %s", self.game_name)
|
||||
self.cancelled = True
|
||||
|
||||
if self.abort_current_task:
|
||||
|
|
|
@ -67,7 +67,7 @@ class wine(Runner):
|
|||
"option": "args",
|
||||
"type": "string",
|
||||
"label": "Arguments",
|
||||
"help": "Windows command line arguments used when launching the game"
|
||||
"help": "Windows command line arguments used when launching the game",
|
||||
},
|
||||
{
|
||||
"option": "working_dir",
|
||||
|
@ -95,7 +95,7 @@ class wine(Runner):
|
|||
"label": "Prefix architecture",
|
||||
"choices": [("Auto", "auto"), ("32-bit", "win32"), ("64-bit", "win64")],
|
||||
"default": "auto",
|
||||
"help": "The architecture of the Windows environment"
|
||||
"help": "The architecture of the Windows environment",
|
||||
},
|
||||
]
|
||||
|
||||
|
@ -393,7 +393,7 @@ class wine(Runner):
|
|||
("2", "2"),
|
||||
("4", "4"),
|
||||
("8", "8"),
|
||||
("16", "16")
|
||||
("16", "16"),
|
||||
],
|
||||
"default": "auto",
|
||||
"advanced": True,
|
||||
|
@ -403,7 +403,7 @@ class wine(Runner):
|
|||
"panel setting available with some GPU drivers. This one might work in more "
|
||||
"cases than the driver setting though. "
|
||||
"Not all applications are compatible with all sample counts. "
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
"option": "UseXVidMode",
|
||||
|
@ -498,9 +498,7 @@ class wine(Runner):
|
|||
@property
|
||||
def context_menu_entries(self):
|
||||
"""Return the contexual menu entries for wine"""
|
||||
menu_entries = [
|
||||
("wineexec", "Run EXE inside wine prefix", self.run_wineexec)
|
||||
]
|
||||
menu_entries = [("wineexec", "Run EXE inside wine prefix", self.run_wineexec)]
|
||||
if "Proton" not in self.get_version():
|
||||
menu_entries.append(("winecfg", "Wine configuration", self.run_winecfg))
|
||||
menu_entries += [
|
||||
|
@ -517,8 +515,10 @@ class wine(Runner):
|
|||
"""Return the absolute path of the Wine prefix"""
|
||||
_prefix_path = self.game_config.get("prefix")
|
||||
if not _prefix_path:
|
||||
logger.warning("Wine prefix not provided, defaulting to $WINEPREFIX then ~/.wine."
|
||||
" This is probably not the intended behavior.")
|
||||
logger.warning(
|
||||
"Wine prefix not provided, defaulting to $WINEPREFIX then ~/.wine."
|
||||
" This is probably not the intended behavior."
|
||||
)
|
||||
_prefix_path = os.environ.get("WINEPREFIX") or "~/.wine"
|
||||
return os.path.expanduser(_prefix_path)
|
||||
|
||||
|
@ -629,13 +629,13 @@ class wine(Runner):
|
|||
|
||||
@classmethod
|
||||
def msi_exec(
|
||||
cls,
|
||||
msi_file,
|
||||
quiet=False,
|
||||
prefix=None,
|
||||
wine_path=None,
|
||||
working_dir=None,
|
||||
blocking=False,
|
||||
cls,
|
||||
msi_file,
|
||||
quiet=False,
|
||||
prefix=None,
|
||||
wine_path=None,
|
||||
working_dir=None,
|
||||
blocking=False,
|
||||
):
|
||||
msi_args = "/i %s" % msi_file
|
||||
if quiet:
|
||||
|
@ -656,7 +656,7 @@ class wine(Runner):
|
|||
wine_path=self.get_executable(),
|
||||
prefix=self.prefix_path,
|
||||
config=self,
|
||||
env=self.get_env(os_env=True)
|
||||
env=self.get_env(os_env=True),
|
||||
)
|
||||
|
||||
def run_wineexec(self, *args):
|
||||
|
@ -765,7 +765,9 @@ class wine(Runner):
|
|||
dxvk_manager=dxvk_manager,
|
||||
)
|
||||
except dxvk.UnavailableDXVKVersion:
|
||||
raise GameConfigError("Unable to get "+base_name.upper()+" %s" % dxvk_manager.version)
|
||||
raise GameConfigError(
|
||||
"Unable to get " + base_name.upper() + " %s" % dxvk_manager.version
|
||||
)
|
||||
|
||||
def prelaunch(self):
|
||||
if not system.path_exists(os.path.join(self.prefix_path, "user.reg")):
|
||||
|
@ -776,15 +778,25 @@ class wine(Runner):
|
|||
self.sandbox(prefix_manager)
|
||||
self.set_regedit_keys()
|
||||
self.setup_x360ce(self.runner_config.get("x360ce-path"))
|
||||
self.setup_dxvk("dxvk", dxvk_manager=dxvk.DXVKManager(
|
||||
self.prefix_path, arch=self.wine_arch, version=self.runner_config.get("dxvk_version")
|
||||
),)
|
||||
self.setup_dxvk(
|
||||
"dxvk",
|
||||
dxvk_manager=dxvk.DXVKManager(
|
||||
self.prefix_path,
|
||||
arch=self.wine_arch,
|
||||
version=self.runner_config.get("dxvk_version"),
|
||||
),
|
||||
)
|
||||
|
||||
# we don't want d9vk to restore d3d9.dll, because dxvk could set it already
|
||||
if bool(self.runner_config.get("d9vk")):
|
||||
self.setup_dxvk("d9vk", dxvk_manager=dxvk.D9VKManager(
|
||||
self.prefix_path, arch=self.wine_arch, version=self.runner_config.get("d9vk_version")
|
||||
),)
|
||||
self.setup_dxvk(
|
||||
"d9vk",
|
||||
dxvk_manager=dxvk.D9VKManager(
|
||||
self.prefix_path,
|
||||
arch=self.wine_arch,
|
||||
version=self.runner_config.get("d9vk_version"),
|
||||
),
|
||||
)
|
||||
try:
|
||||
self.setup_nine(self.runner_config.get("gallium_nine"))
|
||||
except nine.NineUnavailable as ex:
|
||||
|
@ -794,7 +806,7 @@ class wine(Runner):
|
|||
def get_dll_overrides(self):
|
||||
"""Return the DLLs overriden at runtime"""
|
||||
try:
|
||||
overrides = self.runner_config['overrides']
|
||||
overrides = self.runner_config["overrides"]
|
||||
except KeyError:
|
||||
overrides = {}
|
||||
else:
|
||||
|
@ -847,7 +859,7 @@ class wine(Runner):
|
|||
return runtime.get_env(
|
||||
version=version,
|
||||
prefer_system_libs=self.system_config.get("prefer_system_libs", True),
|
||||
wine_path=wine_root
|
||||
wine_path=wine_root,
|
||||
)
|
||||
|
||||
def get_pids(self, wine_path=None):
|
||||
|
@ -908,10 +920,7 @@ class wine(Runner):
|
|||
self.dll_overrides["dinput8"] = "native"
|
||||
|
||||
def setup_nine(self, enable):
|
||||
nine_manager = nine.NineManager(
|
||||
self.prefix_path,
|
||||
self.wine_arch,
|
||||
)
|
||||
nine_manager = nine.NineManager(self.prefix_path, self.wine_arch,)
|
||||
|
||||
if enable:
|
||||
nine_manager.enable()
|
||||
|
|
|
@ -12,7 +12,7 @@ from lutris.util.steam.config import read_config
|
|||
from lutris.util.steam.appmanifest import get_path_from_appmanifest
|
||||
from lutris.util.wine.registry import WineRegistry
|
||||
from lutris.util.wine.wine import WINE_DEFAULT_ARCH
|
||||
from lutris.runners.commands.wine import ( # noqa pylint: disable=unused-import
|
||||
from lutris.runners.commands.wine import ( # noqa pylint: disable=unused-import
|
||||
set_regedit,
|
||||
set_regedit_file,
|
||||
delete_registry_key,
|
||||
|
@ -24,7 +24,9 @@ from lutris.runners.commands.wine import ( # noqa pylint: disable=unused-import
|
|||
install_cab_component,
|
||||
)
|
||||
|
||||
STEAM_INSTALLER_URL = "https://lutris.nyc3.cdn.digitaloceanspaces.com/runners/winesteam/SteamSetup.exe"
|
||||
STEAM_INSTALLER_URL = (
|
||||
"https://lutris.nyc3.cdn.digitaloceanspaces.com/runners/winesteam/SteamSetup.exe"
|
||||
)
|
||||
|
||||
|
||||
def is_running():
|
||||
|
@ -109,8 +111,8 @@ class winesteam(wine.wine):
|
|||
"type": "file",
|
||||
"label": "Game binary path",
|
||||
"advanced": True,
|
||||
"help": "Path to the game executable (Required by DRM free mode)"
|
||||
}
|
||||
"help": "Path to the game executable (Required by DRM free mode)",
|
||||
},
|
||||
]
|
||||
|
||||
def __init__(self, config=None):
|
||||
|
@ -255,8 +257,8 @@ class winesteam(wine.wine):
|
|||
for prefix in candidates:
|
||||
# Try the default install path
|
||||
for default_path in [
|
||||
"drive_c/Program Files (x86)/Steam/Steam.exe",
|
||||
"drive_c/Program Files/Steam/Steam.exe",
|
||||
"drive_c/Program Files (x86)/Steam/Steam.exe",
|
||||
"drive_c/Program Files/Steam/Steam.exe",
|
||||
]:
|
||||
steam_path = os.path.join(prefix, default_path)
|
||||
if system.path_exists(steam_path):
|
||||
|
@ -281,11 +283,7 @@ class winesteam(wine.wine):
|
|||
prefix = self.get_or_create_default_prefix()
|
||||
|
||||
# Install CJK fonts in the Steam prefix before Steam
|
||||
winetricks(
|
||||
"cjkfonts",
|
||||
prefix=prefix,
|
||||
wine_path=self.get_executable()
|
||||
)
|
||||
winetricks("cjkfonts", prefix=prefix, wine_path=self.get_executable())
|
||||
wineexec(
|
||||
installer_path,
|
||||
args="/S",
|
||||
|
@ -294,11 +292,14 @@ class winesteam(wine.wine):
|
|||
)
|
||||
if callback:
|
||||
callback()
|
||||
|
||||
downloader(STEAM_INSTALLER_URL, installer_path, on_steam_downloaded)
|
||||
|
||||
def is_installed(self, version=None, fallback=True, min_version=None):
|
||||
"""Checks if wine is installed and if the steam executable is on the drive"""
|
||||
if not super().is_installed(version=version, fallback=fallback, min_version=min_version):
|
||||
if not super().is_installed(
|
||||
version=version, fallback=fallback, min_version=min_version
|
||||
):
|
||||
return False
|
||||
if not system.path_exists(self.get_default_prefix(arch=self.default_arch)):
|
||||
return False
|
||||
|
@ -382,21 +383,20 @@ class winesteam(wine.wine):
|
|||
if not appid:
|
||||
raise ValueError("Missing appid in winesteam.install_game")
|
||||
system.execute(
|
||||
self.launch_args + ["steam://install/%s" % appid],
|
||||
env=self.get_env()
|
||||
self.launch_args + ["steam://install/%s" % appid], env=self.get_env()
|
||||
)
|
||||
|
||||
def validate_game(self, appid):
|
||||
if not appid:
|
||||
raise ValueError("Missing appid in winesteam.validate_game")
|
||||
system.execute(
|
||||
self.launch_args + ["steam://validate/%s" % appid],
|
||||
env=self.get_env()
|
||||
self.launch_args + ["steam://validate/%s" % appid], env=self.get_env()
|
||||
)
|
||||
|
||||
def force_shutdown(self):
|
||||
"""Forces a Steam shutdown, double checking its exit status and raising
|
||||
an error if it cannot be killed"""
|
||||
|
||||
def has_steam_shutdown(times=10):
|
||||
for _ in range(1, times + 1):
|
||||
time.sleep(1)
|
||||
|
@ -452,10 +452,7 @@ class winesteam(wine.wine):
|
|||
if self.runner_config.get("x360ce-path"):
|
||||
self.setup_x360ce(self.runner_config["x360ce-path"])
|
||||
try:
|
||||
return {
|
||||
"env": self.get_env(os_env=False),
|
||||
"command": self.get_command()
|
||||
}
|
||||
return {"env": self.get_env(os_env=False), "command": self.get_command()}
|
||||
except FileNotFoundError as ex:
|
||||
return {"error": "FILE_NOT_FOUND", "file": ex.filename}
|
||||
|
||||
|
@ -465,7 +462,7 @@ class winesteam(wine.wine):
|
|||
shutdown_command = MonitoredCommand(
|
||||
(self.launch_args + ["-shutdown"]),
|
||||
runner=self,
|
||||
env=self.get_env(os_env=False)
|
||||
env=self.get_env(os_env=False),
|
||||
)
|
||||
shutdown_command.start()
|
||||
|
||||
|
@ -485,6 +482,6 @@ class winesteam(wine.wine):
|
|||
uninstall_command = MonitoredCommand(
|
||||
(self.launch_args + ["steam://uninstall/%s" % (appid or self.appid)]),
|
||||
runner=self,
|
||||
env=self.get_env(os_env=False)
|
||||
env=self.get_env(os_env=False),
|
||||
)
|
||||
uninstall_command.start()
|
||||
|
|
|
@ -147,7 +147,8 @@ class GogService:
|
|||
token = self.load_token()
|
||||
if not token:
|
||||
logger.warning(
|
||||
"Request to %s cancelled because the GOG token could not be acquired", url
|
||||
"Request to %s cancelled because the GOG token could not be acquired",
|
||||
url,
|
||||
)
|
||||
return
|
||||
headers = {"Authorization": "Bearer " + token["access_token"]}
|
||||
|
@ -157,7 +158,7 @@ class GogService:
|
|||
except HTTPError:
|
||||
logger.error(
|
||||
"Failed to request %s, check your GOG credentials and internet connectivity",
|
||||
url
|
||||
url,
|
||||
)
|
||||
return
|
||||
request.get()
|
||||
|
@ -173,7 +174,7 @@ class GogService:
|
|||
|
||||
if system.path_exists(self.cache_path) and not force_reload:
|
||||
logger.debug("Returning cached GOG library")
|
||||
with open(self.cache_path, 'r') as gog_cache:
|
||||
with open(self.cache_path, "r") as gog_cache:
|
||||
return json.load(gog_cache)
|
||||
|
||||
total_pages = 1
|
||||
|
@ -184,7 +185,7 @@ class GogService:
|
|||
page += 1
|
||||
total_pages = products_response["totalPages"]
|
||||
games += products_response["products"]
|
||||
with open(self.cache_path, 'w') as gog_cache:
|
||||
with open(self.cache_path, "w") as gog_cache:
|
||||
json.dump(games, gog_cache)
|
||||
return games
|
||||
|
||||
|
@ -226,9 +227,9 @@ class GOGGame(ServiceGame):
|
|||
def new_from_gog_game(cls, gog_game):
|
||||
"""Return a GOG game instance from the API info"""
|
||||
service_game = GOGGame()
|
||||
service_game.appid = str(gog_game['id'])
|
||||
service_game.appid = str(gog_game["id"])
|
||||
service_game.icon = cls.get_banner(gog_game)
|
||||
service_game.name = gog_game['title']
|
||||
service_game.name = gog_game["title"]
|
||||
service_game.details = json.dumps(gog_game)
|
||||
return service_game
|
||||
|
||||
|
@ -237,8 +238,8 @@ class GOGGame(ServiceGame):
|
|||
"""Return the path to the game banner.
|
||||
Downloads the banner if not present.
|
||||
"""
|
||||
image_url = "https:%s_prof_game_100x60.jpg" % gog_game['image']
|
||||
image_hash = gog_game['image'].split("/")[-1]
|
||||
image_url = "https:%s_prof_game_100x60.jpg" % gog_game["image"]
|
||||
image_hash = gog_game["image"].split("/")[-1]
|
||||
cache_dir = os.path.join(settings.CACHE_DIR, "gog/banners/small/")
|
||||
if not system.path_exists(cache_dir):
|
||||
os.makedirs(cache_dir)
|
||||
|
@ -293,7 +294,9 @@ class GOGSyncer:
|
|||
"slug": game["slug"],
|
||||
"year": game["year"],
|
||||
"updated": game["updated"],
|
||||
"gogid": game.get("gogid"), # GOG IDs will be added at a later stage in the API
|
||||
"gogid": game.get(
|
||||
"gogid"
|
||||
), # GOG IDs will be added at a later stage in the API
|
||||
}
|
||||
added_games.append(pga.add_or_update(**game_data))
|
||||
if not full:
|
||||
|
|
|
@ -15,6 +15,7 @@ ONLINE = False
|
|||
|
||||
class SteamGame(ServiceGame):
|
||||
"""ServiceGame for Steam games"""
|
||||
|
||||
store = "steam"
|
||||
installer_slug = "steam"
|
||||
excluded_appids = [
|
||||
|
@ -80,7 +81,9 @@ class SteamGame(ServiceGame):
|
|||
|
||||
def create_config(self):
|
||||
"""Create the game configuration for a Steam game"""
|
||||
game_config = LutrisConfig(runner_slug=self.runner, game_config_id=self.config_id)
|
||||
game_config = LutrisConfig(
|
||||
runner_slug=self.runner, game_config_id=self.config_id
|
||||
)
|
||||
game_config.raw_game_config.update({"appid": self.appid})
|
||||
game_config.save()
|
||||
|
||||
|
@ -100,8 +103,7 @@ class SteamSyncer:
|
|||
def lutris_games(self):
|
||||
if not self._lutris_games:
|
||||
self._lutris_games = pga.get_games_where(
|
||||
steamid__isnull=False,
|
||||
steamid__not=""
|
||||
steamid__isnull=False, steamid__not=""
|
||||
)
|
||||
return self._lutris_games
|
||||
|
||||
|
@ -117,7 +119,9 @@ class SteamSyncer:
|
|||
steamapps_paths = get_steamapps_paths()
|
||||
for steamapps_path in steamapps_paths[self.platform]:
|
||||
for appmanifest_file in get_appmanifests(steamapps_path):
|
||||
app_manifest = AppManifest(os.path.join(steamapps_path, appmanifest_file))
|
||||
app_manifest = AppManifest(
|
||||
os.path.join(steamapps_path, appmanifest_file)
|
||||
)
|
||||
if SteamGame.is_importable(app_manifest):
|
||||
games.append(SteamGame.new_from_steam_game(app_manifest))
|
||||
return games
|
||||
|
@ -126,9 +130,9 @@ class SteamSyncer:
|
|||
"""Return a PGA game if one is found"""
|
||||
for pga_game in self.lutris_games:
|
||||
if (
|
||||
str(pga_game["steamid"]) == game.appid
|
||||
and pga_game["runner"] == self.runner
|
||||
and not pga_game["installed"]
|
||||
str(pga_game["steamid"]) == game.appid
|
||||
and pga_game["runner"] == self.runner
|
||||
and not pga_game["installed"]
|
||||
):
|
||||
return pga_game
|
||||
|
||||
|
@ -142,7 +146,11 @@ class SteamSyncer:
|
|||
pga_game = self.get_pga_game(game)
|
||||
|
||||
if pga_game:
|
||||
if steamid in self.lutris_steamids and pga_game["installed"] != 1 and pga_game["installed"]:
|
||||
if (
|
||||
steamid in self.lutris_steamids
|
||||
and pga_game["installed"] != 1
|
||||
and pga_game["installed"]
|
||||
):
|
||||
added_games.append(game.install())
|
||||
|
||||
if steamid not in self.lutris_steamids:
|
||||
|
@ -159,9 +167,9 @@ class SteamSyncer:
|
|||
for steamid in unavailable_ids:
|
||||
for pga_game in self.lutris_games:
|
||||
if (
|
||||
str(pga_game["steamid"]) == steamid
|
||||
and pga_game["installed"]
|
||||
and pga_game["runner"] == self.runner
|
||||
str(pga_game["steamid"]) == steamid
|
||||
and pga_game["installed"]
|
||||
and pga_game["runner"] == self.runner
|
||||
):
|
||||
game = SteamGame.new_from_lutris_id(pga_game["id"])
|
||||
game.uninstall()
|
||||
|
|
|
@ -51,7 +51,9 @@ def check_driver():
|
|||
if drivers.is_nvidia():
|
||||
driver_info = drivers.get_nvidia_driver_info()
|
||||
# pylint: disable=logging-format-interpolation
|
||||
logger.info("Using {vendor} drivers {version} for {arch}".format(**driver_info["nvrm"]))
|
||||
logger.info(
|
||||
"Using {vendor} drivers {version} for {arch}".format(**driver_info["nvrm"])
|
||||
)
|
||||
gpus = drivers.get_nvidia_gpu_ids()
|
||||
for gpu_id in gpus:
|
||||
gpu_info = drivers.get_nvidia_gpu_info(gpu_id)
|
||||
|
@ -65,7 +67,9 @@ def check_driver():
|
|||
LINUX_SYSTEM.glxinfo.GLX_MESA_query_renderer.device,
|
||||
)
|
||||
else:
|
||||
logger.warning("glxinfo is not available on your system, unable to detect driver version")
|
||||
logger.warning(
|
||||
"glxinfo is not available on your system, unable to detect driver version"
|
||||
)
|
||||
|
||||
for card in drivers.get_gpus():
|
||||
# pylint: disable=logging-format-interpolation
|
||||
|
@ -88,8 +92,7 @@ def check_driver():
|
|||
"fully support all features for Vulkan and DXVK games.\n"
|
||||
"Please upgrade your driver as described in our "
|
||||
"<a href='https://github.com/lutris/lutris/wiki/Installing-drivers'>"
|
||||
"installation guide</a>"
|
||||
% driver_info["nvrm"]["version"]
|
||||
"installation guide</a>" % driver_info["nvrm"]["version"],
|
||||
)
|
||||
|
||||
|
||||
|
@ -118,8 +121,7 @@ def check_libs(all_components=False):
|
|||
"This will prevent many games and programs from working.\n"
|
||||
"To install it, please use the following guide: "
|
||||
"<a href='https://github.com/lutris/lutris/wiki/Installing-drivers'>"
|
||||
"Installing Graphics Drivers</a>"
|
||||
% " and ".join(missing_vulkan_libs)
|
||||
"Installing Graphics Drivers</a>" % " and ".join(missing_vulkan_libs),
|
||||
)
|
||||
|
||||
|
||||
|
@ -143,7 +145,7 @@ def check_donate():
|
|||
"Please consider making a donation if you can. This will greatly help "
|
||||
"cover the costs of hosting the project and fund new features "
|
||||
"like cloud saves or a full-screen interface for the TV!\n"
|
||||
"<a href='https://lutris.net/donate'>SUPPORT US! https://lutris.net/donate</a>"
|
||||
"<a href='https://lutris.net/donate'>SUPPORT US! https://lutris.net/donate</a>",
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -106,9 +106,7 @@ def extract_archive(path, to_directory=".", merge_single=True, extractor=None):
|
|||
elif extractor is None or is_7zip_supported(path, extractor):
|
||||
opener = "7zip"
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"Could not extract `%s` - unknown format specified" % path
|
||||
)
|
||||
raise RuntimeError("Could not extract `%s` - unknown format specified" % path)
|
||||
|
||||
temp_name = ".extract-" + str(uuid.uuid4())[:8]
|
||||
temp_path = temp_dir = os.path.join(to_directory, temp_name)
|
||||
|
@ -144,7 +142,11 @@ def extract_archive(path, to_directory=".", merge_single=True, extractor=None):
|
|||
try:
|
||||
system.merge_folders(source_path, destination_path)
|
||||
except OSError as ex:
|
||||
logger.error("Failed to merge to destination %s: %s", destination_path, ex)
|
||||
logger.error(
|
||||
"Failed to merge to destination %s: %s",
|
||||
destination_path,
|
||||
ex,
|
||||
)
|
||||
raise ExtractFailure(str(ex))
|
||||
else:
|
||||
shutil.move(source_path, destination_path)
|
||||
|
@ -170,7 +172,7 @@ def extract_exe(path, dest):
|
|||
if check_inno_exe(path):
|
||||
decompress_gog(path, dest)
|
||||
else:
|
||||
#use 7za to check if exe is an archive
|
||||
# use 7za to check if exe is an archive
|
||||
_7zip_path = os.path.join(settings.RUNTIME_DIR, "p7zip/7za")
|
||||
if not system.path_exists(_7zip_path):
|
||||
_7zip_path = system.find_executable("7za")
|
||||
|
@ -191,13 +193,13 @@ def extract_gog(path, dest):
|
|||
raise RuntimeError("specified exe is not a GOG setup file")
|
||||
|
||||
|
||||
#Check if exe is in fact an inno setup file
|
||||
# Check if exe is in fact an inno setup file
|
||||
def check_inno_exe(path):
|
||||
_innoextract_path = os.path.join(settings.RUNTIME_DIR, "innoextract/innoextract")
|
||||
if not system.path_exists(_innoextract_path):
|
||||
_innoextract_path = system.find_executable("innoextract")
|
||||
if not system.path_exists(_innoextract_path):
|
||||
return False #Can't find innoextract
|
||||
return False # Can't find innoextract
|
||||
command = [_innoextract_path, "-i", path]
|
||||
return_code = subprocess.call(command)
|
||||
if return_code != 0:
|
||||
|
@ -211,7 +213,7 @@ def decompress_gog(file_path, destination_path):
|
|||
_innoextract_path = system.find_executable("innoextract")
|
||||
if not system.path_exists(_innoextract_path):
|
||||
raise OSError("innoextract is not found in the lutris runtime or on the system")
|
||||
#innoextract cannot do mkdir -p, so we have to do it here:
|
||||
# innoextract cannot do mkdir -p, so we have to do it here:
|
||||
try:
|
||||
os.makedirs(destination_path)
|
||||
except OSError as e:
|
||||
|
|
|
@ -68,48 +68,39 @@ SYSTEM_COMPONENTS = {
|
|||
"alacritty",
|
||||
],
|
||||
"LIBRARIES": {
|
||||
"OPENGL": [
|
||||
"libGL.so.1",
|
||||
],
|
||||
"VULKAN": [
|
||||
"libvulkan.so.1",
|
||||
],
|
||||
"WINE": [
|
||||
"libsqlite3.so.0"
|
||||
],
|
||||
"RADEON": [
|
||||
"libvulkan_radeon.so"
|
||||
],
|
||||
"GAMEMODE": [
|
||||
"libgamemodeauto.so"
|
||||
]
|
||||
}
|
||||
"OPENGL": ["libGL.so.1",],
|
||||
"VULKAN": ["libvulkan.so.1",],
|
||||
"WINE": ["libsqlite3.so.0"],
|
||||
"RADEON": ["libvulkan_radeon.so"],
|
||||
"GAMEMODE": ["libgamemodeauto.so"],
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class LinuxSystem:
|
||||
"""Global cache for system commands"""
|
||||
|
||||
_cache = {}
|
||||
|
||||
multiarch_lib_folders = [
|
||||
('/lib', '/lib64'),
|
||||
('/lib32', '/lib64'),
|
||||
('/usr/lib', '/usr/lib64'),
|
||||
('/usr/lib32', '/usr/lib64'),
|
||||
('/lib/i386-linux-gnu', '/lib/x86_64-linux-gnu'),
|
||||
('/usr/lib/i386-linux-gnu', '/usr/lib/x86_64-linux-gnu'),
|
||||
("/lib", "/lib64"),
|
||||
("/lib32", "/lib64"),
|
||||
("/usr/lib", "/usr/lib64"),
|
||||
("/usr/lib32", "/usr/lib64"),
|
||||
("/lib/i386-linux-gnu", "/lib/x86_64-linux-gnu"),
|
||||
("/usr/lib/i386-linux-gnu", "/usr/lib/x86_64-linux-gnu"),
|
||||
]
|
||||
|
||||
soundfont_folders = [
|
||||
'/usr/share/sounds/sf2',
|
||||
'/usr/share/soundfonts',
|
||||
"/usr/share/sounds/sf2",
|
||||
"/usr/share/soundfonts",
|
||||
]
|
||||
|
||||
recommended_no_file_open = 524288
|
||||
required_components = ["OPENGL", "VULKAN"]
|
||||
optional_components = ["WINE", "GAMEMODE"]
|
||||
|
||||
flatpak_info_path="/.flatpak-info"
|
||||
flatpak_info_path = "/.flatpak-info"
|
||||
|
||||
def __init__(self):
|
||||
for key in ("COMMANDS", "TERMINALS"):
|
||||
|
@ -170,7 +161,8 @@ class LinuxSystem:
|
|||
logger.error("Failed to get drive information: %s", ex)
|
||||
return None
|
||||
return [
|
||||
drive for drive in json.loads(output)["blockdevices"]
|
||||
drive
|
||||
for drive in json.loads(output)["blockdevices"]
|
||||
if drive["fstype"] != "squashfs"
|
||||
]
|
||||
|
||||
|
@ -282,7 +274,7 @@ class LinuxSystem:
|
|||
exported_lib_folders.add(lib_folder)
|
||||
yield lib_folder
|
||||
for lib_paths in self.multiarch_lib_folders:
|
||||
if self.arch != 'x86_64':
|
||||
if self.arch != "x86_64":
|
||||
# On non amd64 setups, only the first element is relevant
|
||||
lib_paths = [lib_paths[0]]
|
||||
else:
|
||||
|
@ -291,11 +283,11 @@ class LinuxSystem:
|
|||
continue
|
||||
if all([os.path.exists(path) for path in lib_paths]):
|
||||
if lib_paths[0] not in exported_lib_folders:
|
||||
yield lib_paths[0]
|
||||
yield lib_paths[0]
|
||||
if len(lib_paths) != 1:
|
||||
if lib_paths[1] not in exported_lib_folders:
|
||||
yield lib_paths[1]
|
||||
|
||||
|
||||
def get_ldconfig_libs(self):
|
||||
"""Return a list of available libraries, as returned by `ldconfig -p`."""
|
||||
ldconfig = self.get("ldconfig")
|
||||
|
@ -303,7 +295,11 @@ class LinuxSystem:
|
|||
logger.error("Could not detect ldconfig on this system")
|
||||
return []
|
||||
try:
|
||||
output = subprocess.check_output([ldconfig, "-p"]).decode("utf-8", errors="ignore").split("\n")
|
||||
output = (
|
||||
subprocess.check_output([ldconfig, "-p"])
|
||||
.decode("utf-8", errors="ignore")
|
||||
.split("\n")
|
||||
)
|
||||
except subprocess.CalledProcessError as ex:
|
||||
logger.error("Failed to get libraries from ldconfig: %s", ex)
|
||||
return []
|
||||
|
@ -351,8 +347,7 @@ class LinuxSystem:
|
|||
def get_missing_libs(self):
|
||||
"""Return a dictionary of missing libraries"""
|
||||
return {
|
||||
req: self.get_missing_requirement_libs(req)
|
||||
for req in self.requirements
|
||||
req: self.get_missing_requirement_libs(req) for req in self.requirements
|
||||
}
|
||||
|
||||
def is_feature_supported(self, feature):
|
||||
|
@ -362,6 +357,7 @@ class LinuxSystem:
|
|||
|
||||
class SharedLibrary:
|
||||
"""Representation of a Linux shared library"""
|
||||
|
||||
default_arch = "i386"
|
||||
|
||||
def __init__(self, name, flags, path):
|
||||
|
@ -374,7 +370,9 @@ class SharedLibrary:
|
|||
"""Create a SharedLibrary instance from an output line from ldconfig"""
|
||||
lib_match = re.match(r"^(.*) \((.*)\) => (.*)$", ldconfig_line)
|
||||
if not lib_match:
|
||||
raise ValueError("Received incorrect value for ldconfig line: %s" % ldconfig_line)
|
||||
raise ValueError(
|
||||
"Received incorrect value for ldconfig line: %s" % ldconfig_line
|
||||
)
|
||||
return cls(lib_match.group(1), lib_match.group(2), lib_match.group(3))
|
||||
|
||||
@property
|
||||
|
|
|
@ -36,17 +36,23 @@ def init_dxvk_versions():
|
|||
version_name = x["tag_name"].replace("v", "")
|
||||
if internet_available or version_name in os.listdir(dxvk_path):
|
||||
dxvk_versions.append(version_name)
|
||||
if not dxvk_versions: # We don't want to set manager.DXVK_VERSIONS, if the list is empty
|
||||
if (
|
||||
not dxvk_versions
|
||||
): # We don't want to set manager.DXVK_VERSIONS, if the list is empty
|
||||
raise IndexError
|
||||
return dxvk_versions
|
||||
|
||||
def init_versions(manager):
|
||||
try:
|
||||
manager.DXVK_VERSIONS \
|
||||
= get_dxvk_versions(manager.base_name, manager.DXVK_TAGS_URL)
|
||||
manager.DXVK_VERSIONS = get_dxvk_versions(
|
||||
manager.base_name, manager.DXVK_TAGS_URL
|
||||
)
|
||||
except (IndexError, FileNotFoundError):
|
||||
pass
|
||||
manager.DXVK_LATEST, manager.DXVK_PAST_RELEASES = manager.DXVK_VERSIONS[0], manager.DXVK_VERSIONS[1:9]
|
||||
manager.DXVK_LATEST, manager.DXVK_PAST_RELEASES = (
|
||||
manager.DXVK_VERSIONS[0],
|
||||
manager.DXVK_VERSIONS[1:9],
|
||||
)
|
||||
|
||||
init_versions(DXVKManager)
|
||||
init_versions(D9VKManager)
|
||||
|
@ -110,14 +116,17 @@ class DXVKManager:
|
|||
|
||||
def dxvk_dll_exists(self, dll_name):
|
||||
"""Check if the dll exists as a DXVK variant"""
|
||||
return system.path_exists(os.path.join(self.dxvk_path, "x64", dll_name + ".dll")) \
|
||||
and system.path_exists(os.path.join(self.dxvk_path, "x32", dll_name + ".dll"))
|
||||
return system.path_exists(
|
||||
os.path.join(self.dxvk_path, "x64", dll_name + ".dll")
|
||||
) and system.path_exists(os.path.join(self.dxvk_path, "x32", dll_name + ".dll"))
|
||||
|
||||
def download(self):
|
||||
"""Download DXVK to the local cache"""
|
||||
dxvk_url = self.base_url.format(self.version, self.version)
|
||||
if self.is_available():
|
||||
logger.warning("%s already available at %s", self.base_name.upper(), self.dxvk_path)
|
||||
logger.warning(
|
||||
"%s already available at %s", self.base_name.upper(), self.dxvk_path
|
||||
)
|
||||
|
||||
dxvk_archive_path = os.path.join(self.base_dir, os.path.basename(dxvk_url))
|
||||
|
||||
|
@ -126,13 +135,17 @@ class DXVKManager:
|
|||
while downloader.check_progress() < 1 and downloader.state != downloader.ERROR:
|
||||
time.sleep(0.3)
|
||||
if not system.path_exists(dxvk_archive_path):
|
||||
raise UnavailableDXVKVersion("Failed to download %s %s" % (self.base_name.upper(), self.version))
|
||||
raise UnavailableDXVKVersion(
|
||||
"Failed to download %s %s" % (self.base_name.upper(), self.version)
|
||||
)
|
||||
if os.stat(dxvk_archive_path).st_size:
|
||||
extract_archive(dxvk_archive_path, self.dxvk_path, merge_single=True)
|
||||
os.remove(dxvk_archive_path)
|
||||
else:
|
||||
os.remove(dxvk_archive_path)
|
||||
raise UnavailableDXVKVersion("Failed to download %s %s" % (self.base_name.upper(), self.version))
|
||||
raise UnavailableDXVKVersion(
|
||||
"Failed to download %s %s" % (self.base_name.upper(), self.version)
|
||||
)
|
||||
|
||||
def enable_dxvk_dll(self, system_dir, dxvk_arch, dll):
|
||||
"""Copies DXVK dlls to the appropriate destination"""
|
||||
|
@ -140,9 +153,16 @@ class DXVKManager:
|
|||
dxvk_dll_path = os.path.join(self.dxvk_path, dxvk_arch, "%s.dll" % dll)
|
||||
if system.path_exists(dxvk_dll_path):
|
||||
wine_dll_path = os.path.join(system_dir, "%s.dll" % dll)
|
||||
logger.info("Replacing %s/%s with %s version", system_dir, dll, self.base_name.upper())
|
||||
logger.info(
|
||||
"Replacing %s/%s with %s version",
|
||||
system_dir,
|
||||
dll,
|
||||
self.base_name.upper(),
|
||||
)
|
||||
if system.path_exists(wine_dll_path):
|
||||
if not self.is_dxvk_dll(wine_dll_path) and not os.path.islink(wine_dll_path):
|
||||
if not self.is_dxvk_dll(wine_dll_path) and not os.path.islink(
|
||||
wine_dll_path
|
||||
):
|
||||
# Backing up original version (may not be needed)
|
||||
shutil.move(wine_dll_path, wine_dll_path + ".orig")
|
||||
else:
|
||||
|
@ -156,7 +176,9 @@ class DXVKManager:
|
|||
wine_dll_path = os.path.join(system_dir, "%s.dll" % dll)
|
||||
if system.path_exists(wine_dll_path + ".orig"):
|
||||
if system.path_exists(wine_dll_path):
|
||||
logger.info("Removing %s dll %s/%s", self.base_name.upper(), system_dir, dll)
|
||||
logger.info(
|
||||
"Removing %s dll %s/%s", self.base_name.upper(), system_dir, dll
|
||||
)
|
||||
os.remove(wine_dll_path)
|
||||
shutil.move(wine_dll_path + ".orig", wine_dll_path)
|
||||
|
||||
|
@ -177,7 +199,9 @@ class DXVKManager:
|
|||
def enable(self):
|
||||
"""Enable DXVK for the current prefix"""
|
||||
if not system.path_exists(self.dxvk_path):
|
||||
logger.error("%s %s is not available locally", self.base_name.upper(), self.version)
|
||||
logger.error(
|
||||
"%s %s is not available locally", self.base_name.upper(), self.version
|
||||
)
|
||||
return
|
||||
for system_dir, dxvk_arch, dll in self._iter_dxvk_dlls():
|
||||
self.enable_dxvk_dll(system_dir, dxvk_arch, dll)
|
||||
|
@ -195,7 +219,9 @@ class D9VKManager(DXVKManager):
|
|||
]
|
||||
DXVK_LATEST, DXVK_PAST_RELEASES = DXVK_VERSIONS[0], DXVK_VERSIONS[1:9]
|
||||
|
||||
base_url = "https://github.com/Joshua-Ashton/d9vk/releases/download/{}/d9vk-{}.tar.gz"
|
||||
base_url = (
|
||||
"https://github.com/Joshua-Ashton/d9vk/releases/download/{}/d9vk-{}.tar.gz"
|
||||
)
|
||||
base_name = "d9vk"
|
||||
base_dir = os.path.join(RUNTIME_DIR, base_name)
|
||||
dxvk_dlls = ("d3d9",)
|
||||
|
|
|
@ -6,9 +6,11 @@ from lutris.util import system
|
|||
from lutris.runners.commands.wine import wineexec
|
||||
from lutris.util.wine.cabinstall import CabInstaller
|
||||
|
||||
|
||||
class NineUnavailable(RuntimeError):
|
||||
"""Exception raised when Gallium Nine is not available"""
|
||||
|
||||
|
||||
class NineManager:
|
||||
"""Utility class to install and manage Gallium Nine to a Wine prefix"""
|
||||
|
||||
|
@ -27,8 +29,12 @@ class NineManager:
|
|||
of system library directory
|
||||
"""
|
||||
for mesa_file in NineManager.mesa_files:
|
||||
if not any([os.path.exists(os.path.join(lib, "d3d", mesa_file))
|
||||
for lib in system.LINUX_SYSTEM.iter_lib_folders()]):
|
||||
if not any(
|
||||
[
|
||||
os.path.exists(os.path.join(lib, "d3d", mesa_file))
|
||||
for lib in system.LINUX_SYSTEM.iter_lib_folders()
|
||||
]
|
||||
):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
@ -40,8 +46,12 @@ class NineManager:
|
|||
check 'wine/fakedlls' subdirectory of system library directory for Nine binaries
|
||||
"""
|
||||
for nine_file in NineManager.nine_files:
|
||||
if not any([os.path.exists(os.path.join(lib, "wine/fakedlls", nine_file))
|
||||
for lib in system.LINUX_SYSTEM.iter_lib_folders()]):
|
||||
if not any(
|
||||
[
|
||||
os.path.exists(os.path.join(lib, "wine/fakedlls", nine_file))
|
||||
for lib in system.LINUX_SYSTEM.iter_lib_folders()
|
||||
]
|
||||
):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
@ -65,13 +75,17 @@ class NineManager:
|
|||
return None
|
||||
|
||||
def is_prefix_prepared(self):
|
||||
if not all(system.path_exists(os.path.join(self.get_system_path("x32"), nine_file))
|
||||
for nine_file in self.nine_files):
|
||||
if not all(
|
||||
system.path_exists(os.path.join(self.get_system_path("x32"), nine_file))
|
||||
for nine_file in self.nine_files
|
||||
):
|
||||
return False
|
||||
|
||||
if self.wine_arch == "win64":
|
||||
if not all(system.path_exists(os.path.join(self.get_system_path("x64"), nine_file))
|
||||
for nine_file in self.nine_files):
|
||||
if not all(
|
||||
system.path_exists(os.path.join(self.get_system_path("x64"), nine_file))
|
||||
for nine_file in self.nine_files
|
||||
):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
@ -81,20 +95,26 @@ class NineManager:
|
|||
for lib in system.LINUX_SYSTEM.iter_lib_folders():
|
||||
nine_file_path = os.path.join(lib, "wine/fakedlls", nine_file)
|
||||
|
||||
if (os.path.exists(nine_file_path) and
|
||||
CabInstaller.get_arch_from_dll(nine_file_path) == "win32"):
|
||||
if (
|
||||
os.path.exists(nine_file_path)
|
||||
and CabInstaller.get_arch_from_dll(nine_file_path) == "win32"
|
||||
):
|
||||
shutil.copy(nine_file_path, self.get_system_path("x32"))
|
||||
|
||||
if self.wine_arch == "win64":
|
||||
if (os.path.exists(nine_file_path) and
|
||||
CabInstaller.get_arch_from_dll(nine_file_path) == "win64"):
|
||||
if (
|
||||
os.path.exists(nine_file_path)
|
||||
and CabInstaller.get_arch_from_dll(nine_file_path) == "win64"
|
||||
):
|
||||
shutil.copy(nine_file_64, self.get_system_path("x64"))
|
||||
|
||||
if not os.path.exists(os.path.join(self.get_system_path("x32"), nine_file)):
|
||||
raise NineUnavailable("could not install " + nine_file + " (x32)")
|
||||
|
||||
if self.wine_arch == "win64":
|
||||
if not os.path.exists(os.path.join(self.get_system_path("x64"), nine_file)):
|
||||
if not os.path.exists(
|
||||
os.path.join(self.get_system_path("x64"), nine_file)
|
||||
):
|
||||
raise NineUnavailable("could not install " + nine_file + " (x64)")
|
||||
|
||||
def enable(self):
|
||||
|
@ -106,17 +126,11 @@ class NineManager:
|
|||
self.prepare_prefix()
|
||||
|
||||
wineexec(
|
||||
"ninewinecfg",
|
||||
args="-e",
|
||||
prefix=self.prefix,
|
||||
blocking=True,
|
||||
"ninewinecfg", args="-e", prefix=self.prefix, blocking=True,
|
||||
)
|
||||
|
||||
def disable(self):
|
||||
if self.is_prefix_prepared():
|
||||
wineexec(
|
||||
"ninewinecfg",
|
||||
args="-d",
|
||||
prefix=self.prefix,
|
||||
blocking=True,
|
||||
"ninewinecfg", args="-d", prefix=self.prefix, blocking=True,
|
||||
)
|
||||
|
|
|
@ -27,7 +27,9 @@ class WinePrefixManager:
|
|||
try:
|
||||
self.desktop_integration()
|
||||
except OSError as ex:
|
||||
logger.error("Failed to setup desktop integration, the prefix may not be valid.")
|
||||
logger.error(
|
||||
"Failed to setup desktop integration, the prefix may not be valid."
|
||||
)
|
||||
logger.exception(ex)
|
||||
|
||||
def get_registry_path(self, key):
|
||||
|
@ -41,7 +43,7 @@ class WinePrefixManager:
|
|||
|
||||
def get_key_path(self, key):
|
||||
if key.startswith(self.hkcu_prefix):
|
||||
return key[len(self.hkcu_prefix) + 1:]
|
||||
return key[len(self.hkcu_prefix) + 1 :]
|
||||
raise ValueError(
|
||||
"The key {} is currently not supported by WinePrefixManager".format(key)
|
||||
)
|
||||
|
@ -82,8 +84,12 @@ class WinePrefixManager:
|
|||
user_dir = os.path.join(self.path, "drive_c/users/", user)
|
||||
|
||||
for key in DESKTOP_KEYS:
|
||||
folder = self.get_registry_key(self.hkcu_prefix+"/Software/Microsoft/Windows/CurrentVersion/Explorer/Shell Folders",key)
|
||||
DESKTOP_FOLDERS.append(folder[folder.rfind("\\")+1:])
|
||||
folder = self.get_registry_key(
|
||||
self.hkcu_prefix
|
||||
+ "/Software/Microsoft/Windows/CurrentVersion/Explorer/Shell Folders",
|
||||
key,
|
||||
)
|
||||
DESKTOP_FOLDERS.append(folder[folder.rfind("\\") + 1 :])
|
||||
|
||||
if not desktop_dir:
|
||||
desktop_dir = user_dir
|
||||
|
@ -92,7 +98,7 @@ class WinePrefixManager:
|
|||
|
||||
if system.path_exists(user_dir):
|
||||
# Replace or restore desktop integration symlinks
|
||||
for i,item in enumerate(DESKTOP_FOLDERS):
|
||||
for i, item in enumerate(DESKTOP_FOLDERS):
|
||||
path = os.path.join(user_dir, item)
|
||||
old_path = path + ".winecfg"
|
||||
|
||||
|
@ -107,7 +113,7 @@ class WinePrefixManager:
|
|||
os.rename(path, old_path)
|
||||
|
||||
if restore and not os.path.isdir(path):
|
||||
os.symlink(xdgshortcuts.get_xdg_entry(DESKTOP_XDG[i]),path)
|
||||
os.symlink(xdgshortcuts.get_xdg_entry(DESKTOP_XDG[i]), path)
|
||||
# We don't need all the others process of the loop
|
||||
continue
|
||||
|
||||
|
@ -146,12 +152,14 @@ class WinePrefixManager:
|
|||
if enabled:
|
||||
self.set_registry_key(path, "Desktop", "WineDesktop")
|
||||
default_resolution = "x".join(DISPLAY_MANAGER.get_current_resolution())
|
||||
logger.debug("Enabling wine virtual desktop with default resolution of %s",
|
||||
default_resolution)
|
||||
logger.debug(
|
||||
"Enabling wine virtual desktop with default resolution of %s",
|
||||
default_resolution,
|
||||
)
|
||||
self.set_registry_key(
|
||||
self.hkcu_prefix + "/Software/Wine/Explorer/Desktops",
|
||||
"WineDesktop",
|
||||
default_resolution
|
||||
default_resolution,
|
||||
)
|
||||
else:
|
||||
self.clear_registry_key(path)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
"""Manipulate Wine registry files"""
|
||||
import os
|
||||
import re
|
||||
from collections import OrderedDict
|
||||
|
@ -100,7 +101,7 @@ class WineRegistry:
|
|||
except Exception: # pylint: disable=broad-except
|
||||
logger.exception(
|
||||
"Failed to registry read %s, please send attach this file in a bug report",
|
||||
reg_filename
|
||||
reg_filename,
|
||||
)
|
||||
registry_content = []
|
||||
return registry_content
|
||||
|
@ -121,7 +122,7 @@ class WineRegistry:
|
|||
additional_values.append(line)
|
||||
elif not add_next_to_value:
|
||||
if additional_values:
|
||||
additional_values = '\n'.join(additional_values)
|
||||
additional_values = "\n".join(additional_values)
|
||||
current_key.add_to_last(additional_values)
|
||||
additional_values = []
|
||||
current_key.parse(line)
|
||||
|
@ -150,9 +151,10 @@ class WineRegistry:
|
|||
raise OSError("No filename provided")
|
||||
prefix_path = os.path.dirname(path)
|
||||
if not os.path.isdir(prefix_path):
|
||||
raise OSError("Invalid Wine prefix path %s, make sure to "
|
||||
"create the prefix before saving to a registry"
|
||||
% prefix_path)
|
||||
raise OSError(
|
||||
"Invalid Wine prefix path %s, make sure to "
|
||||
"create the prefix before saving to a registry" % prefix_path
|
||||
)
|
||||
with open(path, "w") as registry_file:
|
||||
registry_file.write(self.render())
|
||||
|
||||
|
@ -290,16 +292,21 @@ class WineRegistryKey:
|
|||
return '"{}"'.format(value)
|
||||
raise NotImplementedError("TODO")
|
||||
|
||||
def decode_unicode(self,string):
|
||||
chunks = string.split('\\x')
|
||||
out = chunks.pop(0).encode().decode('unicode_escape')
|
||||
def decode_unicode(self, string):
|
||||
chunks = string.split("\\x")
|
||||
out = chunks.pop(0).encode().decode("unicode_escape")
|
||||
for chunk in chunks:
|
||||
#We have seen file with unicode characters escaped on 1 byte (\xfa), 1.5 bytes (\x444) and 2 bytes (\x00ed)
|
||||
#So we try 0 padding, 1 and 2 (python wants its escaped sequence to be exactly on 4 characters).
|
||||
#The exception let us know if it worked or not
|
||||
for i in [0,1,2]:
|
||||
# We have seen file with unicode characters escaped on 1 byte (\xfa),
|
||||
# 1.5 bytes (\x444) and 2 bytes (\x00ed). So we try 0 padding, 1 and 2
|
||||
# (python wants its escaped sequence to be exactly on 4 characters).
|
||||
# The exception let us know if it worked or not
|
||||
for i in [0, 1, 2]:
|
||||
try:
|
||||
out += '\\u{}{}'.format('0'*i,chunk).encode().decode('unicode_escape')
|
||||
out += (
|
||||
"\\u{}{}".format("0" * i, chunk)
|
||||
.encode()
|
||||
.decode("unicode_escape")
|
||||
)
|
||||
break
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
|
|
|
@ -10,16 +10,19 @@ from gi.repository import GLib
|
|||
from lutris.util import system
|
||||
from lutris.settings import CACHE_DIR
|
||||
|
||||
|
||||
def get_xdg_entry(directory):
|
||||
"""Return the path for specific user folders"""
|
||||
special_dir = { "DESKTOP": GLib.UserDirectory.DIRECTORY_DESKTOP,
|
||||
"MUSIC": GLib.UserDirectory.DIRECTORY_MUSIC,
|
||||
"PICTURES": GLib.UserDirectory.DIRECTORY_PICTURES,
|
||||
"VIDEOS": GLib.UserDirectory.DIRECTORY_VIDEOS,
|
||||
"DOCUMENTS":GLib.UserDirectory.DIRECTORY_DOCUMENTS }
|
||||
special_dir = {
|
||||
"DESKTOP": GLib.UserDirectory.DIRECTORY_DESKTOP,
|
||||
"MUSIC": GLib.UserDirectory.DIRECTORY_MUSIC,
|
||||
"PICTURES": GLib.UserDirectory.DIRECTORY_PICTURES,
|
||||
"VIDEOS": GLib.UserDirectory.DIRECTORY_VIDEOS,
|
||||
"DOCUMENTS": GLib.UserDirectory.DIRECTORY_DOCUMENTS,
|
||||
}
|
||||
directory = directory.upper()
|
||||
if directory not in special_dir.keys():
|
||||
raise ValueError("Only those folders are supported "+special_dir.keys())
|
||||
raise ValueError("Only those folders are supported " + special_dir.keys())
|
||||
return GLib.get_user_special_dir(special_dir[directory])
|
||||
|
||||
|
||||
|
@ -29,9 +32,9 @@ def get_xdg_basename(game_slug, game_id, base_dir=None):
|
|||
# When base dir is provided, lookup possible combinations
|
||||
# and return the first match
|
||||
for path in [
|
||||
"{}.desktop".format(game_slug),
|
||||
"{}-{}.desktop".format(game_slug, game_id),
|
||||
"net.lutris.{}-{}.desktop".format(game_slug, game_id),
|
||||
"{}.desktop".format(game_slug),
|
||||
"{}-{}.desktop".format(game_slug, game_id),
|
||||
"net.lutris.{}-{}.desktop".format(game_slug, game_id),
|
||||
]:
|
||||
if system.path_exists(os.path.join(base_dir, path)):
|
||||
return path
|
||||
|
@ -99,6 +102,7 @@ def get_menu_launcher_path(game_slug, game_id):
|
|||
menu_dir, get_xdg_basename(game_slug, game_id, base_dir=menu_dir)
|
||||
)
|
||||
|
||||
|
||||
def desktop_launcher_exists(game_slug, game_id):
|
||||
return system.path_exists(get_launcher_path(game_slug, game_id))
|
||||
|
||||
|
|
Loading…
Reference in a new issue