orca r4202 - in branches/phase2: . src/orca



Author: wwalker
Date: Sat Sep 13 08:59:49 2008
New Revision: 4202
URL: http://svn.gnome.org/viewvc/orca?rev=4202&view=rev

Log:
Add some TODO's, do a little reorganizing.


Modified:
   branches/phase2/pylintrc
   branches/phase2/src/orca/braille.py
   branches/phase2/src/orca/input_bindings.py
   branches/phase2/src/orca/orca.in
   branches/phase2/src/orca/orca.py
   branches/phase2/src/orca/script.py
   branches/phase2/src/orca/script_manager.py
   branches/phase2/src/orca/settings.py
   branches/phase2/src/orca/utils.py

Modified: branches/phase2/pylintrc
==============================================================================
--- branches/phase2/pylintrc	(original)
+++ branches/phase2/pylintrc	Sat Sep 13 08:59:49 2008
@@ -88,7 +88,7 @@
 # R0915: Function or method has too many statements
 #
 #disable-msg=E0611,C0111,R0201,W0102,W0141,W0333,W0401,W0403,W0603,W0612,W0613,W0702,W0704,W0511,R0801,R0912,R0915,R0914,R0904,R0903,R0401,R0911,R0913,C0302,R0902
-disable-msg=W0403,W0612,W0613,W0702,W0704,R0201,R0903,R0912,R0913
+disable-msg=W0403,W0612,W0613,W0702,W0704,R0201,R0902,R0903,R0912,R0913
 
 [REPORTS]
 

Modified: branches/phase2/src/orca/braille.py
==============================================================================
--- branches/phase2/src/orca/braille.py	(original)
+++ branches/phase2/src/orca/braille.py	Sat Sep 13 08:59:49 2008
@@ -15,6 +15,16 @@
 # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
 # Boston MA  02110-1301 USA.
 
+# Allow globals to be used in this module.
+#
+# pylint: disable-msg=W0603
+
+# TODO: make new module for braille regions.  This module is now
+# just for I/O with the braille display.
+
+# TODO: find a way to output the attributes.  Perhaps an extra line
+# under the VISIBLE line where we use - ~ and =.
+
 """Used to get input events from the braille display and to paint raw
 strings to the braille display.
 """
@@ -119,10 +129,6 @@
 #
 _callback = None
 
-# Allow globals to be used in this module.
-#
-# pylint: disable-msg=W0603
-#
 def writeText(text, attributeMask, cursorCell):
     """Writes the given text with the given attribute mask.  Also
     puts the cursor at the given 1-based cursorCell (0 means no cursor).
@@ -174,7 +180,7 @@
             #
             consumed = _callback(event)
         except:
-            log.exception('exception from braille callback')
+            log.exception("handled exception from braille callback:")
             consumed = False
     return consumed
 
@@ -212,7 +218,7 @@
             keySet.append(brlapi.KEY_TYPE_CMD | key)
         _brlAPI.acceptKeys(brlapi.rangeType_command, keySet)
     except:
-        log.exception('exception while setting up braille key ranges:')
+        log.exception("handled exception while setting up braille key ranges:")
 
 def init(callback=None):
     """Initializes the braille module, connecting to the BrlTTY driver.
@@ -256,7 +262,7 @@
                                                gobject.IO_IN,
                                                _brlAPIKeyReader)
     except:
-        log.exception("exception while initializing brltty:")
+        log.exception("handled exception while initializing brltty:")
         return False
 
     _displaySize = _brlAPI.displaySize

Modified: branches/phase2/src/orca/input_bindings.py
==============================================================================
--- branches/phase2/src/orca/input_bindings.py	(original)
+++ branches/phase2/src/orca/input_bindings.py	Sat Sep 13 08:59:49 2008
@@ -199,12 +199,7 @@
         - modifiers:  any modifiers associated with the event
         """
         log.debug("process %s for %s" % (inputEvent, script))
-        try:
-            consumed = self.function(script, inputEvent, modifiers)
-        except:
-            log.exception("while attempting to process input event")
-            consumed = False
-        return consumed
+        self.function(script, inputEvent, modifiers)
 
 class Binding:
     """A single input event binding, consisting of a command, a keyboard
@@ -365,29 +360,24 @@
 
         return None
 
