Coverage Report - orca.orca

ModuleCoverage %
orca.orca
43%
1
# Orca
2
#
3
# Copyright 2004-2007 Sun Microsystems Inc.
4
#
5
# This library is free software; you can redistribute it and/or
6
# modify it under the terms of the GNU Library General Public
7
# License as published by the Free Software Foundation; either
8
# version 2 of the License, or (at your option) any later version.
9
#
10
# This library is distributed in the hope that it will be useful,
11
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
# Library General Public License for more details.
14
#
15
# You should have received a copy of the GNU Library General Public
16
# License along with this library; if not, write to the
17
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18
# Boston, MA 02111-1307, USA.
19
20 1
"""The main module for the Orca screen reader."""
21
22 1
__id__        = "$Id: orca.py 2126 2007-03-06 21:35:17Z richb $"
23 1
__version__   = "$Revision: 2126 $"
24 1
__date__      = "$Date: 2007-03-06 13:35:17 -0800 (Tue, 06 Mar 2007) $"
25 1
__copyright__ = "Copyright (c) 2005-2007 Sun Microsystems Inc."
26 1
__license__   = "LGPL"
27
28
# We're going to force the name of the app to "orca" so pygtk
29
# will end up showing us as "orca" to the AT-SPI.  If we don't
30
# do this, the name can end up being "-c".  See bug 364452 at
31
# http://bugzilla.gnome.org/show_bug.cgi?id=364452 for more
32
# information.
33
#
34 1
import sys
35 1
sys.argv[0] = "orca"
36
37 1
try:
38
    # This can fail due to gtk not being available.  We want to
39
    # be able to recover from that if possible.  The main driver
40
    # for this is to allow "orca --text-setup" to work even if
41
    # the desktop is not running.
42
    #
43 1
    import gtk
44 0
except:
45 0
    pass
46
47 1
import getopt
48 1
import os
49 1
import signal
50 1
import string
51 1
import time
52
53 1
import atspi
54 1
import braille
55 1
import debug
56 1
import httpserver
57 1
import keynames
58 1
import keybindings
59 1
import mag
60 1
import orca_state
61 1
import platform
62 1
import rolenames
63 1
import settings
64 1
import speech
65
66 1
import threading
67
68 1
from input_event import BrailleEvent
69 1
from input_event import KeyboardEvent
70 1
from input_event import MouseButtonEvent
71 1
from input_event import InputEventHandler
72
73 1
from orca_i18n import _           # for gettext support
74
75
# The user-settings module (see loadUserSettings).
76
#
77 1
_userSettings = None
78
79
# Command line options that override any other settings.
80
#
81 1
_commandLineSettings = {}
82
83
########################################################################
84
#                                                                      #
85
# METHODS FOR HANDLING PRESENTATION MANAGERS                           #
86
#                                                                      #
87
# A presentation manager is what reacts to AT-SPI object events as     #
88
# well as user input events (keyboard and Braille) to present info     #
89
# to the user.                                                         #
90
#                                                                      #
91
########################################################################
92
93
# The known presentation managers (set up in start())
94
#
95 1
_PRESENTATION_MANAGERS = None
96
97
# The current presentation manager, which is an index into the
98
# _PRESENTATION_MANAGERS list.
99
#
100 1
_currentPresentationManager = -1
101
102 1
def _switchToPresentationManager(index):
103
    """Switches to the given presentation manager.
104
105
    Arguments:
106
    - index: an index into _PRESENTATION_MANAGERS
107
    """
108
109 0
    global _currentPresentationManager
110
111 1
    if _currentPresentationManager >= 0:
112 0
        _PRESENTATION_MANAGERS[_currentPresentationManager].deactivate()
113
114 1
    _currentPresentationManager = index
115
116
    # Wrap the presenter index around.
117
    #
118 1
    if _currentPresentationManager >= len(_PRESENTATION_MANAGERS):
119 0
        _currentPresentationManager = 0
120 1
    elif _currentPresentationManager < 0:
121 0
        _currentPresentationManager = len(_PRESENTATION_MANAGERS) - 1
122
123 1
    _PRESENTATION_MANAGERS[_currentPresentationManager].activate()
124
125 1
def _switchToNextPresentationManager(script=None, inputEvent=None):
126
    """Switches to the next presentation manager.
127
128
    Arguments:
129
    - inputEvent: the InputEvent instance that caused this to be called.
130
131
    Returns True indicating the event should be consumed.
132
    """
133
134 0
    _switchToPresentationManager(_currentPresentationManager + 1)
135 0
    return True
136
137
########################################################################
138
#                                                                      #
139
# METHODS TO HANDLE APPLICATION LIST AND FOCUSED OBJECTS               #
140
#                                                                      #
141
########################################################################
142
143 1
def setLocusOfFocus(event, obj, notifyPresentationManager=True):
144
    """Sets the locus of focus (i.e., the object with visual focus) and
145
    notifies the current presentation manager of the change.
146
147
    Arguments:
148
    - event: if not None, the Event that caused this to happen
149
    - obj: the Accessible with the new locus of focus.
150
    - notifyPresentationManager: if True, propagate this event
151
    """
152
153 1317
    if obj == orca_state.locusOfFocus:
154 315
        return
155
156 1002
    oldLocusOfFocus = orca_state.locusOfFocus
157 1002
    if oldLocusOfFocus and not oldLocusOfFocus.valid:
158 0
        oldLocusOfFocus = None
159
160 1002
    orca_state.locusOfFocus = obj
161 1002
    if orca_state.locusOfFocus and not orca_state.locusOfFocus.valid:
162 0
        orca_state.locusOfFocus = None
163
164 1002
    if orca_state.locusOfFocus:
165 970
        appname = ""
166 970
        if not orca_state.locusOfFocus.app:
167 3
            appname = "None"
168
        else:
169 967
            appname = "'" + orca_state.locusOfFocus.app.name + "'"
170
171 970
        debug.println(debug.LEVEL_FINE,
172 970
                      "LOCUS OF FOCUS: app=%s name='%s' role='%s'" \
173
                      % (appname,
174
                         orca_state.locusOfFocus.name,
175
                         orca_state.locusOfFocus.role))
176
177 970
        if event:
178 969
            debug.println(debug.LEVEL_FINE,
179 969
                          "                event='%s'" % event.type)
180
        else:
181 1
            debug.println(debug.LEVEL_FINE,
182 1
                          "                event=None")
183
    else:
184 32
        if event:
185 32
            debug.println(debug.LEVEL_FINE,
186 32
                          "LOCUS OF FOCUS: None event='%s'" % event.type)
