Ejemplo n.º 1
0
Archivo: wine.py Proyecto: Freso/lutris
def create_prefix(prefix, wine_path=None, arch='win32'):
    """Create a new Wine prefix."""
    logger.debug("Creating a %s prefix in %s", arch, 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_path = wine().get_executable()

    wineboot_path = os.path.join(os.path.dirname(wine_path), 'wineboot')

    env = {
        'WINEARCH': arch,
        'WINEPREFIX': prefix
    }
    system.execute([wineboot_path], env=env)
    for i in range(20):
        time.sleep(.25)
        if os.path.exists(os.path.join(prefix, 'user.reg')):
            break
    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')
    logger.info('%s Prefix created in %s', arch, prefix)
    prefix_manager = WinePrefixManager(prefix)
    prefix_manager.setup_defaults()
Ejemplo n.º 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 {}".format(run_with))
    working_dir = system.create_folder(working_dir)
    dosbox_runner = dosbox()
    command = [dosbox_runner.get_executable()]
    if config_file:
        command += ['-conf', config_file]
    if executable:
        if not os.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)
Ejemplo n.º 3
0
 def install_game(self, appid, generate_acf=False):
     if not appid:
         raise ValueError("Missing appid in winesteam.install_game")
     system.execute(
         self.launch_args + ["steam://install/%s" % appid],
         env=self.get_env()
     )
Ejemplo n.º 4
0
 def validate_game(self, appid):
     if not appid:
         raise ValueError("Missing appid in winesteam.validate_game")
     system.execute(
         self.launch_args + ["steam://validate/%s" % appid],
         env=self.get_env()
     )
Ejemplo n.º 5
0
 def install_game(self, appid, generate_acf=False):
     """Install a game with Steam"""
     if not appid:
         raise ValueError("Missing appid in winesteam.install_game")
     system.execute(
         self.launch_args + ["steam://install/%s" % appid], env=self.get_env()
     )
Ejemplo n.º 6
0
 def validate_game(self, appid):
     """Validate game files with Steam"""
     if not appid:
         raise ValueError("Missing appid in winesteam.validate_game")
     system.execute(
         self.launch_args + ["steam://validate/%s" % appid], env=self.get_env()
     )
Ejemplo n.º 7
0
def get_compositor_commands():
    """Nominated for the worst function in lutris"""
    start_compositor = None
    stop_compositor = None
    desktop_session = os.environ.get("DESKTOP_SESSION")
    if desktop_session == "plasma":
        stop_compositor = ("qdbus org.kde.KWin /Compositor org.kde.kwin.Compositing.suspend")
        start_compositor = ("qdbus org.kde.KWin /Compositor org.kde.kwin.Compositing.resume")
    elif (
        desktop_session == "mate"
        and system.execute("gsettings get org.mate.Marco.general compositing-manager", shell=True) == "true"
    ):
        stop_compositor = ("gsettings set org.mate.Marco.general compositing-manager false")
        start_compositor = ("gsettings set org.mate.Marco.general compositing-manager true")
    elif (
        desktop_session == "xfce" and system.execute(
            "xfconf-query --channel=xfwm4 --property=/general/use_compositing",
            shell=True,
        ) == "true"
    ):
        stop_compositor = ("xfconf-query --channel=xfwm4 --property=/general/use_compositing --set=false")
        start_compositor = ("xfconf-query --channel=xfwm4 --property=/general/use_compositing --set=true")
    elif (
        desktop_session == "deepin" and system.execute(
            "dbus-send --session --dest=com.deepin.WMSwitcher --type=method_call "
            "--print-reply=literal /com/deepin/WMSwitcher com.deepin.WMSwitcher.CurrentWM",
            shell=True,
        ) == "deepin wm"
    ):
        start_compositor, stop_compositor = (
            "dbus-send --session --dest=com.deepin.WMSwitcher --type=method_call "
            "/com/deepin/WMSwitcher com.deepin.WMSwitcher.RequestSwitchWM",
        ) * 2
    return start_compositor, stop_compositor
