orca r3782 - in trunk: . src/orca



Author: eitani
Date: Fri Mar 28 20:41:31 2008
New Revision: 3782
URL: http://svn.gnome.org/viewvc/orca?rev=3782&view=rev

Log:
* src/orca/mouse_review.py:
  Fix for bug #520611.
  New mouse review feature (all of the changes below too).
* src/orca/Makefile.am:
  Added mouse_review.py.
* src/orca/default.py:
  - Added unbound mouse review toggle key.
  - Added getComponentAtDesktopCoords() (and
    _getPopupItemAtDesktopCoords).
  - Added speakWordUnderMouse().
  - Added getWordAtCoords().
* src/orca/Gecko.py:
  Added override for speakWordUnderMouse().
* src/orca/focus_tracking_presenter.py:
  Chaged _getScript to a public getScript.
* src/orca/orca.py:
  - Initialize mouse review on start up.
  - Added getScriptForApp.
* src/orca/settings.py:
  Added enableMouseReview and mouseDwellDelay
* src/orca/orca_gui_prefs.py:
* src/orca/orca-setup.glade
  Toggle mouse review in general tab.


Added:
   trunk/src/orca/mouse_review.py
Modified:
   trunk/ChangeLog
   trunk/src/orca/Gecko.py
   trunk/src/orca/Makefile.am
   trunk/src/orca/default.py
   trunk/src/orca/focus_tracking_presenter.py
   trunk/src/orca/orca-setup.glade
   trunk/src/orca/orca.py
   trunk/src/orca/orca_gui_prefs.py
   trunk/src/orca/settings.py

Modified: trunk/src/orca/Gecko.py
==============================================================================
--- trunk/src/orca/Gecko.py	(original)
+++ trunk/src/orca/Gecko.py	Fri Mar 28 20:41:31 2008
@@ -10862,6 +10862,24 @@
         speech.speak(string)
         braille.displayMessage(string)
         
+
+
+    def speakWordUnderMouse(self, acc):
+        """Determine if the speak-word-under-mouse capability applies to
+        the given accessible.
+
+        Arguments:
+        - acc: Accessible to test.
+
+        Returns True if this accessible should provide the single word.
+        """
+        if self.inDocumentContent(acc):
+            try:
+                ai = acc.queryAction()
+            except NotImplementedError:
+                return True
+        default.Script.speakWordUnderMouse(self, acc)
+
     ####################################################################
     #                                                                  #
     # Match Predicates                                                 #

Modified: trunk/src/orca/Makefile.am
==============================================================================
--- trunk/src/orca/Makefile.am	(original)
+++ trunk/src/orca/Makefile.am	Fri Mar 28 20:41:31 2008
@@ -33,6 +33,7 @@
 	keynames.py \
 	liveregions.py \
 	mag.py \
+	mouse_review.py \
 	orca.py \
 	orca_console_prefs.py \
 	orca_glade.py \

Modified: trunk/src/orca/default.py
==============================================================================
--- trunk/src/orca/default.py	(original)
+++ trunk/src/orca/default.py	Fri Mar 28 20:41:31 2008
@@ -62,6 +62,8 @@
 import settings
 import speech
 import speechserver
+import mouse_review
+
 
 from orca_i18n import _         # for gettext support
 from orca_i18n import ngettext  # for ngettext support
@@ -123,6 +125,8 @@
         self.lastProgressBarTime = {}
         self.lastProgressBarValue = {}
 
+        self.lastSelectedMenu = None
+
     def setupInputEventHandlers(self):
         """Defines InputEventHandler fields for this script that can be
         called by the key and braille bindings."""
@@ -938,6 +942,14 @@
                 #
                 _("Cycles to the next magnifier position."))
 
