Index: src/orca/scripts/gmail.py
===================================================================
--- src/orca/scripts/gmail.py	(revision 0)
+++ src/orca/scripts/gmail.py	(revision 0)
@@ -0,0 +1,40 @@
+# Orca
+#
+# Copyright 2005-2006 Sun Microsystems Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+"""Custom script for BBC. CONCEPT"""
+
+__id__        = "$Id: $"
+__version__   = "$Revision: $"
+__date__      = "$Date: $"
+__copyright__ = "Copyright (c) 2005-2006 Sun Microsystems Inc."
+__license__   = "LGPL"
+
+import Mozilla
+import orca.debug as debug
+
+class Script(Mozilla.Script):
+    def __init__(self, app):
+        Mozilla.Script.__init__(self, app)
+        self.debugLevel = debug.LEVEL_FINEST
+        self._debug('__init__')
+
+    def _debug(self, msg):
+        """ Convenience method for printing debug messages
+        """
+        debug.println(self.debugLevel, "gmail.py: "+msg)
Index: src/orca/scripts/Makefile.am
===================================================================
--- src/orca/scripts/Makefile.am	(revision 2519)
+++ src/orca/scripts/Makefile.am	(working copy)
@@ -8,6 +8,7 @@
 	gcalctool.py \
 	gdmlogin.py \
 	gedit.py \
+	gmail.py \
 	gnome_segv2.py \
 	gnome-keyring-ask.py \
 	gnome-mud.py \
Index: src/orca/settings.py
===================================================================
--- src/orca/settings.py	(revision 2519)
+++ src/orca/settings.py	(working copy)
@@ -29,6 +29,7 @@
 
 import os
 import re
+import rolenames
 
 screenWidth = 640
 screenHeight = 480
@@ -598,9 +599,9 @@
 
     _scriptMappings.insert(0, [regExpression, moduleName])
 
-def getScriptModuleName(app):
+def getScriptModuleName(acc):
     """Returns the module name of the script to use for a given
-    application.  Any script mapping set via the setScriptMapping
+    accessible.  Any script mapping set via the setScriptMapping
     method is searched first, with the ultimate fallback being the
     name of the application itself.
 
@@ -608,19 +609,21 @@
     - app: the application to find a script module name for
     """
 
-    if not app.name:
+    if acc.role == rolenames.ROLE_DOCUMENT_FRAME:
+        app_id = acc.document.getAttributeValue("DocURL")
+    elif acc.name:
+        app_id = acc.name
+    else:
         return None
 
-    for mapping in _scriptMappings:
-        regExpression = mapping[0]
-        moduleName = mapping[1]
-        if regExpression.match(app.name):
+    for regExpression, moduleName in _scriptMappings:
+        if regExpression.match(app_id):
             debug.println(
                 debug.LEVEL_FINEST,
-                "Script mapping for %s is %s" % (app.name, moduleName))
+                "Script mapping for %s is %s" % (app_id, moduleName))
             return moduleName
 
-    return app.name
+    return app_id
 
 # Translators: the regular expression here represents a string to
 # match in the localized application name as seen by at-poke.  For
@@ -631,6 +634,7 @@
 # I wish the AT-SPI spec'd this out as machine readable (unlocalized)
 # names, but it's what we're stuck with (unfortunately).
 #
+
 setScriptMapping(re.compile(_('[\S\s]*StarOffice[\s\S]*')), "StarOffice")
 
 # Translators: see the regular expression note above.  This is for
@@ -666,6 +670,12 @@
 #
 setScriptMapping(re.compile(_('Minefield')), "Mozilla")
 
+# Translators: see the regular expression note above.  This is for a
+# version of Mozilla Firefox, which chooses to create strange names
+# for itself at the drop of a hat.
+#
+setScriptMapping(re.compile(_('Gran Paradiso')), "Mozilla")
+
 # Translators: see the regular expression note above.  This is for
 # the Thunderbird e-mail application.
 #
@@ -685,3 +695,8 @@
 # supporting pidgin, which is the new name for gaim.
 #
 setScriptMapping(re.compile(_('pidgin')), "gaim")
+
+# Translators: see the regular expression note above.  This is for
+# GMail.
+#
+setScriptMapping(re.compile(_('.*mail.google.com/mail.*')), "gmail")
Index: src/orca/focus_tracking_presenter.py
===================================================================
--- src/orca/focus_tracking_presenter.py	(revision 2519)
+++ src/orca/focus_tracking_presenter.py	(working copy)
@@ -146,8 +146,8 @@
     #
 
     def _createScript(self, app):
