47
52
newFile = baseName + '.' + fileExt
48
53
path = config.scratchDir + newFile
52
rootWindow = gtk.gdk.get_default_root_window()
55
from gi.repository import Gdk
56
from gi.repository import GObject
57
from gi.repository import GdkPixbuf
58
rootWindow = Gdk.get_default_root_window()
53
59
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'
60
pixbuf = GdkPixbuf.Pixbuf(colorspace=GdkPixbuf.Colorspace.RGB,
66
pixbuf = Gdk.pixbuf_get_from_window(rootWindow, 0, 0, \
67
geometry[2], geometry[3])
68
# GdkPixbuf.Pixbuf.save() needs 'jpeg' and not 'jpg'
59
69
if fileExt == 'jpg': fileExt = 'jpeg'
60
try: pixbuf.save(path, fileExt)
61
except gobject.GError:
71
pixbuf.savev(path, fileExt, [], [])
72
except GObject.GError:
62
73
raise ValueError, "Failed to save screenshot in %s format" % fileExt
63
74
assert os.path.exists(path)
64
75
logger.log("Screenshot taken: " + path)
113
123
logger.log("sleeping for %f" % delay)
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'
126
class Highlight (Gtk.Window):
128
def __init__(self, x, y, w, h):
129
super(Highlight, self).__init__()
130
self.set_decorated(False)
131
self.set_has_resize_grip(False)
132
self.set_default_size(w, h)
133
self.screen = self.get_screen()
134
self.visual = self.screen.get_rgba_visual()
135
if self.visual is not None and self.screen.is_composited():
136
self.set_visual(self.visual)
137
self.set_app_paintable(True)
138
self.connect("draw", self.area_draw)
142
def area_draw(self, widget, cr):
143
cr.set_source_rgba(.0, .0, .0, 0.0)
144
cr.set_operator(cairo.OPERATOR_SOURCE)
146
cr.set_operator(cairo.OPERATOR_OVER)
147
cr.set_source_rgb(0.9, 0.1, 0.1)
149
cr.rectangle(0, 0, self.get_size()[0], self.get_size()[1])
152
class Blinker(object):
154
main_loop = GObject.MainLoop()
155
def __init__(self, x, y, w, h):
156
from gi.repository import Gdk
157
self.highlight_window = Highlight(x, y, w, h)
158
if self.highlight_window.screen.is_composited() is not False:
159
self.timeout_handler_id = GObject.timeout_add (Blinker.INTERVAL_MS, self.destroyHighlight)
162
self.highlight_window.destroy()
164
def destroyHighlight(self):
165
self.highlight_window.destroy()
166
self.main_loop.quit()
171
A mutex implementation that uses atomicity of the mkdir operation in UNIX-like
172
systems. This can be used by scripts to provide for mutual exlusion, either in single
173
scripts using threads etc. or i.e. to handle sitations of possible collisions among
174
multiple running scripts. You can choose to make randomized single-script wise locks
175
or a more general locks if you do not choose to randomize the lockdir name
177
def __init__(self, location='/tmp', lockname='dogtail_lockdir_', randomize=True):
179
You can change the default lockdir location or name. Setting randomize to
180
False will result in no random string being appened to the lockdir name.
182
self.lockdir = os.path.join(os.path.normpath(location), lockname)
184
self.lockdir = "%s%s" % (self.lockdir,self.__getPostfix())
188
Creates a lockdir based on the settings on Lock() instance creation.
189
Raises OSError exception of the lock is already present. Should be
190
atomic on POSIX compliant systems.
192
locked_msg = 'Dogtail lock: Already locked with the same lock'
193
if not os.path.exists(self.lockdir):
195
os.mkdir(self.lockdir)
198
if e.errno == errno.EEXIST and os.path.isdir(self.lockdir):
199
raise OSError(locked_msg)
201
raise OSError(locked_msg)
205
Removes a lock. Will raise OSError exception if the lock was not present.
206
Should be atomic on POSIX compliant systems.
208
import os #have to import here for situations when executed from __del__
209
if os.path.exists(self.lockdir):
211
os.rmdir(self.lockdir)
213
if e.erron == errno.EEXIST:
214
raise OSError('Dogtail unlock: lockdir removed elsewhere!')
216
raise OSError('Dogtail unlock: not locked')
220
Makes sure lock is removed when the process ends. Although not when killed indeed.
224
def __getPostfix(self):
227
return ''.join(random.choice(string.letters + string.digits) for x in range(5))
230
a11yDConfKey = 'org.gnome.desktop.interface'
156
232
def isA11yEnabled():
158
Checks if accessibility is enabled via gconf.
234
Checks if accessibility is enabled via DConf.
160
return gconfClient.get_bool(a11yGConfKey)
236
from gi.repository.Gio import Settings
237
InterfaceSettings = Settings(a11yDConfKey)
238
dconfEnabled = InterfaceSettings.get_boolean('toolkit-accessibility')
239
if os.environ.get('GTK_MODULES','').find('gail:atk-bridge') == -1:
241
else: envEnabled = True
242
return (dconfEnabled or envEnabled)
162
244
def bailBecauseA11yIsDisabled():
245
if sys.argv[0].endswith("pydoc"): return
247
if file("/proc/%s/cmdline" % os.getpid()).read().find('epydoc') != -1:
163
250
logger.log("Dogtail requires that Assistive Technology support be enabled. Aborting...")
166
253
def enableA11y():
168
Enables accessibility via gconf.
255
Enables accessibility via GConf.
170
return gconfClient.set_bool(a11yGConfKey, True)
257
from gi.repository.Gio import Settings
258
InterfaceSettings = Settings(a11yDConfKey)
259
dconfEnabled = InterfaceSettings.set_boolean('toolkit-accessibility', True)
172
261
def checkForA11y():
181
270
user if it should be enabled if it is not already, then halts execution.
183
272
if isA11yEnabled(): return
185
dialog = gtk.Dialog('Enable Assistive Technology Support?',
273
from gi.repository import Gtk
274
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))
276
Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT,
277
(Gtk.STOCK_QUIT, Gtk.ResponseType.CLOSE,
278
"_Enable", Gtk.ResponseType.ACCEPT))
190
279
question = """Dogtail requires that Assistive Technology Support be enabled for it to function. Would you like to enable Assistive Technology support now?
192
281
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)
283
dialog.set_default_response(Gtk.ResponseType.ACCEPT)
284
questionLabel = Gtk.Label(label=question)
196
285
questionLabel.set_line_wrap(True)
197
dialog.vbox.pack_start(questionLabel)
286
dialog.vbox.pack_start(questionLabel, True, True, 0)
198
287
dialog.show_all()
199
288
result = dialog.run()
200
if result == gtk.RESPONSE_ACCEPT:
289
if result == Gtk.ResponseType.ACCEPT:
201
290
logger.log("Enabling accessibility...")
203
elif result == gtk.RESPONSE_CLOSE:
292
elif result == Gtk.ResponseType.CLOSE:
204
293
bailBecauseA11yIsDisabled()