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 gdb_assert (layout_type
!= UNDEFINED_LAYOUT
);
121 enum tui_layout_type cur_layout
= tui_current_layout ();
122 struct gdbarch
*gdbarch
;
124 struct tui_win_info
*win_with_focus
= tui_win_with_focus ();
125 struct tui_layout_def
*layout_def
= tui_layout_def ();
127 extract_display_start_addr (&gdbarch
, &addr
);
129 enum tui_layout_type new_layout
= layout_type
;
131 if (new_layout
!= cur_layout
)
133 show_layout (new_layout
);
135 /* Now determine where focus should be. */
136 if (win_with_focus
!= TUI_CMD_WIN
)
141 tui_set_win_focus_to (TUI_SRC_WIN
);
142 layout_def
->display_mode
= SRC_WIN
;
144 case DISASSEM_COMMAND
:
145 /* The previous layout was not showing code.
146 This can happen if there is no source
149 1. if the source file is in another dir OR
150 2. if target was compiled without -g
151 We still want to show the assembly though! */
153 tui_get_begin_asm_address (&gdbarch
, &addr
);
154 tui_set_win_focus_to (TUI_DISASM_WIN
);
155 layout_def
->display_mode
= DISASSEM_WIN
;
157 case SRC_DISASSEM_COMMAND
:
158 /* The previous layout was not showing code.
159 This can happen if there is no source
162 1. if the source file is in another dir OR
163 2. if target was compiled without -g
164 We still want to show the assembly though! */
166 tui_get_begin_asm_address (&gdbarch
, &addr
);
167 if (win_with_focus
== TUI_SRC_WIN
)
168 tui_set_win_focus_to (TUI_SRC_WIN
);
170 tui_set_win_focus_to (TUI_DISASM_WIN
);
172 case SRC_DATA_COMMAND
:
173 if (win_with_focus
!= TUI_DATA_WIN
)
174 tui_set_win_focus_to (TUI_SRC_WIN
);
176 tui_set_win_focus_to (TUI_DATA_WIN
);
177 layout_def
->display_mode
= SRC_WIN
;
179 case DISASSEM_DATA_COMMAND
:
180 /* The previous layout was not showing code.
181 This can happen if there is no source
184 1. if the source file is in another dir OR
185 2. if target was compiled without -g
186 We still want to show the assembly though! */
188 tui_get_begin_asm_address (&gdbarch
, &addr
);
189 if (win_with_focus
!= TUI_DATA_WIN
)
190 tui_set_win_focus_to (TUI_DISASM_WIN
);
192 tui_set_win_focus_to (TUI_DATA_WIN
);
193 layout_def
->display_mode
= DISASSEM_WIN
;
200 * Now update the window content.
202 tui_update_source_windows_with_addr (gdbarch
, addr
);
203 if (new_layout
== SRC_DATA_COMMAND
204 || new_layout
== DISASSEM_DATA_COMMAND
)
205 tui_show_registers (TUI_DATA_WIN
->current_group
);
209 /* Add the specified window to the layout in a logical way. This
210 means setting up the most logical layout given the window to be
213 tui_add_win_to_layout (enum tui_win_type type
)
215 enum tui_layout_type cur_layout
= tui_current_layout ();
220 if (cur_layout
!= SRC_COMMAND
221 && cur_layout
!= SRC_DISASSEM_COMMAND
222 && cur_layout
!= SRC_DATA_COMMAND
)
224 tui_clear_source_windows_detail ();
225 if (cur_layout
== DISASSEM_DATA_COMMAND
)
226 show_layout (SRC_DATA_COMMAND
);
228 show_layout (SRC_COMMAND
);
232 if (cur_layout
!= DISASSEM_COMMAND
233 && cur_layout
!= SRC_DISASSEM_COMMAND
234 && cur_layout
!= DISASSEM_DATA_COMMAND
)
236 tui_clear_source_windows_detail ();
237 if (cur_layout
== SRC_DATA_COMMAND
)
238 show_layout (DISASSEM_DATA_COMMAND
);
240 show_layout (DISASSEM_COMMAND
);
244 if (cur_layout
!= SRC_DATA_COMMAND
245 && cur_layout
!= DISASSEM_DATA_COMMAND
)
247 if (cur_layout
== DISASSEM_COMMAND
)
248 show_layout (DISASSEM_DATA_COMMAND
);
250 show_layout (SRC_DATA_COMMAND
);
259 /* Answer the height of a window. If it hasn't been created yet,
260 answer what the height of a window would be based upon its type and
263 tui_default_win_height (enum tui_win_type type
,
264 enum tui_layout_type layout
)
268 if (tui_win_list
[type
] != NULL
)
269 h
= tui_win_list
[type
]->height
;
275 case DISASSEM_COMMAND
:
276 if (TUI_CMD_WIN
== NULL
)
277 h
= tui_term_height () / 2;
279 h
= tui_term_height () - TUI_CMD_WIN
->height
;
281 case SRC_DISASSEM_COMMAND
:
282 case SRC_DATA_COMMAND
:
283 case DISASSEM_DATA_COMMAND
:
284 if (TUI_CMD_WIN
== NULL
)
285 h
= tui_term_height () / 3;
287 h
= (tui_term_height () - TUI_CMD_WIN
->height
) / 2;
299 /* Answer the height of a window. If it hasn't been created yet,
300 answer what the height of a window would be based upon its type and
303 tui_default_win_viewport_height (enum tui_win_type type
,
304 enum tui_layout_type layout
)
308 h
= tui_default_win_height (type
, layout
);
310 if (tui_win_list
[type
] == TUI_CMD_WIN
)
318 /* Complete possible layout names. TEXT is the complete text entered so
319 far, WORD is the word currently being completed. */
322 layout_completer (struct cmd_list_element
*ignore
,
323 completion_tracker
&tracker
,
324 const char *text
, const char *word
)
326 static const char *layout_names
[] =
327 { "src", "asm", "split", "regs", "next", "prev", NULL
};
329 complete_on_enum (tracker
, layout_names
, text
, word
);
332 /* Function to initialize gdb commands, for tui window layout
336 _initialize_tui_layout (void)
338 struct cmd_list_element
*cmd
;
340 cmd
= add_com ("layout", class_tui
, tui_layout_command
, _("\
341 Change the layout of windows.\n\
342 Usage: layout prev | next | LAYOUT-NAME\n\
344 src : Displays source and command windows.\n\
345 asm : Displays disassembly and command windows.\n\
346 split : Displays source, disassembly and command windows.\n\
347 regs : Displays register window. If existing layout\n\
348 is source/command or assembly/command, the \n\
349 register window is displayed. If the\n\
350 source/assembly/command (split) is displayed, \n\
351 the register window is displayed with \n\
352 the window that has current logical focus."));
353 set_cmd_completer (cmd
, layout_completer
);
357 /*************************
358 ** STATIC LOCAL FUNCTIONS
359 **************************/
362 /* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
365 tui_set_layout_by_name (const char *layout_name
)
367 enum tui_status status
= TUI_SUCCESS
;
369 if (layout_name
!= NULL
)
372 enum tui_layout_type new_layout
= UNDEFINED_LAYOUT
;
373 enum tui_layout_type cur_layout
= tui_current_layout ();
375 std::string copy
= layout_name
;
376 for (i
= 0; i
< copy
.size (); i
++)
377 copy
[i
] = toupper (copy
[i
]);
378 const char *buf_ptr
= copy
.c_str ();
380 /* First check for ambiguous input. */
381 if (strlen (buf_ptr
) <= 1 && *buf_ptr
== 'S')
383 warning (_("Ambiguous command input."));
384 status
= TUI_FAILURE
;
388 if (subset_compare (buf_ptr
, "SRC"))
389 new_layout
= SRC_COMMAND
;
390 else if (subset_compare (buf_ptr
, "ASM"))
391 new_layout
= DISASSEM_COMMAND
;
392 else if (subset_compare (buf_ptr
, "SPLIT"))
393 new_layout
= SRC_DISASSEM_COMMAND
;
394 else if (subset_compare (buf_ptr
, "REGS"))
396 if (cur_layout
== SRC_COMMAND
397 || cur_layout
== SRC_DATA_COMMAND
)
398 new_layout
= SRC_DATA_COMMAND
;
400 new_layout
= DISASSEM_DATA_COMMAND
;
402 else if (subset_compare (buf_ptr
, "NEXT"))
403 new_layout
= next_layout ();
404 else if (subset_compare (buf_ptr
, "PREV"))
405 new_layout
= prev_layout ();
407 status
= TUI_FAILURE
;
409 if (status
== TUI_SUCCESS
)
411 /* Make sure the curses mode is enabled. */
413 tui_set_layout (new_layout
);
418 status
= TUI_FAILURE
;
425 extract_display_start_addr (struct gdbarch
**gdbarch_p
, CORE_ADDR
*addr_p
)
427 enum tui_layout_type cur_layout
= tui_current_layout ();
428 struct gdbarch
*gdbarch
= get_current_arch ();
431 struct symtab_and_line cursal
= get_current_source_symtab_and_line ();
436 case SRC_DATA_COMMAND
:
437 gdbarch
= TUI_SRC_WIN
->gdbarch
;
438 find_line_pc (cursal
.symtab
,
439 TUI_SRC_WIN
->start_line_or_addr
.u
.line_no
,
443 case DISASSEM_COMMAND
:
444 case SRC_DISASSEM_COMMAND
:
445 case DISASSEM_DATA_COMMAND
:
446 gdbarch
= TUI_DISASM_WIN
->gdbarch
;
447 addr
= TUI_DISASM_WIN
->start_line_or_addr
.u
.addr
;
454 *gdbarch_p
= gdbarch
;
460 tui_layout_command (const char *arg
, int from_tty
)
462 /* Switch to the selected layout. */
463 if (tui_set_layout_by_name (arg
) != TUI_SUCCESS
)
464 warning (_("Invalid layout specified.\n%s"), LAYOUT_USAGE
);
467 /* Answer the previous layout to cycle to. */
468 static enum tui_layout_type
473 new_layout
= tui_current_layout ();
474 if (new_layout
== UNDEFINED_LAYOUT
)
475 new_layout
= SRC_COMMAND
;
479 if (new_layout
== UNDEFINED_LAYOUT
)
480 new_layout
= SRC_COMMAND
;
483 return (enum tui_layout_type
) new_layout
;
487 /* Answer the next layout to cycle to. */
488 static enum tui_layout_type
493 new_layout
= tui_current_layout ();
494 if (new_layout
== SRC_COMMAND
)
495 new_layout
= DISASSEM_DATA_COMMAND
;
499 if (new_layout
== UNDEFINED_LAYOUT
)
500 new_layout
= DISASSEM_DATA_COMMAND
;
503 return (enum tui_layout_type
) new_layout
;
508 static struct tui_win_info
*
509 make_command_window (int height
, int origin_y
)
511 struct tui_win_info
*result
= new tui_cmd_window ();
512 result
->reset (height
, tui_term_width (), 0, origin_y
);
513 tui_make_window (result
, DONT_BOX_WINDOW
);
518 /* make_source_window().
520 static struct tui_win_info
*
521 make_source_window (int height
, int origin_y
)
523 tui_win_info
*result
= new tui_source_window ();
524 result
->reset (height
, tui_term_width (), 0, origin_y
);
525 result
->make_visible (true);
530 /* make_disasm_window().
532 static struct tui_win_info
*
533 make_disasm_window (int height
, int origin_y
)
535 tui_win_info
*result
= new tui_disasm_window ();
536 result
->reset (height
, tui_term_width (), 0, origin_y
);
537 result
->make_visible (true);
542 static tui_win_info
*
543 make_data_window (int height
, int origin_y
)
545 tui_win_info
*result
= new tui_data_window ();
546 result
->reset (height
, tui_term_width (), 0, origin_y
);
547 result
->make_visible (true);
553 /* Show the Source/Command layout. */
555 show_source_command (void)
557 show_source_or_disasm_and_command (SRC_COMMAND
);
561 /* Show the Dissassem/Command layout. */
563 show_disasm_command (void)
565 show_source_or_disasm_and_command (DISASSEM_COMMAND
);
569 /* Show the Source/Disassem/Command layout. */
571 show_source_disasm_command (void)
573 if (tui_current_layout () != SRC_DISASSEM_COMMAND
)
575 int cmd_height
, src_height
, asm_height
;
577 if (TUI_CMD_WIN
!= NULL
)
578 cmd_height
= TUI_CMD_WIN
->height
;
580 cmd_height
= tui_term_height () / 3;
582 src_height
= (tui_term_height () - cmd_height
) / 2;
583 asm_height
= tui_term_height () - (src_height
+ cmd_height
);
585 if (TUI_SRC_WIN
== NULL
)
586 tui_win_list
[SRC_WIN
] = make_source_window (src_height
, 0);
589 TUI_SRC_WIN
->reset (src_height
,
593 tui_make_visible (TUI_SRC_WIN
);
594 TUI_SRC_WIN
->m_has_locator
= false;
597 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
598 gdb_assert (locator
!= nullptr);
600 tui_show_source_content (TUI_SRC_WIN
);
601 if (TUI_DISASM_WIN
== NULL
)
603 tui_win_list
[DISASSEM_WIN
]
604 = make_disasm_window (asm_height
, src_height
- 1);
605 locator
->reset (2 /* 1 */ ,
608 (src_height
+ asm_height
) - 1);
612 locator
->reset (2 /* 1 */ ,
615 (src_height
+ asm_height
) - 1);
616 TUI_DISASM_WIN
->m_has_locator
= true;
617 TUI_DISASM_WIN
->reset (asm_height
,
621 tui_make_visible (TUI_DISASM_WIN
);
623 TUI_SRC_WIN
->m_has_locator
= false;
624 TUI_DISASM_WIN
->m_has_locator
= true;
625 tui_make_visible (locator
);
626 tui_show_locator_content ();
627 tui_show_source_content (TUI_DISASM_WIN
);
629 if (TUI_CMD_WIN
== NULL
)
630 tui_win_list
[CMD_WIN
]
631 = make_command_window (cmd_height
, tui_term_height () - cmd_height
);
634 TUI_CMD_WIN
->reset (TUI_CMD_WIN
->height
,
637 TUI_CMD_WIN
->origin
.y
);
638 tui_make_visible (TUI_CMD_WIN
);
640 tui_set_current_layout_to (SRC_DISASSEM_COMMAND
);
645 /* Show the Source/Data/Command or the Dissassembly/Data/Command
648 show_data (enum tui_layout_type new_layout
)
650 int total_height
= (tui_term_height () - TUI_CMD_WIN
->height
);
651 int src_height
, data_height
;
652 enum tui_win_type win_type
;
654 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
655 gdb_assert (locator
!= nullptr);
657 data_height
= total_height
/ 2;
658 src_height
= total_height
- data_height
;
659 tui_make_all_invisible ();
660 tui_make_invisible (locator
);
661 if (tui_win_list
[DATA_WIN
] == nullptr)
662 tui_win_list
[DATA_WIN
] = make_data_window (data_height
, 0);
664 tui_win_list
[DATA_WIN
]->reset (data_height
, tui_term_width (), 0, 0);
665 tui_win_list
[DATA_WIN
]->make_visible (true);
667 if (new_layout
== SRC_DATA_COMMAND
)
670 win_type
= DISASSEM_WIN
;
672 tui_source_window_base
*base
;
673 if (tui_win_list
[win_type
] == NULL
)
675 if (win_type
== SRC_WIN
)
676 tui_win_list
[win_type
]
677 = make_source_window (src_height
, data_height
- 1);
679 tui_win_list
[win_type
]
680 = make_disasm_window (src_height
, data_height
- 1);
681 locator
->reset (2 /* 1 */ ,
685 base
= (tui_source_window_base
*) tui_win_list
[win_type
];
689 base
= (tui_source_window_base
*) tui_win_list
[win_type
];
690 tui_win_list
[win_type
]->reset (src_height
,
694 tui_make_visible (tui_win_list
[win_type
]);
695 locator
->reset (2 /* 1 */ ,
700 base
->m_has_locator
= true;
701 tui_make_visible (locator
);
702 tui_show_locator_content ();
703 tui_add_to_source_windows
704 ((tui_source_window_base
*) tui_win_list
[win_type
]);
705 tui_set_current_layout_to (new_layout
);
709 tui_gen_win_info::reset (int height_
, int width_
,
710 int origin_x_
, int origin_y_
)
718 viewport_height
= h
- 1;
724 origin
.x
= origin_x_
;
725 origin
.y
= origin_y_
;
728 /* Show the Source/Command or the Disassem layout. */
730 show_source_or_disasm_and_command (enum tui_layout_type layout_type
)
732 if (tui_current_layout () != layout_type
)
734 struct tui_win_info
**win_info_ptr
;
735 int src_height
, cmd_height
;
736 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
737 gdb_assert (locator
!= nullptr);
739 if (TUI_CMD_WIN
!= NULL
)
740 cmd_height
= TUI_CMD_WIN
->height
;
742 cmd_height
= tui_term_height () / 3;
743 src_height
= tui_term_height () - cmd_height
;
745 if (layout_type
== SRC_COMMAND
)
746 win_info_ptr
= &tui_win_list
[SRC_WIN
];
748 win_info_ptr
= &tui_win_list
[DISASSEM_WIN
];
750 tui_source_window_base
*base
;
751 if ((*win_info_ptr
) == NULL
)
753 if (layout_type
== SRC_COMMAND
)
754 *win_info_ptr
= make_source_window (src_height
- 1, 0);
756 *win_info_ptr
= make_disasm_window (src_height
- 1, 0);
757 locator
->reset (2 /* 1 */ ,
761 base
= (tui_source_window_base
*) *win_info_ptr
;
765 base
= (tui_source_window_base
*) *win_info_ptr
;
766 locator
->reset (2 /* 1 */ ,
770 base
->m_has_locator
= true;
771 (*win_info_ptr
)->reset (src_height
- 1,
775 tui_make_visible (*win_info_ptr
);
778 base
->m_has_locator
= true;
779 tui_make_visible (locator
);
780 tui_show_locator_content ();
781 tui_show_source_content (base
);
783 if (TUI_CMD_WIN
== NULL
)
785 tui_win_list
[CMD_WIN
] = make_command_window (cmd_height
,
790 TUI_CMD_WIN
->reset (TUI_CMD_WIN
->height
,
792 TUI_CMD_WIN
->origin
.x
,
793 TUI_CMD_WIN
->origin
.y
);
794 tui_make_visible (TUI_CMD_WIN
);
796 tui_set_current_layout_to (layout_type
);