1
2 """
3 Various utilities
4
5 Authors: Ed Rousseau <rousseau@redhat.com>, Zack Cerza <zcerza@redhat.com, David Malcolm <dmalcolm@redhat.com>
6 """
7
8 __author__ = """Ed Rousseau <rousseau@redhat.com>,
9 Zack Cerza <zcerza@redhat.com,
10 David Malcolm <dmalcolm@redhat.com>
11 """
12
13 import os
14 import sys
15 import subprocess
16 import re
17 from config import config
18 from time import sleep
19 from logging import debugLogger as logger
20 from logging import TimeStamp
21 from errors import DependencyNotFoundError
22
23 -def screenshot(file = 'screenshot.png', timeStamp = True):
24 """
25 This function wraps the ImageMagick import command to take a screenshot.
26
27 The file argument may be specified as 'foo', 'foo.png', or using any other
28 extension that ImageMagick supports. PNG is the default.
29
30 By default, screenshot filenames are in the format of foo_YYYYMMDD-hhmmss.png .
31 The timeStamp argument may be set to False to name the file foo.png.
32 """
33 if not isinstance(timeStamp, bool):
34 raise TypeError, "timeStampt must be True or False"
35
36 assert os.path.isdir(config.scratchDir)
37
38 baseName = ''.join(file.split('.')[0:-1])
39 fileExt = file.split('.')[-1].lower()
40 if not baseName:
41 baseName = file
42 fileExt = 'png'
43
44 if timeStamp:
45 ts = TimeStamp()
46 newFile = ts.fileStamp(baseName) + '.' + fileExt
47 path = config.scratchDir + newFile
48 else:
49 newFile = baseName + '.' + fileExt
50 path = config.scratchDir + newFile
51
52 import gtk.gdk
53 import gobject
54 rootWindow = gtk.gdk.get_default_root_window()
55 geometry = rootWindow.get_geometry()
56 pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, geometry[2], \
57 geometry[3])
58 gtk.gdk.Pixbuf.get_from_drawable(pixbuf, rootWindow, \
59 rootWindow.get_colormap(), 0, 0, 0, 0, geometry[2], geometry[3])
60
61 if fileExt == 'jpg': fileExt = 'jpeg'
62 try: pixbuf.save(path, fileExt)
63 except gobject.GError:
64 raise ValueError, "Failed to save screenshot in %s format" % fileExt
65 assert os.path.exists(path)
66 logger.log("Screenshot taken: " + path)
67 return path
68
69 -def run(string, timeout=config.runTimeout, interval=config.runInterval, desktop=None, dumb=False, appName=''):
70 """
71 Runs an application. [For simple command execution such as 'rm *', use os.popen() or os.system()]
72 If dumb is omitted or is False, polls at interval seconds until the application is finished starting, or until timeout is reached.
73 If dumb is True, returns when timeout is reached.
74 """
75 if not desktop: from tree import root as desktop
76 args = string.split()
77 name = args[0]
78 os.environ['GTK_MODULES'] = 'gail:atk-bridge'
79 pid = subprocess.Popen(args, env = os.environ).pid
80
81 if not appName:
82 appName=args[0]
83
84 if dumb:
85
86 doDelay(timeout)
87 else:
88
89
90 time = 0
91 while time < timeout:
92 time = time + interval
93 try:
94 for child in desktop.children[::-1]:
95 if child.name == appName:
96 for grandchild in child.children:
97 if grandchild.roleName == 'frame':
98 from procedural import focus
99 focus.application.node = child
100 doDelay(interval)
101 return pid
102 except AttributeError: pass
103 doDelay(interval)
104 return pid
105
107 """
108 Utility function to insert a delay (with logging and a configurable
109 default delay)
110 """
111 if delay is None:
112 delay = config.defaultDelay
113 if config.debugSleep:
114 logger.log("sleeping for %f" % delay)
115 sleep(delay)
116
118 INTERVAL_MS = 200
119
120 - def __init__(self, x, y, w, h, count = 2):
121 import gobject
122 import gtk.gdk
123 self.count = count
124 self.x = x
125 self.y = y
126 self.w = w
127 self.h = h
128 self.timeout_handler_id = gobject.timeout_add (Blinker.INTERVAL_MS, self.blinkDrawRectangle)
129 gtk.main()
130
132 import gtk.gdk
133 display = gtk.gdk.display_get_default()
134 screen = display.get_default_screen()
135 rootWindow = screen.get_root_window()
136 gc = rootWindow.new_gc()
137
138 gc.set_subwindow (gtk.gdk.INCLUDE_INFERIORS)
139 gc.set_function (gtk.gdk.INVERT)
140 gc.set_line_attributes (3, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER)
141 rootWindow.draw_rectangle (gc, False, self.x, self.y, self.w, self.h);
142
143 self.count-=1
144
145 if self.count <= 0:
146 gtk.main_quit()
147 return False
148
149 return True
150
151
152 a11yGConfKey = '/desktop/gnome/interface/accessibility'
153
155 """
156 Checks if accessibility is enabled via gconf.
157 """
158 import gconf
159 gconfEnabled = gconf.client_get_default().get_bool(a11yGConfKey)
160 if os.environ.get('GTK_MODULES','').find('gail:atk-bridge') == -1:
161 envEnabled = False
162 else: envEnabled = True
163 return (gconfEnabled or envEnabled)
164
166 if sys.argv[0].endswith("pydoc"): return
167 try:
168 if file("/proc/%s/cmdline" % os.getpid()).read().find('epydoc') != -1:
169 return
170 except: pass
171 logger.log("Dogtail requires that Assistive Technology support be enabled. Aborting...")
172 sys.exit(1)
173
175 """
176 Enables accessibility via gconf.
177 """
178 import gconf
179 return gconf.client_get_default().set_bool(a11yGConfKey, True)
180
186
188 """
189 Checks if accessibility is enabled, and presents a dialog prompting the
190 user if it should be enabled if it is not already, then halts execution.
191 """
192 if isA11yEnabled(): return
193 import gtk
194 dialog = gtk.Dialog('Enable Assistive Technology Support?',
195 None,
196 gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
197 (gtk.STOCK_QUIT, gtk.RESPONSE_CLOSE,
198 "_Enable", gtk.RESPONSE_ACCEPT))
199 question = """Dogtail requires that Assistive Technology Support be enabled for it to function. Would you like to enable Assistive Technology support now?
200
201 Note that you will have to log out for the change to fully take effect.
202 """.strip()
203 dialog.set_default_response(gtk.RESPONSE_ACCEPT)
204 questionLabel = gtk.Label(question)
205 questionLabel.set_line_wrap(True)
206 dialog.vbox.pack_start(questionLabel)
207 dialog.show_all()
208 result = dialog.run()
209 if result == gtk.RESPONSE_ACCEPT:
210 logger.log("Enabling accessibility...")
211 enableA11y()
212 elif result == gtk.RESPONSE_CLOSE:
213 bailBecauseA11yIsDisabled()
214 dialog.destroy()
215