Index: dogtail/config.py
===================================================================
RCS file: /cvs/gnome/dogtail/dogtail/config.py,v
retrieving revision 1.6
diff -u -r1.6 config.py
--- dogtail/config.py	5 Apr 2006 00:11:36 -0000	1.6
+++ dogtail/config.py	5 May 2006 15:52:27 -0000
@@ -57,6 +57,10 @@
     blinkOnActions (boolean):
     Whether we should blink a rectangle around a Node when an action is
     performed on it.
+
+    modalTrack (boolean):
+    Whether dogtail will respect modal states and avoid sending events or
+    actions to not grabbed windows on checking sensitivity.
     """
     __scriptName = staticmethod(_scriptName)
     __encoding = staticmethod(_encoding)
@@ -87,7 +91,8 @@
             'absoluteNodePaths' : False,
             'ensureSensitivity' : False,
             'debugTranslation' : False,
-            'blinkOnActions' : False
+            'blinkOnActions' : False,
+            'modalTrack' : True
     }
 
     options = {}
Index: dogtail/predicate.py
===================================================================
RCS file: /cvs/gnome/dogtail/dogtail/predicate.py,v
retrieving revision 1.8
diff -u -r1.8 predicate.py
--- dogtail/predicate.py	5 Apr 2006 00:11:36 -0000	1.8
+++ dogtail/predicate.py	5 May 2006 15:52:28 -0000
@@ -350,6 +350,17 @@
     def makeScriptVariableName(self):
         return makeCamel(self.tabName)+"Tab"
 
+class IsATopLevel(Predicate):
+    """Predicate subclass that checks that a node is a toplevel (child of an app)"""
+    def satisfiedByNode(self, node):
+        if node.parent:
+            return node.parent.roleName=='application'
+        else:
+            return False
+        
+    def describeSearchResult(self):
+        return "toplevel"
+
 class PredicateTests(unittest.TestCase):
     def testCapitalization(self):
         self.assertEquals(makeCamel("gnome-terminal"),"gnomeTerminal")
Index: dogtail/tree.py
===================================================================
RCS file: /cvs/gnome/dogtail/dogtail/tree.py,v
retrieving revision 1.27
diff -u -r1.27 tree.py
--- dogtail/tree.py	17 Apr 2006 06:18:54 -0000	1.27
+++ dogtail/tree.py	5 May 2006 15:52:31 -0000
@@ -166,7 +166,7 @@
         """
         assert isinstance(self, Action)
         logger.log("%s on %s"%(self.name, self.node.getLogString()))
-        if not self.node.sensitive:
+        if not self.node.canReceiveEvents:
             if config.ensureSensitivity:
                 raise NotSensitiveError, self
             else:
@@ -244,6 +244,16 @@
     based on presence of atspi.SPI_STATE_SENSITIVE
     Not all applications/toolkits seem to properly set this up.
 
+    'modal' (read-only boolean):
+    Is this node modal (i.e. a modal dialog). Generated from stateSet
+    based on presence of atspi.SPI_STATE_MODAL
+
+    'canReceiveEvents' (read-only boolean):
+    Can this node receive events? It checks if the element is sensitive
+    and there's no modal toplevel preventing it from getting events. It's
+    the variable that should be used (instead of senstive or modal). Modality
+    check is done only if modalTrack config property is enabled.
+
     'showing' (read-only boolean):
     Generated from stateSet based on presence of atspi.SPI_STATE_SHOWING
 
@@ -486,8 +496,24 @@
         # Attributes synthesized from the Accessible's stateSet:
         elif attr == "sensitive":
             return self.__accessible.getStateSet().contains(atspi.SPI_STATE_SENSITIVE)
+	elif attr == "modal":
+            return self.__accessible.getStateSet() and self.__accessible.getStateSet().contains(atspi.SPI_STATE_MODAL)
         elif attr == "showing":
             return self.__accessible.getStateSet().contains(atspi.SPI_STATE_SHOWING)
+
+        # Derived attributes:
+        elif attr == "canReceiveEvents":
+            if not self.sensitive:
+                return False
+            if config.modalTrack:
+                toplevel = self.findAncestor(predicate.IsATopLevel())
+                if toplevel.modal:
+                    return True
+                if toplevel.parent and toplevel.parent.roleName == 'application':
+                    for child in toplevel.parent.children:
+                        if child.modal:
+                            return False
+            return True
 
         # Attributes from the Action object
         elif attr == "actions":