-    def _consumeInputEvent(self, 
-                          script, 
-                          inputEvent, 
-                          commandCode, 
-                          modifiers, 
-                          process=True):
-        """Attempts to consume the given input event.
+    def _processInputEvent(self, 
+                           script, 
+                           inputEvent, 
+                           commandCode, 
+                           modifiers, 
+                           process=True):
+        """Processes the given input event.  Returns True if a handler
+        was found and the event was actually processed.
         """
-        consumed = False
         handler = self.getHandler(commandCode,
                                   modifiers,
                                   script.getClickCount())
         if handler:
-            consumed = True
-            if process:
-                try:
-                    handler.processInputEvent(script,
-                                              inputEvent,
-                                              modifiers)
-                except:
-                    log.exception("while processing input event")
+            handler.processInputEvent(script,
+                                      inputEvent,
+                                      modifiers)
 
-        return consumed
+        return handler != None
 
 ########################################################################
 #                                                                      #
@@ -437,13 +427,11 @@
     def __init__(self):
         Bindings.__init__(self)
 
-    def consumeInputEvent(self, script, keyboardEvent, modifiers):
-        """Attempts to consume the given keyboard event.  If these
-        keybindings have a handler for the given keyboardEvent, it is
-        assumed the event will always be consumed (e.g., we want to
-        consume key presses as well, but not really process them).
+    def processInputEvent(self, script, keyboardEvent, modifiers):
+        """Processes the given input event.  Returns True if a handler
+        was found and the event was actually processed.
         """
