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 void show_source_or_disasm_and_command (enum tui_layout_type);
47 static struct tui_win_info *make_command_window (int, int);
48 static struct tui_win_info *make_source_window (int, int);
49 static struct tui_win_info *make_disasm_window (int, int);
50 static void show_source_command (void);
51 static void show_disasm_command (void);
52 static void show_source_disasm_command (void);
53 static void show_data (enum tui_layout_type);
54 static enum tui_layout_type next_layout (void);
55 static enum tui_layout_type prev_layout (void);
56 static void tui_layout_command (const char *, int);
57 static void extract_display_start_addr (struct gdbarch **, CORE_ADDR *);
60 /***************************************
62 ***************************************/
64 /* Show the screen layout defined. */
66 show_layout (enum tui_layout_type layout)
68 enum tui_layout_type cur_layout = tui_current_layout ();
70 if (layout != cur_layout)
72 /* Since the new layout may cause changes in window size, we
73 should free the content and reallocate on next display of
75 tui_clear_source_windows ();
76 if (layout == SRC_DATA_COMMAND
77 || layout == DISASSEM_DATA_COMMAND)
84 /* First make the current layout be invisible. */
85 tui_make_all_invisible ();
86 tui_make_invisible (tui_locator_win_info_ptr ());
90 /* Now show the new layout. */
92 show_source_command ();
93 tui_add_to_source_windows (TUI_SRC_WIN);
95 case DISASSEM_COMMAND:
96 show_disasm_command ();
97 tui_add_to_source_windows (TUI_DISASM_WIN);
99 case SRC_DISASSEM_COMMAND:
100 show_source_disasm_command ();
101 tui_add_to_source_windows (TUI_SRC_WIN);
102 tui_add_to_source_windows (TUI_DISASM_WIN);
112 /* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
113 SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. */
115 tui_set_layout (enum tui_layout_type layout_type)
117 gdb_assert (layout_type != UNDEFINED_LAYOUT);
119 enum tui_layout_type cur_layout = tui_current_layout ();
120 struct gdbarch *gdbarch;
122 struct tui_win_info *win_with_focus = tui_win_with_focus ();
123 struct tui_layout_def *layout_def = tui_layout_def ();
125 extract_display_start_addr (&gdbarch, &addr);
127 enum tui_layout_type new_layout = layout_type;
129 if (new_layout != cur_layout)
131 show_layout (new_layout);
133 /* Now determine where focus should be. */
134 if (win_with_focus != TUI_CMD_WIN)
139 tui_set_win_focus_to (TUI_SRC_WIN);
140 layout_def->display_mode = SRC_WIN;
142 case DISASSEM_COMMAND:
143 /* The previous layout was not showing code.
144 This can happen if there is no source
147 1. if the source file is in another dir OR
148 2. if target was compiled without -g
149 We still want to show the assembly though! */
151 tui_get_begin_asm_address (&gdbarch, &addr);
152 tui_set_win_focus_to (TUI_DISASM_WIN);
153 layout_def->display_mode = DISASSEM_WIN;
155 case SRC_DISASSEM_COMMAND:
156 /* The previous layout was not showing code.
157 This can happen if there is no source
160 1. if the source file is in another dir OR
161 2. if target was compiled without -g
162 We still want to show the assembly though! */
164 tui_get_begin_asm_address (&gdbarch, &addr);
165 if (win_with_focus == TUI_SRC_WIN)
166 tui_set_win_focus_to (TUI_SRC_WIN);
168 tui_set_win_focus_to (TUI_DISASM_WIN);
170 case SRC_DATA_COMMAND:
171 if (win_with_focus != TUI_DATA_WIN)
172 tui_set_win_focus_to (TUI_SRC_WIN);
174 tui_set_win_focus_to (TUI_DATA_WIN);
175 layout_def->display_mode = SRC_WIN;
177 case DISASSEM_DATA_COMMAND:
178 /* The previous layout was not showing code.
179 This can happen if there is no source
182 1. if the source file is in another dir OR
183 2. if target was compiled without -g
184 We still want to show the assembly though! */
186 tui_get_begin_asm_address (&gdbarch, &addr);
187 if (win_with_focus != TUI_DATA_WIN)
188 tui_set_win_focus_to (TUI_DISASM_WIN);
190 tui_set_win_focus_to (TUI_DATA_WIN);
191 layout_def->display_mode = DISASSEM_WIN;
198 * Now update the window content.
200 tui_update_source_windows_with_addr (gdbarch, addr);
201 if (new_layout == SRC_DATA_COMMAND
202 || new_layout == DISASSEM_DATA_COMMAND)
203 tui_show_registers (TUI_DATA_WIN->current_group);
207 /* Add the specified window to the layout in a logical way. This
208 means setting up the most logical layout given the window to be
211 tui_add_win_to_layout (enum tui_win_type type)
213 enum tui_layout_type cur_layout = tui_current_layout ();
218 if (cur_layout != SRC_COMMAND
219 && cur_layout != SRC_DISASSEM_COMMAND
220 && cur_layout != SRC_DATA_COMMAND)
222 tui_clear_source_windows_detail ();
223 if (cur_layout == DISASSEM_DATA_COMMAND)
224 show_layout (SRC_DATA_COMMAND);
226 show_layout (SRC_COMMAND);
230 if (cur_layout != DISASSEM_COMMAND
231 && cur_layout != SRC_DISASSEM_COMMAND
232 && cur_layout != DISASSEM_DATA_COMMAND)
234 tui_clear_source_windows_detail ();
235 if (cur_layout == SRC_DATA_COMMAND)
236 show_layout (DISASSEM_DATA_COMMAND);
238 show_layout (DISASSEM_COMMAND);
242 if (cur_layout != SRC_DATA_COMMAND
243 && cur_layout != DISASSEM_DATA_COMMAND)
245 if (cur_layout == DISASSEM_COMMAND)
246 show_layout (DISASSEM_DATA_COMMAND);
248 show_layout (SRC_DATA_COMMAND);
257 /* Answer the height of a window. If it hasn't been created yet,
258 answer what the height of a window would be based upon its type and
261 tui_default_win_height (enum tui_win_type type,
262 enum tui_layout_type layout)
266 if (tui_win_list[type] != NULL)
267 h = tui_win_list[type]->height;
273 case DISASSEM_COMMAND:
274 if (TUI_CMD_WIN == NULL)
275 h = tui_term_height () / 2;
277 h = tui_term_height () - TUI_CMD_WIN->height;
279 case SRC_DISASSEM_COMMAND:
280 case SRC_DATA_COMMAND:
281 case DISASSEM_DATA_COMMAND:
282 if (TUI_CMD_WIN == NULL)
283 h = tui_term_height () / 3;
285 h = (tui_term_height () - TUI_CMD_WIN->height) / 2;
297 /* Answer the height of a window. If it hasn't been created yet,
298 answer what the height of a window would be based upon its type and
301 tui_default_win_viewport_height (enum tui_win_type type,
302 enum tui_layout_type layout)
306 h = tui_default_win_height (type, layout);
308 if (tui_win_list[type] == TUI_CMD_WIN)
316 /* Complete possible layout names. TEXT is the complete text entered so
317 far, WORD is the word currently being completed. */
320 layout_completer (struct cmd_list_element *ignore,
321 completion_tracker &tracker,
322 const char *text, const char *word)
324 static const char *layout_names [] =
325 { "src", "asm", "split", "regs", "next", "prev", NULL };
327 complete_on_enum (tracker, layout_names, text, word);
330 /* Function to initialize gdb commands, for tui window layout
334 _initialize_tui_layout (void)
336 struct cmd_list_element *cmd;
338 cmd = add_com ("layout", class_tui, tui_layout_command, _("\
339 Change the layout of windows.\n\
340 Usage: layout prev | next | LAYOUT-NAME\n\
342 src : Displays source and command windows.\n\
343 asm : Displays disassembly and command windows.\n\
344 split : Displays source, disassembly and command windows.\n\
345 regs : Displays register window. If existing layout\n\
346 is source/command or assembly/command, the \n\
347 register window is displayed. If the\n\
348 source/assembly/command (split) is displayed, \n\
349 the register window is displayed with \n\
350 the window that has current logical focus."));
351 set_cmd_completer (cmd, layout_completer);
355 /*************************
356 ** STATIC LOCAL FUNCTIONS
357 **************************/
360 /* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
363 tui_layout_command (const char *layout_name, int from_tty)
366 enum tui_layout_type new_layout = UNDEFINED_LAYOUT;
367 enum tui_layout_type cur_layout = tui_current_layout ();
369 if (layout_name == NULL)
370 error (_("Usage: layout prev | next | LAYOUT-NAME"));
372 std::string copy = layout_name;
373 for (i = 0; i < copy.size (); i++)
374 copy[i] = toupper (copy[i]);
375 const char *buf_ptr = copy.c_str ();
377 /* First check for ambiguous input. */
378 if (strlen (buf_ptr) <= 1 && *buf_ptr == 'S')
379 error (_("Ambiguous command input."));
381 if (subset_compare (buf_ptr, "SRC"))
382 new_layout = SRC_COMMAND;
383 else if (subset_compare (buf_ptr, "ASM"))
384 new_layout = DISASSEM_COMMAND;
385 else if (subset_compare (buf_ptr, "SPLIT"))
386 new_layout = SRC_DISASSEM_COMMAND;
387 else if (subset_compare (buf_ptr, "REGS"))
389 if (cur_layout == SRC_COMMAND
390 || cur_layout == SRC_DATA_COMMAND)
391 new_layout = SRC_DATA_COMMAND;
393 new_layout = DISASSEM_DATA_COMMAND;
395 else if (subset_compare (buf_ptr, "NEXT"))
396 new_layout = next_layout ();
397 else if (subset_compare (buf_ptr, "PREV"))
398 new_layout = prev_layout ();
400 error (_("Unrecognized layout: %s"), layout_name);
402 /* Make sure the curses mode is enabled. */
404 tui_set_layout (new_layout);
409 extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
411 enum tui_layout_type cur_layout = tui_current_layout ();
412 struct gdbarch *gdbarch = get_current_arch ();
415 struct symtab_and_line cursal = get_current_source_symtab_and_line ();
420 case SRC_DATA_COMMAND:
421 gdbarch = TUI_SRC_WIN->gdbarch;
422 find_line_pc (cursal.symtab,
423 TUI_SRC_WIN->start_line_or_addr.u.line_no,
427 case DISASSEM_COMMAND:
428 case SRC_DISASSEM_COMMAND:
429 case DISASSEM_DATA_COMMAND:
430 gdbarch = TUI_DISASM_WIN->gdbarch;
431 addr = TUI_DISASM_WIN->start_line_or_addr.u.addr;
438 *gdbarch_p = gdbarch;
443 /* Answer the previous layout to cycle to. */
444 static enum tui_layout_type
449 new_layout = tui_current_layout ();
450 if (new_layout == UNDEFINED_LAYOUT)
451 new_layout = SRC_COMMAND;
455 if (new_layout == UNDEFINED_LAYOUT)
456 new_layout = SRC_COMMAND;
459 return (enum tui_layout_type) new_layout;
463 /* Answer the next layout to cycle to. */
464 static enum tui_layout_type
469 new_layout = tui_current_layout ();
470 if (new_layout == SRC_COMMAND)
471 new_layout = DISASSEM_DATA_COMMAND;
475 if (new_layout == UNDEFINED_LAYOUT)
476 new_layout = DISASSEM_DATA_COMMAND;
479 return (enum tui_layout_type) new_layout;
484 static struct tui_win_info *
485 make_command_window (int height, int origin_y)
487 struct tui_win_info *result = new tui_cmd_window ();
488 result->reset (height, tui_term_width (), 0, origin_y);
489 tui_make_window (result, DONT_BOX_WINDOW);
494 /* make_source_window().
496 static struct tui_win_info *
497 make_source_window (int height, int origin_y)
499 tui_win_info *result = new tui_source_window ();
500 result->reset (height, tui_term_width (), 0, origin_y);
501 result->make_visible (true);
506 /* make_disasm_window().
508 static struct tui_win_info *
509 make_disasm_window (int height, int origin_y)
511 tui_win_info *result = new tui_disasm_window ();
512 result->reset (height, tui_term_width (), 0, origin_y);
513 result->make_visible (true);
518 static tui_win_info *
519 make_data_window (int height, int origin_y)
521 tui_win_info *result = new tui_data_window ();
522 result->reset (height, tui_term_width (), 0, origin_y);
523 result->make_visible (true);
529 /* Show the Source/Command layout. */
531 show_source_command (void)
533 show_source_or_disasm_and_command (SRC_COMMAND);
537 /* Show the Dissassem/Command layout. */
539 show_disasm_command (void)
541 show_source_or_disasm_and_command (DISASSEM_COMMAND);
545 /* Show the Source/Disassem/Command layout. */
547 show_source_disasm_command (void)
549 if (tui_current_layout () != SRC_DISASSEM_COMMAND)
551 int cmd_height, src_height, asm_height;
553 if (TUI_CMD_WIN != NULL)
554 cmd_height = TUI_CMD_WIN->height;
556 cmd_height = tui_term_height () / 3;
558 src_height = (tui_term_height () - cmd_height) / 2;
559 asm_height = tui_term_height () - (src_height + cmd_height);
561 if (TUI_SRC_WIN == NULL)
562 tui_win_list[SRC_WIN] = new tui_source_window ();
563 TUI_SRC_WIN->reset (src_height,
567 tui_make_visible (TUI_SRC_WIN);
568 TUI_SRC_WIN->m_has_locator = false;
570 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
571 gdb_assert (locator != nullptr);
573 tui_show_source_content (TUI_SRC_WIN);
574 if (TUI_DISASM_WIN == NULL)
575 tui_win_list[DISASSEM_WIN] = new tui_disasm_window ();
576 TUI_DISASM_WIN->reset (asm_height,
580 tui_make_visible (TUI_DISASM_WIN);
581 locator->reset (2 /* 1 */ ,
584 (src_height + asm_height) - 1);
585 TUI_SRC_WIN->m_has_locator = false;
586 TUI_DISASM_WIN->m_has_locator = true;
587 tui_make_visible (locator);
588 tui_show_locator_content ();
589 tui_show_source_content (TUI_DISASM_WIN);
591 if (TUI_CMD_WIN == NULL)
592 tui_win_list[CMD_WIN]
593 = make_command_window (cmd_height, tui_term_height () - cmd_height);
596 TUI_CMD_WIN->reset (TUI_CMD_WIN->height,
599 TUI_CMD_WIN->origin.y);
600 tui_make_visible (TUI_CMD_WIN);
602 tui_set_current_layout_to (SRC_DISASSEM_COMMAND);
607 /* Show the Source/Data/Command or the Dissassembly/Data/Command
610 show_data (enum tui_layout_type new_layout)
612 int total_height = (tui_term_height () - TUI_CMD_WIN->height);
613 int src_height, data_height;
614 enum tui_win_type win_type;
616 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
617 gdb_assert (locator != nullptr);
619 data_height = total_height / 2;
620 src_height = total_height - data_height;
621 tui_make_all_invisible ();
622 tui_make_invisible (locator);
623 if (tui_win_list[DATA_WIN] == nullptr)
624 tui_win_list[DATA_WIN] = make_data_window (data_height, 0);
626 tui_win_list[DATA_WIN]->reset (data_height, tui_term_width (), 0, 0);
627 tui_win_list[DATA_WIN]->make_visible (true);
629 if (new_layout == SRC_DATA_COMMAND)
632 win_type = DISASSEM_WIN;
634 tui_source_window_base *base;
635 if (tui_win_list[win_type] == NULL)
637 if (win_type == SRC_WIN)
638 tui_win_list[win_type]
639 = make_source_window (src_height, data_height - 1);
641 tui_win_list[win_type]
642 = make_disasm_window (src_height, data_height - 1);
643 locator->reset (2 /* 1 */ ,
647 base = (tui_source_window_base *) tui_win_list[win_type];
651 base = (tui_source_window_base *) tui_win_list[win_type];
652 tui_win_list[win_type]->reset (src_height,
656 tui_make_visible (tui_win_list[win_type]);
657 locator->reset (2 /* 1 */ ,
662 base->m_has_locator = true;
663 tui_make_visible (locator);
664 tui_show_locator_content ();
665 tui_add_to_source_windows
666 ((tui_source_window_base *) tui_win_list[win_type]);
667 tui_set_current_layout_to (new_layout);
671 tui_gen_win_info::reset (int height_, int width_,
672 int origin_x_, int origin_y_)
680 viewport_height = h - 1;
686 origin.x = origin_x_;
687 origin.y = origin_y_;
690 /* Show the Source/Command or the Disassem layout. */
692 show_source_or_disasm_and_command (enum tui_layout_type layout_type)
694 if (tui_current_layout () != layout_type)
696 struct tui_source_window_base *win_info;
697 int src_height, cmd_height;
698 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
699 gdb_assert (locator != nullptr);
701 if (TUI_CMD_WIN != NULL)
702 cmd_height = TUI_CMD_WIN->height;
704 cmd_height = tui_term_height () / 3;
705 src_height = tui_term_height () - cmd_height;
707 if (layout_type == SRC_COMMAND)
709 if (tui_win_list[SRC_WIN] == nullptr)
710 tui_win_list[SRC_WIN] = new tui_source_window ();
711 win_info = TUI_SRC_WIN;
715 if (tui_win_list[DISASSEM_WIN] == nullptr)
716 tui_win_list[DISASSEM_WIN] = new tui_disasm_window ();
717 win_info = TUI_DISASM_WIN;
720 locator->reset (2 /* 1 */ ,
724 win_info->reset (src_height - 1,
728 tui_make_visible (win_info);
731 win_info->m_has_locator = true;
732 tui_make_visible (locator);
733 tui_show_locator_content ();
734 tui_show_source_content (win_info);
736 if (TUI_CMD_WIN == NULL)
738 tui_win_list[CMD_WIN] = make_command_window (cmd_height,
743 TUI_CMD_WIN->reset (TUI_CMD_WIN->height,
745 TUI_CMD_WIN->origin.x,
746 TUI_CMD_WIN->origin.y);
747 tui_make_visible (TUI_CMD_WIN);
749 tui_set_current_layout_to (layout_type);