diff --git a/source/NVDAObjects/IAccessible/__init__.py b/source/NVDAObjects/IAccessible/__init__.py
index 8e0bc8bb8cb..5e9d952eee6 100644
--- a/source/NVDAObjects/IAccessible/__init__.py
+++ b/source/NVDAObjects/IAccessible/__init__.py
@@ -377,8 +377,8 @@ def findOverlayClasses(self,clsList):
from . import adobeFlash
adobeFlash.findExtraOverlayClasses(self, clsList)
elif windowClassName.startswith('Mozilla'):
- from .mozilla import Mozilla
- clsList.append( Mozilla)
+ from . import mozilla
+ mozilla.findExtraOverlayClasses(self, clsList)
elif windowClassName.startswith('bosa_sdm'):
from .msOffice import SDM
clsList.append(SDM)
@@ -1450,17 +1450,6 @@ def _get_lastChild(self):
("TrayClockWClass",oleacc.ROLE_SYSTEM_CLIENT):"TrayClockWClass",
("TRxRichEdit",oleacc.ROLE_SYSTEM_CLIENT):"delphi.TRxRichEdit",
(None,oleacc.ROLE_SYSTEM_OUTLINEITEM):"OutlineItem",
- ("MozillaDialogClass",oleacc.ROLE_SYSTEM_ALERT):"Dialog",
- ("MozillaContentWindowClass",oleacc.ROLE_SYSTEM_COMBOBOX):"mozilla.ComboBox",
- ("MozillaContentWindowClass",oleacc.ROLE_SYSTEM_LIST):"mozilla.List",
- ("MozillaWindowClass",oleacc.ROLE_SYSTEM_LISTITEM):"mozilla.ListItem",
- ("MozillaContentWindowClass",oleacc.ROLE_SYSTEM_LISTITEM):"mozilla.ListItem",
- ("MozillaContentWindowClass",oleacc.ROLE_SYSTEM_DOCUMENT):"mozilla.Document",
- ("MozillaWindowClass",oleacc.ROLE_SYSTEM_DOCUMENT):"mozilla.Document",
- ("MozillaUIWindowClass",oleacc.ROLE_SYSTEM_TABLE):"mozilla.Table",
- ("MozillaUIWindowClass",oleacc.ROLE_SYSTEM_OUTLINE):"mozilla.Tree",
- ("MozillaContentWindowClass",IAccessibleHandler.IA2_ROLE_EMBEDDED_OBJECT):"mozilla.EmbeddedObject",
- ("MozillaContentWindowClass","embed"):"mozilla.EmbeddedObject",
("ConsoleWindowClass",oleacc.ROLE_SYSTEM_WINDOW):"ConsoleWindowClass",
(None,oleacc.ROLE_SYSTEM_LIST):"List",
(None,oleacc.ROLE_SYSTEM_COMBOBOX):"ComboBox",
diff --git a/source/NVDAObjects/IAccessible/mozilla.py b/source/NVDAObjects/IAccessible/mozilla.py
index 7fb5d771071..283dd744ff1 100755
--- a/source/NVDAObjects/IAccessible/mozilla.py
+++ b/source/NVDAObjects/IAccessible/mozilla.py
@@ -1,16 +1,16 @@
#NVDAObjects/IAccessible/mozilla.py
#A part of NonVisual Desktop Access (NVDA)
-#Copyright (C) 2006-2007 NVDA Contributors
#This file is covered by the GNU General Public License.
#See the file COPYING for more details.
+#Copyright (C) 2006-2010 Michael Curran , James Teh
import IAccessibleHandler
import oleacc
import winUser
+from comtypes import IServiceProvider, COMError
import eventHandler
import controlTypes
-from . import IAccessible
-import textInfos
+from . import IAccessible, Dialog
from logHandler import log
class Mozilla(IAccessible):
@@ -22,13 +22,6 @@ def _get_beTransparentToMouse(self):
return True
return super(Mozilla,self).beTransparentToMouse
- def _get_description(self):
- rawDescription=super(Mozilla,self).description
- if isinstance(rawDescription,basestring) and rawDescription.startswith('Description: '):
- return rawDescription[13:]
- else:
- return ""
-
def _get_parent(self):
#Special code to support Mozilla node_child_of relation (for comboboxes)
res=IAccessibleHandler.accNavigate(self.IAccessibleObject,self.IAccessibleChildID,IAccessibleHandler.NAVRELATION_NODE_CHILD_OF)
@@ -38,36 +31,54 @@ def _get_parent(self):
return newObj
return super(Mozilla,self).parent
+ def _get_states(self):
+ states = super(Mozilla, self).states
+ if self.IAccessibleStates & oleacc.STATE_SYSTEM_MARQUEED:
+ states.add(controlTypes.STATE_CHECKABLE)
+ return states
+
+class Gecko1_9(Mozilla):
+
+ def _get_description(self):
+ rawDescription=super(Mozilla,self).description
+ if isinstance(rawDescription,basestring) and rawDescription.startswith('Description: '):
+ return rawDescription[13:]
+ else:
+ return ""
+
def event_scrollingStart(self):
#Firefox 3.6 fires scrollingStart on leaf nodes which is not useful to us.
#Bounce the event up to the node's parent so that any possible virtualBuffers will detect it.
if self.role==controlTypes.ROLE_EDITABLETEXT and controlTypes.STATE_READONLY in self.states:
eventHandler.queueEvent("scrollingStart",self.parent)
- def _get_states(self):
- states = super(Mozilla, self).states
- if self.IAccessibleStates & oleacc.STATE_SYSTEM_MARQUEED:
- states.add(controlTypes.STATE_CHECKABLE)
- return states
+class BrokenFocusedState(Mozilla):
+ shouldAllowIAccessibleFocusEvent=True
+
+class RootApplication(Mozilla):
+ """Mozilla exposes a root application accessible as the parent of all top level frames.
+ See MozillaBug:555861.
+ This is non-standard; the top level accessible should be the top level window.
+ NVDA expects the standard behaviour, so we never want to see this object.
+ """
+
+ def __nonzero__(self):
+ # As far as NVDA is concerned, this is a useless object.
+ return False
class Document(Mozilla):
- shouldAllowIAccessibleFocusEvent=True
+ value=None
def _get_treeInterceptorClass(self):
states=self.states
- if isinstance(self.IAccessibleObject,IAccessibleHandler.IAccessible2) and controlTypes.STATE_READONLY in states and controlTypes.STATE_BUSY not in states and self.windowClassName=="MozillaContentWindowClass":
+ if controlTypes.STATE_READONLY in states and controlTypes.STATE_BUSY not in states and self.windowClassName=="MozillaContentWindowClass":
import virtualBuffers.gecko_ia2
return virtualBuffers.gecko_ia2.Gecko_ia2
return super(Document,self).treeInterceptorClass
- def _get_value(self):
- return
-
class ListItem(Mozilla):
- shouldAllowIAccessibleFocusEvent=True
-
def _get_name(self):
name=super(ListItem,self)._get_name()
if self.IAccessibleStates&oleacc.STATE_SYSTEM_READONLY:
@@ -82,20 +93,6 @@ def _get_children(self):
del children[0]
return children
-class ComboBox(Mozilla):
-
- shouldAllowIAccessibleFocusEvent=True
-
-class List(Mozilla):
-
- shouldAllowIAccessibleFocusEvent=True
-
-class Table(Mozilla):
- shouldAllowIAccessibleFocusEvent=True
-
-class Tree(Mozilla):
- shouldAllowIAccessibleFocusEvent=True
-
class EmbeddedObject(Mozilla):
def _get_shouldAllowIAccessibleFocusEvent(self):
@@ -105,3 +102,64 @@ def _get_shouldAllowIAccessibleFocusEvent(self):
# We don't want to override the focus event fired by the embedded object.
return False
return super(EmbeddedObject, self).shouldAllowIAccessibleFocusEvent
+
+def _getGeckoVersion(obj):
+ appMod = obj.appModule
+ try:
+ return appMod._geckoVersion
+ except AttributeError:
+ pass
+ try:
+ ver = obj.IAccessibleObject.QueryInterface(IServiceProvider).QueryService(IAccessibleHandler.IAccessibleApplication._iid_, IAccessibleHandler.IAccessibleApplication).toolkitVersion
+ except COMError:
+ return None
+ appMod._geckoVersion = ver
+ return ver
+
+def findExtraOverlayClasses(obj, clsList):
+ """Determine the most appropriate class if this is a Mozilla object.
+ This works similarly to L{NVDAObjects.NVDAObject.findOverlayClasses} except that it never calls any other findOverlayClasses method.
+ """
+ if not isinstance(obj.IAccessibleObject, IAccessibleHandler.IAccessible2):
+ # We require IAccessible2; i.e. Gecko >= 1.9.
+ return
+
+ iaRole = obj.IAccessibleRole
+ cls = None
+ if iaRole == oleacc.ROLE_SYSTEM_APPLICATION:
+ try:
+ if not obj.IAccessibleObject.windowHandle:
+ cls = RootApplication
+ except COMError:
+ pass
+ if not cls:
+ cls = _IAccessibleRolesToOverlayClasses.get(iaRole)
+ if cls:
+ clsList.append(cls)
+ if iaRole in _IAccessibleRolesWithBrokenFocusedState:
+ clsList.append(BrokenFocusedState)
+
+ if _getGeckoVersion(obj).startswith("1.9"):
+ clsList.append(Gecko1_9)
+
+ clsList.append(Mozilla)
+
+#: Maps IAccessible roles to NVDAObject overlay classes.
+_IAccessibleRolesToOverlayClasses = {
+ oleacc.ROLE_SYSTEM_ALERT: Dialog,
+ oleacc.ROLE_SYSTEM_LISTITEM: ListItem,
+ oleacc.ROLE_SYSTEM_DOCUMENT: Document,
+ IAccessibleHandler.IA2_ROLE_EMBEDDED_OBJECT: EmbeddedObject,
+ "embed": EmbeddedObject,
+}
+
+#: Roles that mightn't set the focused state when they are focused.
+_IAccessibleRolesWithBrokenFocusedState = frozenset((
+ oleacc.ROLE_SYSTEM_COMBOBOX,
+ oleacc.ROLE_SYSTEM_LIST,
+ oleacc.ROLE_SYSTEM_LISTITEM,
+ oleacc.ROLE_SYSTEM_DOCUMENT,
+ oleacc.ROLE_SYSTEM_APPLICATION,
+ oleacc.ROLE_SYSTEM_TABLE,
+ oleacc.ROLE_SYSTEM_OUTLINE,
+))
diff --git a/source/speech.py b/source/speech.py
index b59011e120c..2329c54b59c 100755
--- a/source/speech.py
+++ b/source/speech.py
@@ -431,6 +431,7 @@ def speakTypedCharacters(ch):
controlTypes.ROLE_RADIOBUTTON,
controlTypes.ROLE_LINK,
controlTypes.ROLE_MENUITEM,
+ controlTypes.ROLE_APPLICATION,
])
def processPositiveStates(role, states, reason, positiveStates):