diff --git a/gdb/testsuite/gdb.tui/tui-focus.exp b/gdb/testsuite/gdb.tui/tui-focus.exp
index 9e2a1cd0935..72f80523af3 100644
--- a/gdb/testsuite/gdb.tui/tui-focus.exp
+++ b/gdb/testsuite/gdb.tui/tui-focus.exp
@@ -13,12 +13,12 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-# Minimal testcase that just checks that the various "layout $foo"
-# commands do not cause gdb to crash.
+# Testcase that just checks the tui 'focus' command works as expected.
 
 require allow_tui_tests
 
 tuiterm_env
+load_lib gdb-python.exp
 
 standard_testfile
 
@@ -31,7 +31,8 @@ if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} {
 # Each test specification is a tuple where the first item is the name of a
 # window, and the second item is a boolean indicating if we expect that
 # window to be present in the default (src) layout.
-foreach spec {{src true} {cmd true} {status true} {regs false} {asm false}} {
+foreach spec {{src true} {cmd true} {status true} {regs false} \
+		  {asm false} {unknown false}} {
     lassign $spec window valid_p
     with_test_prefix "window=$window" {
 
@@ -54,8 +55,13 @@ foreach spec {{src true} {cmd true} {status true} {regs false} {asm false}} {
 		    "^Focus set to $window window\\.\\s*"
 	    }
 	} else {
-	    Term::check_region_contents "check focus error" 0 16 80 1 \
-		"^Unrecognized window name \"$window\"\\s*"
+	    if {$window == "unknown"} {
+		Term::check_region_contents "check focus error" 0 16 80 1 \
+		    "^Unrecognized window name \"$window\"\\s*"
+	    } else {
+		Term::check_region_contents "check focus error" 0 16 80 1 \
+		    "^Window \"$window\" is not in the current layout\\s*"
+	    }
 	}
 
 	Term::check_box "check src box" 0 0 80 15
@@ -66,3 +72,72 @@ foreach spec {{src true} {cmd true} {status true} {regs false} {asm false}} {
 	Term::command "focus prev"
     }
 }
+
+# Use the Python TUI API to exercise some of the ambigous window name
+# handling parts of the 'focus' command.
+Term::clean_restart 24 80 $binfile
+if {[allow_python_tests]} {
+    # Create a very simple tui window.
+    gdb_py_test_silent_cmd \
+	[multi_line_input \
+	     "python" \
+	     "class TestWindow:" \
+	     "    def __init__(self, win):" \
+	     "        pass" \
+	     "" \
+	     "    def render(self):" \
+	     "        pass" \
+	     "end"] \
+	"setup dummy window class" \
+	true
+
+    # Register the window with a set of similar names.
+    gdb_test_no_output "python gdb.register_window_type(\"test1\", TestWindow)"
+    gdb_test_no_output "python gdb.register_window_type(\"test2\", TestWindow)"
+    gdb_test_no_output "python gdb.register_window_type(\"test3\", TestWindow)"
+
+    # Create a layout containing just one of the above windows.
+    gdb_test_no_output "tui new-layout example1 test2 1 status 1 cmd 1"
+
+    # Create a layout containing two of the above windows.
+    gdb_test_no_output "tui new-layout example2 test1 1 test2 1 status 1 cmd 1"
+
+    if {![Term::prepare_for_tui]} {
+	unsupported "TUI not supported"
+	return
+    }
+
+    # Try to focus using an ambiguous, partial window name.  This
+    # should fail as the default layout (src) doesn't include any
+    # windows matching this name.
+    Term::command_no_prompt_prefix "focus test"
+    Term::check_region_contents "check no matching window focus message" \
+	0 16 80 1 \
+	"^No windows matching \"test\" in the current layout\\s*"
+
+    # Now select a layout that includes a single window that matches
+    # the ambiguous, partial name 'test', and disable tui mode.
+    Term::command "layout example1"
+    send_gdb "tui disable\n"
+
+    # Reactivate tui mode and try to set focus using the ambiguous,
+    # partial window name.  This should succeed though, as, within the
+    # current layout, the partial name is not actually ambiguous.
+    send_gdb "focus test\n"
+    gdb_assert [Term::wait_for_region_contents 0 19 80 1 \
+		    "^Focus set to test2 window\\.\\s*"] \
+	"check test2 focus message"
+
+    # Now select a layout that includes two windows that matches the
+    # ambiguous, partial name 'test', and disable tui mode.
+    Term::command "layout example2"
+    send_gdb "tui disable\n"
+
+    # Reactivate tui mode and try to set focus using the ambiguous,
+    # partial window name.  This will fail as now the layout includes
+    # multiple windows that match 'test'.
+    send_gdb "focus test\n"
+    gdb_assert [Term::wait_for_region_contents 0 22 80 1 \
+		    "^Window name \"test\" is ambiguous\\s*"] \
+	"check ambiguous focus message"
+}
diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index 27abee02087..ecdcd4884a7 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -29,7 +29,6 @@
 #include "cli/cli-decode.h"
 #include "cli/cli-utils.h"
 #include <ctype.h>
-#include <unordered_map>
 #include <unordered_set>
 
 #include "tui/tui.h"
@@ -351,7 +350,17 @@ make_standard_window (const char *)
    shut down, causing crashes if any window destruction requires
    running Python code.  */
 
-static std::unordered_map<std::string, window_factory> *known_window_types;
+static window_types_map *known_window_types;
+
+/* See tui-layout.h.  */
+
+known_window_names_range
+all_known_window_names ()
+{
+  auto begin = known_window_names_iterator (known_window_types->begin ());
+  auto end = known_window_names_iterator (known_window_types->end ());
+  return known_window_names_range (begin, end);
+}
 
 /* Helper function that returns a TUI window, given its name.  */
 
@@ -377,7 +386,7 @@ tui_get_window_by_name (const std::string &name)
 static void
 initialize_known_windows ()
 {
-  known_window_types = new std::unordered_map<std::string, window_factory>;
+  known_window_types = new window_types_map;
 
   known_window_types->emplace (SRC_NAME,
 			       make_standard_window<SRC_WIN,
diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h
index 206f1117445..ff354fb7c2f 100644
--- a/gdb/tui/tui-layout.h
+++ b/gdb/tui/tui-layout.h
@@ -26,6 +26,9 @@
 
 #include "tui/tui.h"
 #include "tui/tui-data.h"
+#include "gdbsupport/iterator-range.h"
+
+#include <unordered_map>
 
 /* Values that can be returned when handling a request to adjust a
    window's size.  */
@@ -358,10 +361,56 @@ extern void tui_adjust_window_width (struct tui_win_info *win,
 
 typedef std::function<tui_win_info * (const char *name)> window_factory;
 
+/* The type for a data structure that maps a window name to that window's
+   factory function.  */
+typedef std::unordered_map<std::string, window_factory> window_types_map;
+
 /* Register a new TUI window type.  NAME is the name of the window
    type.  FACTORY is a function that can be called to instantiate the
    window.  */
 
 extern void tui_register_window (const char *name, window_factory &&factory);
 
+/* An iterator class that exposes just the window names from the
+   known_window_types map in tui-layout.c.  This is just a wrapper around
+   an iterator of the underlying known_window_types map, but this just
+   exposes the window names.  */
+
+struct known_window_names_iterator
+{
+  using known_window_types_iterator = window_types_map::iterator;
+
+  known_window_names_iterator (known_window_types_iterator &&iter)
+    : m_iter (std::move (iter))
+  { /* Nothing.  */ }
+
+  known_window_names_iterator &operator++ ()
+  {
+    ++m_iter;
+    return *this;
+  }
+
+  const std::string &operator* () const
+  { return (*m_iter).first; }
+
+  bool operator!= (const known_window_names_iterator &other) const
+  { return m_iter != other.m_iter; }
+
+private:
+
+  /* The underlying iterator.  */
+  known_window_types_iterator m_iter;
+};
+
+/* A range adapter that makes it possible to iterate over the names of all
+   known tui windows.  */
+
+using known_window_names_range
+  = iterator_range<known_window_names_iterator>;
+
+/* Return a range that can be used to walk over the name of all known tui
+   windows in a range-for loop.  */
+
+extern known_window_names_range all_known_window_names ();
+
 #endif /* TUI_TUI_LAYOUT_H */
diff --git a/gdb/tui/tui-win.c b/gdb/tui/tui-win.c
index 492a5191025..008189eb99b 100644
--- a/gdb/tui/tui-win.c
+++ b/gdb/tui/tui-win.c
@@ -728,8 +728,44 @@ tui_set_focus_command (const char *arg, int from_tty)
   else
     win_info = tui_partial_win_by_name (arg);
 
-  if (win_info == NULL)
-    error (_("Unrecognized window name \"%s\""), arg);
+  if (win_info == nullptr)
+    {
+      /* When WIN_INFO is nullptr this can either mean that the window name
+	 is unknown to GDB, or that the window is not in the current
+	 layout.  To try and help the user, give a different error
+	 depending on which of these is the case.  */
+      std::string matching_window_name;
+      bool is_ambiguous = false;
+
+      for (const std::string &name : all_known_window_names ())
+	{
+	  /* Look through all windows in the current layout, if the window
+	     is in the current layout then we're not interested is it.  */
+	  for (tui_win_info *item : all_tui_windows ())
+	    if (item->name () == name)
+	      continue;
+
+	  if (startswith (name, arg))
+	    {
+	      if (matching_window_name.empty ())
+		matching_window_name = name;
+	      else
+		is_ambiguous = true;
+	    }
+	};
+
+      if (!matching_window_name.empty ())
+	{
+	  if (is_ambiguous)
+	    error (_("No windows matching \"%s\" in the current layout"),
+		   arg);
+	  else
+	    error (_("Window \"%s\" is not in the current layout"),
+		   matching_window_name.c_str ());
+	}
+      else
+	error (_("Unrecognized window name \"%s\""), arg);
+    }
 
   /* If a window is part of the current layout then it will have a
      tui_win_info associated with it and be visible, otherwise, there will
