1.1 --- a/desktop.py Wed Oct 15 23:18:08 2008 +0200
1.2 +++ b/desktop.py Sun Aug 27 00:02:00 2006 +0000
1.3 @@ -48,6 +48,21 @@
1.4 to use the "standard" desktop opening mechanism which is controlled by the
1.5 DESKTOP_LAUNCH environment variable as described below.
1.6
1.7 +Opening Dialogue Boxes (Dialogs)
1.8 +--------------------------------
1.9 +
1.10 +To open a dialogue box (dialog) in the current desktop environment, relying on
1.11 +the automatic detection of that environment, use the desktop.dialog function as
1.12 +follows:
1.13 +
1.14 +desktop.dialog("question", text="Are you sure?")
1.15 +
1.16 +To override the detected desktop, specify the desktop parameter to the dialog
1.17 +function as follows:
1.18 +
1.19 +desktop.dialog("question", "KDE", text="Are you sure?") # Insists on KDE
1.20 +desktop.dialog("question", "GNOME", text="Are you sure?") # Insists on GNOME
1.21 +
1.22 The DESKTOP_LAUNCH Environment Variable
1.23 ---------------------------------------
1.24
1.25 @@ -68,7 +83,7 @@
1.26 http://lists.freedesktop.org/archives/xdg/2004-August/004489.html
1.27 """
1.28
1.29 -__version__ = "0.2.3"
1.30 +__version__ = "0.2.4"
1.31
1.32 import os
1.33 import sys
1.34 @@ -80,6 +95,16 @@
1.35 if wait: opener.wait()
1.36 return opener.pid
1.37
1.38 + def _readfrom(cmd, shell):
1.39 + opener = subprocess.Popen(cmd, shell=shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
1.40 + opener.stdin.close()
1.41 + return opener.stdout.read()
1.42 +
1.43 + def _status(cmd, shell):
1.44 + opener = subprocess.Popen(cmd, shell=shell)
1.45 + opener.wait()
1.46 + return opener.returncode == 0
1.47 +
1.48 except ImportError:
1.49 import popen2
1.50 def _run(cmd, shell, wait):
1.51 @@ -87,8 +112,58 @@
1.52 if wait: opener.wait()
1.53 return opener.pid
1.54
1.55 + def _readfrom(cmd, shell):
1.56 + opener = popen2.Popen3(cmd)
1.57 + opener.tochild.close()
1.58 + opener.childerr.close()
1.59 + return opener.fromchild.read()
1.60 +
1.61 + def _status(cmd, shell):
1.62 + opener = popen2.Popen3(cmd)
1.63 + opener.wait()
1.64 + return opener.poll() == 0
1.65 +
1.66 import commands
1.67
1.68 +# Internal data.
1.69 +
1.70 +_dialog_commands = {
1.71 + "KDE" : "kdialog",
1.72 + "GNOME" : "zenity",
1.73 + "X11" : "Xdialog"
1.74 + }
1.75 +
1.76 +_dialog_options = {
1.77 + "KDE" : {
1.78 + "question" : (_status, ["--yesno"], ["text"]),
1.79 + "message" : (_status, ["--msgbox"], ["text"]),
1.80 + "input" : (_readfrom, ["--inputbox"], ["text", "input"]),
1.81 + "password" : (_readfrom, ["--password"], ["text"]),
1.82 + "textfile" : (_readfrom, ["--textbox"], ["filename", "width", "height"]),
1.83 + "menu" : (_readfrom, ["--menu"], ["text", "entries2"]),
1.84 + "radiolist" : (_readfrom, ["--radiolist"], ["text", "entries3"]),
1.85 + "checklist" : (_readfrom, ["--checklist"], ["text", "entries3"]),
1.86 + "pulldown" : (_readfrom, ["--combobox"], ["text", "entries1"]),
1.87 + },
1.88 + "X11" : {
1.89 + "question" : (_status, ["--stdout", "--yesno"], ["text", "height", "width"]),
1.90 + "message" : (_status, ["--stdout", "--msgbox"], ["text", "height", "width"]),
1.91 + "input" : (_readfrom, ["--stdout", "--inputbox"], ["text", "height", "width", "input"]),
1.92 + "password" : (_readfrom, ["--stdout", "--password", "--inputbox"], ["text", "height", "width"]),
1.93 + "textfile" : (_readfrom, ["--stdout", "--textbox"], ["text", "height", "width"]),
1.94 + "menu" : (_readfrom, ["--stdout", "--menubox"], ["text", "height", "width", "menu_height", "entries2"]),
1.95 + "radiolist" : (_readfrom, ["--stdout", "--radiolist"], ["text", "height", "width", "list_height", "entries3"]),
1.96 + "checklist" : (_readfrom, ["--stdout", "--checklist"], ["text", "height", "width", "list_height", "entries3"]),
1.97 + "pulldown" : (_readfrom, ["--stdout", "--combobox"], ["text", "height", "width", "entries1"]),
1.98 + },
1.99 + }
1.100 +
1.101 +_dialog_defaults = {
1.102 + "width" : 40, "height" : 30, "menu_height" : 20, "list_height" : 20
1.103 + }
1.104 +
1.105 +# Introspection functions.
1.106 +
1.107 def get_desktop():
1.108
1.109 """
1.110 @@ -106,6 +181,41 @@
1.111 return "Mac OS X"
1.112 elif hasattr(os, "startfile"):
1.113 return "Windows"
1.114 + elif os.environ.has_key("DISPLAY"):
1.115 + return "X11"
1.116 + else:
1.117 + return None
1.118 +
1.119 +def use_desktop(desktop):
1.120 +
1.121 + """
1.122 + Decide which desktop should be used, based on the detected desktop and a
1.123 + supplied 'desktop' argument (which may be None). Return an identifier
1.124 + indicating the desktop type as being either "standard" or one of the results
1.125 + from the 'get_desktop' function.
1.126 + """
1.127 +
1.128 + # Attempt to detect a desktop environment.
1.129 +
1.130 + detected = get_desktop()
1.131 +
1.132 + # Start with desktops whose existence can be easily tested.
1.133 +
1.134 + if (desktop is None or desktop == "standard") and is_standard():
1.135 + return "standard"
1.136 + elif (desktop is None or desktop == "Windows") and detected == "Windows":
1.137 + return "Windows"
1.138 +
1.139 + # Test for desktops where the overriding is not verified.
1.140 +
1.141 + elif (desktop or detected) == "KDE":
1.142 + return "KDE"
1.143 + elif (desktop or detected) == "GNOME":
1.144 + return "GNOME"
1.145 + elif (desktop or detected) == "Mac OS X":
1.146 + return "Mac OS X"
1.147 + elif (desktop or detected) == "X11":
1.148 + return "X11"
1.149 else:
1.150 return None
1.151
1.152 @@ -118,6 +228,8 @@
1.153
1.154 return os.environ.has_key("DESKTOP_LAUNCH")
1.155
1.156 +# Activity functions.
1.157 +
1.158 def open(url, desktop=None, wait=0):
1.159
1.160 """
1.161 @@ -129,7 +241,7 @@
1.162 Suggested values for 'desktop' are "standard", "KDE", "GNOME", "Mac OS X",
1.163 "Windows" where "standard" employs a DESKTOP_LAUNCH environment variable to
1.164 open the specified 'url'. DESKTOP_LAUNCH should be a command, possibly
1.165 - followed by arguments, and must have any special characters shell-escaped.
1.166 + followed by arguments, and must have any special characters shell-escaped.
1.167
1.168 The process identifier of the "opener" (ie. viewer, editor, browser or
1.169 program) associated with the 'url' is returned by this function. If the
1.170 @@ -141,29 +253,25 @@
1.171 as is the default behaviour).
1.172 """
1.173
1.174 - # Attempt to detect a desktop environment.
1.175 -
1.176 - detected = get_desktop()
1.177 + # Decide on the desktop environment in use.
1.178
1.179 - # Start with desktops whose existence can be easily tested.
1.180 + desktop_in_use = use_desktop(desktop)
1.181
1.182 - if (desktop is None or desktop == "standard") and is_standard():
1.183 + if desktop_in_use == "standard":
1.184 arg = "".join([os.environ["DESKTOP_LAUNCH"], commands.mkarg(url)])
1.185 return _run(arg, 1, wait)
1.186
1.187 - elif (desktop is None or desktop == "Windows") and detected == "Windows":
1.188 + elif desktop_in_use == "Windows":
1.189 # NOTE: This returns None in current implementations.
1.190 return os.startfile(url)
1.191
1.192 - # Test for desktops where the overriding is not verified.
1.193 -
1.194 - elif (desktop or detected) == "KDE":
1.195 + elif desktop_in_use == "KDE":
1.196 cmd = ["kfmclient", "exec", url]
1.197
1.198 - elif (desktop or detected) == "GNOME":
1.199 + elif desktop_in_use == "GNOME":
1.200 cmd = ["gnome-open", url]
1.201
1.202 - elif (desktop or detected) == "Mac OS X":
1.203 + elif desktop_in_use == "Mac OS X":
1.204 cmd = ["open", url]
1.205
1.206 # Finish with an error where no suitable desktop was identified.
1.207 @@ -173,4 +281,104 @@
1.208
1.209 return _run(cmd, 0, wait)
1.210
1.211 +def dialog(dialog_type, desktop=None, **options):
1.212 +
1.213 + """
1.214 + Open a dialogue box (dialog) using a program appropriate to the desktop
1.215 + environment in use. The specified 'dialog_type' may be one of the following:
1.216 +
1.217 + question A dialogue asking a question and showing response buttons.
1.218 + Options: text, width (in characters), height (in characters)
1.219 +
1.220 + message A message dialogue.
1.221 + Options: text, level ("warning", "error", "info")
1.222 +
1.223 + menu A menu of options, one of which being selectable.
1.224 + Options: text, width (in characters), height (in characters),
1.225 + menu_height (in entries), entries (list of (value, text) tuples)
1.226 +
1.227 + radiolist A list of radio buttons, one of which being selectable.
1.228 + Options: text, width (in characters), height (in characters),
1.229 + list_height (in entries), entries (list of (value, text, status)
1.230 + tuples)
1.231 +
1.232 + checklist A list of checkboxes, many being selectable.
1.233 + Options: text, width (in characters), height (in characters),
1.234 + list_height (in entries), entries (list of (value, text, status)
1.235 + tuples)
1.236 +
1.237 + pulldown A pull-down menu of options, one of which being selectable.
1.238 + Options: text, width (in characters), height (in characters),
1.239 + entries (list of values)
1.240 +
1.241 + input An input dialogue, consisting of an input field.
1.242 + Options: text, width (in characters), height (in characters),
1.243 + input
1.244 +
1.245 + password A password dialogue, consisting of a password entry field.
1.246 + Options: text, width (in characters), height (in characters),
1.247 + input
1.248 +
1.249 + textfile A text file input box.
1.250 + Options: text, width (in characters), height (in characters),
1.251 + filename
1.252 +
1.253 + If the optional 'desktop' parameter is specified then attempt to use that
1.254 + particular desktop environment's mechanisms to open the 'url' instead of
1.255 + guessing or detecting which environment is being used.
1.256 +
1.257 + Suggested values for 'desktop' are "standard", "KDE", "GNOME", "Mac OS X",
1.258 + "Windows".
1.259 +
1.260 + The result of the dialogue interaction may be a string indicating user
1.261 + input (for input, password, menu, radiolist, pulldown), a list of strings
1.262 + indicating selections of one or more items (for checklist), or a value
1.263 + indicating true or false (for question).
1.264 + """
1.265 +
1.266 + # Decide on the desktop environment in use.
1.267 +
1.268 + desktop_in_use = use_desktop(desktop)
1.269 +
1.270 + # Get the base command.
1.271 +
1.272 + cmd = _dialog_commands[desktop_in_use]
1.273 +
1.274 + # Get the handler for the command, along with required command options and
1.275 + # the fields that the command expects.
1.276 +
1.277 + handler, cmd_options, fields = _dialog_options[desktop_in_use][dialog_type]
1.278 +
1.279 + # Form a command list.
1.280 +
1.281 + l = [cmd] + cmd_options
1.282 +
1.283 + # Process the fields, adding values if found or defaults if available.
1.284 +
1.285 + for field in fields:
1.286 + if field[-1].isdigit():
1.287 + n = int(field[-1])
1.288 + field = field[:-1]
1.289 + else:
1.290 + n = 0 # not list
1.291 +
1.292 + if options.has_key(field):
1.293 + if n == 0:
1.294 + l.append(str(options[field]))
1.295 + else:
1.296 + values = options[field]
1.297 + for value in values:
1.298 + if n == 1:
1.299 + l.append(str(value))
1.300 + else:
1.301 + for i in range(0, n):
1.302 + l.append(str(value[i]))
1.303 + elif _dialog_defaults.has_key(field):
1.304 + l.append(str(_dialog_defaults[field]))
1.305 + else:
1.306 + raise ValueError, "Field '%s' missing from options." % field
1.307 +
1.308 + print l
1.309 + return handler(l, 0)
1.310 +
1.311 # vim: tabstop=4 expandtab shiftwidth=4