~ubuntu-branches/debian/experimental/dogtail/experimental

« back to all changes in this revision

Viewing changes to dogtail/utils.py

  • Committer: Package Import Robot
  • Author(s): Alessio Treglia
  • Date: 2013-02-09 16:01:44 UTC
  • mfrom: (1.2.2)
  • Revision ID: package-import@ubuntu.com-20130209160144-k2yk35tll4eew9wg
Tags: 0.8.1-1
* New maintainer. (Closes: #696136) (Closes: #553898)
* Set packaging format to 3.0 (quilt).
* New upstream release (Closes: #486452):
  - String exceptions are not used anymore. (Closes: #585287)
  - Fix missing check in findChildren(), tree.py (Closes: #485758)
* ACK NMUs:
  - Convert APT's API patch into the quilt format. (Closes: #572087)
  - Convert Ludovico Gardenghi's patch into the quilt
    format. (Closes: #485752)
* Fix desktop file as Freedesktop.org's per-spec.
* Migrate from CDBS + python-support to DH short-form + dh_python2.
* Move to section python.
* Refresh {,Build-}Depends lists.
* Remove xbase-clients from Depends. (Closes: #601486)
* Add Homepage field. (Closes: #572570)
* Add watch file.
* Add gbp config file.
* Refresh debian/copyright to meet copyright format 1.0.
* Install NEWS as upstream changelog.
* Bump Standards.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
"""
12
12
 
13
13
import os
 
14
import sys
 
15
import subprocess
14
16
import re
 
17
import cairo
 
18
from gi.repository import Gtk
 
19
from gi.repository import GObject
15
20
from config import config
16
21
from time import sleep
17
22
from logging import debugLogger as logger
47
52
        newFile = baseName + '.' + fileExt
48
53
        path = config.scratchDir + newFile
49
54
 
50
 
    import gtk.gdk
51
 
    import gobject
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], \
55
 
            geometry[3])
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,
 
61
                              has_alpha=False,
 
62
                              bits_per_sample=8,
 
63
                              width=geometry[2],
 
64
                              height=geometry[3])
 
65
 
 
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:
 
70
    try:
 
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)
70
81
    If dumb is omitted or is False, polls at interval seconds until the application is finished starting, or until timeout is reached.
71
82
    If dumb is True, returns when timeout is reached.
72
83
    """
73
 
    from os import environ, spawnvpe, P_NOWAIT
74
84
    if not desktop: from tree import root as desktop
75
85
    args = string.split()
76
86
    name = args[0]
77
 
    environ['GTK_MODULES'] = 'gail:atk-bridge'
78
 
    pid = spawnvpe (P_NOWAIT, name, args, environ)
 
87
    os.environ['GTK_MODULES'] = 'gail:atk-bridge'
 
88
    pid = subprocess.Popen(args, env = os.environ).pid
79
89
 
80
90
    if not appName:
81
91
        appName=args[0]
113
123
        logger.log("sleeping for %f" % delay)
114
124
    sleep(delay)
115
125
 
116
 
class Blinker:
117
 
    INTERVAL_MS = 200
118
 
 
119
 
    def __init__(self, x, y, w, h, count = 2):
120
 
        import gobject
121
 
        import gtk.gdk
122
 
        self.count = count
123
 
        self.x = x
124
 
        self.y = y
125
 
        self.w = w
126
 
        self.h = h
127
 
        self.timeout_handler_id = gobject.timeout_add (Blinker.INTERVAL_MS, self.blinkDrawRectangle)
128
 
        gtk.main()
129
 
 
130
 
    def blinkDrawRectangle (self):
131
 
        import gtk.gdk
132
 
        display = gtk.gdk.display_get_default()
133
 
        screen = display.get_default_screen()
134
 
        rootWindow = screen.get_root_window()
135
 
        gc = rootWindow.new_gc()
136
 
 
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);
141
 
 
142
 
        self.count-=1
143
 
 
144
 
        if self.count <= 0:
145
 
            gtk.main_quit()
146
 
            return False
147
 
 
148
 
        return True
149
 
 
150
 
 
151
 
import sys
152
 
import gconf
153
 
gconfClient = gconf.client_get_default()
154
 
a11yGConfKey = '/desktop/gnome/interface/accessibility'
 
126
class Highlight (Gtk.Window):
 
127
 
 
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)
 
139
        self.show_all()
 
140
        self.move(x,y)
 
141
 
 
142
    def area_draw(self, widget, cr):
 
143
        cr.set_source_rgba(.0, .0, .0, 0.0)
 
144
        cr.set_operator(cairo.OPERATOR_SOURCE)
 
145
        cr.paint()
 
146
        cr.set_operator(cairo.OPERATOR_OVER)
 
147
        cr.set_source_rgb(0.9, 0.1, 0.1)
 
148
        cr.set_line_width(6)
 
149
        cr.rectangle(0, 0, self.get_size()[0], self.get_size()[1])
 
150
        cr.stroke()
 
151
 
 
152
class Blinker(object):
 
153
    INTERVAL_MS = 1000
 
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)
 
160
            self.main_loop.run()
 
161
        else:
 
162
            self.highlight_window.destroy()
 
163
 
 
164
    def destroyHighlight(self):
 
165
        self.highlight_window.destroy()
 
166
        self.main_loop.quit()
 
167
        return False
 
168
        
 
169
class Lock(object):
 
170
    """
 
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
 
176
    """
 
177
    def __init__(self, location='/tmp', lockname='dogtail_lockdir_', randomize=True):
 
178
        """
 
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.
 
181
        """
 
182
        self.lockdir = os.path.join(os.path.normpath(location), lockname)
 
183
        if randomize:
 
184
            self.lockdir = "%s%s" % (self.lockdir,self.__getPostfix())
 
185
 
 
186
    def lock(self):
 
187
        """
 
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. 
 
191
        """
 
192
        locked_msg = 'Dogtail lock: Already locked with the same lock'
 
193
        if not os.path.exists(self.lockdir):
 
194
            try:
 
195
                os.mkdir(self.lockdir)
 
196
                return self.lockdir
 
197
            except OSError, e:
 
198
                if e.errno == errno.EEXIST and os.path.isdir(self.lockdir):
 
199
                    raise OSError(locked_msg)
 
200
        else:
 
201
            raise OSError(locked_msg)
 
202
 
 
203
    def unlock(self):
 
204
        """
 
205
        Removes a lock. Will raise OSError exception if the lock was not present.
 
206
        Should be atomic on POSIX compliant systems.
 
207
        """
 
208
        import os #have to import here for situations when executed from __del__
 
209
        if os.path.exists(self.lockdir):
 
210
            try:
 
211
                os.rmdir(self.lockdir)
 
212
            except OSError, e:
 
213
                if e.erron == errno.EEXIST:
 
214
                    raise OSError('Dogtail unlock: lockdir removed elsewhere!')
 
215
        else:
 
216
            raise OSError('Dogtail unlock: not locked')
 
217
 
 
218
    def __del__(self):
 
219
        """
 
220
        Makes sure lock is removed when the process ends. Although not when killed indeed.
 
221
        """
 
222
        self.unlock()
 
223
 
 
224
    def __getPostfix(self):
 
225
        import random
 
226
        import string
 
227
        return ''.join(random.choice(string.letters + string.digits) for x in range(5))
 
228
        
 
229
 
 
230
a11yDConfKey = 'org.gnome.desktop.interface'
155
231
 
156
232
def isA11yEnabled():
157
233
    """
158
 
    Checks if accessibility is enabled via gconf.
 
234
    Checks if accessibility is enabled via DConf.
159
235
    """
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:
 
240
        envEnabled = False
 
241
    else: envEnabled = True
 
242
    return (dconfEnabled or envEnabled)
161
243
 
162
244
def bailBecauseA11yIsDisabled():
 
245
    if sys.argv[0].endswith("pydoc"): return
 
246
    try:
 
247
        if file("/proc/%s/cmdline" % os.getpid()).read().find('epydoc') != -1:
 
248
            return
 
249
    except: pass
163
250
    logger.log("Dogtail requires that Assistive Technology support be enabled. Aborting...")
164
251
    sys.exit(1)
165
252
 
166
253
def enableA11y():
167
254
    """
168
 
    Enables accessibility via gconf.
 
255
    Enables accessibility via GConf.
169
256
    """
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)
171
260
 
172
261
def checkForA11y():
173
262
    """
181
270
    user if it should be enabled if it is not already, then halts execution.
182
271
    """
183
272
    if isA11yEnabled(): return
184
 
    import gtk
185
 
    dialog = gtk.Dialog('Enable Assistive Technology Support?',
 
273
    from gi.repository import Gtk
 
274
    dialog = Gtk.Dialog('Enable Assistive Technology Support?',
186
275
                     None,
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?
191
280
 
192
281
Note that you will have to log out for the change to fully take effect.
193
282
    """.strip()
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...")
202
291
        enableA11y()
203
 
    elif result == gtk.RESPONSE_CLOSE:
 
292
    elif result == Gtk.ResponseType.CLOSE:
204
293
       bailBecauseA11yIsDisabled()
205
294
    dialog.destroy()
206
295