Home | History | Annotate | Line # | Download | only in tui
tui-win.c revision 1.9
      1 /* TUI window generic functions.
      2 
      3    Copyright (C) 1998-2020 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   fprintf_filtered (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   fprintf_filtered (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   fprintf_filtered (file, _("The kind of border for TUI windows is \"%s\".\n"),
    218 		    value);
    219 }
    220 
    221 
    222 /* Tui internal configuration variables.  These variables are updated
    223    by tui_update_variables to reflect the tui configuration
    224    variables.  */
    225 chtype tui_border_vline;
    226 chtype tui_border_hline;
    227 chtype tui_border_ulcorner;
    228 chtype tui_border_urcorner;
    229 chtype tui_border_llcorner;
    230 chtype tui_border_lrcorner;
    231 
    232 int tui_border_attrs;
    233 int tui_active_border_attrs;
    234 
    235 /* Identify the item in the translation table.
    236    When the item is not recognized, use the default entry.  */
    237 static struct tui_translate *
    238 translate (const char *name, struct tui_translate *table)
    239 {
    240   while (table->name)
    241     {
    242       if (name && strcmp (table->name, name) == 0)
    243         return table;
    244       table++;
    245     }
    246 
    247   /* Not found, return default entry.  */
    248   table++;
    249   return table;
    250 }
    251 
    252 /* Update the tui internal configuration according to gdb settings.
    253    Returns 1 if the configuration has changed and the screen should
    254    be redrawn.  */
    255 bool
    256 tui_update_variables ()
    257 {
    258   bool need_redraw = false;
    259   struct tui_translate *entry;
    260 
    261   entry = translate (tui_border_mode, tui_border_mode_translate);
    262   if (tui_border_attrs != entry->value)
    263     {
    264       tui_border_attrs = entry->value;
    265       need_redraw = true;
    266     }
    267   entry = translate (tui_active_border_mode, tui_border_mode_translate);
    268   if (tui_active_border_attrs != entry->value)
    269     {
    270       tui_active_border_attrs = entry->value;
    271       need_redraw = true;
    272     }
    273 
    274   /* If one corner changes, all characters are changed.
    275      Only check the first one.  The ACS characters are determined at
    276      run time by curses terminal management.  */
    277   entry = translate (tui_border_kind, tui_border_kind_translate_lrcorner);
    278   if (tui_border_lrcorner != (chtype) entry->value)
    279     {
    280       tui_border_lrcorner = (entry->value < 0) ? ACS_LRCORNER : entry->value;
    281       need_redraw = true;
    282     }
    283   entry = translate (tui_border_kind, tui_border_kind_translate_llcorner);
    284   tui_border_llcorner = (entry->value < 0) ? ACS_LLCORNER : entry->value;
    285 
    286   entry = translate (tui_border_kind, tui_border_kind_translate_ulcorner);
    287   tui_border_ulcorner = (entry->value < 0) ? ACS_ULCORNER : entry->value;
    288 
    289   entry = translate (tui_border_kind, tui_border_kind_translate_urcorner);
    290   tui_border_urcorner = (entry->value < 0) ? ACS_URCORNER : entry->value;
    291 
    292   entry = translate (tui_border_kind, tui_border_kind_translate_hline);
    293   tui_border_hline = (entry->value < 0) ? ACS_HLINE : entry->value;
    294 
    295   entry = translate (tui_border_kind, tui_border_kind_translate_vline);
    296   tui_border_vline = (entry->value < 0) ? ACS_VLINE : entry->value;
    297 
    298   return need_redraw;
    299 }
    300 
    301 static struct cmd_list_element *tuilist;
    302 
    303 struct cmd_list_element **
    304 tui_get_cmd_list (void)
    305 {
    306   if (tuilist == 0)
    307     add_basic_prefix_cmd ("tui", class_tui,
    308 			  _("Text User Interface commands."),
    309 			  &tuilist, "tui ", 0, &cmdlist);
    310   return &tuilist;
    311 }
    312 
    313 /* The set_func hook of "set tui ..." commands that affect the window
    314    borders on the TUI display.  */
    315 
    316 static void
    317 tui_set_var_cmd (const char *null_args,
    318 		 int from_tty, struct cmd_list_element *c)
    319 {
    320   if (tui_update_variables () && tui_active)
    321     tui_rehighlight_all ();
    322 }
    323 
    324 
    325 
    327 /* True if TUI resizes should print a message.  This is used by the
    328    test suite.  */
    329 
    330 static bool resize_message;
    331 
    332 static void
    333 show_tui_resize_message (struct ui_file *file, int from_tty,
    334 			 struct cmd_list_element *c, const char *value)
    335 {
    336   fprintf_filtered (file, _("TUI resize messaging is %s.\n"), value);
    337 }
    338 
    339 
    340 
    342 /* Generic window name completion function.  Complete window name pointed
    343    to by TEXT and WORD.  If INCLUDE_NEXT_PREV_P is true then the special
    344    window names 'next' and 'prev' will also be considered as possible
    345    completions of the window name.  */
    346 
    347 static void
    348 window_name_completer (completion_tracker &tracker,
    349 		       int include_next_prev_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       /* We can't focus on an invisible window.  */
    359       if (!win_info->is_visible ())
    360 	continue;
    361 
    362       completion_name = win_info->name ();
    363       gdb_assert (completion_name != NULL);
    364       completion_name_vec.push_back (completion_name);
    365     }
    366 
    367   /* If no windows are considered visible then the TUI has not yet been
    368      initialized.  But still "focus src" and "focus cmd" will work because
    369      invoking the focus command will entail initializing the TUI which sets the
    370      default layout to "src".  */
    371   if (completion_name_vec.empty ())
    372     {
    373       completion_name_vec.push_back (SRC_NAME);
    374       completion_name_vec.push_back (CMD_NAME);
    375     }
    376 
    377   if (include_next_prev_p)
    378     {
    379       completion_name_vec.push_back ("next");
    380       completion_name_vec.push_back ("prev");
    381     }
    382 
    383 
    384   completion_name_vec.push_back (NULL);
    385   complete_on_enum (tracker, completion_name_vec.data (), text, word);
    386 }
    387 
    388 /* Complete possible window names to focus on.  TEXT is the complete text
    389    entered so far, WORD is the word currently being completed.  */
    390 
    391 static void
    392 focus_completer (struct cmd_list_element *ignore,
    393 		 completion_tracker &tracker,
    394 		 const char *text, const char *word)
    395 {
    396   window_name_completer (tracker, 1, text, word);
    397 }
    398 
    399 /* Complete possible window names for winheight command.  TEXT is the
    400    complete text entered so far, WORD is the word currently being
    401    completed.  */
    402 
    403 static void
    404 winheight_completer (struct cmd_list_element *ignore,
    405 		     completion_tracker &tracker,
    406 		     const char *text, const char *word)
    407 {
    408   /* The first word is the window name.  That we can complete.  Subsequent
    409      words can't be completed.  */
    410   if (word != text)
    411     return;
    412 
    413   window_name_completer (tracker, 0, text, word);
    414 }
    415 
    416 /* Update gdb's knowledge of the terminal size.  */
    417 void
    418 tui_update_gdb_sizes (void)
    419 {
    420   int width, height;
    421 
    422   if (tui_active)
    423     {
    424       width = TUI_CMD_WIN->width;
    425       height = TUI_CMD_WIN->height;
    426     }
    427   else
    428     {
    429       width = tui_term_width ();
    430       height = tui_term_height ();
    431     }
    432 
    433   set_screen_width_and_height (width, height);
    434 }
    435 
    436 
    437 void
    438 tui_win_info::forward_scroll (int num_to_scroll)
    439 {
    440   if (num_to_scroll == 0)
    441     num_to_scroll = height - 3;
    442 
    443   do_scroll_vertical (num_to_scroll);
    444 }
    445 
    446 void
    447 tui_win_info::backward_scroll (int num_to_scroll)
    448 {
    449   if (num_to_scroll == 0)
    450     num_to_scroll = height - 3;
    451 
    452   do_scroll_vertical (-num_to_scroll);
    453 }
    454 
    455 
    456 void
    457 tui_win_info::left_scroll (int num_to_scroll)
    458 {
    459   if (num_to_scroll == 0)
    460     num_to_scroll = 1;
    461 
    462   do_scroll_horizontal (num_to_scroll);
    463 }
    464 
    465 
    466 void
    467 tui_win_info::right_scroll (int num_to_scroll)
    468 {
    469   if (num_to_scroll == 0)
    470     num_to_scroll = 1;
    471 
    472   do_scroll_horizontal (-num_to_scroll);
    473 }
    474 
    475 
    476 void
    477 tui_refresh_all_win (void)
    478 {
    479   clearok (curscr, TRUE);
    480   tui_refresh_all ();
    481 }
    482 
    483 void
    484 tui_rehighlight_all (void)
    485 {
    486   for (tui_win_info *win_info : all_tui_windows ())
    487     win_info->check_and_display_highlight_if_needed ();
    488 }
    489 
    490 /* Resize all the windows based on the terminal size.  This function
    491    gets called from within the readline SIGWINCH handler.  */
    492 void
    493 tui_resize_all (void)
    494 {
    495   int height_diff, width_diff;
    496   int screenheight, screenwidth;
    497 
    498   rl_get_screen_size (&screenheight, &screenwidth);
    499   width_diff = screenwidth - tui_term_width ();
    500   height_diff = screenheight - tui_term_height ();
    501   if (height_diff || width_diff)
    502     {
    503       struct tui_win_info *win_with_focus = tui_win_with_focus ();
    504 
    505 #ifdef HAVE_RESIZE_TERM
    506       resize_term (screenheight, screenwidth);
    507 #endif
    508       /* Turn keypad off while we resize.  */
    509       if (win_with_focus != TUI_CMD_WIN)
    510 	keypad (TUI_CMD_WIN->handle.get (), FALSE);
    511       tui_update_gdb_sizes ();
    512       tui_set_term_height_to (screenheight);
    513       tui_set_term_width_to (screenwidth);
    514 
    515       /* erase + clearok are used instead of a straightforward clear as
    516          AIX 5.3 does not define clear.  */
    517       erase ();
    518       clearok (curscr, TRUE);
    519       tui_apply_current_layout ();
    520       /* Turn keypad back on, unless focus is in the command
    521 	 window.  */
    522       if (win_with_focus != TUI_CMD_WIN)
    523 	keypad (TUI_CMD_WIN->handle.get (), TRUE);
    524     }
    525 }
    526 
    527 #ifdef SIGWINCH
    528 /* Token for use by TUI's asynchronous SIGWINCH handler.  */
    529 static struct async_signal_handler *tui_sigwinch_token;
    530 
    531 /* TUI's SIGWINCH signal handler.  */
    532 static void
    533 tui_sigwinch_handler (int signal)
    534 {
    535   mark_async_signal_handler (tui_sigwinch_token);
    536   tui_set_win_resized_to (true);
    537 }
    538 
    539 /* Callback for asynchronously resizing TUI following a SIGWINCH signal.  */
    540 static void
    541 tui_async_resize_screen (gdb_client_data arg)
    542 {
    543   rl_resize_terminal ();
    544 
    545   if (!tui_active)
    546     {
    547       int screen_height, screen_width;
    548 
    549       rl_get_screen_size (&screen_height, &screen_width);
    550       set_screen_width_and_height (screen_width, screen_height);
    551 
    552       /* win_resized is left set so that the next call to tui_enable()
    553 	 resizes the TUI windows.  */
    554     }
    555   else
    556     {
    557       tui_set_win_resized_to (false);
    558       tui_resize_all ();
    559       tui_refresh_all_win ();
    560       tui_update_gdb_sizes ();
    561       if (resize_message)
    562 	{
    563 	  static int count;
    564 	  printf_unfiltered ("@@ resize done %d, size = %dx%d\n", count,
    565 			     tui_term_width (), tui_term_height ());
    566 	  ++count;
    567 	}
    568       tui_redisplay_readline ();
    569     }
    570 }
    571 #endif
    572 
    573 /* Initialize TUI's SIGWINCH signal handler.  Note that the handler is not
    574    uninstalled when we exit TUI, so the handler should not assume that TUI is
    575    always active.  */
    576 void
    577 tui_initialize_win (void)
    578 {
    579 #ifdef SIGWINCH
    580   tui_sigwinch_token
    581     = create_async_signal_handler (tui_async_resize_screen, NULL);
    582 
    583   {
    584 #ifdef HAVE_SIGACTION
    585     struct sigaction old_winch;
    586 
    587     memset (&old_winch, 0, sizeof (old_winch));
    588     old_winch.sa_handler = &tui_sigwinch_handler;
    589 #ifdef SA_RESTART
    590     old_winch.sa_flags = SA_RESTART;
    591 #endif
    592     sigaction (SIGWINCH, &old_winch, NULL);
    593 #else
    594     signal (SIGWINCH, &tui_sigwinch_handler);
    595 #endif
    596   }
    597 #endif
    598 }
    599 
    600 
    601 static void
    602 tui_scroll_forward_command (const char *arg, int from_tty)
    603 {
    604   int num_to_scroll = 1;
    605   struct tui_win_info *win_to_scroll;
    606 
    607   /* Make sure the curses mode is enabled.  */
    608   tui_enable ();
    609   if (arg == NULL)
    610     parse_scrolling_args (arg, &win_to_scroll, NULL);
    611   else
    612     parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
    613   win_to_scroll->forward_scroll (num_to_scroll);
    614 }
    615 
    616 
    617 static void
    618 tui_scroll_backward_command (const char *arg, int from_tty)
    619 {
    620   int num_to_scroll = 1;
    621   struct tui_win_info *win_to_scroll;
    622 
    623   /* Make sure the curses mode is enabled.  */
    624   tui_enable ();
    625   if (arg == NULL)
    626     parse_scrolling_args (arg, &win_to_scroll, NULL);
    627   else
    628     parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
    629   win_to_scroll->backward_scroll (num_to_scroll);
    630 }
    631 
    632 
    633 static void
    634 tui_scroll_left_command (const char *arg, int from_tty)
    635 {
    636   int num_to_scroll;
    637   struct tui_win_info *win_to_scroll;
    638 
    639   /* Make sure the curses mode is enabled.  */
    640   tui_enable ();
    641   parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
    642   win_to_scroll->left_scroll (num_to_scroll);
    643 }
    644 
    645 
    646 static void
    647 tui_scroll_right_command (const char *arg, int from_tty)
    648 {
    649   int num_to_scroll;
    650   struct tui_win_info *win_to_scroll;
    651 
    652   /* Make sure the curses mode is enabled.  */
    653   tui_enable ();
    654   parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
    655   win_to_scroll->right_scroll (num_to_scroll);
    656 }
    657 
    658 
    659 /* Answer the window represented by name.  */
    660 static struct tui_win_info *
    661 tui_partial_win_by_name (gdb::string_view name)
    662 {
    663   struct tui_win_info *best = nullptr;
    664 
    665   for (tui_win_info *item : all_tui_windows ())
    666     {
    667       const char *cur_name = item->name ();
    668 
    669       if (name == cur_name)
    670 	return item;
    671       if (startswith (cur_name, name))
    672 	{
    673 	  if (best != nullptr)
    674 	    error (_("Window name \"%*s\" is ambiguous"),
    675 		   (int) name.size (), name.data ());
    676 	  best = item;
    677 	}
    678     }
    679 
    680   return best;
    681 }
    682 
    683 /* Set focus to the window named by 'arg'.  */
    684 static void
    685 tui_set_focus_command (const char *arg, int from_tty)
    686 {
    687   tui_enable ();
    688 
    689   if (arg == NULL)
    690     error_no_arg (_("name of window to focus"));
    691 
    692   struct tui_win_info *win_info = NULL;
    693 
    694   if (subset_compare (arg, "next"))
    695     win_info = tui_next_win (tui_win_with_focus ());
    696   else if (subset_compare (arg, "prev"))
    697     win_info = tui_prev_win (tui_win_with_focus ());
    698   else
    699     win_info = tui_partial_win_by_name (arg);
    700 
    701   if (win_info == NULL)
    702     error (_("Unrecognized window name \"%s\""), arg);
    703   if (!win_info->is_visible ())
    704     error (_("Window \"%s\" is not visible"), arg);
    705 
    706   tui_set_win_focus_to (win_info);
    707   keypad (TUI_CMD_WIN->handle.get (), win_info != TUI_CMD_WIN);
    708   printf_filtered (_("Focus set to %s window.\n"),
    709 		   tui_win_with_focus ()->name ());
    710 }
    711 
    712 static void
    713 tui_all_windows_info (const char *arg, int from_tty)
    714 {
    715   if (!tui_active)
    716     {
    717       printf_filtered (_("The TUI is not active.\n"));
    718       return;
    719     }
    720 
    721   struct tui_win_info *win_with_focus = tui_win_with_focus ();
    722   struct ui_out *uiout = current_uiout;
    723 
    724   ui_out_emit_table table_emitter (uiout, 3, -1, "tui-windows");
    725   uiout->table_header (10, ui_left, "name", "Name");
    726   uiout->table_header (5, ui_right, "lines", "Lines");
    727   uiout->table_header (10, ui_left, "focus", "Focus");
    728   uiout->table_body ();
    729 
    730   for (tui_win_info *win_info : all_tui_windows ())
    731     if (win_info->is_visible ())
    732       {
    733 	ui_out_emit_tuple tuple_emitter (uiout, nullptr);
    734 
    735 	uiout->field_string ("name", win_info->name ());
    736 	uiout->field_signed ("lines", win_info->height);
    737 	if (win_with_focus == win_info)
    738 	  uiout->field_string ("focus", _("(has focus)"));
    739 	else
    740 	  uiout->field_skip ("focus");
    741 	uiout->text ("\n");
    742       }
    743 }
    744 
    745 
    746 static void
    747 tui_refresh_all_command (const char *arg, int from_tty)
    748 {
    749   /* Make sure the curses mode is enabled.  */
    750   tui_enable ();
    751 
    752   tui_refresh_all_win ();
    753 }
    754 
    755 #define DEFAULT_TAB_LEN         8
    756 
    757 /* The tab width that should be used by the TUI.  */
    758 
    759 unsigned int tui_tab_width = DEFAULT_TAB_LEN;
    760 
    761 /* The tab width as set by the user.  */
    762 
    763 static unsigned int internal_tab_width = DEFAULT_TAB_LEN;
    764 
    765 /* After the tab width is set, call this to update the relevant
    766    windows.  */
    767 
    768 static void
    769 update_tab_width ()
    770 {
    771   for (tui_win_info *win_info : all_tui_windows ())
    772     {
    773       if (win_info->is_visible ())
    774 	win_info->update_tab_width ();
    775     }
    776 }
    777 
    778 /* Callback for "set tui tab-width".  */
    779 
    780 static void
    781 tui_set_tab_width (const char *ignore,
    782 		   int from_tty, struct cmd_list_element *c)
    783 {
    784   if (internal_tab_width == 0)
    785     {
    786       internal_tab_width = tui_tab_width;
    787       error (_("Tab width must not be 0"));
    788     }
    789 
    790   tui_tab_width = internal_tab_width;
    791   update_tab_width ();
    792 }
    793 
    794 /* Callback for "show tui tab-width".  */
    795 
    796 static void
    797 tui_show_tab_width (struct ui_file *file, int from_tty,
    798 		    struct cmd_list_element *c, const char *value)
    799 {
    800   fprintf_filtered (gdb_stdout, _("TUI tab width is %s spaces.\n"), value);
    801 
    802 }
    803 
    804 /* See tui-win.h.  */
    805 
    806 bool compact_source = false;
    807 
    808 /* Callback for "set tui compact-source".  */
    809 
    810 static void
    811 tui_set_compact_source (const char *ignore, int from_tty,
    812 			struct cmd_list_element *c)
    813 {
    814   if (TUI_SRC_WIN != nullptr)
    815     TUI_SRC_WIN->refill ();
    816 }
    817 
    818 /* Callback for "show tui compact-source".  */
    819 
    820 static void
    821 tui_show_compact_source (struct ui_file *file, int from_tty,
    822 			 struct cmd_list_element *c, const char *value)
    823 {
    824   printf_filtered (_("TUI source window compactness is %s.\n"), value);
    825 }
    826 
    827 /* Set the tab width of the specified window.  */
    828 static void
    829 tui_set_tab_width_command (const char *arg, int from_tty)
    830 {
    831   /* Make sure the curses mode is enabled.  */
    832   tui_enable ();
    833   if (arg != NULL)
    834     {
    835       int ts;
    836 
    837       ts = atoi (arg);
    838       if (ts <= 0)
    839 	warning (_("Tab widths greater than 0 must be specified."));
    840       else
    841 	{
    842 	  internal_tab_width = ts;
    843 	  tui_tab_width = ts;
    844 
    845 	  update_tab_width ();
    846 	}
    847     }
    848 }
    849 
    850 
    851 /* Set the height of the specified window.  */
    852 static void
    853 tui_set_win_height_command (const char *arg, int from_tty)
    854 {
    855   /* Make sure the curses mode is enabled.  */
    856   tui_enable ();
    857   if (arg == NULL)
    858     error_no_arg (_("name of window"));
    859 
    860   const char *buf = arg;
    861   const char *buf_ptr = buf;
    862   int new_height;
    863   struct tui_win_info *win_info;
    864 
    865   buf_ptr = skip_to_space (buf_ptr);
    866 
    867   /* Validate the window name.  */
    868   gdb::string_view wname (buf, buf_ptr - buf);
    869   win_info = tui_partial_win_by_name (wname);
    870 
    871   if (win_info == NULL)
    872     error (_("Unrecognized window name \"%s\""), arg);
    873   if (!win_info->is_visible ())
    874     error (_("Window \"%s\" is not visible"), arg);
    875 
    876   /* Process the size.  */
    877   buf_ptr = skip_spaces (buf_ptr);
    878 
    879   if (*buf_ptr != '\0')
    880     {
    881       bool negate = false;
    882       bool fixed_size = true;
    883       int input_no;;
    884 
    885       if (*buf_ptr == '+' || *buf_ptr == '-')
    886 	{
    887 	  if (*buf_ptr == '-')
    888 	    negate = true;
    889 	  fixed_size = false;
    890 	  buf_ptr++;
    891 	}
    892       input_no = atoi (buf_ptr);
    893       if (input_no > 0)
    894 	{
    895 	  if (negate)
    896 	    input_no *= (-1);
    897 	  if (fixed_size)
    898 	    new_height = input_no;
    899 	  else
    900 	    new_height = win_info->height + input_no;
    901 
    902 	  /* Now change the window's height, and adjust
    903 	     all other windows around it.  */
    904 	  tui_adjust_window_height (win_info, new_height);
    905 	  tui_update_gdb_sizes ();
    906 	}
    907       else
    908 	error (_("Invalid window height specified"));
    909     }
    910 }
    911 
    912 /* See tui-data.h.  */
    913 
    914 int
    915 tui_win_info::max_height () const
    916 {
    917   return tui_term_height () - 2;
    918 }
    919 
    920 /* See tui-data.h.  */
    921 
    922 int
    923 tui_win_info::max_width () const
    924 {
    925   return tui_term_width () - 2;
    926 }
    927 
    928 static void
    929 parse_scrolling_args (const char *arg,
    930 		      struct tui_win_info **win_to_scroll,
    931 		      int *num_to_scroll)
    932 {
    933   if (num_to_scroll)
    934     *num_to_scroll = 0;
    935   *win_to_scroll = tui_win_with_focus ();
    936 
    937   /* First set up the default window to scroll, in case there is no
    938      window name arg.  */
    939   if (arg != NULL)
    940     {
    941       char *buf_ptr;
    942 
    943       /* Process the number of lines to scroll.  */
    944       std::string copy = arg;
    945       buf_ptr = &copy[0];
    946       if (isdigit (*buf_ptr))
    947 	{
    948 	  char *num_str;
    949 
    950 	  num_str = buf_ptr;
    951 	  buf_ptr = strchr (buf_ptr, ' ');
    952 	  if (buf_ptr != NULL)
    953 	    {
    954 	      *buf_ptr = '\0';
    955 	      if (num_to_scroll)
    956 		*num_to_scroll = atoi (num_str);
    957 	      buf_ptr++;
    958 	    }
    959 	  else if (num_to_scroll)
    960 	    *num_to_scroll = atoi (num_str);
    961 	}
    962 
    963       /* Process the window name if one is specified.  */
    964       if (buf_ptr != NULL)
    965 	{
    966 	  const char *wname;
    967 
    968 	  wname = skip_spaces (buf_ptr);
    969 
    970 	  if (*wname != '\0')
    971 	    {
    972 	      *win_to_scroll = tui_partial_win_by_name (wname);
    973 
    974 	      if (*win_to_scroll == NULL)
    975 		error (_("Unrecognized window `%s'"), wname);
    976 	      if (!(*win_to_scroll)->is_visible ())
    977 		error (_("Window is not visible"));
    978 	      else if (*win_to_scroll == TUI_CMD_WIN)
    979 		*win_to_scroll = *(tui_source_windows ().begin ());
    980 	    }
    981 	}
    982     }
    983 }
    984 
    985 /* Function to initialize gdb commands, for tui window
    986    manipulation.  */
    987 
    988 void _initialize_tui_win ();
    989 void
    990 _initialize_tui_win ()
    991 {
    992   static struct cmd_list_element *tui_setlist;
    993   static struct cmd_list_element *tui_showlist;
    994   struct cmd_list_element *cmd;
    995 
    996   /* Define the classes of commands.
    997      They will appear in the help list in the reverse of this order.  */
    998   add_basic_prefix_cmd ("tui", class_tui,
    999 			_("TUI configuration variables."),
   1000 			&tui_setlist, "set tui ",
   1001 			0 /* allow-unknown */, &setlist);
   1002   add_show_prefix_cmd ("tui", class_tui,
   1003 		       _("TUI configuration variables."),
   1004 		       &tui_showlist, "show tui ",
   1005 		       0 /* allow-unknown */, &showlist);
   1006 
   1007   add_com ("refresh", class_tui, tui_refresh_all_command,
   1008            _("Refresh the terminal display."));
   1009 
   1010   cmd = add_com ("tabset", class_tui, tui_set_tab_width_command, _("\
   1011 Set the width (in characters) of tab stops.\n\
   1012 Usage: tabset N"));
   1013   deprecate_cmd (cmd, "set tui tab-width");
   1014 
   1015   cmd = add_com ("winheight", class_tui, tui_set_win_height_command, _("\
   1016 Set or modify the height of a specified window.\n\
   1017 Usage: winheight WINDOW-NAME [+ | -] NUM-LINES\n\
   1018 Use \"info win\" to see the names of the windows currently being displayed."));
   1019   add_com_alias ("wh", "winheight", class_tui, 0);
   1020   set_cmd_completer (cmd, winheight_completer);
   1021   add_info ("win", tui_all_windows_info,
   1022 	    _("List of all displayed windows.\n\
   1023 Usage: info win"));
   1024   cmd = add_com ("focus", class_tui, tui_set_focus_command, _("\
   1025 Set focus to named window or next/prev window.\n\
   1026 Usage: focus [WINDOW-NAME | next | prev]\n\
   1027 Use \"info win\" to see the names of the windows currently being displayed."));
   1028   add_com_alias ("fs", "focus", class_tui, 0);
   1029   set_cmd_completer (cmd, focus_completer);
   1030   add_com ("+", class_tui, tui_scroll_forward_command, _("\
   1031 Scroll window forward.\n\
   1032 Usage: + [N] [WIN]\n\
   1033 Scroll window WIN N lines forwards.  Both WIN and N are optional, N\n\
   1034 defaults to 1, and WIN defaults to the currently focused window."));
   1035   add_com ("-", class_tui, tui_scroll_backward_command, _("\
   1036 Scroll window backward.\n\
   1037 Usage: - [N] [WIN]\n\
   1038 Scroll window WIN N lines backwards.  Both WIN and N are optional, N\n\
   1039 defaults to 1, and WIN defaults to the currently focused window."));
   1040   add_com ("<", class_tui, tui_scroll_left_command, _("\
   1041 Scroll window text to the left.\n\
   1042 Usage: < [N] [WIN]\n\
   1043 Scroll window WIN N characters left.  Both WIN and N are optional, N\n\
   1044 defaults to 1, and WIN defaults to the currently focused window."));
   1045   add_com (">", class_tui, tui_scroll_right_command, _("\
   1046 Scroll window text to the right.\n\
   1047 Usage: > [N] [WIN]\n\
   1048 Scroll window WIN N characters right.  Both WIN and N are optional, N\n\
   1049 defaults to 1, and WIN defaults to the currently focused window."));
   1050 
   1051   /* Define the tui control variables.  */
   1052   add_setshow_enum_cmd ("border-kind", no_class, tui_border_kind_enums,
   1053 			&tui_border_kind, _("\
   1054 Set the kind of border for TUI windows."), _("\
   1055 Show the kind of border for TUI windows."), _("\
   1056 This variable controls the border of TUI windows:\n\
   1057    space           use a white space\n\
   1058    ascii           use ascii characters + - | for the border\n\
   1059    acs             use the Alternate Character Set"),
   1060 			tui_set_var_cmd,
   1061 			show_tui_border_kind,
   1062 			&tui_setlist, &tui_showlist);
   1063 
   1064   add_setshow_enum_cmd ("border-mode", no_class, tui_border_mode_enums,
   1065 			&tui_border_mode, _("\
   1066 Set the attribute mode to use for the TUI window borders."), _("\
   1067 Show the attribute mode to use for the TUI window borders."), _("\
   1068 This variable controls the attributes to use for the window borders:\n\
   1069    normal          normal display\n\
   1070    standout        use highlight mode of terminal\n\
   1071    reverse         use reverse video mode\n\
   1072    half            use half bright\n\
   1073    half-standout   use half bright and standout mode\n\
   1074    bold            use extra bright or bold\n\
   1075    bold-standout   use extra bright or bold with standout mode"),
   1076 			tui_set_var_cmd,
   1077 			show_tui_border_mode,
   1078 			&tui_setlist, &tui_showlist);
   1079 
   1080   add_setshow_enum_cmd ("active-border-mode", no_class, tui_border_mode_enums,
   1081 			&tui_active_border_mode, _("\
   1082 Set the attribute mode to use for the active TUI window border."), _("\
   1083 Show the attribute mode to use for the active TUI window border."), _("\
   1084 This variable controls the attributes to use for the active window border:\n\
   1085    normal          normal display\n\
   1086    standout        use highlight mode of terminal\n\
   1087    reverse         use reverse video mode\n\
   1088    half            use half bright\n\
   1089    half-standout   use half bright and standout mode\n\
   1090    bold            use extra bright or bold\n\
   1091    bold-standout   use extra bright or bold with standout mode"),
   1092 			tui_set_var_cmd,
   1093 			show_tui_active_border_mode,
   1094 			&tui_setlist, &tui_showlist);
   1095 
   1096   add_setshow_zuinteger_cmd ("tab-width", no_class,
   1097 			     &internal_tab_width, _("\
   1098 Set the tab width, in characters, for the TUI."), _("\
   1099 Show the tab witdh, in characters, for the TUI."), _("\
   1100 This variable controls how many spaces are used to display a tab character."),
   1101 			     tui_set_tab_width, tui_show_tab_width,
   1102 			     &tui_setlist, &tui_showlist);
   1103 
   1104   add_setshow_boolean_cmd ("tui-resize-message", class_maintenance,
   1105 			   &resize_message, _("\
   1106 Set TUI resize messaging."), _("\
   1107 Show TUI resize messaging."), _("\
   1108 When enabled GDB will print a message when the terminal is resized."),
   1109 			   nullptr,
   1110 			   show_tui_resize_message,
   1111 			   &maintenance_set_cmdlist,
   1112 			   &maintenance_show_cmdlist);
   1113 
   1114   add_setshow_boolean_cmd ("compact-source", class_tui,
   1115 			   &compact_source, _("\
   1116 Set whether the TUI source window is compact."), _("\
   1117 Show whether the TUI source window is compact."), _("\
   1118 This variable controls whether the TUI source window is shown\n\
   1119 in a compact form.  The compact form puts the source closer to\n\
   1120 the line numbers and uses less horizontal space."),
   1121 			   tui_set_compact_source, tui_show_compact_source,
   1122 			   &tui_setlist, &tui_showlist);
   1123 
   1124   tui_border_style.changed.attach (tui_rehighlight_all);
   1125   tui_active_border_style.changed.attach (tui_rehighlight_all);
   1126 }
   1127