+        self.inputEventHandlers["toggleMouseReviewHandler"] = \
+            input_event.InputEventHandler(
+                mouse_review.toggle,
+                # Translators: Orca allows the item under the pointer to
+                # be spoken. This toggles the feature.
+                #
+                _("Toggle mouse review mode."))
+
     def getInputEventHandlerKey(self, inputEventHandler):
         """Returns the name of the key that contains an inputEventHadler
         passed as argument
@@ -1912,6 +1924,13 @@
                 0,
                 self.inputEventHandlers["panBrailleRightHandler"]))
 
+        keyBindings.add(
+            keybindings.KeyBinding(
+                None,
+                0,
+                0,
+                self.inputEventHandlers["toggleMouseReviewHandler"]))
+
         keyBindings = settings.overrideKeyBindings(self, keyBindings)
 
         return keyBindings
@@ -2837,7 +2856,6 @@
         - event: if not None, the Event that caused this to happen
         - obj: the Accessible whose visual appearance changed.
         """
-
         # Check if this event is for a progress bar.
         #
         if obj.getRole() == pyatspi.ROLE_PROGRESS_BAR:
@@ -3646,6 +3664,15 @@
         if not event or not event.source:
             return
 
+        # Save the event source, if it is a menu or combo box. It will be 
+        # useful for optimizing getComponentAtDesktopCoords in the case
+        # that the  pointer is hovering over a menu item. The alternative is
+        # to traverse the application's tree looking for potential moused-over
+        # menu items.
+        if event.source.getRole() in (pyatspi.ROLE_COMBO_BOX, 
+                                           pyatspi.ROLE_MENU):
+            self.lastSelectedMenu = event.source
+
         # Avoid doing this with objects that manage their descendants
         # because they'll issue a descendant changed event.
         #
@@ -6789,10 +6816,10 @@
         """Creates a Python dict from a typical attributes list returned from
         different AT-SPI methods.
 
+
         Arguments:
         - dict_string: A list of colon seperated key/value pairs seperated by
         semicolons.
-
         Returns a Python dict of the given attributes.
         """
         try:
@@ -6802,6 +6829,77 @@
         except ValueError:
             return {}
 
+    def _getPopupItemAtDesktopCoords(self, x, y):
+        """Since pop-up items often don't contain nested components, we need
+        a way to efficiently determine if the cursor is over a menu item.
+
+        Arguments:
+        - x: X coordinate.
+        - y: Y coordinate.
+        
+        Returns a menu item the mouse is over, or None.
+        """
+        suspect_children = []
+        if self.lastSelectedMenu:
+            try:
+                si = self.lastSelectedMenu.querySelection()
+            except NotImplementedError:
+                return None
+
+            if si.nSelectedChildren > 0:
+                suspect_children = [si.getSelectedChild(0)]
+            else:
+                suspect_children = self.lastSelectedMenu
+            for child in suspect_children:
+                try:
+                    ci = child.queryComponent()
+                except NotImplementedError:
+                    continue
+
+                if ci.contains(x,y, pyatspi.DESKTOP_COORDS) and \
+                        ci.getLayer() == pyatspi.LAYER_POPUP:
+                    return child
+
+    def getComponentAtDesktopCoords(self, parent, x, y):
+        """Get the descendant component at the given desktop coordinates.
+
+        Arguments:
+        
+        - parent: The parent component we are searching below.
+        - x: X coordinate.
+        - y: Y coordinate.
+
+        Returns end-node that contains the given coordinates, or None.
+        """
+        acc = self._getPopupItemAtDesktopCoords(x, y)
+        if acc: 
+            return acc
+
+        container = parent
+        while True:
+            if container.getRole() == pyatspi.ROLE_PAGE_TAB_LIST:
+                try:
+                    si = container.querySelection()
+                    container = si.getSelectedChild(0)[0]
+                except NotImplementedError:
+                    pass
+            try:
+                ci = container.queryComponent()
+            except:
+                return None
+            else:
+                inner_container = container
+            container =  ci.getAccessibleAtPoint(x, y, pyatspi.DESKTOP_COORDS)
+            if not container or container.queryComponent() == ci:
+                # The gecko bridge simply has getAccessibleAtPoint return
+                # itself if there are no further children.
+                # TODO: Put in Gecko.py
+                break
+        if inner_container == parent:
+            return None
+        else:
+            return inner_container
+
     def getTextSelections(self, acc):
         """Get a list of text selections in the given accessible object,
         equivelent to getNSelections()*texti.getSelection()
@@ -6824,6 +6922,17 @@
             
         return rv
 
+    def speakWordUnderMouse(self, acc):
+        """Determine if the speak-word-under-mouse capability applies to
+        the given accessible.
+
+        Arguments:
+        - acc: Accessible to test.
+
+        Returns True if this accessible should provide the single word.
+        """
+        return acc and acc.getState().contains(pyatspi.STATE_EDITABLE)
+
     def getTextAttributes(self, acc, offset, get_defaults=False):
         """Get the text attributes run for a given offset in a given accessible
 
