#!/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 = 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 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)