diff --git a/src/orca/default.py b/src/orca/default.py
index ec8d66c..f6ce43c 100644
--- a/src/orca/default.py
+++ b/src/orca/default.py
@@ -3263,6 +3263,7 @@ class Script(script.Script):
                 return
 
         if event.type.startswith("object:state-changed:selected") \
+           and not settings.onlySpeakDisplayedText \
            and orca_state.locusOfFocus:
             # If this selection state change is for the object which
             # currently has the locus of focus, and the last keyboard
@@ -5104,6 +5105,9 @@ class Script(script.Script):
         - endOffset: text end offset.
         """
 
+        if settings.onlySpeakDisplayedText:
+            return
+
         try:
             text = obj.queryText()
         except:
@@ -5280,18 +5284,19 @@ class Script(script.Script):
         except:
             debug.printException(debug.LEVEL_FINEST)
 
-        voice = self.voices.get(settings.SYSTEM_VOICE)
-        if self.utilities.isTextSelected(obj, startOffset, endOffset):
-            # Translators: when the user selects (highlights) text in
-            # a document, Orca lets them know this.
-            #
-            speech.speak(C_("text", "selected"), voice, False)
-        elif len(text.getText(startOffset, endOffset)):
-            # Translators: when the user unselects
-            # (unhighlights) text in a document, Orca lets
-            # them know this.
-            #
-            speech.speak(C_("text", "unselected"), voice, False)
+        if not settings.onlySpeakDisplayedText:
+            voice = self.voices.get(settings.SYSTEM_VOICE)
+            if self.utilities.isTextSelected(obj, startOffset, endOffset):
+                # Translators: when the user selects (highlights) text in
+                # a document, Orca lets them know this.
+                #
+                speech.speak(C_("text", "selected"), voice, False)
+            elif len(text.getText(startOffset, endOffset)):
+                # Translators: when the user unselects
+                # (unhighlights) text in a document, Orca lets
+                # them know this.
+                #
+                speech.speak(C_("text", "unselected"), voice, False)
 
         self._saveLastTextSelections(text)
 
@@ -5381,7 +5386,8 @@ class Script(script.Script):
         if briefMessage is None:
             briefMessage = fullMessage
 
-        if settings.enableSpeech:
+        if settings.enableSpeech \
+           and (voice != None or not settings.onlySpeakDisplayedText):
             if settings.messageVerbosityLevel == settings.VERBOSITY_LEVEL_BRIEF:
                 message = briefMessage
             else:
@@ -5741,9 +5747,11 @@ class Script(script.Script):
         - interrupt: If True, any current speech should be interrupted
           prior to speaking the new text.
         """
- 
-        voice = voice or self.voices.get(settings.SYSTEM_VOICE)
-        speech.speak(string, voice, interrupt)
+
+        if settings.enableSpeech \
+           and (voice != None or not settings.onlySpeakDisplayedText):
+            voice = voice or self.voices.get(settings.SYSTEM_VOICE)
+            speech.speak(string, voice, interrupt)
 
     @staticmethod
     def presentItemsInSpeech(items):
diff --git a/src/orca/orca.py b/src/orca/orca.py
index 330bc5a..0e262d7 100644
--- a/src/orca/orca.py
+++ b/src/orca/orca.py
@@ -306,7 +306,8 @@ def _onChildrenChanged(e):
         #
         try:
             if desktop.childCount == 0:
-                speech.speak(_("Goodbye."))
+                if not settings.onlySpeakDisplayedText:
+                    speech.speak(_("Goodbye."))
                 shutdown()
                 return
         except: # could be a CORBA.COMM_FAILURE
@@ -2100,7 +2101,8 @@ def main():
 
     try:
         message = _("Welcome to Orca.")
-        speech.speak(message, settings.voices.get(settings.SYSTEM_VOICE))
+        if not settings.onlySpeakDisplayedText:
+            speech.speak(message, settings.voices.get(settings.SYSTEM_VOICE))
         braille.displayMessage(message)
     except:
         debug.printException(debug.LEVEL_SEVERE)
