Index: src/orca/scripts/gedit.py
===================================================================
--- src/orca/scripts/gedit.py	(revision 2111)
+++ src/orca/scripts/gedit.py	(working copy)
@@ -417,9 +417,9 @@
 
             allComboBoxes = self.findByRole(orca_state.locusOfFocus.app,
                                             rolenames.ROLE_COMBO_BOX)
-            phrase = util.getDisplayedText(allComboBoxes[0])
+            phrase = self.getDisplayedText(allComboBoxes[0])
             [text, caretOffset, startOffset] = \
-                util.getTextLineAtCaret(event.source)
+                self.getTextLineAtCaret(event.source)
             if text.lower().find(phrase) != -1:
                 speech.speak(_("Phrase found."))
                 utterances = self.speechGenerator.getSpeech(event.source, True)
Index: src/orca/scripts/planner.py
===================================================================
--- src/orca/scripts/planner.py	(revision 2111)
+++ src/orca/scripts/planner.py	(working copy)
@@ -63,7 +63,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self.getDisplayedText(obj))
 
         # First special toggle button is the one in the toolbar and
         # that it has no name Application should implement an
Index: src/orca/scripts/gcalctool.py
===================================================================
--- src/orca/scripts/gcalctool.py	(revision 2111)
+++ src/orca/scripts/gcalctool.py	(working copy)
@@ -61,7 +61,7 @@
         if obj.name:
             name = obj.name
         else:
-            name = util.getDisplayedText(obj)
+            name = self.getDisplayedText(obj)
 
         if name:
             return [name]
Index: src/orca/scripts/Thunderbird.py
===================================================================
--- src/orca/scripts/Thunderbird.py	(revision 2109)
+++ src/orca/scripts/Thunderbird.py	(working copy)
@@ -113,7 +113,7 @@
 
             # Append the text and label. Skip displayed text
             # that starts with "chrome://"
-            text = util.getDisplayedText(parent)
+            text = self.getDisplayedText(parent)
             label = util.getDisplayedLabel(parent)
             if text and (text != label) and len(text) \
                 and (not text.startswith("chrome://")):
@@ -240,7 +240,7 @@
             speech.stop()
 
             utterances = []
-            [text, caretOffset, startOffset] = util.getTextLineAtCaret(obj)
+            [text, caretOffset, startOffset] = self.getTextLineAtCaret(obj)
             utterances.append(text)
             self._debug("onTextInserted: utterances='%s'" % utterances)
 
Index: src/orca/scripts/gaim.py
===================================================================
--- src/orca/scripts/gaim.py	(revision 2111)
+++ src/orca/scripts/gaim.py	(working copy)
@@ -327,7 +327,7 @@
             if message and message[0] == "\n":
                 message = message[1:]
 
-            chatRoomName = util.getDisplayedText(chatRoomTab)
+            chatRoomName = self.getDisplayedText(chatRoomTab)
             self.utterMessage(chatRoomName, message)
 
             # Add the latest message to the list of saved ones. For each
Index: src/orca/scripts/acroread.py
===================================================================
--- src/orca/scripts/acroread.py	(revision 2109)
+++ src/orca/scripts/acroread.py	(working copy)
@@ -404,7 +404,7 @@
         #
         if findToolbarActive:
             if newLocusOfFocus.role == rolenames.ROLE_TEXT:
-                newText = util.getTextLineAtCaret(newLocusOfFocus)
+                newText = self.getTextLineAtCaret(newLocusOfFocus)
                 if newText == preFindLine:
                     orca.setLocusOfFocus(event, oldLocusOfFocus, False)
                     return
@@ -488,7 +488,7 @@
         # left. Since this SEEMS limited to page up/page down, let's be
         # conservative until we have evidence to the contrary.
         #
-        textLine = util.getTextLineAtCaret(event.source)
+        textLine = self.getTextLineAtCaret(event.source)
         isOldLine = textLine == lastCaretMovedLine and \
                     (lastKey == "Page_Down" or lastKey == "Page_Up")
         if isOldLine:
@@ -560,7 +560,7 @@
         if event.source.name == findToolbarName:
             findToolbarActive = False
         elif locusOfFocus.text:
-            preFindLine = util.getTextLineAtCaret(locusOfFocus)
+            preFindLine = self.getTextLineAtCaret(locusOfFocus)
 
         default.Script.onWindowDeactivated(self, event)
 
Index: src/orca/scripts/Evolution.py
===================================================================
--- src/orca/scripts/Evolution.py	(revision 2111)
+++ src/orca/scripts/Evolution.py	(working copy)
@@ -190,7 +190,7 @@
                         self.textAttrsToDictionary(charAttributes[0])
                     weight = charDict.get('weight')
                     if weight and weight == '800':
-                        text = util.getDisplayedText(label)
+                        text = self.getDisplayedText(label)
 
                         # Only speak the screen label if we haven't already
                         # done so.
@@ -217,7 +217,7 @@
             # events for the same label. If we've already handled this
             # label, then just ignore it.
             #