187
        else:
188 0
            debug.println(debug.LEVEL_FINE,
189 0
                          "LOCUS OF FOCUS: None event=None")
190
191 1002
    if notifyPresentationManager and _currentPresentationManager >= 0:
192 960
        _PRESENTATION_MANAGERS[_currentPresentationManager].\
193
            locusOfFocusChanged(event,
194 960
                                oldLocusOfFocus,
195 960
                                orca_state.locusOfFocus)
196
197 1
def visualAppearanceChanged(event, obj):
198
    """Called (typically by scripts) when the visual appearance of an object
199
    changes and notifies the current presentation manager of the change.  This
200
    method should not be called for objects whose visual appearance changes
201
    solely because of focus -- setLocusOfFocus is used for that.  Instead, it
202
    is intended mostly for objects whose notional 'value' has changed, such as
203
    a checkbox changing state, a progress bar advancing, a slider moving, text
204
    inserted, caret moved, etc.
205
206
    Arguments:
207
    - event: if not None, the Event that caused this to happen
208
    - obj: the Accessible whose visual appearance changed.
209
    """
210
211 685
    if _currentPresentationManager >= 0:
212 685
        _PRESENTATION_MANAGERS[_currentPresentationManager].\
213
            visualAppearanceChanged(event, obj)
214
215 1
def _onChildrenChanged(e):
216
    """Tracks children-changed events on the desktop to determine when
217
    apps start and stop.
218
219
    Arguments:
220
    - e: at-spi event from the at-api registry
221
    """
222
223 2450
    registry = atspi.Registry()
224 2450
    if e.source == registry.desktop:
225
226
        # If the desktop is empty, the user has logged out-- shutdown Orca
227
        #
228 96
        try:
229 96
            if registry.desktop.childCount == 0:
230 0
                speech.speak(_("User logged out - shutting down."))
231 0
                shutdown()
232 0
                return
233 0
        except: # could be a CORBA.COMM_FAILURE
234 0
            debug.printException(debug.LEVEL_FINEST)
235 0
            shutdown()
236 0
            return
237
238 1
def _onMouseButton(e):
239
    """Tracks mouse button events, stopping any speech in progress.
240
241
    Arguments:
242
    - e: at-spi event from the at-api registry
243
    """
244
245 4
    event = atspi.Event(e)
246 4
    orca_state.lastInputEvent = MouseButtonEvent(event)
247
248
    # A mouse button event looks like: mouse:button:1p, where the
249
    # number is the button number and the 'p' is either 'p' or 'r',
250
    # meaning pressed or released.  We only want to stop speech on
251
    # button presses.
252
    #
253 4
    if event.type.endswith("p"):
254 2
        speech.stop()
255
256
########################################################################
257
#                                                                      #
258
# Keyboard Event Recording Support                                     #
259
#                                                                      #
260
########################################################################
261
262 1
_recordingKeystrokes = False
263 1
_keystrokesFile = None
264
265 1
def _closeKeystrokeWindowAndRecord(entry, window):
266 0
    global _keystrokesFile
267 0
    window.destroy()
268 0
    entry_text = entry.get_text()
269 0
    _keystrokesFile = open(entry_text, 'w')
270
271 1
def _closeKeystrokeWindowAndCancel(window):
272 0
    global _recordingKeystrokes
273 0
    window.destroy()
274 0
    _recordingKeystrokes = False
275
276 1
def toggleKeystrokeRecording(script=None, inputEvent=None):
277
    """Toggles the recording of keystrokes on and off.  When the
278
    user presses the magic key (Pause), Orca will pop up a window
279
    requesting a filename.  When the user presses the close button,
280
    Orca will start recording keystrokes to the file and will continue
281
    recording them until the user presses the magic key again.
282
283
    This functionality is used primarily to help gather keystroke
284
    information for regression testing purposes.  The keystrokes are
285
    recorded in such a way that they can be played back via the
286
    src/tools/play_keystrokes.py utility.
287
288
    Arguments:
289
    - inputEvent: the key event (if any) which caused this to be called.
290
291
    Returns True indicating the event should be consumed.
292
    """
293
294 0
    global _recordingKeystrokes
295 0
    global _keystrokesFile
296
297 0
    if _recordingKeystrokes:
298
        # If the filename entry window is still up, we don't have a file
299
        # yet.
300
        #
301 0
        if _keystrokesFile:
302 0
            _keystrokesFile.close()
303 0
            _keystrokesFile = None
304 0
            _recordingKeystrokes = False
305
    else:
306 0
        _recordingKeystrokes = True
307 0
        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
308 0
        window.set_title("Keystroke Filename")
309
310 0
        vbox = gtk.VBox(False, 0)
311 0
        window.add(vbox)
312 0
        vbox.show()
313
314 0
        entry = gtk.Entry()
315 0
        entry.set_max_length(50)
316 0
        entry.set_editable(True)
317 0
        entry.set_text("keystrokes.txt")
318 0
        entry.select_region(0, len(entry.get_text()))
319
        # For now, do not allow "Return" to close the window - the reason
320
        # for this is that the key press closes the window, and the key
321
        # release will end up getting recorded.
322
        #
323
        #entry.connect("activate", _closeKeystrokeWindow, window)
324 0
        vbox.pack_start(entry, True, True, 0)
325 0
        entry.show()
326
327 0
        hbox = gtk.HBox(False, 0)
328 0
        vbox.add(hbox)
329 0
        hbox.show()
330
331 0
        ok = gtk.Button(stock=gtk.STOCK_OK)
332 0
        ok.connect("clicked", lambda w: _closeKeystrokeWindowAndRecord(\
333
            entry, \
334 0
            window))
335
336 0
        cancel = gtk.Button(stock=gtk.STOCK_CANCEL)
337 0
        cancel.connect("clicked", lambda w: _closeKeystrokeWindowAndCancel(\
338
            window))
339
340 0
        vbox.pack_start(cancel, True, True, 0)
341 0
        vbox.pack_start(ok, True, True, 0)
342
343 0
        ok.set_flags(gtk.CAN_DEFAULT)
344 0
        ok.grab_default()
345 0
        ok.show()
346 0
        cancel.show()
347
348 0
        window.set_modal(True)
349 0
        window.show()
350 0
    return True
351
352
########################################################################
353
#                                                                      #
354
# DEBUG support.                                                       #
355
#                                                                      #
356
########################################################################
357
358 1
def cycleDebugLevel(script=None, inputEvent=None):
359
    """Cycles the debug level at run time.
360
361
    Arguments:
362
    - inputEvent: the InputEvent instance that caused this to be called.
363
364
    Returns True indicating the event should be consumed.
365
    """
