[orca] Web: Attempt to work around object destruction during structural nav



commit 174658e377b3e6d8446d61ee51c9c37635ed12ae
Author: Joanmarie Diggs <jdiggs igalia com>
Date:   Tue Jan 4 14:48:15 2022 +0100

    Web: Attempt to work around object destruction during structural nav
    
    Browsers sometimes destroy objects as a result of our grabbing focus
    and/or setting the caret in those elements. When this happens, Orca
    fails to present the new object correctly because it either no longer
    exists at all, or lacks information it once had (like its name) due to
    the destruction process having been started.
    
    This commit attempts to work around that problem during structural
    navigation by detecting the condition and then looking for a
    replacement object at the same accessible path and with the same role.
    
    Note that this work around sometimes fails due to timing and/or browser
    bugs. More specifically, if AT-SPI2 has not received a children-changed
    event from the parent of the element in question at the time we look for
    that replacement, we'll still wind up with the defunct object we had
    before. That said, this workaround seems to make things suck a bit less
    than doing nothing at all to recover.

 src/orca/script_utilities.py             | 15 ++++++++
 src/orca/scripts/web/script_utilities.py | 15 --------
 src/orca/structural_navigation.py        | 62 ++++++++++++++++++++++----------
 3 files changed, 59 insertions(+), 33 deletions(-)
---
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index f5a32bfbb..290cb8874 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -1660,6 +1660,21 @@ class Utilities:
     def isSwitch(self, obj):
         return False
 
+    def getObjectFromPath(self, path):
+        start = self._script.app
+        rv = None
+        for p in path:
+            if p == -1:
+                continue
+            try:
+                start = start[p]
+            except:
+                break
+        else:
+            rv = start
+
+        return rv
+
     def _hasSamePath(self, obj1, obj2):
         path1 = pyatspi.utils.getPath(obj1)
         path2 = pyatspi.utils.getPath(obj2)
diff --git a/src/orca/scripts/web/script_utilities.py b/src/orca/scripts/web/script_utilities.py
index 7e3516582..5509c8835 100644
--- a/src/orca/scripts/web/script_utilities.py
+++ b/src/orca/scripts/web/script_utilities.py
@@ -4896,21 +4896,6 @@ class Utilities(script_utilities.Utilities):
 
         return rv
 
-    def getObjectFromPath(self, path):
-        start = self._script.app
-        rv = None
-        for p in path:
-            if p == -1:
-                continue
-            try:
-                start = start[p]
-            except:
-                break
-        else:
-            rv = start
-
-        return rv
-
     def clearCaretContext(self, documentFrame=None):
         self.clearContentCache()
         documentFrame = documentFrame or self.documentFrame()
diff --git a/src/orca/structural_navigation.py b/src/orca/structural_navigation.py
index c93c419cb..11b16cad3 100644
--- a/src/orca/structural_navigation.py
+++ b/src/orca/structural_navigation.py
@@ -1217,8 +1217,34 @@ class StructuralNavigation:
     def _setCaretPosition(self, obj, characterOffset):
         """Sets the caret at the specified offset within obj."""
 
+        try:
+            objPath = pyatspi.getPath(obj)
+            objRole = obj.getRole()
+        except:
+            return obj, characterOffset
+
         self._script.utilities.setCaretPosition(obj, characterOffset)
 
+        try:
+            obj.clearCache()
+            isDefunct = obj.getState().contains(pyatspi.STATE_DEFUNCT)
+        except:
+            isDefunct = True
+
+        if not isDefunct:
+            return obj, characterOffset
+
+        msg = "STRUCTURAL NAVIGATION: %s became defunct after setting caret position" % obj
+        debug.println(debug.LEVEL_INFO, msg, True)
+
+        replicant = self._script.utilities.getObjectFromPath(objPath)
+        if replicant and replicant.getRole() == objRole:
+            msg = "STRUCTURAL NAVIGATION: Updating obj to replicant %s" % replicant
+            debug.println(debug.LEVEL_INFO, msg, True)
+            obj = replicant
+
+        return obj, characterOffset
+
     def _presentLine(self, obj, offset):
         """Presents the first line of the object to the user.
 
@@ -1439,7 +1465,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentObject(obj, characterOffset)
         else:
             full = messages.NO_MORE_BLOCKQUOTES
@@ -1522,7 +1548,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentObject(obj, characterOffset)
         else:
             full = messages.NO_MORE_BUTTONS
@@ -1606,7 +1632,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentObject(obj, characterOffset)
         else:
             full = messages.NO_MORE_CHECK_BOXES
@@ -1788,7 +1814,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentObject(obj, characterOffset)
         else:
             full = messages.NO_MORE_COMBO_BOXES
@@ -1871,7 +1897,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentObject(obj, characterOffset)
         else:
             full = messages.NO_MORE_ENTRIES
@@ -1971,7 +1997,7 @@ class StructuralNavigation:
             if obj.getRole() == pyatspi.ROLE_TEXT and obj.childCount:
                 obj = obj[0]
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentObject(obj, characterOffset)
         else:
             full = messages.NO_MORE_FORM_FIELDS
@@ -2093,7 +2119,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentObject(obj, characterOffset)
         elif not arg:
             full = messages.NO_MORE_HEADINGS
@@ -2269,7 +2295,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._script.presentMessage(obj.name)
             self._presentLine(obj, characterOffset)
         else:
@@ -2356,7 +2382,7 @@ class StructuralNavigation:
         if obj:
             self._script.speakMessage(self._getListDescription(obj))
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentLine(obj, characterOffset)
         else:
             full = messages.NO_MORE_LISTS
@@ -2440,7 +2466,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentLine(obj, characterOffset)
         else:
             full = messages.NO_MORE_LIST_ITEMS
@@ -2522,7 +2548,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentObject(obj, characterOffset)
         else:
             full = messages.NO_MORE_LIVE_REGIONS
@@ -2695,7 +2721,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentObject(obj, characterOffset)
         else:
             full = messages.NO_MORE_RADIO_BUTTONS
@@ -2950,7 +2976,7 @@ class StructuralNavigation:
             self._presentCellHeaders(cell, arg)
 
         [obj, characterOffset] = self._getCaretPosition(cell)
-        self._setCaretPosition(obj, characterOffset)
+        obj, characterOffset = self._setCaretPosition(obj, characterOffset)
         self._script.updateBraille(obj)
 
         blank = self._isBlankCell(cell)
@@ -3042,7 +3068,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentObject(obj, characterOffset)
         else:
             full = messages.NO_MORE_UNVISITED_LINKS
@@ -3130,7 +3156,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentObject(obj, characterOffset)
         else:
             full = messages.NO_MORE_VISITED_LINKS
@@ -3213,7 +3239,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentObject(obj, characterOffset)
         else:
             full = messages.NO_MORE_LINKS
@@ -3298,7 +3324,7 @@ class StructuralNavigation:
 
         if obj:
             [obj, characterOffset] = self._getCaretPosition(obj)
-            self._setCaretPosition(obj, characterOffset)
+            obj, characterOffset = self._setCaretPosition(obj, characterOffset)
             self._presentObject(obj, characterOffset)
         elif not arg:
             full = messages.NO_MORE_CLICKABLES
@@ -3348,5 +3374,5 @@ class StructuralNavigation:
         if characterOffset is None:
             obj, characterOffset = self._getCaretPosition(obj)
 
-        self._setCaretPosition(obj, characterOffset)
+        obj, characterOffset = self._setCaretPosition(obj, characterOffset)
         self._presentLine(obj, characterOffset)


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