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_source_or_disasm_window (enum tui_win_type,
53 static struct tui_win_info *make_command_window (int, int);
54 static struct tui_win_info *make_source_window (int, int);
55 static struct tui_win_info *make_disasm_window (int, int);
56 static void make_data_window (struct tui_win_info **, int, int);
57 static void show_source_command (void);
58 static void show_disasm_command (void);
59 static void show_source_disasm_command (void);
60 static void show_data (enum tui_layout_type);
61 static enum tui_layout_type next_layout (void);
62 static enum tui_layout_type prev_layout (void);
63 static void tui_layout_command (const char *, int);
64 static void extract_display_start_addr (struct gdbarch **, CORE_ADDR *);
67 /***************************************
69 ***************************************/
71 #define LAYOUT_USAGE "Usage: layout prev | next | <layout_name> \n"
73 /* Show the screen layout defined. */
75 show_layout (enum tui_layout_type layout)
77 enum tui_layout_type cur_layout = tui_current_layout ();
79 if (layout != cur_layout)
81 /* Since the new layout may cause changes in window size, we
82 should free the content and reallocate on next display of
84 tui_clear_source_windows ();
85 if (layout == SRC_DATA_COMMAND
86 || layout == DISASSEM_DATA_COMMAND)
93 /* First make the current layout be invisible. */
94 tui_make_all_invisible ();
95 tui_make_invisible (tui_locator_win_info_ptr ());
99 /* Now show the new layout. */
101 show_source_command ();
102 tui_add_to_source_windows (TUI_SRC_WIN);
104 case DISASSEM_COMMAND:
105 show_disasm_command ();
106 tui_add_to_source_windows (TUI_DISASM_WIN);
108 case SRC_DISASSEM_COMMAND:
109 show_source_disasm_command ();
110 tui_add_to_source_windows (TUI_SRC_WIN);
111 tui_add_to_source_windows (TUI_DISASM_WIN);
121 /* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
122 SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. */
124 tui_set_layout (enum tui_layout_type layout_type)
126 enum tui_status status = TUI_SUCCESS;
128 if (layout_type != UNDEFINED_LAYOUT)
130 enum tui_layout_type cur_layout = tui_current_layout ();
131 struct gdbarch *gdbarch;
133 struct tui_win_info *win_with_focus = tui_win_with_focus ();
134 struct tui_layout_def *layout_def = tui_layout_def ();
136 extract_display_start_addr (&gdbarch, &addr);
138 enum tui_layout_type new_layout = layout_type;
140 if (new_layout != cur_layout)
142 show_layout (new_layout);
144 /* Now determine where focus should be. */
145 if (win_with_focus != TUI_CMD_WIN)
150 tui_set_win_focus_to (TUI_SRC_WIN);
151 layout_def->display_mode = SRC_WIN;
153 case DISASSEM_COMMAND:
154 /* The previous layout was not showing code.
155 This can happen if there is no source
158 1. if the source file is in another dir OR
159 2. if target was compiled without -g
160 We still want to show the assembly though! */
162 tui_get_begin_asm_address (&gdbarch, &addr);
163 tui_set_win_focus_to (TUI_DISASM_WIN);
164 layout_def->display_mode = DISASSEM_WIN;
166 case SRC_DISASSEM_COMMAND:
167 /* The previous layout was not showing code.
168 This can happen if there is no source
171 1. if the source file is in another dir OR
172 2. if target was compiled without -g
173 We still want to show the assembly though! */
175 tui_get_begin_asm_address (&gdbarch, &addr);
176 if (win_with_focus == TUI_SRC_WIN)
177 tui_set_win_focus_to (TUI_SRC_WIN);
179 tui_set_win_focus_to (TUI_DISASM_WIN);
181 case SRC_DATA_COMMAND:
182 if (win_with_focus != TUI_DATA_WIN)
183 tui_set_win_focus_to (TUI_SRC_WIN);
185 tui_set_win_focus_to (TUI_DATA_WIN);
186 layout_def->display_mode = SRC_WIN;
188 case DISASSEM_DATA_COMMAND:
189 /* The previous layout was not showing code.
190 This can happen if there is no source
193 1. if the source file is in another dir OR
194 2. if target was compiled without -g
195 We still want to show the assembly though! */
197 tui_get_begin_asm_address (&gdbarch, &addr);
198 if (win_with_focus != TUI_DATA_WIN)
199 tui_set_win_focus_to (TUI_DISASM_WIN);
201 tui_set_win_focus_to (TUI_DATA_WIN);
202 layout_def->display_mode = DISASSEM_WIN;
209 * Now update the window content.
211 tui_update_source_windows_with_addr (gdbarch, addr);
212 if (new_layout == SRC_DATA_COMMAND
213 || new_layout == DISASSEM_DATA_COMMAND)
214 tui_show_registers (TUI_DATA_WIN->current_group);
218 status = TUI_FAILURE;
223 /* Add the specified window to the layout in a logical way. This
224 means setting up the most logical layout given the window to be
227 tui_add_win_to_layout (enum tui_win_type type)
229 enum tui_layout_type cur_layout = tui_current_layout ();
234 if (cur_layout != SRC_COMMAND
235 && cur_layout != SRC_DISASSEM_COMMAND
236 && cur_layout != SRC_DATA_COMMAND)
238 tui_clear_source_windows_detail ();
239 if (cur_layout == DISASSEM_DATA_COMMAND)
240 show_layout (SRC_DATA_COMMAND);
242 show_layout (SRC_COMMAND);
246 if (cur_layout != DISASSEM_COMMAND
247 && cur_layout != SRC_DISASSEM_COMMAND
248 && cur_layout != DISASSEM_DATA_COMMAND)
250 tui_clear_source_windows_detail ();
251 if (cur_layout == SRC_DATA_COMMAND)
252 show_layout (DISASSEM_DATA_COMMAND);
254 show_layout (DISASSEM_COMMAND);
258 if (cur_layout != SRC_DATA_COMMAND
259 && cur_layout != DISASSEM_DATA_COMMAND)
261 if (cur_layout == DISASSEM_COMMAND)
262 show_layout (DISASSEM_DATA_COMMAND);
264 show_layout (SRC_DATA_COMMAND);
273 /* Answer the height of a window. If it hasn't been created yet,
274 answer what the height of a window would be based upon its type and
277 tui_default_win_height (enum tui_win_type type,
278 enum tui_layout_type layout)
282 if (tui_win_list[type] != NULL)
283 h = tui_win_list[type]->height;
289 case DISASSEM_COMMAND:
290 if (TUI_CMD_WIN == NULL)
291 h = tui_term_height () / 2;
293 h = tui_term_height () - TUI_CMD_WIN->height;
295 case SRC_DISASSEM_COMMAND:
296 case SRC_DATA_COMMAND:
297 case DISASSEM_DATA_COMMAND:
298 if (TUI_CMD_WIN == NULL)
299 h = tui_term_height () / 3;
301 h = (tui_term_height () - TUI_CMD_WIN->height) / 2;
313 /* Answer the height of a window. If it hasn't been created yet,
314 answer what the height of a window would be based upon its type and
317 tui_default_win_viewport_height (enum tui_win_type type,
318 enum tui_layout_type layout)
322 h = tui_default_win_height (type, layout);
324 if (tui_win_list[type] == TUI_CMD_WIN)
332 /* Complete possible layout names. TEXT is the complete text entered so
333 far, WORD is the word currently being completed. */
336 layout_completer (struct cmd_list_element *ignore,
337 completion_tracker &tracker,
338 const char *text, const char *word)
340 static const char *layout_names [] =
341 { "src", "asm", "split", "regs", "next", "prev", NULL };
343 complete_on_enum (tracker, layout_names, text, word);
346 /* Function to initialize gdb commands, for tui window layout
350 _initialize_tui_layout (void)
352 struct cmd_list_element *cmd;
354 cmd = add_com ("layout", class_tui, tui_layout_command, _("\
355 Change the layout of windows.\n\
356 Usage: layout prev | next | LAYOUT-NAME\n\
358 src : Displays source and command windows.\n\
359 asm : Displays disassembly and command windows.\n\
360 split : Displays source, disassembly and command windows.\n\
361 regs : Displays register window. If existing layout\n\
362 is source/command or assembly/command, the \n\
363 register window is displayed. If the\n\
364 source/assembly/command (split) is displayed, \n\
365 the register window is displayed with \n\
366 the window that has current logical focus."));
367 set_cmd_completer (cmd, layout_completer);
371 /*************************
372 ** STATIC LOCAL FUNCTIONS
373 **************************/
376 /* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
379 tui_set_layout_by_name (const char *layout_name)
381 enum tui_status status = TUI_SUCCESS;
383 if (layout_name != NULL)
386 enum tui_layout_type new_layout = UNDEFINED_LAYOUT;
387 enum tui_layout_type cur_layout = tui_current_layout ();
389 std::string copy = layout_name;
390 for (i = 0; i < copy.size (); i++)
391 copy[i] = toupper (copy[i]);
392 const char *buf_ptr = copy.c_str ();
394 /* First check for ambiguous input. */
395 if (strlen (buf_ptr) <= 1 && *buf_ptr == 'S')
397 warning (_("Ambiguous command input."));
398 status = TUI_FAILURE;
402 if (subset_compare (buf_ptr, "SRC"))
403 new_layout = SRC_COMMAND;
404 else if (subset_compare (buf_ptr, "ASM"))
405 new_layout = DISASSEM_COMMAND;
406 else if (subset_compare (buf_ptr, "SPLIT"))
407 new_layout = SRC_DISASSEM_COMMAND;
408 else if (subset_compare (buf_ptr, "REGS"))
410 if (cur_layout == SRC_COMMAND
411 || cur_layout == SRC_DATA_COMMAND)
412 new_layout = SRC_DATA_COMMAND;
414 new_layout = DISASSEM_DATA_COMMAND;
416 else if (subset_compare (buf_ptr, "NEXT"))
417 new_layout = next_layout ();
418 else if (subset_compare (buf_ptr, "PREV"))
419 new_layout = prev_layout ();
421 status = TUI_FAILURE;
423 if (status == TUI_SUCCESS)
425 /* Make sure the curses mode is enabled. */
427 tui_set_layout (new_layout);
432 status = TUI_FAILURE;
439 extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
441 enum tui_layout_type cur_layout = tui_current_layout ();
442 struct gdbarch *gdbarch = get_current_arch ();
445 struct symtab_and_line cursal = get_current_source_symtab_and_line ();
450 case SRC_DATA_COMMAND:
451 gdbarch = TUI_SRC_WIN->gdbarch;
452 find_line_pc (cursal.symtab,
453 TUI_SRC_WIN->start_line_or_addr.u.line_no,
457 case DISASSEM_COMMAND:
458 case SRC_DISASSEM_COMMAND:
459 case DISASSEM_DATA_COMMAND:
460 gdbarch = TUI_DISASM_WIN->gdbarch;
461 addr = TUI_DISASM_WIN->start_line_or_addr.u.addr;
468 *gdbarch_p = gdbarch;
474 tui_layout_command (const char *arg, int from_tty)
476 /* Switch to the selected layout. */
477 if (tui_set_layout_by_name (arg) != TUI_SUCCESS)
478 warning (_("Invalid layout specified.\n%s"), LAYOUT_USAGE);
481 /* Answer the previous layout to cycle to. */
482 static enum tui_layout_type
487 new_layout = tui_current_layout ();
488 if (new_layout == UNDEFINED_LAYOUT)
489 new_layout = SRC_COMMAND;
493 if (new_layout == UNDEFINED_LAYOUT)
494 new_layout = SRC_COMMAND;
497 return (enum tui_layout_type) new_layout;
501 /* Answer the next layout to cycle to. */
502 static enum tui_layout_type
507 new_layout = tui_current_layout ();
508 if (new_layout == SRC_COMMAND)
509 new_layout = DISASSEM_DATA_COMMAND;
513 if (new_layout == UNDEFINED_LAYOUT)
514 new_layout = DISASSEM_DATA_COMMAND;
517 return (enum tui_layout_type) new_layout;
522 static struct tui_win_info *
523 make_command_window (int height, int origin_y)
525 struct tui_win_info *result
526 = (struct tui_win_info *) init_and_make_win (NULL,
537 /* make_source_window().
539 static struct tui_win_info *
540 make_source_window (int height, int origin_y)
542 return make_source_or_disasm_window (SRC_WIN, height, origin_y);
543 } /* make_source_window */
546 /* make_disasm_window().
548 static struct tui_win_info *
549 make_disasm_window (int height, int origin_y)
551 return make_source_or_disasm_window (DISASSEM_WIN, height, origin_y);
552 } /* make_disasm_window */
556 make_data_window (struct tui_win_info **win_info_ptr,
557 int height, int origin_y)
560 = (struct tui_win_info *) init_and_make_win (*win_info_ptr,
571 /* Show the Source/Command layout. */
573 show_source_command (void)
575 show_source_or_disasm_and_command (SRC_COMMAND);
579 /* Show the Dissassem/Command layout. */
581 show_disasm_command (void)
583 show_source_or_disasm_and_command (DISASSEM_COMMAND);
587 /* Show the Source/Disassem/Command layout. */
589 show_source_disasm_command (void)
591 if (tui_current_layout () != SRC_DISASSEM_COMMAND)
593 int cmd_height, src_height, asm_height;
595 if (TUI_CMD_WIN != NULL)
596 cmd_height = TUI_CMD_WIN->height;
598 cmd_height = tui_term_height () / 3;
600 src_height = (tui_term_height () - cmd_height) / 2;
601 asm_height = tui_term_height () - (src_height + cmd_height);
603 if (TUI_SRC_WIN == NULL)
604 tui_win_list[SRC_WIN] = make_source_window (src_height, 0);
607 TUI_SRC_WIN->reset (TUI_SRC_WIN->type,
610 TUI_SRC_WIN->execution_info->width,
612 TUI_SRC_WIN->execution_info->reset (EXEC_INFO_WIN,
617 tui_make_visible (TUI_SRC_WIN);
618 tui_make_visible (TUI_SRC_WIN->execution_info);
619 TUI_SRC_WIN->m_has_locator = false;
622 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
623 gdb_assert (locator != nullptr);
625 tui_show_source_content (TUI_SRC_WIN);
626 if (TUI_DISASM_WIN == NULL)
628 tui_win_list[DISASSEM_WIN]
629 = make_disasm_window (asm_height, src_height - 1);
630 init_and_make_win (locator,
635 (src_height + asm_height) - 1,
640 locator->reset (LOCATOR_WIN,
644 (src_height + asm_height) - 1);
645 TUI_DISASM_WIN->m_has_locator = true;
646 TUI_DISASM_WIN->reset (TUI_DISASM_WIN->type,
648 TUI_DISASM_WIN->width,
649 TUI_DISASM_WIN->execution_info->width,
651 TUI_DISASM_WIN->execution_info->reset (EXEC_INFO_WIN,
656 tui_make_visible (TUI_DISASM_WIN);
657 tui_make_visible (TUI_DISASM_WIN->execution_info);
659 TUI_SRC_WIN->m_has_locator = false;
660 TUI_DISASM_WIN->m_has_locator = true;
661 tui_make_visible (locator);
662 tui_show_locator_content ();
663 tui_show_source_content (TUI_DISASM_WIN);
665 if (TUI_CMD_WIN == NULL)
666 tui_win_list[CMD_WIN]
667 = make_command_window (cmd_height, tui_term_height () - cmd_height);
670 TUI_CMD_WIN->reset (TUI_CMD_WIN->type,
674 TUI_CMD_WIN->origin.y);
675 tui_make_visible (TUI_CMD_WIN);
677 tui_set_current_layout_to (SRC_DISASSEM_COMMAND);
682 /* Show the Source/Data/Command or the Dissassembly/Data/Command
685 show_data (enum tui_layout_type new_layout)
687 int total_height = (tui_term_height () - TUI_CMD_WIN->height);
688 int src_height, data_height;
689 enum tui_win_type win_type;
691 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
692 gdb_assert (locator != nullptr);
694 data_height = total_height / 2;
695 src_height = total_height - data_height;
696 tui_make_all_invisible ();
697 tui_make_invisible (locator);
698 make_data_window (&tui_win_list[DATA_WIN], data_height, 0);
699 if (new_layout == SRC_DATA_COMMAND)
702 win_type = DISASSEM_WIN;
704 tui_source_window_base *base;
705 if (tui_win_list[win_type] == NULL)
707 if (win_type == SRC_WIN)
708 tui_win_list[win_type]
709 = make_source_window (src_height, data_height - 1);
711 tui_win_list[win_type]
712 = make_disasm_window (src_height, data_height - 1);
713 init_and_make_win (locator,
720 base = (tui_source_window_base *) tui_win_list[win_type];
724 base = (tui_source_window_base *) tui_win_list[win_type];
725 tui_win_list[win_type]->reset (tui_win_list[win_type]->type,
727 tui_win_list[win_type]->width,
728 base->execution_info->width,
730 base->execution_info->reset (EXEC_INFO_WIN,
735 tui_make_visible (tui_win_list[win_type]);
736 tui_make_visible (base->execution_info);
737 locator->reset (LOCATOR_WIN,
743 base->m_has_locator = true;
744 tui_make_visible (locator);
745 tui_show_locator_content ();
746 tui_add_to_source_windows
747 ((tui_source_window_base *) tui_win_list[win_type]);
748 tui_set_current_layout_to (new_layout);
752 tui_gen_win_info::reset (enum tui_win_type win_type,
753 int height_, int width_,
754 int origin_x_, int origin_y_)
758 gdb_assert (type == win_type);
764 viewport_height = h - 1;
770 origin.x = origin_x_;
771 origin.y = origin_y_;
774 /* init_and_make_win().
776 static tui_gen_win_info *
777 init_and_make_win (tui_gen_win_info *win_info,
778 enum tui_win_type win_type,
779 int height, int width,
780 int origin_x, int origin_y,
783 if (win_info == NULL)
788 win_info = new tui_source_window ();
792 win_info = new tui_disasm_window ();
796 win_info = new tui_data_window ();
800 win_info = new tui_cmd_window ();
804 win_info = new tui_exec_info_window ();
808 gdb_assert_not_reached (_("unhandled window type"));
812 win_info->reset (win_type, height, width, origin_x, origin_y);
813 tui_make_window (win_info, box_it);
819 static struct tui_win_info *
820 make_source_or_disasm_window (enum tui_win_type type,
821 int height, int origin_y)
823 struct tui_exec_info_window *execution_info
824 = (tui_exec_info_window *) init_and_make_win (nullptr,
832 /* Now create the source window. */
833 struct tui_source_window_base *result
834 = ((struct tui_source_window_base *)
835 init_and_make_win (NULL,
838 tui_term_width () - execution_info->width,
839 execution_info->width,
842 result->execution_info = execution_info;
847 /* Show the Source/Command or the Disassem layout. */
849 show_source_or_disasm_and_command (enum tui_layout_type layout_type)
851 if (tui_current_layout () != layout_type)
853 struct tui_win_info **win_info_ptr;
854 int src_height, cmd_height;
855 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
856 gdb_assert (locator != nullptr);
858 if (TUI_CMD_WIN != NULL)
859 cmd_height = TUI_CMD_WIN->height;
861 cmd_height = tui_term_height () / 3;
862 src_height = tui_term_height () - cmd_height;
864 if (layout_type == SRC_COMMAND)
865 win_info_ptr = &tui_win_list[SRC_WIN];
867 win_info_ptr = &tui_win_list[DISASSEM_WIN];
869 tui_source_window_base *base;
870 if ((*win_info_ptr) == NULL)
872 if (layout_type == SRC_COMMAND)
873 *win_info_ptr = make_source_window (src_height - 1, 0);
875 *win_info_ptr = make_disasm_window (src_height - 1, 0);
876 init_and_make_win (locator,
883 base = (tui_source_window_base *) *win_info_ptr;
887 base = (tui_source_window_base *) *win_info_ptr;
888 locator->reset (LOCATOR_WIN,
893 base->m_has_locator = true;
894 (*win_info_ptr)->reset ((*win_info_ptr)->type,
896 (*win_info_ptr)->width,
897 base->execution_info->width,
899 base->execution_info->reset (EXEC_INFO_WIN,
904 tui_make_visible (*win_info_ptr);
905 tui_make_visible (base->execution_info);
908 base->m_has_locator = true;
909 tui_make_visible (locator);
910 tui_show_locator_content ();
911 tui_show_source_content (base);
913 if (TUI_CMD_WIN == NULL)
915 tui_win_list[CMD_WIN] = make_command_window (cmd_height,
920 TUI_CMD_WIN->reset (TUI_CMD_WIN->type,
923 TUI_CMD_WIN->origin.x,
924 TUI_CMD_WIN->origin.y);
925 tui_make_visible (TUI_CMD_WIN);
927 tui_set_current_layout_to (layout_type);