366
367 1
def cycleDebugLevel(script=None, inputEvent=None):
368 0
    global _debugLevel
369
370 0
    level = debug.debugLevel
371
372 0
    if level == debug.LEVEL_ALL:
373 0
        level = debug.LEVEL_FINEST
374 0
    elif level == debug.LEVEL_FINEST:
375 0
        level = debug.LEVEL_FINER
376 0
    elif level == debug.LEVEL_FINER:
377 0
        level = debug.LEVEL_FINE
378 0
    elif level == debug.LEVEL_FINE:
379 0
        level = debug.LEVEL_CONFIGURATION
380 0
    elif level == debug.LEVEL_CONFIGURATION:
381 0
        level = debug.LEVEL_INFO
382 0
    elif level == debug.LEVEL_INFO:
383 0
        level = debug.LEVEL_WARNING
384 0
    elif level == debug.LEVEL_WARNING:
385 0
        level = debug.LEVEL_SEVERE
386 0
    elif level == debug.LEVEL_SEVERE:
387 0
        level = debug.LEVEL_OFF
388 0
    elif level == debug.LEVEL_OFF:
389 0
        level = debug.LEVEL_ALL
390
391 0
    debug.debugLevel = level
392
393 0
    if level == debug.LEVEL_ALL:
394 0
        speech.speak(_("Debug level all."))
395 0
    elif level == debug.LEVEL_FINEST:
396 0
        speech.speak(_("Debug level finest."))
397 0
    elif level == debug.LEVEL_FINER:
398 0
        speech.speak(_("Debug level finer."))
399 0
    elif level == debug.LEVEL_FINE:
400 0
        speech.speak(("Debug level fine."))
401 0
    elif level == debug.LEVEL_CONFIGURATION:
402 0
        speech.speak("Debug level configuration.")
403 0
    elif level == debug.LEVEL_INFO:
404 0
        speech.speak("Debug level info.")
405 0
    elif level == debug.LEVEL_WARNING:
406 0
        speech.speak("Debug level warning.")
407 0
    elif level == debug.LEVEL_SEVERE:
408 0
        speech.speak("Debug level severe.")
409 0
    elif level == debug.LEVEL_OFF:
410 0
        speech.speak("Debug level off.")
411
412 0
    return True
413
414
########################################################################
415
#                                                                      #
416
# METHODS FOR PRE-PROCESSING AND MASSAGING KEYBOARD EVENTS.            #
417
#                                                                      #
418
# All keyboard events are funnelled through here first.  Orca itself   #
419
# might have global keybindings (e.g., to switch between presenters),  #
420
# but it will typically pass the event onto the currently active       #
421
# active presentation manager.                                         #
422
#                                                                      #
423
########################################################################
424
425
# Keybindings that Orca itself cares about.
426
#
427 1
_keyBindings = None
428
429
# True if the orca modifier key is currently pressed.
430
#
431 1
_orcaModifierPressed = False
432
433 1
def _isPrintableKey(event_string):
434
    """Return an indication of whether this is an alphanumeric or
435
       punctuation key.
436
437
    Arguments:
438
    - event: the event string
439
440
    Returns True if this is an alphanumeric or punctuation key.
441
    """
442
443 0
    if event_string == "space":
444 0
        reply = True
445
    else:
446 0
        reply = event_string in string.printable
447 0
    debug.println(debug.LEVEL_FINEST,
448 0
                  "orca._echoPrintableKey: returning: %s" % reply)
449 0
    return reply
450
451 1
def _isModifierKey(event_string):
452
    """Return an indication of whether this is a modifier key.
453
454
    Arguments:
455
    - event: the event string
456
457
    Returns True if this is a modifier key
458
    """
459
460
    # [[[TODO:richb - the Fn key on my laptop doesn't seem to generate an
461
    #    event.]]]
462
463 0
    modifierKeys = [ 'Alt_L', 'Alt_R', 'Control_L', 'Control_R', \
464
                     'Shift_L', 'Shift_R', 'Meta_L', 'Meta_R' ]
465 0
    modifierKeys.extend(settings.orcaModifierKeys)
466
467 0
    reply = event_string in modifierKeys
468 0
    debug.println(debug.LEVEL_FINEST,
469 0
                  "orca._echoModifierKey: returning: %s" % reply)
470 0
    return reply
471
472 1
def _isLockingKey(event_string):
473
    """Return an indication of whether this is a locking key.
474
475
    Arguments:
476
    - event: the event string
477
478
    Returns True if this is a locking key.
479
    """
480
481 0
    lockingKeys = [ "Caps_Lock", "Num_Lock", "Scroll_Lock" ]
482
483 0
    reply = event_string in lockingKeys \
484
            and not event_string in settings.orcaModifierKeys
485 0
    debug.println(debug.LEVEL_FINEST,
486 0
                  "orca._echoLockingKey: returning: %s" % reply)
487 0
    return reply
488
489 1
def _isFunctionKey(event_string):
490
    """Return an indication of whether this is a function key.
491
492
    Arguments:
493
    - event: the event string
494
495
    Returns True if this is a function key.
496
    """
497
498
    # [[[TODO:richb - what should be done about the function keys on the left
499
    #    side of my Sun keyboard and the other keys (like Scroll Lock), which
500
    #    generate "Fn" key events?]]]
501
502 0
    functionKeys = [ "F1", "F2", "F3", "F4", "F5", "F6",
503
                     "F7", "F8", "F9", "F10", "F11", "F12" ]
504
505 0
    reply = event_string in functionKeys
506 0
    debug.println(debug.LEVEL_FINEST,
507 0
                  "orca._echoFunctionKey: returning: %s" % reply)
508 0
    return reply
509
510 1
def _isActionKey(event_string):
511
    """Return an indication of whether this is an action key.
512
513
    Arguments:
514
    - event: the event string
515
516
    Returns True if this is an action key.
517
    """
518
519 0
    actionKeys = [ "Return", "Escape", "Tab", "BackSpace", "Delete",
520
                   "Page_Up", "Page_Down", "Home", "End" ]
521
522 0
    reply = event_string in actionKeys
523 0
    debug.println(debug.LEVEL_FINEST,
524 0
                  "orca._echoActionKey: returning: %s" % reply)
525 0
    return reply
526
527 1
def _keyEcho(event):
528
    """If the keyEcho setting is enabled, check to see what type of key
529
    event it is and echo it via speech, if the user wants that type of
530
    key echoed.
531
532
    Uppercase keys will be spoken using the "uppercase" voice style,
533
    whereas lowercase keys will be spoken using the "default" voice style.
534
535
    Arguments:
536
    - event: an AT-SPI DeviceEvent
537
    """