-            text = util.getDisplayedText(label)
+            text = self.getDisplayedText(label)
             if text and not self.setupLabels.has_key(label):
                 # Most of the Setup Assistant screens have a useful piece
                 # of text starting with the word "Please". We want to speak
@@ -386,7 +386,7 @@
                           + "individual lines of text.")
 
             [string, caretOffset, startOffset] = \
-                util.getTextLineAtCaret(event.source)
+                self.getTextLineAtCaret(event.source)
             braille.displayMessage(string)
             if settings.enableSpeechIndentation:
                 self.speakTextIndentation(event.source, string)
@@ -449,7 +449,7 @@
                     if cell.role == rolenames.ROLE_TEXT:
                         regions.append(braille.Text(cell))
                         [string, caretOffset, startOffset] = \
-                            util.getTextLineAtCaret(cell)
+                            self.getTextLineAtCaret(cell)
                         utterances.append(string)
 
                 braille.displayRegions([regions, regions[0]])
@@ -918,7 +918,7 @@
             found = False
             for i in range(0, len(allLabels)):
                 if not found:
-                    text = util.getDisplayedText(allLabels[i])
+                    text = self.getDisplayedText(allLabels[i])
                     if text:
                         tokens = text.split()
                     else:
Index: src/orca/scripts/StarOffice.py
===================================================================
--- src/orca/scripts/StarOffice.py	(revision 2111)
+++ src/orca/scripts/StarOffice.py	(working copy)
@@ -338,13 +338,13 @@
                 inputLineForCell = locateInputLine(obj)
 
             regions = []
-            text = util.getDisplayedText(obj)
+            text = self.getDisplayedText(obj)
             componentRegion = braille.Component(obj, text)
             regions.append(componentRegion)
 
             # If the spread sheet table cell has something in it, then we
             # want to append the name of the cell (which will be its location).
-            # Note that if the cell was empty, then util.getDisplayedText will
+            # Note that if the cell was empty, then self.getDisplayedText will
             # have already done this for us.
             #
             if obj.text:
