[orca] Fix several popup menu-related issues
- From: Joanmarie Diggs <joanied src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [orca] Fix several popup menu-related issues
- Date: Fri, 26 Aug 2022 12:39:17 +0000 (UTC)
commit 5b14a13696098e5ed70b23042c97bb38ebe5dce0
Author: Joanmarie Diggs <jdiggs igalia com>
Date: Fri Aug 26 13:10:20 2022 +0200
Fix several popup menu-related issues
* Ensure we present Thunderbird's New Address Book popup menu when
it first appears (issue #261)
* Don't present child position for menus if there is only one menu
* Don't present the name of the menu if it's the same as the widget
which caused the menu to pop up
src/orca/script_utilities.py | 25 ++++++++++++++++++
src/orca/scripts/apps/Thunderbird/script.py | 6 +++++
src/orca/scripts/toolkits/Chromium/script.py | 30 +++++++++++++++-------
.../scripts/toolkits/Chromium/script_utilities.py | 21 +--------------
src/orca/scripts/web/speech_generator.py | 6 +++++
src/orca/speech_generator.py | 10 ++++++++
6 files changed, 69 insertions(+), 29 deletions(-)
---
diff --git a/src/orca/script_utilities.py b/src/orca/script_utilities.py
index bbdf8e54a..c603890fb 100644
--- a/src/orca/script_utilities.py
+++ b/src/orca/script_utilities.py
@@ -4226,6 +4226,31 @@ class Utilities:
return role == pyatspi.ROLE_PUSH_BUTTON and state.contains(pyatspi.STATE_HAS_POPUP)
+ def isPopupMenuForCurrentItem(self, obj):
+ if obj == orca_state.locusOfFocus:
+ return False
+
+ if obj.name and obj.name == orca_state.locusOfFocus.name:
+ return obj.getRole() == pyatspi.ROLE_MENU
+
+ return False
+
+ def isMenuWithNoSelectedChild(self, obj):
+ if not obj:
+ return False
+
+ try:
+ role = obj.getRole()
+ except:
+ msg = "ERROR: Exception getting role for %s" % obj
+ debug.println(debug.LEVEL_INFO, msg, True)
+ return False
+
+ if role != pyatspi.ROLE_MENU:
+ return False
+
+ return not self.selectedChildCount(obj)
+
def isMenuButton(self, obj):
if not obj:
return False
diff --git a/src/orca/scripts/apps/Thunderbird/script.py b/src/orca/scripts/apps/Thunderbird/script.py
index a19e15c74..843e34000 100644
--- a/src/orca/scripts/apps/Thunderbird/script.py
+++ b/src/orca/scripts/apps/Thunderbird/script.py
@@ -255,6 +255,12 @@ class Script(Gecko.Script):
# right now just to prevent the Gecko script from presenting non-
# existent browsery autocompletes for Thunderbird.
+ if event.detail1 and self.utilities.isMenuWithNoSelectedChild(event.source) \
+ and orca_state.activeWindow == self.utilities.topLevelObject(event.source):
+ self.presentObject(event.source)
+ orca.setLocusOfFocus(event, event.source, False)
+ return
+
default.Script.onShowingChanged(self, event)
def onTextDeleted(self, event):
diff --git a/src/orca/scripts/toolkits/Chromium/script.py b/src/orca/scripts/toolkits/Chromium/script.py
index 62b0198a5..e41293cae 100644
--- a/src/orca/scripts/toolkits/Chromium/script.py
+++ b/src/orca/scripts/toolkits/Chromium/script.py
@@ -336,8 +336,8 @@ class Script(web.Script):
topLevel = self.utilities.topLevelObject(event.source)
if self.utilities.canBeActiveWindow(topLevel):
orca_state.activeWindow = topLevel
- notify = not self.utilities.isPopupMenuForCurrentItem(event.source)
- orca.setLocusOfFocus(event, event.source, notify)
+ self.presentObject(event.source)
+ orca.setLocusOfFocus(event, event.source, False)
return
if super().onShowingChanged(event):
@@ -406,17 +406,29 @@ class Script(web.Script):
# If this is a frame for a popup menu, we don't want to treat
# it like a proper window:activate event because it's not as
# far as the end-user experience is concerned.
- activeItem = self.utilities.popupMenuForFrame(event.source)
- if activeItem:
- selected = self.utilities.selectedChildren(activeItem)
+ menu = self.utilities.popupMenuForFrame(event.source)
+ if menu:
+ orca_state.activeWindow = event.source
+
+ activeItem = None
+ selected = self.utilities.selectedChildren(menu)
if len(selected) == 1:
activeItem = selected[0]
- msg = "CHROMIUM: Setting locusOfFocus to %s" % activeItem
- orca_state.activeWindow = event.source
- orca.setLocusOfFocus(event, activeItem)
+ if activeItem:
+ # If this is the popup menu for the locusOfFocus, we don't want to
+ # present the popup menu as part of the new ancestry of activeItem.
+ if self.utilities.isPopupMenuForCurrentItem(menu):
+ orca.setLocusOfFocus(event, menu, False)
+
+ msg = "CHROMIUM: Setting locusOfFocus to active item %s" % activeItem
+ orca.setLocusOfFocus(event, activeItem)
+ debug.println(debug.LEVEL_INFO, msg, True)
+ return
+
+ msg = "CHROMIUM: Setting locusOfFocus to popup menu %s" % menu
+ orca.setLocusOfFocus(event, menu)
debug.println(debug.LEVEL_INFO, msg, True)
- return
if super().onWindowActivated(event):
return
diff --git a/src/orca/scripts/toolkits/Chromium/script_utilities.py
b/src/orca/scripts/toolkits/Chromium/script_utilities.py
index f483ab5c0..fe99fce41 100644
--- a/src/orca/scripts/toolkits/Chromium/script_utilities.py
+++ b/src/orca/scripts/toolkits/Chromium/script_utilities.py
@@ -160,22 +160,6 @@ class Utilities(web.Utilities):
return result
- def isMenuWithNoSelectedChild(self, obj):
- if not obj:
- return False
-
- try:
- role = obj.getRole()
- except:
- msg = "CHROMIUM: Exception getting role for %s" % obj
- debug.println(debug.LEVEL_INFO, msg, True)
- return False
-
- if role != pyatspi.ROLE_MENU:
- return False
-
- return not self.selectedChildCount(obj)
-
def isMenuInCollapsedSelectElement(self, obj):
try:
role = obj.getRole()
@@ -224,10 +208,7 @@ class Utilities(web.Utilities):
if not self.treatAsMenu(orca_state.locusOfFocus):
return False
- if obj.name and obj.name == orca_state.locusOfFocus.name:
- return obj.getRole() == pyatspi.ROLE_MENU
-
- return False
+ return super().isPopupMenuForCurrentItem(obj)
def isFrameForPopupMenu(self, obj):
try:
diff --git a/src/orca/scripts/web/speech_generator.py b/src/orca/scripts/web/speech_generator.py
index 0eb41b606..44abb3391 100644
--- a/src/orca/scripts/web/speech_generator.py
+++ b/src/orca/scripts/web/speech_generator.py
@@ -334,6 +334,12 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
debug.println(debug.LEVEL_INFO, msg, True)
return []
+ role = args.get('role', obj.getRole())
+ if role == pyatspi.ROLE_MENU and self._script.utilities.isPopupMenuForCurrentItem(obj):
+ msg = "WEB: %s is popup menu for current item." % obj
+ debug.println(debug.LEVEL_INFO, msg, True)
+ return []
+
if self._script.utilities.isContentEditableWithEmbeddedObjects(obj) \
or self._script.utilities.isDocument(obj):
lastKey, mods = self._script.utilities.lastKeyAndModifiers()
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index 957cbf941..f85c67785 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -177,6 +177,13 @@ class SpeechGenerator(generator.Generator):
If the label cannot be found, the name will be used instead.
If the name cannot be found, an empty array will be returned.
"""
+
+ role = args.get('role', obj.getRole())
+ if role == pyatspi.ROLE_MENU and self._script.utilities.isPopupMenuForCurrentItem(obj):
+ msg = 'SPEECH GENERATOR: %s is popup menu for current item.' % obj
+ debug.println(debug.LEVEL_INFO, msg, True)
+ return []
+
result = []
result.extend(self._generateLabel(obj, **args))
if not result:
@@ -2341,6 +2348,9 @@ class SpeechGenerator(generator.Generator):
if position < 0 or total < 0:
return []
+ if obj.getRole() == pyatspi.ROLE_MENU and total == 1:
+ return []
+
position += 1
result.append(self._script.formatting.getString(
mode='speech',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]