Add RAII class for blocking gdb signals
[deliverable/binutils-gdb.git] / gdb / tui / tui-win.c
1 /* TUI window generic functions.
2
3 Copyright (C) 1998-2019 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 "top.h"
34 #include "source.h"
35 #include "event-loop.h"
36 #include "gdbcmd.h"
37
38 #include "tui/tui.h"
39 #include "tui/tui-io.h"
40 #include "tui/tui-command.h"
41 #include "tui/tui-data.h"
42 #include "tui/tui-layout.h"
43 #include "tui/tui-wingeneral.h"
44 #include "tui/tui-stack.h"
45 #include "tui/tui-regs.h"
46 #include "tui/tui-disasm.h"
47 #include "tui/tui-source.h"
48 #include "tui/tui-winsource.h"
49 #include "tui/tui-win.h"
50
51 #include "gdb_curses.h"
52 #include <ctype.h>
53 #include "readline/readline.h"
54 #include "gdbsupport/gdb_string_view.h"
55
56 #include <signal.h>
57
58 static enum tui_status tui_adjust_win_heights (struct tui_win_info *,
59 int);
60 static int new_height_ok (struct tui_win_info *, int);
61 static void tui_set_tab_width_command (const char *, int);
62 static void tui_refresh_all_command (const char *, int);
63 static void tui_all_windows_info (const char *, int);
64 static void tui_scroll_forward_command (const char *, int);
65 static void tui_scroll_backward_command (const char *, int);
66 static void tui_scroll_left_command (const char *, int);
67 static void tui_scroll_right_command (const char *, int);
68 static void parse_scrolling_args (const char *,
69 struct tui_win_info **,
70 int *);
71
72
73 #define WIN_HEIGHT_USAGE "Usage: winheight WINDOW-NAME [+ | -] NUM-LINES\n"
74 #define FOCUS_USAGE "Usage: focus [WINDOW-NAME | next | prev]\n"
75
76 #ifndef ACS_LRCORNER
77 # define ACS_LRCORNER '+'
78 #endif
79 #ifndef ACS_LLCORNER
80 # define ACS_LLCORNER '+'
81 #endif
82 #ifndef ACS_ULCORNER
83 # define ACS_ULCORNER '+'
84 #endif
85 #ifndef ACS_URCORNER
86 # define ACS_URCORNER '+'
87 #endif
88 #ifndef ACS_HLINE
89 # define ACS_HLINE '-'
90 #endif
91 #ifndef ACS_VLINE
92 # define ACS_VLINE '|'
93 #endif
94
95 /* Possible values for tui-border-kind variable. */
96 static const char *const tui_border_kind_enums[] = {
97 "space",
98 "ascii",
99 "acs",
100 NULL
101 };
102
103 /* Possible values for tui-border-mode and tui-active-border-mode. */
104 static const char *const tui_border_mode_enums[] = {
105 "normal",
106 "standout",
107 "reverse",
108 "half",
109 "half-standout",
110 "bold",
111 "bold-standout",
112 NULL
113 };
114
115 struct tui_translate
116 {
117 const char *name;
118 int value;
119 };
120
121 /* Translation table for border-mode variables.
122 The list of values must be terminated by a NULL.
123 After the NULL value, an entry defines the default. */
124 struct tui_translate tui_border_mode_translate[] = {
125 { "normal", A_NORMAL },
126 { "standout", A_STANDOUT },
127 { "reverse", A_REVERSE },
128 { "half", A_DIM },
129 { "half-standout", A_DIM | A_STANDOUT },
130 { "bold", A_BOLD },
131 { "bold-standout", A_BOLD | A_STANDOUT },
132 { 0, 0 },
133 { "normal", A_NORMAL }
134 };
135
136 /* Translation tables for border-kind, one for each border
137 character (see wborder, border curses operations).
138 -1 is used to indicate the ACS because ACS characters
139 are determined at run time by curses (depends on terminal). */
140 struct tui_translate tui_border_kind_translate_vline[] = {
141 { "space", ' ' },
142 { "ascii", '|' },
143 { "acs", -1 },
144 { 0, 0 },
145 { "ascii", '|' }
146 };
147
148 struct tui_translate tui_border_kind_translate_hline[] = {
149 { "space", ' ' },
150 { "ascii", '-' },
151 { "acs", -1 },
152 { 0, 0 },
153 { "ascii", '-' }
154 };
155
156 struct tui_translate tui_border_kind_translate_ulcorner[] = {
157 { "space", ' ' },
158 { "ascii", '+' },
159 { "acs", -1 },
160 { 0, 0 },
161 { "ascii", '+' }
162 };
163
164 struct tui_translate tui_border_kind_translate_urcorner[] = {
165 { "space", ' ' },
166 { "ascii", '+' },
167 { "acs", -1 },
168 { 0, 0 },
169 { "ascii", '+' }
170 };
171
172 struct tui_translate tui_border_kind_translate_llcorner[] = {
173 { "space", ' ' },
174 { "ascii", '+' },
175 { "acs", -1 },
176 { 0, 0 },
177 { "ascii", '+' }
178 };
179
180 struct tui_translate tui_border_kind_translate_lrcorner[] = {
181 { "space", ' ' },
182 { "ascii", '+' },
183 { "acs", -1 },
184 { 0, 0 },
185 { "ascii", '+' }
186 };
187
188
189 /* Tui configuration variables controlled with set/show command. */
190 const char *tui_active_border_mode = "bold-standout";
191 static void
192 show_tui_active_border_mode (struct ui_file *file,
193 int from_tty,
194 struct cmd_list_element *c,
195 const char *value)
196 {
197 fprintf_filtered (file, _("\
198 The attribute mode to use for the active TUI window border is \"%s\".\n"),
199 value);
200 }
201
202 const char *tui_border_mode = "normal";
203 static void
204 show_tui_border_mode (struct ui_file *file,
205 int from_tty,
206 struct cmd_list_element *c,
207 const char *value)
208 {
209 fprintf_filtered (file, _("\
210 The attribute mode to use for the TUI window borders is \"%s\".\n"),
211 value);
212 }
213
214 const char *tui_border_kind = "acs";
215 static void
216 show_tui_border_kind (struct ui_file *file,
217 int from_tty,
218 struct cmd_list_element *c,
219 const char *value)
220 {
221 fprintf_filtered (file, _("The kind of border for TUI windows is \"%s\".\n"),
222 value);
223 }
224
225
226 /* Tui internal configuration variables. These variables are updated
227 by tui_update_variables to reflect the tui configuration
228 variables. */
229 chtype tui_border_vline;
230 chtype tui_border_hline;
231 chtype tui_border_ulcorner;
232 chtype tui_border_urcorner;
233 chtype tui_border_llcorner;
234 chtype tui_border_lrcorner;
235
236 int tui_border_attrs;
237 int tui_active_border_attrs;
238
239 /* Identify the item in the translation table.
240 When the item is not recognized, use the default entry. */
241 static struct tui_translate *
242 translate (const char *name, struct tui_translate *table)
243 {
244 while (table->name)
245 {
246 if (name && strcmp (table->name, name) == 0)
247 return table;
248 table++;
249 }
250
251 /* Not found, return default entry. */
252 table++;
253 return table;
254 }
255
256 /* Update the tui internal configuration according to gdb settings.
257 Returns 1 if the configuration has changed and the screen should
258 be redrawn. */
259 int
260 tui_update_variables (void)
261 {
262 int need_redraw = 0;
263 struct tui_translate *entry;
264
265 entry = translate (tui_border_mode, tui_border_mode_translate);
266 if (tui_border_attrs != entry->value)
267 {
268 tui_border_attrs = entry->value;
269 need_redraw = 1;
270 }
271 entry = translate (tui_active_border_mode, tui_border_mode_translate);
272 if (tui_active_border_attrs != entry->value)
273 {
274 tui_active_border_attrs = entry->value;
275 need_redraw = 1;
276 }
277
278 /* If one corner changes, all characters are changed.
279 Only check the first one. The ACS characters are determined at
280 run time by curses terminal management. */
281 entry = translate (tui_border_kind, tui_border_kind_translate_lrcorner);
282 if (tui_border_lrcorner != (chtype) entry->value)
283 {
284 tui_border_lrcorner = (entry->value < 0) ? ACS_LRCORNER : entry->value;
285 need_redraw = 1;
286 }
287 entry = translate (tui_border_kind, tui_border_kind_translate_llcorner);
288 tui_border_llcorner = (entry->value < 0) ? ACS_LLCORNER : entry->value;
289
290 entry = translate (tui_border_kind, tui_border_kind_translate_ulcorner);
291 tui_border_ulcorner = (entry->value < 0) ? ACS_ULCORNER : entry->value;
292
293 entry = translate (tui_border_kind, tui_border_kind_translate_urcorner);
294 tui_border_urcorner = (entry->value < 0) ? ACS_URCORNER : entry->value;
295
296 entry = translate (tui_border_kind, tui_border_kind_translate_hline);
297 tui_border_hline = (entry->value < 0) ? ACS_HLINE : entry->value;
298
299 entry = translate (tui_border_kind, tui_border_kind_translate_vline);
300 tui_border_vline = (entry->value < 0) ? ACS_VLINE : entry->value;
301
302 return need_redraw;
303 }
304
305 static void
306 set_tui_cmd (const char *args, int from_tty)
307 {
308 }
309
310 static void
311 show_tui_cmd (const char *args, int from_tty)
312 {
313 }
314
315 static struct cmd_list_element *tuilist;
316
317 static void
318 tui_command (const char *args, int from_tty)
319 {
320 printf_unfiltered (_("\"tui\" must be followed by the name of a "
321 "tui command.\n"));
322 help_list (tuilist, "tui ", all_commands, gdb_stdout);
323 }
324
325 struct cmd_list_element **
326 tui_get_cmd_list (void)
327 {
328 if (tuilist == 0)
329 add_prefix_cmd ("tui", class_tui, tui_command,
330 _("Text User Interface commands."),
331 &tuilist, "tui ", 0, &cmdlist);
332 return &tuilist;
333 }
334
335 /* The set_func hook of "set tui ..." commands that affect the window
336 borders on the TUI display. */
337
338 static void
339 tui_set_var_cmd (const char *null_args,
340 int from_tty, struct cmd_list_element *c)
341 {
342 if (tui_update_variables () && tui_active)
343 tui_rehighlight_all ();
344 }
345
346 \f
347
348 /* True if TUI resizes should print a message. This is used by the
349 test suite. */
350
351 static bool resize_message;
352
353 static void
354 show_tui_resize_message (struct ui_file *file, int from_tty,
355 struct cmd_list_element *c, const char *value)
356 {
357 fprintf_filtered (file, _("TUI resize messaging is %s.\n"), value);
358 }
359
360 \f
361
362 /* Generic window name completion function. Complete window name pointed
363 to by TEXT and WORD. If INCLUDE_NEXT_PREV_P is true then the special
364 window names 'next' and 'prev' will also be considered as possible
365 completions of the window name. */
366
367 static void
368 window_name_completer (completion_tracker &tracker,
369 int include_next_prev_p,
370 const char *text, const char *word)
371 {
372 std::vector<const char *> completion_name_vec;
373
374 for (tui_win_info *win_info : all_tui_windows ())
375 {
376 const char *completion_name = NULL;
377
378 /* We can't focus on an invisible window. */
379 if (!win_info->is_visible ())
380 continue;
381
382 completion_name = win_info->name ();
383 gdb_assert (completion_name != NULL);
384 completion_name_vec.push_back (completion_name);
385 }
386
387 /* If no windows are considered visible then the TUI has not yet been
388 initialized. But still "focus src" and "focus cmd" will work because
389 invoking the focus command will entail initializing the TUI which sets the
390 default layout to SRC_COMMAND. */
391 if (completion_name_vec.empty ())
392 {
393 completion_name_vec.push_back (SRC_NAME);
394 completion_name_vec.push_back (CMD_NAME);
395 }
396
397 if (include_next_prev_p)
398 {
399 completion_name_vec.push_back ("next");
400 completion_name_vec.push_back ("prev");
401 }
402
403
404 completion_name_vec.push_back (NULL);
405 complete_on_enum (tracker, completion_name_vec.data (), text, word);
406 }
407
408 /* Complete possible window names to focus on. TEXT is the complete text
409 entered so far, WORD is the word currently being completed. */
410
411 static void
412 focus_completer (struct cmd_list_element *ignore,
413 completion_tracker &tracker,
414 const char *text, const char *word)
415 {
416 window_name_completer (tracker, 1, text, word);
417 }
418
419 /* Complete possible window names for winheight command. TEXT is the
420 complete text entered so far, WORD is the word currently being
421 completed. */
422
423 static void
424 winheight_completer (struct cmd_list_element *ignore,
425 completion_tracker &tracker,
426 const char *text, const char *word)
427 {
428 /* The first word is the window name. That we can complete. Subsequent
429 words can't be completed. */
430 if (word != text)
431 return;
432
433 window_name_completer (tracker, 0, text, word);
434 }
435
436 /* Update gdb's knowledge of the terminal size. */
437 void
438 tui_update_gdb_sizes (void)
439 {
440 int width, height;
441
442 if (tui_active)
443 {
444 width = TUI_CMD_WIN->width;
445 height = TUI_CMD_WIN->height;
446 }
447 else
448 {
449 width = tui_term_width ();
450 height = tui_term_height ();
451 }
452
453 set_screen_width_and_height (width, height);
454 }
455
456
457 /* Set the logical focus to win_info. */
458 void
459 tui_set_win_focus_to (struct tui_win_info *win_info)
460 {
461 if (win_info != NULL)
462 {
463 struct tui_win_info *win_with_focus = tui_win_with_focus ();
464
465 tui_unhighlight_win (win_with_focus);
466 tui_set_win_with_focus (win_info);
467 tui_highlight_win (win_info);
468 }
469 }
470
471
472 void
473 tui_win_info::forward_scroll (int num_to_scroll)
474 {
475 if (num_to_scroll == 0)
476 num_to_scroll = height - 3;
477
478 do_scroll_vertical (num_to_scroll);
479 }
480
481 void
482 tui_win_info::backward_scroll (int num_to_scroll)
483 {
484 if (num_to_scroll == 0)
485 num_to_scroll = height - 3;
486
487 do_scroll_vertical (-num_to_scroll);
488 }
489
490
491 void
492 tui_win_info::left_scroll (int num_to_scroll)
493 {
494 if (num_to_scroll == 0)
495 num_to_scroll = 1;
496
497 do_scroll_horizontal (num_to_scroll);
498 }
499
500
501 void
502 tui_win_info::right_scroll (int num_to_scroll)
503 {
504 if (num_to_scroll == 0)
505 num_to_scroll = 1;
506
507 do_scroll_horizontal (-num_to_scroll);
508 }
509
510
511 void
512 tui_refresh_all_win (void)
513 {
514 clearok (curscr, TRUE);
515 tui_refresh_all ();
516 }
517
518 void
519 tui_rehighlight_all (void)
520 {
521 for (tui_win_info *win_info : all_tui_windows ())
522 win_info->check_and_display_highlight_if_needed ();
523 }
524
525 /* Resize all the windows based on the terminal size. This function
526 gets called from within the readline SIGWINCH handler. */
527 void
528 tui_resize_all (void)
529 {
530 int height_diff, width_diff;
531 int screenheight, screenwidth;
532
533 rl_get_screen_size (&screenheight, &screenwidth);
534 width_diff = screenwidth - tui_term_width ();
535 height_diff = screenheight - tui_term_height ();
536 if (height_diff || width_diff)
537 {
538 enum tui_layout_type cur_layout = tui_current_layout ();
539 struct tui_win_info *win_with_focus = tui_win_with_focus ();
540 struct tui_win_info *first_win;
541 struct tui_win_info *second_win;
542 tui_source_window_base *src_win;
543 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
544 int new_height, split_diff, cmd_split_diff, num_wins_displayed = 2;
545
546 #ifdef HAVE_RESIZE_TERM
547 resize_term (screenheight, screenwidth);
548 #endif
549 /* Turn keypad off while we resize. */
550 if (win_with_focus != TUI_CMD_WIN)
551 keypad (TUI_CMD_WIN->handle.get (), FALSE);
552 tui_update_gdb_sizes ();
553 tui_set_term_height_to (screenheight);
554 tui_set_term_width_to (screenwidth);
555 if (cur_layout == SRC_DISASSEM_COMMAND
556 || cur_layout == SRC_DATA_COMMAND
557 || cur_layout == DISASSEM_DATA_COMMAND)
558 num_wins_displayed++;
559 split_diff = height_diff / num_wins_displayed;
560 cmd_split_diff = split_diff;
561 if (height_diff % num_wins_displayed)
562 {
563 if (height_diff < 0)
564 cmd_split_diff--;
565 else
566 cmd_split_diff++;
567 }
568 /* Now adjust each window. */
569 /* erase + clearok are used instead of a straightforward clear as
570 AIX 5.3 does not define clear. */
571 erase ();
572 clearok (curscr, TRUE);
573 switch (cur_layout)
574 {
575 case SRC_COMMAND:
576 case DISASSEM_COMMAND:
577 src_win = *(tui_source_windows ().begin ());
578 /* Check for invalid heights. */
579 if (height_diff == 0)
580 new_height = src_win->height;
581 else if ((src_win->height + split_diff) >=
582 (screenheight - MIN_CMD_WIN_HEIGHT - 1))
583 new_height = screenheight - MIN_CMD_WIN_HEIGHT - 1;
584 else if ((src_win->height + split_diff) <= 0)
585 new_height = MIN_WIN_HEIGHT;
586 else
587 new_height = src_win->height + split_diff;
588
589 src_win->resize (new_height, screenwidth, 0, 0);
590
591 locator->resize (1, screenwidth, 0, new_height);
592
593 new_height = screenheight - (new_height + 1);
594 TUI_CMD_WIN->resize (new_height, screenwidth,
595 0, locator->origin.y + 1);
596 break;
597 default:
598 if (cur_layout == SRC_DISASSEM_COMMAND)
599 {
600 src_win = TUI_SRC_WIN;
601 first_win = src_win;
602 second_win = TUI_DISASM_WIN;
603 }
604 else
605 {
606 first_win = TUI_DATA_WIN;
607 src_win = *(tui_source_windows ().begin ());
608 second_win = src_win;
609 }
610 /* Change the first window's height/width. */
611 /* Check for invalid heights. */
612 if (height_diff == 0)
613 new_height = first_win->height;
614 else if ((first_win->height +
615 second_win->height + (split_diff * 2)) >=
616 (screenheight - MIN_CMD_WIN_HEIGHT - 1))
617 new_height = (screenheight - MIN_CMD_WIN_HEIGHT - 1) / 2;
618 else if ((first_win->height + split_diff) <= 0)
619 new_height = MIN_WIN_HEIGHT;
620 else
621 new_height = first_win->height + split_diff;
622
623 first_win->resize (new_height, screenwidth, 0, 0);
624
625 /* Change the second window's height/width. */
626 /* Check for invalid heights. */
627 if (height_diff == 0)
628 new_height = second_win->height;
629 else if ((first_win->height +
630 second_win->height + (split_diff * 2)) >=
631 (screenheight - MIN_CMD_WIN_HEIGHT - 1))
632 {
633 new_height = screenheight - MIN_CMD_WIN_HEIGHT - 1;
634 if (new_height % 2)
635 new_height = (new_height / 2) + 1;
636 else
637 new_height /= 2;
638 }
639 else if ((second_win->height + split_diff) <= 0)
640 new_height = MIN_WIN_HEIGHT;
641 else
642 new_height = second_win->height + split_diff;
643
644 second_win->resize (new_height, screenwidth,
645 0, first_win->height - 1);
646
647 locator->resize (1, screenwidth,
648 0, second_win->origin.y + new_height);
649
650 /* Change the command window's height/width. */
651 new_height = screenheight - (locator->origin.y + 1);
652 TUI_CMD_WIN->resize (new_height, screenwidth,
653 0, locator->origin.y + 1);
654 break;
655 }
656
657 tui_delete_invisible_windows ();
658 /* Turn keypad back on, unless focus is in the command
659 window. */
660 if (win_with_focus != TUI_CMD_WIN)
661 keypad (TUI_CMD_WIN->handle.get (), TRUE);
662 }
663 }
664
665 #ifdef SIGWINCH
666 /* Token for use by TUI's asynchronous SIGWINCH handler. */
667 static struct async_signal_handler *tui_sigwinch_token;
668
669 /* TUI's SIGWINCH signal handler. */
670 static void
671 tui_sigwinch_handler (int signal)
672 {
673 mark_async_signal_handler (tui_sigwinch_token);
674 tui_set_win_resized_to (true);
675 }
676
677 /* Callback for asynchronously resizing TUI following a SIGWINCH signal. */
678 static void
679 tui_async_resize_screen (gdb_client_data arg)
680 {
681 rl_resize_terminal ();
682
683 if (!tui_active)
684 {
685 int screen_height, screen_width;
686
687 rl_get_screen_size (&screen_height, &screen_width);
688 set_screen_width_and_height (screen_width, screen_height);
689
690 /* win_resized is left set so that the next call to tui_enable()
691 resizes the TUI windows. */
692 }
693 else
694 {
695 tui_set_win_resized_to (false);
696 tui_resize_all ();
697 tui_refresh_all_win ();
698 tui_update_gdb_sizes ();
699 if (resize_message)
700 {
701 static int count;
702 printf_unfiltered ("@@ resize done %d, size = %dx%d\n", count,
703 tui_term_width (), tui_term_height ());
704 ++count;
705 }
706 tui_redisplay_readline ();
707 }
708 }
709 #endif
710
711 /* Initialize TUI's SIGWINCH signal handler. Note that the handler is not
712 uninstalled when we exit TUI, so the handler should not assume that TUI is
713 always active. */
714 void
715 tui_initialize_win (void)
716 {
717 #ifdef SIGWINCH
718 tui_sigwinch_token
719 = create_async_signal_handler (tui_async_resize_screen, NULL);
720
721 {
722 #ifdef HAVE_SIGACTION
723 struct sigaction old_winch;
724
725 memset (&old_winch, 0, sizeof (old_winch));
726 old_winch.sa_handler = &tui_sigwinch_handler;
727 #ifdef SA_RESTART
728 old_winch.sa_flags = SA_RESTART;
729 #endif
730 sigaction (SIGWINCH, &old_winch, NULL);
731 #else
732 signal (SIGWINCH, &tui_sigwinch_handler);
733 #endif
734 }
735 #endif
736 }
737
738
739 static void
740 tui_scroll_forward_command (const char *arg, int from_tty)
741 {
742 int num_to_scroll = 1;
743 struct tui_win_info *win_to_scroll;
744
745 /* Make sure the curses mode is enabled. */
746 tui_enable ();
747 if (arg == NULL)
748 parse_scrolling_args (arg, &win_to_scroll, NULL);
749 else
750 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
751 win_to_scroll->forward_scroll (num_to_scroll);
752 }
753
754
755 static void
756 tui_scroll_backward_command (const char *arg, int from_tty)
757 {
758 int num_to_scroll = 1;
759 struct tui_win_info *win_to_scroll;
760
761 /* Make sure the curses mode is enabled. */
762 tui_enable ();
763 if (arg == NULL)
764 parse_scrolling_args (arg, &win_to_scroll, NULL);
765 else
766 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
767 win_to_scroll->backward_scroll (num_to_scroll);
768 }
769
770
771 static void
772 tui_scroll_left_command (const char *arg, int from_tty)
773 {
774 int num_to_scroll;
775 struct tui_win_info *win_to_scroll;
776
777 /* Make sure the curses mode is enabled. */
778 tui_enable ();
779 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
780 win_to_scroll->left_scroll (num_to_scroll);
781 }
782
783
784 static void
785 tui_scroll_right_command (const char *arg, int from_tty)
786 {
787 int num_to_scroll;
788 struct tui_win_info *win_to_scroll;
789
790 /* Make sure the curses mode is enabled. */
791 tui_enable ();
792 parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
793 win_to_scroll->right_scroll (num_to_scroll);
794 }
795
796
797 /* Answer the window represented by name. */
798 static struct tui_win_info *
799 tui_partial_win_by_name (gdb::string_view name)
800 {
801 if (name != NULL)
802 {
803 for (tui_win_info *item : all_tui_windows ())
804 {
805 const char *cur_name = item->name ();
806
807 if (startswith (cur_name, name))
808 return item;
809 }
810 }
811
812 return NULL;
813 }
814
815 /* Set focus to the window named by 'arg'. */
816 static void
817 tui_set_focus_command (const char *arg, int from_tty)
818 {
819 tui_enable ();
820
821 if (arg != NULL)
822 {
823 struct tui_win_info *win_info = NULL;
824
825 if (subset_compare (arg, "next"))
826 win_info = tui_next_win (tui_win_with_focus ());
827 else if (subset_compare (arg, "prev"))
828 win_info = tui_prev_win (tui_win_with_focus ());
829 else
830 win_info = tui_partial_win_by_name (arg);
831
832 if (win_info == NULL)
833 error (_("Unrecognized window name \"%s\""), arg);
834 if (!win_info->is_visible ())
835 error (_("Window \"%s\" is not visible"), arg);
836
837 tui_set_win_focus_to (win_info);
838 keypad (TUI_CMD_WIN->handle.get (), win_info != TUI_CMD_WIN);
839 printf_filtered (_("Focus set to %s window.\n"),
840 tui_win_with_focus ()->name ());
841 }
842 else
843 error (_("Incorrect Number of Arguments.\n%s"), FOCUS_USAGE);
844 }
845
846 static void
847 tui_all_windows_info (const char *arg, int from_tty)
848 {
849 struct tui_win_info *win_with_focus = tui_win_with_focus ();
850 struct ui_out *uiout = current_uiout;
851
852 ui_out_emit_table table_emitter (uiout, 3, -1, "tui-windows");
853 uiout->table_header (10, ui_left, "name", "Name");
854 uiout->table_header (5, ui_right, "lines", "Lines");
855 uiout->table_header (10, ui_left, "focus", "Focus");
856 uiout->table_body ();
857
858 for (tui_win_info *win_info : all_tui_windows ())
859 if (win_info->is_visible ())
860 {
861 ui_out_emit_tuple tuple_emitter (uiout, nullptr);
862
863 uiout->field_string ("name", win_info->name ());
864 uiout->field_signed ("lines", win_info->height);
865 if (win_with_focus == win_info)
866 uiout->field_string ("focus", _("(has focus)"));
867 else
868 uiout->field_skip ("focus");
869 uiout->text ("\n");
870 }
871 }
872
873
874 static void
875 tui_refresh_all_command (const char *arg, int from_tty)
876 {
877 /* Make sure the curses mode is enabled. */
878 tui_enable ();
879
880 tui_refresh_all_win ();
881 }
882
883 /* The tab width that should be used by the TUI. */
884
885 unsigned int tui_tab_width = DEFAULT_TAB_LEN;
886
887 /* The tab width as set by the user. */
888
889 static unsigned int internal_tab_width = DEFAULT_TAB_LEN;
890
891 /* After the tab width is set, call this to update the relevant
892 windows. */
893
894 static void
895 update_tab_width ()
896 {
897 for (tui_win_info *win_info : all_tui_windows ())
898 {
899 if (win_info->is_visible ())
900 win_info->update_tab_width ();
901 }
902 }
903
904 /* Callback for "set tui tab-width". */
905
906 static void
907 tui_set_tab_width (const char *ignore,
908 int from_tty, struct cmd_list_element *c)
909 {
910 if (internal_tab_width == 0)
911 {
912 internal_tab_width = tui_tab_width;
913 error (_("Tab width must not be 0"));
914 }
915
916 tui_tab_width = internal_tab_width;
917 update_tab_width ();
918 }
919
920 /* Callback for "show tui tab-width". */
921
922 static void
923 tui_show_tab_width (struct ui_file *file, int from_tty,
924 struct cmd_list_element *c, const char *value)
925 {
926 fprintf_filtered (gdb_stdout, _("TUI tab width is %s spaces.\n"), value);
927
928 }
929
930 /* Set the tab width of the specified window. */
931 static void
932 tui_set_tab_width_command (const char *arg, int from_tty)
933 {
934 /* Make sure the curses mode is enabled. */
935 tui_enable ();
936 if (arg != NULL)
937 {
938 int ts;
939
940 ts = atoi (arg);
941 if (ts <= 0)
942 warning (_("Tab widths greater than 0 must be specified."));
943 else
944 {
945 internal_tab_width = ts;
946 tui_tab_width = ts;
947
948 update_tab_width ();
949 }
950 }
951 }
952
953
954 /* Set the height of the specified window. */
955 static void
956 tui_set_win_height_command (const char *arg, int from_tty)
957 {
958 /* Make sure the curses mode is enabled. */
959 tui_enable ();
960 if (arg != NULL)
961 {
962 const char *buf = arg;
963 const char *buf_ptr = buf;
964 int new_height;
965 struct tui_win_info *win_info;
966
967 buf_ptr = strchr (buf_ptr, ' ');
968 if (buf_ptr != NULL)
969 {
970 /* Validate the window name. */
971 gdb::string_view wname (buf, buf_ptr - buf);
972 win_info = tui_partial_win_by_name (wname);
973
974 if (win_info == NULL)
975 error (_("Unrecognized window name \"%s\""), arg);
976 if (!win_info->is_visible ())
977 error (_("Window \"%s\" is not visible"), arg);
978
979 /* Process the size. */
980 buf_ptr = skip_spaces (buf_ptr);
981
982 if (*buf_ptr != '\0')
983 {
984 bool negate = false;
985 bool fixed_size = true;
986 int input_no;;
987
988 if (*buf_ptr == '+' || *buf_ptr == '-')
989 {
990 if (*buf_ptr == '-')
991 negate = true;
992 fixed_size = false;
993 buf_ptr++;
994 }
995 input_no = atoi (buf_ptr);
996 if (input_no > 0)
997 {
998 if (negate)
999 input_no *= (-1);
1000 if (fixed_size)
1001 new_height = input_no;
1002 else
1003 new_height = win_info->height + input_no;
1004
1005 /* Now change the window's height, and adjust
1006 all other windows around it. */
1007 if (tui_adjust_win_heights (win_info,
1008 new_height) == TUI_FAILURE)
1009 warning (_("Invalid window height specified.\n%s"),
1010 WIN_HEIGHT_USAGE);
1011 else
1012 tui_update_gdb_sizes ();
1013 }
1014 else
1015 warning (_("Invalid window height specified.\n%s"),
1016 WIN_HEIGHT_USAGE);
1017 }
1018 }
1019 else
1020 printf_filtered (WIN_HEIGHT_USAGE);
1021 }
1022 else
1023 printf_filtered (WIN_HEIGHT_USAGE);
1024 }
1025
1026 /* Function to adjust all window heights around the primary. */
1027 static enum tui_status
1028 tui_adjust_win_heights (struct tui_win_info *primary_win_info,
1029 int new_height)
1030 {
1031 enum tui_status status = TUI_FAILURE;
1032
1033 if (new_height_ok (primary_win_info, new_height))
1034 {
1035 status = TUI_SUCCESS;
1036 if (new_height != primary_win_info->height)
1037 {
1038 int diff;
1039 struct tui_win_info *win_info;
1040 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
1041 enum tui_layout_type cur_layout = tui_current_layout ();
1042 int width = tui_term_width ();
1043
1044 diff = (new_height - primary_win_info->height) * (-1);
1045 if (cur_layout == SRC_COMMAND
1046 || cur_layout == DISASSEM_COMMAND)
1047 {
1048 struct tui_win_info *src_win_info;
1049
1050 primary_win_info->resize (new_height, width,
1051 0, primary_win_info->origin.y);
1052 if (primary_win_info->type == CMD_WIN)
1053 {
1054 win_info = *(tui_source_windows ().begin ());
1055 src_win_info = win_info;
1056 }
1057 else
1058 {
1059 win_info = tui_win_list[CMD_WIN];
1060 src_win_info = primary_win_info;
1061 }
1062 win_info->resize (win_info->height + diff, width,
1063 0, win_info->origin.y);
1064 TUI_CMD_WIN->origin.y = locator->origin.y + 1;
1065 if ((src_win_info->type == SRC_WIN
1066 || src_win_info->type == DISASSEM_WIN))
1067 {
1068 tui_source_window_base *src_base
1069 = (tui_source_window_base *) src_win_info;
1070 if (src_base->content.empty ())
1071 src_base->erase_source_content ();
1072 }
1073 }
1074 else
1075 {
1076 struct tui_win_info *first_win;
1077 struct tui_source_window_base *second_win;
1078 tui_source_window_base *src1;
1079
1080 if (cur_layout == SRC_DISASSEM_COMMAND)
1081 {
1082 src1 = TUI_SRC_WIN;
1083 first_win = src1;
1084 second_win = TUI_DISASM_WIN;
1085 }
1086 else
1087 {
1088 src1 = nullptr;
1089 first_win = TUI_DATA_WIN;
1090 second_win = *(tui_source_windows ().begin ());
1091 }
1092 if (primary_win_info == TUI_CMD_WIN)
1093 { /* Split the change in height across the 1st & 2nd
1094 windows, adjusting them as well. */
1095 /* Subtract the locator. */
1096 int first_split_diff = diff / 2;
1097 int second_split_diff = first_split_diff;
1098
1099 if (diff % 2)
1100 {
1101 if (first_win->height >
1102 second_win->height)
1103 if (diff < 0)
1104 first_split_diff--;
1105 else
1106 first_split_diff++;
1107 else
1108 {
1109 if (diff < 0)
1110 second_split_diff--;
1111 else
1112 second_split_diff++;
1113 }
1114 }
1115 /* Make sure that the minimum heights are
1116 honored. */
1117 while ((first_win->height + first_split_diff) < 3)
1118 {
1119 first_split_diff++;
1120 second_split_diff--;
1121 }
1122 while ((second_win->height + second_split_diff) < 3)
1123 {
1124 second_split_diff++;
1125 first_split_diff--;
1126 }
1127 first_win->resize (first_win->height + first_split_diff,
1128 width,
1129 0, first_win->origin.y);
1130 second_win->resize (second_win->height + second_split_diff,
1131 width,
1132 0, first_win->height - 1);
1133 locator->resize (1, width,
1134 0, (second_win->origin.y
1135 + second_win->height + 1));
1136
1137 TUI_CMD_WIN->resize (new_height, width,
1138 0, locator->origin.y + 1);
1139 }
1140 else
1141 {
1142 if ((TUI_CMD_WIN->height + diff) < 1)
1143 { /* If there is no way to increase the command
1144 window take real estate from the 1st or 2nd
1145 window. */
1146 if ((TUI_CMD_WIN->height + diff) < 1)
1147 {
1148 int i;
1149
1150 for (i = TUI_CMD_WIN->height + diff;
1151 (i < 1); i++)
1152 if (primary_win_info == first_win)
1153 second_win->height--;
1154 else
1155 first_win->height--;
1156 }
1157 }
1158 if (primary_win_info == first_win)
1159 first_win->resize (new_height, width, 0, 0);
1160 else
1161 first_win->resize (first_win->height, width, 0, 0);
1162 second_win->origin.y = first_win->height - 1;
1163 if (primary_win_info == second_win)
1164 second_win->resize (new_height, width,
1165 0, first_win->height - 1);
1166 else
1167 second_win->resize (second_win->height, width,
1168 0, first_win->height - 1);
1169 locator->resize (1, width,
1170 0, (second_win->origin.y
1171 + second_win->height + 1));
1172 TUI_CMD_WIN->origin.y = locator->origin.y + 1;
1173 if ((TUI_CMD_WIN->height + diff) < 1)
1174 TUI_CMD_WIN->resize (1, width, 0, locator->origin.y + 1);
1175 else
1176 TUI_CMD_WIN->resize (TUI_CMD_WIN->height + diff, width,
1177 0, locator->origin.y + 1);
1178 }
1179 if (src1 != nullptr && src1->content.empty ())
1180 src1->erase_source_content ();
1181 if (second_win->content.empty ())
1182 second_win->erase_source_content ();
1183 }
1184 }
1185 }
1186
1187 return status;
1188 }
1189
1190 /* See tui-data.h. */
1191
1192 int
1193 tui_win_info::max_height () const
1194 {
1195 return tui_term_height () - 2;
1196 }
1197
1198 static int
1199 new_height_ok (struct tui_win_info *primary_win_info,
1200 int new_height)
1201 {
1202 int ok = (new_height < tui_term_height ());
1203
1204 if (ok)
1205 {
1206 int diff;
1207 enum tui_layout_type cur_layout = tui_current_layout ();
1208
1209 diff = (new_height - primary_win_info->height) * (-1);
1210 if (cur_layout == SRC_COMMAND || cur_layout == DISASSEM_COMMAND)
1211 {
1212 ok = (new_height <= primary_win_info->max_height ()
1213 && new_height >= MIN_CMD_WIN_HEIGHT);
1214 if (ok)
1215 { /* Check the total height. */
1216 struct tui_win_info *win_info;
1217
1218 if (primary_win_info == TUI_CMD_WIN)
1219 win_info = *(tui_source_windows ().begin ());
1220 else
1221 win_info = TUI_CMD_WIN;
1222 ok = ((new_height +
1223 (win_info->height + diff)) <= tui_term_height ());
1224 }
1225 }
1226 else
1227 {
1228 int cur_total_height, total_height, min_height = 0;
1229 struct tui_win_info *first_win;
1230 struct tui_win_info *second_win;
1231
1232 if (cur_layout == SRC_DISASSEM_COMMAND)
1233 {
1234 first_win = TUI_SRC_WIN;
1235 second_win = TUI_DISASM_WIN;
1236 }
1237 else
1238 {
1239 first_win = TUI_DATA_WIN;
1240 second_win = *(tui_source_windows ().begin ());
1241 }
1242 /* We could simply add all the heights to obtain the same
1243 result but below is more explicit since we subtract 1 for
1244 the line that the first and second windows share, and add
1245 one for the locator. */
1246 total_height = cur_total_height =
1247 (first_win->height + second_win->height - 1)
1248 + TUI_CMD_WIN->height + 1; /* Locator. */
1249 if (primary_win_info == TUI_CMD_WIN)
1250 {
1251 /* Locator included since first & second win share a line. */
1252 ok = ((first_win->height +
1253 second_win->height + diff) >=
1254 (MIN_WIN_HEIGHT * 2)
1255 && new_height >= MIN_CMD_WIN_HEIGHT);
1256 if (ok)
1257 {
1258 total_height = new_height +
1259 (first_win->height +
1260 second_win->height + diff);
1261 min_height = MIN_CMD_WIN_HEIGHT;
1262 }
1263 }
1264 else
1265 {
1266 min_height = MIN_WIN_HEIGHT;
1267
1268 /* First see if we can increase/decrease the command
1269 window. And make sure that the command window is at
1270 least 1 line. */
1271 ok = ((TUI_CMD_WIN->height + diff) > 0);
1272 if (!ok)
1273 { /* Looks like we have to increase/decrease one of
1274 the other windows. */
1275 if (primary_win_info == first_win)
1276 ok = (second_win->height + diff) >= min_height;
1277 else
1278 ok = (first_win->height + diff) >= min_height;
1279 }
1280 if (ok)
1281 {
1282 if (primary_win_info == first_win)
1283 total_height = new_height +
1284 second_win->height +
1285 TUI_CMD_WIN->height + diff;
1286 else
1287 total_height = new_height +
1288 first_win->height +
1289 TUI_CMD_WIN->height + diff;
1290 }
1291 }
1292 /* Now make sure that the proposed total height doesn't
1293 exceed the old total height. */
1294 if (ok)
1295 ok = (new_height >= min_height
1296 && total_height <= cur_total_height);
1297 }
1298 }
1299
1300 return ok;
1301 }
1302
1303
1304 static void
1305 parse_scrolling_args (const char *arg,
1306 struct tui_win_info **win_to_scroll,
1307 int *num_to_scroll)
1308 {
1309 if (num_to_scroll)
1310 *num_to_scroll = 0;
1311 *win_to_scroll = tui_win_with_focus ();
1312
1313 /* First set up the default window to scroll, in case there is no
1314 window name arg. */
1315 if (arg != NULL)
1316 {
1317 char *buf_ptr;
1318
1319 /* Process the number of lines to scroll. */
1320 std::string copy = arg;
1321 buf_ptr = &copy[0];
1322 if (isdigit (*buf_ptr))
1323 {
1324 char *num_str;
1325
1326 num_str = buf_ptr;
1327 buf_ptr = strchr (buf_ptr, ' ');
1328 if (buf_ptr != NULL)
1329 {
1330 *buf_ptr = '\0';
1331 if (num_to_scroll)
1332 *num_to_scroll = atoi (num_str);
1333 buf_ptr++;
1334 }
1335 else if (num_to_scroll)
1336 *num_to_scroll = atoi (num_str);
1337 }
1338
1339 /* Process the window name if one is specified. */
1340 if (buf_ptr != NULL)
1341 {
1342 const char *wname;
1343
1344 wname = skip_spaces (buf_ptr);
1345
1346 if (*wname != '\0')
1347 {
1348 *win_to_scroll = tui_partial_win_by_name (wname);
1349
1350 if (*win_to_scroll == NULL)
1351 error (_("Unrecognized window `%s'"), wname);
1352 if (!(*win_to_scroll)->is_visible ())
1353 error (_("Window is not visible"));
1354 else if (*win_to_scroll == TUI_CMD_WIN)
1355 *win_to_scroll = *(tui_source_windows ().begin ());
1356 }
1357 }
1358 }
1359 }
1360
1361 /* Function to initialize gdb commands, for tui window
1362 manipulation. */
1363
1364 void
1365 _initialize_tui_win (void)
1366 {
1367 static struct cmd_list_element *tui_setlist;
1368 static struct cmd_list_element *tui_showlist;
1369 struct cmd_list_element *cmd;
1370
1371 /* Define the classes of commands.
1372 They will appear in the help list in the reverse of this order. */
1373 add_prefix_cmd ("tui", class_tui, set_tui_cmd,
1374 _("TUI configuration variables."),
1375 &tui_setlist, "set tui ",
1376 0 /* allow-unknown */, &setlist);
1377 add_prefix_cmd ("tui", class_tui, show_tui_cmd,
1378 _("TUI configuration variables."),
1379 &tui_showlist, "show tui ",
1380 0 /* allow-unknown */, &showlist);
1381
1382 add_com ("refresh", class_tui, tui_refresh_all_command,
1383 _("Refresh the terminal display."));
1384
1385 cmd = add_com ("tabset", class_tui, tui_set_tab_width_command, _("\
1386 Set the width (in characters) of tab stops.\n\
1387 Usage: tabset N"));
1388 deprecate_cmd (cmd, "set tui tab-width");
1389
1390 cmd = add_com ("winheight", class_tui, tui_set_win_height_command, _("\
1391 Set or modify the height of a specified window.\n"
1392 WIN_HEIGHT_USAGE
1393 "Window names are:\n\
1394 src : the source window\n\
1395 cmd : the command window\n\
1396 asm : the disassembly window\n\
1397 regs : the register display"));
1398 add_com_alias ("wh", "winheight", class_tui, 0);
1399 set_cmd_completer (cmd, winheight_completer);
1400 add_info ("win", tui_all_windows_info,
1401 _("List of all displayed windows."));
1402 cmd = add_com ("focus", class_tui, tui_set_focus_command, _("\
1403 Set focus to named window or next/prev window.\n"
1404 FOCUS_USAGE
1405 "Valid Window names are:\n\
1406 src : the source window\n\
1407 asm : the disassembly window\n\
1408 regs : the register display\n\
1409 cmd : the command window"));
1410 add_com_alias ("fs", "focus", class_tui, 0);
1411 set_cmd_completer (cmd, focus_completer);
1412 add_com ("+", class_tui, tui_scroll_forward_command, _("\
1413 Scroll window forward.\n\
1414 Usage: + [WIN] [N]"));
1415 add_com ("-", class_tui, tui_scroll_backward_command, _("\
1416 Scroll window backward.\n\
1417 Usage: - [WIN] [N]"));
1418 add_com ("<", class_tui, tui_scroll_left_command, _("\
1419 Scroll window text to the left.\n\
1420 Usage: < [WIN] [N]"));
1421 add_com (">", class_tui, tui_scroll_right_command, _("\
1422 Scroll window text to the right.\n\
1423 Usage: > [WIN] [N]"));
1424
1425 /* Define the tui control variables. */
1426 add_setshow_enum_cmd ("border-kind", no_class, tui_border_kind_enums,
1427 &tui_border_kind, _("\
1428 Set the kind of border for TUI windows."), _("\
1429 Show the kind of border for TUI windows."), _("\
1430 This variable controls the border of TUI windows:\n\
1431 space use a white space\n\
1432 ascii use ascii characters + - | for the border\n\
1433 acs use the Alternate Character Set"),
1434 tui_set_var_cmd,
1435 show_tui_border_kind,
1436 &tui_setlist, &tui_showlist);
1437
1438 add_setshow_enum_cmd ("border-mode", no_class, tui_border_mode_enums,
1439 &tui_border_mode, _("\
1440 Set the attribute mode to use for the TUI window borders."), _("\
1441 Show the attribute mode to use for the TUI window borders."), _("\
1442 This variable controls the attributes to use for the window borders:\n\
1443 normal normal display\n\
1444 standout use highlight mode of terminal\n\
1445 reverse use reverse video mode\n\
1446 half use half bright\n\
1447 half-standout use half bright and standout mode\n\
1448 bold use extra bright or bold\n\
1449 bold-standout use extra bright or bold with standout mode"),
1450 tui_set_var_cmd,
1451 show_tui_border_mode,
1452 &tui_setlist, &tui_showlist);
1453
1454 add_setshow_enum_cmd ("active-border-mode", no_class, tui_border_mode_enums,
1455 &tui_active_border_mode, _("\
1456 Set the attribute mode to use for the active TUI window border."), _("\
1457 Show the attribute mode to use for the active TUI window border."), _("\
1458 This variable controls the attributes to use for the active window border:\n\
1459 normal normal display\n\
1460 standout use highlight mode of terminal\n\
1461 reverse use reverse video mode\n\
1462 half use half bright\n\
1463 half-standout use half bright and standout mode\n\
1464 bold use extra bright or bold\n\
1465 bold-standout use extra bright or bold with standout mode"),
1466 tui_set_var_cmd,
1467 show_tui_active_border_mode,
1468 &tui_setlist, &tui_showlist);
1469
1470 add_setshow_zuinteger_cmd ("tab-width", no_class,
1471 &internal_tab_width, _("\
1472 Set the tab width, in characters, for the TUI."), _("\
1473 Show the tab witdh, in characters, for the TUI."), _("\
1474 This variable controls how many spaces are used to display a tab character."),
1475 tui_set_tab_width, tui_show_tab_width,
1476 &tui_setlist, &tui_showlist);
1477
1478 add_setshow_boolean_cmd ("tui-resize-message", class_maintenance,
1479 &resize_message, _("\
1480 Set TUI resize messaging."), _("\
1481 Show TUI resize messaging."), _("\
1482 When enabled GDB will print a message when the terminal is resized."),
1483 nullptr,
1484 show_tui_resize_message,
1485 &maintenance_set_cmdlist,
1486 &maintenance_show_cmdlist);
1487 }
This page took 0.066112 seconds and 4 git commands to generate.