@@ -1122,7 +1122,7 @@
         - label: the Setup dialog Label.
         """
 
-        text = util.getDisplayedText(label)
+        text = self.getDisplayedText(label)
         if text:
             speech.speak(text)
 
@@ -1197,7 +1197,7 @@
             debug.println(self.debugLevel,
                   "StarOffice.locusOfFocusChanged - Writer: text paragraph.")
 
-            result = util.getTextLineAtCaret(event.source)
+            result = self.getTextLineAtCaret(event.source)
             result[0] = result[0].decode("UTF-8")
 
             if oldLocusOfFocus.role == rolenames.ROLE_MENU_ITEM and \
Index: src/orca/flat_review.py
===================================================================
--- src/orca/flat_review.py	(revision 2109)
+++ src/orca/flat_review.py	(working copy)
@@ -572,7 +572,7 @@
         #print "LOOKING AT '%s'" % unicodeString
         for i in range(0, len(unicodeString) + 1):
             if (i != len(unicodeString)) \
-               and (unicodeString[i] != util.EMBEDDED_OBJECT_CHARACTER):
+               and (unicodeString[i] != orca_state.activeScript.EMBEDDED_OBJECT_CHARACTER):
                 substringEndOffset += 1
             elif (substringEndOffset == substringStartOffset):
                 substringStartOffset += 1
@@ -666,7 +666,7 @@
             #      % (offset, startOffset, endOffset, string)
             #if startOffset > offset:
             #    embedded = text.getText(offset, offset + 1).decode("UTF-8")
-            #    if embedded[0] == util.EMBEDDED_OBJECT_CHARACTER:
+            #    if embedded[0] == orca_state.activeScript.EMBEDDED_OBJECT_CHARACTER:
             #        offset = startOffset
 
             debug.println(debug.LEVEL_FINEST,
Index: src/orca/util.py
===================================================================
--- src/orca/util.py	(revision 2115)
+++ src/orca/util.py	(working copy)
@@ -48,11 +48,6 @@
 #
 _unicodeCurrencySymbols = []
 
-# Embedded object character used to indicate that an object is
-# embedded in a string.
-#
-EMBEDDED_OBJECT_CHARACTER = u'\ufffc'
-
 def isSameObject(obj1, obj2):
     if (obj1 == obj2):
         return True
@@ -290,136 +285,6 @@
 
     return label
 
-def __getDisplayedTextInComboBox(combo):
-
-    """Returns the text being displayed in a combo box.  If nothing is
-    displayed, then None is returned.
-
-    Arguments:
-    - combo: the combo box
-
-    Returns the text in the combo box or an empty string if nothing is
-    displayed.
-    """
-
-    displayedText = None
-
-    # Find the text displayed in the combo box.  This is either:
-    #
-    # 1) The last text object that's a child of the combo box
-    # 2) The selected child of the combo box.
-    # 3) The contents of the text of the combo box itself when
-    #    treated as a text object.
-    #
-    # Preference is given to #1, if it exists.
-    #
-    # If the label of the combo box is the same as the utterance for
-    # the child object, then this utterance is only displayed once.
-    #
-    # [[[TODO: WDW - Combo boxes are complex beasts.  This algorithm
-    # needs serious work.  Logged as bugzilla bug 319745.]]]
-    #
-    textObj = None
-    for i in range(0, combo.childCount):
-        child = combo.child(i)
-        if child and child.role == rolenames.ROLE_TEXT:
-            textObj = child
-
-    if textObj:
-        [displayedText, caretOffset, startOffset] = getTextLineAtCaret(textObj)
-        #print "TEXTOBJ", displayedText
-    else:
-        selectedItem = None
-        comboSelection = combo.selection
-        if comboSelection and comboSelection.nSelectedChildren > 0:
-            try:
-                selectedItem = atspi.Accessible.makeAccessible(
-                    comboSelection.getSelectedChild(0))
-            except:
-                pass
-        if selectedItem:
-            displayedText = getDisplayedText(selectedItem)
-            #print "SELECTEDITEM", displayedText
-        elif combo.name and len(combo.name):
-            # We give preference to the name over the text because
-            # the text for combo boxes seems to never change in
-            # some cases.  The main one where we see this is in
-            # the gaim "Join Chat" window.
-            #
-            displayedText = combo.name
-            #print "NAME", displayedText
-        elif combo.text:
-            [displayedText, caretOffset, startOffset] = \
-                getTextLineAtCaret(combo)
-            #print "TEXT", displayedText
-
-    return displayedText
-
-def getDisplayedText(obj):
-    """Returns the text being displayed for an object.
-
-    Arguments:
-    - obj: the object
-
-    Returns the text being displayed for an object or None if there isn't
-    any text being shown.
-    """
-
-    displayedText = None
-
-    if obj.role == rolenames.ROLE_COMBO_BOX:
-        return __getDisplayedTextInComboBox(obj)
-
-    # The accessible text of an object is used to represent what is
-    # drawn on the screen.
-    #
-    if obj.text:
-        displayedText = obj.text.getText(0, -1)
-
-        # [[[WDW - HACK to account for things such as Gecko that want
-        # to use the EMBEDDED_OBJECT_CHARACTER on a label to hold the
-        # object that has the real accessible text for the label.  We
-        # detect this by the specfic case where the text for the
-        # current object is a single EMBEDDED_OBJECT_CHARACTER.  In
-        # this case, we look to the child for the real text.]]]
-        #
-        unicodeText = displayedText.decode("UTF-8")
-        if unicodeText \
-           and (len(unicodeText) == 1) \
-           and (unicodeText[0] == EMBEDDED_OBJECT_CHARACTER):
-            try:
-                displayedText = getDisplayedText(obj.child(0))
-            except:
-                debug.printException(debug.LEVEL_WARNING)
-        elif unicodeText:
-            # [[[TODO: HACK - Welll.....we'll just plain ignore any
-            # text with EMBEDDED_OBJECT_CHARACTERs here.  We still need a
-            # general case to handle this stuff and expand objects
-            # with EMBEDDED_OBJECT_CHARACTERs.]]]
-            #
-            for i in range(0, len(unicodeText)):
-                if unicodeText[i] == EMBEDDED_OBJECT_CHARACTER:
-                    displayedText = None
-                    break
-
-    if (not displayedText) or (len(displayedText) == 0):
-        displayedText = obj.name
-
-    # [[[WDW - HACK because push buttons can have labels as their
-    # children.  An example of this is the Font: button on the General
-    # tab in the Editing Profile dialog in gnome-terminal.
-    #
-    if ((not displayedText) or (len(displayedText) == 0)) \
-       and obj.role == rolenames.ROLE_PUSH_BUTTON:
-        for i in range(0, obj.childCount):
-            child = obj.child(i)
-            if child.role == rolenames.ROLE_LABEL:
-                childText = getDisplayedText(child)
-                if childText and len(childText):
-                    displayedText = appendString(displayedText, childText)
-
-    return displayedText
-
 def getRealActiveDescendant(obj):
     """Given an object that should be a child of an object that
     manages its descendants, return the child that is the real
@@ -865,67 +730,3 @@
         return ""
     else:
         return top.name