538
539
    # If this keyboard event was for an object like a password text
540
    # field, then don't echo it.
541
    #
542 1638
    if orca_state.locusOfFocus \
543
        and (orca_state.locusOfFocus.role == rolenames.ROLE_PASSWORD_TEXT):
544 0
        return
545
546 1638
    event_string = event.event_string
547 1638
    debug.println(debug.LEVEL_FINEST,
548 1638
                  "orca._keyEcho: string to echo: %s" % event_string)
549
550 1638
    voices = settings.voices
551 1638
    voice = voices[settings.DEFAULT_VOICE]
552
553 1638
    lockState = None
554
555
    # If key echo is enabled, then check to see what type of key event
556
    # it is and echo it via speech, if the user wants that type of key
557
    # echoed.
558
    #
559 1638
    if settings.enableKeyEcho:
560
561 0
        if _isPrintableKey(event_string):
562 0
            if not settings.enablePrintableKeys:
563 0
                return
564
565 0
            if event_string.isupper():
566 0
                voice = voices[settings.UPPERCASE_VOICE]
567
568 0
        elif _isModifierKey(event_string):
569 0
            if not settings.enableModifierKeys:
570 0
                return
571
572 0
        elif _isLockingKey(event_string):
573 0
            if not settings.enableLockingKeys:
574 0
                return
575
576 0
            modifiers = event.modifiers
577 0
            if event_string == _("Caps_Lock"):
578 0
                if modifiers & (1 << atspi.Accessibility.MODIFIER_SHIFTLOCK):
579 0
                    lockState = _(" off")
580
                else:
581 0
                    lockState = _(" on")
582
583 0
            elif event_string == _("Num_Lock"):
584
                # [[[TODO: richb - we are not getting a correct modifier
585
                # state value returned when Num Lock is turned off.
586
                # Commenting out the speaking of the bogus on/off state
587
                # until this can be fixed.]]]
588
                #
589
                #if modifiers & (1 << atspi.Accessibility.MODIFIER_NUMLOCK):
590
                #    event_string += _(" off")
591
                #else:
592
                #    event_string += _(" on")
593 0
                pass
594
595 0
        elif _isFunctionKey(event_string):
596 0
            if not settings.enableFunctionKeys:
597 0
                return
598
599 0
        elif _isActionKey(event_string):
600 0
            if not settings.enableActionKeys:
601 0
                return
602
603
        else:
604 0
            debug.println(debug.LEVEL_FINEST,
605 0
                  "orca._keyEcho: event string not handled: %s" % event_string)
606 0
            return
607
608
        # Check to see if there are localized words to be spoken for
609
        # this key event.
610
        #
611 0
        event_string = keynames.getKeyName(event_string)
612
613 0
        if lockState:
614 0
            event_string += lockState
615
616 0
        debug.println(debug.LEVEL_FINEST,
617 0
                      "orca._keyEcho: speaking: %s" % event_string)
618
619
        # We keep track of the time as means to let others know that
620
        # we are probably echoing a key and should not be interrupted.
621
        #
622 0
        orca_state.lastKeyEchoTime = time.time()
623
624 0
        speech.speak(event_string, voice)
625
626 1
def _processKeyCaptured(event):
627
    """Called when a new key event arrives and orca_state.capturingKeys=True.
628
    (used for key bindings redefinition)
629
    """
630
631 0
    if event.type == 0:
632 0
        if _isModifierKey(event.event_string) \
633
               or event.event_string == "Return":
634 0
            pass
635 0
        elif event.event_string == "Escape":
636 0
            orca_state.capturingKeys = False
637
        else:
638 0
            speech.speak(_("Key captured: %s. Press enter to confirm.") \
639
                         % str(event.event_string))
640 0
            orca_state.lastCapturedKey = event
641
    else:
642 0
        pass
643 0
    return False
644
645 1
def _processKeyboardEvent(event):
646
    """The primary key event handler for Orca.  Keeps track of various
647
    attributes, such as the lastInputEvent.  Also calls keyEcho as well
648
    as any local keybindings before passing the event on to the active
649
    presentation manager.  This method is called synchronously from the
650
    AT-SPI registry and should be performant.  In addition, it
651
    must return True if it has consumed the event (and False if not).
652
653
    Arguments:
654
    - event: an AT-SPI DeviceEvent
655
656
    Returns True if the event should be consumed.
657
    """
658 0
    global _orcaModifierPressed
659
660 3257
    orca_state.lastInputEventTimestamp = event.timestamp
661
662
    # Log the keyboard event for future playback, if desired.
663
    # Note here that the key event_string being output is
664
    # exactly what we received.  The KeyboardEvent object,
665
    # however, will translate the event_string for control
666
    # characters to their upper case ASCII equivalent.
667
    #
668 3257
    string = atspi.KeystrokeListener.keyEventToString(event)
669 3257
    if _recordingKeystrokes and _keystrokesFile \
670
       and (event.event_string != "Pause") \
671
       and (event.event_string != "F21"):
672 0
        _keystrokesFile.write(string + "\n")
673 3257
    debug.printInputEvent(debug.LEVEL_FINE, string)
674
675 3257
    keyboardEvent = KeyboardEvent(event)
676
677
    # See if this is one of our special Orca modifiers (e.g., "Insert")
678
    #
679 3257
    orcaModifierKeys = settings.orcaModifierKeys
680 3257
    isOrcaModifier = orcaModifierKeys.count(keyboardEvent.event_string) > 0
681
682 3257
    if event.type == atspi.Accessibility.KEY_PRESSED_EVENT:
683
        # Key presses always interrupt speech.
684
        #
685 1638
        speech.stop()
686
687
        # If learn mode is enabled, it will echo the keys.
688
        #
689 1638
        if not settings.learnModeEnabled:
690 1638
            _keyEcho(keyboardEvent)
691
692
        # We treat the Insert key as a modifier - so just swallow it and
693
        # set our internal state.
694
        #
695 1638
        if isOrcaModifier:
696 10
            _orcaModifierPressed = True
697
698 1619
    elif isOrcaModifier \
699
        and (keyboardEvent.type == atspi.Accessibility.KEY_RELEASED_EVENT):
700 6
        _orcaModifierPressed = False
701
702 3257
    if _orcaModifierPressed:
703 110
        keyboardEvent.modifiers |= (1 << settings.MODIFIER_ORCA)
704
705
    # Orca gets first stab at the event.  Then, the presenter gets