-        return Bindings._consumeInputEvent(
+        return Bindings._processInputEvent(
             self, 
             script,
             keyboardEvent,
@@ -491,10 +479,11 @@
     def __init__(self):
         Bindings.__init__(self)
 
-    def consumeInputEvent(self, script, brailleEvent, modifiers):
-        """Attempts to consume the given braille event.
+    def processInputEvent(self, script, brailleEvent, modifiers):
+        """Processes the given input event.  Returns True if a handler
+        was found and the event was actually processed.
         """
-        return Bindings._consumeInputEvent(
+        return Bindings._processInputEvent(
             self,
             script,
             brailleEvent,

Modified: branches/phase2/src/orca/orca.in
==============================================================================
--- branches/phase2/src/orca/orca.in	(original)
+++ branches/phase2/src/orca/orca.in	Sat Sep 13 08:59:49 2008
@@ -113,41 +113,6 @@
     cleanup
 }
 
-main()
-{
-    RUN=1
-    while [ "$RUN" -gt 0 ]
-    do
-        runOrca &
-        orca_pid=$!
-        wait $orca_pid
-
-        RUN=$?  # quit on a normal exit status from Orca
-
-        # We will stop re-running Orca on SEGV's (139 = SEGV + 128).
-        # The reason for this is that there are cases where Python
-        # will SEGV when Orca attempts to exit normally.  This happens
-        # because of something going on in pyorbit.  This should be
-        # fixed in pyorbit 2.14.1, but not everyone has that.
-        # So...we'll check for it.
-        #
-        if [ "$RUN" -eq 139 ]
-        then
-            RUN=0
-        fi
-
-        # We will also stop re-running Orca on KILL's (137 = KILL + 128).
-        # The reason for this is that if someone has done a "kill -KILL"
-        # on the Python process, it was probably on purpose and they want
-        # everything to die.
-        #
-        if [ "$RUN" -eq 137 ]
-        then
-            RUN=0
-        fi
-    done
-}
-
 trap kill_orca QUIT TERM INT ABRT
 trap hup_orca HUP
 

Modified: branches/phase2/src/orca/orca.py
==============================================================================
--- branches/phase2/src/orca/orca.py	(original)
+++ branches/phase2/src/orca/orca.py	Sat Sep 13 08:59:49 2008
@@ -15,6 +15,21 @@
 # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
 # Boston MA  02110-1301 USA.
 
+# TODO: key echo (perhaps move this to the script itself?)
+# TODO: speech stopping on mouse buttons (perhaps in script itself?)
+# TODO: learn mode (maybe in script manager?)
+# TODO: click count (maybe in script manager?)
+# TODO: capturing of keystrokes (maybe in script?)
+# TODO: setting Orca modifier (maybe in script manager?)
+# TODO: toggling of speech on/off (maybe per script?)
+# TODO: loading of user settings
+# TODO: main window GUI
+# TODO: preferences GUI
+# TODO: preferences console
+# TODO: help (gnome.help_display_with_doc_id)
+# TODO: quit GUI
+# TODO: find GUI
+
 """The main module for the Orca screen reader."""
 
 __id__        = "$Id: orca.py 4148 2008-09-03 14:31:54Z wwalker $"
@@ -72,65 +87,6 @@
 #
 _commandLineSettings = settings.Settings(settings.globalSettings)
 
-def abort(exitCode=1):
-    """Aborts orca because something went horribly wrong.
-    
-    Arguments:
-    - exitCode: the exit code to send to the calling process.
-    """
-
-    # We know what we are doing here, so tell pylint not to flag
-    # the _exit method call as a warning.  The disable-msg is
-    # localized to just this method.
-    #
-    # pylint: disable-msg=W0212
-    #
-    log.debug("aborting with exit code %d" % exitCode)
-    os._exit(exitCode)
-
-def timeout(signum=None, frame=None):
-    """Aborts when we get a timeout, indicating an operation has
-    taken way too long.
-    """
-
-    log.debug("timeout with signum %d" % signum)
-    abort(50)
-
-exitCount = 0
-def shutdownOnSignal(signum, frame):
-    """Shuts down (gracefully if possible) when we get a given signal.
-    """
-    # We don't like globals, but we'll use it for this case.
-    #
-    # pylint: disable-msg=W0603
-    #
-    global exitCount
-
-    log.debug("shutting down and exiting due to signal = %d" % signum)
-
-    # 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:
-        shutdown()
-        cleanExit = True
-    except:
-        cleanExit = False
-
-    if not cleanExit:
-        abort(signum)
-
-def abortOnSignal(signum, frame):
-    """Aborts quickly when we get a given signal.
-    """
-    log.debug("aborting due to signal = %d" % signum)
-    abort(signum)
-
 def usage():
     """Prints out usage information.
     """
@@ -202,7 +158,7 @@
                     os.chdir(userPrefsDir)
                     _commandLineSettings["userPrefsDir"] = userPrefsDir
                 except:
-                    log.exception("exception processing user-prefs-dir:")
+                    log.exception("handled exception with user-prefs-dir:")
 
             if opt in ("-e", "--enable"):
                 feature = val.strip()
@@ -219,7 +175,7 @@
                     _commandLineSettings["showMainWindow"] = True
                 else:
                     usage()
-                    abort(2)
+                    utils.abort(2)
 
             if opt in ("-d", "--disable"):
                 feature = val.strip()
@@ -235,7 +191,7 @@
                     _commandLineSettings["showMainWindow"] = False
                 else:
                     usage()
-                    abort(2)
+                    utils.abort(2)
 
             if opt in ("-s", "--gui-setup", "--setup"):
                 _commandLineSettings["setupRequested"] = True
@@ -247,19 +203,19 @@
                 _commandLineSettings["bypassSetup"] = True
             if opt in ("-?", "--help"):
                 usage()
-                abort(0)
+                utils.abort(0)
             if opt in ("-v", "--version"):
                 print "Orca %s" % platform.version
-                abort(0)
+                utils.abort(0)
             if opt in ("-l", "--list-apps"):
                 apps = utils.getKnownApplications()
                 for app in apps:
                     print app.name
-                abort(0)
+                utils.abort(0)
     except:
         log.exception("exception processing command line arguments:")
         usage()
-        abort(2)
+        utils.abort(2)
 
 def main():
     """The main entry point for Orca.  The exit codes for Orca will
@@ -270,11 +226,12 @@
     """
     # 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)
+    utils.shutdown = shutdown
+    signal.signal(signal.SIGHUP, utils.shutdownOnSignal)
+    signal.signal(signal.SIGINT, utils.shutdownOnSignal)
+    signal.signal(signal.SIGTERM, utils.shutdownOnSignal)
+    signal.signal(signal.SIGQUIT, utils.shutdownOnSignal)
+    signal.signal(signal.SIGSEGV, utils.abortOnSignal)
 
     # See if the desktop is running.  If it is, the import of gtk will
     # succeed.  If it isn't, the import will fail.

Modified: branches/phase2/src/orca/script.py
==============================================================================
--- branches/phase2/src/orca/script.py	(original)
+++ branches/phase2/src/orca/script.py	Sat Sep 13 08:59:49 2008
@@ -15,6 +15,21 @@
 # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
 # Boston MA  02110-1301 USA.
 
+# TODO: Add ability for script to find/load/save its own settings file.
+# TODO: Add bookmarks support
+# TODO: Add where am I support
+# TODO: Add braille generator support
+# TODO: Add speech generator support
+# TODO: Add tutorial support
+# TODO: Add structural navigation support
+# TODO: Add flat review support
+# TODO: Add click count
+# TODO: Add hook to override key bindings
+# TODO: Add hook to override braille bindings
+# TODO: Add hook to override pronunciations
+# TODO: Add locus of focus support
+# TODO: Add key bypass
+
 """Each script maintains a set of key bindings, braille bindings, and
 AT-SPI event listeners.  The key bindings are an instance of
 KeyBindings.  The braille bindings are also a dictionary where the
@@ -27,7 +42,8 @@
 
 This Script class is not intended to be instantiated directly.
 Instead, it is expected that subclasses of the Script class will be
-created in their own module.  See default.py for an example."""
+created in their own module.  See default.py for an example.
+"""
 
 __id__        = "$Id: script.py 4103 2008-08-15 11:07:31Z wwalker $"
 __version__   = "$Revision: 4103 $"
@@ -39,6 +55,8 @@
 log = logging.getLogger('orca.script')
 
 import braille
+import input_bindings
+import utils
 
 class Script:
     """The specific focus tracking scripts for applications.
@@ -61,12 +79,16 @@
         self._name += " (module=" + self.__module__ + ")"
         
         self._isActive = False
-
         self.presentIfInactive = False
-        self.listeners = self._createListeners()
-        self.keyBindings = self._createKeyBindings()
-        self.brailleBindings = self._createBrailleBindings()
+        
+        self._objectEventListeners = self._createObjectEventListeners()
+        self._inputEventHandlers = self._createInputEventHandlers()
+        self._keyBindings = self._createKeyBindings()
+        self._brailleBindings = self._createBrailleBindings()
 
+        self._focus = None
+        self._pointOfReference = {}
+        
         log.debug("NEW SCRIPT: %s" % self)
 
     def __str__(self):
@@ -74,7 +96,7 @@
         """
         return self._name
 
-    def _createListeners(self):
+    def _createObjectEventListeners(self):
         """Sets up the AT-SPI event listeners for this script.
 
         Returns a dictionary where the keys are AT-SPI event names
@@ -82,19 +104,28 @@
         """
         return {}
 
+    def _createInputEventHandlers(self):
+        """Defines InputEventHandler fields for this script that can be
+        called by the key and braille bindings.
+
+        Returns a dictionary where the key is a handler name and the
+        values are instances if input_event.InputEventHandler.
+        """
+        return {}
+
     def _createKeyBindings(self):
         """Defines the key bindings for this script.
 
         Returns an instance of input_bindings.KeyBindings.
         """
-        return []
+        return input_bindings.KeyBindings()
 
     def _createBrailleBindings(self):
         """Defines the braille bindings for this script.
 
         Returns an instance of input_bindings.BrailleBindings
         """
-        return []
+        return input_bindings.BrailleBindings()
 
     def _getPronunciations(self):
         """Defines the application specific pronunciations for this script.
@@ -114,12 +145,15 @@
 
         Returns True if the event is of interest.
         """
+        # TODO: implement consumesKeyboardEvent
+        # TODO: add support for user-settings.py keyBindingsMap
         return False
 
     def processKeyboardEvent(self, keyboardEvent):
         """Called whenever a key is pressed on the Braille display
         and we have an interest in it.
         """
+        # TODO: implement processKeyboardEvent
         log.debug("processKeyboardEvent %s" % keyboardEvent)
 
     def consumesBrailleEvent(self, brailleEvent):
@@ -132,6 +166,8 @@
 
         Returns True if the event is of interest.
         """
+        # TODO: implement consumesBrailleEvent
+        # TODO: add support for user-settings.py keyBindingsMap
         return False
 
     def processBrailleEvent(self, brailleEvent):
@@ -141,6 +177,7 @@
         Arguments:
         - brailleEvent: an instance of input_event.BrailleEvent
         """
+        # TODO: implement processBrailleEvent
         log.debug("processBrailleEvent %s" % brailleEvent)
 
     def processObjectEvent(self, event):
@@ -171,25 +208,43 @@
         # keys is *not* deterministic, and is not guaranteed to be related
         # to the order in which they were added.
         #
-        for key in self.listeners.keys():
+        for key in self._objectEventListeners.keys():
             if event.type.startswith(key):
-                self.listeners[key](event)
+                self._objectEventListeners[key](event)
 
     def activate(self):
-        """Called when this script is activated."""
+        """Called when this script is activated.
+        """
+        if self._isActive:
+            return
+
         log.debug("%s has been activated" % self)
 
-        self._isActive = True
+        for eventType in self._objectEventListeners.keys():
+            utils.registerEventListener(eventType)
 
-        # Tell BrlTTY which commands we care about.
-        # [[[TODO: WDW - do this.]]]
+        # TODO: Tell BrlTTY which commands we care about by looking at
+        # self._brailleBindings
         #
         braille.setupKeyRanges([])
 
+        self._isActive = True
+
     def deactivate(self):
-        """Called when this script is deactivated."""
+        """Called when this script is deactivated.
+        """
+        if not self._isActive:
+            return
+
         log.debug("%s has been deactivated" % self)
 
+        for eventType in self._objectEventListeners.keys():
+            utils.deregisterEventListener(eventType)
+
+        # Tell BrlTTY which commands we don't care about events any more.
+        #
+        braille.setupKeyRanges([])
+
         self._isActive = False
 
 if __name__ == "__main__":

Modified: branches/phase2/src/orca/script_manager.py
==============================================================================
--- branches/phase2/src/orca/script_manager.py	(original)
+++ branches/phase2/src/orca/script_manager.py	Sat Sep 13 08:59:49 2008
@@ -15,6 +15,9 @@
 # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
 # Boston MA  02110-1301 USA.
 
+# TODO: incorporate utils.startTimeout for handling events
+# TODO: add bandaid for tooltips from old focus_tracking_presenter?
+
 """Provides the script manager for Orca."""
 
 __id__  = "$Id: focus_tracking_presenter.py 4088 2008-08-06 20:42:48Z wwalker $"
@@ -95,9 +98,10 @@
         self._gidleId        = 0
         self._eventQueue     = Queue.Queue(0)
 
-        self._registerEventListener("window:activate")
-        self._registerEventListener("window:deactivate")
-        self._registerEventListener("object:children-changed:remove")
+        utils.setEventListenerCallback(self._enqueueEvent)
+        utils.registerEventListener("window:activate")
+        utils.registerEventListener("window:deactivate")
+        utils.registerEventListener("object:children-changed:remove")
 
         # Cover all masks in 8 bits.
         #
@@ -144,75 +148,6 @@
 
     ########################################################################
     #                                                                      #
-    # METHODS FOR KEEPING TRACK OF LISTENERS REGISTERED WITH ATSPI         #
-    #                                                                      #
-    ########################################################################
-
-    def _registerEventListener(self, eventType):
-        """Tells this module to listen for the given event type.
-
-        Arguments:
-        - eventType: the event type.
-        """
-        if eventType in self._listenerCounts:
-            self._listenerCounts[eventType] += 1
-        else:
-            pyatspi.Registry.registerEventListener(self._enqueueEvent,
-                                                   eventType)
-            self._listenerCounts[eventType] = 1
-
-    def _deregisterEventListener(self, eventType):
-        """Tells this module to stop listening for the given event type.
-
-        Arguments:
-        - eventType: the event type.
-        """
-        self._listenerCounts[eventType] -= 1
-        if self._listenerCounts[eventType] == 0:
-            pyatspi.Registry.deregisterEventListener(self._enqueueEvent,
-                                                     eventType)
-            del self._listenerCounts[eventType]
-
-    def _registerAllEvents(self):
-        """Register all top-level event types except for "mouse".
-        """
-        topLevelEvents = filter(lambda et: ':' not in et and 'mouse' not in et,
-                                pyatspi.EVENT_TREE)
-        for event_type in topLevelEvents:
-            pyatspi.Registry.registerEventListener(
-                self._enqueueEvent, event_type)
-
-    def _deregisterAllEvents(self):
-        """Unregister for all the event types except for "mouse".
-        """
-        topLevelEvents = filter(lambda et: ':' not in et and 'mouse' not in et,
-                                pyatspi.EVENT_TREE)
-        for event_type in topLevelEvents:
-            pyatspi.Registry.deregisterEventListener(
-                self._enqueueEvent, event_type)
-
-    def _registerEventListeners(self, script):
-        """Tells the ScriptManager to listen for all
-        the event types of interest to the script.
-
-        Arguments:
-        - script: the script.
-        """
-        for eventType in script.listeners.keys():
-            self._registerEventListener(eventType)
-
-    def _deregisterEventListeners(self, script):
-        """Tells the FocusTrackingPresenter to stop listening for all the
-        event types of interest to the script.
-
-        Arguments:
-        - script: the script.
-        """
-        for eventType in script.listeners.keys():
-            self._deregisterEventListener(eventType)
-
-    ########################################################################
-    #                                                                      #
     # METHODS FOR KEEPING TRACK OF KNOWN SCRIPTS.                          #
     #                                                                      #
     ########################################################################
@@ -279,7 +214,7 @@
                     except ImportError:
                         log.debug("...could not find %s.py" % name)
                     except:
-                        log.exception("while attempting to import %s" % name)
+                        log.exception("handled exception importing %s:" % name)
             if module:
                 try:
                     script = module.Script(app)
@@ -288,7 +223,7 @@
                     # we want to let the script developer know what went wrong,
                     # but we also want to move along without crashing Orca.
                     #
-                    log.exception("while attempting to create script")
+                    log.exception("handled exception creating script:")
 
         # If there is no custom script for an application, try seeing if
         # there is a script for the toolkit of the application.  If there
@@ -314,7 +249,7 @@
                 except ImportError:
                     log.debug("...could not find %s.py" % name)
                 except:
-                    log.exception("while attempting to import %s" % name)
+                    log.exception("handled exception importing %s:" % name)
 
         if not script:
             script = default.Script(app)
@@ -338,13 +273,7 @@
             for app in self._knownScripts.keys():
                 if app not in desktop:
                     script = self._knownScripts[app]
-                    self._deregisterEventListeners(script)
-
-                    # Provide a bunch of hints to the garbage collector
-                    # that we just don't care about this stuff any longer.
-                    # Note the "app.app = None" - that helps remove a
-                    # cycle of the application referring to itself.
-                    #
+                    script.deactivate()
                     del self._knownScripts[app]
                     del app
                     del script
@@ -366,14 +295,12 @@
         if not app:
             if not self._defaultScript:
                 self._defaultScript = default.Script(None)
-                self._registerEventListeners(self._defaultScript)
             script = self._defaultScript
         elif app in self._knownScripts:
             script = self._knownScripts[app]
         else:
             script = self._createScript(app)
             self._knownScripts[app] = script
-            self._registerEventListeners(script)
 
         return script
 
@@ -410,7 +337,7 @@
         try:
             self._activeScript.processKeyboardEvent(keyboardEvent)
         except:
-            log.exception("exception while processing keyboard event:")
+            log.exception("handled exception while processing keyboard event:")
 
     def _dispatchBrailleEvent(self, brailleEvent):
         """Called whenever we get a braille input event.
@@ -421,7 +348,7 @@
         try:
             self._activeScript.processBrailleEvent(brailleEvent)
         except:
-            log.exception("exception while processing braille event:")
+            log.exception("handled exception while processing braille event:")
 
     def _dispatchObjectEvent(self, event):
         """Handles all events destined for scripts.
@@ -487,7 +414,7 @@
                 log.debug("IGNORING DEFUNCT OBJECT")
                 return
         except:
-            log.exception("exception while checking object state for defunct:")
+            log.exception("handled exception while checking for defunct:")
             return
 
         try:
@@ -503,7 +430,7 @@
                 s = self._activeScript
         except:
             s = None
-            log.exception("exception while trying to find script:")
+            log.exception("handled exception trying to find script:")
             return
 
         if not s:
@@ -580,7 +507,7 @@
                         log.warning("  SUCCEEDED AFTER %d TRIES" % retryCount)
                 break
             except LookupError:
-                log.exception("exception while processing %s" % event.type)
+                log.exception("handled exception processing %s:" % event.type)
                 retryCount += 1
                 if retryCount <= commFailureAttemptLimit:
                     log.warning("  TRYING AGAIN (%d)" % retryCount)
@@ -588,7 +515,7 @@
                 else:
                     log.warning("  GIVING UP AFTER %d TRIES" % (retryCount - 1))
             except:
-                log.exception("exception while processing %s" % event.type)
+                log.exception("handled exception processing %s:" % event.type)
                 break
 
     def _enqueueEvent(self, e):
@@ -673,7 +600,7 @@
         except Queue.Empty:
             rerun = False
         except:
-            log.exception("while processing event")
+            log.exception("handled exception processing event:")
 
         return rerun
 

Modified: branches/phase2/src/orca/settings.py
==============================================================================
--- branches/phase2/src/orca/settings.py	(original)
+++ branches/phase2/src/orca/settings.py	Sat Sep 13 08:59:49 2008
@@ -50,6 +50,11 @@
             except TypeError:
                 raise KeyError(key)
 
+# Global settings that scripts can use when creating their own
+# Settings instances.
+#
+# TODO: fill these in with defaults from the old settings.py.
+#
 globalSettings = Settings()
 
 if __name__ == "__main__":
@@ -67,4 +72,4 @@
     try:
         print blah["o"]
     except KeyError:
-        log.exception("This exception is expected:")
+        log.exception("the following exception is expected:")

Modified: branches/phase2/src/orca/utils.py
==============================================================================
--- branches/phase2/src/orca/utils.py	(original)
+++ branches/phase2/src/orca/utils.py	Sat Sep 13 08:59:49 2008
@@ -15,6 +15,10 @@
 # Free Software Foundation, Inc., Franklin Street, Fifth Floor,
 # Boston MA  02110-1301 USA.
 
+# Allow globals to be used in this module.
+#
+# pylint: disable-msg=W0603
+
 """Common utilities for the Orca screen reader."""
 
 __id__        = "$Id: orca.py 4148 2008-09-03 14:31:54Z wwalker $"
@@ -26,7 +30,166 @@
 import logging
 log = logging.getLogger('orca.utils')
 
+import os
 import pyatspi
+import signal
+import sys
+import traceback
+
+def logStack(logger):
+    """Logs a snapshot of the stack to the given logger without
+    including the stack trace for this specific method.
+    """
+    # We know what we are doing here, so tell pylint not to flag
+    # the _getframe method call as a warning.  The disable-msg is
+    # localized to just this method.
+    #
+    # pylint: disable-msg=W0212
+    #
+    logger.debug('current stack:\n %s' \
+    % "".join(traceback.format_stack(sys._getframe(1), 100)).strip("\n")[1:])
+
+############################################################################
+#                                                                          #
+# METHODS FOR DEALING WITH SIGNALS, EXITING, ABORTING, AND TIMEOUTS        #
+#                                                                          #
+############################################################################
+
+# The timeout value (in seconds) used to determine if Orca has hung or not.
+# A value of 0 means don't do hang checking.
+#
+timeoutTime = 10
+
+def abort(exitCode=1):
+    """Aborts orca because something went horribly wrong.
+    
+    Arguments:
+    - exitCode: the exit code to send to the calling process.
+    """
+    # We know what we are doing here, so tell pylint not to flag
+    # the _exit method call as a warning.  The disable-msg is
+    # localized to just this method.
+    #
+    # pylint: disable-msg=W0212
+    #
+    log.debug("aborting with exit code %d" % exitCode)
+    os._exit(exitCode)
+
+shutdown = None
+def shutdownOnSignal(signum, frame):
+    """Shuts down (gracefully if possible) when we get a given signal.
+    """
+    log.debug("shutting down and exiting due to signal = %d" % signum)
+
+    # We know shutdown may not be callable (i.e., it might be None),
+    # so we trap for it in a try/except clause.
+    #
+    # pylint: disable-msg=E1102
+    #
+    try:
+        shutdown()
+    except:
+        abort(signum)
+        
+def abortOnSignal(signum, frame):
+    """Aborts quickly when we get a given signal.
+    """
+    log.debug("aborting due to signal = %d" % signum)
+    abort(signum)
+
+def timeout(signum=None, frame=None):
+    """Aborts when we get a timeout, indicating an operation has
+    taken way too long.
+    """
+    log.critical("timeout with signum %d:" % signum)
+    logStack(log)
+    abort(50)
+
+def startTimeout():
+    """Adds a timeout alarm.  Must call stopTimeout to stop it."""
+    if timeoutTime > 0:
+        signal.signal(signal.SIGALRM, timeout)
+        signal.alarm(timeoutTime)
+
+def stopTimeout():
+    """Removes a timeout alarm set by startTimeout."""
+    if timeoutTime > 0:
+        signal.alarm(0)
+
+############################################################################
+#                                                                          #
+# METHODS FOR LIMITING THE NUMBER OF REGISTERED EVENT LISTENERS TO 1       #
+#                                                                          #
+############################################################################
+
+_eventListenerCounts = {}
+_eventListenerCallback = None
+
+def setEventListenerCallback(callback):
+    """Sets the event listener callback.  This must be called before
+    any calls to registerEventListener or deregisterEventListener.
+    """
+    global _eventListenerCallback
+    if _eventListenerCallback:
+        log.critical("setEventListenerCallback called more than once!!!")
+        abort()
+    _eventListenerCallback = callback
+    
+def registerEventListener(eventType):
+    """Listen for the given event type.
+
+    Arguments:
+    - eventType: the event type.
+    """
+    if not _eventListenerCallback:
+        log.critical("setEventListenerCallback not set!!!")
+        abort()
+
+    if eventType in _eventListenerCounts:
+        _eventListenerCounts[eventType] += 1
+    else:
+        pyatspi.Registry.registerEventListener(_eventListenerCallback,
+                                               eventType)
+        _eventListenerCounts[eventType] = 1
+
+def deregisterEventListener(eventType):
+    """Stop listening for the given event type.
+
+    Arguments:
+    - eventType: the event type.
+    """
+    
+    if not _eventListenerCallback:
+        log.critical("setEventListenerCallback not set!!!")
+        abort()
+
+    _eventListenerCounts[eventType] -= 1
+    if _eventListenerCounts[eventType] == 0:
+        pyatspi.Registry.deregisterEventListener(_eventListenerCallback,
+                                                 eventType)
+        del _eventListenerCounts[eventType]
+
+def registerAllEvents():
+    """Register all top-level event types except for "mouse".
+    """
+    topLevelEvents = filter(lambda et: ':' not in et and 'mouse' not in et,
+                            pyatspi.EVENT_TREE)
+    for event_type in topLevelEvents:
+        registerEventListener(event_type)
+
+def deregisterAllEvents():
+    """Unregister for all the event types except for "mouse".
+    """
+    topLevelEvents = filter(lambda et: ':' not in et and 'mouse' not in et,
+                            pyatspi.EVENT_TREE)
+    for event_type in topLevelEvents:
+        deregisterEventListener(event_type)
+
+############################################################################
+#                                                                          #
+# METHODS FOR FINDING THE KNOWN ACCESSIBLE APPLICATIONS AND ACTIVE WINDOW  #
+#                                                                          #
+############################################################################
 
 def getKnownApplications():
     """Retrieves the list of currently running apps for the desktop
@@ -60,12 +223,16 @@
                     window = child
                     break
             except:
-                log.exception("exception looking at accessible's state")
+                log.exception("handled exception looking at accessible state:")
 
     log.debug("...findActiveWindow: %s" % window)
 
     return window
 
+def _myCallback(event):
+    """Just for testing when run in standalone mode."""
+    print event
+
 if __name__ == "__main__":
     logging.basicConfig(format="%(name)s %(message)s")
     log.setLevel(logging.DEBUG)
@@ -74,3 +241,20 @@
     for application in getKnownApplications():
         print "  ", application
     print "Active window: %s" % findActiveWindow()    
+
+    print "Checking logStack method:"
+    logStack(log)
+
+    print "Checking timeout support (wait %d seconds):" % (timeoutTime - 3)
+    import time
+    startTimeout()
+    time.sleep(timeoutTime - 3)
+    stopTimeout()
+
+    print "Listening for window events.  Press Ctrl+C to quit."
+    setEventListenerCallback(_myCallback)
+    registerEventListener("window")
+    registerEventListener("window")
+    deregisterEventListener("window")
+    pyatspi.Registry.start()
+    



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]