-
-def getTextLineAtCaret(obj):
-    """Gets the line of text where the caret is.
-
-    Argument:
-    - obj: an Accessible object that implements the AccessibleText
-           interface
-
-    Returns the [string, caretOffset, startOffset] for the line of text
-    where the caret is.
-    """
-
-    # Get the the AccessibleText interrface
-    #
-    text = obj.text
-    if not text:
-        return ["", 0, 0]
-
-    # The caret might be positioned at the very end of the text area.
-    # In these cases, calling text.getTextAtOffset on an offset that's
-    # not positioned to a character can yield unexpected results.  In
-    # particular, we'll see the Gecko toolkit return a start and end
-    # offset of (0, 0), and we'll see other implementations, such as
-    # gedit, return reasonable results (i.e., gedit will give us the
-    # last line).
-    #
-    # In order to accommodate the differing behavior of different
-    # AT-SPI implementations, we'll make sure we give getTextAtOffset
-    # the offset of an actual character.  Then, we'll do a little check
-    # to see if that character is a newline - if it is, we'll treat it
-    # as the line.
-    #
-    if text.caretOffset == text.characterCount:
-        caretOffset = max(0, text.caretOffset - 1)
-        character = text.getText(caretOffset, caretOffset + 1).decode("UTF-8")
-    else:
-        caretOffset = text.caretOffset
-        character = None
-
-    if (text.caretOffset == text.characterCount) \
-        and (character == "\n"):
-        content = ""
-        startOffset = caretOffset
-    else:
-        # Get the line containing the caret.  [[[TODO: HACK WDW - If
-        # there's only 1 character in the string, well, we get it.  We
-        # do this because Gecko's implementation of getTextAtOffset
-        # is broken if there is just one character in the string.]]]
-        #
-        if (text.characterCount == 1):
-            string = text.getText(caretOffset, caretOffset + 1)
-            startOffset = caretOffset
-            endOffset = caretOffset + 1
-        else:
-            [string, startOffset, endOffset] = text.getTextAtOffset(
-                caretOffset, atspi.Accessibility.TEXT_BOUNDARY_LINE_START)
-
-        # Sometimes we get the trailing line-feed-- remove it
-        #
-        content = string.decode("UTF-8")
-        if content[-1:] == "\n":
-            content = content[:-1]
-
-    return [content.encode("UTF-8"), text.caretOffset, startOffset]
Index: src/orca/speechgenerator.py
===================================================================
--- src/orca/speechgenerator.py	(revision 2114)
+++ src/orca/speechgenerator.py	(working copy)
@@ -207,7 +207,7 @@
             return []
 
     def _getSpeechForObjectName(self, obj):
-        name = util.getDisplayedText(obj)
+        name = self._script.getDisplayedText(obj)
         if name:
             return [name]
         elif obj.description:
@@ -815,7 +815,7 @@
         if obj.role != rolenames.ROLE_PARAGRAPH:
             utterances.extend(self._getSpeechForObjectRole(obj))
 