706
    # a shot. [[[TODO: WDW - might want to let the presenter try first?
707
    # The main reason this is staying as is is that we may not want
708
    # scripts to override fundamental Orca key bindings.]]]
709
    #
710 3257
    consumed = False
711 3257
    try:
712 3257
        if orca_state.capturingKeys:
713 0
            _processKeyCaptured(keyboardEvent)
714
        else:
715 3257
            consumed = _keyBindings.consumeKeyboardEvent(None, keyboardEvent)
716 3257
            if (not consumed) and (_currentPresentationManager >= 0):
717 3257
                consumed = _PRESENTATION_MANAGERS[_currentPresentationManager].\
718
                           processKeyboardEvent(keyboardEvent)
719 3257
            if (not consumed) and settings.learnModeEnabled:
720 0
                if keyboardEvent.type \
721
                    == atspi.Accessibility.KEY_PRESSED_EVENT:
722 0
                    clickCount = orca_state.activeScript.getClickCount(\
723
                                                orca_state.lastInputEvent,
724 0
                                                keyboardEvent)
725 0
                    if clickCount == 2:
726 0
                        orca_state.activeScript.phoneticSpellCurrentItem(\
727
                            keyboardEvent.event_string)
728
                    else:
729
                        # Check to see if there are localized words to be
730
                        # spoken for this key event.
731
                        #
732 0
                        braille.displayMessage(keyboardEvent.event_string)
733 0
                        event_string = keyboardEvent.event_string
734 0
                        event_string = keynames.getKeyName(event_string)
735 0
                        speech.speak(event_string)
736 0
                consumed = True
737 0
    except:
738 0
        debug.printException(debug.LEVEL_SEVERE)
739
740 3257
    orca_state.lastInputEvent = keyboardEvent
741
742 3257
    return consumed or isOrcaModifier
743
744
########################################################################
745
#                                                                      #
746
# METHODS FOR PRE-PROCESSING AND MASSAGING BRAILLE EVENTS.             #
747
#                                                                      #
748
########################################################################
749
750 1
def _processBrailleEvent(command):
751
    """Called whenever a  key is pressed on the Braille display.
752
753
    Arguments:
754
    - command: the BrlAPI command for the key that was pressed.
755
756
    Returns True if the event was consumed; otherwise False
757
    """
758
759
    # [[[TODO: WDW - probably should add braille bindings to this module.]]]
760
761 0
    consumed = False
762
763
    # Braille key presses always interrupt speech.
764
    #
765 0
    speech.stop()
766
767 0
    event = BrailleEvent(command)
768 0
    orca_state.lastInputEvent = event
769
770 0
    try:
771 0
        consumed = _PRESENTATION_MANAGERS[_currentPresentationManager].\
772
                   processBrailleEvent(event)
773 0
    except:
774 0
        debug.printException(debug.LEVEL_SEVERE)
775
776 0
    if (not consumed) and settings.learnModeEnabled:
777 0
        consumed = True
778
779 0
    return consumed
780
781
########################################################################
782
#                                                                      #
783
# METHODS FOR HANDLING INITIALIZATION, SHUTDOWN, AND USE.              #
784
#                                                                      #
785
########################################################################
786
787 1
def _toggleSilenceSpeech(script=None, inputEvent=None):
788
    """Toggle the silencing of speech.
789
790
    Returns True to indicate the input event has been consumed.
791
    """
792 0
    speech.stop()
793 0
    if settings.silenceSpeech:
794 0
        settings.silenceSpeech = False
795 0
        speech.speak(_("Speech enabled."))
796
    else:
797 0
        speech.speak(_("Speech disabled."))
798 0
        settings.silenceSpeech = True
799 0
    return True
800
801 1
def loadUserSettings(script=None, inputEvent=None):
802
    """Loads (and reloads) the user settings module, reinitializing
803
    things such as speech if necessary.
804
805
    Returns True to indicate the input event has been consumed.
806
    """
807
808 0
    global _userSettings
809
810
    # Shutdown the output drivers and give them a chance to die.
811
    #
812 1
    httpserver.shutdown()
813 1
    speech.shutdown()
814 1
    braille.shutdown()
815 1
    mag.shutdown()
816
817 1
    if _currentPresentationManager >= 0:
818 0
        _PRESENTATION_MANAGERS[_currentPresentationManager].deactivate()
819
820 1
    time.sleep(1)
821
822 1
    reloaded = False
823 1
    if _userSettings:
824 0
        try:
825 0
            reload(_userSettings)
826 0
            reloaded = True
827 0
        except ImportError:
828 0
            debug.printException(debug.LEVEL_FINEST)
829
    else:
830 1
        try:
831 1
            _userSettings = __import__("user-settings")
832 0
        except ImportError:
833 0
            debug.printException(debug.LEVEL_FINEST)
834
835
    # If any settings were added to the command line, they take
836
    # precedence over everything else.
837
    #
838 1
    for key in _commandLineSettings:
839 0
        settings.__dict__[key] = _commandLineSettings[key]
840
841 1
    if settings.enableSpeech:
842 1
        try:
843 1
            speech.init()
844 1
            if reloaded:
845 0
                speech.speak(_("Orca user settings reloaded."))
846 1
            debug.println(debug.LEVEL_CONFIGURATION,
847 1
                          "Speech module has been initialized.")
848 0
        except:
849 0
            debug.printException(debug.LEVEL_SEVERE)
850 0
            debug.println(debug.LEVEL_SEVERE,
851 0
                          "Could not initialize connection to speech.")
852
    else:
853 0
        debug.println(debug.LEVEL_CONFIGURATION,
854 0
                      "Speech module has NOT been initialized.")
855
856 1
    if settings.enableBraille:
857 1
        try:
858 1
            braille.init(_processBrailleEvent, settings.tty)
859 1
        except:
860 1
            debug.printException(debug.LEVEL_WARNING)
861 1
            debug.println(debug.LEVEL_WARNING,
862 1
                          "Could not initialize connection to braille.")
863
864 1
    if settings.enableMagnifier:
865 0
        try:
866 0
            mag.init()
867 0
            debug.println(debug.LEVEL_CONFIGURATION,
868 0
                          "Magnification module has been initialized.")
869 0
        except:
870 0
            debug.printException(debug.LEVEL_SEVERE)
871 0
            debug.println(debug.LEVEL_SEVERE,
872 0
                          "Could not initialize connection to magnifier.")
873
    else:
874 1
        debug.println(debug.LEVEL_CONFIGURATION,
875 1
                      "Magnification module has NOT been initialized.")