diff --git a/src/orca/scripts/apps/evolution/speech_generator.py b/src/orca/scripts/apps/evolution/speech_generator.py
index ebdbebd..8fb50f9 100644
--- a/src/orca/scripts/apps/evolution/speech_generator.py
+++ b/src/orca/scripts/apps/evolution/speech_generator.py
@@ -27,6 +27,7 @@ __license__   = "LGPL"
 
 import pyatspi
 
+import orca.settings as settings
 import orca.speech_generator as speech_generator
 
 from orca.orca_i18n import _ # for gettext support
@@ -84,6 +85,9 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
         # formatting string to address the headers associated with
         # toggle columns. That's really the difference here.]]]
         #
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(speech_generator.SYSTEM)
         try:
diff --git a/src/orca/scripts/apps/soffice/speech_generator.py b/src/orca/scripts/apps/soffice/speech_generator.py
index c89e358..d3932e8 100644
--- a/src/orca/scripts/apps/soffice/speech_generator.py
+++ b/src/orca/scripts/apps/soffice/speech_generator.py
@@ -156,6 +156,9 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
         if that description is different from that of the name and
         label.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(speech_generator.SYSTEM)
         if obj.description:
@@ -351,6 +354,9 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
         Returns an indication of how many characters are greater than the size
         of the spread sheet cell, or None if the message fits.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(speech_generator.SYSTEM)
         try:
diff --git a/src/orca/scripts/toolkits/Gecko/speech_generator.py b/src/orca/scripts/toolkits/Gecko/speech_generator.py
index bff614d..c9699b3 100644
--- a/src/orca/scripts/toolkits/Gecko/speech_generator.py
+++ b/src/orca/scripts/toolkits/Gecko/speech_generator.py
@@ -32,6 +32,7 @@ __license__   = "LGPL"
 import pyatspi
 
 import orca.rolenames as rolenames
+import orca.settings as settings
 import orca.speech_generator as speech_generator
 
 from orca.orca_i18n import _
@@ -285,6 +286,9 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
         return result
 
     def _generateNumberOfChildren(self, obj, **args):
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(speech_generator.SYSTEM)
         role = args.get('role', obj.getRole())
@@ -416,12 +420,13 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
             # Finally add the role if it's not among the roles we don't
             # wish to speak.
             #
-            acss = self.voice(speech_generator.SYSTEM)
-            if not (role in dontSpeakRoles) and len(newResult):
-                roleInfo = rolenames.getSpeechForRoleName(parent)
-                if roleInfo:
-                    result.extend(acss)
-                    result.append(roleInfo)
+            if not settings.onlySpeakDisplayedText:
+                acss = self.voice(speech_generator.SYSTEM)
+                if not (role in dontSpeakRoles) and len(newResult):
+                    roleInfo = rolenames.getSpeechForRoleName(parent)
+                    if roleInfo:
+                        result.extend(acss)
+                        result.append(roleInfo)
 
             # If this object is an ARIA widget with STATE_REQUIRED, add
             # that. (Note that for the most part, the ARIA widget itself
diff --git a/src/orca/scripts/toolkits/J2SE-access-bridge/speech_generator.py b/src/orca/scripts/toolkits/J2SE-access-bridge/speech_generator.py
index 453691e..7d1cd8a 100644
--- a/src/orca/scripts/toolkits/J2SE-access-bridge/speech_generator.py
+++ b/src/orca/scripts/toolkits/J2SE-access-bridge/speech_generator.py
@@ -84,6 +84,9 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
         specifications) that represents the number of children the
         object has."""
 
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(speech_generator.SYSTEM)
         if obj and obj.getState().contains(pyatspi.STATE_EXPANDED) \
@@ -107,6 +110,9 @@ class SpeechGenerator(speech_generator.SpeechGenerator):
         object in a list.
         """
 
