Home | History | Annotate | Line # | Download | only in tui
tui-win.c revision 1.1.1.9
      1 /* TUI window generic functions.
      2 
      3    Copyright (C) 1998-2024 Free Software Foundation, Inc.
      4 
      5    Contributed by Hewlett-Packard Company.
      6 
      7    This file is part of GDB.
      8 
      9    This program is free software; you can redistribute it and/or modify
     10    it under the terms of the GNU General Public License as published by
     11    the Free Software Foundation; either version 3 of the License, or
     12    (at your option) any later version.
     13 
     14    This program is distributed in the hope that it will be useful,
     15    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17    GNU General Public License for more details.
     18 
     19    You should have received a copy of the GNU General Public License
     20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     21 
     22 /* This module contains procedures for handling tui window functions
     23    like resize, scrolling, scrolling, changing focus, etc.
     24 
     25    Author: Susan B. Macchia  */
     26 
     27 #include "command.h"
     28 #include "symtab.h"
     29 #include "breakpoint.h"
     30 #include "frame.h"
     31 #include "cli/cli-cmds.h"
     32 #include "cli/cli-style.h"
     33 #include "top.h"
     34 #include "source.h"
     35 #include "gdbsupport/event-loop.h"
     36 #include "async-event.h"
     37 #include "utils.h"
     38 
     39 #include "tui/tui.h"
     40 #include "tui/tui-io.h"
     41 #include "tui/tui-command.h"
     42 #include "tui/tui-data.h"
     43 #include "tui/tui-layout.h"
     44 #include "tui/tui-wingeneral.h"
     45 #include "tui/tui-status.h"
     46 #include "tui/tui-regs.h"
     47 #include "tui/tui-disasm.h"
     48 #include "tui/tui-source.h"
     49 #include "tui/tui-winsource.h"
     50 #include "tui/tui-win.h"
     51 
     52 #include "gdb_curses.h"
     53 #include <ctype.h>
     54 #include "readline/readline.h"
     55 #include <string_view>
     56 
     57 #include <signal.h>
     58 
     59 static void tui_set_tab_width_command (const char *, int);
     60 static void tui_refresh_all_command (const char *, int);
     61 static void tui_all_windows_info (const char *, int);
     62 static void tui_scroll_forward_command (const char *, int);
     63 static void tui_scroll_backward_command (const char *, int);
     64 static void tui_scroll_left_command (const char *, int);
     65 static void tui_scroll_right_command (const char *, int);
     66 static void parse_scrolling_args (const char *,
     67 				  struct tui_win_info **,
     68 				  int *);
     69 
     70 
     71 #ifndef ACS_LRCORNER
     72 #  define ACS_LRCORNER '+'
     73 #endif
     74 #ifndef ACS_LLCORNER
     75 #  define ACS_LLCORNER '+'
     76 #endif
     77 #ifndef ACS_ULCORNER
     78 #  define ACS_ULCORNER '+'
     79 #endif
     80 #ifndef ACS_URCORNER
     81 #  define ACS_URCORNER '+'
     82 #endif
     83 #ifndef ACS_HLINE
     84 #  define ACS_HLINE '-'
     85 #endif
     86 #ifndef ACS_VLINE
     87 #  define ACS_VLINE '|'
     88 #endif
     89 
     90 /* Possible values for tui-border-kind variable.  */
     91 static const char *const tui_border_kind_enums[] = {
     92   "space",
     93   "ascii",
     94   "acs",
     95   NULL
     96 };
     97 
     98 /* Possible values for tui-border-mode and tui-active-border-mode.  */
     99 static const char *const tui_border_mode_enums[] = {
    100   "normal",
    101   "standout",
    102   "reverse",
    103   "half",
    104   "half-standout",
    105   "bold",
    106   "bold-standout",
    107   NULL
    108 };
    109 
    110 struct tui_translate
    111 {
    112   const char *name;
    113   int value;
    114 };
    115 
    116 /* Translation table for border-mode variables.
    117    The list of values must be terminated by a NULL.  */
    118 static struct tui_translate tui_border_mode_translate[] = {
    119   { "normal",		A_NORMAL },
    120   { "standout",		A_STANDOUT },
    121   { "reverse",		A_REVERSE },
    122   { "half",		A_DIM },
    123   { "half-standout",	A_DIM | A_STANDOUT },
    124   { "bold",		A_BOLD },
    125   { "bold-standout",	A_BOLD | A_STANDOUT },
    126   { 0, 0 }
    127 };
    128 
    129 /* Translation tables for border-kind (acs excluded), one for vline, hline and
    130    corners (see wborder, border curses operations).  */
    131 static struct tui_translate tui_border_kind_translate_vline[] = {
    132   { "space",    ' ' },
    133   { "ascii",    '|' },
    134   { 0, 0 }
    135 };
    136 
    137 static struct tui_translate tui_border_kind_translate_hline[] = {
    138   { "space",    ' ' },
    139   { "ascii",    '-' },
    140   { 0, 0 }
    141 };
    142 
    143 static struct tui_translate tui_border_kind_translate_corner[] = {
    144   { "space",    ' ' },
    145   { "ascii",    '+' },
    146   { 0, 0 }
    147 };
    148 
    149 
    150 /* Tui configuration variables controlled with set/show command.  */
    151 static const char *tui_active_border_mode = "bold-standout";
    152 static void
    153 show_tui_active_border_mode (struct ui_file *file,
    154 			     int from_tty,
    155 			     struct cmd_list_element *c,
    156 			     const char *value)
    157 {
    158   gdb_printf (file, _("\
    159 The attribute mode to use for the active TUI window border is \"%s\".\n"),
    160 	      value);
    161 }
    162 
    163 static const char *tui_border_mode = "normal";
    164 static void
    165 show_tui_border_mode (struct ui_file *file,
    166 		      int from_tty,
    167 		      struct cmd_list_element *c,
    168 		      const char *value)
    169 {
    170   gdb_printf (file, _("\
    171 The attribute mode to use for the TUI window borders is \"%s\".\n"),
    172 	      value);
    173 }
    174 
    175 static const char *tui_border_kind = "acs";
    176 static void
    177 show_tui_border_kind (struct ui_file *file,
    178 		      int from_tty,
    179 		      struct cmd_list_element *c,
    180 		      const char *value)
    181 {
    182   gdb_printf (file, _("The kind of border for TUI windows is \"%s\".\n"),
    183 	      value);
    184 }
    185 
    186 /* Implementation of the "set/show style tui-current-position" commands.  */
    187 
    188 bool style_tui_current_position = false;
    189 
    190 static void
    191 show_style_tui_current_position (ui_file *file,
    192 				 int from_tty,
    193 				 cmd_list_element *c,
    194 				 const char *value)
    195 {
    196   gdb_printf (file, _("\
    197 Styling the text highlighted by the TUI's current position indicator is %s.\n"),
    198 		    value);
    199 }
    200 
    201 static void
    202 set_style_tui_current_position (const char *ignore, int from_tty,
    203 				cmd_list_element *c)
    204 {
    205   if (TUI_SRC_WIN != nullptr)
    206     TUI_SRC_WIN->refill ();
    207   if (TUI_DISASM_WIN != nullptr)
    208     TUI_DISASM_WIN->refill ();
    209 }
    210 
    211 /* Tui internal configuration variables.  These variables are updated
    212    by tui_update_variables to reflect the tui configuration
    213    variables.  */
    214 chtype tui_border_vline;
    215 chtype tui_border_hline;
    216 chtype tui_border_ulcorner;
    217 chtype tui_border_urcorner;
    218 chtype tui_border_llcorner;
    219 chtype tui_border_lrcorner;
    220 
    221 int tui_border_attrs;
    222 int tui_active_border_attrs;
    223 
    224 /* Identify the item in the translation table, and return the corresponding value.  */
    225 static int
    226 translate (const char *name, struct tui_translate *table)
    227 {
    228   while (table->name)
    229     {
    230       if (name && strcmp (table->name, name) == 0)
    231 	return table->value;
    232       table++;
    233     }
    234 
    235   gdb_assert_not_reached ("");
    236 }
    237 
    238 /* Translate NAME to a value.  If NAME is "acs", use ACS_CHAR.  Otherwise, use
    239    translation table TABLE. */
    240 static int
    241 translate_acs (const char *name, struct tui_translate *table, int acs_char)
    242 {
    243   /* The ACS characters are determined at run time by curses terminal
    244      management.  */
    245   if (strcmp (name, "acs") == 0)
    246     return acs_char;
    247 
    248   return translate (name, table);
    249 }
    250 
    251 /* Update the tui internal configuration according to gdb settings.
    252    Returns 1 if the configuration has changed and the screen should
    253    be redrawn.  */
    254 bool
    255 tui_update_variables ()
    256 {
    257   bool need_redraw = false;
    258   int val;
    259 
    260   val = translate (tui_border_mode, tui_border_mode_translate);
    261   need_redraw |= assign_return_if_changed<int> (tui_border_attrs, val);
    262 
    263   val = translate (tui_active_border_mode, tui_border_mode_translate);
    264   need_redraw |= assign_return_if_changed<int> (tui_active_border_attrs, val);
    265 
    266   /* If one corner changes, all characters are changed.  Only check the first
    267      one.  */
    268   val = translate_acs (tui_border_kind, tui_border_kind_translate_corner,
    269 		       ACS_LRCORNER);
    270   need_redraw |= assign_return_if_changed<chtype> (tui_border_lrcorner, val);
    271 
    272   tui_border_llcorner
    273     = translate_acs (tui_border_kind, tui_border_kind_translate_corner,
    274 		     ACS_LLCORNER);
    275 
    276   tui_border_ulcorner
    277     = translate_acs (tui_border_kind, tui_border_kind_translate_corner,
    278 		     ACS_ULCORNER);
    279 
    280   tui_border_urcorner =
    281     translate_acs (tui_border_kind, tui_border_kind_translate_corner,
    282 		   ACS_URCORNER);
    283 
    284   tui_border_hline
    285     = translate_acs (tui_border_kind, tui_border_kind_translate_hline,
    286 		     ACS_HLINE);
    287 
    288   tui_border_vline
    289     = translate_acs (tui_border_kind, tui_border_kind_translate_vline,
    290 		     ACS_VLINE);
    291 
    292   return need_redraw;
    293 }
    294 
    295 static struct cmd_list_element *tuilist;
    296 
    297 struct cmd_list_element **
    298 tui_get_cmd_list (void)
    299 {
    300   if (tuilist == 0)
    301     add_basic_prefix_cmd ("tui", class_tui,
    302 			  _("Text User Interface commands."),
    303 			  &tuilist, 0, &cmdlist);
    304   return &tuilist;
    305 }
    306 
    307 /* The set_func hook of "set tui ..." commands that affect the window
    308    borders on the TUI display.  */
    309 
    310 static void
    311 tui_set_var_cmd (const char *null_args,
    312 		 int from_tty, struct cmd_list_element *c)
    313 {
    314   if (tui_update_variables () && tui_active)
    315     tui_rehighlight_all ();
    316 }
    317 
    318 
    319 
    321 /* True if TUI resizes should print a message.  This is used by the
    322    test suite.  */
    323 
    324 static bool resize_message;
    325 
    326 static void
    327 show_tui_resize_message (struct ui_file *file, int from_tty,
    328 			 struct cmd_list_element *c, const char *value)
    329 {
    330   gdb_printf (file, _("TUI resize messaging is %s.\n"), value);
    331 }
    332 
    333 
    334 
    336 /* Generic window name completion function.  Complete window name pointed
    337    to by TEXT and WORD.
    338 
    339    If EXCLUDE_CANNOT_FOCUS_P is true, then windows that can't take focus
    340    will be excluded from the completions, otherwise they will be included.
    341 
    342    If INCLUDE_NEXT_PREV_P is true then the special window names 'next' and
    343    'prev' will also be considered as possible completions of the window
    344    name.  This is independent of EXCLUDE_CANNOT_FOCUS_P.  */
    345 
    346 static void
    347 window_name_completer (completion_tracker &tracker,
    348 		       bool include_next_prev_p,
    349 		       bool exclude_cannot_focus_p,
    350 		       const char *text, const char *word)
    351 {
    352   std::vector<const char *> completion_name_vec;
    353 
    354   for (tui_win_info *win_info : all_tui_windows ())
    355     {
    356       const char *completion_name = NULL;
    357 
    358       /* Don't include an invisible window.  */
    359       if (!win_info->is_visible ())
    360 	continue;
    361 
    362       /* If requested, exclude windows that can't be focused.  */
    363       if (exclude_cannot_focus_p && !win_info->can_focus ())
    364 	continue;
    365 
    366       completion_name = win_info->name ();
    367       gdb_assert (completion_name != NULL);
    368       completion_name_vec.push_back (completion_name);
    369     }
    370 
    371   /* If no windows are considered visible then the TUI has not yet been
    372      initialized.  But still "focus src" and "focus cmd" will work because
    373      invoking the focus command will entail initializing the TUI which sets the
    374      default layout to "src".  */
    375   if (completion_name_vec.empty ())
    376     {
    377       completion_name_vec.push_back (SRC_NAME);
    378       completion_name_vec.push_back (CMD_NAME);
    379     }
    380 
    381   if (include_next_prev_p)
    382     {
    383       completion_name_vec.push_back ("next");
    384       completion_name_vec.push_back ("prev");
    385     }
    386 
    387 
    388   completion_name_vec.push_back (NULL);
    389   complete_on_enum (tracker, completion_name_vec.data (), text, word);
    390 }
    391 
    392 /* Complete possible window names to focus on.  TEXT is the complete text
    393    entered so far, WORD is the word currently being completed.  */
    394 
    395 static void
    396 focus_completer (struct cmd_list_element *ignore,
    397 		 completion_tracker &tracker,
    398 		 const char *text, const char *word)
    399 {
    400   window_name_completer (tracker, true, true, text, word);
    401 }
    402 
    403 /* Complete possible window names for winheight command.  TEXT is the
    404    complete text entered so far, WORD is the word currently being
    405    completed.  */
    406 
    407 static void
    408 winheight_completer (struct cmd_list_element *ignore,
    409 		     completion_tracker &tracker,
    410 		     const char *text, const char *word)
    411 {
    412   /* The first word is the window name.  That we can complete.  Subsequent
    413      words can't be completed.  */
    414   if (word != text)
    415     return;
    416 
    417   window_name_completer (tracker, false, false, text, word);
    418 }
    419 
    420 /* Update gdb's knowledge of the terminal size.  */
    421 void
    422 tui_update_gdb_sizes (void)
    423 {
    424   int width, height;
    425 
    426   if (tui_active)
    427     {
    428       width = TUI_CMD_WIN->width;
    429       height = TUI_CMD_WIN->height;
    430     }
    431   else
    432     {
    433       width = tui_term_width ();
    434       height = tui_term_height ();
    435     }
    436 
    437   set_screen_width_and_height (width, height);
    438 }
    439 
    440 
    441 void
    442 tui_win_info::forward_scroll (int num_to_scroll)
    443 {
    444   if (num_to_scroll == 0)
    445     num_to_scroll = height - 3;
    446 
    447   do_scroll_vertical (num_to_scroll);
    448 }
    449 
    450 void
    451 tui_win_info::backward_scroll (int num_to_scroll)
    452 {
    453   if (num_to_scroll == 0)
    454     num_to_scroll = height - 3;
    455 
    456   do_scroll_vertical (-num_to_scroll);
    457 }
    458 
    459 
    460 void
    461 tui_win_info::left_scroll (int num_to_scroll)
    462 {
    463   if (num_to_scroll == 0)
    464     num_to_scroll = 1;
    465 
    466   do_scroll_horizontal (num_to_scroll);
    467 }
    468 
    469 
    470 void
    471 tui_win_info::right_scroll (int num_to_scroll)
    472 {
    473   if (num_to_scroll == 0)
    474     num_to_scroll = 1;
    475 
    476   do_scroll_horizontal (-num_to_scroll);
    477 }
    478 
    479 
    480 void
    481 tui_refresh_all_win (void)
    482 {
    483   clearok (curscr, TRUE);
    484   for (tui_win_info *win_info : all_tui_windows ())
    485     {
    486       if (win_info->is_visible ())
    487 	win_info->refresh_window ();
    488     }
    489 }
    490 
    491 void
    492 tui_rehighlight_all (void)
    493 {
    494   for (tui_win_info *win_info : all_tui_windows ())
    495     win_info->check_and_display_highlight_if_needed ();
    496 }
    497 
    498 /* Resize all the windows based on the terminal size.  This function
    499    gets called from within the readline SIGWINCH handler.  */
    500 void
    501 tui_resize_all (void)
    502 {
    503   int height_diff, width_diff;
    504   int screenheight, screenwidth;
    505 
    506   rl_get_screen_size (&screenheight, &screenwidth);
    507   screenwidth += readline_hidden_cols;
    508 
    509   width_diff = screenwidth - tui_term_width ();
    510   height_diff = screenheight - tui_term_height ();
    511   if (height_diff || width_diff)
    512     {
    513 #ifdef HAVE_RESIZE_TERM
    514       resize_term (screenheight, screenwidth);
    515 #endif
    516       /* Turn keypad off while we resize.  */
    517       keypad (TUI_CMD_WIN->handle.get (), FALSE);
    518       tui_update_gdb_sizes ();
    519       tui_set_term_height_to (screenheight);
    520       tui_set_term_width_to (screenwidth);
    521 
    522       /* erase + clearok are used instead of a straightforward clear as
    523 	 AIX 5.3 does not define clear.  */
    524       erase ();
    525       clearok (curscr, TRUE);
    526       /* Apply the current layout.  The 'false' here allows the command
    527 	 window to resize proportionately with containing terminal, rather
    528 	 than maintaining a fixed size.  */
    529       tui_apply_current_layout (false); /* Turn keypad back on.  */
    530       keypad (TUI_CMD_WIN->handle.get (), TRUE);
    531     }
    532 }
    533 
    534 #ifdef SIGWINCH
    535 /* Token for use by TUI's asynchronous SIGWINCH handler.  */
    536 static struct async_signal_handler *tui_sigwinch_token;
    537 
    538 /* TUI's SIGWINCH signal handler.  */
    539 static void
    540 tui_sigwinch_handler (int signal)
    541 {
    542   mark_async_signal_handler (tui_sigwinch_token);
    543   tui_set_win_resized_to (true);
    544 }
    545 
    546 /* Callback for asynchronously resizing TUI following a SIGWINCH signal.  */
    547 static void
    548 tui_async_resize_screen (gdb_client_data arg)
    549 {
    550   rl_resize_terminal ();
    551 
    552   if (!tui_active)
    553     {
    554       int screen_height, screen_width;
    555 
    556       rl_get_screen_size (&screen_height, &screen_width);
    557       screen_width += readline_hidden_cols;
    558       set_screen_width_and_height (screen_width, screen_height);
    559 
    560       /* win_resized is left set so that the next call to tui_enable()
    561 	 resizes the TUI windows.  */
    562     }
    563   else
    564     {
    565       tui_set_win_resized_to (false);
    566       tui_resize_all ();
    567       tui_refresh_all_win ();
    568       tui_update_gdb_sizes ();
    569       if (resize_message)
    570 	{
    571 	  static int count;
    572 	  printf_unfiltered ("@@ resize done %d, size = %dx%d\n", count,
    573 			     tui_term_width (), tui_term_height ());
    574 	  ++count;
    575 	}
    576       tui_redisplay_readline ();
    577     }
    578 }
    579 #endif
    580 
    581 /* Initialize TUI's SIGWINCH signal handler.  Note that the handler is not
    582    uninstalled when we exit TUI, so the handler should not assume that TUI is
    583    always active.  */
    584 void
    585 tui_initialize_win (void)
    586 {
    587 #ifdef SIGWINCH
    588   tui_sigwinch_token
    589     = create_async_signal_handler (tui_async_resize_screen, NULL,
    590 				   "tui-sigwinch");
    591 
    592   {
    593 #ifdef HAVE_SIGACTION
    594     struct sigaction old_winch;
    595 
    596     memset (&old_winch, 0, sizeof (old_winch));
    597     old_winch.sa_handler = &tui_sigwinch_handler;
    598 #ifdef SA_RESTART
    599     old_winch.sa_flags = SA_RESTART;
    600 #endif
    601     sigaction (SIGWINCH, &old_winch, NULL);
    602 #else
    603     signal (SIGWINCH, &tui_sigwinch_handler);
    604 #endif
    605   }
    606 #endif
    607 }
    608 
    609 
    610 static void
    611 tui_scroll_forward_command (const char *arg, int from_tty)
    612 {
    613   int num_to_scroll = 1;
    614   struct tui_win_info *win_to_scroll;
    615 
    616   /* Make sure the curses mode is enabled.  */
    617   tui_enable ();
    618   if (arg == NULL)
    619     parse_scrolling_args (arg, &win_to_scroll, NULL);
    620   else
    621     parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
    622   win_to_scroll->forward_scroll (num_to_scroll);
    623 }
    624 
    625 
    626 static void
    627 tui_scroll_backward_command (const char *arg, int from_tty)
    628 {
    629   int num_to_scroll = 1;
    630   struct tui_win_info *win_to_scroll;
    631 
    632   /* Make sure the curses mode is enabled.  */
    633   tui_enable ();
    634   if (arg == NULL)
    635     parse_scrolling_args (arg, &win_to_scroll, NULL);
    636   else
    637     parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
    638   win_to_scroll->backward_scroll (num_to_scroll);
    639 }
    640 
    641 
    642 static void
    643 tui_scroll_left_command (const char *arg, int from_tty)
    644 {
    645   int num_to_scroll;
    646   struct tui_win_info *win_to_scroll;
    647 
    648   /* Make sure the curses mode is enabled.  */
    649   tui_enable ();
    650   parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
    651   win_to_scroll->left_scroll (num_to_scroll);
    652 }
    653 
    654 
    655 static void
    656 tui_scroll_right_command (const char *arg, int from_tty)
    657 {
    658   int num_to_scroll;
    659   struct tui_win_info *win_to_scroll;
    660 
    661   /* Make sure the curses mode is enabled.  */
    662   tui_enable ();
    663   parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
    664   win_to_scroll->right_scroll (num_to_scroll);
    665 }
    666 
    667 
    668 /* Answer the window represented by name.  */
    669 static struct tui_win_info *
    670 tui_partial_win_by_name (std::string_view name)
    671 {
    672   struct tui_win_info *best = nullptr;
    673 
    674   for (tui_win_info *item : all_tui_windows ())
    675     {
    676       const char *cur_name = item->name ();
    677 
    678       if (name == cur_name)
    679 	return item;
    680       if (startswith (cur_name, name))
    681 	{
    682 	  if (best != nullptr)
    683 	    error (_("Window name \"%*s\" is ambiguous"),
    684 		   (int) name.size (), name.data ());
    685 	  best = item;
    686 	}
    687     }
    688 
    689   return best;
    690 }
    691 
    692 /* Set focus to the window named by 'arg'.  */
    693 static void
    694 tui_set_focus_command (const char *arg, int from_tty)
    695 {
    696   tui_enable ();
    697 
    698   if (arg == NULL)
    699     error_no_arg (_("name of window to focus"));
    700 
    701   struct tui_win_info *win_info = NULL;
    702 
    703   if (startswith ("next", arg))
    704     win_info = tui_next_win (tui_win_with_focus ());
    705   else if (startswith ("prev", arg))
    706     win_info = tui_prev_win (tui_win_with_focus ());
    707   else
    708     win_info = tui_partial_win_by_name (arg);
    709 
    710   if (win_info == nullptr)
    711     {
    712       /* When WIN_INFO is nullptr this can either mean that the window name
    713 	 is unknown to GDB, or that the window is not in the current
    714 	 layout.  To try and help the user, give a different error
    715 	 depending on which of these is the case.  */
    716       std::string matching_window_name;
    717       bool is_ambiguous = false;
    718 
    719       for (const std::string &name : all_known_window_names ())
    720 	{
    721 	  /* Look through all windows in the current layout, if the window
    722 	     is in the current layout then we're not interested is it.  */
    723 	  for (tui_win_info *item : all_tui_windows ())
    724 	    if (item->name () == name)
    725 	      continue;
    726 
    727 	  if (startswith (name, arg))
    728 	    {
    729 	      if (matching_window_name.empty ())
    730 		matching_window_name = name;
    731 	      else
    732 		is_ambiguous = true;
    733 	    }
    734 	};
    735 
    736       if (!matching_window_name.empty ())
    737 	{
    738 	  if (is_ambiguous)
    739 	    error (_("No windows matching \"%s\" in the current layout"),
    740 		   arg);
    741 	  else
    742 	    error (_("Window \"%s\" is not in the current layout"),
    743 		   matching_window_name.c_str ());
    744 	}
    745       else
    746 	error (_("Unrecognized window name \"%s\""), arg);
    747     }
    748 
    749   /* If a window is part of the current layout then it will have a
    750      tui_win_info associated with it and be visible, otherwise, there will
    751      be no tui_win_info and the above error will have been raised.  */
    752   gdb_assert (win_info->is_visible ());
    753 
    754   if (!win_info->can_focus ())
    755     error (_("Window \"%s\" cannot be focused"), arg);
    756 
    757   tui_set_win_focus_to (win_info);
    758   gdb_printf (_("Focus set to %s window.\n"),
    759 	      tui_win_with_focus ()->name ());
    760 }
    761 
    762 static void
    763 tui_all_windows_info (const char *arg, int from_tty)
    764 {
    765   if (!tui_active)
    766     {
    767       gdb_printf (_("The TUI is not active.\n"));
    768       return;
    769     }
    770 
    771   struct tui_win_info *win_with_focus = tui_win_with_focus ();
    772   struct ui_out *uiout = current_uiout;
    773 
    774   ui_out_emit_table table_emitter (uiout, 4, -1, "tui-windows");
    775   uiout->table_header (10, ui_left, "name", "Name");
    776   uiout->table_header (5, ui_right, "lines", "Lines");
    777   uiout->table_header (7, ui_right, "columns", "Columns");
    778   uiout->table_header (10, ui_left, "focus", "Focus");
    779   uiout->table_body ();
    780 
    781   for (tui_win_info *win_info : all_tui_windows ())
    782     if (win_info->is_visible ())
    783       {
    784 	ui_out_emit_tuple tuple_emitter (uiout, nullptr);
    785 
    786 	uiout->field_string ("name", win_info->name ());
    787 	uiout->field_signed ("lines", win_info->height);
    788 	uiout->field_signed ("columns", win_info->width);
    789 	if (win_with_focus == win_info)
    790 	  uiout->field_string ("focus", _("(has focus)"));
    791 	else
    792 	  uiout->field_skip ("focus");
    793 	uiout->text ("\n");
    794       }
    795 }
    796 
    797 
    798 static void
    799 tui_refresh_all_command (const char *arg, int from_tty)
    800 {
    801   /* Make sure the curses mode is enabled.  */
    802   tui_enable ();
    803 
    804   tui_refresh_all_win ();
    805 }
    806 
    807 #define DEFAULT_TAB_LEN         8
    808 
    809 /* The tab width that should be used by the TUI.  */
    810 
    811 unsigned int tui_tab_width = DEFAULT_TAB_LEN;
    812 
    813 /* The tab width as set by the user.  */
    814 
    815 static unsigned int internal_tab_width = DEFAULT_TAB_LEN;
    816 
    817 /* After the tab width is set, call this to update the relevant
    818    windows.  */
    819 
    820 static void
    821 update_tab_width ()
    822 {
    823   for (tui_win_info *win_info : all_tui_windows ())
    824     {
    825       if (win_info->is_visible ())
    826 	win_info->update_tab_width ();
    827     }
    828 }
    829 
    830 /* Callback for "set tui tab-width".  */
    831 
    832 static void
    833 tui_set_tab_width (const char *ignore,
    834 		   int from_tty, struct cmd_list_element *c)
    835 {
    836   if (internal_tab_width == 0)
    837     {
    838       internal_tab_width = tui_tab_width;
    839       error (_("Tab width must not be 0"));
    840     }
    841 
    842   tui_tab_width = internal_tab_width;
    843   update_tab_width ();
    844 }
    845 
    846 /* Callback for "show tui tab-width".  */
    847 
    848 static void
    849 tui_show_tab_width (struct ui_file *file, int from_tty,
    850 		    struct cmd_list_element *c, const char *value)
    851 {
    852   gdb_printf (file, _("TUI tab width is %s spaces.\n"), value);
    853 
    854 }
    855 
    856 /* See tui-win.h.  */
    857 
    858 bool compact_source = false;
    859 
    860 /* Callback for "set tui compact-source".  */
    861 
    862 static void
    863 tui_set_compact_source (const char *ignore, int from_tty,
    864 			struct cmd_list_element *c)
    865 {
    866   if (TUI_SRC_WIN != nullptr)
    867     TUI_SRC_WIN->refill ();
    868 }
    869 
    870 /* Callback for "show tui compact-source".  */
    871 
    872 static void
    873 tui_show_compact_source (struct ui_file *file, int from_tty,
    874 			 struct cmd_list_element *c, const char *value)
    875 {
    876   gdb_printf (file, _("TUI source window compactness is %s.\n"), value);
    877 }
    878 
    879 bool tui_enable_mouse = true;
    880 
    881 /* Implement 'show tui mouse-events'.  */
    882 
    883 static void
    884 show_tui_mouse_events (struct ui_file *file, int from_tty,
    885 		       struct cmd_list_element *c, const char *value)
    886 {
    887   gdb_printf (file, _("TUI mouse events are %s.\n"), value);
    888 }
    889 
    890 /* Set the tab width of the specified window.  */
    891 static void
    892 tui_set_tab_width_command (const char *arg, int from_tty)
    893 {
    894   /* Make sure the curses mode is enabled.  */
    895   tui_enable ();
    896   if (arg != NULL)
    897     {
    898       int ts;
    899 
    900       ts = atoi (arg);
    901       if (ts <= 0)
    902 	warning (_("Tab widths greater than 0 must be specified."));
    903       else
    904 	{
    905 	  internal_tab_width = ts;
    906 	  tui_tab_width = ts;
    907 
    908 	  update_tab_width ();
    909 	}
    910     }
    911 }
    912 
    913 /* Helper function for the user commands to adjust a window's width or
    914    height.  The ARG string contains the command line arguments from the
    915    user, which should give the name of a window, and how to adjust the
    916    size.
    917 
    918    When SET_WIDTH_P is true the width of the window is adjusted based on
    919    ARG, and when SET_WIDTH_P is false, the height of the window is adjusted
    920    based on ARG.
    921 
    922    On invalid input, or if the size can't be adjusted as requested, then an
    923    error is thrown, otherwise, the window sizes are adjusted, and the
    924    windows redrawn.  */
    925 
    926 static void
    927 tui_set_win_size (const char *arg, bool set_width_p)
    928 {
    929   /* Make sure the curses mode is enabled.  */
    930   tui_enable ();
    931   if (arg == NULL)
    932     error_no_arg (_("name of window"));
    933 
    934   const char *buf = arg;
    935   const char *buf_ptr = buf;
    936   int new_size;
    937   struct tui_win_info *win_info;
    938 
    939   buf_ptr = skip_to_space (buf_ptr);
    940 
    941   /* Validate the window name.  */
    942   std::string_view wname (buf, buf_ptr - buf);
    943   win_info = tui_partial_win_by_name (wname);
    944 
    945   if (win_info == NULL)
    946     error (_("Unrecognized window name \"%s\""), arg);
    947   if (!win_info->is_visible ())
    948     error (_("Window \"%s\" is not visible"), arg);
    949 
    950   /* Process the size.  */
    951   buf_ptr = skip_spaces (buf_ptr);
    952 
    953   if (*buf_ptr != '\0')
    954     {
    955       bool negate = false;
    956       bool fixed_size = true;
    957       int input_no;;
    958 
    959       if (*buf_ptr == '+' || *buf_ptr == '-')
    960 	{
    961 	  if (*buf_ptr == '-')
    962 	    negate = true;
    963 	  fixed_size = false;
    964 	  buf_ptr++;
    965 	}
    966       input_no = atoi (buf_ptr);
    967       if (input_no > 0)
    968 	{
    969 	  if (negate)
    970 	    input_no *= (-1);
    971 	  if (fixed_size)
    972 	    new_size = input_no;
    973 	  else
    974 	    {
    975 	      int curr_size;
    976 	      if (set_width_p)
    977 		curr_size = win_info->width;
    978 	      else
    979 		curr_size = win_info->height;
    980 	      new_size = curr_size + input_no;
    981 	    }
    982 
    983 	  /* Now change the window's height, and adjust
    984 	     all other windows around it.  */
    985 	  if (set_width_p)
    986 	    tui_adjust_window_width (win_info, new_size);
    987 	  else
    988 	    tui_adjust_window_height (win_info, new_size);
    989 	  tui_update_gdb_sizes ();
    990 	}
    991       else
    992 	{
    993 	  if (set_width_p)
    994 	    error (_("Invalid window width specified"));
    995 	  else
    996 	    error (_("Invalid window height specified"));
    997 	}
    998     }
    999 }
   1000 
   1001 /* Implement the 'tui window height' command (alias 'winheight').  */
   1002 
   1003 static void
   1004 tui_set_win_height_command (const char *arg, int from_tty)
   1005 {
   1006   /* Pass false as the final argument to set the height.  */
   1007   tui_set_win_size (arg, false);
   1008 }
   1009 
   1010 /* Implement the 'tui window width' command (alias 'winwidth').  */
   1011 
   1012 static void
   1013 tui_set_win_width_command (const char *arg, int from_tty)
   1014 {
   1015   /* Pass true as the final argument to set the width.  */
   1016   tui_set_win_size (arg, true);
   1017 }
   1018 
   1019 /* See tui-data.h.  */
   1020 
   1021 int
   1022 tui_win_info::max_height () const
   1023 {
   1024   return tui_term_height ();
   1025 }
   1026 
   1027 /* See tui-data.h.  */
   1028 
   1029 int
   1030 tui_win_info::max_width () const
   1031 {
   1032   return tui_term_width ();
   1033 }
   1034 
   1035 static void
   1036 parse_scrolling_args (const char *arg,
   1037 		      struct tui_win_info **win_to_scroll,
   1038 		      int *num_to_scroll)
   1039 {
   1040   if (num_to_scroll)
   1041     *num_to_scroll = 0;
   1042   *win_to_scroll = tui_win_with_focus ();
   1043 
   1044   /* First set up the default window to scroll, in case there is no
   1045      window name arg.  */
   1046   if (arg != NULL)
   1047     {
   1048       char *buf_ptr;
   1049 
   1050       /* Process the number of lines to scroll.  */
   1051       std::string copy = arg;
   1052       buf_ptr = &copy[0];
   1053       if (isdigit (*buf_ptr))
   1054 	{
   1055 	  char *num_str;
   1056 
   1057 	  num_str = buf_ptr;
   1058 	  buf_ptr = strchr (buf_ptr, ' ');
   1059 	  if (buf_ptr != NULL)
   1060 	    {
   1061 	      *buf_ptr = '\0';
   1062 	      if (num_to_scroll)
   1063 		*num_to_scroll = atoi (num_str);
   1064 	      buf_ptr++;
   1065 	    }
   1066 	  else if (num_to_scroll)
   1067 	    *num_to_scroll = atoi (num_str);
   1068 	}
   1069 
   1070       /* Process the window name if one is specified.  */
   1071       if (buf_ptr != NULL)
   1072 	{
   1073 	  const char *wname;
   1074 
   1075 	  wname = skip_spaces (buf_ptr);
   1076 
   1077 	  if (*wname != '\0')
   1078 	    {
   1079 	      *win_to_scroll = tui_partial_win_by_name (wname);
   1080 
   1081 	      if (*win_to_scroll == NULL)
   1082 		error (_("Unrecognized window `%s'"), wname);
   1083 	      if (!(*win_to_scroll)->is_visible ())
   1084 		error (_("Window is not visible"));
   1085 	      else if (*win_to_scroll == TUI_CMD_WIN)
   1086 		*win_to_scroll = *(tui_source_windows ().begin ());
   1087 	    }
   1088 	}
   1089     }
   1090 }
   1091 
   1092 /* The list of 'tui window' sub-commands.  */
   1093 
   1094 static cmd_list_element *tui_window_cmds = nullptr;
   1095 
   1096 /* Called to implement 'tui window'.  */
   1097 
   1098 static void
   1099 tui_window_command (const char *args, int from_tty)
   1100 {
   1101   help_list (tui_window_cmds, "tui window ", all_commands, gdb_stdout);
   1102 }
   1103 
   1104 /* See tui-win.h.  */
   1105 
   1106 bool tui_left_margin_verbose = false;
   1107 
   1108 /* Function to initialize gdb commands, for tui window
   1109    manipulation.  */
   1110 
   1111 void _initialize_tui_win ();
   1112 void
   1113 _initialize_tui_win ()
   1114 {
   1115   static struct cmd_list_element *tui_setlist;
   1116   static struct cmd_list_element *tui_showlist;
   1117 
   1118   /* Define the classes of commands.
   1119      They will appear in the help list in the reverse of this order.  */
   1120   add_setshow_prefix_cmd ("tui", class_tui,
   1121 			  _("TUI configuration variables."),
   1122 			  _("TUI configuration variables."),
   1123 			  &tui_setlist, &tui_showlist,
   1124 			  &setlist, &showlist);
   1125 
   1126   cmd_list_element *refresh_cmd
   1127     = add_cmd ("refresh", class_tui, tui_refresh_all_command,
   1128 	       _("Refresh the terminal display."),
   1129 	       tui_get_cmd_list ());
   1130   add_com_alias ("refresh", refresh_cmd, class_tui, 0);
   1131 
   1132   cmd_list_element *tabset_cmd
   1133     = add_com ("tabset", class_tui, tui_set_tab_width_command, _("\
   1134 Set the width (in characters) of tab stops.\n\
   1135 Usage: tabset N"));
   1136   deprecate_cmd (tabset_cmd, "set tui tab-width");
   1137 
   1138   /* Setup the 'tui window' list of command.  */
   1139   add_prefix_cmd ("window", class_tui, tui_window_command,
   1140 		  _("Text User Interface window commands."),
   1141 		  &tui_window_cmds, 1, tui_get_cmd_list ());
   1142 
   1143   cmd_list_element *winheight_cmd
   1144     = add_cmd ("height", class_tui, tui_set_win_height_command, _("\
   1145 Set or modify the height of a specified window.\n\
   1146 Usage: tui window height WINDOW-NAME [+ | -] NUM-LINES\n\
   1147 Use \"info win\" to see the names of the windows currently being displayed."),
   1148 	       &tui_window_cmds);
   1149   add_com_alias ("winheight", winheight_cmd, class_tui, 0);
   1150   add_com_alias ("wh", winheight_cmd, class_tui, 0);
   1151   set_cmd_completer (winheight_cmd, winheight_completer);
   1152 
   1153   cmd_list_element *winwidth_cmd
   1154     = add_cmd ("width", class_tui, tui_set_win_width_command, _("\
   1155 Set or modify the width of a specified window.\n\
   1156 Usage: tui window width WINDOW-NAME [+ | -] NUM-LINES\n\
   1157 Use \"info win\" to see the names of the windows currently being displayed."),
   1158 	       &tui_window_cmds);
   1159   add_com_alias ("winwidth", winwidth_cmd, class_tui, 0);
   1160   set_cmd_completer (winwidth_cmd, winheight_completer);
   1161 
   1162   add_info ("win", tui_all_windows_info,
   1163 	    _("List of all displayed windows.\n\
   1164 Usage: info win"));
   1165   cmd_list_element *focus_cmd
   1166     = add_cmd ("focus", class_tui, tui_set_focus_command, _("\
   1167 Set focus to named window or next/prev window.\n\
   1168 Usage: tui focus [WINDOW-NAME | next | prev]\n\
   1169 Use \"info win\" to see the names of the windows currently being displayed."),
   1170 	       tui_get_cmd_list ());
   1171   add_com_alias ("focus", focus_cmd, class_tui, 0);
   1172   add_com_alias ("fs", focus_cmd, class_tui, 0);
   1173   set_cmd_completer (focus_cmd, focus_completer);
   1174   add_com ("+", class_tui, tui_scroll_forward_command, _("\
   1175 Scroll window forward.\n\
   1176 Usage: + [N] [WIN]\n\
   1177 Scroll window WIN N lines forwards.  Both WIN and N are optional, N\n\
   1178 defaults to 1, and WIN defaults to the currently focused window."));
   1179   add_com ("-", class_tui, tui_scroll_backward_command, _("\
   1180 Scroll window backward.\n\
   1181 Usage: - [N] [WIN]\n\
   1182 Scroll window WIN N lines backwards.  Both WIN and N are optional, N\n\
   1183 defaults to 1, and WIN defaults to the currently focused window."));
   1184   add_com ("<", class_tui, tui_scroll_left_command, _("\
   1185 Scroll window text to the left.\n\
   1186 Usage: < [N] [WIN]\n\
   1187 Scroll window WIN N characters left.  Both WIN and N are optional, N\n\
   1188 defaults to 1, and WIN defaults to the currently focused window."));
   1189   add_com (">", class_tui, tui_scroll_right_command, _("\
   1190 Scroll window text to the right.\n\
   1191 Usage: > [N] [WIN]\n\
   1192 Scroll window WIN N characters right.  Both WIN and N are optional, N\n\
   1193 defaults to 1, and WIN defaults to the currently focused window."));
   1194 
   1195   /* Define the tui control variables.  */
   1196   add_setshow_enum_cmd ("border-kind", no_class, tui_border_kind_enums,
   1197 			&tui_border_kind, _("\
   1198 Set the kind of border for TUI windows."), _("\
   1199 Show the kind of border for TUI windows."), _("\
   1200 This variable controls the border of TUI windows:\n\
   1201    space           use a white space\n\
   1202    ascii           use ascii characters + - | for the border\n\
   1203    acs             use the Alternate Character Set"),
   1204 			tui_set_var_cmd,
   1205 			show_tui_border_kind,
   1206 			&tui_setlist, &tui_showlist);
   1207 
   1208   const std::string help_attribute_mode (_("\
   1209    normal          normal display\n\
   1210    standout        use highlight mode of terminal\n\
   1211    reverse         use reverse video mode\n\
   1212    half            use half bright\n\
   1213    half-standout   use half bright and standout mode\n\
   1214    bold            use extra bright or bold\n\
   1215    bold-standout   use extra bright or bold with standout mode"));
   1216 
   1217   const std::string help_tui_border_mode
   1218     = (_("\
   1219 This variable controls the attributes to use for the window borders:\n")
   1220        + help_attribute_mode);
   1221 
   1222   add_setshow_enum_cmd ("border-mode", no_class, tui_border_mode_enums,
   1223 			&tui_border_mode, _("\
   1224 Set the attribute mode to use for the TUI window borders."), _("\
   1225 Show the attribute mode to use for the TUI window borders."),
   1226 			help_tui_border_mode.c_str (),
   1227 			tui_set_var_cmd,
   1228 			show_tui_border_mode,
   1229 			&tui_setlist, &tui_showlist);
   1230 
   1231   const std::string help_tui_active_border_mode
   1232     = (_("\
   1233 This variable controls the attributes to use for the active window borders:\n")
   1234        + help_attribute_mode);
   1235 
   1236   add_setshow_enum_cmd ("active-border-mode", no_class, tui_border_mode_enums,
   1237 			&tui_active_border_mode, _("\
   1238 Set the attribute mode to use for the active TUI window border."), _("\
   1239 Show the attribute mode to use for the active TUI window border."),
   1240 			help_tui_active_border_mode.c_str (),
   1241 			tui_set_var_cmd,
   1242 			show_tui_active_border_mode,
   1243 			&tui_setlist, &tui_showlist);
   1244 
   1245   add_setshow_zuinteger_cmd ("tab-width", no_class,
   1246 			     &internal_tab_width, _("\
   1247 Set the tab width, in characters, for the TUI."), _("\
   1248 Show the tab width, in characters, for the TUI."), _("\
   1249 This variable controls how many spaces are used to display a tab character."),
   1250 			     tui_set_tab_width, tui_show_tab_width,
   1251 			     &tui_setlist, &tui_showlist);
   1252 
   1253   add_setshow_boolean_cmd ("tui-resize-message", class_maintenance,
   1254 			   &resize_message, _("\
   1255 Set TUI resize messaging."), _("\
   1256 Show TUI resize messaging."), _("\
   1257 When enabled GDB will print a message when the terminal is resized."),
   1258 			   nullptr,
   1259 			   show_tui_resize_message,
   1260 			   &maintenance_set_cmdlist,
   1261 			   &maintenance_show_cmdlist);
   1262 
   1263   add_setshow_boolean_cmd ("compact-source", class_tui,
   1264 			   &compact_source, _("\
   1265 Set whether the TUI source window is compact."), _("\
   1266 Show whether the TUI source window is compact."), _("\
   1267 This variable controls whether the TUI source window is shown\n\
   1268 in a compact form.  The compact form uses less horizontal space."),
   1269 			   tui_set_compact_source, tui_show_compact_source,
   1270 			   &tui_setlist, &tui_showlist);
   1271 
   1272   add_setshow_boolean_cmd ("mouse-events", class_tui,
   1273 			   &tui_enable_mouse, _("\
   1274 Set whether TUI mode handles mouse clicks."), _("\
   1275 Show whether TUI mode handles mouse clicks."), _("\
   1276 When on (default), mouse clicks control the TUI and can be accessed by Python\n\
   1277 extensions.  When off, mouse clicks are handled by the terminal, enabling\n\
   1278 terminal-native text selection."),
   1279 			   nullptr,
   1280 			   show_tui_mouse_events,
   1281 			   &tui_setlist, &tui_showlist);
   1282 
   1283   add_setshow_boolean_cmd ("tui-current-position", class_maintenance,
   1284 			   &style_tui_current_position, _("\
   1285 Set whether to style text highlighted by the TUI's current position indicator."),
   1286 			   _("\
   1287 Show whether to style text highlighted by the TUI's current position indicator."),
   1288 			   _("\
   1289 When enabled, the source and assembly code highlighted by the TUI's current\n\
   1290 position indicator is styled."),
   1291 			   set_style_tui_current_position,
   1292 			   show_style_tui_current_position,
   1293 			   &style_set_list,
   1294 			   &style_show_list);
   1295 
   1296   add_setshow_boolean_cmd ("tui-left-margin-verbose", class_maintenance,
   1297 			   &tui_left_margin_verbose, _("\
   1298 Set whether the left margin should use '_' and '0' instead of spaces."),
   1299 			   _("\
   1300 Show whether the left margin should use '_' and '0' instead of spaces."),
   1301 			   _("\
   1302 When enabled, the left margin will use '_' and '0' instead of spaces."),
   1303 			   nullptr,
   1304 			   nullptr,
   1305 			   &maintenance_set_cmdlist,
   1306 			   &maintenance_show_cmdlist);
   1307 
   1308   tui_border_style.changed.attach (tui_rehighlight_all, "tui-win");
   1309   tui_active_border_style.changed.attach (tui_rehighlight_all, "tui-win");
   1310 }
   1311