-        [text, caretOffset, startOffset] = util.getTextLineAtCaret(obj)
+        [text, caretOffset, startOffset] = self._script.getTextLineAtCaret(obj)
         utterances.append(text)
 
         self._debugGenerator("_getSpeechForText",
@@ -1130,7 +1130,7 @@
         """
 
         if already_focused:
-            utterances = [util.getDisplayedText(obj)]
+            utterances = [self._script.getDisplayedText(obj)]
         else:
             utterances = self._getDefaultSpeech(obj, already_focused)
 
@@ -1220,7 +1220,7 @@
                     obj.role = rolenames.ROLE_TABLE_CELL
                     break
 
-        utterances.append(util.getDisplayedText(\
+        utterances.append(self._script.getDisplayedText(\
                           util.getRealActiveDescendant(obj)))
 
         # [[[TODO: WDW - HACK attempt to determine if this is a node;
@@ -1572,7 +1572,7 @@
 
                 # Announce the label and text of the object in the hierarchy.
                 #
-                text = util.getDisplayedText(parent)
+                text = self._script.getDisplayedText(parent)
                 label = util.getDisplayedLabel(parent)
 
                 # Push announcement of cell after text and label.
Index: src/orca/default.py
===================================================================
--- src/orca/default.py	(revision 2115)
+++ src/orca/default.py	(working copy)
@@ -89,6 +89,11 @@
         #
         self.lastWhereAmIEvent = None
 
+        # Embedded object character used to indicate that an object is
+        # embedded in a string.
+        #
+        self.EMBEDDED_OBJECT_CHARACTER = u'\ufffc'
+
         # Used by the drawOutline routine.
         #
         self._display = None
@@ -1193,7 +1198,7 @@
 
         # Get the AccessibleText interface of the provided object
         #
-        [line, caretOffset, startOffset] = util.getTextLineAtCaret(obj)
+        [line, caretOffset, startOffset] = self.getTextLineAtCaret(obj)
         debug.println(debug.LEVEL_FINEST, \
             "sayLine: line=<%s>, len=%d, start=%d, caret=%d, speakBlankLines=%s" % \
             (line, len(line), startOffset, caretOffset, settings.speakBlankLines))
@@ -1693,7 +1698,7 @@
                 # switch groups.
                 #
                 if (not inSameGroup) and radioGroupLabel:
-                    utterances.append(util.getDisplayedText(radioGroupLabel))
+                    utterances.append(self.getDisplayedText(radioGroupLabel))
 
             # Get the text for the object itself.
             #
@@ -2554,7 +2559,7 @@
                     layoutOnly = True
                     break
         elif obj and (obj.role == rolenames.ROLE_PANEL):
-            text = util.getDisplayedText(obj)
+            text = self.getDisplayedText(obj)
             label = util.getDisplayedLabel(obj)
             if not ((label and len(label)) or (text and len(text))):
                 layoutOnly = True
@@ -3445,6 +3450,202 @@
 # here so that they can be customized in application scripts if so desired.
 # 
 
+    def __getDisplayedTextInComboBox(self, combo):
+
+        """Returns the text being displayed in a combo box.  If nothing is
+        displayed, then None is returned.
+
+        Arguments:
+        - combo: the combo box
+
+        Returns the text in the combo box or an empty string if nothing is
+        displayed.
+        """
+
+        displayedText = None
+
+        # Find the text displayed in the combo box.  This is either:
+        #
+        # 1) The last text object that's a child of the combo box
+        # 2) The selected child of the combo box.
+        # 3) The contents of the text of the combo box itself when
+        #    treated as a text object.
+        #
+        # Preference is given to #1, if it exists.
+        #
+        # If the label of the combo box is the same as the utterance for
+        # the child object, then this utterance is only displayed once.
+        #
+        # [[[TODO: WDW - Combo boxes are complex beasts.  This algorithm
+        # needs serious work.  Logged as bugzilla bug 319745.]]]
+        #
+        textObj = None
+        for i in range(0, combo.childCount):
+            child = combo.child(i)
+            if child and child.role == rolenames.ROLE_TEXT:
+                textObj = child
+
+        if textObj:
+            [displayedText, caretOffset, startOffset] = \
+                self.getTextLineAtCaret(textObj)
+            #print "TEXTOBJ", displayedText
+        else:
+            selectedItem = None
+            comboSelection = combo.selection
+            if comboSelection and comboSelection.nSelectedChildren > 0:
+                try:
+                    selectedItem = atspi.Accessible.makeAccessible(
+                        comboSelection.getSelectedChild(0))
+                except:
+                    pass
+            if selectedItem:
+                displayedText = self.getDisplayedText(selectedItem)
+                #print "SELECTEDITEM", displayedText
+            elif combo.name and len(combo.name):
+                # We give preference to the name over the text because
+                # the text for combo boxes seems to never change in
+                # some cases.  The main one where we see this is in
+                # the gaim "Join Chat" window.
+                #
+                displayedText = combo.name
+                #print "NAME", displayedText
+            elif combo.text:
+                [displayedText, caretOffset, startOffset] = \
+                    self.getTextLineAtCaret(combo)
+                #print "TEXT", displayedText
+
+        return displayedText
+
+    def getDisplayedText(self, obj):
+        """Returns the text being displayed for an object.
+
+        Arguments:
+        - obj: the object
+
+        Returns the text being displayed for an object or None if there isn't
+        any text being shown.
+        """
+
+        displayedText = None
+
+        if obj.role == rolenames.ROLE_COMBO_BOX:
+            return self.__getDisplayedTextInComboBox(obj)
+
+        # The accessible text of an object is used to represent what is
+        # drawn on the screen.
+        #
+        if obj.text:
+            displayedText = obj.text.getText(0, -1)
+
+            # [[[WDW - HACK to account for things such as Gecko that want
+            # to use the EMBEDDED_OBJECT_CHARACTER on a label to hold the
+            # object that has the real accessible text for the label.  We
+            # detect this by the specfic case where the text for the
+            # current object is a single EMBEDDED_OBJECT_CHARACTER.  In
+            # this case, we look to the child for the real text.]]]
+            #
+            unicodeText = displayedText.decode("UTF-8")
+            if unicodeText \
+               and (len(unicodeText) == 1) \
+               and (unicodeText[0] == self.EMBEDDED_OBJECT_CHARACTER):
+                try:
+                    displayedText = self.getDisplayedText(obj.child(0))
+                except:
+                    debug.printException(debug.LEVEL_WARNING)
+            elif unicodeText:
+                # [[[TODO: HACK - Welll.....we'll just plain ignore any
+                # text with EMBEDDED_OBJECT_CHARACTERs here.  We still need a
+                # general case to handle this stuff and expand objects
+                # with EMBEDDED_OBJECT_CHARACTERs.]]]
+                #
+                for i in range(0, len(unicodeText)):
+                    if unicodeText[i] == self.EMBEDDED_OBJECT_CHARACTER:
+                        displayedText = None
+                        break
+
+        if (not displayedText) or (len(displayedText) == 0):
+            displayedText = obj.name
+
+        # [[[WDW - HACK because push buttons can have labels as their
+        # children.  An example of this is the Font: button on the General
+        # tab in the Editing Profile dialog in gnome-terminal.
+        #
+        if ((not displayedText) or (len(displayedText) == 0)) \
+           and obj.role == rolenames.ROLE_PUSH_BUTTON:
+            for i in range(0, obj.childCount):
+                child = obj.child(i)
+                if child.role == rolenames.ROLE_LABEL:
+                    childText = self.getDisplayedText(child)
+                    if childText and len(childText):
+                        displayedText = appendString(displayedText, childText)
+
+        return displayedText
+
+    def getTextLineAtCaret(self, obj):
+        """Gets the line of text where the caret is.
+
+        Argument:
+        - obj: an Accessible object that implements the AccessibleText
+               interface
+
+        Returns the [string, caretOffset, startOffset] for the line of text
+        where the caret is.
+        """
+
+        # Get the the AccessibleText interrface
+        #
+        text = obj.text
+        if not text:
+            return ["", 0, 0]
+
+        # The caret might be positioned at the very end of the text area.
+        # In these cases, calling text.getTextAtOffset on an offset that's
+        # not positioned to a character can yield unexpected results.  In
+        # particular, we'll see the Gecko toolkit return a start and end
+        # offset of (0, 0), and we'll see other implementations, such as
+        # gedit, return reasonable results (i.e., gedit will give us the
+        # last line).
+        #
+        # In order to accommodate the differing behavior of different
+        # AT-SPI implementations, we'll make sure we give getTextAtOffset
+        # the offset of an actual character.  Then, we'll do a little check
+        # to see if that character is a newline - if it is, we'll treat it
+        # as the line.
+        #
+        if text.caretOffset == text.characterCount:
+            caretOffset = max(0, text.caretOffset - 1)
+            character = text.getText(caretOffset, 
+                                     caretOffset + 1).decode("UTF-8")
+        else:
+            caretOffset = text.caretOffset
+            character = None
+
+        if (text.caretOffset == text.characterCount) \
+            and (character == "\n"):
+            content = ""
+            startOffset = caretOffset
+        else:
+            # Get the line containing the caret.  [[[TODO: HACK WDW - If
+            # there's only 1 character in the string, well, we get it.  We
+            # do this because Gecko's implementation of getTextAtOffset
+            # is broken if there is just one character in the string.]]]
+            #
+            if (text.characterCount == 1):
+                string = text.getText(caretOffset, caretOffset + 1)
+                startOffset = caretOffset
+                endOffset = caretOffset + 1
+            else:
+                [string, startOffset, endOffset] = text.getTextAtOffset(
+                    caretOffset, atspi.Accessibility.TEXT_BOUNDARY_LINE_START)
+
+            # Sometimes we get the trailing line-feed-- remove it
+            #
+            content = string.decode("UTF-8")
+            if content[-1:] == "\n":
+                content = content[:-1]
+
+        return [content.encode("UTF-8"), text.caretOffset, startOffset]
+
     def getNodeLevel(self, obj):
         """Determines the node level of this object if it is in a tree
         relation, with 0 being the top level node.  If this object is
Index: src/orca/Gecko.py
===================================================================
--- src/orca/Gecko.py	(revision 2109)
+++ src/orca/Gecko.py	(working copy)
@@ -171,7 +171,7 @@
         text = ""
         if not self._script.inDocumentContent():
             text = util.appendString(text, util.getDisplayedLabel(obj))
-            text = util.appendString(text, util.getDisplayedText(obj))
+            text = util.appendString(text, self.getDisplayedText(obj))
         else:
             isLabelled = False
             relations = obj.relations
@@ -322,7 +322,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self.getDisplayedText(obj))
 
         # If there's no text for the link, expose part of the
         # link to the user if the image is in a link.
