예제 #1
0
    def _processObjectEvent(self, event):
        """Handles all object events destined for scripts.

        Arguments:
        - e: an at-spi event.
        """

        debug.printObjectEvent(debug.LEVEL_FINEST, event)
        eType = event.type

        if eType.startswith("object:children-changed:remove"):
            try:
                if event.source == self.registry.getDesktop(0):
                    _scriptManager.reclaimScripts()
                    if settings.debugMemoryUsage:
                        orca.cleanupGarbage()
                    if not event.source.childCount:
                        orca.shutdown()
                    return
            except (LookupError, RuntimeError):
                # If we got this error here, we'll get it again when we
                # attempt to get the state, catch it, and clean up.
                pass
            except:
                debug.printException(debug.LEVEL_WARNING)
                return

        # Clean up any flat review context so that Orca does not get
        # confused (see bgo#609633)
        #
        if (
            eType.startswith("window:deactivate")
            and orca_state.activeScript
            and orca_state.activeScript.flatReviewContext
            and orca_state.activeScript.app == event.host_application
        ):
            orca_state.activeScript.drawOutline(-1, 0, 0, 0)
            orca_state.activeScript.flatReviewContext = None

        try:
            state = event.source.getState()
        except (LookupError, RuntimeError):
            debug.println(debug.LEVEL_WARNING, "Error while processing event: %s" % eType)
            if eType.startswith("window:deactivate"):
                orca.setLocusOfFocus(event, None)
                orca_state.activeWindow = None
            return
        except:
            debug.printException(debug.LEVEL_WARNING)
            return

        if state and state.contains(pyatspi.STATE_DEFUNCT):
            debug.println(debug.LEVEL_FINEST, "IGNORING DEFUNCT OBJECT")
            if eType.startswith("window:deactivate"):
                orca.setLocusOfFocus(event, None)
                orca_state.activeWindow = None
            return

        if state and state.contains(pyatspi.STATE_ICONIFIED):
            debug.println(debug.LEVEL_FINEST, "IGNORING ICONIFIED OBJECT")
            return

        if not debug.eventDebugFilter or debug.eventDebugFilter.match(eType) and not eType.startswith("mouse:"):
            debug.printDetails(debug.LEVEL_FINEST, "    ", event.source)

        script = self._getScriptForEvent(event)
        debug.println(debug.LEVEL_FINEST, "Script for event: %s" % script.name)
        setNewActiveScript, reason = self._isActivatableEvent(event, script)
        if setNewActiveScript:
            app = event.host_application or event.source.getApplication()
            _scriptManager.setActiveScript(script, reason)

        script.processObjectEvent(event)
    def _processObjectEvent(self, event):
        """Handles all events destined for scripts.

        Arguments:
        - e: an at-spi event.
        """

        debug.printObjectEvent(debug.LEVEL_FINEST, event)

        # [[[TODO: WDW - HACK to prevent gnome-panel from killing
        # itself.  It seems to do so after it issues some tool tip
        # events and Orca attempts to process them.  We're not really
        # doing anything with tool tips right now, so we just ignore
        # them.  Note that this is just a bandaid to the problem.  We
        # should do something better.  Please refer to bug 368626
        # http://bugzilla.gnome.org/show_bug.cgi?id=368626 to follow
        # this problem.]]]
        #
        try:
            if event.source.role == rolenames.ROLE_TOOL_TIP:
                # Check that it's okay to present tool tips. Always present
                # tooltips initiated by the user pressing Control-F1 on the
                # keyboard.
                #
                if isinstance(orca_state.lastInputEvent, \
                              input_event.KeyboardEvent):
                    if not orca_state.lastNonModifierKeyEvent.event_string == "F1":
                        return

                    # Mouse move events don't update orca_state.lastInputEvent
                    # so it's possible the user accidentally nudged the
                    # mouse and generated another tooltip event. If the
                    # current time minus the last keyboard event time is
                    # greater than 0.2 seconds, than just ignore this tooltip
                    # event.
                    #
                    currentTime =  time.time()
                    if (currentTime - orca_state.lastInputEvent.time) > 0.2:
                        return
                elif not settings.presentToolTips:
                    return
        except:
            pass

        # Reclaim (delete) any scripts when desktop children go away.
        # The idea here is that a desktop child is an app. We also
        # generally do not like object:children-changed:remove events,
        # either.
        #
        if event.type.startswith("object:children-changed:remove"):
            if event.source == atspi.Accessible.makeAccessible(
                                   self.registry.desktop):
                self._reclaimScripts()
                self._cleanupCache()
                if settings.debugMemoryUsage:
                    self._cleanupGarbage()
            return

        try:
            # We don't want to touch a defunct object.  It's useless and it
            # can cause hangs.
            #
            if event.source \
               and event.source.state.count(atspi.Accessibility.STATE_DEFUNCT):
                debug.println(debug.LEVEL_FINEST,
                              "IGNORING DEFUNCT OBJECT")
                atspi.Accessible.deleteAccessible(event.source)
                return

            if (not debug.eventDebugFilter) \
                or (debug.eventDebugFilter \
                    and debug.eventDebugFilter.match(event.type)):
                if not event.type.startswith("mouse:"):
                    debug.printDetails(debug.LEVEL_FINEST, "    ", event.source)

        except CORBA.COMM_FAILURE:
            debug.printException(debug.LEVEL_WARNING)
            debug.println(debug.LEVEL_FINEST,
                          "COMM_FAILURE above while processing event: " \
                          + event.type)
        except CORBA.OBJECT_NOT_EXIST:
            debug.printException(debug.LEVEL_WARNING)
            debug.println(debug.LEVEL_WARNING,
                          "OBJECT_NOT_EXIST above while processing event: " \
                          + event.type)
            atspi.Accessible.deleteAccessible(event.source)
            return
        except:
            debug.printException(debug.LEVEL_WARNING)
            return

        if not event.source:
            debug.println(debug.LEVEL_WARNING,
                          "ERROR: received an event with no source.")
            return

        # We can sometimes get COMM_FAILURES even if the object has not
        # gone away.  This happens a lot with the Java access bridge.
        # So...we will try a few times before giving up.
        #
        # [[[TODO: WDW - might want to consider re-introducing the reload
        # feature of scripts somewhere around here.  I pulled it out as
        # part of the big refactor to make scripts object-oriented. Logged
        # as bugzilla bug 319777.]]]
        #
        retryCount = 0
        oldLocusOfFocus = orca_state.locusOfFocus
        try:
            # If we've received a mouse event, then don't try to get
            # event.source.app because the top most parent is of role
            # unknown, which will cause an ERROR message to be displayed.
            # See Orca bug #409731 for more details.
            #
            if not event.type.startswith("mouse:"):
                s = self._getScript(event.source.app)
            else:
                s = orca_state.activeScript
            if not s:
                return
        except:
            s = None
            debug.printException(debug.LEVEL_WARNING)
            debug.println(debug.LEVEL_WARNING,
                          "ERROR: received an event, but Script is None")

        while s and retryCount <= s.commFailureAttemptLimit:
            try:
                if not event.source.state.count( \
                                      atspi.Accessibility.STATE_ICONIFIED):

                    # [[[TODO: WDW - HACK we look for frame that get
                    # focus: as a means to detect active scripts
                    # because yelp does this.  Actually, yelp is a bit
                    # odd in that it calls itself 'yelp' then changes
                    # its application name and id to the Gecko toolkit
                    # in use, and then issues a focus: event on the
                    # main window, which is a frame.]]]
                    #
                    if event.type.startswith("window:activate") \
                       or (event.type.startswith("focus:") \
                           and (event.source.role == rolenames.ROLE_FRAME)):

                        # We'll let someone else decide if it's important
                        # to stop speech or not.
                        #speech.stop()
                        debug.println(debug.LEVEL_FINE, "ACTIVE SCRIPT: " \
                                      + orca_state.activeScript.name)

                        self.setActiveScript(self._getScript(event.source.app))

                        # Load in the application specific settings for the
                        # app for this event (if found).
                        #
                        appSettings = self.loadAppSettings( \
                                                      orca_state.activeScript)

                        # Tell BrlTTY which commands we care about.
                        #
                        braille.setupKeyRanges(\
                            orca_state.activeScript.brailleBindings.keys())

                    s.processObjectEvent(event)
                    if retryCount:
                        debug.println(debug.LEVEL_WARNING,
                                      "  SUCCEEDED AFTER %d TRIES" % retryCount)
                break
            except CORBA.COMM_FAILURE:
                debug.printException(debug.LEVEL_WARNING)
                debug.println(debug.LEVEL_WARNING,
                              "COMM_FAILURE above while processing: " \
                              + event.type)
                retryCount += 1
                if retryCount <= s.commFailureAttemptLimit:
                    # We want the old locus of focus to be reset so
                    # the proper stuff will be spoken if the locus
                    # of focus changed during our last attempt at
                    # handling this event.
                    #
                    orca_state.locusOfFocus = oldLocusOfFocus
                    debug.println(debug.LEVEL_WARNING,
                                  "  TRYING AGAIN (%d)" % retryCount)
                    time.sleep(s.commFailureWaitTime)
                else:
                    debug.println(debug.LEVEL_WARNING,
                                  "  GIVING UP AFTER %d TRIES" \
                                  % (retryCount - 1))
                    atspi.Accessible.deleteAccessible(event.source)
            except:
                debug.printException(debug.LEVEL_WARNING)
                break