Ejemplo n.º 8
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 {}".format(run_with))
    working_dir = system.create_folder(working_dir)
    dosbox_runner = dosbox()
    command = [dosbox_runner.get_executable()]
    if config_file:
        command += ['-conf', config_file]
    if executable:
        if not os.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)
Ejemplo n.º 9
0
def create_prefix(prefix, wine_path=None, arch='win32'):
    """Create a new Wine prefix."""
    logger.debug("Creating a %s prefix in %s", arch, 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_path = wine().get_executable()

    wineboot_path = os.path.join(os.path.dirname(wine_path), 'wineboot')

    env = {
        'WINEARCH': arch,
        'WINEPREFIX': prefix
    }
    system.execute([wineboot_path], env=env)
    for i in range(20):
        time.sleep(.25)
        if os.path.exists(os.path.join(prefix, 'user.reg')):
            break
    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')
    logger.info('%s Prefix created in %s', arch, prefix)
    prefix_manager = WinePrefixManager(prefix)
    prefix_manager.setup_defaults()
Ejemplo n.º 10
0
def open_uri(uri):
    """Opens a local or remote URI with the default application"""
    system.reset_library_preloads()
    try:
        Gtk.show_uri(None, uri, Gdk.CURRENT_TIME)
    except GLib.Error as ex:
        logger.exception("Failed to open URI %s: %s, falling back to xdg-open", uri, ex)
        system.execute(["xdg-open", uri])
Ejemplo n.º 11
0
 def set_desktop_compositing(self, enable):
     if enable:
         system.execute(self.start_compositor, shell=True)
     else:
         self.start_compositor, self.stop_compositor = display.get_compositor_commands()
         if not (self.compositor_disabled or not self.stop_compositor):
             system.execute(self.stop_compositor, shell=True)
             self.compositor_disabled = True
Ejemplo n.º 12
0
 def stop(self):
     """The kill command runs wineserver -k."""
     wine_path = self.get_executable()
     wine_root = os.path.dirname(wine_path)
     command = os.path.join(wine_root, "wineserver") + " -k"
     if self.prefix_path:
         command = "WINEPREFIX=%s %s" % (self.prefix_path, command)
     logger.debug("Killing all wine processes: %s" % command)
     system.execute(command, shell=True)
Ejemplo n.º 13
0
def reset_pulse():
    """Reset pulseaudio."""
    if not system.find_executable("pulseaudio"):
        logger.warning("PulseAudio not installed. Nothing to do.")
        return
    system.execute(["pulseaudio", "--kill"])
    time.sleep(1)
    system.execute(["pulseaudio", "--start"])
    logger.debug("PulseAudio restarted")
Ejemplo n.º 14
0
 def stop(self):
     """The kill command runs wineserver -k."""
     wine_path = self.get_executable()
     wine_root = os.path.dirname(wine_path)
     command = os.path.join(wine_root, "wineserver") + " -k"
     if self.prefix_path:
         command = "WINEPREFIX=%s %s" % (self.prefix_path, command)
     logger.debug("Killing all wine processes: %s" % command)
     system.execute(command, shell=True)
Ejemplo n.º 15
0
def open_wine_terminal(terminal, wine_path, prefix, env):
    aliases = {
        "wine": wine_path,
        "winecfg": wine_path + "cfg",
        "wineserver": wine_path + "server",
        "wineboot": wine_path + "boot",
    }
    env["WINEPREFIX"] = prefix
    shell_command = get_shell_command(prefix, env, aliases)
    terminal = terminal or linux.get_default_terminal()
    system.execute([linux.get_default_terminal(), "-e", shell_command])
Ejemplo n.º 16
0
 def set_desktop_compositing(self, enable):
     """Enables or disables compositing"""
     if enable:
         system.execute(self.start_compositor, shell=True)
     else:
         self.start_compositor, self.stop_compositor = (
             display.get_compositor_commands()
         )
         if not (self.compositor_disabled or not self.stop_compositor):
             system.execute(self.stop_compositor, shell=True)
             self.compositor_disabled = True
Ejemplo n.º 17
0
    def extract_from_cab(self, cabfile, component):
        """Extracts files matching a `component` name from a `cabfile`

        Params:
            cabfile (str): Path to a cabfile to extract from
            component (str): component to extract from the cab file

        Returns:
            list: Files extracted from the cab file
        """
        execute(["cabextract", "-F", "*%s*" % component, "-d", self.tmpdir, cabfile])
        return [os.path.join(r, file) for r, d, f in os.walk(self.tmpdir) for file in f]
Ejemplo n.º 18
0
def create_prefix(prefix,
                  wine_path=None,
                  arch='win32',
                  overrides={},
                  install_gecko=None,
                  install_mono=None):
    """Create a new Wine prefix."""
    logger.debug("Creating a %s prefix in %s", arch, 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(.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()
Ejemplo n.º 19
0
def shutdown():
    """ Shutdown Steam in a clean way.
        TODO: Detect wine binary
    """
    pid = system.get_pid('Steam.exe')
    if not pid:
        return False
    cwd = system.get_cwd(pid)
    cmdline = system.get_command_line(pid)
    steam_exe = os.path.join(cwd, cmdline)
    logger.debug("Shutting winesteam: %s", steam_exe)
    system.execute(['wine', steam_exe, '-shutdown'])
Ejemplo n.º 20
0
def shutdown():
    """ Shutdown Steam in a clean way.
        TODO: Detect wine binary
    """
    pid = system.get_pid('Steam.exe$')
    if not pid:
        return False
    cwd = system.get_cwd(pid)
    cmdline = system.get_command_line(pid)
    steam_exe = os.path.join(cwd, cmdline)
    logger.debug("Shutting winesteam: %s", steam_exe)
    system.execute(['wine', steam_exe, '-shutdown'])
Ejemplo n.º 21
0
 def set_desktop_compositing(self, enable):
     """Enables or disables compositing"""
     if enable:
         system.execute(self.start_compositor, shell=True)
     else:
         (
             self.start_compositor,
             self.stop_compositor,
         ) = get_compositor_commands()
         if not (self.compositor_disabled or not self.stop_compositor):
             system.execute(self.stop_compositor, shell=True)
             self.compositor_disabled = True
Ejemplo n.º 22
0
 def prelaunch(self):
     if not system.path_exists(os.path.join(self.config_dir, "mame.ini")):
         try:
             os.makedirs(self.config_dir)
         except OSError:
             pass
         system.execute(
             [self.get_executable(), "-createconfig", "-inipath", self.config_dir],
             env=runtime.get_env(),
             cwd=self.working_dir
         )
     return True
Ejemplo n.º 23
0
    def shutdown(self):
        """Shutdown Steam in a clean way."""
        pid = system.get_pid('Steam.exe$')
        if not pid:
            return False

        command = []
        command.append('WINEARCH=%s ' % self.wine_arch)
        command.append('WINEPREFIX="%s" ' % self.prefix_path)
        command += self.launch_args
        command.append('-shutdown')
        logger.debug("Shutting winesteam: %s", command)
        system.execute(' '.join(command), shell=True)
Ejemplo n.º 24
0
def get_compositor_commands():
    """Nominated for the worst function in lutris"""
    start_compositor = None
    stop_compositor = None
    desktop_session = os.environ.get('DESKTOP_SESSION')
    if desktop_session == "plasma":
        stop_compositor = "qdbus org.kde.KWin /Compositor org.kde.kwin.Compositing.suspend"
        start_compositor = "qdbus org.kde.KWin /Compositor org.kde.kwin.Compositing.resume"
    elif desktop_session == "mate" and system.execute("gsettings get org.mate.Marco.general compositing-manager", shell=True) == 'true':
        stop_compositor = "gsettings set org.mate.Marco.general compositing-manager false"
        start_compositor = "gsettings set org.mate.Marco.general compositing-manager true"
    elif desktop_session == "xfce" and system.execute("xfconf-query --channel=xfwm4 --property=/general/use_compositing", shell=True) == 'true':
        stop_compositor = "xfconf-query --channel=xfwm4 --property=/general/use_compositing --set=false"
        start_compositor = "xfconf-query --channel=xfwm4 --property=/general/use_compositing --set=true"
    return start_compositor, stop_compositor
Ejemplo n.º 25
0
 def cancel_installation(self, widget=None):
     """Ask a confirmation before cancelling the install"""
     confirm_cancel_dialog = QuestionDialog({
         "question": "Are you sure you want to cancel the installation?",
         "title": "Cancel installation?",
     })
     if confirm_cancel_dialog.result != Gtk.ResponseType.YES:
         logger.warning(
             "Attempting to terminate with the system wineserver. "
             "This is most likely to fail or to have no effect.")
         system.execute([system.find_executable("wineserver"), "-k9"])
         return True
     if self.interpreter:
         self.interpreter.revert()
         self.interpreter.cleanup()
     self.destroy()
Ejemplo n.º 26
0
def winekill(prefix,
             arch='win32',
             wine_path=None,
             env=None,
             initial_pids=None):
    """Kill processes in Wine prefix."""

    initial_pids = initial_pids or []
    for pid in initial_pids:
        logger.debug(Process(pid))

    if not wine_path:
        wine_path = wine().get_executable()
    wine_root = os.path.dirname(wine_path)
    if not env:
        env = {'WINEARCH': arch, 'WINEPREFIX': prefix}
    command = [os.path.join(wine_root, "wineserver"), "-k"]

    logger.debug("Killing all wine processes: %s" % command)
    logger.debug("\tWine prefix: %s", prefix)
    logger.debug("\tWine arch: %s", arch)
    logger.debug("\tInitial pids: %s", initial_pids)

    system.execute(command, env=env, quiet=True)

    logger.debug("Waiting for wine processes to terminate")
    # Wineserver needs time to terminate processes
    num_cycles = 0
    while True:
        num_cycles += 1
        running_processes = [
            pid for pid in initial_pids if os.path.exists("/proc/%s" % pid)
        ]
        logger.debug("running_processes: %s, cycles: %s", running_processes,
                     num_cycles)

        for pid in running_processes:
            logger.debug(Process(pid))

        if not running_processes:
            logger.debug("Done in %s cycles", num_cycles)
            break
        if num_cycles > 300:
            logger.warning("Some wine processes are still running: %s",
                           ', '.join(running_processes))
            break
        time.sleep(0.1)
Ejemplo n.º 27
0
 def write_xml_list(self):
     """Write the full game list in XML to disk"""
     if not os.path.exists(self.cache_dir):
         os.makedirs(self.cache_dir)
     with open(self.xml_path, "w") as xml_file:
         output = system.execute([self.get_executable(), "-listxml"])
         xml_file.write(output)
         logger.info("MAME XML list written to %s", self.xml_path)
Ejemplo n.º 28
0
 def cancel_installation(self, widget=None):
     """Ask a confirmation before cancelling the install"""
     confirm_cancel_dialog = QuestionDialog(
         {
             "question": "Are you sure you want to cancel the installation?",
             "title": "Cancel installation?",
         }
     )
     if confirm_cancel_dialog.result != Gtk.ResponseType.YES:
         logger.warning("Attempting to terminate with the system wineserver. "
                        "This is most likely to fail or to have no effect.")
         system.execute([system.find_executable("wineserver"), "-k9"])
         return True
     if self.interpreter:
         self.interpreter.revert()
         self.interpreter.cleanup()
     self.destroy()
Ejemplo n.º 29
0
def winekill(prefix,
             arch=WINE_DEFAULT_ARCH,
             wine_path=None,
             env=None,
             initial_pids=None):
    """Kill processes in Wine prefix."""

    initial_pids = initial_pids or []

    if not wine_path:
        wine = import_runner("wine")
        wine_path = wine().get_executable()
    wine_root = os.path.dirname(wine_path)
    if not env:
        env = {"WINEARCH": arch, "WINEPREFIX": prefix}
    command = [os.path.join(wine_root, "wineserver"), "-k"]

    logger.debug("Killing all wine processes: %s", command)
    logger.debug("\tWine prefix: %s", prefix)
    logger.debug("\tWine arch: %s", arch)
    if initial_pids:
        logger.debug("\tInitial pids: %s", initial_pids)

    system.execute(command, env=env, quiet=True)

    logger.debug("Waiting for wine processes to terminate")
    # Wineserver needs time to terminate processes
    num_cycles = 0
    while True:
        num_cycles += 1
        running_processes = [
            pid for pid in initial_pids if system.path_exists("/proc/%s" % pid)
        ]

        if not running_processes:
            break
        if num_cycles > 20:
            logger.warning(
                "Some wine processes are still running: %s",
                ", ".join(running_processes),
            )
            break
        time.sleep(0.1)
    logger.debug("Done waiting.")
Ejemplo n.º 30
0
def create_prefix(prefix, wine_path=None, arch='win32', overrides={},
                  install_gecko=None, install_mono=None):
    """Create a new Wine prefix."""
    logger.debug("Creating a %s prefix in %s", arch, 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_path = wine().get_executable()

    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 is 'False':
        overrides['mshtml'] = 'disabled'
    if install_mono is 'False':
        overrides['mscoree'] = 'disabled'

    wineenv = {
        'WINEARCH': arch,
        'WINEPREFIX': prefix,
        'WINEDLLOVERRIDES': get_overrides_env(overrides)
    }

    system.execute([wineboot_path], env=wineenv)
    for i in range(20):
        time.sleep(.25)
        if os.path.exists(os.path.join(prefix, 'user.reg')):
            break
    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()
Ejemplo n.º 31
0
def wineexec(executable,
             args="",
             wine_path=None,
             prefix=None,
             arch=None,
             working_dir=None,
             winetricks_wine='',
             blocking=False,
             config=None):
    """Execute a Wine command."""
    detected_arch = detect_prefix_arch(prefix)
    executable = str(executable) if executable else ''
    if arch not in ('win32', 'win64'):
        arch = detected_arch or 'win32'
    if not wine_path:
        wine_path = wine().get_executable()
    if not working_dir:
        if os.path.isfile(executable):
            working_dir = os.path.dirname(executable)

    if executable.endswith(".msi"):
        executable = 'msiexec /i "%s"' % executable
    elif executable:
        executable = '%s' % executable

    # Create prefix if necessary
    if not detected_arch:
        wine_bin = winetricks_wine if winetricks_wine else wine_path
        create_prefix(prefix, wine_path=wine_bin, arch=arch)

    env = {'WINEARCH': arch}
    if winetricks_wine:
        env['WINE'] = winetricks_wine
    else:
        env['WINE'] = wine_path
    if prefix:
        env['WINEPREFIX'] = prefix

    wine_config = config or LutrisConfig(runner_slug='wine')
    if not wine_config.system_config[
            'disable_runtime'] and not runtime.is_disabled():
        env['LD_LIBRARY_PATH'] = ':'.join(runtime.get_paths())

    command = [wine_path]
    if executable:
        command.append(executable)
    command += shlex.split(args)
    if blocking:
        return system.execute(command, env=env, cwd=working_dir)
    else:
        thread = LutrisThread(command, runner=wine(), env=env, cwd=working_dir)
        thread.start()
        return thread
Ejemplo n.º 32
0
 def write_xml_list(self):
     """Write the full game list in XML to disk"""
     if not os.path.exists(self.cache_dir):
         os.makedirs(self.cache_dir)
     output = system.execute([self.get_executable(), "-listxml"],
                             env=runtime.get_env())
     if output:
         with open(self.xml_path, "w") as xml_file:
             xml_file.write(output)
         logger.info("MAME XML list written to %s", self.xml_path)
     else:
         logger.warning("Couldn't get any output for mame -listxml")
Ejemplo n.º 33
0
def winekill(prefix, arch='win32', wine_path=None, env=None, initial_pids=None):
    """Kill processes in Wine prefix."""

    initial_pids = initial_pids or []

    if not wine_path:
        wine_path = wine().get_executable()
    wine_root = os.path.dirname(wine_path)
    if not env:
        env = {
            'WINEARCH': arch,
            'WINEPREFIX': prefix
        }
    command = [os.path.join(wine_root, "wineserver"), "-k"]

    logger.debug("Killing all wine processes: %s" % command)
    logger.debug("\tWine prefix: %s", prefix)
    logger.debug("\tWine arch: %s", arch)
    if initial_pids:
        logger.debug("\tInitial pids: %s", initial_pids)

    system.execute(command, env=env, quiet=True)

    logger.debug("Waiting for wine processes to terminate")
    # Wineserver needs time to terminate processes
    num_cycles = 0
    while True:
        num_cycles += 1
        running_processes = [
            pid for pid in initial_pids
            if os.path.exists("/proc/%s" % pid)
        ]

        if not running_processes:
            break
        if num_cycles > 20:
            logger.warning("Some wine processes are still running: %s",
                           ', '.join(running_processes))
            break
        time.sleep(0.1)
Ejemplo n.º 34
0
 def cancel_installation(self, widget=None):
     """Ask a confirmation before cancelling the install"""
     remove_checkbox = Gtk.CheckButton.new_with_label("Remove game files")
     if self.interpreter:
         remove_checkbox.set_active(self.interpreter.game_dir_created)
         remove_checkbox.show()
     confirm_cancel_dialog = QuestionDialog(
         {
             "question": "Are you sure you want to cancel the installation?",
             "title": "Cancel installation?",
             "widgets": [remove_checkbox]
         }
     )
     if confirm_cancel_dialog.result != Gtk.ResponseType.YES:
         logger.warning("Attempting to terminate with the system wineserver. "
                        "This is most likely to fail or to have no effect.")
         system.execute([system.find_executable("wineserver"), "-k9"])
         return True
     if self.interpreter:
         self.interpreter.game_dir_created = remove_checkbox.get_active()
         self.interpreter.revert()
         self.interpreter.cleanup()
     self.destroy()
Ejemplo n.º 35
0
def _get_graphics_adapters():
    """Return the list of graphics cards available on a system

    Returns:
        list: list of tuples containing PCI ID and description of the VGA adapter
    """
    lspci_path = system.find_executable("lspci")
    if not lspci_path:
        logger.warning(
            "lspci is not available. List of graphics cards not available")
        return []
    return [(pci_id, vga_desc.split(": ")[1]) for pci_id, vga_desc in [
        line.split(maxsplit=1)
        for line in system.execute(lspci_path).split("\n") if "VGA" in line
    ]]
Ejemplo n.º 36
0
Archivo: wine.py Proyecto: Freso/lutris
def wineexec(executable, args="", wine_path=None, prefix=None, arch=None,
             working_dir=None, winetricks_wine='', blocking=False):
    """Execute a Wine command."""
    detected_arch = detect_prefix_arch(prefix)
    executable = str(executable) if executable else ''
    if arch not in ('win32', 'win64'):
        arch = detected_arch or 'win32'
    if not wine_path:
        wine_path = wine().get_executable()
    if not working_dir:
        if os.path.isfile(executable):
            working_dir = os.path.dirname(executable)

    if executable.endswith(".msi"):
        executable = 'msiexec /i "%s"' % executable
    elif executable:
        executable = '%s' % executable

    # Create prefix if necessary
    if not detected_arch:
        wine_bin = winetricks_wine if winetricks_wine else wine_path
        create_prefix(prefix, wine_path=wine_bin, arch=arch)

    env = {
        'WINEARCH': arch
    }
    if winetricks_wine:
        env['WINE'] = winetricks_wine
    else:
        env['WINE'] = wine_path
    if prefix:
        env['WINEPREFIX'] = prefix

    wine_config = LutrisConfig(runner_slug='wine')
    if not wine_config.system_config['disable_runtime'] and not runtime.is_disabled():
        env['LD_LIBRARY_PATH'] = ':'.join(runtime.get_paths())

    command = [wine_path]
    if executable:
        command.append(executable)
    command += shlex.split(args)
    if blocking:
        return system.execute(command, env=env, cwd=working_dir)
    else:
        thread = LutrisThread(command, runner=wine(), env=env, cwd=working_dir)
        thread.start()
        return thread
Ejemplo n.º 37
0
def _get_graphics_adapters():
    """Return the list of graphics cards available on a system

    Returns:
        list: list of tuples containing PCI ID and description of the display controller
    """
    lspci_path = system.find_executable("lspci")
    dev_subclasses = ["VGA", "XGA", "3D controller", "Display controller"]
    if not lspci_path:
        logger.warning(
            "lspci is not available. List of graphics cards not available")
        return []
    return [(pci_id, device_desc.split(": ")[1]) for pci_id, device_desc in [
        line.split(maxsplit=1)
        for line in system.execute(lspci_path, timeout=3).split("\n")
        if any(subclass in line for subclass in dev_subclasses)
    ]]
Ejemplo n.º 38
0
    def desktop_effects(self, enable):
        if enable:
            system.execute(self.start_compositor, shell=True)
        else:
            if os.environ.get('DESKTOP_SESSION') == "plasma":
                self.stop_compositor = "qdbus org.kde.KWin /Compositor org.kde.kwin.Compositing.suspend"
                self.start_compositor = "qdbus org.kde.KWin /Compositor org.kde.kwin.Compositing.resume"
            elif os.environ.get('DESKTOP_SESSION') == "mate" and system.execute("gsettings get org.mate.Marco.general compositing-manager", shell=True) == 'true':
                self.stop_compositor = "gsettings set org.mate.Marco.general compositing-manager false"
                self.start_compositor = "gsettings set org.mate.Marco.general compositing-manager true"
            elif os.environ.get('DESKTOP_SESSION') == "xfce" and system.execute("xfconf-query --channel=xfwm4 --property=/general/use_compositing", shell=True) == 'true':
                self.stop_compositor = "xfconf-query --channel=xfwm4 --property=/general/use_compositing --set=false"
                self.start_compositor = "xfconf-query --channel=xfwm4 --property=/general/use_compositing --set=true"

            if not (self.compositor_disabled or self.stop_compositor == ""):
                system.execute(self.stop_compositor, shell=True)
                self.compositor_disabled = True;
Ejemplo n.º 39
0
def wineexec(executable, args="", wine_path=None, prefix=None, arch=None,
             working_dir=None, winetricks_wine='', blocking=False,
             config=None, include_processes=[]):
    """
    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
        LutrisThread instance otherwise.
    """
    detected_arch = detect_prefix_arch(prefix)
    executable = str(executable) if executable else ''
    if arch not in ('win32', 'win64'):
        arch = detected_arch or 'win32'
    if not wine_path:
        wine_path = wine().get_executable()
    if not working_dir:
        if os.path.isfile(executable):
            working_dir = os.path.dirname(executable)

    if executable.endswith(".msi"):
        args = '/i "%s"' % executable
        executable = 'msiexec'

    # Create prefix if necessary
    if not detected_arch:
        wine_bin = winetricks_wine if winetricks_wine else wine_path
        create_prefix(prefix, wine_path=wine_bin, arch=arch)

    env = {
        'WINEARCH': arch
    }
    if winetricks_wine:
        env['WINE'] = winetricks_wine
    else:
        env['WINE'] = wine_path
    if prefix:
        env['WINEPREFIX'] = prefix

    wine_config = config or LutrisConfig(runner_slug='wine')
    if not wine_config.system_config['disable_runtime'] and not runtime.is_disabled():
        env['LD_LIBRARY_PATH'] = ':'.join(runtime.get_paths())

    command = [wine_path]
    if executable:
        command.append(executable)
    command += shlex.split(args)
    if blocking:
        return system.execute(command, env=env, cwd=working_dir)
    else:
        thread = LutrisThread(command, runner=wine(), env=env, cwd=working_dir,
                              include_processes=include_processes)
        thread.start()
        return thread
Ejemplo n.º 40
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 += shlex.split(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
Ejemplo n.º 41
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)
Ejemplo n.º 42
0
def wineexec(executable, args="", wine_path=None, prefix=None, arch=None,
             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
        LutrisThread instance otherwise.
    """
    executable = str(executable) if executable else ''
    if not wine_path:
        wine_path = wine().get_executable()
    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
    detected_arch = detect_prefix_arch(prefix)
    if arch not in ('win32', 'win64'):
        arch = detected_arch or 'win32'
    if not detected_arch:
        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')
    if (
            not runtime.RUNTIME_DISABLED and
            not disable_runtime and
            not wine_config.system_config['disable_runtime']
    ):
        wineenv['LD_LIBRARY_PATH'] = ':'.join(runtime.get_paths())

    if overrides:
        wineenv['WINEDLLOVERRIDES'] = get_overrides_env(overrides)

    wineenv.update(env)

    command = [wine_path]
    if executable:
        command.append(executable)
    command += shlex.split(args)
    if blocking:
        return system.execute(command, env=wineenv, cwd=working_dir)
    else:
        thread = LutrisThread(command, runner=wine(), env=wineenv, cwd=working_dir,
                              include_processes=include_processes,
                              exclude_processes=exclude_processes)
        thread.start()
        return thread
Ejemplo n.º 43
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
        LutrisThread instance otherwise.
    """
    executable = str(executable) if executable else ''
    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 = [wine_path]
    if executable:
        command.append(executable)
    command += shlex.split(args)
    if blocking:
        return system.execute(command, env=wineenv, cwd=working_dir)
    wine = import_runner('wine')
    thread = LutrisThread(command,
                          runner=wine(),
                          env=wineenv,
                          cwd=working_dir,
                          include_processes=include_processes,
                          exclude_processes=exclude_processes)
    thread.start()
    return thread
Ejemplo n.º 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)
Ejemplo n.º 45
0
def wineexec(executable, args="", wine_path=None, prefix=None, arch=None,
             working_dir=None, winetricks_wine='', blocking=False,
             config=None, include_processes=[]):
    """
    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
        LutrisThread instance otherwise.
    """
    detected_arch = detect_prefix_arch(prefix)
    executable = str(executable) if executable else ''
    if arch not in ('win32', 'win64'):
        arch = detected_arch or 'win32'
    if not wine_path:
        wine_path = wine().get_executable()
    if not working_dir:
        if os.path.isfile(executable):
            working_dir = os.path.dirname(executable)

    executable, _args = get_real_executable(executable)
    if _args:
        args = '{} "{}"'.format(_args[0], _args[1])

    # Create prefix if necessary
    if not detected_arch:
        wine_bin = winetricks_wine if winetricks_wine else wine_path
        create_prefix(prefix, wine_path=wine_bin, arch=arch)

    env = {
        'WINEARCH': arch
    }
    if winetricks_wine:
        env['WINE'] = winetricks_wine
    else:
        env['WINE'] = wine_path
    if prefix:
        env['WINEPREFIX'] = prefix

    wine_config = config or LutrisConfig(runner_slug='wine')
    if not wine_config.system_config['disable_runtime'] and not runtime.is_disabled():
        env['LD_LIBRARY_PATH'] = ':'.join(runtime.get_paths())

    command = [wine_path]
    if executable:
        command.append(executable)
    command += shlex.split(args)
    if blocking:
        return system.execute(command, env=env, cwd=working_dir)
    else:
        thread = LutrisThread(command, runner=wine(), env=env, cwd=working_dir,
                              include_processes=include_processes)
        thread.start()
        return thread