@@ -363,7 +363,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self.getDisplayedText(obj))
 
         # If there's no text for the link, expose part of the
         # URI to the user.
@@ -463,7 +463,7 @@
 
         utterances.extend(self._getSpeechForObjectRole(obj))
 
-        [text, caretOffset, startOffset] = util.getTextLineAtCaret(obj)
+        [text, caretOffset, startOffset] = self.getTextLineAtCaret(obj)
         utterances.append(text)
 
         self._debugGenerator("Gecko._getSpeechForText",
@@ -689,7 +689,7 @@
 
             # Well...now we skip the parent if it's accessible text is
             # a single EMBEDDED_OBJECT_CHARACTER.  The reason for this
-            # is that it util.py:getDisplayedText will end up coming
+            # is that it Script.getDisplayedText will end up coming
             # back to the children of an object for the text in the
             # children if an object's text contains an
             # EMBEDDED_OBJECT_CHARACTER.
@@ -699,13 +699,13 @@
                 unicodeText = displayedText.decode("UTF-8")
                 if unicodeText \
                     and (len(unicodeText) == 1) \
-                    and (unicodeText[0] == util.EMBEDDED_OBJECT_CHARACTER):
+                    and (unicodeText[0] == self.EMBEDDED_OBJECT_CHARACTER):
                     parent = parent.parent
                     continue
 
             # Finally, put in the text and label (if they exist)
             #
-            text = util.getDisplayedText(parent)
+            text = self.getDisplayedText(parent)
             label = util.getDisplayedLabel(parent)
             if text and (text != label) and len(text):
                 utterances.append(text)
@@ -2054,7 +2054,7 @@
                 text = self.getUnicodeText(obj.parent)
                 if text:
                     for offset in range(0, len(text)):
-                        if text[offset] == util.EMBEDDED_OBJECT_CHARACTER:
+                        if text[offset] == self.EMBEDDED_OBJECT_CHARACTER:
                             if index == obj.index:
                                 obj.characterOffsetInParent = offset
                                 break
@@ -2095,11 +2095,11 @@
             unicodeText = self.getUnicodeText(obj)
             if unicodeText \
                and (unicodeText[characterOffset] \
-                    == util.EMBEDDED_OBJECT_CHARACTER):
+                    == self.EMBEDDED_OBJECT_CHARACTER):
                 index = -1
                 for character in range(0, characterOffset + 1):
                     if unicodeText[character] \
