class RunningGame: """Class for manipulating running games""" def __init__(self, game_id, application=None, window=None): self.application = application self.window = window self.game_id = game_id self.running_game_box = None self.game = Game(game_id) self.game.connect("game-error", self.window.on_game_error) self.game.connect("game-stop", self.on_stop) def __str__(self): return "Running %s" % self.game.name def play(self): if self.game.is_installed: self.game.play() else: logger.warning("%s is not available", self.game.slug) InstallerWindow( game_slug=self.game.slug, parent=self.window, application=self.application ) if self.game.state == Game.STATE_STOPPED: return self.running_game_box = RunningGameBox(self.game) self.running_game_box.stop_button.connect("clicked", self.on_stop) self.running_game_box.log_button.connect("clicked", self.on_show_logs) self.window.add_running_game(self.running_game_box) def on_stop(self, caller): """Stops the game""" if not isinstance(caller, Game): # If the signal is coming from a game, it has already stopped. self.game.stop() self.running_game_box.destroy() try: logger.debug("Removing %s from running games", self) self.application.running_games.pop(self.application.running_games.index(self)) except ValueError: logger.warning("%s not in running game list", self) self.window.remove_running_game() def on_show_logs(self, _widget): """Display game log in a LogDialog""" log_title = u"Log for {}".format(self.game) log_window = LogDialog( title=log_title, buffer=self.game.log_buffer, parent=self.window ) log_window.run() log_window.destroy()
class GameActions: """Regroup a list of callbacks for a game""" def __init__(self, application=None, window=None): self.application = application or Gio.Application.get_default() self.window = window self.game_id = None self._game = None @property def game(self): if not self._game: self._game = self.application.get_game_by_id(self.game_id) if not self._game: self._game = Game(self.game_id) self._game.connect("game-error", self.window.on_game_error) return self._game @property def is_game_running(self): return bool(self.application.get_game_by_id(self.game_id)) def set_game(self, game=None, game_id=None): if game: self._game = game self.game_id = game.id else: self._game = None self.game_id = game_id def get_game_actions(self): """Return a list of game actions and their callbacks""" return [ ("play", _("Play"), self.on_game_launch), ("stop", _("Stop"), self.on_game_stop), ("install", _("Install"), self.on_install_clicked), ("update", _("Install updates"), self.on_update_clicked), ("install_dlcs", "Install DLCs", self.on_install_dlc_clicked), ("show_logs", _("Show logs"), self.on_show_logs), ("add", _("Add installed game"), self.on_add_manually), ("configure", _("Configure"), self.on_edit_game_configuration), ("favorite", _("Add to favorites"), self.on_add_favorite_game), ("deletefavorite", _("Remove from favorites"), self.on_delete_favorite_game), ("execute-script", _("Execute script"), self.on_execute_script_clicked), ("browse", _("Browse files"), self.on_browse_files), ( "desktop-shortcut", _("Create desktop shortcut"), self.on_create_desktop_shortcut, ), ( "rm-desktop-shortcut", _("Delete desktop shortcut"), self.on_remove_desktop_shortcut, ), ( "menu-shortcut", _("Create application menu shortcut"), self.on_create_menu_shortcut, ), ( "rm-menu-shortcut", _("Delete application menu shortcut"), self.on_remove_menu_shortcut, ), ("install_more", _("Install another version"), self.on_install_clicked), ("remove", _("Remove"), self.on_remove_game), ("view", _("View on Lutris.net"), self.on_view_game), ("hide", _("Hide game from library"), self.on_hide_game), ("unhide", _("Unhide game from library"), self.on_unhide_game), ] def get_displayed_entries(self): """Return a dictionary of actions that should be shown for a game""" return { "add": not self.game.is_installed, "install": not self.game.is_installed, "play": self.game.is_installed and not self.is_game_running, "update": self.game.is_updatable, "install_dlcs": self.game.is_updatable, "stop": self.is_game_running, "configure": bool(self.game.is_installed), "browse": self.game.is_installed and self.game.runner_name != "browser", "show_logs": self.game.is_installed, "favorite": not self.game.is_favorite, "deletefavorite": self.game.is_favorite, "install_more": not self.game.service and self.game.is_installed, "execute-script": bool( self.game.is_installed and self.game.runner and self.game.runner.system_config.get("manual_command") ), "desktop-shortcut": ( self.game.is_installed and not xdgshortcuts.desktop_launcher_exists(self.game.slug, self.game.id) ), "menu-shortcut": ( self.game.is_installed and not xdgshortcuts.menu_launcher_exists(self.game.slug, self.game.id) ), "rm-desktop-shortcut": bool( self.game.is_installed and xdgshortcuts.desktop_launcher_exists(self.game.slug, self.game.id) ), "rm-menu-shortcut": bool( self.game.is_installed and xdgshortcuts.menu_launcher_exists(self.game.slug, self.game.id) ), "remove": True, "view": True, "hide": self.game.is_installed and not self.game.is_hidden, "unhide": self.game.is_hidden, } def on_game_launch(self, *_args): """Launch a game""" self.game.launch() def get_running_game(self): ids = self.application.get_running_game_ids() for game_id in ids: if str(game_id) == str(self.game.id): return self.game logger.warning("Game %s not in %s", self.game_id, ids) def on_game_stop(self, _caller): """Stops the game""" game = self.get_running_game() if game: game.force_stop() def on_show_logs(self, _widget): """Display game log""" _buffer = self.game.log_buffer if not _buffer: logger.info("No log for game %s", self.game) return LogWindow( title=_("Log for {}").format(self.game), buffer=_buffer, application=self.application ) def on_install_clicked(self, *_args): """Install a game""" # Install the currently selected game in the UI if not self.game.slug: raise RuntimeError("No game to install: %s" % self.game.id) self.game.emit("game-install") def on_update_clicked(self, _widget): self.game.emit("game-install-update") def on_install_dlc_clicked(self, _widget): self.game.emit("game-install-dlc") def on_locate_installed_game(self, _button, game): """Show the user a dialog to import an existing install to a DRM free service Params: game (Game): Game instance without a database ID, populated with a fields the service can provides """ AddGameDialog(self.window, game=game) def on_add_manually(self, _widget, *_args): """Callback that presents the Add game dialog""" return AddGameDialog(self.window, game=self.game, runner=self.game.runner_name) def on_edit_game_configuration(self, _widget): """Edit game preferences""" self.application.show_window(EditGameConfigDialog, game=self.game, parent=self.window) def on_add_favorite_game(self, _widget): """Add to favorite Games list""" self.game.add_to_favorites() def on_delete_favorite_game(self, _widget): """delete from favorites""" self.game.remove_from_favorites() def on_hide_game(self, _widget): """Add a game to the list of hidden games""" self.game.set_hidden(True) def on_unhide_game(self, _widget): """Removes a game from the list of hidden games""" self.game.set_hidden(False) def on_execute_script_clicked(self, _widget): """Execute the game's associated script""" manual_command = self.game.runner.system_config.get("manual_command") if path_exists(manual_command): MonitoredCommand( [manual_command], include_processes=[os.path.basename(manual_command)], cwd=self.game.directory, ).start() logger.info("Running %s in the background", manual_command) def on_browse_files(self, _widget): """Callback to open a game folder in the file browser""" path = self.game.get_browse_dir() if not path: dialogs.NoticeDialog(_("This game has no installation directory")) elif path_exists(path): open_uri("file://%s" % path) else: dialogs.NoticeDialog(_("Can't open %s \nThe folder doesn't exist.") % path) def on_create_menu_shortcut(self, *_args): """Add the selected game to the system's Games menu.""" xdgshortcuts.create_launcher(self.game.slug, self.game.id, self.game.name, menu=True) def on_create_desktop_shortcut(self, *_args): """Create a desktop launcher for the selected game.""" xdgshortcuts.create_launcher(self.game.slug, self.game.id, self.game.name, desktop=True) def on_remove_menu_shortcut(self, *_args): """Remove an XDG menu shortcut""" xdgshortcuts.remove_launcher(self.game.slug, self.game.id, menu=True) def on_remove_desktop_shortcut(self, *_args): """Remove a .desktop shortcut""" xdgshortcuts.remove_launcher(self.game.slug, self.game.id, desktop=True) def on_view_game(self, _widget): """Callback to open a game on lutris.net""" open_uri("https://lutris.net/games/%s" % self.game.slug) def on_remove_game(self, *_args): """Callback that present the uninstall dialog to the user""" if self.game.is_installed: UninstallGameDialog(game_id=self.game.id, parent=self.window) else: RemoveGameDialog(game_id=self.game.id, parent=self.window)
class GameActions: """Regroup a list of callbacks for a game""" def __init__(self, application=None, window=None): self.application = application or Gio.Application.get_default() self.window = window self.game_id = None self._game = None @property def game(self): if not self._game: self._game = self.application.get_game_by_id(self.game_id) if not self._game: self._game = Game(self.game_id) self._game.connect("game-error", self.window.on_game_error) return self._game @property def is_game_running(self): return bool(self.application.get_game_by_id(self.game_id)) def set_game(self, game=None, game_id=None): if game: self._game = game self.game_id = game.id else: self._game = None self.game_id = game_id def get_game_actions(self): """Return a list of game actions and their callbacks""" return [ ("play", "Play", self.on_game_run), ("stop", "Stop", self.on_stop), ("show_logs", "Show logs", self.on_show_logs), ("install", "Install", self.on_install_clicked), ("add", "Add installed game", self.on_add_manually), ("configure", "Configure", self.on_edit_game_configuration), ("execute-script", "Execute script", self.on_execute_script_clicked), ("browse", "Browse files", self.on_browse_files), ( "desktop-shortcut", "Create desktop shortcut", self.on_create_desktop_shortcut, ), ( "rm-desktop-shortcut", "Delete desktop shortcut", self.on_remove_desktop_shortcut, ), ( "menu-shortcut", "Create application menu shortcut", self.on_create_menu_shortcut, ), ( "rm-menu-shortcut", "Delete application menu shortcut", self.on_remove_menu_shortcut, ), ("install_more", "Install another version", self.on_install_clicked), ("remove", "Remove", self.on_remove_game), ("view", "View on Lutris.net", self.on_view_game), ("hide", "Hide game from library", self.on_hide_game), ("unhide", "Unhide game from library", self.on_unhide_game), ] def on_hide_game(self, _widget): """Add a game to the list of hidden games""" game = Game(self.window.view.selected_game.id) # Append the new hidden ID and save it ignores = pga.get_hidden_ids() + [game.id] pga.set_hidden_ids(ignores) # Update the GUI if not self.window.show_hidden_games: self.window.game_store.remove_game(game.id) def on_unhide_game(self, _widget): """Removes a game from the list of hidden games""" game = Game(self.window.view.selected_game.id) # Remove the ID to unhide and save it ignores = pga.get_hidden_ids() ignores.remove(game.id) pga.set_hidden_ids(ignores) @staticmethod def is_game_hidden(game): """Returns whether a game is on the list of hidden games""" return game.id in pga.get_hidden_ids() def get_displayed_entries(self): """Return a dictionary of actions that should be shown for a game""" return { "add": not self.game.is_installed and not self.game.is_search_result, "install": not self.game.is_installed, "play": self.game.is_installed and not self.is_game_running, "stop": self.is_game_running, "show_logs": self.game.is_installed, "configure": bool(self.game.is_installed), "install_more": self.game.is_installed and not self.game.is_search_result, "execute-script": bool(self.game.is_installed and self.game.runner.system_config.get("manual_command")), "desktop-shortcut": (self.game.is_installed and not xdgshortcuts.desktop_launcher_exists( self.game.slug, self.game.id)), "menu-shortcut": (self.game.is_installed and not xdgshortcuts.menu_launcher_exists( self.game.slug, self.game.id)), "rm-desktop-shortcut": bool(self.game.is_installed and xdgshortcuts.desktop_launcher_exists( self.game.slug, self.game.id)), "rm-menu-shortcut": bool(self.game.is_installed and xdgshortcuts.menu_launcher_exists( self.game.slug, self.game.id)), "browse": self.game.is_installed and self.game.runner_name != "browser", "remove": not self.game.is_search_result, "view": True, "hide": not GameActions.is_game_hidden(self.game), "unhide": GameActions.is_game_hidden(self.game) } def on_game_run(self, *_args): """Launch a game""" self.application.launch(self.game) def get_running_game(self): for i in range(self.application.running_games.get_n_items()): game = self.application.running_games.get_item(i) if game == self.game: return game def on_stop(self, caller): """Stops the game""" matched_game = self.get_running_game() if not matched_game: logger.warning("Game %s not in running game list", self.game_id) return if not matched_game.game_thread: logger.warning( "Game %s doesn't appear to be running, not killing it", self.game_id) return try: os.kill(matched_game.game_thread.game_process.pid, signal.SIGTERM) except ProcessLookupError: pass logger.debug("Removed game with ID %s from running games", self.game_id) def on_show_logs(self, _widget): """Display game log""" return LogWindow(title="Log for {}".format(self.game), buffer=self.game.log_buffer, application=self.application) def on_install_clicked(self, *_args): """Install a game""" # Install the currently selected game in the UI return InstallerWindow( parent=self.window, game_slug=self.game.slug, application=self.application, ) def on_add_manually(self, _widget, *_args): """Callback that presents the Add game dialog""" AddGameDialog(self.window, game=self.game, runner=self.game.runner_name) def on_edit_game_configuration(self, _widget): """Edit game preferences""" EditGameConfigDialog(self.window, self.game) def on_execute_script_clicked(self, _widget): """Execute the game's associated script""" manual_command = self.game.runner.system_config.get("manual_command") if path_exists(manual_command): MonitoredCommand( [manual_command], include_processes=[os.path.basename(manual_command)], cwd=self.game.directory, ).start() logger.info("Running %s in the background", manual_command) def on_browse_files(self, _widget): """Callback to open a game folder in the file browser""" path = self.game.get_browse_dir() if not path: dialogs.NoticeDialog("This game has no installation directory") elif path_exists(path): open_uri("file://%s" % path) else: dialogs.NoticeDialog("Can't open %s \nThe folder doesn't exist." % path) def on_create_menu_shortcut(self, *_args): """Add the selected game to the system's Games menu.""" xdgshortcuts.create_launcher(self.game.slug, self.game.id, self.game.name, menu=True) def on_create_desktop_shortcut(self, *_args): """Create a desktop launcher for the selected game.""" xdgshortcuts.create_launcher(self.game.slug, self.game.id, self.game.name, desktop=True) def on_remove_menu_shortcut(self, *_args): """Remove an XDG menu shortcut""" xdgshortcuts.remove_launcher(self.game.slug, self.game.id, menu=True) def on_remove_desktop_shortcut(self, *_args): """Remove a .desktop shortcut""" xdgshortcuts.remove_launcher(self.game.slug, self.game.id, desktop=True) def on_view_game(self, _widget): """Callback to open a game on lutris.net""" open_uri("https://lutris.net/games/%s" % self.game.slug) def on_remove_game(self, *_args): """Callback that present the uninstall dialog to the user""" UninstallGameDialog(game_id=self.game.id, callback=self.window.remove_game_from_view, parent=self.window)
class GameActions: """Regroup a list of callbacks for a game""" def __init__(self, application=None, window=None): self.application = application or Gio.Application.get_default() self.window = window self.game_id = None self._game = None @property def game(self): if not self._game: self._game = self.application.get_game_by_id(self.game_id) if not self._game: self._game = Game(self.game_id) self._game.connect("game-error", self.window.on_game_error) return self._game @property def is_game_running(self): return bool(self.application.get_game_by_id(self.game_id)) def set_game(self, game=None, game_id=None): if game: self._game = game self.game_id = game.id else: self._game = None self.game_id = game_id def get_game_actions(self): """Return a list of game actions and their callbacks""" return [ ( "play", "Play", self.on_game_run ), ( "stop", "Stop", self.on_stop ), ( "show_logs", "Show logs", self.on_show_logs ), ( "install", "Install", self.on_install_clicked ), ( "add", "Add installed game", self.on_add_manually ), ( "configure", "Configure", self.on_edit_game_configuration ), ( "execute-script", "Execute script", self.on_execute_script_clicked ), ( "browse", "Browse files", self.on_browse_files ), ( "desktop-shortcut", "Create desktop shortcut", self.on_create_desktop_shortcut, ), ( "rm-desktop-shortcut", "Delete desktop shortcut", self.on_remove_desktop_shortcut, ), ( "menu-shortcut", "Create application menu shortcut", self.on_create_menu_shortcut, ), ( "rm-menu-shortcut", "Delete application menu shortcut", self.on_remove_menu_shortcut, ), ( "install_more", "Install another version", self.on_install_clicked ), ( "remove", "Remove", self.on_remove_game ), ( "view", "View on Lutris.net", self.on_view_game ), ] def get_displayed_entries(self): """Return a dictionary of actions that should be shown for a game""" return { "add": not self.game.is_installed and not self.game.is_search_result, "install": not self.game.is_installed, "play": self.game.is_installed and not self.is_game_running, "stop": self.is_game_running, "show_logs": self.game.is_installed, "configure": bool(self.game.is_installed), "install_more": self.game.is_installed and not self.game.is_search_result, "execute-script": bool( self.game.is_installed and self.game.runner.system_config.get("manual_command") ), "desktop-shortcut": ( self.game.is_installed and not xdgshortcuts.desktop_launcher_exists(self.game.slug, self.game.id) ), "menu-shortcut": ( self.game.is_installed and not xdgshortcuts.menu_launcher_exists(self.game.slug, self.game.id) ), "rm-desktop-shortcut": bool( self.game.is_installed and xdgshortcuts.desktop_launcher_exists(self.game.slug, self.game.id) ), "rm-menu-shortcut": bool( self.game.is_installed and xdgshortcuts.menu_launcher_exists(self.game.slug, self.game.id) ), "browse": self.game.is_installed and self.game.runner_name != "browser", "remove": not self.game.is_search_result, "view": True } def on_game_run(self, *_args): """Launch a game""" self.application.launch(self.game) def get_running_game(self): for i in range(self.application.running_games.get_n_items()): game = self.application.running_games.get_item(i) if game == self.game: return game def on_stop(self, caller): """Stops the game""" matched_game = self.get_running_game() if not matched_game: logger.warning("%s not in running game list", self.game_id) return try: os.kill(matched_game.game_thread.game_process.pid, signal.SIGTERM) except ProcessLookupError: pass logger.debug("Removed game with ID %s from running games", self.game_id) def on_show_logs(self, _widget): """Display game log""" return LogWindow( title="Log for {}".format(self.game), buffer=self.game.log_buffer, application=self.application ) def on_install_clicked(self, *_args): """Install a game""" # Install the currently selected game in the UI return InstallerWindow( parent=self.window, game_slug=self.game.slug, application=self.application, ) def on_add_manually(self, _widget, *_args): """Callback that presents the Add game dialog""" AddGameDialog(self.window, game=self.game, runner=self.game.runner_name) def on_edit_game_configuration(self, _widget): """Edit game preferences""" EditGameConfigDialog(self.window, self.game) def on_execute_script_clicked(self, _widget): """Execute the game's associated script""" manual_command = self.game.runner.system_config.get("manual_command") if path_exists(manual_command): MonitoredCommand( [manual_command], include_processes=[os.path.basename(manual_command)], cwd=self.game.directory, ).start() logger.info("Running %s in the background", manual_command) def on_browse_files(self, _widget): """Callback to open a game folder in the file browser""" path = self.game.get_browse_dir() if not path: dialogs.NoticeDialog("This game has no installation directory") elif path_exists(path): open_uri("file://%s" % path) else: dialogs.NoticeDialog("Can't open %s \nThe folder doesn't exist." % path) def on_create_menu_shortcut(self, *_args): """Add the selected game to the system's Games menu.""" xdgshortcuts.create_launcher(self.game.slug, self.game.id, self.game.name, menu=True) def on_create_desktop_shortcut(self, *_args): """Create a desktop launcher for the selected game.""" xdgshortcuts.create_launcher(self.game.slug, self.game.id, self.game.name, desktop=True) def on_remove_menu_shortcut(self, *_args): """Remove an XDG menu shortcut""" xdgshortcuts.remove_launcher(self.game.slug, self.game.id, menu=True) def on_remove_desktop_shortcut(self, *_args): """Remove a .desktop shortcut""" xdgshortcuts.remove_launcher(self.game.slug, self.game.id, desktop=True) def on_view_game(self, _widget): """Callback to open a game on lutris.net""" open_uri("https://lutris.net/games/%s" % self.game.slug) def on_remove_game(self, *_args): """Callback that present the uninstall dialog to the user""" UninstallGameDialog( game_id=self.game.id, callback=self.window.remove_game_from_view, parent=self.window )
class GameActions: """Regroup a list of callbacks for a game""" def __init__(self, application=None, window=None): self.application = application or Gio.Application.get_default() self.window = window self.game_id = None self._game = None @property def game(self): if not self._game: self._game = self.application.get_game_by_id(self.game_id) if not self._game: self._game = Game(self.game_id) self._game.connect("game-error", self.window.on_game_error) self._game.connect("game-stop", self.on_stop) return self._game @property def is_game_running(self): return bool(self.application.get_game_by_id(self.game_id)) def set_game(self, game=None, game_id=None): if game: self._game = game self.game_id = game.id else: self._game = None self.game_id = game_id def get_game_actions(self): """Return a list of game actions and their callbacks""" return [ ("play", "Play", self.on_game_run), ("stop", "Stop", self.on_stop), ("show_logs", "Show logs", self.on_show_logs), ("install", "Install", self.on_install_clicked), ("add", "Add installed game", self.on_add_manually), ("configure", "Configure", self.on_edit_game_configuration), ("execute-script", "Execute script", self.on_execute_script_clicked), ("browse", "Browse files", self.on_browse_files), ( "desktop-shortcut", "Create desktop shortcut", self.on_create_desktop_shortcut, ), ( "rm-desktop-shortcut", "Delete desktop shortcut", self.on_remove_desktop_shortcut, ), ( "menu-shortcut", "Create application menu shortcut", self.on_create_menu_shortcut, ), ( "rm-menu-shortcut", "Delete application menu shortcut", self.on_remove_menu_shortcut, ), ("install_more", "Install another version", self.on_install_clicked), ("remove", "Remove", self.on_remove_game), ("view", "View on Lutris.net", self.on_view_game), ] def get_displayed_entries(self): """Return a dictionary of actions that should be shown for a game""" return { "add": not self.game.is_installed, "install": not self.game.is_installed, "play": self.game.is_installed and not self.is_game_running, "stop": self.is_game_running, "show_logs": self.is_game_running, "configure": bool(self.game.is_installed), "install_more": self.game.is_installed, "execute-script": bool(self.game.is_installed and self.game.runner.system_config.get("manual_command")), "desktop-shortcut": (self.game.is_installed and not xdgshortcuts.desktop_launcher_exists( self.game.slug, self.game.id)), "menu-shortcut": (self.game.is_installed and not xdgshortcuts.menu_launcher_exists( self.game.slug, self.game.id)), "rm-desktop-shortcut": bool(self.game.is_installed and xdgshortcuts.desktop_launcher_exists( self.game.slug, self.game.id)), "rm-menu-shortcut": bool(self.game.is_installed and xdgshortcuts.menu_launcher_exists( self.game.slug, self.game.id)), "browse": self.game.is_installed and self.game.runner_name != "browser", "remove": self.game.is_installed, "view": True } def get_disabled_entries(self): """Return a dictionary of actions that should be disabled for a game""" return {} def on_game_run(self, *_args): """Launch a game""" self.application.launch(self.game) def on_stop(self, caller): """Stops the game""" try: game = self.application.running_games.pop( self.application.running_games.index(self.game)) os.kill(game.game_thread.game_process.pid, signal.SIGKILL) except ValueError: logger.warning("%s not in running game list", self.game_id) else: logger.debug("Removed game with ID %s from running games", self.game_id) def on_show_logs(self, _widget): """Display game log in a LogDialog""" log_title = u"Log for {}".format(self.game) log_window = LogDialog(title=log_title, buffer=self.game.log_buffer, parent=self.window) log_window.run() log_window.destroy() def on_install_clicked(self, *_args): """Install a game""" # Install the currently selected game in the UI return InstallerWindow( parent=self.window, game_slug=self.game.slug, application=self.application, ) def on_add_manually(self, _widget, *_args): """Callback that presents the Add game dialog""" def on_game_added(game): self.window.view.set_installed(game) GLib.idle_add(resources.fetch_icon, game.slug, self.window.on_image_downloaded) self.window.sidebar_listbox.update() AddGameDialog( self.window, game=self.game, runner=self.game.runner_name, callback=lambda: on_game_added(self.game), ) def on_edit_game_configuration(self, _widget): """Edit game preferences""" def on_dialog_saved(): game_id = dialog.game.id self.window.view.remove_game(game_id) self.window.view.add_game_by_id(game_id) self.window.view.set_selected_game(game_id) self.window.sidebar_listbox.update() dialog = EditGameConfigDialog(self.window, self.game, on_dialog_saved) def on_execute_script_clicked(self, _widget): """Execute the game's associated script""" manual_command = self.game.runner.system_config.get("manual_command") if path_exists(manual_command): MonitoredCommand( [manual_command], include_processes=[os.path.basename(manual_command)], cwd=self.game.directory, ).start() logger.info("Running %s in the background", manual_command) def on_browse_files(self, _widget): """Callback to open a game folder in the file browser""" path = self.game.get_browse_dir() if path and os.path.exists(path): open_uri("file://%s" % path) else: dialogs.NoticeDialog("Can't open %s \nThe folder doesn't exist." % path) def on_create_menu_shortcut(self, *_args): """Add the selected game to the system's Games menu.""" xdgshortcuts.create_launcher(self.game.slug, self.game.id, self.game.name, menu=True) def on_create_desktop_shortcut(self, *_args): """Create a desktop launcher for the selected game.""" xdgshortcuts.create_launcher(self.game.slug, self.game.id, self.game.name, desktop=True) def on_remove_menu_shortcut(self, *_args): """Remove an XDG menu shortcut""" xdgshortcuts.remove_launcher(self.game.slug, self.game.id, menu=True) def on_remove_desktop_shortcut(self, *_args): """Remove a .desktop shortcut""" xdgshortcuts.remove_launcher(self.game.slug, self.game.id, desktop=True) def on_view_game(self, _widget): """Callback to open a game on lutris.net""" open_uri("https://lutris.net/games/%s" % self.game.slug) def on_remove_game(self, *_args): """Callback that present the uninstall dialog to the user""" UninstallGameDialog(game_id=self.game.id, callback=self.window.remove_game_from_view, parent=self.window)
class GameActions: """Regroup a list of callbacks for a game""" def __init__(self, application=None, window=None): self.application = application or Gio.Application.get_default() self.window = window self.game_id = None self._game = None @property def game(self): if not self._game: self._game = self.application.get_game_by_id(self.game_id) if not self._game: self._game = Game(self.game_id) self._game.connect("game-error", self.window.on_game_error) return self._game @property def is_game_running(self): return bool(self.application.get_game_by_id(self.game_id)) def set_game(self, game=None, game_id=None): if game: self._game = game self.game_id = game.id else: self._game = None self.game_id = game_id def get_game_actions(self): """Return a list of game actions and their callbacks""" return [ ("play", _("Play"), self.on_game_launch), ("stop", _("Stop"), self.on_game_stop), ("show_logs", _("Show logs"), self.on_show_logs), ("install", _("Install"), self.on_install_clicked), ("add", _("Add installed game"), self.on_add_manually), ("configure", _("Configure"), self.on_edit_game_configuration), ("favorite", _("Add to favorites"), self.on_add_favorite_game), ("deletefavorite", _("Remove from favorites"), self.on_delete_favorite_game), ("execute-script", _("Execute script"), self.on_execute_script_clicked), ("browse", _("Browse files"), self.on_browse_files), ( "desktop-shortcut", _("Create desktop shortcut"), self.on_create_desktop_shortcut, ), ( "rm-desktop-shortcut", _("Delete desktop shortcut"), self.on_remove_desktop_shortcut, ), ( "menu-shortcut", _("Create application menu shortcut"), self.on_create_menu_shortcut, ), ( "rm-menu-shortcut", _("Delete application menu shortcut"), self.on_remove_menu_shortcut, ), ("install_more", _("Install another version"), self.on_install_clicked), ("remove", _("Remove"), self.on_remove_game), ("view", _("View on Lutris.net"), self.on_view_game), ("hide", _("Hide game from library"), self.on_hide_game), ("unhide", _("Unhide game from library"), self.on_unhide_game), ] def get_displayed_entries(self): """Return a dictionary of actions that should be shown for a game""" return { "add": not self.game.is_installed, "install": not self.game.is_installed, "play": self.game.is_installed and not self.is_game_running, "stop": self.is_game_running, "configure": bool(self.game.is_installed), "browse": self.game.is_installed and self.game.runner_name != "browser", "show_logs": self.game.is_installed, "favorite": not self.game.is_favorite, "deletefavorite": self.game.is_favorite, "install_more": self.game.is_installed, "execute-script": bool(self.game.is_installed and self.game.runner.system_config.get("manual_command")), "desktop-shortcut": (self.game.is_installed and not xdgshortcuts.desktop_launcher_exists( self.game.slug, self.game.id)), "menu-shortcut": (self.game.is_installed and not xdgshortcuts.menu_launcher_exists( self.game.slug, self.game.id)), "rm-desktop-shortcut": bool(self.game.is_installed and xdgshortcuts.desktop_launcher_exists( self.game.slug, self.game.id)), "rm-menu-shortcut": bool(self.game.is_installed and xdgshortcuts.menu_launcher_exists( self.game.slug, self.game.id)), "remove": self.game.is_installed, "view": True, "hide": not self.game.is_hidden, "unhide": self.game.is_hidden, } def on_game_launch(self, *_args): """Launch a game""" self.game.launch() def get_running_game(self): ids = self.application.get_running_game_ids() for game_id in ids: if game_id == self.game.id: return self.game logger.warning("Game %s not in %s", self.game_id, ids) def on_game_stop(self, caller): # pylint: disable=unused-argument """Stops the game""" matched_game = self.get_running_game() if not matched_game: return if not matched_game.game_thread: logger.warning( "Game %s doesn't appear to be running, not killing it", self.game_id) return try: os.kill(matched_game.game_thread.game_process.pid, signal.SIGTERM) except ProcessLookupError as ex: logger.debug("Failed to kill game process: %s", ex) def on_show_logs(self, _widget): """Display game log""" _buffer = LOG_BUFFERS.get(self.game.id) if not _buffer: logger.info("No log for game %s", self.game) return LogWindow(title=_("Log for {}").format(self.game), buffer=_buffer, application=self.application) def on_install_clicked(self, *_args): """Install a game""" # Install the currently selected game in the UI installers = get_installers(game_slug=self.game.slug) self.application.show_installer_window(installers=installers) def on_add_manually(self, _widget, *_args): """Callback that presents the Add game dialog""" AddGameDialog(self.window, game=self.game, runner=self.game.runner_name) def on_edit_game_configuration(self, _widget): """Edit game preferences""" EditGameConfigDialog(self.window, self.game) def on_add_favorite_game(self, _widget): """Add to favorite Games list""" self.game.add_to_favorites() def on_delete_favorite_game(self, _widget): """delete from favorites""" self.game.remove_from_favorites() def on_hide_game(self, _widget): """Add a game to the list of hidden games""" self.game.hide() def on_unhide_game(self, _widget): """Removes a game from the list of hidden games""" self.game.unhide() def on_execute_script_clicked(self, _widget): """Execute the game's associated script""" manual_command = self.game.runner.system_config.get("manual_command") if path_exists(manual_command): MonitoredCommand( [manual_command], include_processes=[os.path.basename(manual_command)], cwd=self.game.directory, ).start() logger.info("Running %s in the background", manual_command) def on_browse_files(self, _widget): """Callback to open a game folder in the file browser""" path = self.game.get_browse_dir() if not path: dialogs.NoticeDialog(_("This game has no installation directory")) elif path_exists(path): open_uri("file://%s" % path) else: dialogs.NoticeDialog( _("Can't open %s \nThe folder doesn't exist.") % path) def on_create_menu_shortcut(self, *_args): """Add the selected game to the system's Games menu.""" xdgshortcuts.create_launcher(self.game.slug, self.game.id, self.game.name, menu=True) def on_create_desktop_shortcut(self, *_args): """Create a desktop launcher for the selected game.""" xdgshortcuts.create_launcher(self.game.slug, self.game.id, self.game.name, desktop=True) def on_remove_menu_shortcut(self, *_args): """Remove an XDG menu shortcut""" xdgshortcuts.remove_launcher(self.game.slug, self.game.id, menu=True) def on_remove_desktop_shortcut(self, *_args): """Remove a .desktop shortcut""" xdgshortcuts.remove_launcher(self.game.slug, self.game.id, desktop=True) def on_view_game(self, _widget): """Callback to open a game on lutris.net""" open_uri("https://lutris.net/games/%s" % self.game.slug) def on_remove_game(self, *_args): """Callback that present the uninstall dialog to the user""" UninstallGameDialog(game_id=self.game.id, callback=self.window.update_store, parent=self.window)