+        if settings.onlySpeakDisplayedText:
+            return []
+
         listObj = None
         if obj and obj.getRole() == pyatspi.ROLE_COMBO_BOX:
             allLists = self._script.utilities.descendantsWithRole(
diff --git a/src/orca/settings.py b/src/orca/settings.py
index 07abc5f..d60e253 100644
--- a/src/orca/settings.py
+++ b/src/orca/settings.py
@@ -89,6 +89,7 @@ from orca_i18n import C_          # to provide qualified translatable strings
 userCustomizableSettings = [
     "orcaModifierKeys",
     "enableSpeech",
+    "onlySpeakDisplayedText",
     "speechServerFactory",
     "speechServerInfo",
     "voices",
@@ -360,6 +361,11 @@ enableSpeechCallbacks   = True
 #
 silenceSpeech           = False
 
+# If True, only text which is displayed on screen will be spoken
+# (roles, states, etc. will not be).
+#
+onlySpeakDisplayedText = False
+
 # Settings that apply to the particular speech engine to
 # use as well details on the default voices to use.
 #
diff --git a/src/orca/speech_generator.py b/src/orca/speech_generator.py
index b816bde..e92dfb2 100644
--- a/src/orca/speech_generator.py
+++ b/src/orca/speech_generator.py
@@ -172,6 +172,9 @@ class SpeechGenerator(generator.Generator):
         represent the description of the object, if that description
         is different from that of the name and label.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         acss = self.voice(SYSTEM)
         result = generator.Generator._generateDescription(self, obj, **args)
         if result:
@@ -190,6 +193,9 @@ class SpeechGenerator(generator.Generator):
         of a speech generator that we can update and the user can
         override.]]]
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         role = args.get('role', obj.getRole())
@@ -205,6 +211,9 @@ class SpeechGenerator(generator.Generator):
         Note that a 'role' attribute in args will override the
         accessible role of the obj.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         role = args.get('role', obj.getRole())
@@ -268,6 +277,9 @@ class SpeechGenerator(generator.Generator):
         for check boxes. [[[WDW - should we return an empty array if
         we can guarantee we know this thing is not checkable?]]]
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         acss = self.voice(STATE)
         result = generator.Generator._generateCheckedState(self, obj, **args)
         if result:
@@ -280,6 +292,9 @@ class SpeechGenerator(generator.Generator):
         tree node. If the object is not expandable, an empty array
         will be returned.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         acss = self.voice(STATE)
         result = generator.Generator._generateExpandableState(self, obj, **args)
         if result:
@@ -291,6 +306,9 @@ class SpeechGenerator(generator.Generator):
         represent the checked state of the menu item, only if it is
         checked. Otherwise, and empty array will be returned.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         acss = self.voice(STATE)
         result = generator.Generator.\
             _generateMenuItemCheckedState(self, obj, **args)
@@ -304,6 +322,9 @@ class SpeechGenerator(generator.Generator):
         the object.  This is typically for check boxes. If the object
         is not multiselectable, an empty array will be returned.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(STATE)
         if obj.getState().contains(pyatspi.STATE_MULTISELECTABLE):
@@ -322,6 +343,9 @@ class SpeechGenerator(generator.Generator):
         for check boxes. [[[WDW - should we return an empty array if
         we can guarantee we know this thing is not checkable?]]]
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         acss = self.voice(STATE)
         result = generator.Generator._generateRadioState(self, obj, **args)
         if result:
@@ -334,6 +358,9 @@ class SpeechGenerator(generator.Generator):
         for check boxes. [[[WDW - should we return an empty array if
         we can guarantee we know this thing is not checkable?]]]
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         acss = self.voice(STATE)
         result = generator.Generator._generateToggleState(self, obj, **args)
         if result:
@@ -646,6 +673,9 @@ class SpeechGenerator(generator.Generator):
         returned.  [[[WDW - I wonder if this string should be moved to
         settings.py.]]]
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(STATE)
         # If this is an icon within an layered pane or a table cell
@@ -691,6 +721,9 @@ class SpeechGenerator(generator.Generator):
         """Returns an array of strings (and possibly voice and audio
         specifications) reflecting the column number of a cell.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         col = -1
@@ -717,6 +750,9 @@ class SpeechGenerator(generator.Generator):
         """Returns an array of strings (and possibly voice and audio
         specifications) reflecting the row number of a cell.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         row = -1