예제 #3
0
    def _processObjectEvent(self, event):
        """Handles all events destined for scripts.

        Arguments:
        - e: an at-spi event.
        """

        debug.printObjectEvent(debug.LEVEL_FINEST, event)

        # [[[TODO: WDW - HACK to prevent gnome-panel from killing
        # itself.  It seems to do so after it issues some tool tip
        # events and Orca attempts to process them.  We're not really
        # doing anything with tool tips right now, so we just ignore
        # them.  Note that this is just a bandaid to the problem.  We
        # should do something better.  Please refer to bug 368626
        # http://bugzilla.gnome.org/show_bug.cgi?id=368626 to follow
        # this problem.]]]
        #
        try:
            if event.source.role == rolenames.ROLE_TOOL_TIP:
                # Check that it's okay to present tool tips. Always present
                # tooltips initiated by the user pressing Control-F1 on the
                # keyboard.
                #
                if isinstance(orca_state.lastInputEvent, \
                              input_event.KeyboardEvent):
                    if not orca_state.lastNonModifierKeyEvent.event_string == "F1":
                        return

                    # Mouse move events don't update orca_state.lastInputEvent
                    # so it's possible the user accidentally nudged the
                    # mouse and generated another tooltip event. If the
                    # current time minus the last keyboard event time is
                    # greater than 0.2 seconds, than just ignore this tooltip
                    # event.
                    #
                    currentTime = time.time()
                    if (currentTime - orca_state.lastInputEvent.time) > 0.2:
                        return
                elif not settings.presentToolTips:
                    return
        except:
            pass

        # Reclaim (delete) any scripts when desktop children go away.
        # The idea here is that a desktop child is an app. We also
        # generally do not like object:children-changed:remove events,
        # either.
        #
        if event.type.startswith("object:children-changed:remove"):
            if event.source == atspi.Accessible.makeAccessible(
                    self.registry.desktop):
                self._reclaimScripts()
                self._cleanupCache()
                if settings.debugMemoryUsage:
                    self._cleanupGarbage()
            return

        try:
            # We don't want to touch a defunct object.  It's useless and it
            # can cause hangs.
            #
            if event.source \
               and event.source.state.count(atspi.Accessibility.STATE_DEFUNCT):
                debug.println(debug.LEVEL_FINEST, "IGNORING DEFUNCT OBJECT")
                atspi.Accessible.deleteAccessible(event.source)
                return

            if (not debug.eventDebugFilter) \
                or (debug.eventDebugFilter \
                    and debug.eventDebugFilter.match(event.type)):
                if not event.type.startswith("mouse:"):
                    debug.printDetails(debug.LEVEL_FINEST, "    ",
                                       event.source)

        except CORBA.COMM_FAILURE:
            debug.printException(debug.LEVEL_WARNING)
            debug.println(debug.LEVEL_FINEST,
                          "COMM_FAILURE above while processing event: " \
                          + event.type)
        except CORBA.OBJECT_NOT_EXIST:
            debug.printException(debug.LEVEL_WARNING)
            debug.println(debug.LEVEL_WARNING,
                          "OBJECT_NOT_EXIST above while processing event: " \
                          + event.type)
            atspi.Accessible.deleteAccessible(event.source)
            return
        except:
            debug.printException(debug.LEVEL_WARNING)
            return

        if not event.source:
            debug.println(debug.LEVEL_WARNING,
                          "ERROR: received an event with no source.")
            return

        # We can sometimes get COMM_FAILURES even if the object has not
        # gone away.  This happens a lot with the Java access bridge.
        # So...we will try a few times before giving up.
        #
        # [[[TODO: WDW - might want to consider re-introducing the reload
        # feature of scripts somewhere around here.  I pulled it out as
        # part of the big refactor to make scripts object-oriented. Logged
        # as bugzilla bug 319777.]]]
        #
        retryCount = 0
        oldLocusOfFocus = orca_state.locusOfFocus
        try:
            # If we've received a mouse event, then don't try to get
            # event.source.app because the top most parent is of role
            # unknown, which will cause an ERROR message to be displayed.
            # See Orca bug #409731 for more details.
            #
            if not event.type.startswith("mouse:"):
                s = self._getScript(event.source.app)
            else:
                s = orca_state.activeScript
            if not s:
                return
        except:
            s = None
            debug.printException(debug.LEVEL_WARNING)
            debug.println(debug.LEVEL_WARNING,
                          "ERROR: received an event, but Script is None")

        while s and retryCount <= s.commFailureAttemptLimit:
            try:
                if not event.source.state.count( \
                                      atspi.Accessibility.STATE_ICONIFIED):

                    # [[[TODO: WDW - HACK we look for frame that get
                    # focus: as a means to detect active scripts
                    # because yelp does this.  Actually, yelp is a bit
                    # odd in that it calls itself 'yelp' then changes
                    # its application name and id to the Gecko toolkit
                    # in use, and then issues a focus: event on the
                    # main window, which is a frame.]]]
                    #
                    if event.type.startswith("window:activate") \
                       or (event.type.startswith("focus:") \
                           and (event.source.role == rolenames.ROLE_FRAME)):

                        # We'll let someone else decide if it's important
                        # to stop speech or not.
                        #speech.stop()
                        debug.println(debug.LEVEL_FINE, "ACTIVE SCRIPT: " \
                                      + orca_state.activeScript.name)

                        self.setActiveScript(self._getScript(event.source.app))

                        # Load in the application specific settings for the
                        # app for this event (if found).
                        #
                        appSettings = self.loadAppSettings( \
                                                      orca_state.activeScript)

                        # Tell BrlTTY which commands we care about.
                        #
                        braille.setupKeyRanges(\
                            orca_state.activeScript.brailleBindings.keys())

                    s.processObjectEvent(event)
                    if retryCount:
                        debug.println(
                            debug.LEVEL_WARNING,
                            "  SUCCEEDED AFTER %d TRIES" % retryCount)
                break
            except CORBA.COMM_FAILURE:
                debug.printException(debug.LEVEL_WARNING)
                debug.println(debug.LEVEL_WARNING,
                              "COMM_FAILURE above while processing: " \
                              + event.type)
                retryCount += 1
                if retryCount <= s.commFailureAttemptLimit:
                    # We want the old locus of focus to be reset so
                    # the proper stuff will be spoken if the locus
                    # of focus changed during our last attempt at
                    # handling this event.
                    #
                    orca_state.locusOfFocus = oldLocusOfFocus
                    debug.println(debug.LEVEL_WARNING,
                                  "  TRYING AGAIN (%d)" % retryCount)
                    time.sleep(s.commFailureWaitTime)
                else:
                    debug.println(debug.LEVEL_WARNING,
                                  "  GIVING UP AFTER %d TRIES" \
                                  % (retryCount - 1))
                    atspi.Accessible.deleteAccessible(event.source)
            except:
                debug.printException(debug.LEVEL_WARNING)
                break