@@ -6853,6 +6962,58 @@
 
         return rv, start, end
 
+    def getWordAtCoords(self, acc, x, y):
+        """Get the word at the given coords in the accessible.
+
+        Arguments:
+        - acc: Accessible that supports the Text interface.
+        - x: X coordinate.
+        - y: Y coordinate.
+
+        Returns a tuple containing the word, start offset, and end offset.
+        """
+        try:
+            ti = acc.queryText()
+        except NotImplementedError:
+            return '', 0, 0
+        
+        text_contents = ti.getText(0, -1)
+        line_offsets = []
+        start_offset = 0
+        while True:
+            try:
+                end_offset = text_contents.index('\n', start_offset)
+            except ValueError:
+                line_offsets.append((start_offset, len(text_contents)))
+                break
+            line_offsets.append((start_offset, end_offset))
+            start_offset = end_offset + 1
+        for start, end in line_offsets:
+            bx, by, bw, bh = \
+                ti.getRangeExtents(start, end, pyatspi.DESKTOP_COORDS)
+            bb = mouse_review.BoundingBox(bx, by, bw, bh)
+            if bb.isInBox(x, y):
+                start_offset = 0
+                word_offsets = []
+                while True:
+                    try:
+                        end_offset = \
+                            text_contents[start:end].index(' ', start_offset)
+                    except ValueError:
+                        word_offsets.append((start_offset, 
+                                             len(text_contents[start:end])))
+                        break
+                    word_offsets.append((start_offset, end_offset))
+                    start_offset = end_offset + 1
+                for a, b in word_offsets:
+                    bx, by, bw, bh = \
+                        ti.getRangeExtents(start+a, start+b,
+                                           pyatspi.DESKTOP_COORDS)
+                    bb = mouse_review.BoundingBox(bx, by, bw, bh)
+                    if bb.isInBox(x, y):
+                        return text_contents[start+a:start+b], start+a, start+b
+        return '', 0, 0
+
 # Dictionary that defines the state changes we care about for various
 # objects.  The key represents the role and the value represents a list
 # of states that we care about.

Modified: trunk/src/orca/focus_tracking_presenter.py
==============================================================================
--- trunk/src/orca/focus_tracking_presenter.py	(original)
+++ trunk/src/orca/focus_tracking_presenter.py	Fri Mar 28 20:41:31 2008
@@ -266,7 +266,7 @@
 
         return script
 