@@ -745,6 +781,9 @@ class SpeechGenerator(generator.Generator):
         of its column number, the total number of columns, its row,
         and the total number of rows.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         if obj.parent.getRole() == pyatspi.ROLE_TABLE_CELL:
@@ -777,6 +816,9 @@ class SpeechGenerator(generator.Generator):
         specifications) indicating that this cell is the last cell
         in the table.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         if settings.speechVerbosityLevel == settings.VERBOSITY_LEVEL_VERBOSE:
@@ -1052,6 +1094,9 @@ class SpeechGenerator(generator.Generator):
         object is selected. [[[WDW - I wonder if this string should be
         moved to settings.py.]]]
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
 
@@ -1073,6 +1118,9 @@ class SpeechGenerator(generator.Generator):
         object is selected. [[[WDW - I wonder if this string should be
         moved to settings.py.]]]
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         try:
@@ -1103,6 +1151,9 @@ class SpeechGenerator(generator.Generator):
         - obj: the text object.
         - line: the string to check for spaces and tabs.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         acss = self.voice(SYSTEM)
         if not settings.enableSpeechIndentation:
             return []
@@ -1168,6 +1219,9 @@ class SpeechGenerator(generator.Generator):
         is typically set by Orca to be the previous object with
         focus.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         oldLevel = self._script.utilities.nodeLevel(args.get('priorObj', None))
@@ -1189,6 +1243,9 @@ class SpeechGenerator(generator.Generator):
         object.  This is typically for progress bars. [[[WDW - we
         should consider returning an empty array if there is no value.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         try:
@@ -1262,6 +1319,9 @@ class SpeechGenerator(generator.Generator):
         this doesn't apply?]]] [[[WDW - I wonder if this string should
         be moved to settings.py.]]]
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         childNodes = self._script.utilities.childNodes(obj)
@@ -1283,6 +1343,9 @@ class SpeechGenerator(generator.Generator):
         apply?]]] [[[WDW - I wonder if this string should be moved to
         settings.py.]]]
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         hasItems = False
@@ -1307,6 +1370,9 @@ class SpeechGenerator(generator.Generator):
         apply?]]] [[[WDW - I wonder if this string should be moved to
         settings.py.]]]
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         if not obj.childCount:
@@ -1323,6 +1389,9 @@ class SpeechGenerator(generator.Generator):
         and the position of the current item. This object will be an icon
         panel or a layered pane.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         # TODO - JD: Is there a better way to do this other than
@@ -1383,6 +1452,9 @@ class SpeechGenerator(generator.Generator):
         [[[WDW - I wonder if this string should be moved to
         settings.py.]]]
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         # If this application has more than one unfocused alert or
@@ -1500,6 +1572,9 @@ class SpeechGenerator(generator.Generator):
         specifications) that represent the relative position of an
         object in a group.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         position = -1
@@ -1533,6 +1608,9 @@ class SpeechGenerator(generator.Generator):
         specifications) that represent the relative position of an
         object in a list.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         position = -1
@@ -1696,6 +1774,9 @@ class SpeechGenerator(generator.Generator):
         specifications) that represent the accelerator for the object,
         or an empty array if no accelerator can be found.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         [mnemonic, shortcut, accelerator] = \
@@ -1711,6 +1792,9 @@ class SpeechGenerator(generator.Generator):
         specifications) that represent the mnemonic for the object, or
         an empty array if no mnemonic can be found.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         if settings.enableMnemonicSpeaking or args.get('forceMnemonic', False):
@@ -1740,6 +1824,9 @@ class SpeechGenerator(generator.Generator):
         tutorial generator.  A tutorial can be forced by setting the
         'forceTutorial' attribute of the args dictionary to True.
         """
+        if settings.onlySpeakDisplayedText:
+            return []
+
         result = []
         acss = self.voice(SYSTEM)
         alreadyFocused = args.get('alreadyFocused', False)
