diff --git a/pupgui2/pupgui2ctinfodialog.py b/pupgui2/pupgui2ctinfodialog.py index 9c631c18..aa430e61 100644 --- a/pupgui2/pupgui2ctinfodialog.py +++ b/pupgui2/pupgui2ctinfodialog.py @@ -6,7 +6,7 @@ from pupgui2.lutrisutil import get_lutris_game_list, is_lutris_game_using_wine from pupgui2.pupgui2ctbatchupdatedialog import PupguiCtBatchUpdateDialog from pupgui2.steamutil import get_steam_game_list -from pupgui2.util import open_webbrowser_thread, get_random_game_name +from pupgui2.util import open_webbrowser_thread, get_random_game_name, is_mark_global_available, set_launcher_global_tool from pupgui2.heroicutil import get_heroic_game_list, is_heroic_launcher from PySide6.QtCore import QObject, Signal, QDataStream, QByteArray @@ -29,6 +29,7 @@ def __init__(self, parent=None, ctool: BasicCompatTool = None, install_loc=None) self.games: List[Union[SteamApp, LutrisGame, HeroicGame]] = [] self.install_loc = install_loc self.is_batch_update_available = False + self.is_mark_global_available = False self.load_ui() self.setup_ui() @@ -41,13 +42,14 @@ def load_ui(self): self.ui = loader.load(ui_file.device()) def setup_ui(self): + self.update_game_list() + self.ui.txtToolName.setText(self.ctool.displayname) self.ui.txtLauncherName.setText(self.install_loc.get('display_name')) self.ui.txtInstallDirectory.setText(self.ctool.get_install_dir()) self.ui.btnBatchUpdate.setVisible(False) self.ui.searchBox.setVisible(False) - - self.update_game_list() + self.ui.btnMarkGlobal.setVisible(self.is_mark_global_available) # Gets updated in update_game_list self.ui.btnSearch.clicked.connect(self.btn_search_clicked) self.ui.btnRefreshGames.clicked.connect(self.btn_refresh_games_clicked) @@ -118,6 +120,8 @@ def setup_game_list(self, row_count: int, header_labels: List[str]): self.ui.txtNumGamesUsingTool.setText(str(row_count)) def update_game_list_ui(self): + self.is_mark_global_available = is_mark_global_available(self.install_loc, self.ctool) + # switch between showing the QTableWidget (listGames) or the QLabel (lblGamesList) self.ui.stackTableOrText.setCurrentIndex(0 if len(self.games) > 0 and not self.ctool.is_global else 1) self.ui.btnBatchUpdate.setEnabled(len(self.games) > 0 and not self.ctool.is_global) @@ -126,6 +130,10 @@ def update_game_list_ui(self): if self.ctool.is_global: self.ui.lblGamesList.setText(self.tr('Tool is Global')) + self.ui.btnMarkGlobal.setVisible(self.is_mark_global_available) + if self.is_mark_global_available: + self.ui.btnMarkGlobal.clicked.connect(self.btn_mark_global_clicked) + if len(self.games) < 0 or self.ctool.is_global: self.ui.btnClose.setFocus() @@ -161,3 +169,7 @@ def search_ctinfo_games(self, text): for row in range(self.ui.listGames.rowCount()): should_hide: bool = not text.lower() in self.ui.listGames.item(row, 1).text().lower() self.ui.listGames.setRowHidden(row, should_hide) + + def btn_mark_global_clicked(self): + self.is_mark_global_available = not set_launcher_global_tool(self.install_loc, self.ctool) + self.btn_refresh_games_clicked() diff --git a/pupgui2/resources/ui/pupgui2_ctinfodialog.ui b/pupgui2/resources/ui/pupgui2_ctinfodialog.ui index 4f731e8d..50b85839 100644 --- a/pupgui2/resources/ui/pupgui2_ctinfodialog.ui +++ b/pupgui2/resources/ui/pupgui2_ctinfodialog.ui @@ -14,8 +14,7 @@ About compatibility tool - - .. + @@ -33,7 +32,7 @@ - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -50,7 +49,7 @@ - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -67,7 +66,7 @@ - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + Qt::TextInteractionFlag::LinksAccessibleByMouse|Qt::TextInteractionFlag::TextSelectableByMouse @@ -76,7 +75,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -99,7 +98,7 @@ - Qt::Horizontal + Qt::Orientation::Horizontal @@ -118,8 +117,7 @@ - - .. + @@ -132,8 +130,7 @@ - - .. + @@ -170,13 +167,13 @@ - Qt::ClickFocus + Qt::FocusPolicy::ClickFocus - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers - QAbstractItemView::SelectRows + QAbstractItemView::SelectionBehavior::SelectRows true @@ -248,7 +245,7 @@ No games - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -275,10 +272,17 @@ + + + + Set as Global + + + - Qt::Horizontal + Qt::Orientation::Horizontal @@ -291,7 +295,7 @@ - Qt::StrongFocus + Qt::FocusPolicy::StrongFocus Close @@ -304,10 +308,12 @@ btnClose + btnMarkGlobal + searchBox btnBatchUpdate btnSearch - searchBox btnRefreshGames + lblGamesUsingTool diff --git a/pupgui2/steamutil.py b/pupgui2/steamutil.py index 8914f561..8758c20d 100644 --- a/pupgui2/steamutil.py +++ b/pupgui2/steamutil.py @@ -636,6 +636,8 @@ def install_steam_library_shortcut(steam_config_folder: str, remove_shortcut=Fal except Exception as e: print(f'Error: Could not add {APP_NAME} as Steam shortcut:', e) + return 1 + return 0 @@ -794,6 +796,35 @@ def determine_most_recent_steam_user(steam_users: List[SteamUser]) -> SteamUser: return None +def set_steam_global_compat_tool(steam_config_folder: str, ctool: BasicCompatTool): + """ Update the global compatibility tool to the ctool parameter defined in config.vdf CompatToolMapping (AppID '0') """ + + if ctool.ct_type != CTType.CUSTOM: + return False + + config_vdf_file = os.path.join(os.path.expanduser(steam_config_folder), 'config.vdf') + if not os.path.exists(config_vdf_file): + return False + + try: + d = vdf.load(open(config_vdf_file)) + c = get_steam_vdf_compat_tool_mapping(d) + + # Create or update the '0' CompatToolMapping entry + if not c.get('0', {}): + c['0'] = { 'name': ctool.get_internal_name(), 'config': '', 'priority': '75' } + else: + c['0']['name'] = ctool.get_internal_name() + + vdf.dump(d, open(config_vdf_file, 'w'), pretty=True) + except Exception as e: + print(f'Error, could not update Global Steam compatibility tool to {ctool.displayname}: {e}, vdf: {config_vdf_file}') + return False + + return True + + + def is_valid_steam_install(steam_path) -> bool: """ diff --git a/pupgui2/util.py b/pupgui2/util.py index e91991fa..3f11b280 100644 --- a/pupgui2/util.py +++ b/pupgui2/util.py @@ -23,7 +23,7 @@ from pupgui2.constants import AWACY_GAME_LIST_URL, LOCAL_AWACY_GAME_LIST from pupgui2.constants import GITHUB_API, GITLAB_API, GITLAB_API_RATELIMIT_TEXT from pupgui2.datastructures import BasicCompatTool, CTType, Launcher, SteamApp, LutrisGame, HeroicGame -from pupgui2.steamutil import remove_steamtinkerlaunch, is_valid_steam_install +from pupgui2.steamutil import remove_steamtinkerlaunch, is_valid_steam_install, set_steam_global_compat_tool def create_msgbox( @@ -892,3 +892,62 @@ def get_random_game_name(games: List[Union[SteamApp, LutrisGame, HeroicGame]]) - tooltip_game_name = random_game.title return tooltip_game_name + + +def is_mark_global_available(install_loc, ctool: BasicCompatTool) -> bool: + + """ + Check if marking a tool is "global" is supported by the current launcher, + and if the given ctool can be marked as global for this launcher. + + For example, runtimes are not valid to be marked as Global. + + Return Type: bool + """ + + allowed_launchers = [ 'steam', 'lutris' ] # Only allow marking global for these launchers + + # Only allow marking global for compatibility tools and not runtimes etc + if ctool.ct_type != CTType.CUSTOM: + return False + + # Don't allow marking global compat tools as global + if ctool.is_global: + return False + + # Exit early if launcher is not on our list of compatible/allowed launchers + if install_loc.get('launcher') not in allowed_launchers: + return False + + # Only allow marking global for Steam if we have the VDF directory path + if install_loc.get('launcher') == 'steam' and 'vdf_dir' not in install_loc: + return False + + # Could put other conditions for other launchers in an elif here, i.e. check for Lutris and ensure a specific path exists + # Nothing here yet... + + return True # All other checks passed so default to true + + +def set_launcher_global_tool(install_loc, compat_tool: BasicCompatTool) -> bool: + + """ + Set a given compat_tool as global for a given launcher by calling the + relevant util function for that launcher. + """ + + launcher = install_loc.get('launcher', '').lower() + + # Skip empty launcher + if not launcher: + return False + + if not is_mark_global_available(install_loc, compat_tool): + return False + + if launcher == 'steam': + steam_config_folder = install_loc.get('vdf_dir', '') + + return set_steam_global_compat_tool(steam_config_folder, compat_tool) + + return False