def options_as_dict(self, options_type): """Convert the option list to a dict with option name as keys""" options = {} if options_type == 'system': options = sysoptions.system_options elif options_type == 'runner' and self.runner_slug: runner = import_runner(self.runner_slug)() options = runner.runner_options elif options_type == 'game' and self.runner_slug: runner = import_runner(self.runner_slug)() options = runner.game_options return dict((opt['option'], opt) for opt in options)
def dosexec(config_file=None, executable=None, args=None, exit=True, working_dir=None): """Execute Dosbox with given config_file.""" if config_file: run_with = "config {}".format(config_file) if not working_dir: working_dir = os.path.dirname(config_file) elif executable: run_with = "executable {}".format(executable) if not working_dir: working_dir = os.path.dirname(executable) else: raise ValueError("Neither a config file or an executable were provided") logger.debug("Running dosbox with %s", run_with) working_dir = system.create_folder(working_dir) dosbox = import_runner("dosbox") dosbox_runner = dosbox() command = [dosbox_runner.get_executable()] if config_file: command += ["-conf", config_file] if executable: if not system.path_exists(executable): raise OSError("Can't find file {}".format(executable)) command += [executable] if args: command += args.split() if exit: command.append("-exit") system.execute(command, cwd=working_dir)
def on_save(self, _button): """Save game info and destroy widget. Return True if success.""" if not self.is_valid(): return False name = self.name_entry.get_text() # Do not modify slug if not self.slug: self.slug = slugify(name) if not self.game: self.game = Game(self.slug) self.game.config = self.lutris_config if not self.lutris_config.game_slug: self.lutris_config.game_slug = self.slug self.lutris_config.save() runner_class = runners.import_runner(self.runner_name) runner = runner_class(self.lutris_config) self.game.name = name self.game.slug = self.slug self.game.runner_name = self.runner_name self.game.directory = runner.game_path self.game.is_installed = True self.game.save() self.destroy() logger.debug("Saved %s", name) self.saved = True
def task(self, data): """ This action triggers a task within a runner. The 'name' parameter is mandatory. If 'args' is provided it will be passed to the runner task. """ task_name = data.pop('name') if not task_name: raise ScriptingError("Missing required task name", data) if '.' in task_name: # Run a task from a different runner than the one for this installer runner_name, task_name = task_name.split('.') else: runner_name = self.script["runner"] # Check that runner is installed or install it runner = import_runner(runner_name)() if not runner.is_installed(): Gdk.threads_init() Gdk.threads_enter() runner.install() Gdk.threads_leave() for key in data: data[key] = self._substitute(data[key]) task = import_task(runner_name, task_name) task(**data)
def __init__(self, lutris_config, caller, runner_name): ConfigBox.__init__(self, runner_name, caller) runner = import_runner(runner_name)() self.options = runner.runner_options self.lutris_config = lutris_config self.generate_widgets()
def _create_button_box(self): self.btn_box = Gtk.Box( spacing=3, no_show_all=True, valign=Gtk.Align.CENTER, homogeneous=True ) # Creation is delayed because only installed runners can be imported # and all visible boxes should be installed. self.runner = runners.import_runner(self.id)() entries = [] if self.runner.multiple_versions: entries.append( ( "system-software-install-symbolic", "Manage Versions", self.on_manage_versions, ) ) if self.runner.runnable_alone: entries.append(("media-playback-start-symbolic", "Run", self.runner.run)) entries.append( ("emblem-system-symbolic", "Configure", self.on_configure_runner) ) for entry in entries: btn = Gtk.Button( tooltip_text=entry[1], relief=Gtk.ReliefStyle.NONE, visible=True ) image = Gtk.Image.new_from_icon_name(entry[0], Gtk.IconSize.MENU) image.show() btn.add(image) btn.connect("clicked", entry[2]) self.btn_box.add(btn) self.box.add(self.btn_box)
def on_save(self, _button, callback=None): """Save game info and destroy widget. Return True if success.""" if not self.is_valid(): return False name = self.name_entry.get_text() # Do not modify slug if not self.slug: self.slug = slugify(name) if not self.game: self.game = Game() if self.lutris_config.game_config_id == TEMP_CONFIG: self.lutris_config.game_config_id = self.get_config_id() runner_class = runners.import_runner(self.runner_name) runner = runner_class(self.lutris_config) self.game.name = name self.game.slug = self.slug self.game.runner_name = self.runner_name self.game.config = self.lutris_config self.game.directory = runner.game_path self.game.is_installed = True if self.runner_name in ('steam', 'winesteam'): self.game.steamid = self.lutris_config.game_config['appid'] self.game.save() self.destroy() logger.debug("Saved %s", name) self.saved = True if callback: callback()
def get_runner_class(self, runner_name): try: runner = import_runner(runner_name) except InvalidRunner: GLib.idle_add(self.parent.cancel_button.set_sensitive, True) raise ScriptingError('Invalid runner provided %s', runner_name) return runner
def get_runner_class(self, runner_name): """Runner the runner class from its name""" try: runner = import_runner(runner_name) except InvalidRunner: GLib.idle_add(self.parent.cancel_button.set_sensitive, True) raise ScriptingError("Invalid runner provided %s" % runner_name) return runner
def __init__(self, pga_data): if not pga_data: raise RuntimeError("No game data provided") self._pga_data = pga_data self.runner_names = { runner: runners.import_runner(runner).human_name for runner in runners.__all__ }
def __init__(self, lutris_config, caller): ConfigBox.__init__(self, "game", caller) self.lutris_config = lutris_config self.lutris_config.config_type = "game" self.runner_class = self.lutris_config.runner runner = import_runner(self.runner_class)() self.options = runner.game_options self.generate_widgets()
def __init__(self): GObject.GObject.__init__(self) self.set_title("Configure runners") self.set_size_request(570, 400) label = Gtk.Label() label.set_markup("<b>Install and configure the game runners</b>") scrolled_window = Gtk.ScrolledWindow() scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.vbox.pack_start(label, False, True, 20) self.vbox.pack_start(scrolled_window, True, True, 10) close_button = Gtk.Button("Close") close_button.connect('clicked', self.close) self.action_area.pack_start(close_button, False, False, 10) runner_list = lutris.runners.__all__ runner_vbox = Gtk.VBox() for runner_name in runner_list: # Get runner details runner = import_runner(runner_name)() platform = runner.platform description = runner.description hbox = Gtk.HBox() #Icon icon_path = os.path.join(datapath.get(), 'media/runner_icons', runner_name + '.png') icon = Gtk.Image() icon.set_from_file(icon_path) hbox.pack_start(icon, False, False, 10) #Label runner_label = Gtk.Label() runner_label.set_markup( "<b>%s</b>\n%s\n <i>Supported platforms : %s</i>" % (runner_name, description, platform) ) runner_label.set_width_chars(38) runner_label.set_line_wrap(True) runner_label.set_alignment(0.0, 0.0) runner_label.set_padding(25, 5) hbox.pack_start(runner_label, True, True, 5) #Button button = Gtk.Button() button.set_size_request(100, 30) button_align = Gtk.Alignment.new(0.0, 1.0, 0.0, 0.0) self.configure_button(button, runner) button_align.add(button) hbox.pack_start(button_align, True, False, 5) runner_vbox.pack_start(hbox, True, True, 5) scrolled_window.add_with_viewport(runner_vbox) self.show_all()
def _get_runner(self): """Return the runner instance for this game's configuration""" try: runner_class = import_runner(self.runner_name) return runner_class(self.config) except InvalidRunner: logger.error( "Unable to import runner %s for %s", self.runner_name, self.slug )
def load_config(self): """Load the game's configuration.""" self.config = LutrisConfig(game=self.slug) if self.is_installed: runner_class = import_runner(self.runner_name) if runner_class: self.runner = runner_class(self.config) else: logger.error("Unable to import runner %s", self.runner_name)
def load_config(self): """ Load the game's configuration. """ self.game_config = LutrisConfig(game=self.slug) if self.is_installed: if not self.game_config.is_valid(): logger.error("Invalid game config for %s" % self.slug) else: runner_class = import_runner(self.runner_name) self.runner = runner_class(self.game_config)
def get_runner_hbox(self, runner_name): # Get runner details runner = runners.import_runner(runner_name)() platform = ', '.join(sorted(list(set(runner.platforms)))) description = runner.description hbox = Gtk.HBox() hbox.show() # Icon icon = get_runner_icon(runner_name) icon.show() icon.set_alignment(0.5, 0.1) hbox.pack_start(icon, False, False, 10) # Label runner_label = Gtk.Label() runner_label.show() if not runner.is_installed(): runner_label.set_sensitive(False) runner_label.set_markup( "<b>%s</b>\n%s\n <i>Supported platforms : %s</i>" % (runner.human_name, description, platform) ) runner_label.set_width_chars(40) runner_label.set_max_width_chars(40) runner_label.set_property('wrap', True) runner_label.set_line_wrap(True) runner_label.set_alignment(0.0, 0.1) runner_label.set_padding(5, 0) self.runner_labels[runner] = runner_label hbox.pack_start(runner_label, True, True, 5) # Buttons self.versions_button = Gtk.Button("Manage versions") self.versions_button.set_size_request(120, 30) self.versions_button.set_valign(Gtk.Align.CENTER) self.versions_button.connect("clicked", self.on_versions_clicked, runner, runner_label) hbox.pack_start(self.versions_button, False, False, 5) self.install_button = Gtk.Button("Install") self.install_button.set_size_request(80, 30) self.install_button.set_valign(Gtk.Align.CENTER) self.install_button.connect("clicked", self.on_install_clicked, runner, runner_label) hbox.pack_start(self.install_button, False, False, 5) self.configure_button = Gtk.Button("Configure") self.configure_button.set_size_request(90, 30) self.configure_button.set_valign(Gtk.Align.CENTER) self.configure_button.connect("clicked", self.on_configure_clicked, runner, runner_label) hbox.pack_start(self.configure_button, False, False, 5) self.set_button_display(runner) return hbox
def test_options(self): for runner_name in runners.__all__: LOGGER.info("Importing %s", runner_name) runner_class = runners.import_runner(runner_name) runner = runner_class() self.assertTrue(hasattr(runner, "game_options"), "%s doesn't have game options" % runner_name) self.assertTrue(hasattr(runner, "runner_options")) for option in runner.game_options: self.assertIn("type", option) self.assertFalse(option["type"] == "single")
def __init__(self, lutris_config, game): ConfigBox.__init__(self, game) self.lutris_config = lutris_config if game.runner_name: runner = game.runner or import_runner(game.runner_name)() self.options = runner.game_options else: logger.warning("No runner in game supplied to GameBox") self.options = [] self.generate_widgets('game')
def popup(self, event, game_row): game_id = game_row[COL_ID] game_slug = game_row[COL_SLUG] runner_slug = game_row[COL_RUNNER] # Clear existing menu for item in self.get_children(): self.remove(item) # Main items self.add_menuitems(self.main_entries) # Runner specific items runner_entries = None if runner_slug: game = Game(game_id) runner = import_runner(runner_slug)(game.config) runner_entries = runner.context_menu_entries if runner_entries: self.append(Gtk.SeparatorMenuItem()) self.add_menuitems(runner_entries) self.show_all() # Hide some items is_installed = game_row[COL_INSTALLED] hiding_condition = { 'add': is_installed, 'play': not is_installed, 'configure': not is_installed, 'desktop-shortcut': ( not is_installed or desktop_launcher_exists(game_slug, game_id) ), 'menu-shortcut': ( not is_installed or menu_launcher_exists(game_slug, game_id) ), 'rm-desktop-shortcut': ( not is_installed or not desktop_launcher_exists(game_slug, game_id) ), 'rm-menu-shortcut': ( not is_installed or not menu_launcher_exists(game_slug, game_id) ), 'browse': not is_installed or game_row[COL_RUNNER] == 'browser', } for menuitem in self.get_children(): if type(menuitem) is not Gtk.ImageMenuItem: continue action = menuitem.action_id visible = not hiding_condition.get(action) menuitem.set_visible(visible) super(ContextualMenu, self).popup(None, None, None, None, event.button, event.time)
def test_options(self): for runner_name in runners.__all__: LOGGER.info("Importing %s", runner_name) runner_class = runners.import_runner(runner_name) runner = runner_class() self.assertTrue(hasattr(runner, 'game_options'), "%s doesn't have game options" % runner_name) self.assertTrue(hasattr(runner, 'runner_options')) for option in runner.game_options: self.assertIn('type', option) self.assertFalse(option['type'] == 'single')
def __init__(self, lutris_config, caller, game=None): ConfigBox.__init__(self, "game", caller, game) self.lutris_config = lutris_config self.lutris_config.config_type = "game" self.runner_class = self.lutris_config.runner if self.runner_class: runner = import_runner(self.runner_class)() self.options = runner.game_options else: self.options = [] self.generate_widgets()
def task(self, data): """Directive triggering another function specific to a runner. The 'name' parameter is mandatory. If 'args' is provided it will be passed to the runner task. """ self._check_required_params("name", data, "task") self.parent.cancel_button.set_sensitive(False) task_name = data.pop("name") if "." in task_name: # Run a task from a different runner # than the one for this installer runner_name, task_name = task_name.split(".") else: runner_name = self.script["runner"] try: runner_class = import_runner(runner_name) except InvalidRunner: self.parent.cancel_button.set_sensitive(True) raise ScriptingError("Invalid runner provided %s", runner_name) runner = runner_class() # Check/install Wine runner at version specified in the script wine_version = None if runner_name == "wine" and self.script.get("wine"): wine_version = self.script.get("wine").get("version") # Old lutris versions used a version + arch tuple, we now include # everything in the version. # Before that change every wine runner was for i386 if "-" not in wine_version: wine_version += "-i386" if wine_version and task_name == "wineexec": if not wine.is_version_installed(wine_version): Gdk.threads_init() Gdk.threads_enter() runner.install(wine_version) Gdk.threads_leave() data["wine_path"] = wine.get_wine_version_exe(wine_version) # Check/install other runner elif not runner.is_installed(): Gdk.threads_init() Gdk.threads_enter() runner.install() Gdk.threads_leave() for key in data: data[key] = self._substitute(data[key]) task = import_task(runner_name, task_name) task(**data) self.parent.cancel_button.set_sensitive(True)
def __init__(self, lutris_config): ConfigBox.__init__(self) self.lutris_config = lutris_config runner = import_runner(self.lutris_config.runner_slug)() self.options = runner.runner_options if lutris_config.game_slug: self.generate_top_info_box( "If modified, these options supersede the same options from " "the base runner configuration." ) self.generate_widgets('runner')
def __init__(self, lutris_config, caller, game): ConfigBox.__init__(self, "game", caller, game) self.lutris_config = lutris_config self.lutris_config.config_type = "game" if game.runner_name: self.runner_name = game.runner_name runner = import_runner(self.runner_name)() self.options = runner.game_options else: logger.warning("No runner in game supplied to GameBox") self.options = [] self.generate_widgets()
def __init__(self, lutris_config, caller): runner_classname = lutris_config.runner ConfigVBox.__init__(self, runner_classname, caller) runner = import_runner(runner_classname)() if "runner_options" is not None: self.options = runner.runner_options self.lutris_config = lutris_config self.generate_widgets() else: warningLabel = Gtk.Label(label="This runner has no options yet\n" + "Please fix this") self.pack_start(warningLabel, True, True, 0)
def get_runner_liststore(): """Build a ListStore with available runners.""" runner_liststore = Gtk.ListStore(str, str) runner_liststore.append(("Select a runner from the list", "")) for runner_name in runners.__all__: runner_class = runners.import_runner(runner_name) runner = runner_class() if runner.is_installed(): description = runner.description runner_liststore.append( ("%s (%s)" % (runner_name, description), runner_name) ) return runner_liststore
def test_get_system_config(self): def fake_yaml_reader(path): if not path: return {} if 'system.yml' in path: return {'system': {'resolution': '640x480'}} return {} with patch('lutris.config.read_yaml_from_file') as yaml_reader: yaml_reader.side_effect = fake_yaml_reader wine_runner = runners.import_runner('wine') wine = wine_runner() self.assertEqual(wine.system_config.get('resolution'), '640x480')
def build_game_tab(self): if self.game and self.runner_name: self.game.runner_name = self.runner_name self.game.runner = runners.import_runner(self.runner_name) self.game_box = GameBox(self.lutris_config, self.game) game_sw = self.build_scrolled_window(self.game_box) elif self.runner_name: game = Game(None) game.runner_name = self.runner_name self.game_box = GameBox(self.lutris_config, game) game_sw = self.build_scrolled_window(self.game_box) else: game_sw = Gtk.Label(label=self.no_runner_label) self.add_notebook_tab(game_sw, "Game options")
def load_config(self): """Load the game's configuration.""" self.config = LutrisConfig(game=self.slug) if not self.is_installed: return if not self.runner_name: logger.error('Incomplete data for %s', self.slug) return try: runner_class = import_runner(self.runner_name) except InvalidRunner: logger.error("Unable to import runner %s for %s", self.runner_name, self.slug) self.runner = runner_class(self.config)
def task(self, data): """ This action triggers a task within a runner. The 'name' parameter is mandatory. If 'args' is provided it will be passed to the runner task. """ self._check_required_params('name', data, 'task') task_name = data.pop('name') if '.' in task_name: # Run a task from a different runner than the one for this installer runner_name, task_name = task_name.split('.') else: runner_name = self.script["runner"] try: runner_class = import_runner(runner_name) except InvalidRunner: raise ScriptingError('Invalid runner provided %s', runner_name) runner = runner_class() # Check/install Wine runner at version specified in the script wine_version = None if runner_name == 'wine' and self.script.get('wine'): wine_version = self.script.get('wine').get('version') # Old lutris versions used a version + arch tuple, we now include # everything in the version. # Before that change every wine runner was for i386 if '-' not in wine_version: wine_version += '-i386' if wine_version and task_name == 'wineexec': if not wine.is_version_installed(wine_version): Gdk.threads_init() Gdk.threads_enter() runner.install(wine_version) Gdk.threads_leave() data['wine_path'] = wine.get_wine_version_exe(wine_version) # Check/install other runner elif not runner.is_installed(): Gdk.threads_init() Gdk.threads_enter() runner.install() Gdk.threads_leave() for key in data: data[key] = self._substitute(data[key]) task = import_task(runner_name, task_name) task(**data)
def __init__(self): GObject.GObject.__init__(self) self.set_title("Configure runners") self.set_size_request(700, 600) self.vbox = Gtk.VBox() self.vbox.set_margin_right(10) self.vbox.set_margin_left(10) self.vbox.set_margin_bottom(10) self.add(self.vbox) label = Gtk.Label() label.set_markup("<b>Install and configure the game runners</b>") scrolled_window = Gtk.ScrolledWindow() scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) scrolled_window.set_shadow_type(Gtk.ShadowType.ETCHED_OUT) self.vbox.pack_start(label, False, True, 15) self.vbox.pack_start(scrolled_window, True, True, 0) runner_list = lutris.runners.__all__ runner_vbox = Gtk.VBox() self.runner_labels = {} for runner_name in runner_list: # Get runner details runner = import_runner(runner_name)() platform = runner.platform description = runner.description hbox = Gtk.HBox() # Icon icon_path = os.path.join(datapath.get(), 'media/runner_icons', runner_name + '.png') icon = Gtk.Image() icon.set_from_file(icon_path) icon.set_alignment(0.5, 0.1) hbox.pack_start(icon, False, False, 10) # Label runner_label = Gtk.Label() if not runner.is_installed(): runner_label.set_sensitive(False) runner_label.set_markup( "<b>%s</b>\n%s\n <i>Supported platforms : %s</i>" % (runner_name, description, platform) ) runner_label.set_width_chars(40) runner_label.set_max_width_chars(40) runner_label.set_property('wrap', True) runner_label.set_line_wrap(True) runner_label.set_alignment(0.0, 0.1) runner_label.set_padding(5, 0) self.runner_labels[runner] = runner_label hbox.pack_start(runner_label, True, True, 5) # Button button = Gtk.Button() button.set_size_request(100, 30) button_align = Gtk.Alignment.new(1.0, 0.0, 0.0, 0.0) self.configure_button(button, runner) button_align.add(button) hbox.pack_start(button_align, False, False, 15) runner_vbox.pack_start(hbox, True, True, 5) separator = Gtk.Separator() runner_vbox.pack_start(separator, False, False, 5) scrolled_window.add_with_viewport(runner_vbox) self.show_all()
def get_runner_hbox(self, runner_name): # Get runner details runner = runners.import_runner(runner_name)() platform = runner.platforms if (isinstance(platform, tuple) or isinstance(platform, list)) and isinstance(platform[0], tuple): platform = map(lambda p: ' '.join(p), platform) platform = sorted(list(set(platform))) platform = ', '.join(platform) if not isinstance(platform, str): platform = ' '.join(platform) description = runner.description hbox = Gtk.HBox() hbox.show() # Icon icon = get_runner_icon(runner_name) icon.show() icon.set_alignment(0.5, 0.1) hbox.pack_start(icon, False, False, 10) # Label runner_label = Gtk.Label() runner_label.show() if not runner.is_installed(): runner_label.set_sensitive(False) runner_label.set_markup( "<b>%s</b>\n%s\n <i>Supported platforms : %s</i>" % (runner.human_name, description, platform) ) runner_label.set_width_chars(40) runner_label.set_max_width_chars(40) runner_label.set_property('wrap', True) runner_label.set_line_wrap(True) runner_label.set_alignment(0.0, 0.1) runner_label.set_padding(5, 0) self.runner_labels[runner] = runner_label hbox.pack_start(runner_label, True, True, 5) # Buttons self.versions_button = Gtk.Button("Manage versions") self.versions_button.set_size_request(120, 30) self.versions_button.set_valign(Gtk.Align.CENTER) self.versions_button.connect("clicked", self.on_versions_clicked, runner, runner_label) hbox.pack_start(self.versions_button, False, False, 5) self.install_button = Gtk.Button("Install") self.install_button.set_size_request(80, 30) self.install_button.set_valign(Gtk.Align.CENTER) self.install_button.connect("clicked", self.on_install_clicked, runner, runner_label) hbox.pack_start(self.install_button, False, False, 5) self.configure_button = Gtk.Button("Configure") self.configure_button.set_size_request(90, 30) self.configure_button.set_valign(Gtk.Align.CENTER) self.configure_button.connect("clicked", self.on_configure_clicked, runner, runner_label) hbox.pack_start(self.configure_button, False, False, 5) self.set_button_display(runner) return hbox
def create_prefix( # noqa: C901 prefix, wine_path=None, arch=WINE_DEFAULT_ARCH, overrides=None, install_gecko=None, install_mono=None, ): """Create a new Wine prefix.""" # pylint: disable=too-many-locals if overrides is None: overrides = {} if not prefix: raise ValueError("No Wine prefix path given") logger.info("Creating a %s prefix in %s", arch, prefix) # Follow symlinks, don't delete existing ones as it would break some setups if os.path.islink(prefix): prefix = os.readlink(prefix) # Avoid issue of 64bit Wine refusing to create win32 prefix # over an existing empty folder. if os.path.isdir(prefix) and not os.listdir(prefix): os.rmdir(prefix) if not wine_path: wine = import_runner("wine") wine_path = wine().get_executable() if not wine_path: logger.error("Wine not found, can't create prefix") return wineboot_path = os.path.join(os.path.dirname(wine_path), "wineboot") if not system.path_exists(wineboot_path): logger.error( "No wineboot executable found in %s, " "your wine installation is most likely broken", wine_path, ) return wineenv = { "WINEARCH": arch, "WINEPREFIX": prefix, "WINEDLLOVERRIDES": get_overrides_env(overrides), "WINE_MONO_CACHE_DIR": os.path.join(os.path.dirname(os.path.dirname(wine_path)), "mono"), "WINE_GECKO_CACHE_DIR": os.path.join(os.path.dirname(os.path.dirname(wine_path)), "gecko"), } if install_gecko == "False": wineenv["WINE_SKIP_GECKO_INSTALLATION"] = "1" overrides["mshtml"] = "disabled" if install_mono == "False": wineenv["WINE_SKIP_MONO_INSTALLATION"] = "1" overrides["mscoree"] = "disabled" system.execute([wineboot_path], env=wineenv) for loop_index in range(60): time.sleep(0.5) if system.path_exists(os.path.join(prefix, "user.reg")): break if loop_index == 30: logger.warning( "Wine prefix creation is taking longer than expected...") if not os.path.exists(os.path.join(prefix, "user.reg")): logger.error("No user.reg found after prefix creation. " "Prefix might not be valid") return logger.info("%s Prefix created in %s", arch, prefix) prefix_manager = WinePrefixManager(prefix) prefix_manager.setup_defaults()
def initialize_rows(self): """ Select the initial row; this triggers the initialization of the game view so we must do this even if this sidebar is never realized, but only after the sidebar's signals are connected. """ self.active_platforms = games_db.get_used_platforms() self.runners = sorted(runners.__all__) self.platforms = sorted(runners.RUNNER_PLATFORMS) self.categories = categories_db.get_categories() self.add( SidebarRow( "all", "category", _("Games"), Gtk.Image.new_from_icon_name("applications-games-symbolic", Gtk.IconSize.MENU))) self.add( SidebarRow( "recent", "dynamic_category", _("Recent"), Gtk.Image.new_from_icon_name("document-open-recent-symbolic", Gtk.IconSize.MENU))) self.add( SidebarRow( "favorite", "category", _("Favorites"), Gtk.Image.new_from_icon_name("favorite-symbolic", Gtk.IconSize.MENU))) self.running_row = SidebarRow( "running", "dynamic_category", _("Running"), Gtk.Image.new_from_icon_name("media-playback-start-symbolic", Gtk.IconSize.MENU)) # I wanted this to be on top but it really messes with the headers when showing/hiding the row. self.add(self.running_row) service_classes = services.get_enabled_services() for service_name in service_classes: service = service_classes[service_name]() row_class = OnlineServiceSidebarRow if service.online else ServiceSidebarRow service_row = row_class(service) self.service_rows[service_name] = service_row self.add(service_row) for runner_name in self.runners: icon_name = runner_name.lower().replace(" ", "") + "-symbolic" runner = runners.import_runner(runner_name)() self.add( RunnerSidebarRow(runner_name, "runner", runner.human_name, self.get_sidebar_icon(icon_name), application=self.application)) for platform in self.platforms: icon_name = (platform.lower().replace(" ", "").replace("/", "_") + "-symbolic") self.add( SidebarRow(platform, "platform", platform, self.get_sidebar_icon(icon_name))) self.update() for row in self.get_children(): if row.type == self.selected_row_type and row.id == self.selected_row_id: self.select_row(row) break self.show_all() self.running_row.hide()
def __init__(self, application, selected=None): super().__init__() self.application = application self.get_style_context().add_class("sidebar") self.installed_runners = [] self.active_platforms = games_db.get_used_platforms() self.runners = sorted(runners.__all__) self.platforms = sorted(platforms.__all__) self.categories = categories_db.get_categories() if selected: row_type, row_id = selected.split(":") else: row_type, row_id = ("runner", "all") GObject.add_emission_hook(RunnersDialog, "runner-installed", self.update) GObject.add_emission_hook(RunnersDialog, "runner-removed", self.update) GObject.add_emission_hook(Game, "game-updated", self.update) GObject.add_emission_hook(Game, "game-removed", self.update) load_icon_theme() self.add( SidebarRow( "running", "dynamic_category", _("Running"), Gtk.Image.new_from_icon_name("media-playback-start-symbolic", Gtk.IconSize.MENU) ) ) self.add( SidebarRow( "installed", "dynamic_category", _("Installed"), Gtk.Image.new_from_icon_name("drive-harddisk-symbolic", Gtk.IconSize.MENU) ) ) self.add( SidebarRow( "favorite", "category", _("Favorites"), Gtk.Image.new_from_icon_name("favorite-symbolic", Gtk.IconSize.MENU) ) ) service_classes = services.get_services() for service_name in service_classes: service = service_classes[service_name]() self.add( SidebarRow( service.id, "service", service.name, Gtk.Image.new_from_icon_name(service.icon, Gtk.IconSize.MENU) ) ) all_row = RunnerSidebarRow(None, "runner", _("All"), None) self.add(all_row) for runner_name in self.runners: icon_name = runner_name.lower().replace(" ", "") + "-symbolic" icon = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.MENU) runner = runners.import_runner(runner_name)() self.add(RunnerSidebarRow(runner_name, "runner", runner.human_name, icon, application=self.application)) self.add(SidebarRow(None, "platform", _("All"), None)) # what are the consequences of changing this to only use active platforms? # maybe the platform list is not automatically updated when a game from a # new platform is added? for platform in self.active_platforms: icon_name = (platform.lower().replace(" ", "").replace("/", "_") + "-symbolic") icon = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.MENU) self.add(SidebarRow(platform, "platform", platform, icon)) self.set_filter_func(self._filter_func) self.set_header_func(self._header_func) self.update() for row in self.get_children(): if row.type == row_type and row.id == row_id: self.select_row(row) break self.show_all()
def get_runner_entries(self, game): try: runner = runners.import_runner(game.runner_name)(game.config) except runners.InvalidRunner: return None return runner.context_menu_entries
def populate_runner_names(self): names = {} for runner in runners.__all__: runner_inst = runners.import_runner(runner) names[runner] = runner_inst.human_name return names
def add_runner(self, slug): name = runners.import_runner(slug).human_name icon = get_runner_icon(slug, format='pixbuf', size=(16, 16)) self.model.append(self.runner_node, ['runners', slug, icon, name])
def on_realize(self, widget): self.active_platforms = games_db.get_used_platforms() self.runners = sorted(runners.__all__) self.platforms = sorted(platforms.__all__) self.categories = categories_db.get_categories() self.add( SidebarRow( "all", "category", _("Games"), Gtk.Image.new_from_icon_name("applications-games-symbolic", Gtk.IconSize.MENU))) self.add( SidebarRow( "recent", "dynamic_category", _("Recent"), Gtk.Image.new_from_icon_name("document-open-recent-symbolic", Gtk.IconSize.MENU))) self.add( SidebarRow( "favorite", "category", _("Favorites"), Gtk.Image.new_from_icon_name("favorite-symbolic", Gtk.IconSize.MENU))) self.running_row = SidebarRow( "running", "dynamic_category", _("Running"), Gtk.Image.new_from_icon_name("media-playback-start-symbolic", Gtk.IconSize.MENU)) # I wanted this to be on top but it really messes with the headers when showing/hiding the row. self.add(self.running_row) service_classes = services.get_services() for service_name in service_classes: service = service_classes[service_name]() row_class = OnlineServiceSidebarRow if service.online else ServiceSidebarRow service_row = row_class(service) self.service_rows[service_name] = service_row self.add(service_row) for runner_name in self.runners: icon_name = runner_name.lower().replace(" ", "") + "-symbolic" icon = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.MENU) runner = runners.import_runner(runner_name)() self.add( RunnerSidebarRow(runner_name, "runner", runner.human_name, icon, application=self.application)) for platform in self.platforms: icon_name = (platform.lower().replace(" ", "").replace("/", "_") + "-symbolic") icon = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.MENU) self.add(SidebarRow(platform, "platform", platform, icon)) self.update() for row in self.get_children(): if row.type == self.selected_row_type and row.id == self.selected_row_id: self.select_row(row) break self.show_all() self.running_row.hide()
def __init__(self, pga_data): self._pga_data = pga_data self.runner_names = { runner: runners.import_runner(runner).human_name for runner in runners.__all__ }
def popup(self, event, game_row=None, game=None): if game_row: game_id = game_row[COL_ID] game_slug = game_row[COL_SLUG] runner_slug = game_row[COL_RUNNER] is_installed = game_row[COL_INSTALLED] elif game: game_id = game['id'] game_slug = game['slug'] runner_slug = game['runner'] is_installed = game['installed'] # Clear existing menu for item in self.get_children(): self.remove(item) # Main items self.add_menuitems(self.main_entries) # Runner specific items runner_entries = None if runner_slug: game = Game(game_id) try: runner = import_runner(runner_slug)(game.config) except InvalidRunner: runner_entries = None else: runner_entries = runner.context_menu_entries if runner_entries: self.append(Gtk.SeparatorMenuItem()) self.add_menuitems(runner_entries) self.show_all() # Hide some items hiding_condition = { 'add': is_installed, 'install': is_installed, 'install_more': not is_installed, 'play': not is_installed, 'configure': not is_installed, 'desktop-shortcut': (not is_installed or desktop_launcher_exists(game_slug, game_id)), 'menu-shortcut': (not is_installed or menu_launcher_exists(game_slug, game_id)), 'rm-desktop-shortcut': (not is_installed or not desktop_launcher_exists(game_slug, game_id)), 'rm-menu-shortcut': (not is_installed or not menu_launcher_exists(game_slug, game_id)), 'browse': not is_installed or runner_slug == 'browser', } for menuitem in self.get_children(): if type(menuitem) is not Gtk.ImageMenuItem: continue action = menuitem.action_id visible = not hiding_condition.get(action) menuitem.set_visible(visible) super(ContextualMenu, self).popup(None, None, None, None, event.button, event.time)
def test_import_module(self): for runner_name in runners.__all__: runner_class = runners.import_runner(runner_name) self.assertEqual(runner_class().__class__.__name__, runner_name)
def _init_platforms(): for runner_name in runners.__all__: runner = runners.import_runner(runner_name)() for platform in runner.platforms: __all__[platform].append(runner_name)
def create_prefix( prefix, wine_path=None, arch=WINE_DEFAULT_ARCH, overrides={}, install_gecko=None, install_mono=None, ): """Create a new Wine prefix.""" if not prefix: raise ValueError("No Wine prefix path given") logger.info("Creating a %s prefix in %s", arch, prefix) # Follow symlinks, don't delete existing ones as it would break some setups if os.path.islink(prefix): prefix = os.readlink(prefix) # Avoid issue of 64bit Wine refusing to create win32 prefix # over an existing empty folder. if os.path.isdir(prefix) and not os.listdir(prefix): os.rmdir(prefix) if not wine_path: wine = import_runner("wine") wine_path = wine().get_executable() if not wine_path: logger.error("Wine not found, can't create prefix") return wineboot_path = os.path.join(os.path.dirname(wine_path), "wineboot") if not system.path_exists(wineboot_path): logger.error( "No wineboot executable found in %s, " "your wine installation is most likely broken", wine_path, ) return if install_gecko == "False": overrides["mshtml"] = "disabled" if install_mono == "False": overrides["mscoree"] = "disabled" wineenv = { "WINEARCH": arch, "WINEPREFIX": prefix, "WINEDLLOVERRIDES": get_overrides_env(overrides), } system.execute([wineboot_path], env=wineenv) for loop_index in range(50): time.sleep(0.25) if system.path_exists(os.path.join(prefix, "user.reg")): break if loop_index == 20: logger.warning("Wine prefix creation is taking longer than expected...") if not os.path.exists(os.path.join(prefix, "user.reg")): logger.error( "No user.reg found after prefix creation. " "Prefix might not be valid" ) return logger.info("%s Prefix created in %s", arch, prefix) prefix_manager = WinePrefixManager(prefix) prefix_manager.setup_defaults() if 'steamapps/common' in prefix.lower(): from lutris.runners.winesteam import winesteam runner = winesteam() logger.info("Transfering Steam information from default prefix to new prefix") dest_path = '/tmp/steam.reg' default_prefix = runner.get_default_prefix(runner.default_arch) wineexec( "regedit", args=r"/E '%s' 'HKEY_CURRENT_USER\Software\Valve\Steam'" % dest_path, prefix=default_prefix ) set_regedit_file( dest_path, wine_path=wine_path, prefix=prefix, arch=arch ) try: os.remove(dest_path) except FileNotFoundError: logger.error("File %s was already removed", dest_path) steam_drive_path = os.path.join(prefix, 'dosdevices', 's:') if not system.path_exists(steam_drive_path): logger.info("Linking Steam default prefix to drive S:") os.symlink(os.path.join(default_prefix, 'drive_c'), steam_drive_path)
def wineexec( executable, args="", wine_path=None, prefix=None, arch=None, # pylint: disable=too-many-locals working_dir=None, winetricks_wine="", blocking=False, config=None, include_processes=[], exclude_processes=[], disable_runtime=False, env={}, overrides=None, ): """ Execute a Wine command. Args: executable (str): wine program to run, pass None to run wine itself args (str): program arguments wine_path (str): path to the wine version to use prefix (str): path to the wine prefix to use arch (str): wine architecture of the prefix working_dir (str): path to the working dir for the process winetricks_wine (str): path to the wine version used by winetricks blocking (bool): if true, do not run the process in a thread config (LutrisConfig): LutrisConfig object for the process context watch (list): list of process names to monitor (even when in a ignore list) Returns: Process results if the process is running in blocking mode or MonitoredCommand instance otherwise. """ executable = str(executable) if executable else "" if isinstance(include_processes, str): include_processes = shlex.split(include_processes) if isinstance(exclude_processes, str): exclude_processes = shlex.split(exclude_processes) if not wine_path: wine = import_runner("wine") wine_path = wine().get_executable() if not wine_path: raise RuntimeError("Wine is not installed") if not working_dir: if os.path.isfile(executable): working_dir = os.path.dirname(executable) executable, _args, working_dir = get_real_executable(executable, working_dir) if _args: args = '{} "{}"'.format(_args[0], _args[1]) # Create prefix if necessary if arch not in ("win32", "win64"): arch = detect_arch(prefix, wine_path) if not detect_prefix_arch(prefix): wine_bin = winetricks_wine if winetricks_wine else wine_path create_prefix(prefix, wine_path=wine_bin, arch=arch) wineenv = {"WINEARCH": arch} if winetricks_wine: wineenv["WINE"] = winetricks_wine else: wineenv["WINE"] = wine_path if prefix: wineenv["WINEPREFIX"] = prefix wine_config = config or LutrisConfig(runner_slug="wine") disable_runtime = disable_runtime or wine_config.system_config["disable_runtime"] if use_lutris_runtime(wine_path=wineenv["WINE"], force_disable=disable_runtime): if WINE_DIR in wine_path: wine_root_path = os.path.dirname(os.path.dirname(wine_path)) elif WINE_DIR in winetricks_wine: wine_root_path = os.path.dirname(os.path.dirname(winetricks_wine)) else: wine_root_path = None wineenv["LD_LIBRARY_PATH"] = ":".join( runtime.get_paths( prefer_system_libs=wine_config.system_config["prefer_system_libs"], wine_path=wine_root_path, ) ) if overrides: wineenv["WINEDLLOVERRIDES"] = get_overrides_env(overrides) wineenv.update(env) command_parameters = [wine_path] if executable: command_parameters.append(executable) command_parameters += split_arguments(args) if blocking: return system.execute(command_parameters, env=wineenv, cwd=working_dir) wine = import_runner("wine") command = MonitoredCommand( command_parameters, runner=wine(), env=wineenv, cwd=working_dir, include_processes=include_processes, exclude_processes=exclude_processes, ) command.start() return command