876
877 3
    for keyName in settings.orcaModifierKeys:
878 2
        if keyName == "Caps_Lock":
879 0
            os.system('xmodmap -e "clear Lock"')
880
881 1
    if _currentPresentationManager >= 0:
882 0
        _PRESENTATION_MANAGERS[_currentPresentationManager].activate()
883
884 1
    _showMainWindowGUI()
885
886 1
    httpserver.init()
887
888 1
    return True
889
890 1
def _showPreferencesGUI(script=None, inputEvent=None):
891
    """Displays the user interace to configure Orca and set up
892
    user preferences using a GUI.
893
894
    Returns True to indicate the input event has been consumed.
895
    """
896
897 1
    try:
898 1
        module = __import__(settings.guiPreferencesModule,
899 1
                            globals(),
900 1
                            locals(),
901 1
                            [''])
902 1
        module.showPreferencesUI()
903 1
    except:
904 1
        debug.printException(debug.LEVEL_SEVERE)
905 1
        pass
906
907 1
    return True
908
909 1
def _showMainWindowGUI(script=None, inputEvent=None):
910
    """Displays the Orca main window.
911
912
    Returns True to indicate the input event has been consumed.
913
    """
914
915 1
    try:
916 1
        module = __import__(settings.mainWindowModule,
917 1
                            globals(),
918 1
                            locals(),
919 1
                            [''])
920 1
        if settings.showMainWindow:
921 1
            module.showMainUI()
922
        else:
923 0
            module.hideMainUI()
924 0
    except:
925 0
        debug.printException(debug.LEVEL_SEVERE)
926 0
        pass
927
928 1
    return True
929
930 1
def _showPreferencesConsole(script=None, inputEvent=None):
931
    """Displays the user interace to configure Orca and set up
932
    user preferences via a command line interface.
933
934
    Returns True to indicate the input event has been consumed.
935
    """
936
937 0
    try:
938 0
        module = __import__(settings.consolePreferencesModule,
939 0
                            globals(),
940 0
                            locals(),
941 0
                            [''])
942 0
        module.showPreferencesUI()
943 0
    except:
944 0
        debug.printException(debug.LEVEL_SEVERE)
945 0
        pass
946
947 0
    return True
948
949 1
def _showQuitGUI(script=None, inputEvent=None):
950
    """Displays the user interace to quit Orca.
951
952
    Returns True to indicate the input event has been consumed.
953
    """
954
955 1
    try:
956 1
        module = __import__(settings.quitModule,
957 1
                            globals(),
958 1
                            locals(),
959 1
                            [''])
960 1
        module.showQuitUI()
961 0
    except:
962 0
        debug.printException(debug.LEVEL_SEVERE)
963 0
        pass
964
965 1
    return True
966
967 1
def _showFindGUI(script=None, inputEvent=None):
968
    """Displays the user interace to perform an Orca Find.
969
970
    Returns True to indicate the input event has been consumed.
971
    """
972
973 0
    try:
974 0
        module = __import__(settings.findModule,
975 0
                            globals(),
976 0
                            locals(),
977 0
                            [''])
978 0
        module.showFindUI()
979 0
    except:
980 0
        debug.printException(debug.LEVEL_SEVERE)
981 0
        pass
982
983
# If True, this module has been initialized.
984
#
985 1
_initialized = False
986
987 1
def init(registry):
988
    """Initialize the orca module, which initializes speech, braille,
989
    and mag modules.  Also builds up the application list, registers
990
    for AT-SPI events, and creates scripts for all known applications.
991
992
    Returns True if the initialization procedure has run, or False if this
993
    module has already been initialized.
994
    """
995
996 0
    global _initialized
997 0
    global _keyBindings
998
999 1
    if _initialized:
1000 0
        return False
1001
1002
    # Do not hang on initialization if we can help it.
1003
    #
1004 1
    if settings.timeoutCallback and (settings.timeoutTime > 0):
1005 1
        signal.signal(signal.SIGALRM, settings.timeoutCallback)
1006 1
        signal.alarm(settings.timeoutTime)
1007
1008
    # Note that we have moved the Orca specific keybindings to the default
1009
    # script, so _keyBindings is currently empty. The logic is retained
1010
    # here, just in case we wish to reinstate them in the future.
1011
    #
1012 1
    _keyBindings = keybindings.KeyBindings()
1013
1014
    # Create and load an app's script when it is added to the desktop
1015
    #
1016 1
    registry.registerEventListener(_onChildrenChanged,
1017 1
                                   "object:children-changed:")
1018
1019
    # We also want to stop speech when a mouse button is pressed.
1020
    #
1021 1
    registry.registerEventListener(_onMouseButton,
1022 1
                                   "mouse:button")
1023
1024 1
    loadUserSettings()
1025
1026 1
    registry.registerKeystrokeListeners(_processKeyboardEvent)
1027
1028 1
    if settings.timeoutCallback and (settings.timeoutTime > 0):
1029 1
        signal.alarm(0)
1030
1031 1
    _initialized = True
1032 1
    return True
1033
1034 1
def start(registry):
1035
    """Starts Orca.
1036
    """
1037
1038 0
    global _PRESENTATION_MANAGERS
1039
1040 1
    if not _initialized:
1041 0
        init(registry)
1042
1043
    # Do not hang on startup if we can help it.
1044
    #
1045 1
    if settings.timeoutCallback and (settings.timeoutTime > 0):
1046 1
        signal.signal(signal.SIGALRM, settings.timeoutCallback)
1047 1
        signal.alarm(settings.timeoutTime)
1048
1049 1
    try:
1050 1
        speech.speak(_("Welcome to Orca."))
1051 1
        braille.displayMessage(_("Welcome to Orca."))
1052 0
    except:
1053 0
        debug.printException(debug.LEVEL_SEVERE)
1054
1055 1
    if not _PRESENTATION_MANAGERS:
1056
1057
        # [[[WDW - comment out hierarchical_presenter for now.  It
1058
        # relies on the list of known applications, and we've disabled
1059
        # that due to a hang in a call to getChildAtIndex in
1060
        # Script.getKnownApplications.]]]
1061
        #
1062
        #import focus_tracking_presenter
1063
        #import hierarchical_presenter
1064
        #_PRESENTATION_MANAGERS = \
1065
        #    [focus_tracking_presenter.FocusTrackingPresenter(),
1066
        #     hierarchical_presenter.HierarchicalPresenter()]
1067
1068 1
        import focus_tracking_presenter
1069 1
        _PRESENTATION_MANAGERS = \
1070
            [focus_tracking_presenter.FocusTrackingPresenter()]