-                        == util.EMBEDDED_OBJECT_CHARACTER:
+                        == self.EMBEDDED_OBJECT_CHARACTER:
                         index += 1
                 obj.childrenIndices[characterOffset] = index
 
@@ -2327,7 +2327,7 @@
         useless = False
 
         if obj.role in [rolenames.ROLE_IMAGE, rolenames.ROLE_TABLE_CELL]:
-            text = util.getDisplayedText(obj)
+            text = self.getDisplayedText(obj)
             if (not text) or (len(text) == 0):
                 text = util.getDisplayedLabel(obj)
                 if (not text) or (len(text) == 0):
@@ -2404,7 +2404,7 @@
             character = self.getText(obj,
                                      characterOffset,
                                      characterOffset + 1).decode("UTF-8")
-            if character == util.EMBEDDED_OBJECT_CHARACTER:
+            if character == self.EMBEDDED_OBJECT_CHARACTER:
                 try:
                     childIndex = self.getChildIndex(obj, characterOffset)
                     return self.findFirstCaretContext(obj.child(childIndex), 0)
@@ -2454,7 +2454,7 @@
             unicodeText = self.getUnicodeText(obj)
             nextOffset = startOffset + 1
             if nextOffset < len(unicodeText):
-                if unicodeText[nextOffset] != util.EMBEDDED_OBJECT_CHARACTER:
+                if unicodeText[nextOffset] != self.EMBEDDED_OBJECT_CHARACTER:
                     return [obj, nextOffset]
                 elif obj.childCount:
                     child = obj.child(self.getChildIndex(obj, nextOffset))
@@ -2529,7 +2529,7 @@
             previousOffset = startOffset - 1
             if previousOffset >= 0:
                 if unicodeText[previousOffset] \
-                    != util.EMBEDDED_OBJECT_CHARACTER:
+                    != self.EMBEDDED_OBJECT_CHARACTER:
                     return [obj, previousOffset]
                 else:
                     return self.findPreviousCaretInOrder(
@@ -2954,7 +2954,7 @@
         contents = []
         text = self.getUnicodeText(obj)
         for offset in range(characterOffset, len(text)):
-            if text[offset] == util.EMBEDDED_OBJECT_CHARACTER:
+            if text[offset] == self.EMBEDDED_OBJECT_CHARACTER:
                 contents.extend(self.getObjectContentsAtOffset(
                     obj.child(self.getChildIndex(obj, offset)),
                     0))
Index: src/orca/where_am_I.py
===================================================================
--- src/orca/where_am_I.py	(revision 2115)
+++ src/orca/where_am_I.py	(working copy)
@@ -649,7 +649,7 @@
     Returns the name to speak for an object.
     """
     text = ""
-    name = util.getDisplayedText(obj)
+    name = orca_state.activeScript.getDisplayedText(obj)
     if not name:
         name = obj.description
 
@@ -897,7 +897,7 @@
         return ""
     
     descendant = util.getRealActiveDescendant(obj)
-    text = util.getDisplayedText(descendant)
+    text = orca_state.activeScript.getDisplayedText(descendant)
 
     # For Evolution mail header list.
     if _getAppName().startswith("evolution") and text == "Status":
Index: src/orca/braille.py
===================================================================
--- src/orca/braille.py	(revision 2109)
+++ src/orca/braille.py	(working copy)
@@ -63,6 +63,7 @@
     pass
 import debug
 import eventsynthesizer
+import orca_state
 import settings
 import util
 
@@ -312,7 +313,7 @@
 
         self.accessible = accessible
         [string, self.caretOffset, self.lineOffset] = \
-                 util.getTextLineAtCaret(self.accessible)
+                 orca_state.activeScript.getTextLineAtCaret(self.accessible)
 
         # Sometimes, gnome-terminal will give us very odd values when
         # the user is editing using 'vi' and has positioned the caret
@@ -345,7 +346,7 @@
         """
 
         [string, caretOffset, lineOffset] = \
-                 util.getTextLineAtCaret(self.accessible)
+                 orca_state.activeScript.getTextLineAtCaret(self.accessible)
         cursorOffset = caretOffset - lineOffset
         if self.label:
             cursorOffset += len(self.label.decode("UTF-8")) + 1
Index: src/orca/braillegenerator.py
===================================================================
--- src/orca/braillegenerator.py	(revision 2115)
+++ src/orca/braillegenerator.py	(working copy)
@@ -294,7 +294,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self._script.getDisplayedText(obj))
         text = util.appendString(text, self._getTextForValue(obj))
         text = util.appendString(text, self._getTextForRole(obj))
 
