18
18
from logging import TimeStamp
19
19
from errors import DependencyNotFoundError
21
def screenshot(windowname = 'root', file = 'screenshot.png', timeStamp = True, args = ''):
23
This function wraps the ImageMagick import command to take a screenshot.
25
The file argument may be specified as 'foo', 'foo.png', or using any other
26
extension that ImageMagick supports. PNG is the default.
28
By default, screenshot filenames are in the format of foo_YYYYMMDD-hhmmss.png .
29
The timeStamp argument may be set to False to name the file foo.png.
31
IMVer = os.popen('import -version').readline()
32
IMVer = re.match('Version: ImageMagick ([0-9\.]+) .*', IMVer)
34
raise DependencyNotFoundError, "ImageMagick"
36
# config is supposed to create this for us. If it's not there, bail.
37
assert os.path.isdir(config.scratchDir)
42
baseName = ''.join(file.split('.')[0:-1])
43
fileExt = file.split('.')[-1]
50
newFile = ts.fileStamp(baseName) + '.' + fileExt
51
path = config.scratchDir + newFile
53
newFile = baseName + '.' + fileExt
54
path = config.scratchDir + newFile
58
# Generate the command and redirect STDERR to STDOUT
59
# This really needs window manipulation and pyspi state binding to be done
60
# to actually be really useful
62
cmd = "import -window '%s' %s %s 2>&1" % (windowname, path, args)
63
answer = os.popen(cmd).readlines()
65
# If successful we should get nothing back. If not something went wrong
66
# and our mouse is now probably unusable
68
raise ValueError, "Screenshot failed: " + answer[-1]
69
assert os.path.exists(path)
70
logger.log("Screenshot taken: " + path)
21
def screenshot(file = 'screenshot.png', timeStamp = True):
23
This function wraps the ImageMagick import command to take a screenshot.
25
The file argument may be specified as 'foo', 'foo.png', or using any other
26
extension that ImageMagick supports. PNG is the default.
28
By default, screenshot filenames are in the format of foo_YYYYMMDD-hhmmss.png .
29
The timeStamp argument may be set to False to name the file foo.png.
31
if not isinstance(timeStamp, bool):
32
raise TypeError, "timeStampt must be True or False"
33
# config is supposed to create this for us. If it's not there, bail.
34
assert os.path.isdir(config.scratchDir)
36
baseName = ''.join(file.split('.')[0:-1])
37
fileExt = file.split('.')[-1].lower()
44
newFile = ts.fileStamp(baseName) + '.' + fileExt
45
path = config.scratchDir + newFile
47
newFile = baseName + '.' + fileExt
48
path = config.scratchDir + newFile
52
rootWindow = gtk.gdk.get_default_root_window()
53
geometry = rootWindow.get_geometry()
54
pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, geometry[2], \
56
gtk.gdk.Pixbuf.get_from_drawable(pixbuf, rootWindow, \
57
rootWindow.get_colormap(), 0, 0, 0, 0, geometry[2], geometry[3])
58
# gtk.gdk.Pixbuf.save() needs 'jpeg' and not 'jpg'
59
if fileExt == 'jpg': fileExt = 'jpeg'
60
try: pixbuf.save(path, fileExt)
61
except gobject.GError:
62
raise ValueError, "Failed to save screenshot in %s format" % fileExt
63
assert os.path.exists(path)
64
logger.log("Screenshot taken: " + path)
73
67
def run(string, timeout=config.runTimeout, interval=config.runInterval, desktop=None, dumb=False, appName=''):
75
Runs an application. [For simple command execution such as 'rm *', use os.popen() or os.system()]
76
If dumb is omitted or is False, polls at interval seconds until the application is finished starting, or until timeout is reached.
77
If dumb is True, returns when timeout is reached.
79
from os import environ, spawnvpe, P_NOWAIT
80
if not desktop: from tree import root as desktop
83
pid = spawnvpe (P_NOWAIT, name, args, environ)
89
# We're starting a non-AT-SPI-aware application. Disable startup detection.
92
# Startup detection code
93
# The timing here is not totally precise, but it's good enough for now.
96
time = time + interval
98
for child in desktop.children[::-1]:
99
if child.name == appName:
100
for grandchild in child.children:
101
if grandchild.roleName == 'frame':
102
from procedural import focus
103
focus.application.node = child
106
except AttributeError: pass
69
Runs an application. [For simple command execution such as 'rm *', use os.popen() or os.system()]
70
If dumb is omitted or is False, polls at interval seconds until the application is finished starting, or until timeout is reached.
71
If dumb is True, returns when timeout is reached.
73
from os import environ, spawnvpe, P_NOWAIT
74
if not desktop: from tree import root as desktop
77
environ['GTK_MODULES'] = 'gail:atk-bridge'
78
pid = spawnvpe (P_NOWAIT, name, args, environ)
84
# We're starting a non-AT-SPI-aware application. Disable startup detection.
87
# Startup detection code
88
# The timing here is not totally precise, but it's good enough for now.
91
time = time + interval
93
for child in desktop.children[::-1]:
94
if child.name == appName:
95
for grandchild in child.children:
96
if grandchild.roleName == 'frame':
97
from procedural import focus
98
focus.application.node = child
101
except AttributeError: pass
110
105
def doDelay(delay=None):
112
Utility function to insert a delay (with logging and a configurable
116
delay = config.defaultDelay
117
if config.debugSleep:
118
logger.log("sleeping for %f"%delay)
107
Utility function to insert a delay (with logging and a configurable
111
delay = config.defaultDelay
112
if config.debugSleep:
113
logger.log("sleeping for %f" % delay)
124
def __init__(self, x, y, w, h, count = 2):
132
self.timeout_handler_id = gobject.timeout_add (Blinker.INTERVAL_MS, self.blinkDrawRectangle)
135
def blinkDrawRectangle (self):
137
display = gtk.gdk.display_get_default()
138
screen = display.get_default_screen()
139
rootWindow = screen.get_root_window()
140
gc = rootWindow.new_gc()
142
gc.set_subwindow (gtk.gdk.INCLUDE_INFERIORS)
143
gc.set_function (gtk.gdk.INVERT)
144
gc.set_line_attributes (3, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER)
145
rootWindow.draw_rectangle (gc, False, self.x, self.y, self.w, self.h);
119
def __init__(self, x, y, w, h, count = 2):
127
self.timeout_handler_id = gobject.timeout_add (Blinker.INTERVAL_MS, self.blinkDrawRectangle)
130
def blinkDrawRectangle (self):
132
display = gtk.gdk.display_get_default()
133
screen = display.get_default_screen()
134
rootWindow = screen.get_root_window()
135
gc = rootWindow.new_gc()
137
gc.set_subwindow (gtk.gdk.INCLUDE_INFERIORS)
138
gc.set_function (gtk.gdk.INVERT)
139
gc.set_line_attributes (3, gtk.gdk.LINE_SOLID, gtk.gdk.CAP_BUTT, gtk.gdk.JOIN_MITER)
140
rootWindow.draw_rectangle (gc, False, self.x, self.y, self.w, self.h);
153
gconfClient = gconf.client_get_default()
154
a11yGConfKey = '/desktop/gnome/interface/accessibility'
158
Checks if accessibility is enabled via gconf.
160
return gconfClient.get_bool(a11yGConfKey)
162
def bailBecauseA11yIsDisabled():
163
logger.log("Dogtail requires that Assistive Technology support be enabled. Aborting...")
168
Enables accessibility via gconf.
170
return gconfClient.set_bool(a11yGConfKey, True)
174
Checks if accessibility is enabled, and halts execution if it is not.
176
if not isA11yEnabled(): bailBecauseA11yIsDisabled()
178
def checkForA11yInteractively():
180
Checks if accessibility is enabled, and presents a dialog prompting the
181
user if it should be enabled if it is not already, then halts execution.
183
if isA11yEnabled(): return
185
dialog = gtk.Dialog('Enable Assistive Technology Support?',
187
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
188
(gtk.STOCK_QUIT, gtk.RESPONSE_CLOSE,
189
"_Enable", gtk.RESPONSE_ACCEPT))
190
question = """Dogtail requires that Assistive Technology Support be enabled for it to function. Would you like to enable Assistive Technology support now?
192
Note that you will have to log out for the change to fully take effect.
194
dialog.set_default_response(gtk.RESPONSE_ACCEPT)
195
questionLabel = gtk.Label(question)
196
questionLabel.set_line_wrap(True)
197
dialog.vbox.pack_start(questionLabel)
199
result = dialog.run()
200
if result == gtk.RESPONSE_ACCEPT:
201
logger.log("Enabling accessibility...")
203
elif result == gtk.RESPONSE_CLOSE:
204
bailBecauseA11yIsDisabled()