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 #define LAYOUT_USAGE "Usage: layout prev | next | <layout_name> \n"
66 /* Show the screen layout defined. */
68 show_layout (enum tui_layout_type layout
)
70 enum tui_layout_type cur_layout
= tui_current_layout ();
72 if (layout
!= cur_layout
)
74 /* Since the new layout may cause changes in window size, we
75 should free the content and reallocate on next display of
77 tui_clear_source_windows ();
78 if (layout
== SRC_DATA_COMMAND
79 || layout
== DISASSEM_DATA_COMMAND
)
86 /* First make the current layout be invisible. */
87 tui_make_all_invisible ();
88 tui_make_invisible (tui_locator_win_info_ptr ());
92 /* Now show the new layout. */
94 show_source_command ();
95 tui_add_to_source_windows (TUI_SRC_WIN
);
97 case DISASSEM_COMMAND
:
98 show_disasm_command ();
99 tui_add_to_source_windows (TUI_DISASM_WIN
);
101 case SRC_DISASSEM_COMMAND
:
102 show_source_disasm_command ();
103 tui_add_to_source_windows (TUI_SRC_WIN
);
104 tui_add_to_source_windows (TUI_DISASM_WIN
);
114 /* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
115 SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. */
117 tui_set_layout (enum tui_layout_type layout_type
)
119 enum tui_status status
= TUI_SUCCESS
;
121 if (layout_type
!= UNDEFINED_LAYOUT
)
123 enum tui_layout_type cur_layout
= tui_current_layout ();
124 struct gdbarch
*gdbarch
;
126 struct tui_win_info
*win_with_focus
= tui_win_with_focus ();
127 struct tui_layout_def
*layout_def
= tui_layout_def ();
129 extract_display_start_addr (&gdbarch
, &addr
);
131 enum tui_layout_type new_layout
= layout_type
;
133 if (new_layout
!= cur_layout
)
135 show_layout (new_layout
);
137 /* Now determine where focus should be. */
138 if (win_with_focus
!= TUI_CMD_WIN
)
143 tui_set_win_focus_to (TUI_SRC_WIN
);
144 layout_def
->display_mode
= SRC_WIN
;
146 case DISASSEM_COMMAND
:
147 /* The previous layout was not showing code.
148 This can happen if there is no source
151 1. if the source file is in another dir OR
152 2. if target was compiled without -g
153 We still want to show the assembly though! */
155 tui_get_begin_asm_address (&gdbarch
, &addr
);
156 tui_set_win_focus_to (TUI_DISASM_WIN
);
157 layout_def
->display_mode
= DISASSEM_WIN
;
159 case SRC_DISASSEM_COMMAND
:
160 /* The previous layout was not showing code.
161 This can happen if there is no source
164 1. if the source file is in another dir OR
165 2. if target was compiled without -g
166 We still want to show the assembly though! */
168 tui_get_begin_asm_address (&gdbarch
, &addr
);
169 if (win_with_focus
== TUI_SRC_WIN
)
170 tui_set_win_focus_to (TUI_SRC_WIN
);
172 tui_set_win_focus_to (TUI_DISASM_WIN
);
174 case SRC_DATA_COMMAND
:
175 if (win_with_focus
!= TUI_DATA_WIN
)
176 tui_set_win_focus_to (TUI_SRC_WIN
);
178 tui_set_win_focus_to (TUI_DATA_WIN
);
179 layout_def
->display_mode
= SRC_WIN
;
181 case DISASSEM_DATA_COMMAND
:
182 /* The previous layout was not showing code.
183 This can happen if there is no source
186 1. if the source file is in another dir OR
187 2. if target was compiled without -g
188 We still want to show the assembly though! */
190 tui_get_begin_asm_address (&gdbarch
, &addr
);
191 if (win_with_focus
!= TUI_DATA_WIN
)
192 tui_set_win_focus_to (TUI_DISASM_WIN
);
194 tui_set_win_focus_to (TUI_DATA_WIN
);
195 layout_def
->display_mode
= DISASSEM_WIN
;
202 * Now update the window content.
204 tui_update_source_windows_with_addr (gdbarch
, addr
);
205 if (new_layout
== SRC_DATA_COMMAND
206 || new_layout
== DISASSEM_DATA_COMMAND
)
207 tui_show_registers (TUI_DATA_WIN
->current_group
);
211 status
= TUI_FAILURE
;
216 /* Add the specified window to the layout in a logical way. This
217 means setting up the most logical layout given the window to be
220 tui_add_win_to_layout (enum tui_win_type type
)
222 enum tui_layout_type cur_layout
= tui_current_layout ();
227 if (cur_layout
!= SRC_COMMAND
228 && cur_layout
!= SRC_DISASSEM_COMMAND
229 && cur_layout
!= SRC_DATA_COMMAND
)
231 tui_clear_source_windows_detail ();
232 if (cur_layout
== DISASSEM_DATA_COMMAND
)
233 show_layout (SRC_DATA_COMMAND
);
235 show_layout (SRC_COMMAND
);
239 if (cur_layout
!= DISASSEM_COMMAND
240 && cur_layout
!= SRC_DISASSEM_COMMAND
241 && cur_layout
!= DISASSEM_DATA_COMMAND
)
243 tui_clear_source_windows_detail ();
244 if (cur_layout
== SRC_DATA_COMMAND
)
245 show_layout (DISASSEM_DATA_COMMAND
);
247 show_layout (DISASSEM_COMMAND
);
251 if (cur_layout
!= SRC_DATA_COMMAND
252 && cur_layout
!= DISASSEM_DATA_COMMAND
)
254 if (cur_layout
== DISASSEM_COMMAND
)
255 show_layout (DISASSEM_DATA_COMMAND
);
257 show_layout (SRC_DATA_COMMAND
);
266 /* Answer the height of a window. If it hasn't been created yet,
267 answer what the height of a window would be based upon its type and
270 tui_default_win_height (enum tui_win_type type
,
271 enum tui_layout_type layout
)
275 if (tui_win_list
[type
] != NULL
)
276 h
= tui_win_list
[type
]->height
;
282 case DISASSEM_COMMAND
:
283 if (TUI_CMD_WIN
== NULL
)
284 h
= tui_term_height () / 2;
286 h
= tui_term_height () - TUI_CMD_WIN
->height
;
288 case SRC_DISASSEM_COMMAND
:
289 case SRC_DATA_COMMAND
:
290 case DISASSEM_DATA_COMMAND
:
291 if (TUI_CMD_WIN
== NULL
)
292 h
= tui_term_height () / 3;
294 h
= (tui_term_height () - TUI_CMD_WIN
->height
) / 2;
306 /* Answer the height of a window. If it hasn't been created yet,
307 answer what the height of a window would be based upon its type and
310 tui_default_win_viewport_height (enum tui_win_type type
,
311 enum tui_layout_type layout
)
315 h
= tui_default_win_height (type
, layout
);
317 if (tui_win_list
[type
] == TUI_CMD_WIN
)
325 /* Complete possible layout names. TEXT is the complete text entered so
326 far, WORD is the word currently being completed. */
329 layout_completer (struct cmd_list_element
*ignore
,
330 completion_tracker
&tracker
,
331 const char *text
, const char *word
)
333 static const char *layout_names
[] =
334 { "src", "asm", "split", "regs", "next", "prev", NULL
};
336 complete_on_enum (tracker
, layout_names
, text
, word
);
339 /* Function to initialize gdb commands, for tui window layout
343 _initialize_tui_layout (void)
345 struct cmd_list_element
*cmd
;
347 cmd
= add_com ("layout", class_tui
, tui_layout_command
, _("\
348 Change the layout of windows.\n\
349 Usage: layout prev | next | LAYOUT-NAME\n\
351 src : Displays source and command windows.\n\
352 asm : Displays disassembly and command windows.\n\
353 split : Displays source, disassembly and command windows.\n\
354 regs : Displays register window. If existing layout\n\
355 is source/command or assembly/command, the \n\
356 register window is displayed. If the\n\
357 source/assembly/command (split) is displayed, \n\
358 the register window is displayed with \n\
359 the window that has current logical focus."));
360 set_cmd_completer (cmd
, layout_completer
);
364 /*************************
365 ** STATIC LOCAL FUNCTIONS
366 **************************/
369 /* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
372 tui_set_layout_by_name (const char *layout_name
)
374 enum tui_status status
= TUI_SUCCESS
;
376 if (layout_name
!= NULL
)
379 enum tui_layout_type new_layout
= UNDEFINED_LAYOUT
;
380 enum tui_layout_type cur_layout
= tui_current_layout ();
382 std::string copy
= layout_name
;
383 for (i
= 0; i
< copy
.size (); i
++)
384 copy
[i
] = toupper (copy
[i
]);
385 const char *buf_ptr
= copy
.c_str ();
387 /* First check for ambiguous input. */
388 if (strlen (buf_ptr
) <= 1 && *buf_ptr
== 'S')
390 warning (_("Ambiguous command input."));
391 status
= TUI_FAILURE
;
395 if (subset_compare (buf_ptr
, "SRC"))
396 new_layout
= SRC_COMMAND
;
397 else if (subset_compare (buf_ptr
, "ASM"))
398 new_layout
= DISASSEM_COMMAND
;
399 else if (subset_compare (buf_ptr
, "SPLIT"))
400 new_layout
= SRC_DISASSEM_COMMAND
;
401 else if (subset_compare (buf_ptr
, "REGS"))
403 if (cur_layout
== SRC_COMMAND
404 || cur_layout
== SRC_DATA_COMMAND
)
405 new_layout
= SRC_DATA_COMMAND
;
407 new_layout
= DISASSEM_DATA_COMMAND
;
409 else if (subset_compare (buf_ptr
, "NEXT"))
410 new_layout
= next_layout ();
411 else if (subset_compare (buf_ptr
, "PREV"))
412 new_layout
= prev_layout ();
414 status
= TUI_FAILURE
;
416 if (status
== TUI_SUCCESS
)
418 /* Make sure the curses mode is enabled. */
420 tui_set_layout (new_layout
);
425 status
= TUI_FAILURE
;
432 extract_display_start_addr (struct gdbarch
**gdbarch_p
, CORE_ADDR
*addr_p
)
434 enum tui_layout_type cur_layout
= tui_current_layout ();
435 struct gdbarch
*gdbarch
= get_current_arch ();
438 struct symtab_and_line cursal
= get_current_source_symtab_and_line ();
443 case SRC_DATA_COMMAND
:
444 gdbarch
= TUI_SRC_WIN
->gdbarch
;
445 find_line_pc (cursal
.symtab
,
446 TUI_SRC_WIN
->start_line_or_addr
.u
.line_no
,
450 case DISASSEM_COMMAND
:
451 case SRC_DISASSEM_COMMAND
:
452 case DISASSEM_DATA_COMMAND
:
453 gdbarch
= TUI_DISASM_WIN
->gdbarch
;
454 addr
= TUI_DISASM_WIN
->start_line_or_addr
.u
.addr
;
461 *gdbarch_p
= gdbarch
;
467 tui_layout_command (const char *arg
, int from_tty
)
469 /* Switch to the selected layout. */
470 if (tui_set_layout_by_name (arg
) != TUI_SUCCESS
)
471 warning (_("Invalid layout specified.\n%s"), LAYOUT_USAGE
);
474 /* Answer the previous layout to cycle to. */
475 static enum tui_layout_type
480 new_layout
= tui_current_layout ();
481 if (new_layout
== UNDEFINED_LAYOUT
)
482 new_layout
= SRC_COMMAND
;
486 if (new_layout
== UNDEFINED_LAYOUT
)
487 new_layout
= SRC_COMMAND
;
490 return (enum tui_layout_type
) new_layout
;
494 /* Answer the next layout to cycle to. */
495 static enum tui_layout_type
500 new_layout
= tui_current_layout ();
501 if (new_layout
== SRC_COMMAND
)
502 new_layout
= DISASSEM_DATA_COMMAND
;
506 if (new_layout
== UNDEFINED_LAYOUT
)
507 new_layout
= DISASSEM_DATA_COMMAND
;
510 return (enum tui_layout_type
) new_layout
;
515 static struct tui_win_info
*
516 make_command_window (int height
, int origin_y
)
518 struct tui_win_info
*result
= new tui_cmd_window ();
519 result
->reset (height
, tui_term_width (), 0, origin_y
);
520 tui_make_window (result
, DONT_BOX_WINDOW
);
525 /* make_source_window().
527 static struct tui_win_info
*
528 make_source_window (int height
, int origin_y
)
530 tui_win_info
*result
= new tui_source_window ();
531 result
->reset (height
, tui_term_width (), 0, origin_y
);
532 result
->make_visible (true);
537 /* make_disasm_window().
539 static struct tui_win_info
*
540 make_disasm_window (int height
, int origin_y
)
542 tui_win_info
*result
= new tui_disasm_window ();
543 result
->reset (height
, tui_term_width (), 0, origin_y
);
544 result
->make_visible (true);
549 static tui_win_info
*
550 make_data_window (int height
, int origin_y
)
552 tui_win_info
*result
= new tui_data_window ();
553 result
->reset (height
, tui_term_width (), 0, origin_y
);
554 result
->make_visible (true);
560 /* Show the Source/Command layout. */
562 show_source_command (void)
564 show_source_or_disasm_and_command (SRC_COMMAND
);
568 /* Show the Dissassem/Command layout. */
570 show_disasm_command (void)
572 show_source_or_disasm_and_command (DISASSEM_COMMAND
);
576 /* Show the Source/Disassem/Command layout. */
578 show_source_disasm_command (void)
580 if (tui_current_layout () != SRC_DISASSEM_COMMAND
)
582 int cmd_height
, src_height
, asm_height
;
584 if (TUI_CMD_WIN
!= NULL
)
585 cmd_height
= TUI_CMD_WIN
->height
;
587 cmd_height
= tui_term_height () / 3;
589 src_height
= (tui_term_height () - cmd_height
) / 2;
590 asm_height
= tui_term_height () - (src_height
+ cmd_height
);
592 if (TUI_SRC_WIN
== NULL
)
593 tui_win_list
[SRC_WIN
] = make_source_window (src_height
, 0);
596 TUI_SRC_WIN
->reset (src_height
,
600 tui_make_visible (TUI_SRC_WIN
);
601 TUI_SRC_WIN
->m_has_locator
= false;
604 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
605 gdb_assert (locator
!= nullptr);
607 tui_show_source_content (TUI_SRC_WIN
);
608 if (TUI_DISASM_WIN
== NULL
)
610 tui_win_list
[DISASSEM_WIN
]
611 = make_disasm_window (asm_height
, src_height
- 1);
612 locator
->reset (2 /* 1 */ ,
615 (src_height
+ asm_height
) - 1);
619 locator
->reset (2 /* 1 */ ,
622 (src_height
+ asm_height
) - 1);
623 TUI_DISASM_WIN
->m_has_locator
= true;
624 TUI_DISASM_WIN
->reset (asm_height
,
628 tui_make_visible (TUI_DISASM_WIN
);
630 TUI_SRC_WIN
->m_has_locator
= false;
631 TUI_DISASM_WIN
->m_has_locator
= true;
632 tui_make_visible (locator
);
633 tui_show_locator_content ();
634 tui_show_source_content (TUI_DISASM_WIN
);
636 if (TUI_CMD_WIN
== NULL
)
637 tui_win_list
[CMD_WIN
]
638 = make_command_window (cmd_height
, tui_term_height () - cmd_height
);
641 TUI_CMD_WIN
->reset (TUI_CMD_WIN
->height
,
644 TUI_CMD_WIN
->origin
.y
);
645 tui_make_visible (TUI_CMD_WIN
);
647 tui_set_current_layout_to (SRC_DISASSEM_COMMAND
);
652 /* Show the Source/Data/Command or the Dissassembly/Data/Command
655 show_data (enum tui_layout_type new_layout
)
657 int total_height
= (tui_term_height () - TUI_CMD_WIN
->height
);
658 int src_height
, data_height
;
659 enum tui_win_type win_type
;
661 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
662 gdb_assert (locator
!= nullptr);
664 data_height
= total_height
/ 2;
665 src_height
= total_height
- data_height
;
666 tui_make_all_invisible ();
667 tui_make_invisible (locator
);
668 if (tui_win_list
[DATA_WIN
] == nullptr)
669 tui_win_list
[DATA_WIN
] = make_data_window (data_height
, 0);
671 tui_win_list
[DATA_WIN
]->reset (data_height
, tui_term_width (), 0, 0);
672 tui_win_list
[DATA_WIN
]->make_visible (true);
674 if (new_layout
== SRC_DATA_COMMAND
)
677 win_type
= DISASSEM_WIN
;
679 tui_source_window_base
*base
;
680 if (tui_win_list
[win_type
] == NULL
)
682 if (win_type
== SRC_WIN
)
683 tui_win_list
[win_type
]
684 = make_source_window (src_height
, data_height
- 1);
686 tui_win_list
[win_type
]
687 = make_disasm_window (src_height
, data_height
- 1);
688 locator
->reset (2 /* 1 */ ,
692 base
= (tui_source_window_base
*) tui_win_list
[win_type
];
696 base
= (tui_source_window_base
*) tui_win_list
[win_type
];
697 tui_win_list
[win_type
]->reset (src_height
,
701 tui_make_visible (tui_win_list
[win_type
]);
702 locator
->reset (2 /* 1 */ ,
707 base
->m_has_locator
= true;
708 tui_make_visible (locator
);
709 tui_show_locator_content ();
710 tui_add_to_source_windows
711 ((tui_source_window_base
*) tui_win_list
[win_type
]);
712 tui_set_current_layout_to (new_layout
);
716 tui_gen_win_info::reset (int height_
, int width_
,
717 int origin_x_
, int origin_y_
)
725 viewport_height
= h
- 1;
731 origin
.x
= origin_x_
;
732 origin
.y
= origin_y_
;
735 /* Show the Source/Command or the Disassem layout. */
737 show_source_or_disasm_and_command (enum tui_layout_type layout_type
)
739 if (tui_current_layout () != layout_type
)
741 struct tui_win_info
**win_info_ptr
;
742 int src_height
, cmd_height
;
743 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
744 gdb_assert (locator
!= nullptr);
746 if (TUI_CMD_WIN
!= NULL
)
747 cmd_height
= TUI_CMD_WIN
->height
;
749 cmd_height
= tui_term_height () / 3;
750 src_height
= tui_term_height () - cmd_height
;
752 if (layout_type
== SRC_COMMAND
)
753 win_info_ptr
= &tui_win_list
[SRC_WIN
];
755 win_info_ptr
= &tui_win_list
[DISASSEM_WIN
];
757 tui_source_window_base
*base
;
758 if ((*win_info_ptr
) == NULL
)
760 if (layout_type
== SRC_COMMAND
)
761 *win_info_ptr
= make_source_window (src_height
- 1, 0);
763 *win_info_ptr
= make_disasm_window (src_height
- 1, 0);
764 locator
->reset (2 /* 1 */ ,
768 base
= (tui_source_window_base
*) *win_info_ptr
;
772 base
= (tui_source_window_base
*) *win_info_ptr
;
773 locator
->reset (2 /* 1 */ ,
777 base
->m_has_locator
= true;
778 (*win_info_ptr
)->reset (src_height
- 1,
782 tui_make_visible (*win_info_ptr
);
785 base
->m_has_locator
= true;
786 tui_make_visible (locator
);
787 tui_show_locator_content ();
788 tui_show_source_content (base
);
790 if (TUI_CMD_WIN
== NULL
)
792 tui_win_list
[CMD_WIN
] = make_command_window (cmd_height
,
797 TUI_CMD_WIN
->reset (TUI_CMD_WIN
->height
,
799 TUI_CMD_WIN
->origin
.x
,
800 TUI_CMD_WIN
->origin
.y
);
801 tui_make_visible (TUI_CMD_WIN
);
803 tui_set_current_layout_to (layout_type
);