Home | History | Annotate | Download | only in scan-view
      1 """Utility for opening a file using the default application in a cross-platform
      2 manner. Modified from http://code.activestate.com/recipes/511443/.
      3 """
      4 
      5 __version__ = '1.1x'
      6 __all__ = ['open']
      7 
      8 import os
      9 import sys
     10 import webbrowser
     11 import subprocess
     12 
     13 _controllers = {}
     14 _open = None
     15 
     16 
     17 class BaseController(object):
     18     '''Base class for open program controllers.'''
     19 
     20     def __init__(self, name):
     21         self.name = name
     22 
     23     def open(self, filename):
     24         raise NotImplementedError
     25 
     26 
     27 class Controller(BaseController):
     28     '''Controller for a generic open program.'''
     29 
     30     def __init__(self, *args):
     31         super(Controller, self).__init__(os.path.basename(args[0]))
     32         self.args = list(args)
     33 
     34     def _invoke(self, cmdline):
     35         if sys.platform[:3] == 'win':
     36             closefds = False
     37             startupinfo = subprocess.STARTUPINFO()
     38             startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
     39         else:
     40             closefds = True
     41             startupinfo = None
     42 
     43         if (os.environ.get('DISPLAY') or sys.platform[:3] == 'win' or
     44                                                     sys.platform == 'darwin'):
     45             inout = file(os.devnull, 'r+')
     46         else:
     47             # for TTY programs, we need stdin/out
     48             inout = None
     49 
     50         # if possible, put the child precess in separate process group,
     51         # so keyboard interrupts don't affect child precess as well as
     52         # Python
     53         setsid = getattr(os, 'setsid', None)
     54         if not setsid:
     55             setsid = getattr(os, 'setpgrp', None)
     56 
     57         pipe = subprocess.Popen(cmdline, stdin=inout, stdout=inout,
     58                                 stderr=inout, close_fds=closefds,
     59                                 preexec_fn=setsid, startupinfo=startupinfo)
     60 
     61         # It is assumed that this kind of tools (gnome-open, kfmclient,
     62         # exo-open, xdg-open and open for OSX) immediately exit after lauching
     63         # the specific application
     64         returncode = pipe.wait()
     65         if hasattr(self, 'fixreturncode'):
     66             returncode = self.fixreturncode(returncode)
     67         return not returncode
     68 
     69     def open(self, filename):
     70         if isinstance(filename, basestring):
     71             cmdline = self.args + [filename]
     72         else:
     73             # assume it is a sequence
     74             cmdline = self.args + filename
     75         try:
     76             return self._invoke(cmdline)
     77         except OSError:
     78             return False
     79 
     80 
     81 # Platform support for Windows
     82 if sys.platform[:3] == 'win':
     83 
     84     class Start(BaseController):
     85         '''Controller for the win32 start progam through os.startfile.'''
     86 
     87         def open(self, filename):
     88             try:
     89                 os.startfile(filename)
     90             except WindowsError:
     91                 # [Error 22] No application is associated with the specified
     92                 # file for this operation: '<URL>'
     93                 return False
     94             else:
     95                 return True
     96 
     97     _controllers['windows-default'] = Start('start')
     98     _open = _controllers['windows-default'].open
     99 
    100 
    101 # Platform support for MacOS
    102 elif sys.platform == 'darwin':
    103     _controllers['open']= Controller('open')
    104     _open = _controllers['open'].open
    105 
    106 
    107 # Platform support for Unix
    108 else:
    109 
    110     import commands
    111 
    112     # @WARNING: use the private API of the webbrowser module
    113     from webbrowser import _iscommand
    114 
    115     class KfmClient(Controller):
    116         '''Controller for the KDE kfmclient program.'''
    117 
    118         def __init__(self, kfmclient='kfmclient'):
    119             super(KfmClient, self).__init__(kfmclient, 'exec')
    120             self.kde_version = self.detect_kde_version()
    121 
    122         def detect_kde_version(self):
    123             kde_version = None
    124             try:
    125                 info = commands.getoutput('kde-config --version')
    126 
    127                 for line in info.splitlines():
    128                     if line.startswith('KDE'):
    129                         kde_version = line.split(':')[-1].strip()
    130                         break
    131             except (OSError, RuntimeError):
    132                 pass
    133 
    134             return kde_version
    135 
    136         def fixreturncode(self, returncode):
    137             if returncode is not None and self.kde_version > '3.5.4':
    138                 return returncode
    139             else:
    140                 return os.EX_OK
    141 
    142     def detect_desktop_environment():
    143         '''Checks for known desktop environments
    144 
    145         Return the desktop environments name, lowercase (kde, gnome, xfce)
    146         or "generic"
    147 
    148         '''
    149 
    150         desktop_environment = 'generic'
    151 
    152         if os.environ.get('KDE_FULL_SESSION') == 'true':
    153             desktop_environment = 'kde'
    154         elif os.environ.get('GNOME_DESKTOP_SESSION_ID'):
    155             desktop_environment = 'gnome'
    156         else:
    157             try:
    158                 info = commands.getoutput('xprop -root _DT_SAVE_MODE')
    159                 if ' = "xfce4"' in info:
    160                     desktop_environment = 'xfce'
    161             except (OSError, RuntimeError):
    162                 pass
    163 
    164         return desktop_environment
    165 
    166 
    167     def register_X_controllers():
    168         if _iscommand('kfmclient'):
    169             _controllers['kde-open'] = KfmClient()
    170 
    171         for command in ('gnome-open', 'exo-open', 'xdg-open'):
    172             if _iscommand(command):
    173                 _controllers[command] = Controller(command)
    174 
    175     def get():
    176         controllers_map = {
    177             'gnome': 'gnome-open',
    178             'kde': 'kde-open',
    179             'xfce': 'exo-open',
    180         }
    181 
    182         desktop_environment = detect_desktop_environment()
    183 
    184         try:
    185             controller_name = controllers_map[desktop_environment]
    186             return _controllers[controller_name].open
    187 
    188         except KeyError:
    189             if _controllers.has_key('xdg-open'):
    190                 return _controllers['xdg-open'].open
    191             else:
    192                 return webbrowser.open
    193 
    194 
    195     if os.environ.get("DISPLAY"):
    196         register_X_controllers()
    197     _open = get()
    198 
    199 
    200 def open(filename):
    201     '''Open a file or an URL in the registered default application.'''
    202 
    203     return _open(filename)
    204