1071
1072 1
    _switchToPresentationManager(0) # focus_tracking_presenter
1073
1074 1
    if settings.timeoutCallback and (settings.timeoutTime > 0):
1075 1
        signal.alarm(0)
1076
1077 1
    registry.start()
1078
1079 1
def abort(exitCode=1):
1080 0
    os._exit(exitCode)
1081
1082 1
def timeout(signum=None, frame=None):
1083 0
    debug.println(debug.LEVEL_SEVERE,
1084 0
                  "TIMEOUT: something has hung.  Aborting.")
1085 0
    debug.printStack(debug.LEVEL_ALL)
1086 0
    abort(50)
1087
1088 1
def shutdown(script=None, inputEvent=None):
1089
    """Exits Orca.  Unregisters any event listeners and cleans up.  Also
1090
    quits the bonobo main loop and resets the initialized state to False.
1091
1092
    Returns True if the shutdown procedure ran or False if this module
1093
    was never initialized.
1094
    """
1095
1096 0
    global _initialized
1097
1098 1
    if not _initialized:
1099 0
        return False
1100
1101
    # Try to say goodbye, but be defensive if something has hung.
1102
    #
1103 1
    if settings.timeoutCallback and (settings.timeoutTime > 0):
1104 1
        signal.signal(signal.SIGALRM, settings.timeoutCallback)
1105 1
        signal.alarm(settings.timeoutTime)
1106
1107 1
    speech.speak(_("goodbye."))
1108 1
    braille.displayMessage(_("Goodbye."))
1109
1110
    # Deregister our event listeners
1111
    #
1112 1
    registry = atspi.Registry()
1113 1
    registry.deregisterEventListener(_onChildrenChanged,
1114 1
                                     "object:children-changed:")
1115 1
    registry.deregisterEventListener(_onMouseButton,
1116 1
                                     "mouse:button")
1117
1118 1
    if _currentPresentationManager >= 0:
1119 1
        _PRESENTATION_MANAGERS[_currentPresentationManager].deactivate()
1120
1121
    # Shutdown all the other support.
1122
    #
1123 1
    if settings.enableSpeech:
1124 1
        speech.shutdown()
1125 1
    if settings.enableBraille:
1126 1
        braille.shutdown();
1127 1
    if settings.enableMagnifier:
1128 0
        mag.shutdown();
1129
1130 1
    registry.stop()
1131
1132 1
    if settings.timeoutCallback and (settings.timeoutTime > 0):
1133 1
        signal.alarm(0)
1134
1135 1
    _initialized = False
1136 1
    return True
1137
1138 1
exitCount = 0
1139 1
def shutdownOnSignal(signum, frame):
1140 0
    global exitCount
1141
1142 0
    debug.println(debug.LEVEL_ALL,
1143 0
                  "Shutting down and exiting due to signal = %d" \
1144
                  % signum)
1145
1146 0
    debug.println(debug.LEVEL_ALL, "Current stack is:")
1147 0
    debug.printStack(debug.LEVEL_ALL)
1148
1149
    # Well...we'll try to exit nicely, but if we keep getting called,
1150
    # something bad is happening, so just quit.
1151
    #
1152 0
    if exitCount:
1153 0
        abort(signum)
1154
    else:
1155 0
        exitCount += 1
1156
1157
    # Try to do a graceful shutdown if we can.
1158
    #
1159 0
    if settings.timeoutCallback and (settings.timeoutTime > 0):
1160 0
        signal.signal(signal.SIGALRM, settings.timeoutCallback)
1161 0
        signal.alarm(settings.timeoutTime)
1162
1163 0
    try:
1164 0
        if _initialized:
1165 0
            shutdown()
1166
        else:
1167
            # We always want to try to shutdown speech since the
1168
            # speech servers are very persistent about living.
1169
            #
1170 0
            speech.shutdown()
1171 0
            shutdown()
1172 0
        cleanExit = True
1173 0
    except:
1174 0
        cleanExit = False
1175
1176 0
    if settings.timeoutCallback and (settings.timeoutTime > 0):
1177 0
        signal.alarm(0)
1178
1179 0
    if not cleanExit:
1180 0
        abort(signum)
1181
1182 1
def abortOnSignal(signum, frame):
1183 0
    debug.println(debug.LEVEL_ALL,
1184 0
                  "Aborting due to signal = %d" \
1185
                  % signum)
1186 0
    abort(signum)
1187
1188 1
def usage():
1189
    """Prints out usage information."""
1190 0
    print _("Usage: orca [OPTION...]")
1191 0
    print
1192 0
    print _("-?, --help                   Show this help message")
1193 0
    print _("-v, --version                %s") % platform.version
1194 0
    print _("-s, --setup, --gui-setup     Set up user preferences")
1195 0
    print _("-t, --text-setup             Set up user preferences (text version)")
1196 0
    print _("-n, --no-setup               Skip set up of user preferences")
1197 0
    print _("-u, --user-prefs-dir=dirname Use alternate directory for user preferences")
1198 0
    print _("-e, --enable=[speech|braille|braille-monitor|magnifier|main-window] Force use of option")
1199 0
    print _("-d, --disable=[speech|braille|braille-monitor|magnifier|main-window] Prevent use of option")
1200 0
    print _("-q, --quit                   Quits Orca (if shell script used)")
1201 0
    print
1202 0
    print _("If Orca has not been previously set up by the user, Orca\nwill automatically launch the preferences set up unless\nthe -n or --no-setup option is used.")
1203 0
    print
1204 0
    print _("Report bugs to orca-list@gnome.org.")
1205
    pass
1206
1207 1
def main():
1208
    """The main entry point for Orca.  The exit codes for Orca will
1209
    loosely be based on signals, where the exit code will be the
1210
    signal used to terminate Orca (if a signal was used).  Otherwise,
1211
    an exit code of 0 means normal completion and an exit code of 50
1212
    means Orca exited because of a hang."""
1213
1214 0
    global _commandLineSettings
1215
1216
    # Method to call when we think something might be hung.
1217
    #
1218 1
    settings.timeoutCallback = timeout
1219
1220
    # Various signal handlers we want to listen for.
1221
    #
1222 1
    signal.signal(signal.SIGHUP, shutdownOnSignal)
1223 1
    signal.signal(signal.SIGINT, shutdownOnSignal)
1224 1
    signal.signal(signal.SIGTERM, shutdownOnSignal)
1225 1
    signal.signal(signal.SIGQUIT, shutdownOnSignal)
1226 1
    signal.signal(signal.SIGSEGV, abortOnSignal)
