|  | #!/usr/bin/env python | 
|  | # -*- coding: utf-8 -*- | 
|  |  | 
|  | """Utility for opening a file using the default application in a cross-platform | 
|  | manner. Modified from http://code.activestate.com/recipes/511443/. | 
|  | """ | 
|  |  | 
|  | __version__ = "1.1x" | 
|  | __all__ = ["open"] | 
|  |  | 
|  | import os | 
|  | import sys | 
|  | import webbrowser | 
|  | import subprocess | 
|  |  | 
|  | _controllers = {} | 
|  | _open = None | 
|  |  | 
|  |  | 
|  | class BaseController(object): | 
|  | """Base class for open program controllers.""" | 
|  |  | 
|  | def __init__(self, name): | 
|  | self.name = name | 
|  |  | 
|  | def open(self, filename): | 
|  | raise NotImplementedError | 
|  |  | 
|  |  | 
|  | class Controller(BaseController): | 
|  | """Controller for a generic open program.""" | 
|  |  | 
|  | def __init__(self, *args): | 
|  | super(Controller, self).__init__(os.path.basename(args[0])) | 
|  | self.args = list(args) | 
|  |  | 
|  | def _invoke(self, cmdline): | 
|  | if sys.platform[:3] == "win": | 
|  | closefds = False | 
|  | startupinfo = subprocess.STARTUPINFO() | 
|  | startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW | 
|  | else: | 
|  | closefds = True | 
|  | startupinfo = None | 
|  |  | 
|  | if ( | 
|  | os.environ.get("DISPLAY") | 
|  | or sys.platform[:3] == "win" | 
|  | or sys.platform == "darwin" | 
|  | ): | 
|  | inout = subprocess.DEVNULL | 
|  | else: | 
|  | # for TTY programs, we need stdin/out | 
|  | inout = None | 
|  |  | 
|  | # if possible, put the child precess in separate process group, | 
|  | # so keyboard interrupts don't affect child precess as well as | 
|  | # Python | 
|  | setsid = getattr(os, "setsid", None) | 
|  | if not setsid: | 
|  | setsid = getattr(os, "setpgrp", None) | 
|  |  | 
|  | pipe = subprocess.Popen( | 
|  | cmdline, | 
|  | stdin=inout, | 
|  | stdout=inout, | 
|  | stderr=inout, | 
|  | close_fds=closefds, | 
|  | preexec_fn=setsid, | 
|  | startupinfo=startupinfo, | 
|  | ) | 
|  |  | 
|  | # It is assumed that this kind of tools (gnome-open, kfmclient, | 
|  | # exo-open, xdg-open and open for OSX) immediately exit after launching | 
|  | # the specific application | 
|  | returncode = pipe.wait() | 
|  | if hasattr(self, "fixreturncode"): | 
|  | returncode = self.fixreturncode(returncode) | 
|  | return not returncode | 
|  |  | 
|  | def open(self, filename): | 
|  | if isinstance(filename, basestring): | 
|  | cmdline = self.args + [filename] | 
|  | else: | 
|  | # assume it is a sequence | 
|  | cmdline = self.args + filename | 
|  | try: | 
|  | return self._invoke(cmdline) | 
|  | except OSError: | 
|  | return False | 
|  |  | 
|  |  | 
|  | # Platform support for Windows | 
|  | if sys.platform[:3] == "win": | 
|  |  | 
|  | class Start(BaseController): | 
|  | """Controller for the win32 start program through os.startfile.""" | 
|  |  | 
|  | def open(self, filename): | 
|  | try: | 
|  | os.startfile(filename) | 
|  | except WindowsError: | 
|  | # [Error 22] No application is associated with the specified | 
|  | # file for this operation: '<URL>' | 
|  | return False | 
|  | else: | 
|  | return True | 
|  |  | 
|  | _controllers["windows-default"] = Start("start") | 
|  | _open = _controllers["windows-default"].open | 
|  |  | 
|  |  | 
|  | # Platform support for MacOS | 
|  | elif sys.platform == "darwin": | 
|  | _controllers["open"] = Controller("open") | 
|  | _open = _controllers["open"].open | 
|  |  | 
|  |  | 
|  | # Platform support for Unix | 
|  | else: | 
|  |  | 
|  | try: | 
|  | from commands import getoutput | 
|  | except ImportError: | 
|  | from subprocess import getoutput | 
|  |  | 
|  | # @WARNING: use the private API of the webbrowser module | 
|  | from webbrowser import _iscommand | 
|  |  | 
|  | class KfmClient(Controller): | 
|  | """Controller for the KDE kfmclient program.""" | 
|  |  | 
|  | def __init__(self, kfmclient="kfmclient"): | 
|  | super(KfmClient, self).__init__(kfmclient, "exec") | 
|  | self.kde_version = self.detect_kde_version() | 
|  |  | 
|  | def detect_kde_version(self): | 
|  | kde_version = None | 
|  | try: | 
|  | info = getoutput("kde-config --version") | 
|  |  | 
|  | for line in info.splitlines(): | 
|  | if line.startswith("KDE"): | 
|  | kde_version = line.split(":")[-1].strip() | 
|  | break | 
|  | except (OSError, RuntimeError): | 
|  | pass | 
|  |  | 
|  | return kde_version | 
|  |  | 
|  | def fixreturncode(self, returncode): | 
|  | if returncode is not None and self.kde_version > "3.5.4": | 
|  | return returncode | 
|  | else: | 
|  | return os.EX_OK | 
|  |  | 
|  | def detect_desktop_environment(): | 
|  | """Checks for known desktop environments | 
|  |  | 
|  | Return the desktop environments name, lowercase (kde, gnome, xfce) | 
|  | or "generic" | 
|  |  | 
|  | """ | 
|  |  | 
|  | desktop_environment = "generic" | 
|  |  | 
|  | if os.environ.get("KDE_FULL_SESSION") == "true": | 
|  | desktop_environment = "kde" | 
|  | elif os.environ.get("GNOME_DESKTOP_SESSION_ID"): | 
|  | desktop_environment = "gnome" | 
|  | else: | 
|  | try: | 
|  | info = getoutput("xprop -root _DT_SAVE_MODE") | 
|  | if ' = "xfce4"' in info: | 
|  | desktop_environment = "xfce" | 
|  | except (OSError, RuntimeError): | 
|  | pass | 
|  |  | 
|  | return desktop_environment | 
|  |  | 
|  | def register_X_controllers(): | 
|  | if _iscommand("kfmclient"): | 
|  | _controllers["kde-open"] = KfmClient() | 
|  |  | 
|  | for command in ("gnome-open", "exo-open", "xdg-open"): | 
|  | if _iscommand(command): | 
|  | _controllers[command] = Controller(command) | 
|  |  | 
|  | def get(): | 
|  | controllers_map = { | 
|  | "gnome": "gnome-open", | 
|  | "kde": "kde-open", | 
|  | "xfce": "exo-open", | 
|  | } | 
|  |  | 
|  | desktop_environment = detect_desktop_environment() | 
|  |  | 
|  | try: | 
|  | controller_name = controllers_map[desktop_environment] | 
|  | return _controllers[controller_name].open | 
|  |  | 
|  | except KeyError: | 
|  | if "xdg-open" in _controllers: | 
|  | return _controllers["xdg-open"].open | 
|  | else: | 
|  | return webbrowser.open | 
|  |  | 
|  | if os.environ.get("DISPLAY"): | 
|  | register_X_controllers() | 
|  | _open = get() | 
|  |  | 
|  |  | 
|  | def open(filename): | 
|  | """Open a file or a URL in the registered default application.""" | 
|  |  | 
|  | return _open(filename) |