-    def _getScript(self, app):
+    def getScript(self, app):
         """Get a script for an app (and make it if necessary).  This is used
         instead of a simple calls to Script's constructor.
 
@@ -575,7 +575,7 @@
             # displayed. See Orca bug #409731 for more details.
             #
             if not event.type.startswith("mouse:"):
-                s = self._getScript(event.host_application or \
+                s = self.getScript(event.host_application or \
                                       event.source.getApplication())
             else:
                 s = orca_state.activeScript
@@ -610,7 +610,7 @@
                                       + orca_state.activeScript.name)
 
                         self.setActiveScript(
-                            self._getScript(event.host_application or \
+                            self.getScript(event.host_application or \
                                               event.source.getApplication()))
 
                         # Load in the application specific settings for the
@@ -961,7 +961,7 @@
         """Restores script and application state information."""
         try:
             for [app, appState] in self._appStateInfo:
-                script = self._getScript(app)
+                script = self.getScript(app)
                 script.setAppState(appState)
         except:
             pass
@@ -979,7 +979,7 @@
 
         self._restoreAppStates()
 
-        self.setActiveScript(self._getScript(None))
+        self.setActiveScript(self.getScript(None))
 
         # Tell BrlTTY which commands we care about.
         #

Added: trunk/src/orca/mouse_review.py
==============================================================================
--- (empty file)
+++ trunk/src/orca/mouse_review.py	Fri Mar 28 20:41:31 2008
@@ -0,0 +1,321 @@
+# Mouse reviewer for Orca
+#
+# Copyright 2008 Eitan Isaacson
+#
+# 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.
+
+"""Mouse review mode."""
+
+__id__        = "$Id$"
+__version__   = "$Revision$"
+__date__      = "$Date$"
+__copyright__ = "Copyright (c) 2008 Eitan Isaacson"
+__license__   = "LGPL"
+
+import pyatspi
+import orca_state
+import wnck
+import gtk
+import speech
+import braille
+import gobject
+import settings
+import orca
+
+class BoundingBox:
+    """A bounding box, currently it is used to test if a given point is 
+    inside the bounds of the box.
+    """
+    # TODO: Find if we pygtk or something already has this,
+    # if not, maybe this needs to be in a different Orca file.
+    def __init__(self, x, y, width, height):
+        """Initialize a bounding box.
+
+        Arguments:
+        - x: Left border of box.
+        - y: Top border of box.
+        - width: Width of box.
+        - height: Height of box.
+        """
+        self.x, self.y, self.width, self.height = x, y, width, height
+
+    def isInBox(self, x, y):
+        """Test if a given point is inside a box.
+
+        Arguments:
+        - x: X coordinate.
+        - y: Y coordinate.
+
+        Returns True if point is inside box.
+        """
+        return (self.x <= x <= self.x + self.width) and \
+            (self.y <= y <= self.y + self.height)
+
+class _WordContext:
+    """A word on which the mouse id hovering above. This class should have 
+    enough info to make it unique, so we know when we have left the word.
+    """
+    def __init__(self, word, acc, start, end):
+        """Initialize a word context.
+
+        Arguments:
+        - word: The string of the word we are on.
+        - acc: The accessible object that contains the word.
+        - start: The start offset of the word in the text.
+        - end: The end offset of the word in the text.
+        """
+        self.word = word
+        self.acc = acc
+        self.start = start
+        self.end = end
+
+    def __cmp__(self, other):
+        """Compare two word contexts, if they refer to the same word, return 0.
+        Otherwise return 1
+        """
+        if other is None: return 1
+        return int(not(self.word == other.word and self.acc == other.acc and
+                       self.start == other.start and self.end == other.end))
+
+class _ItemContext:
+    """An _ItemContext holds all the information of the item we are currently
+    hovering above. If the accessible supports word speaking, we also store 
+    a word context here.
+    """
+    def __init__(self, x=0, y=0, acc=None, frame=None, app=None, script=None):
+        """Initialize an _ItemContext with all the information we have.
+
+        Arguments:
+        - x: The X coordinate of the pointer.
+        - y: The Y coordinate of the pointer.
+        - acc: The end-node accessible at that coordinate.
+        - frame: The top-level frame below the pointer.
+        - app: The application the pointer is hovering above.
+        - script: The script for the context's application.
+        """
+        self.acc = acc
+        self.frame = frame
+        self.app = app
+        self.script = script
+        self.word_ctx = self._getWordContext(x, y)
+
+    def _getWordContext(self, x, y):
+        """If the context's accessible supports it, retrieve the word we are 
+        currently hovering above.
+
+        Arguments:
+        - x: The X coordinate of the pointer.
+        - y: The Y coordinate of the pointer.
+
+        Returns a _WordContext of the current word, or None.
+        """
+        if not self.script or not self.script.speakWordUnderMouse(self.acc):
+            return None
+        word, start, end = self.script.getWordAtCoords(self.acc, x, y)
+        return _WordContext(word, self.acc, start, end)
+
+class MouseReviewer:
+    """Main class for the mouse-review feature.
+    """
+    def __init__(self):
+        """Initalize a mouse reviewer class.
+        """
+        # Need to do this and allow the main loop to cycle once to get any info
+        wnck_screen = wnck.screen_get_default()
+        self.active = False
+        self._currentMouseOver = _ItemContext()
+        self._oldMouseOver = _ItemContext()
+        self._lastReportedCoord = None
+
+    def toggle(self, on=None):
+        """Toggle mouse reviewing on or off.
+
+        Arguments:
+        - on: If set to True or False, explicitly toggles reviewing on or off.
+        """
+        if on is None:
+            on = not self.active
+        if on and not self.active:
+            pyatspi.Registry.registerEventListener(self._onMouseMoved, 
+                                                   "mouse:abs")
+        elif not on and self.active:
+            pyatspi.Registry.deregisterEventListener(self._onMouseMoved, 
+                                                     "mouse:abs")
+        self.active = on
+                 
+
+    def _onMouseMoved(self, event):
+        """Callback for "mouse:abs" AT-SPI event. We will check after the dwell
+        delay if the mouse moved away, if it didn't we will review the 
+        component under it.
+
+        Arguments:
+        - event: The event we recieved.
+        """
+        if settings.mouseDwellDelay:
+            gobject.timeout_add(settings.mouseDwellDelay, self._mouseDwellTimeout, 
+                                event.detail1, event.detail2)
+        else:
+            self._mouseDwellTimeout(event.detail1, event.detail2)
+
+    def _mouseDwellTimeout(self, prev_x, prev_y):
+        """Dwell timout callback. If we are still dwelling, review the 
+        component.
+
+        Arguments:
+        - prev_x: Previuos X coordinate of mouse pointer.
+        - prev_y: Previuos Y coordinate of mouse pointer.
+        """
+        display = gtk.gdk.Display(gtk.gdk.get_display())
+        screen, x, y, flags =  display.get_pointer()
+        if abs(prev_x - x) <= settings.mouseDwellMaxDrift and \
+                abs(prev_y - y) <= settings.mouseDwellMaxDrift and \
+                not (x, y) == self._lastReportedCoord:
+                self._lastReportedCoord = (x, y)
+                self._reportUnderMouse(x, y)
+        return False
+        
+    def _reportUnderMouse(self, x, y):
+        """Report the element under the given coordinates:
+
+        Arguments:
+        - x: X coordinate.
+        - y: Y coordinate.
+        """
+        current_element = self._getContextUnderMouse(x, y)
+        self._currentMouseOver, self._oldMouseOver = \
+            current_element, self._currentMouseOver
+
+        output_obj = []
+
+        if current_element.acc.getRole() in (pyatspi.ROLE_MENU_ITEM,
+                                             pyatspi.ROLE_COMBO_BOX) and \
+                current_element.acc.getState().contains(
+                    pyatspi.STATE_SELECTED):
+            # If it is selected, we are probably doing that by hovering over it
+            # Orca will report this in any case.
+            return
+
+        if self._currentMouseOver.frame != self._oldMouseOver.frame and \
+                settings.mouseDwellDelay == 0:
+            output_obj.append(self._currentMouseOver.frame)
+
+        if self._currentMouseOver.acc != self._oldMouseOver.acc \
+                or (settings.mouseDwellDelay > 0 and \
+                        not self._currentMouseOver.word_ctx):
+            output_obj.append(self._currentMouseOver.acc)
+
+        if self._currentMouseOver.word_ctx:
+            if self._currentMouseOver.word_ctx != self._oldMouseOver.word_ctx:
+                output_obj.append(self._currentMouseOver.word_ctx.word)
+
+        self._outputElements(output_obj)
+        return False
+            
+    def _outputElements(self, output_obj):
+        """Output the given elements.
+        TODO: Now we are mainly using WhereAmI, we might need to find out a
+        better, less verbose output method.
+
+        Arguments:
+        - output_obj: A list of objects to output, could be accessibles and 
+        text.
+        """
+        if output_obj:
+            speech.stop()
+        for obj in output_obj:
+            if obj is None: continue
+            if isinstance(obj, str):
+                speech.speak(obj)
+                # TODO: There is probably something more useful that we could
+                # display.
+                braille.displayMessage(obj)
+            else:
+                speech.speakUtterances(
+                    self._currentMouseOver.script.speechGenerator.getSpeech(
+                            obj,
+                            False))
+                self._currentMouseOver.script.updateBraille(obj)
+    def _getZOrder(self, frame_name):
+        """Determine the stack position of a given window.
+
+        Arguments:
+        - frame_name: The name of the window.
+
+        Returns position of given window in window-managers stack.
+        """
+        # This is neccesary because z-order is still broken in AT-SPI.
+        wnck_screen = wnck.screen_get_default()
+        window_order = \
+            [w.get_name() for w in wnck_screen.get_windows_stacked()]
+        return window_order.index(frame_name)    
+        
+    def _getContextUnderMouse(self, x, y):
+        """Get the context under the mouse.
+
+        Arguments:
+        - x: X coordinate.
+        - y: Y coordinate.
+
+        Returns _ItemContext of the component under the mouse.
+        """
+        # Inspect accessible under mouse
+        desktop = pyatspi.Registry.getDesktop(0)
+        top_window = [None, -1]
+        for app in desktop:
+            if not app:
+                continue
+            script = orca.getScriptForApp(app)
+            for frame in app:
+                if not frame:
+                    continue
+                acc = script.getComponentAtDesktopCoords(
+                    frame, x, y)
+                if acc:
+                    try:
+                        z_order = self._getZOrder(frame.name)
+                    except ValueError:
+                        # It's possibly a popup menu, so it would not be in 
+                        # our frame name list.
+                        # And if it is, it is probably the top-most 
+                        # component.
+                        try:
+                            if acc.queryComponent().getLayer() == \
+                                    pyatspi.LAYER_POPUP:
+                                return _ItemContext(x, y, acc, frame, 
+                                                    app, script)
+                        except:
+                            pass
+                    else:
+                        if z_order > top_window[-1]:
+                            top_window = \
+                                [_ItemContext(x, y, acc, frame, app, script), 
+                                 z_order]
+        return top_window[0]
+
+
+# Initialize a singleton reviewer.
+mouse_reviewer = MouseReviewer()
+
+def toggle(script=None, event=None):
+    """
+    Toggle the reviewer on or off.
+
+    Arguments:
+    - script: Given script if this was called as a keybinding callback.
+    - event: Given event if this was called as a keybinding callback.
+    """
+    mouse_reviewer.toggle()

Modified: trunk/src/orca/orca-setup.glade
==============================================================================
--- trunk/src/orca/orca-setup.glade	(original)
+++ trunk/src/orca/orca-setup.glade	Fri Mar 28 20:41:31 2008
@@ -299,6 +299,26 @@
 		      <property name="fill">False</property>
 		    </packing>
 		  </child>
+
+		  <child>
+		    <widget class="GtkCheckButton" id="speakUnderMouseCheckButton">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="label" translatable="yes">Speak object under mo_use</property>
+		      <property name="use_underline">True</property>
+		      <property name="relief">GTK_RELIEF_NORMAL</property>
+		      <property name="focus_on_click">True</property>
+		      <property name="active">True</property>
+		      <property name="inconsistent">False</property>
+		      <property name="draw_indicator">True</property>
+		      <signal name="toggled" handler="speakUnderMouseChecked" last_modification_time="Mon, 17 Mar 2008 06:29:21 GMT"/>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
 		</widget>
 		<packing>
 		  <property name="tab_expand">False</property>

Modified: trunk/src/orca/orca.py
==============================================================================
--- trunk/src/orca/orca.py	(original)
+++ trunk/src/orca/orca.py	Fri Mar 28 20:41:31 2008
@@ -62,6 +62,7 @@
 import platform
 import settings
 import speech
+import mouse_review
 
 from input_event import BrailleEvent
 from input_event import KeyboardEvent
@@ -141,6 +142,17 @@
     _switchToPresentationManager(_currentPresentationManager + 1)
     return True
 
+def getScriptForApp(app):
+    """Get the script for the given application object from the current
+    presentation manager.
+
+    Arguments:
+    - app: An application accessible.
+
+    Returns a Script instance.
+    """
+    return _PRESENTATION_MANAGERS[_currentPresentationManager].getScript(app)
+
 ########################################################################
 #                                                                      #
 # METHODS TO HANDLE APPLICATION LIST AND FOCUSED OBJECTS               #
@@ -890,6 +902,11 @@
         debug.println(debug.LEVEL_CONFIGURATION,
                       "Magnification module has NOT been initialized.")
 
+
+    # I'm not sure where else this should go. But it doesn't really look
+    # right here.
+    mouse_review.mouse_reviewer.toggle(on=settings.enableMouseReview)
+
     # We don't want the Caps_Lock modifier to act as a locking
     # modifier if it used as the Orca modifier key.  In addition, if
     # the KP_Insert key is used as the Orca modifier key, we want to

Modified: trunk/src/orca/orca_gui_prefs.py
==============================================================================
--- trunk/src/orca/orca_gui_prefs.py	(original)
+++ trunk/src/orca/orca_gui_prefs.py	Fri Mar 28 20:41:31 2008
@@ -1456,6 +1456,9 @@
         interval = prefs["progressBarUpdateInterval"]
         self.get_widget("speakProgressBarSpinButton").set_value(interval)
 
+        enable = prefs["enableMouseReview"]
+        self.get_widget("speakUnderMouseCheckButton").set_active(enable)
+
         # Braille pane.
         #
         self.get_widget("brailleSupportCheckbutton").set_active( \
@@ -2720,6 +2723,22 @@
 
         self.prefsDict["progressBarUpdateInterval"] = widget.get_value_as_int()
 
+
+    def speakUnderMouseChecked(self, widget):
+        """Signal handler for the "toggled" signal for the
+           speakUnderMouseCheckButton GtkCheckButton widget.
+           The user has [un]checked the "Speak object under mouse" checkbox.
+           Set the 'enableMouseReview' preference to the new value.
+           Set the rest of the 'dwell time' hbox items [in]sensensitive
+           depending upon whether this checkbox is checked.
+
+        Arguments:
+        - widget: the component that generated the signal.
+        """
+
+        enable = widget.get_active()
+        self.prefsDict["enableMouseReview"] = enable
+
     def abbrevRolenamesChecked(self, widget):
         """Signal handler for the "toggled" signal for the abbrevRolenames
            GtkCheckButton widget. The user has [un]checked the 'Abbreviated

Modified: trunk/src/orca/settings.py
==============================================================================
--- trunk/src/orca/settings.py	(original)
+++ trunk/src/orca/settings.py	Fri Mar 28 20:41:31 2008
@@ -157,7 +157,9 @@
     "enableProgressBarUpdates",
     "progressBarUpdateInterval",
     "enableContractedBraille",
-    "brailleContractionTable"
+    "brailleContractionTable",
+    "enableMouseReview",
+    "mouseDwellDelay"
 ]
 
 # The name of the module that hold the user interface for the main window
@@ -919,3 +921,17 @@
 # Use Collection Interface?
 # 
 useCollection = True
+
+
+# Report object under mouse.
+#
+enableMouseReview = False
+
+# Mouse dwell delay in milliseconds for mouse review mode. 
+# If the value is zero, the review will be read time.
+#
+mouseDwellDelay = 0
+
+# Maximum allowed drift while pointer is dwelling in mouse review mode.
+# 
+mouseDwellMaxDrift = 3



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