@@ -333,7 +333,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self._script.getDisplayedText(obj))
         text = util.appendString(text, self._getTextForRole(obj))
         text = util.appendString(text, obj.description, ": ")
 
@@ -376,7 +376,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self._script.getDisplayedText(obj))
 
         if obj.state.count(atspi.Accessibility.STATE_CHECKED):
             text = util.appendString(text, "<x>")
@@ -406,7 +406,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self._script.getDisplayedText(obj))
 
         if obj.state.count(atspi.Accessibility.STATE_CHECKED):
             text = util.appendString(text, "<x>")
@@ -461,7 +461,7 @@
             regions.append(braille.Region(label + " "))
             focusedRegionIndex = 1
 
-        displayedText = util.getDisplayedText(obj)
+        displayedText = self._script.getDisplayedText(obj)
         if displayedText:
             regions.append(braille.Region(displayedText))
 
@@ -586,7 +586,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self._script.getDisplayedText(obj))
 
         if obj.image:
             description = obj.image.imageDescription
@@ -661,7 +661,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self._script.getDisplayedText(obj))
         text = util.appendString(text, rolenames.getBrailleForRoleName(obj))
 
         if obj == orca_state.locusOfFocus:
@@ -704,7 +704,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self._script.getDisplayedText(obj))
 
         if obj == orca_state.locusOfFocus:
             text = util.appendString(text, self._getTextForAvailability(obj))
@@ -770,7 +770,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self._script.getDisplayedText(obj))
 
         if obj == orca_state.locusOfFocus:
             text = util.appendString(text, self._getTextForAvailability(obj))
@@ -829,7 +829,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self._script.getDisplayedText(obj))
 
         # In Java, some push buttons don't have label and text.
         # In this case, we'll add to presentation the object description,
@@ -861,7 +861,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self._script.getDisplayedText(obj))
 
         # In Java, some toggle buttons don't have label and text.
         # In this case, we'll add to presentation the object description,
@@ -898,7 +898,7 @@
 
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
-        text = util.appendString(text, util.getDisplayedText(obj))
+        text = util.appendString(text, self._script.getDisplayedText(obj))
 
         if obj.state.count(atspi.Accessibility.STATE_CHECKED):
             text = util.appendString(text, "&=y")
@@ -967,7 +967,7 @@
         text = ""
         text = util.appendString(text, util.getDisplayedLabel(obj))
         # Ignore the text on the slider.
-        #text = util.appendString(text, util.getDisplayedText(obj))
+        #text = util.appendString(text, self._script.getDisplayedText(obj))
         text = util.appendString(text, self._getTextForValue(obj))
         text = util.appendString(text, self._getTextForRole(obj))
 
@@ -1409,7 +1409,7 @@
                 # Announce the label and text of the object in the hierarchy.
                 #
                 label = util.getDisplayedLabel(parent)
-                text = util.getDisplayedText(parent)
+                text = self._script.getDisplayedText(parent)
                 regions.append(braille.Region(" "))
                 result = self.getBrailleRegions(parent, False)
                 regions.extend(result[0])
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 2115)
+++ ChangeLog	(working copy)
@@ -66,7 +66,7 @@
           Moved:
           def getAcceleratorAndShortcut(obj):
 
-        * src/orca/util.py
+        * src/orca/util.py:
           src/orca/default.py:
           src/orca/where_am_I.py:
           src/orca/braillegenerator.py:
@@ -75,6 +75,29 @@
           Moved:
           def getNodeLevel(obj):
 
+        * src/orca/scripts/gedit.py:
+          src/orca/scripts/planner.py:
+          src/orca/scripts/gcalctool.py:
+          src/orca/scripts/Thunderbird.py:
+          src/orca/scripts/gaim.py:
+          src/orca/scripts/acroread.py:
+          src/orca/scripts/Evolution.py:
+          src/orca/scripts/StarOffice.py:
+          src/orca/flat_review.py:
+          src/orca/where_am_I.py:
+          src/orca/util.py:
+          src/orca/speechgenerator.py:
+          src/orca/default.py:
+          src/orca/Gecko.py:
+          src/orca/braille.py:
+          src/orca/braillegenerator.py:
+          Another partial fix for bug #395548.
+
+          Moved:
+          def __getDisplayedTextInComboBox(combo):
+          def getDisplayedText(obj):
+          def getTextLineAtCaret(obj):
+
 2007-03-05  Rich Burridge <rich.burridge@sun.com>
 
         * src/orca/debug.py:
