Run black on modules with Flake8 warnings

This commit is contained in:
Mathieu Comandon 2019-11-02 12:31:15 -07:00
parent ca415467f9
commit c1412140bf
16 changed files with 359 additions and 245 deletions

View file

@ -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

View file

@ -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):

View file

@ -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"
)

View file

@ -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:

View file

@ -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()

View file

@ -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()

View file

@ -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:

View file

@ -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()

View file

@ -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>",
)

View file

@ -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:

View file

@ -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

View file

@ -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",)

View file

@ -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,
)

View file

@ -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)

View file

@ -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

View file

@ -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))