Index: test/keystrokes/firefox/codetalks_button.py
===================================================================
--- test/keystrokes/firefox/codetalks_button.py	(revision 0)
+++ test/keystrokes/firefox/codetalks_button.py	(revision 0)
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+
+"""Test of Codetalks button test presentation using Firefox.
+"""
+
+from macaroon.playback import *
+import utils
+
+sequence = MacroSequence()
+
+########################################################################
+# We wait for the focus to be on the Firefox window as well as for focus
+# to move to the "text/html: Button Example 1" frame.
+#
+sequence.append(WaitForWindowActivate(utils.firefoxFrameNames, None))
+
+########################################################################
+# Load the Codetalks button demo.
+#
+sequence.append(KeyComboAction("<Control>l"))
+sequence.append(WaitForFocus(acc_role=pyatspi.ROLE_ENTRY))
+sequence.append(TypeAction("http://codetalks.org/source/widgets/button/button.html"))
+sequence.append(KeyComboAction("Return"))
+sequence.append(WaitForDocLoad())
+sequence.append(WaitForFocus("ARIA Button", acc_role=pyatspi.ROLE_DOCUMENT_FRAME))
+
+########################################################################
+# Tab to the "ARIA documentation" link
+#
+sequence.append(KeyComboAction("Tab"))
+sequence.append(WaitForFocus("ARIA documentation", acc_role=pyatspi.ROLE_LINK))
+
+########################################################################
+# Tab to the "Tracking number" entry
+#
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Tab"))
+sequence.append(WaitForFocus("Tracking number", acc_role=pyatspi.ROLE_ENTRY))
+sequence.append(utils.AssertPresentationAction(
+    "Tab to Tracking number text entry", 
+    ["BRAILLE LINE:  'Tracking number Tracking number  $l'",
+     "     VISIBLE:  'Tracking number  $l', cursor=17",
+     "SPEECH OUTPUT: 'Order tracking panel'",
+     "SPEECH OUTPUT: 'Tracking number text '"]))
+
+########################################################################
+# Tab to the "Check Now" push button
+#
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Tab"))
+sequence.append(WaitForFocus("Check Now", acc_role=pyatspi.ROLE_PUSH_BUTTON))
+sequence.append(utils.AssertPresentationAction(
+    "Tab to Check Now push button",
+    ["BRAILLE LINE:  'Check Now Button Check to see if your order has been shipped.  $l'",
+     "     VISIBLE:  'Check Now Button Check to see if', cursor=1",
+     "SPEECH OUTPUT: ''",
+     "SPEECH OUTPUT: 'Check Now button'"]))
+
+########################################################################
+# Do a basic "Where Am I" via KP_Enter.  The following should be
+# presented in speech and braille:
+#
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("KP_Enter"))
+sequence.append(PauseAction(3000))
+sequence.append(utils.AssertPresentationAction(
+    "basic whereamI", 
+    ["BRAILLE LINE:  'Check Now Button Check to see if your order has been shipped.  $l'",
+     "     VISIBLE:  'Check Now Button Check to see if', cursor=1",
+     "SPEECH OUTPUT: 'Check Now'",
+     "SPEECH OUTPUT: 'button'",
+     "SPEECH OUTPUT: ''",
+     "SPEECH OUTPUT: 'Check to see if your order has been shipped.'"]))
+
+########################################################################
+# Now push the button.  The following will be presented.
+#
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Return"))
+sequence.append(WaitForFocus("OK", acc_role=pyatspi.ROLE_PUSH_BUTTON))
+sequence.append(utils.AssertPresentationAction(
+    "Popup dialog", 
+    ["BRAILLE LINE:  'Firefox Application The page at http://codetalks.org says: Dialog'",
+     "     VISIBLE:  'The page at http://codetalks.org', cursor=1",
+     "BRAILLE LINE:  'Firefox Application The page at http://codetalks.org says: Dialog OK Button'",
+     "     VISIBLE:  'OK Button', cursor=1",
+     "SPEECH OUTPUT: 'The page at http://codetalks.org says: Button pressed'",
+     "SPEECH OUTPUT: ''",
+     "SPEECH OUTPUT: 'OK button'"]))
+
+########################################################################
+# Dismiss the dialog.
+#
+sequence.append(utils.StartRecordingAction())
+sequence.append(KeyComboAction("Return"))
+sequence.append(WaitForFocus("Check Now", acc_role=pyatspi.ROLE_PUSH_BUTTON))
+sequence.append(utils.AssertPresentationAction(
+    "Dismiss dialog", 
+    ["BRAILLE LINE:  'Firefox Application ARIA Button - Mozilla Firefox Frame'",
+     "     VISIBLE:  'ARIA Button - Mozilla Firefox Fr', cursor=1",
+     "BRAILLE LINE:  'Check Now Button Check to see if your order has been shipped.  $l'",
+     "     VISIBLE:  'Check Now Button Check to see if', cursor=1",
+     "SPEECH OUTPUT: 'ARIA Button - Mozilla Firefox frame'",
+     "SPEECH OUTPUT: 'Check Now button Check to see if your order has been shipped. text'"]))
+
+########################################################################
+# Close the demo
+#
+sequence.append(KeyComboAction("<Control>l"))
+sequence.append(WaitForFocus(acc_role=pyatspi.ROLE_ENTRY))
+sequence.append(TypeAction("about:blank"))
+sequence.append(KeyComboAction("Return"))
+sequence.append(WaitForDocLoad())
+
+# Just a little extra wait to let some events get through.
+#
+sequence.append(PauseAction(3000))
+
+sequence.append(utils.AssertionSummaryAction())
+
+sequence.start()
Index: src/orca/liveregions.py
===================================================================
--- src/orca/liveregions.py	(revision 4447)
+++ src/orca/liveregions.py	(working copy)
@@ -360,7 +360,14 @@
             if relationtype == pyatspi.RELATION_DESCRIBED_BY:
                 targetobj = relation.getTarget(0)
                 try:
-                    utterances.append(targetobj.queryText().getText(0, -1))
+                    # We will add on descriptions if they don't duplicate
+                    # what's already in the object's description.
+                    # See http://bugzilla.gnome.org/show_bug.cgi?id=568467
+                    # for more information.
+                    #
+                    description = targetobj.queryText().getText(0, -1)
+                    if description.strip() != obj.description.strip():
+                        utterances.append(description)
                 except NotImplemented:
                     pass
 
@@ -372,7 +379,7 @@
             liveprioritystr = 'none'
 
         # We will only output useful information
-        # TODO: check for repeated descriptions
+        # 
         if utterances or liveprioritystr != 'none':
             # Translators: output the politeness level
             #
