Example #1
0
 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)
Example #2
0
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)
Example #3
0
    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
Example #4
0
    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)
Example #5
0
    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()
Example #6
0
    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)
Example #7
0
    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()
Example #8
0
 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
Example #9
0
 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
Example #10
0
 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__
     }
Example #11
0
    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()
Example #12
0
    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()
Example #13
0
 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
         )
Example #14
0
 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)
Example #15
0
 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)
Example #16
0
    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
Example #17
0
 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")
Example #18
0
 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')
Example #19
0
    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)
Example #20
0
 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')
Example #21
0
 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()
Example #22
0
    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)
Example #23
0
    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')
Example #24
0
 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()
Example #25
0
 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)
Example #26
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
Example #27
0
    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')
Example #28
0
 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")
Example #29
0
File: game.py Project: ERIIX/lutris
 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)
Example #30
0
    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)
Example #31
0
    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()
Example #32
0
    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
Example #33
0
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()
Example #34
0
    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()
Example #35
0
    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()
Example #36
0
 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
Example #37
0
 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
Example #38
0
 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])
Example #39
0
    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()
Example #40
0
 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__
     }
Example #41
0
    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)
Example #42
0
 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)
Example #43
0
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)
Example #44
0
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)
Example #45
0
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