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