-        """For the given application name, create a new script instance.
-        We'll first see if a mapping from appName to module name exists.
+        """For the given accessible, create a new script instance.
+        We'll first see if a mapping from appName/URL to module name exists.
         If it does, we use that.  If it doesn't, we try the app name.
         If all else fails, we fall back to the default script.
         """
@@ -238,32 +238,59 @@
 
         return script
 
-    def _getScript(self, app):
-        """Get a script for an app (and make it if necessary).  This is used
-        instead of a simple calls to Script's constructor.
+    def _getDoc(self, acc):
+        """Get the containing document of this accessible.
+        
+        Arguments:
+        - acc: the Python acc
+        
+        Returns the containing document or None"""
+        
+        child = acc
+        try:
+            while child and child.parent and (child != child.parent):
+                if child.role == rolenames.ROLE_DOCUMENT_FRAME:
+                    return child
+                child = child.parent
+        except:
+            pass
+        return None
 
+    def _getScript(self, acc):
+      """Get a script for an accessible (and make it if necessary).
+      This is used instead of a simple calls to Script's constructor.
+
         Arguments:
-        - app: the Python app
+        - acc: the Python acc
 
         Returns an instance of a Script.
         """
 
-        # We might not know what the app is.  In this case, just defer
-        # to the default script for support.
-        #
-        if not app:
-            if not self._defaultScript:
-                self._defaultScript = default.Script(None)
-                self._registerEventListeners(self._defaultScript)
-            script = self._defaultScript
-        elif self._knownScripts.has_key(app):
-            script = self._knownScripts[app]
-        else:
-            script = self._createScript(app)
-            self._knownScripts[app] = script
-            self._registerEventListeners(script)
+      # First check if a special script is defined for the document URL,
+      # If not, continue to check accessible's application.
+      # This will need to be renamed to something else, not app. Can't
+      # think of anything now.
+      for app in (self._getDoc(acc), getattr(acc, 'app', None)):
+          # We might not know what the app is.  In this case, just defer
+          # to the default script for support.
+          #
+          if not app:
+              if not self._defaultScript:
+                  self._defaultScript = default.Script(None)
+                  self._registerEventListeners(self._defaultScript)
+              script = self._defaultScript
+          elif self._knownScripts.has_key(app):
+              script = self._knownScripts[app]
+          else:
+              script = self._createScript(app)
+              self._knownScripts[app] = script
+              self._registerEventListeners(script)
 
-        return script
+          # If we got a custom script stop searching.
+          if script != self._defaultScript:
+              break
+          
+      return script
 
     def setActiveScript(self, newScript):
         """Set the new active script.
@@ -352,7 +379,10 @@
                     pass
 
             for app in self._knownScripts.keys():
-                if apps.count(app) == 0:
+                if (app.role == rolenames.ROLE_APPLICATION and \
+                        app not in apps) or \
+                        (app.role == rolenames.ROLE_DOCUMENT_FRAME and \
+                         "DEFUNCT" in app.getStateString()):
                     script = self._knownScripts[app]
                     self._deregisterEventListeners(script)
 
@@ -501,13 +531,15 @@
         # generally do not like object:children-changed:remove events,
         # either.
         #
-        if event.type == "object:children-changed:remove":
-            if event.source == atspi.Accessible.makeAccessible(
-                                   self.registry.desktop):
-                self._reclaimScripts()
-                self._cleanupCache()
-                if settings.debugMemoryUsage:
-                    self._cleanupGarbage()
+        if event.type == "document:load-complete" or \
+                (event.type == "object:children-changed:remove" and \
+                event.source == \
+                atspi.Accessible.makeAccessible(self.registry.desktop)):
+            self._reclaimScripts()
+            self._cleanupCache()
+            if settings.debugMemoryUsage:
+                self._cleanupGarbage()
+        elif event.type == "object:children-changed:remove":
             return
 
         try:
@@ -559,7 +591,7 @@
         retryCount = 0
         oldLocusOfFocus = orca_state.locusOfFocus
         try:
-            s = self._getScript(event.source.app)
+            s = self._getScript(event.source)
         except:
             s = None
             debug.printException(debug.LEVEL_WARNING)
@@ -579,9 +611,7 @@
                     # in use, and then issues a focus: event on the
                     # main window, which is a frame.]]]
                     #
-                    if (event.type == "window:activate") \
-                       or ((event.type == "focus:") \
-                           and (event.source.role == rolenames.ROLE_FRAME)):
+                    if event.type in ("window:activate", "focus:"):
 
                         # We'll let someone else decide if it's important
                         # to stop speech or not.
@@ -589,7 +619,7 @@
                         debug.println(debug.LEVEL_FINE, "ACTIVE SCRIPT: " \
                                       + orca_state.activeScript.name)
 
-                        self.setActiveScript(self._getScript(event.source.app))
+                        self.setActiveScript(self._getScript(event.source))
 
                         # Load in the application specific settings for the
                         # app for this event (if found).
@@ -976,6 +1006,7 @@
         self._registerEventListener("window:activate")
         self._registerEventListener("window:deactivate")
         self._registerEventListener("object:children-changed:remove")
+        self._registerEventListener("document:load-complete")
 
         win = orca_state.activeScript.findActiveWindow()
         if win:
