1 /* TUI layout window management.
3 Copyright (C) 1998-2019 Free Software Foundation, Inc.
5 Contributed by Hewlett-Packard Company.
7 This file is part of GDB.
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.
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.
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/>. */
23 #include "arch-utils.h"
31 #include "tui/tui-data.h"
32 #include "tui/tui-windata.h"
33 #include "tui/tui-wingeneral.h"
34 #include "tui/tui-stack.h"
35 #include "tui/tui-regs.h"
36 #include "tui/tui-win.h"
37 #include "tui/tui-winsource.h"
38 #include "tui/tui-disasm.h"
39 #include "tui/tui-layout.h"
40 #include "gdb_curses.h"
42 /*******************************
44 ********************************/
45 static void show_layout (enum tui_layout_type);
46 static tui_gen_win_info *init_and_make_win (tui_gen_win_info *,
50 static void show_source_or_disasm_and_command (enum tui_layout_type);
51 static struct tui_win_info *make_command_window (int, int);
52 static struct tui_win_info *make_source_window (int, int);
53 static struct tui_win_info *make_disasm_window (int, int);
54 static void show_source_command (void);
55 static void show_disasm_command (void);
56 static void show_source_disasm_command (void);
57 static void show_data (enum tui_layout_type);
58 static enum tui_layout_type next_layout (void);
59 static enum tui_layout_type prev_layout (void);
60 static void tui_layout_command (const char *, int);
61 static void extract_display_start_addr (struct gdbarch **, CORE_ADDR *);
64 /***************************************
66 ***************************************/
68 #define LAYOUT_USAGE "Usage: layout prev | next | <layout_name> \n"
70 /* Show the screen layout defined. */
72 show_layout (enum tui_layout_type layout)
74 enum tui_layout_type cur_layout = tui_current_layout ();
76 if (layout != cur_layout)
78 /* Since the new layout may cause changes in window size, we
79 should free the content and reallocate on next display of
81 tui_clear_source_windows ();
82 if (layout == SRC_DATA_COMMAND
83 || layout == DISASSEM_DATA_COMMAND)
90 /* First make the current layout be invisible. */
91 tui_make_all_invisible ();
92 tui_make_invisible (tui_locator_win_info_ptr ());
96 /* Now show the new layout. */
98 show_source_command ();
99 tui_add_to_source_windows (TUI_SRC_WIN);
101 case DISASSEM_COMMAND:
102 show_disasm_command ();
103 tui_add_to_source_windows (TUI_DISASM_WIN);
105 case SRC_DISASSEM_COMMAND:
106 show_source_disasm_command ();
107 tui_add_to_source_windows (TUI_SRC_WIN);
108 tui_add_to_source_windows (TUI_DISASM_WIN);
118 /* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
119 SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. */
121 tui_set_layout (enum tui_layout_type layout_type)
123 enum tui_status status = TUI_SUCCESS;
125 if (layout_type != UNDEFINED_LAYOUT)
127 enum tui_layout_type cur_layout = tui_current_layout ();
128 struct gdbarch *gdbarch;
130 struct tui_win_info *win_with_focus = tui_win_with_focus ();
131 struct tui_layout_def *layout_def = tui_layout_def ();
133 extract_display_start_addr (&gdbarch, &addr);
135 enum tui_layout_type new_layout = layout_type;
137 if (new_layout != cur_layout)
139 show_layout (new_layout);
141 /* Now determine where focus should be. */
142 if (win_with_focus != TUI_CMD_WIN)
147 tui_set_win_focus_to (TUI_SRC_WIN);
148 layout_def->display_mode = SRC_WIN;
150 case DISASSEM_COMMAND:
151 /* The previous layout was not showing code.
152 This can happen if there is no source
155 1. if the source file is in another dir OR
156 2. if target was compiled without -g
157 We still want to show the assembly though! */
159 tui_get_begin_asm_address (&gdbarch, &addr);
160 tui_set_win_focus_to (TUI_DISASM_WIN);
161 layout_def->display_mode = DISASSEM_WIN;
163 case SRC_DISASSEM_COMMAND:
164 /* The previous layout was not showing code.
165 This can happen if there is no source
168 1. if the source file is in another dir OR
169 2. if target was compiled without -g
170 We still want to show the assembly though! */
172 tui_get_begin_asm_address (&gdbarch, &addr);
173 if (win_with_focus == TUI_SRC_WIN)
174 tui_set_win_focus_to (TUI_SRC_WIN);
176 tui_set_win_focus_to (TUI_DISASM_WIN);
178 case SRC_DATA_COMMAND:
179 if (win_with_focus != TUI_DATA_WIN)
180 tui_set_win_focus_to (TUI_SRC_WIN);
182 tui_set_win_focus_to (TUI_DATA_WIN);
183 layout_def->display_mode = SRC_WIN;
185 case DISASSEM_DATA_COMMAND:
186 /* The previous layout was not showing code.
187 This can happen if there is no source
190 1. if the source file is in another dir OR
191 2. if target was compiled without -g
192 We still want to show the assembly though! */
194 tui_get_begin_asm_address (&gdbarch, &addr);
195 if (win_with_focus != TUI_DATA_WIN)
196 tui_set_win_focus_to (TUI_DISASM_WIN);
198 tui_set_win_focus_to (TUI_DATA_WIN);
199 layout_def->display_mode = DISASSEM_WIN;
206 * Now update the window content.
208 tui_update_source_windows_with_addr (gdbarch, addr);
209 if (new_layout == SRC_DATA_COMMAND
210 || new_layout == DISASSEM_DATA_COMMAND)
211 tui_show_registers (TUI_DATA_WIN->current_group);
215 status = TUI_FAILURE;
220 /* Add the specified window to the layout in a logical way. This
221 means setting up the most logical layout given the window to be
224 tui_add_win_to_layout (enum tui_win_type type)
226 enum tui_layout_type cur_layout = tui_current_layout ();
231 if (cur_layout != SRC_COMMAND
232 && cur_layout != SRC_DISASSEM_COMMAND
233 && cur_layout != SRC_DATA_COMMAND)
235 tui_clear_source_windows_detail ();
236 if (cur_layout == DISASSEM_DATA_COMMAND)
237 show_layout (SRC_DATA_COMMAND);
239 show_layout (SRC_COMMAND);
243 if (cur_layout != DISASSEM_COMMAND
244 && cur_layout != SRC_DISASSEM_COMMAND
245 && cur_layout != DISASSEM_DATA_COMMAND)
247 tui_clear_source_windows_detail ();
248 if (cur_layout == SRC_DATA_COMMAND)
249 show_layout (DISASSEM_DATA_COMMAND);
251 show_layout (DISASSEM_COMMAND);
255 if (cur_layout != SRC_DATA_COMMAND
256 && cur_layout != DISASSEM_DATA_COMMAND)
258 if (cur_layout == DISASSEM_COMMAND)
259 show_layout (DISASSEM_DATA_COMMAND);
261 show_layout (SRC_DATA_COMMAND);
270 /* Answer the height of a window. If it hasn't been created yet,
271 answer what the height of a window would be based upon its type and
274 tui_default_win_height (enum tui_win_type type,
275 enum tui_layout_type layout)
279 if (tui_win_list[type] != NULL)
280 h = tui_win_list[type]->height;
286 case DISASSEM_COMMAND:
287 if (TUI_CMD_WIN == NULL)
288 h = tui_term_height () / 2;
290 h = tui_term_height () - TUI_CMD_WIN->height;
292 case SRC_DISASSEM_COMMAND:
293 case SRC_DATA_COMMAND:
294 case DISASSEM_DATA_COMMAND:
295 if (TUI_CMD_WIN == NULL)
296 h = tui_term_height () / 3;
298 h = (tui_term_height () - TUI_CMD_WIN->height) / 2;
310 /* Answer the height of a window. If it hasn't been created yet,
311 answer what the height of a window would be based upon its type and
314 tui_default_win_viewport_height (enum tui_win_type type,
315 enum tui_layout_type layout)
319 h = tui_default_win_height (type, layout);
321 if (tui_win_list[type] == TUI_CMD_WIN)
329 /* Complete possible layout names. TEXT is the complete text entered so
330 far, WORD is the word currently being completed. */
333 layout_completer (struct cmd_list_element *ignore,
334 completion_tracker &tracker,
335 const char *text, const char *word)
337 static const char *layout_names [] =
338 { "src", "asm", "split", "regs", "next", "prev", NULL };
340 complete_on_enum (tracker, layout_names, text, word);
343 /* Function to initialize gdb commands, for tui window layout
347 _initialize_tui_layout (void)
349 struct cmd_list_element *cmd;
351 cmd = add_com ("layout", class_tui, tui_layout_command, _("\
352 Change the layout of windows.\n\
353 Usage: layout prev | next | LAYOUT-NAME\n\
355 src : Displays source and command windows.\n\
356 asm : Displays disassembly and command windows.\n\
357 split : Displays source, disassembly and command windows.\n\
358 regs : Displays register window. If existing layout\n\
359 is source/command or assembly/command, the \n\
360 register window is displayed. If the\n\
361 source/assembly/command (split) is displayed, \n\
362 the register window is displayed with \n\
363 the window that has current logical focus."));
364 set_cmd_completer (cmd, layout_completer);
368 /*************************
369 ** STATIC LOCAL FUNCTIONS
370 **************************/
373 /* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
376 tui_set_layout_by_name (const char *layout_name)
378 enum tui_status status = TUI_SUCCESS;
380 if (layout_name != NULL)
383 enum tui_layout_type new_layout = UNDEFINED_LAYOUT;
384 enum tui_layout_type cur_layout = tui_current_layout ();
386 std::string copy = layout_name;
387 for (i = 0; i < copy.size (); i++)
388 copy[i] = toupper (copy[i]);
389 const char *buf_ptr = copy.c_str ();
391 /* First check for ambiguous input. */
392 if (strlen (buf_ptr) <= 1 && *buf_ptr == 'S')
394 warning (_("Ambiguous command input."));
395 status = TUI_FAILURE;
399 if (subset_compare (buf_ptr, "SRC"))
400 new_layout = SRC_COMMAND;
401 else if (subset_compare (buf_ptr, "ASM"))
402 new_layout = DISASSEM_COMMAND;
403 else if (subset_compare (buf_ptr, "SPLIT"))
404 new_layout = SRC_DISASSEM_COMMAND;
405 else if (subset_compare (buf_ptr, "REGS"))
407 if (cur_layout == SRC_COMMAND
408 || cur_layout == SRC_DATA_COMMAND)
409 new_layout = SRC_DATA_COMMAND;
411 new_layout = DISASSEM_DATA_COMMAND;
413 else if (subset_compare (buf_ptr, "NEXT"))
414 new_layout = next_layout ();
415 else if (subset_compare (buf_ptr, "PREV"))
416 new_layout = prev_layout ();
418 status = TUI_FAILURE;
420 if (status == TUI_SUCCESS)
422 /* Make sure the curses mode is enabled. */
424 tui_set_layout (new_layout);
429 status = TUI_FAILURE;
436 extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
438 enum tui_layout_type cur_layout = tui_current_layout ();
439 struct gdbarch *gdbarch = get_current_arch ();
442 struct symtab_and_line cursal = get_current_source_symtab_and_line ();
447 case SRC_DATA_COMMAND:
448 gdbarch = TUI_SRC_WIN->gdbarch;
449 find_line_pc (cursal.symtab,
450 TUI_SRC_WIN->start_line_or_addr.u.line_no,
454 case DISASSEM_COMMAND:
455 case SRC_DISASSEM_COMMAND:
456 case DISASSEM_DATA_COMMAND:
457 gdbarch = TUI_DISASM_WIN->gdbarch;
458 addr = TUI_DISASM_WIN->start_line_or_addr.u.addr;
465 *gdbarch_p = gdbarch;
471 tui_layout_command (const char *arg, int from_tty)
473 /* Switch to the selected layout. */
474 if (tui_set_layout_by_name (arg) != TUI_SUCCESS)
475 warning (_("Invalid layout specified.\n%s"), LAYOUT_USAGE);
478 /* Answer the previous layout to cycle to. */
479 static enum tui_layout_type
484 new_layout = tui_current_layout ();
485 if (new_layout == UNDEFINED_LAYOUT)
486 new_layout = SRC_COMMAND;
490 if (new_layout == UNDEFINED_LAYOUT)
491 new_layout = SRC_COMMAND;
494 return (enum tui_layout_type) new_layout;
498 /* Answer the next layout to cycle to. */
499 static enum tui_layout_type
504 new_layout = tui_current_layout ();
505 if (new_layout == SRC_COMMAND)
506 new_layout = DISASSEM_DATA_COMMAND;
510 if (new_layout == UNDEFINED_LAYOUT)
511 new_layout = DISASSEM_DATA_COMMAND;
514 return (enum tui_layout_type) new_layout;
519 static struct tui_win_info *
520 make_command_window (int height, int origin_y)
522 struct tui_win_info *result = new tui_cmd_window ();
523 result->reset (CMD_WIN, height, tui_term_width (), 0, origin_y);
524 tui_make_window (result, DONT_BOX_WINDOW);
529 /* make_source_window().
531 static struct tui_win_info *
532 make_source_window (int height, int origin_y)
534 tui_win_info *result = new tui_source_window ();
535 result->reset (SRC_WIN, height, tui_term_width (), 0, origin_y);
536 result->make_visible (true);
541 /* make_disasm_window().
543 static struct tui_win_info *
544 make_disasm_window (int height, int origin_y)
546 tui_win_info *result = new tui_disasm_window ();
547 result->reset (SRC_WIN, height, tui_term_width (), 0, origin_y);
548 result->make_visible (true);
553 static tui_win_info *
554 make_data_window (int height, int origin_y)
556 tui_win_info *result = new tui_data_window ();
557 result->reset (DATA_WIN, height, tui_term_width (), 0, origin_y);
558 result->make_visible (true);
564 /* Show the Source/Command layout. */
566 show_source_command (void)
568 show_source_or_disasm_and_command (SRC_COMMAND);
572 /* Show the Dissassem/Command layout. */
574 show_disasm_command (void)
576 show_source_or_disasm_and_command (DISASSEM_COMMAND);
580 /* Show the Source/Disassem/Command layout. */
582 show_source_disasm_command (void)
584 if (tui_current_layout () != SRC_DISASSEM_COMMAND)
586 int cmd_height, src_height, asm_height;
588 if (TUI_CMD_WIN != NULL)
589 cmd_height = TUI_CMD_WIN->height;
591 cmd_height = tui_term_height () / 3;
593 src_height = (tui_term_height () - cmd_height) / 2;
594 asm_height = tui_term_height () - (src_height + cmd_height);
596 if (TUI_SRC_WIN == NULL)
597 tui_win_list[SRC_WIN] = make_source_window (src_height, 0);
600 TUI_SRC_WIN->reset (TUI_SRC_WIN->type,
605 tui_make_visible (TUI_SRC_WIN);
606 TUI_SRC_WIN->m_has_locator = false;
609 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
610 gdb_assert (locator != nullptr);
612 tui_show_source_content (TUI_SRC_WIN);
613 if (TUI_DISASM_WIN == NULL)
615 tui_win_list[DISASSEM_WIN]
616 = make_disasm_window (asm_height, src_height - 1);
617 init_and_make_win (locator,
622 (src_height + asm_height) - 1,
627 locator->reset (LOCATOR_WIN,
631 (src_height + asm_height) - 1);
632 TUI_DISASM_WIN->m_has_locator = true;
633 TUI_DISASM_WIN->reset (TUI_DISASM_WIN->type,
638 tui_make_visible (TUI_DISASM_WIN);
640 TUI_SRC_WIN->m_has_locator = false;
641 TUI_DISASM_WIN->m_has_locator = true;
642 tui_make_visible (locator);
643 tui_show_locator_content ();
644 tui_show_source_content (TUI_DISASM_WIN);
646 if (TUI_CMD_WIN == NULL)
647 tui_win_list[CMD_WIN]
648 = make_command_window (cmd_height, tui_term_height () - cmd_height);
651 TUI_CMD_WIN->reset (TUI_CMD_WIN->type,
655 TUI_CMD_WIN->origin.y);
656 tui_make_visible (TUI_CMD_WIN);
658 tui_set_current_layout_to (SRC_DISASSEM_COMMAND);
663 /* Show the Source/Data/Command or the Dissassembly/Data/Command
666 show_data (enum tui_layout_type new_layout)
668 int total_height = (tui_term_height () - TUI_CMD_WIN->height);
669 int src_height, data_height;
670 enum tui_win_type win_type;
672 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
673 gdb_assert (locator != nullptr);
675 data_height = total_height / 2;
676 src_height = total_height - data_height;
677 tui_make_all_invisible ();
678 tui_make_invisible (locator);
679 if (tui_win_list[DATA_WIN] == nullptr)
680 tui_win_list[DATA_WIN] = make_data_window (data_height, 0);
682 tui_win_list[DATA_WIN]->reset (data_height, tui_term_width (), 0, 0);
683 tui_win_list[DATA_WIN]->make_visible (true);
685 if (new_layout == SRC_DATA_COMMAND)
688 win_type = DISASSEM_WIN;
690 tui_source_window_base *base;
691 if (tui_win_list[win_type] == NULL)
693 if (win_type == SRC_WIN)
694 tui_win_list[win_type]
695 = make_source_window (src_height, data_height - 1);
697 tui_win_list[win_type]
698 = make_disasm_window (src_height, data_height - 1);
699 init_and_make_win (locator,
706 base = (tui_source_window_base *) tui_win_list[win_type];
710 base = (tui_source_window_base *) tui_win_list[win_type];
711 tui_win_list[win_type]->reset (tui_win_list[win_type]->type,
716 tui_make_visible (tui_win_list[win_type]);
717 locator->reset (LOCATOR_WIN,
723 base->m_has_locator = true;
724 tui_make_visible (locator);
725 tui_show_locator_content ();
726 tui_add_to_source_windows
727 ((tui_source_window_base *) tui_win_list[win_type]);
728 tui_set_current_layout_to (new_layout);
732 tui_gen_win_info::reset (enum tui_win_type win_type,
733 int height_, int width_,
734 int origin_x_, int origin_y_)
738 gdb_assert (type == win_type);
744 viewport_height = h - 1;
750 origin.x = origin_x_;
751 origin.y = origin_y_;
754 /* init_and_make_win().
756 static tui_gen_win_info *
757 init_and_make_win (tui_gen_win_info *win_info,
758 enum tui_win_type win_type,
759 int height, int width,
760 int origin_x, int origin_y,
763 if (win_info == NULL)
768 win_info = new tui_source_window ();
772 win_info = new tui_disasm_window ();
776 win_info = new tui_data_window ();
780 win_info = new tui_cmd_window ();
784 win_info = new tui_exec_info_window ();
788 gdb_assert_not_reached (_("unhandled window type"));
792 win_info->reset (win_type, height, width, origin_x, origin_y);
793 tui_make_window (win_info, box_it);
799 /* Show the Source/Command or the Disassem layout. */
801 show_source_or_disasm_and_command (enum tui_layout_type layout_type)
803 if (tui_current_layout () != layout_type)
805 struct tui_win_info **win_info_ptr;
806 int src_height, cmd_height;
807 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
808 gdb_assert (locator != nullptr);
810 if (TUI_CMD_WIN != NULL)
811 cmd_height = TUI_CMD_WIN->height;
813 cmd_height = tui_term_height () / 3;
814 src_height = tui_term_height () - cmd_height;
816 if (layout_type == SRC_COMMAND)
817 win_info_ptr = &tui_win_list[SRC_WIN];
819 win_info_ptr = &tui_win_list[DISASSEM_WIN];
821 tui_source_window_base *base;
822 if ((*win_info_ptr) == NULL)
824 if (layout_type == SRC_COMMAND)
825 *win_info_ptr = make_source_window (src_height - 1, 0);
827 *win_info_ptr = make_disasm_window (src_height - 1, 0);
828 init_and_make_win (locator,
835 base = (tui_source_window_base *) *win_info_ptr;
839 base = (tui_source_window_base *) *win_info_ptr;
840 locator->reset (LOCATOR_WIN,
845 base->m_has_locator = true;
846 (*win_info_ptr)->reset ((*win_info_ptr)->type,
851 tui_make_visible (*win_info_ptr);
854 base->m_has_locator = true;
855 tui_make_visible (locator);
856 tui_show_locator_content ();
857 tui_show_source_content (base);
859 if (TUI_CMD_WIN == NULL)
861 tui_win_list[CMD_WIN] = make_command_window (cmd_height,
866 TUI_CMD_WIN->reset (TUI_CMD_WIN->type,
869 TUI_CMD_WIN->origin.x,
870 TUI_CMD_WIN->origin.y);
871 tui_make_visible (TUI_CMD_WIN);
873 tui_set_current_layout_to (layout_type);