[binutils-gdb] [gdb/tui] Handle tui disable in new ui

Tom de Vries via Gdb-cvs <[email protected]>
Newsgroups gmane.comp.gdb.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=8927b500532538cd86aae2d777c6452c51a210c6

commit 8927b500532538cd86aae2d777c6452c51a210c6
Author: Tom de Vries <[email protected]>
Date:   Tue Apr 21 18:12:05 2026 +0200

    [gdb/tui] Handle tui disable in new ui
    
    I tried out the following scenario.
    
    First, I start a terminal to get a tty [1].
    ...
    $ gnome-terminal -- bash -c "tty; sleep 999999999" &
    ...
    
    Then I start gdb, and start a new UI in the tty:
    ...
    $ gdb
    (gdb) new-ui console /dev/pts/3
    New UI allocated
    (gdb)
    ...
    
    Now I have two terminals, each with a gdb prompt.
    
    I try in the new UI to enable TUI:
    ...
    (gdb) tui enable
    ❌️ Cannot enable the TUI when the interpreter is 'console'
    (gdb)
    ...
    but that is not allowed.
    
    So instead, I enable TUI in the main UI.  So far so good.
    
    Now I disable TUI in the new UI.  That leaves the new UI in this state:
    ...
    (gdb) tui disable
    <blinking cursor>
    ...
    So, no gdb prompt.
    
    The main UI does leave TUI, AFAICT.
    
    If I do "print 1<enter>" in the new UI, I get the result in the main UI, which
    is not supposed to happen.
    
    Fix this by instead throwing an error if we try to disable TUI in the new UI:
    ...
    (gdb) tui disable
    ❌️ Cannot enable  or disablethe TUI when the interpreter is 'console'
    (gdb)
    ...
    
    We could try to fix this instead by allowing tui enable/disable from the new
    UI, using:
    ...
      scoped_restore restore_interpreter
        = make_scoped_restore (&current_ui, main_ui);
    ...
    but with just that change, when doing "tui enable" in the new UI we do get a
    TUI layout in the main UI, but no gdb prompt.  The prompt does appear after a
    new keystroke in the main UI though.
    
    A few more TUI commands (for instance "layout asm") have the same problem:
    - they work when entered in the new UI,
    - they have an effect in the main UI, but
    - they don't show a prompt in the main UI.
    
    I left that problem as is, and exercised some TUI commands in a new UI in the
    test-case.
    
    Tested on x86_64-linux.
    
    Approved-By: Andrew Burgess <[email protected]>
    
    Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34035

Diff:
---
 gdb/testsuite/gdb.tui/new-ui.exp | 93 ++++++++++++++++++++++++++++++++++++++++
 gdb/tui/tui.c                    | 18 ++++++--
 2 files changed, 107 insertions(+), 4 deletions(-)

diff --git a/gdb/testsuite/gdb.tui/new-ui.exp b/gdb/testsuite/gdb.tui/new-ui.exp
new file mode 100644
index 00000000000..8fe3567077a
--- /dev/null
+++ b/gdb/testsuite/gdb.tui/new-ui.exp
@@ -0,0 +1,93 @@
+# Copyright 2026 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test TUI in combination with a new UI.
+
+tuiterm_env
+
+# Creating a pty is done on build, and we use it with gdb on host, so we need
+# build == host, in other words, local host.
+require {!is_remote host}
+
+# Create a pty.
+spawn -pty
+set new_ui_spawn_id $spawn_id
+set new_ui_tty_name $spawn_out(slave,name)
+
+set re_cannot_enable_disable_tui \
+    "Cannot enable or disable the TUI when the interpreter is 'console'"
+
+with_test_prefix main-ui {
+    Term::clean_restart 24 80
+
+    # Check that we cannot setup a new tui UI.  Also checked in
+    # gdb.base/new-ui.exp.
+    gdb_test "new-ui tui $new_ui_tty_name" \
+	"interpreter 'tui' cannot be used with a new UI" \
+	{new-ui tui $new_ui_tty_name}
+
+    # Set up a new console UI.
+    gdb_test "new-ui console $new_ui_tty_name" \
+	"New UI allocated" \
+	{new-ui cli $new_ui_tty_name}
+}
+
+with_test_prefix new-ui {
+    with_spawn_id $new_ui_spawn_id {
+	# Check that we cannot enable TUI in the new UI.
+	gdb_test "tui enable" $re_cannot_enable_disable_tui
+    }
+}
+
+with_test_prefix main-ui {
+    if {![Term::enter_tui]} {
+	unsupported "TUI not supported"
+	return
+    }
+}
+
+with_test_prefix new-ui {
+    with_spawn_id $new_ui_spawn_id {
+	# Check that we cannot disable TUI in the new UI.
+	# Regression test for PR34035.  Without the fix, this test will timeout,
+	# because no prompt will appear.
+	gdb_test "tui disable" $re_cannot_enable_disable_tui
+
+	gdb_test "print 1" \
+	    [quotemeta {$@DECIMAL = 1}] \
+	    "Check that UI is responsive"
+    }
+
+    # Try out some TUI commands.  We don't check for the effect in the main
+    # UI, we just check that the main UI is still responsive at the end.
+    with_spawn_id $new_ui_spawn_id {
+	gdb_test "info win" [quotemeta "@...(has focus)@..."]
+
+	gdb_test "focus cmd" \
+	    [string_to_regexp "Focus set to cmd window."]
+
+	# This command leaves a blinking cursor at the end of the status line.
+	gdb_test_no_output "layout asm"
+
+	gdb_test "winheight asm +1"
+	gdb_test_no_output "tui refresh"
+    }
+}
+
+with_test_prefix main-ui {
+    gdb_assert {[Term::command "print 1"]} \
+	"Check that UI is responsive"
+    Term::dump_screen
+}
diff --git a/gdb/tui/tui.c b/gdb/tui/tui.c
index 9cf21f390c8..5e39eef71c6 100644
--- a/gdb/tui/tui.c
+++ b/gdb/tui/tui.c
@@ -394,6 +394,17 @@ gdb_getenv_term (void)
   return "<unset>";
 }
 
+/* Error out if the toplevel interpreter is not the TUI interpreter.  */
+
+static void
+require_tui_interpreter ()
+{
+  const char *interp = top_level_interpreter ()->name ();
+  if (!streq (interp, INTERP_TUI))
+    error (_("Cannot enable or disable the TUI when the interpreter is '%s'"),
+	   interp);
+}
+
 /* Enter in the tui mode (curses).
    When in normal mode, it installs the tui hooks in gdb, redirects
    the gdb output, configures the readline to work in tui mode.
@@ -424,13 +435,10 @@ tui_enable (void)
 #ifndef __MINGW32__
        const char *cap;
 #endif
-      const char *interp;
 
       /* If the top level interpreter is not the console/tui (e.g.,
 	 MI), enabling curses will certainly lose.  */
-      interp = top_level_interpreter ()->name ();
-      if (!streq (interp, INTERP_TUI))
-	error (_("Cannot enable the TUI when the interpreter is '%s'"), interp);
+      require_tui_interpreter ();
 
       /* Don't try to setup curses (and print funny control
 	 characters) if we're not outputting to a terminal.  */
@@ -556,6 +564,8 @@ tui_disable (void)
   if (!tui_active)
     return;
 
+  require_tui_interpreter ();
+
   /* Restore initial readline keymap.  */
   rl_set_keymap (tui_readline_standard_keymap);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.