Index: src/orca/J2SE-access-bridge.py
===================================================================
--- src/orca/J2SE-access-bridge.py	(revision 2537)
+++ src/orca/J2SE-access-bridge.py	(working copy)
@@ -93,6 +93,10 @@
 
 class Script(default.Script):
 
+    # dictionary for keeping track of which windows contain internal frames
+    _windowContainsInternalFrames = {}
+    _currentInternalFrame = None
+
     def __init__(self, app):
         """Creates a new script for Java applications.
 
@@ -128,16 +132,41 @@
         keyboardEvent.hw_code = keybindings.getKeycode(keysym)
         return default.Script.consumesKeyboardEvent(self, keyboardEvent)
 
+    def onWindowActivated(self, event):
+        """Called whenever a toplevel window is activated.
+
+        Arguments:
+        - event: the Event
+        """
+        window = event.source
+        self._debug("onWindowActivated: '%s'" % window.name)
+
+        # If this is the first time this window has been activated,
+        # record whether it contains internal frames.
+        if not self._windowContainsInternalFrames.has_key(window):
+            list = self.findByRole(window, rolenames.ROLE_INTERNAL_FRAME, False)
+            self._windowContainsInternalFrames[window] = (len(list) > 0)
+
+        default.Script.onWindowActivated(self, event)
+
     def onFocus(self, event):
         """Called whenever an object gets focus.
 
         Arguments:
         - event: the Event
         """
-
         self._debug("onFocus: %s '%s'" % \
                     (event.source.role, event.source.name))
 
+        # If this object is contained in an internal frame and the
+        # internal frame just got focus, speak the internal frame.
+        #
+        if self._windowContainsInternalFrames[orca_state.activeWindow]:
+            internalFrame = self._getInternalFrame(event.source)
+            if internalFrame and internalFrame != self._currentInternalFrame:
+                speech.speak(internalFrame.name)
+                self._currentInternalFrame = internalFrame
+
         role = event.source.role
         if role == rolenames.ROLE_LIST:
             selectedItem = None
@@ -405,3 +434,18 @@
                         return labelFor.rstrip(":")
 
         return label
+
+    def _getInternalFrame(self, obj):
+        """Returns the internal frame containing this obj,
+        or None if this object is not inside an internal frame.
+
+        Arguments:
+        - obj: the Accessible object
+        """
+        while obj and obj.parent and (obj != obj.parent):
+            if obj.role == rolenames.ROLE_INTERNAL_FRAME:
+                return obj
+            obj = obj.parent
+
+        return None
+
