Viewing file: orca.py (39.8 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
# Orca # # Copyright 2004-2006 Sun Microsystems Inc. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA.
"""The main module for the Orca screen reader."""
__id__ = "$Id: orca.py,v 1.154 2006/08/27 23:29:38 wwalker Exp $" __version__ = "$Revision: 1.154 $" __date__ = "$Date: 2006/08/27 23:29:38 $" __copyright__ = "Copyright (c) 2005-2006 Sun Microsystems Inc." __license__ = "LGPL"
try: # This can fail due to gtk not being available. We want to # be able to recover from that if possible. The main driver # for this is to allow "orca --text-setup" to work even if # the desktop is not running. # import gtk except: pass
import getopt import os import signal import string import sys import time
import atspi import braille import debug import httpserver import keynames import keybindings import mag import orca_state import platform import rolenames import settings import speech
import threading import util
from input_event import BrailleEvent from input_event import KeyboardEvent from input_event import MouseButtonEvent from input_event import InputEventHandler
from orca_i18n import _ # for gettext support
# The user-settings module (see loadUserSettings). # _userSettings = None
######################################################################## # # # METHODS FOR HANDLING PRESENTATION MANAGERS # # # # A presentation manager is what reacts to AT-SPI object events as # # well as user input events (keyboard and Braille) to present info # # to the user. # # # ########################################################################
# The known presentation managers (set up in start()) # _PRESENTATION_MANAGERS = None
# The current presentation manager, which is an index into the # _PRESENTATION_MANAGERS list. # _currentPresentationManager = -1
def _switchToPresentationManager(index): """Switches to the given presentation manager.
Arguments: - index: an index into _PRESENTATION_MANAGERS """
global _currentPresentationManager
if _currentPresentationManager >= 0: _PRESENTATION_MANAGERS[_currentPresentationManager].deactivate()
_currentPresentationManager = index
# Wrap the presenter index around. # if _currentPresentationManager >= len(_PRESENTATION_MANAGERS): _currentPresentationManager = 0 elif _currentPresentationManager < 0: _currentPresentationManager = len(_PRESENTATION_MANAGERS) - 1
_PRESENTATION_MANAGERS[_currentPresentationManager].activate()
def _switchToNextPresentationManager(script=None, inputEvent=None): """Switches to the next presentation manager.
Arguments: - inputEvent: the InputEvent instance that caused this to be called.
Returns True indicating the event should be consumed. """
_switchToPresentationManager(_currentPresentationManager + 1) return True
######################################################################## # # # METHODS TO HANDLE APPLICATION LIST AND FOCUSED OBJECTS # # # ########################################################################
def setLocusOfFocus(event, obj, notifyPresentationManager=True): """Sets the locus of focus (i.e., the object with visual focus) and notifies the current presentation manager of the change.
Arguments: - event: if not None, the Event that caused this to happen - obj: the Accessible with the new locus of focus. - notifyPresentationManager: if True, propagate this event """
if obj == orca_state.locusOfFocus: return
oldLocusOfFocus = orca_state.locusOfFocus if oldLocusOfFocus and not oldLocusOfFocus.valid: oldLocusOfFocus = None
orca_state.locusOfFocus = obj if orca_state.locusOfFocus and not orca_state.locusOfFocus.valid: orca_state.locusOfFocus = None
if orca_state.locusOfFocus: appname = "" if not orca_state.locusOfFocus.app: appname = "None" else: appname = "'" + orca_state.locusOfFocus.app.name + "'"
debug.println(debug.LEVEL_FINE, "LOCUS OF FOCUS: app=%s name='%s' role='%s'" \ % (appname, orca_state.locusOfFocus.name, orca_state.locusOfFocus.role))
if event: debug.println(debug.LEVEL_FINE, " event='%s'" % event.type) else: debug.println(debug.LEVEL_FINE, " event=None") else: if event: debug.println(debug.LEVEL_FINE, "LOCUS OF FOCUS: None event='%s'" % event.type) else: debug.println(debug.LEVEL_FINE, "LOCUS OF FOCUS: None event=None")
if notifyPresentationManager and _currentPresentationManager >= 0: _PRESENTATION_MANAGERS[_currentPresentationManager].\ locusOfFocusChanged(event, oldLocusOfFocus, orca_state.locusOfFocus)
def visualAppearanceChanged(event, obj): """Called (typically by scripts) when the visual appearance of an object changes and notifies the current presentation manager of the change. This method should not be called for objects whose visual appearance changes solely because of focus -- setLocusOfFocus is used for that. Instead, it is intended mostly for objects whose notional 'value' has changed, such as a checkbox changing state, a progress bar advancing, a slider moving, text inserted, caret moved, etc.
Arguments: - event: if not None, the Event that caused this to happen - obj: the Accessible whose visual appearance changed. """
if _currentPresentationManager >= 0: _PRESENTATION_MANAGERS[_currentPresentationManager].\ visualAppearanceChanged(event, obj)
def _onChildrenChanged(e): """Tracks children-changed events on the desktop to determine when apps start and stop.
Arguments: - e: at-spi event from the at-api registry """
registry = atspi.Registry() if e.source == registry.desktop:
# If the desktop is empty, the user has logged out-- shutdown Orca # try: if registry.desktop.childCount == 0: speech.speak(_("User logged out - shutting down.")) shutdown() return except: # could be a CORBA.COMM_FAILURE debug.printException(debug.LEVEL_FINEST) shutdown() return
def _onMouseButton(e): """Tracks mouse button events, stopping any speech in progress.
Arguments: - e: at-spi event from the at-api registry """
event = atspi.Event(e) orca_state.lastInputEvent = MouseButtonEvent(event)
# A mouse button event looks like: mouse:button:1p, where the # number is the button number and the 'p' is either 'p' or 'r', # meaning pressed or released. We only want to stop speech on # button presses. # if event.type.endswith("p"): speech.stop()
######################################################################## # # # Keyboard Event Recording Support # # # ########################################################################
_recordingKeystrokes = False _keystrokesFile = None
def _closeKeystrokeWindowAndRecord(entry, window): global _keystrokesFile window.destroy() entry_text = entry.get_text() _keystrokesFile = open(entry_text, 'w')
def _closeKeystrokeWindowAndCancel(window): global _recordingKeystrokes window.destroy() _recordingKeystrokes = False
def toggleKeystrokeRecording(script=None, inputEvent=None): """Toggles the recording of keystrokes on and off. When the user presses the magic key (Pause), Orca will pop up a window requesting a filename. When the user presses the close button, Orca will start recording keystrokes to the file and will continue recording them until the user presses the magic key again.
This functionality is used primarily to help gather keystroke information for regression testing purposes. The keystrokes are recorded in such a way that they can be played back via the src/tools/play_keystrokes.py utility.
Arguments: - inputEvent: the key event (if any) which caused this to be called.
Returns True indicating the event should be consumed. """
global _recordingKeystrokes global _keystrokesFile
if _recordingKeystrokes: # If the filename entry window is still up, we don't have a file # yet. # if _keystrokesFile: _keystrokesFile.close() _keystrokesFile = None _recordingKeystrokes = False else: _recordingKeystrokes = True window = gtk.Window(gtk.WINDOW_TOPLEVEL) window.set_title("Keystroke Filename")
vbox = gtk.VBox(False, 0) window.add(vbox) vbox.show()
entry = gtk.Entry() entry.set_max_length(50) entry.set_editable(True) entry.set_text("keystrokes.txt") entry.select_region(0, len(entry.get_text())) # For now, do not allow "Return" to close the window - the reason # for this is that the key press closes the window, and the key # release will end up getting recorded. # #entry.connect("activate", _closeKeystrokeWindow, window) vbox.pack_start(entry, True, True, 0) entry.show()
hbox = gtk.HBox(False, 0) vbox.add(hbox) hbox.show()
ok = gtk.Button(stock=gtk.STOCK_OK) ok.connect("clicked", lambda w: _closeKeystrokeWindowAndRecord(\ entry, \ window))
cancel = gtk.Button(stock=gtk.STOCK_CANCEL) cancel.connect("clicked", lambda w: _closeKeystrokeWindowAndCancel(\ window))
vbox.pack_start(cancel, True, True, 0) vbox.pack_start(ok, True, True, 0)
ok.set_flags(gtk.CAN_DEFAULT) ok.grab_default() ok.show() cancel.show()
window.set_modal(True) window.show() return True
######################################################################## # # # DEBUG support. # # # ########################################################################
def cycleDebugLevel(script=None, inputEvent=None): """Cycles the debug level at run time.
Arguments: - inputEvent: the InputEvent instance that caused this to be called.
Returns True indicating the event should be consumed. """
def cycleDebugLevel(script=None, inputEvent=None): global _debugLevel
level = debug.debugLevel
if level == debug.LEVEL_ALL: level = debug.LEVEL_FINEST elif level == debug.LEVEL_FINEST: level = debug.LEVEL_FINER elif level == debug.LEVEL_FINER: level = debug.LEVEL_FINE elif level == debug.LEVEL_FINE: level = debug.LEVEL_CONFIGURATION elif level == debug.LEVEL_CONFIGURATION: level = debug.LEVEL_INFO elif level == debug.LEVEL_INFO: level = debug.LEVEL_WARNING elif level == debug.LEVEL_WARNING: level = debug.LEVEL_SEVERE elif level == debug.LEVEL_SEVERE: level = debug.LEVEL_OFF elif level == debug.LEVEL_OFF: level = debug.LEVEL_ALL
debug.debugLevel = level
if level == debug.LEVEL_ALL: speech.speak(_("Debug level all.")) elif level == debug.LEVEL_FINEST: speech.speak(_("Debug level finest.")) elif level == debug.LEVEL_FINER: speech.speak(_("Debug level finer.")) elif level == debug.LEVEL_FINE: speech.speak(("Debug level fine.")) elif level == debug.LEVEL_CONFIGURATION: speech.speak("Debug level configuration.") elif level == debug.LEVEL_INFO: speech.speak("Debug level info.") elif level == debug.LEVEL_WARNING: speech.speak("Debug level warning.") elif level == debug.LEVEL_SEVERE: speech.speak("Debug level severe.") elif level == debug.LEVEL_OFF: speech.speak("Debug level off.")
return True
def printApps(script=None, inputEvent=None): """Prints a list of all applications to stdout.""" util.printApps() return True
def printActiveApp(script=None, inputEvent=None): """Prints the currently active application.""" util.printActiveApp() return True
def printAncestry(script=None, inputEvent=None): """Prints the ancestry for the current locusOfFocus""" util.printAncestry(orca_state.locusOfFocus) return True
def printHierarchy(script=None, inputEvent=None): """Prints the application for the current locusOfFocus""" if orca_state.locusOfFocus: util.printHierarchy(orca_state.locusOfFocus.app, orca_state.locusOfFocus) return True
######################################################################## # # # METHODS FOR PRE-PROCESSING AND MASSAGING KEYBOARD EVENTS. # # # # All keyboard events are funnelled through here first. Orca itself # # might have global keybindings (e.g., to switch between presenters), # # but it will typically pass the event onto the currently active # # active presentation manager. # # # ########################################################################
# Keybindings that Orca itself cares about. # _keyBindings = None
# True if the orca modifier key is currently pressed. # _orcaModifierPressed = False
def _isPrintableKey(event_string): """Return an indication of whether this is an alphanumeric or punctuation key.
Arguments: - event: the event string
Returns True if this is an alphanumeric or punctuation key. """
if event_string == "space": reply = True else: reply = event_string in string.printable debug.println(debug.LEVEL_FINEST, "orca._echoPrintableKey: returning: %s" % reply) return reply
def _isModifierKey(event_string): """Return an indication of whether this is a modifier key.
Arguments: - event: the event string
Returns True if this is a modifier key """
# [[[TODO:richb - the Fn key on my laptop doesn't seem to generate an # event.]]]
modifierKeys = [ 'Alt_L', 'Alt_R', 'Control_L', 'Control_R', \ 'Shift_L', 'Shift_R', 'Meta_L', 'Meta_R', "Insert" ]
reply = event_string in modifierKeys debug.println(debug.LEVEL_FINEST, "orca._echoModifierKey: returning: %s" % reply) return reply
def _isLockingKey(event_string): """Return an indication of whether this is a locking key.
Arguments: - event: the event string
Returns True if this is a locking key. """
lockingKeys = [ "Caps_Lock", "Num_Lock", "Scroll_Lock" ]
reply = event_string in lockingKeys debug.println(debug.LEVEL_FINEST, "orca._echoLockingKey: returning: %s" % reply) return reply
def _isFunctionKey(event_string): """Return an indication of whether this is a function key.
Arguments: - event: the event string
Returns True if this is a function key. """
# [[[TODO:richb - what should be done about the function keys on the left # side of my Sun keyboard and the other keys (like Scroll Lock), which # generate "Fn" key events?]]]
functionKeys = [ "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12" ]
reply = event_string in functionKeys debug.println(debug.LEVEL_FINEST, "orca._echoFunctionKey: returning: %s" % reply) return reply
def _isActionKey(event_string): """Return an indication of whether this is an action key.
Arguments: - event: the event string
Returns True if this is an action key. """
actionKeys = [ "Return", "Escape", "Tab", "BackSpace", "Delete", "Page_Up", "Page_Down", "Home", "End" ]
reply = event_string in actionKeys debug.println(debug.LEVEL_FINEST, "orca._echoActionKey: returning: %s" % reply) return reply
def _keyEcho(event): """If the keyEcho setting is enabled, check to see what type of key event it is and echo it via speech, if the user wants that type of key echoed.
Uppercase keys will be spoken using the "uppercase" voice style, whereas lowercase keys will be spoken using the "default" voice style.
Arguments: - event: an AT-SPI DeviceEvent """
# If this keyboard event was for an object like a password text # field, then don't echo it. # if orca_state.locusOfFocus \ and (orca_state.locusOfFocus.role == rolenames.ROLE_PASSWORD_TEXT): return
event_string = event.event_string debug.println(debug.LEVEL_FINEST, "orca._keyEcho: string to echo: %s" % event_string)
voices = settings.voices voice = voices[settings.DEFAULT_VOICE]
lockState = None
# If key echo is enabled, then check to see what type of key event # it is and echo it via speech, if the user wants that type of key # echoed. # if settings.enableKeyEcho:
if _isPrintableKey(event_string): if not settings.enablePrintableKeys: return
if event_string.isupper(): voice = voices[settings.UPPERCASE_VOICE]
elif _isModifierKey(event_string): if not settings.enableModifierKeys: return
elif _isLockingKey(event_string): if not settings.enableLockingKeys: return
modifiers = event.modifiers if event_string == _("Caps_Lock"): if modifiers & (1 << atspi.Accessibility.MODIFIER_SHIFTLOCK): lockState = _(" off") else: lockState = _(" on")
elif event_string == _("Num_Lock"): # [[[TODO: richb - we are not getting a correct modifier # state value returned when Num Lock is turned off. # Commenting out the speaking of the bogus on/off state # until this can be fixed.]]] # #if modifiers & (1 << atspi.Accessibility.MODIFIER_NUMLOCK): # event_string += _(" off") #else: # event_string += _(" on") pass
elif _isFunctionKey(event_string): if not settings.enableFunctionKeys: return
elif _isActionKey(event_string): if not settings.enableActionKeys: return
else: debug.println(debug.LEVEL_FINEST, "orca._keyEcho: event string not handled: %s" % event_string) return
# Check to see if there are localized words to be spoken for # this key event. if event_string in keynames.keynames: event_string = keynames.keynames[event_string]
if lockState: event_string += lockState
debug.println(debug.LEVEL_FINEST, "orca._keyEcho: speaking: %s" % event_string)
# We keep track of the time as means to let others know that # we are probably echoing a key and should not be interrupted. # orca_state.lastKeyEchoTime = time.time()
speech.speak(event_string, voice)
def _processKeyboardEvent(event): """The primary key event handler for Orca. Keeps track of various attributes, such as the lastInputEvent. Also calls keyEcho as well as any local keybindings before passing the event on to the active presentation manager. This method is called synchronously from the AT-SPI registry and should be performant. In addition, it must return True if it has consumed the event (and False if not).
Arguments: - event: an AT-SPI DeviceEvent
Returns True if the event should be consumed. """ global _orcaModifierPressed
orca_state.lastInputEventTimestamp = event.timestamp
# Log the keyboard event for future playback, if desired. # Note here that the key event_string being output is # exactly what we received. The KeyboardEvent object, # however, will translate the event_string for control # characters to their upper case ASCII equivalent. # string = atspi.KeystrokeListener.keyEventToString(event) if _recordingKeystrokes and _keystrokesFile \ and (event.event_string != "Pause"): _keystrokesFile.write(string + "\n") debug.printInputEvent(debug.LEVEL_FINE, string)
keyboardEvent = KeyboardEvent(event)
# See if this is one of our special Orca modifiers (e.g., "Insert") # orcaModifierKeys = settings.orcaModifierKeys isOrcaModifier = orcaModifierKeys.count(keyboardEvent.event_string) > 0
if event.type == atspi.Accessibility.KEY_PRESSED_EVENT: # Key presses always interrupt speech. # speech.stop()
# If learn mode is enabled, it will echo the keys. # if not settings.learnModeEnabled: _keyEcho(keyboardEvent)
# We treat the Insert key as a modifier - so just swallow it and # set our internal state. # if isOrcaModifier: _orcaModifierPressed = True
elif isOrcaModifier \ and (keyboardEvent.type == atspi.Accessibility.KEY_RELEASED_EVENT): _orcaModifierPressed = False
if _orcaModifierPressed: keyboardEvent.modifiers |= (1 << settings.MODIFIER_ORCA)
# Orca gets first stab at the event. Then, the presenter gets # a shot. [[[TODO: WDW - might want to let the presenter try first? # The main reason this is staying as is is that we may not want # scripts to override fundamental Orca key bindings.]]] # consumed = False try: consumed = _keyBindings.consumeKeyboardEvent(None, keyboardEvent) if (not consumed) and (_currentPresentationManager >= 0): consumed = _PRESENTATION_MANAGERS[_currentPresentationManager].\ processKeyboardEvent(keyboardEvent) if (not consumed) and settings.learnModeEnabled: if keyboardEvent.type \ == atspi.Accessibility.KEY_PRESSED_EVENT: # Check to see if there are localized words to be # spoken for this key event. # braille.displayMessage(keyboardEvent.event_string) event_string = keyboardEvent.event_string if event_string in keynames.keynames: event_string = keynames.keynames[event_string] speech.speak(event_string) consumed = True except: debug.printException(debug.LEVEL_SEVERE)
orca_state.lastInputEvent = keyboardEvent
return consumed or isOrcaModifier
######################################################################## # # # METHODS FOR PRE-PROCESSING AND MASSAGING BRAILLE EVENTS. # # # ########################################################################
def _processBrailleEvent(command): """Called whenever a key is pressed on the Braille display.
Arguments: - command: the BrlAPI command for the key that was pressed.
Returns True if the event was consumed; otherwise False """
# [[[TODO: WDW - probably should add braille bindings to this module.]]]
consumed = False
# Braille key presses always interrupt speech. # speech.stop()
event = BrailleEvent(command) orca_state.lastInputEvent = event
try: consumed = _PRESENTATION_MANAGERS[_currentPresentationManager].\ processBrailleEvent(event) except: debug.printException(debug.LEVEL_SEVERE)
if (not consumed) and settings.learnModeEnabled: consumed = True
return consumed
######################################################################## # # # METHODS FOR HANDLING INITIALIZATION, SHUTDOWN, AND USE. # # # ########################################################################
def _toggleSilenceSpeech(script=None, inputEvent=None): """Toggle the silencing of speech.
Returns True to indicate the input event has been consumed. """ speech.stop() if settings.silenceSpeech: settings.silenceSpeech = False speech.speak(_("Speech enabled.")) else: speech.speak(_("Speech disabled.")) settings.silenceSpeech = True return True
def loadUserSettings(script=None, inputEvent=None): """Loads (and reloads) the user settings module, reinitializing things such as speech if necessary.
Returns True to indicate the input event has been consumed. """
global _userSettings
# Shutdown the output drivers and give them a chance to die. # httpserver.shutdown() speech.shutdown() braille.shutdown() mag.shutdown() time.sleep(1)
reloaded = False if _userSettings: try: reload(_userSettings) reloaded = True except ImportError: debug.printException(debug.LEVEL_FINEST) else: try: _userSettings = __import__("user-settings") except ImportError: debug.printException(debug.LEVEL_FINEST)
if settings.enableSpeech: try: speech.init() if reloaded: speech.speak(_("Orca user settings reloaded.")) debug.println(debug.LEVEL_CONFIGURATION, "Speech module has been initialized.") except: debug.printException(debug.LEVEL_SEVERE) debug.println(debug.LEVEL_SEVERE, "Could not initialize connection to speech.") else: debug.println(debug.LEVEL_CONFIGURATION, "Speech module has NOT been initialized.")
if settings.enableBraille: try: braille.init(_processBrailleEvent, 7) except: debug.printException(debug.LEVEL_WARNING) debug.println(debug.LEVEL_WARNING, "Could not initialize connection to braille.")
if settings.enableMagnifier: try: mag.init() debug.println(debug.LEVEL_CONFIGURATION, "Magnification module has been initialized.") except: debug.printException(debug.LEVEL_SEVERE) debug.println(debug.LEVEL_SEVERE, "Could not initialize connection to magnifier.") else: debug.println(debug.LEVEL_CONFIGURATION, "Magnification module has NOT been initialized.")
httpserver.init()
return True
def _showPreferencesGUI(script=None, inputEvent=None): """Displays the user interace to configure Orca and set up user preferences using a GUI.
Returns True to indicate the input event has been consumed. """
try: module = __import__(settings.guiPreferencesModule, globals(), locals(), ['']) module.showPreferencesUI() except: debug.printException(debug.LEVEL_SEVERE) pass
return True
def _showPreferencesConsole(script=None, inputEvent=None): """Displays the user interace to configure Orca and set up user preferences via a command line interface.
Returns True to indicate the input event has been consumed. """
try: module = __import__(settings.consolePreferencesModule, globals(), locals(), ['']) module.showPreferencesUI() except: debug.printException(debug.LEVEL_SEVERE) pass
return True
# If True, this module has been initialized. # _initialized = False
def init(registry): """Initialize the orca module, which initializes speech, braille, and mag modules. Also builds up the application list, registers for AT-SPI events, and creates scripts for all known applications.
Returns True if the initialization procedure has run, or False if this module has already been initialized. """
global _initialized global _keyBindings
if _initialized: return False
# Do not hang on initialization if we can help it. # if settings.timeoutCallback and (settings.timeoutTime > 0): signal.signal(signal.SIGALRM, settings.timeoutCallback) signal.alarm(settings.timeoutTime)
# Note that we have moved the Orca specific keybindings to the default # script, so _keyBindings is currently empty. The logic is retained # here, just in case we wish to reinstate them in the future. # _keyBindings = keybindings.KeyBindings()
# Create and load an app's script when it is added to the desktop # registry.registerEventListener(_onChildrenChanged, "object:children-changed:")
# We also want to stop speech when a mouse button is pressed. # registry.registerEventListener(_onMouseButton, "mouse:button")
loadUserSettings()
registry.registerKeystrokeListeners(_processKeyboardEvent)
if settings.timeoutCallback and (settings.timeoutTime > 0): signal.alarm(0)
_initialized = True return True
def start(registry): """Starts Orca. """
global _PRESENTATION_MANAGERS
if not _initialized: init(registry)
# Do not hang on startup if we can help it. # if settings.timeoutCallback and (settings.timeoutTime > 0): signal.signal(signal.SIGALRM, settings.timeoutCallback) signal.alarm(settings.timeoutTime)
try: speech.speak(_("Welcome to Orca.")) braille.displayMessage(_("Welcome to Orca.")) except: debug.printException(debug.LEVEL_SEVERE)
if not _PRESENTATION_MANAGERS:
# [[[WDW - comment out hierarchical_presenter for now. It # relies on the list of known applications, and we've disabled # that due to a hang in a call to getChildAtIndex in # util.getKnownApplications.]]] # #import focus_tracking_presenter #import hierarchical_presenter #_PRESENTATION_MANAGERS = \ # [focus_tracking_presenter.FocusTrackingPresenter(), # hierarchical_presenter.HierarchicalPresenter()]
import focus_tracking_presenter _PRESENTATION_MANAGERS = \ [focus_tracking_presenter.FocusTrackingPresenter()]
_switchToPresentationManager(0) # focus_tracking_presenter
if settings.timeoutCallback and (settings.timeoutTime > 0): signal.alarm(0)
registry.start()
def abort(exitCode=1): os._exit(exitCode)
def timeout(signum=None, frame=None): debug.println(debug.LEVEL_SEVERE, "TIMEOUT: something has hung. Aborting.") debug.printStack(debug.LEVEL_ALL) abort(50)
def shutdown(script=None, inputEvent=None): """Exits Orca. Unregisters any event listeners and cleans up. Also quits the bonobo main loop and resets the initialized state to False.
Returns True if the shutdown procedure ran or False if this module was never initialized. """
global _initialized
if not _initialized: return False
# Try to say goodbye, but be defensive if something has hung. # if settings.timeoutCallback and (settings.timeoutTime > 0): signal.signal(signal.SIGALRM, settings.timeoutCallback) signal.alarm(settings.timeoutTime)
speech.speak(_("goodbye.")) braille.displayMessage(_("Goodbye."))
# Deregister our event listeners # registry = atspi.Registry() registry.deregisterEventListener(_onChildrenChanged, "object:children-changed:") registry.deregisterEventListener(_onMouseButton, "mouse:button")
if _currentPresentationManager >= 0: _PRESENTATION_MANAGERS[_currentPresentationManager].deactivate()
# Shutdown all the other support. # if settings.enableSpeech: speech.shutdown() if settings.enableBraille: braille.shutdown(); if settings.enableMagnifier: mag.shutdown();
registry.stop()
if settings.timeoutCallback and (settings.timeoutTime > 0): signal.alarm(0)
_initialized = False return True
exitCount = 0 def shutdownOnSignal(signum, frame): global exitCount
debug.println(debug.LEVEL_ALL, "Shutting down and exiting due to signal = %d" \ % signum)
debug.println(debug.LEVEL_ALL, "Current stack is:") debug.printStack(debug.LEVEL_ALL)
# Well...we'll try to exit nicely, but if we keep getting called, # something bad is happening, so just quit. # if exitCount: abort(signum) else: exitCount += 1
# Try to do a graceful shutdown if we can. # if settings.timeoutCallback and (settings.timeoutTime > 0): signal.signal(signal.SIGALRM, settings.timeoutCallback) signal.alarm(settings.timeoutTime)
try: if _initialized: shutdown() else: # We always want to try to shutdown speech since the # speech servers are very persistent about living. # speech.shutdown() shutdown() except: pass
if settings.timeoutCallback and (settings.timeoutTime > 0): signal.alarm(0)
abort(signum)
def abortOnSignal(signum, frame): debug.println(debug.LEVEL_ALL, "Aborting due to signal = %d" \ % signum) abort(signum)
def usage(): """Prints out usage information.""" print _("Usage: orca [OPTION...]") print print _("-?, --help Show this help message") print _("-v, --version %s") % platform.version print _("-s, --setup, --gui-setup Set up user preferences") print _("-t, --text-setup Set up user preferences (text version)") print _("-n, --no-setup Skip set up of user preferences") #print _("-q, --quit Quits Orca (if shell script used)") print 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.") print print _("Report bugs to orca-list@gnome.org.") pass
def main(): """The main entry point for Orca. The exit codes for Orca will loosely be based on signals, where the exit code will be the signal used to terminate Orca (if a signal was used). Otherwise, an exit code of 0 means normal completion and an exit code of 50 means Orca exited because of a hang."""
# Method to call when we think something might be hung. # settings.timeoutCallback = timeout
# Various signal handlers we want to listen for. # signal.signal(signal.SIGHUP, shutdownOnSignal) signal.signal(signal.SIGINT, shutdownOnSignal) signal.signal(signal.SIGTERM, shutdownOnSignal) signal.signal(signal.SIGQUIT, shutdownOnSignal) signal.signal(signal.SIGSEGV, abortOnSignal)
# See if the desktop is running. If it is, the import of gtk will # succeed. If it isn't, the import will fail. # desktopRunning = False try: import gtk desktopRunning = True except: pass
# Parse the command line options. # # Run the preferences setup if the user has specified # "--setup" or "--text-setup" on the command line. If the # desktop is not running, we will fallback to the console-based # method as appropriate. # bypassSetup = False setupRequested = False showGUI = False try: # ? is for help # h is for help # s is for setup # n is for no setup # t is for text setup # v is for version # opts, args = getopt.getopt( sys.argv[1:], "?stnv", ["help", "setup", "gui-setup", "text-setup", "no-setup", "version", "stop"])
do_shutdown = False for opt, val in opts: if opt in ("-s", "--gui-setup", "--setup"): setupRequested = True showGUI = desktopRunning if opt in ("-t", "--text-setup"): setupRequested = True showGUI = False if opt in ("-n", "--no-setup"): bypassSetup = True if opt in ("-?", "--help"): usage() os._exit(0) if opt in ("-v", "--version"): print "Orca %s" % platform.version os._exit(0) if opt in ("--stop"): do_shutdown = True bypassSetup = True except: usage() os._exit(2)
# Do not run Orca if accessibility has not been enabled. # import commands a11yEnabled = commands.getoutput(\ "gconftool-2 --get /desktop/gnome/interface/accessibility") if a11yEnabled != "true" and not do_shutdown: _showPreferencesConsole() abort()
if setupRequested and (not bypassSetup) and (not showGUI): _showPreferencesConsole()
if not desktopRunning: print "Cannot start Orca because it cannot connect" print "to the Desktop. Please make sure the DISPLAY" print "environment variable has been set." return 1
userprefs = os.path.join(os.environ["HOME"], ".orca") sys.path.insert(0, userprefs) sys.path.insert(0, '') # current directory
registry = atspi.Registry() init(registry)
if do_shutdown: shutdown()
# Check to see if the user wants the configuration GUI. It's # done here so that the user's existing preferences can be used # to set the initial GUI state. We'll also force the set to # be run if the preferences file doesn't exist, unless the # user has bypassed any setup via the --no-setup switch. # if setupRequested and (not bypassSetup) and showGUI: _showPreferencesGUI() elif (not _userSettings) and (not bypassSetup): if desktopRunning: _showPreferencesGUI() else: _showPreferencesConsole()
start(registry) # waits until we stop the registry return 0
if __name__ == "__main__": sys.exit(main())
|