| """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 = file(os.devnull, 'r+') | 
 |         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 lauching | 
 |         # 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 progam 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: | 
 |  | 
 |     import commands | 
 |  | 
 |     # @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 = commands.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 = commands.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 _controllers.has_key('xdg-open'): | 
 |                 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 an URL in the registered default application.''' | 
 |  | 
 |     return _open(filename) |