1227
1228
    # See if the desktop is running.  If it is, the import of gtk will
1229
    # succeed.  If it isn't, the import will fail.
1230
    #
1231 1
    desktopRunning = False
1232 1
    try:
1233 1
        import gtk
1234 1
        if gtk.gdk.display_get_default():
1235 1
            desktopRunning = True
1236 0
    except:
1237 0
        pass
1238
1239
    # Parse the command line options.
1240
    #
1241
    # Run the preferences setup if the user has specified
1242
    # "--setup" or "--text-setup" on the command line.  If the
1243
    # desktop is not running, we will fallback to the console-based
1244
    # method as appropriate.
1245
    #
1246 1
    bypassSetup     = False
1247 1
    setupRequested  = False
1248 1
    showGUI         = False
1249
1250
    # We hack a little here because the shell script to start orca can
1251
    # conflate all of command line arguments into one string, which is
1252
    # not what we want.  We detect this by seeing if the length of the
1253
    # argument list is 1.
1254
    #
1255 1
    arglist = sys.argv[1:]
1256 1
    if len(arglist) == 1:
1257 0
        arglist = arglist[0].split()
1258
1259 1
    try:
1260
        # ? is for help
1261
        # e is for enabling a feature
1262
        # d is for disabling a feature
1263
        # h is for help
1264
        # u is for alternate user preferences location
1265
        # s is for setup
1266
        # n is for no setup
1267
        # t is for text setup
1268
        # v is for version
1269
        #
1270 1
        opts, args = getopt.getopt(
1271
            arglist,
1272 1
            "?stnvd:e:u:",
1273 1
            ["help",
1274
             "user-prefs-dir=",
1275
             "enable=",
1276
             "disable=",
1277
             "setup",
1278
             "gui-setup",
1279
             "text-setup",
1280
             "no-setup",
1281
             "version"])
1282 1
        for opt, val in opts:
1283 0
            if opt in ("-u", "--user-prefs-dir"):
1284 0
                userPrefsDir = val.strip();
1285 0
                try:
1286 0
                    os.chdir(userPrefsDir)
1287 0
                    settings.userPrefsDir = userPrefsDir
1288 0
                except:
1289 0
                    debug.printException(debug.LEVEL_FINEST)
1290
1291 0
            if opt in ("-e", "--enable"):
1292 0
                feature = val.strip()
1293 0
                if feature == "speech":
1294 0
                    _commandLineSettings["enableSpeech"] = True
1295 0
                elif feature == "braille":
1296 0
                    _commandLineSettings["enableBraille"] = True
1297 0
                elif feature == "braille-monitor":
1298 0
                    _commandLineSettings["enableBrailleMonitor"] = True
1299 0
                elif feature == "magnifier":
1300 0
                    _commandLineSettings["enableMagnifier"] = True
1301 0
                elif feature == "main-window":
1302 0
                    _commandLineSettings["showMainWindow"] = True
1303
                else:
1304 0
                    usage()
1305 0
                    os._exit(2)
1306
1307 0
            if opt in ("-d", "--disable"):
1308 0
                feature = val.strip()
1309 0
                if feature == "speech":
1310 0
                    _commandLineSettings["enableSpeech"] = False
1311 0
                elif feature == "braille":
1312 0
                    _commandLineSettings["enableBraille"] = False
1313 0
                elif feature == "braille-monitor":
1314 0
                    _commandLineSettings["enableBrailleMonitor"] = False
1315 0
                elif feature == "magnifier":
1316 0
                    _commandLineSettings["enableMagnifier"] = False
1317 0
                elif feature == "main-window":
1318 0
                    _commandLineSettings["showMainWindow"] = False
1319
                else:
1320 0
                    usage()
1321 0
                    os._exit(2)
1322
1323 0
            if opt in ("-s", "--gui-setup", "--setup"):
1324 0
                setupRequested = True
1325 0
                showGUI = desktopRunning
1326 0
            if opt in ("-t", "--text-setup"):
1327 0
                setupRequested = True
1328 0
                showGUI = False
1329 0
            if opt in ("-n", "--no-setup"):
1330 0
                bypassSetup = True
1331 0
            if opt in ("-?", "--help"):
1332 0
                usage()
1333 0
                os._exit(0)
1334 0
            if opt in ("-v", "--version"):
1335 0
                print "Orca %s" % platform.version
1336 0
                os._exit(0)
1337 0
    except:
1338 0
        debug.printException(debug.LEVEL_OFF)
1339 0
        usage()
1340 0
        os._exit(2)
1341
1342
    # Do not run Orca if accessibility has not been enabled.
1343
    # We do allow, however, one to force Orca to run via the
1344
    # "-n" switch.  The main reason is so that things such
1345
    # as accessible login can work -- in those cases, the gconf
1346
    # setting is typically not set since the gdm user does not
1347
    # have a home.
1348
    #
1349 1
    import commands
1350 1
    a11yEnabled = commands.getoutput(\
1351
        "gconftool-2 --get /desktop/gnome/interface/accessibility")
1352 1
    if (not bypassSetup) and (a11yEnabled != "true"):
1353 0
        _showPreferencesConsole()
1354 0
        abort()
1355
1356 1
    if setupRequested and (not bypassSetup) and (not showGUI):
1357 0
        _showPreferencesConsole()
1358
1359 1
    if not desktopRunning:
1360 0
        print "Cannot start Orca because it cannot connect"
1361 0
        print "to the Desktop.  Please make sure the DISPLAY"
1362 0
        print "environment variable has been set."
1363 0
        return 1
1364
1365 1
    userprefs = settings.userPrefsDir
1366 1
    sys.path.insert(0, userprefs)
1367 1
    sys.path.insert(0, '') # current directory
1368
1369 1
    registry = atspi.Registry()
1370 1
    init(registry)
1371
1372
    # Check to see if the user wants the configuration GUI. It's
1373
    # done here so that the user's existing preferences can be used
1374
    # to set the initial GUI state.  We'll also force the set to
1375
    # be run if the preferences file doesn't exist, unless the
1376
    # user has bypassed any setup via the --no-setup switch.
1377
    #
1378 1
    if setupRequested and (not bypassSetup) and showGUI:
1379 0
        _showPreferencesGUI()
1380 1
    elif (not _userSettings) and (not bypassSetup):
1381 0
        if desktopRunning:
1382 0
            _showPreferencesGUI()
1383
        else:
1384 0
            _showPreferencesConsole()
1385
1386 1
    start(registry) # waits until we stop the registry
1387 1
    return 0
1388
1389 1
if __name__ == "__main__":
1390 0
    sys.exit(main())