1 #!/usr/bin/env python 2 3 """ 4 Simple desktop integration for Python. This module provides desktop environment 5 detection and resource opening support for a selection of common and 6 standardised desktop environments. 7 8 Copyright (C) 2005, 2006 Paul Boddie <paul@boddie.org.uk> 9 10 This library is free software; you can redistribute it and/or 11 modify it under the terms of the GNU Lesser General Public 12 License as published by the Free Software Foundation; either 13 version 2.1 of the License, or (at your option) any later version. 14 15 This library is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 Lesser General Public License for more details. 19 20 You should have received a copy of the GNU Lesser General Public 21 License along with this library; if not, write to the Free Software 22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 23 24 -------- 25 26 Desktop Detection 27 ----------------- 28 29 To detect a specific desktop environment, use the get_desktop function. 30 To detect whether the desktop environment is standardised (according to the 31 proposed DESKTOP_LAUNCH standard), use the is_standard function. 32 33 Opening URLs 34 ------------ 35 36 To open a URL in the current desktop environment, relying on the automatic 37 detection of that environment, use the desktop.open function as follows: 38 39 desktop.open("http://www.python.org") 40 41 To override the detected desktop, specify the desktop parameter to the open 42 function as follows: 43 44 desktop.open("http://www.python.org", "KDE") # Insists on KDE 45 desktop.open("http://www.python.org", "GNOME") # Insists on GNOME 46 47 Without overriding using the desktop parameter, the open function will attempt 48 to use the "standard" desktop opening mechanism which is controlled by the 49 DESKTOP_LAUNCH environment variable as described below. 50 51 The DESKTOP_LAUNCH Environment Variable 52 --------------------------------------- 53 54 The DESKTOP_LAUNCH environment variable must be shell-quoted where appropriate, 55 as shown in some of the following examples: 56 57 DESKTOP_LAUNCH="kdialog --msgbox" Should present any opened URLs in 58 their entirety in a KDE message box. 59 (Command "kdialog" plus parameter.) 60 DESKTOP_LAUNCH="my\ opener" Should run the "my opener" program to 61 open URLs. 62 (Command "my opener", no parameters.) 63 DESKTOP_LAUNCH="my\ opener --url" Should run the "my opener" program to 64 open URLs. 65 (Command "my opener" plus parameter.) 66 67 Details of the DESKTOP_LAUNCH environment variable convention can be found here: 68 http://lists.freedesktop.org/archives/xdg/2004-August/004489.html 69 """ 70 71 __version__ = "0.2.4" 72 73 import os 74 import sys 75 76 # Provide suitable process creation functions. 77 78 try: 79 import subprocess 80 def _run(cmd, shell, wait): 81 opener = subprocess.Popen(cmd, shell=shell) 82 if wait: opener.wait() 83 return opener.pid 84 85 def _readfrom(cmd, shell): 86 opener = subprocess.Popen(cmd, shell=shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE) 87 opener.stdin.close() 88 return opener.stdout.read() 89 90 def _status(cmd, shell): 91 opener = subprocess.Popen(cmd, shell=shell) 92 opener.wait() 93 return opener.returncode == 0 94 95 except ImportError: 96 import popen2 97 def _run(cmd, shell, wait): 98 opener = popen2.Popen3(cmd) 99 if wait: opener.wait() 100 return opener.pid 101 102 def _readfrom(cmd, shell): 103 opener = popen2.Popen3(cmd) 104 opener.tochild.close() 105 opener.childerr.close() 106 return opener.fromchild.read() 107 108 def _status(cmd, shell): 109 opener = popen2.Popen3(cmd) 110 opener.wait() 111 return opener.poll() == 0 112 113 import commands 114 115 # Introspection functions. 116 117 def get_desktop(): 118 119 """ 120 Detect the current desktop environment, returning the name of the 121 environment. If no environment could be detected, None is returned. 122 """ 123 124 if os.environ.has_key("KDE_FULL_SESSION") or \ 125 os.environ.has_key("KDE_MULTIHEAD"): 126 return "KDE" 127 elif os.environ.has_key("GNOME_DESKTOP_SESSION_ID") or \ 128 os.environ.has_key("GNOME_KEYRING_SOCKET"): 129 return "GNOME" 130 elif sys.platform == "darwin": 131 return "Mac OS X" 132 elif hasattr(os, "startfile"): 133 return "Windows" 134 elif os.environ.has_key("DISPLAY"): 135 return "X11" 136 else: 137 return None 138 139 def use_desktop(desktop): 140 141 """ 142 Decide which desktop should be used, based on the detected desktop and a 143 supplied 'desktop' argument (which may be None). Return an identifier 144 indicating the desktop type as being either "standard" or one of the results 145 from the 'get_desktop' function. 146 """ 147 148 # Attempt to detect a desktop environment. 149 150 detected = get_desktop() 151 152 # Start with desktops whose existence can be easily tested. 153 154 if (desktop is None or desktop == "standard") and is_standard(): 155 return "standard" 156 elif (desktop is None or desktop == "Windows") and detected == "Windows": 157 return "Windows" 158 159 # Test for desktops where the overriding is not verified. 160 161 elif (desktop or detected) == "KDE": 162 return "KDE" 163 elif (desktop or detected) == "GNOME": 164 return "GNOME" 165 elif (desktop or detected) == "Mac OS X": 166 return "Mac OS X" 167 elif (desktop or detected) == "X11": 168 return "X11" 169 else: 170 return None 171 172 def is_standard(): 173 174 """ 175 Return whether the current desktop supports standardised application 176 launching. 177 """ 178 179 return os.environ.has_key("DESKTOP_LAUNCH") 180 181 # Activity functions. 182 183 def open(url, desktop=None, wait=0): 184 185 """ 186 Open the 'url' in the current desktop's preferred file browser. If the 187 optional 'desktop' parameter is specified then attempt to use that 188 particular desktop environment's mechanisms to open the 'url' instead of 189 guessing or detecting which environment is being used. 190 191 Suggested values for 'desktop' are "standard", "KDE", "GNOME", "Mac OS X", 192 "Windows" where "standard" employs a DESKTOP_LAUNCH environment variable to 193 open the specified 'url'. DESKTOP_LAUNCH should be a command, possibly 194 followed by arguments, and must have any special characters shell-escaped. 195 196 The process identifier of the "opener" (ie. viewer, editor, browser or 197 program) associated with the 'url' is returned by this function. If the 198 process identifier cannot be determined, None is returned. 199 200 An optional 'wait' parameter is also available for advanced usage and, if 201 'wait' is set to a true value, this function will wait for the launching 202 mechanism to complete before returning (as opposed to immediately returning 203 as is the default behaviour). 204 """ 205 206 # Decide on the desktop environment in use. 207 208 desktop_in_use = use_desktop(desktop) 209 210 if desktop_in_use == "standard": 211 arg = "".join([os.environ["DESKTOP_LAUNCH"], commands.mkarg(url)]) 212 return _run(arg, 1, wait) 213 214 elif desktop_in_use == "Windows": 215 # NOTE: This returns None in current implementations. 216 return os.startfile(url) 217 218 elif desktop_in_use == "KDE": 219 cmd = ["kfmclient", "exec", url] 220 221 elif desktop_in_use == "GNOME": 222 cmd = ["gnome-open", url] 223 224 elif desktop_in_use == "Mac OS X": 225 cmd = ["open", url] 226 227 # Finish with an error where no suitable desktop was identified. 228 229 else: 230 raise OSError, "Desktop '%s' not supported (neither DESKTOP_LAUNCH nor os.startfile could be used)" % desktop_in_use 231 232 return _run(cmd, 0, wait) 233 234 # vim: tabstop=4 expandtab shiftwidth=4