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-command.h"
32 #include "tui/tui-data.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 "tui/tui-source.h"
41 #include "gdb_curses.h"
43 /*******************************
45 ********************************/
46 static void show_layout (enum tui_layout_type
);
47 static void show_source_or_disasm_and_command (enum tui_layout_type
);
48 static void show_source_command (void);
49 static void show_disasm_command (void);
50 static void show_source_disasm_command (void);
51 static void show_data (enum tui_layout_type
);
52 static enum tui_layout_type
next_layout (void);
53 static enum tui_layout_type
prev_layout (void);
54 static void tui_layout_command (const char *, int);
55 static void extract_display_start_addr (struct gdbarch
**, CORE_ADDR
*);
58 static enum tui_layout_type current_layout
= UNDEFINED_LAYOUT
;
60 /* Accessor for the current layout. */
62 tui_current_layout (void)
64 return current_layout
;
67 /***************************************
69 ***************************************/
71 /* Show the screen layout defined. */
73 show_layout (enum tui_layout_type layout
)
75 enum tui_layout_type cur_layout
= tui_current_layout ();
77 if (layout
!= cur_layout
)
79 /* Since the new layout may cause changes in window size, we
80 should free the content and reallocate on next display of
82 tui_clear_source_windows ();
83 if (layout
== SRC_DATA_COMMAND
84 || layout
== DISASSEM_DATA_COMMAND
)
91 /* First make the current layout be invisible. */
92 tui_make_all_invisible ();
93 tui_locator_win_info_ptr ()->make_visible (false);
97 /* Now show the new layout. */
99 show_source_command ();
100 tui_add_to_source_windows (TUI_SRC_WIN
);
102 case DISASSEM_COMMAND
:
103 show_disasm_command ();
104 tui_add_to_source_windows (TUI_DISASM_WIN
);
106 case SRC_DISASSEM_COMMAND
:
107 show_source_disasm_command ();
108 tui_add_to_source_windows (TUI_SRC_WIN
);
109 tui_add_to_source_windows (TUI_DISASM_WIN
);
119 /* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
120 SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. */
122 tui_set_layout (enum tui_layout_type layout_type
)
124 gdb_assert (layout_type
!= UNDEFINED_LAYOUT
);
126 enum tui_layout_type cur_layout
= tui_current_layout ();
127 struct gdbarch
*gdbarch
;
129 struct tui_win_info
*win_with_focus
= tui_win_with_focus ();
131 extract_display_start_addr (&gdbarch
, &addr
);
133 enum tui_layout_type new_layout
= layout_type
;
135 if (new_layout
!= cur_layout
)
137 show_layout (new_layout
);
139 /* Now determine where focus should be. */
140 if (win_with_focus
!= TUI_CMD_WIN
)
145 tui_set_win_focus_to (TUI_SRC_WIN
);
147 case DISASSEM_COMMAND
:
148 /* The previous layout was not showing code.
149 This can happen if there is no source
152 1. if the source file is in another dir OR
153 2. if target was compiled without -g
154 We still want to show the assembly though! */
156 tui_get_begin_asm_address (&gdbarch
, &addr
);
157 tui_set_win_focus_to (TUI_DISASM_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
);
180 case DISASSEM_DATA_COMMAND
:
181 /* The previous layout was not showing code.
182 This can happen if there is no source
185 1. if the source file is in another dir OR
186 2. if target was compiled without -g
187 We still want to show the assembly though! */
189 tui_get_begin_asm_address (&gdbarch
, &addr
);
190 if (win_with_focus
!= TUI_DATA_WIN
)
191 tui_set_win_focus_to (TUI_DISASM_WIN
);
193 tui_set_win_focus_to (TUI_DATA_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_layout_command (const char *layout_name
, int from_tty
)
368 enum tui_layout_type new_layout
= UNDEFINED_LAYOUT
;
369 enum tui_layout_type cur_layout
= tui_current_layout ();
371 if (layout_name
== NULL
)
372 error (_("Usage: layout prev | next | LAYOUT-NAME"));
374 std::string copy
= layout_name
;
375 for (i
= 0; i
< copy
.size (); i
++)
376 copy
[i
] = toupper (copy
[i
]);
377 const char *buf_ptr
= copy
.c_str ();
379 /* First check for ambiguous input. */
380 if (strlen (buf_ptr
) <= 1 && *buf_ptr
== 'S')
381 error (_("Ambiguous command input."));
383 if (subset_compare (buf_ptr
, "SRC"))
384 new_layout
= SRC_COMMAND
;
385 else if (subset_compare (buf_ptr
, "ASM"))
386 new_layout
= DISASSEM_COMMAND
;
387 else if (subset_compare (buf_ptr
, "SPLIT"))
388 new_layout
= SRC_DISASSEM_COMMAND
;
389 else if (subset_compare (buf_ptr
, "REGS"))
391 if (cur_layout
== SRC_COMMAND
392 || cur_layout
== SRC_DATA_COMMAND
)
393 new_layout
= SRC_DATA_COMMAND
;
395 new_layout
= DISASSEM_DATA_COMMAND
;
397 else if (subset_compare (buf_ptr
, "NEXT"))
398 new_layout
= next_layout ();
399 else if (subset_compare (buf_ptr
, "PREV"))
400 new_layout
= prev_layout ();
402 error (_("Unrecognized layout: %s"), layout_name
);
404 /* Make sure the curses mode is enabled. */
406 tui_set_layout (new_layout
);
411 extract_display_start_addr (struct gdbarch
**gdbarch_p
, CORE_ADDR
*addr_p
)
413 enum tui_layout_type cur_layout
= tui_current_layout ();
414 struct gdbarch
*gdbarch
= get_current_arch ();
417 struct symtab_and_line cursal
= get_current_source_symtab_and_line ();
422 case SRC_DATA_COMMAND
:
423 gdbarch
= TUI_SRC_WIN
->gdbarch
;
424 find_line_pc (cursal
.symtab
,
425 TUI_SRC_WIN
->start_line_or_addr
.u
.line_no
,
429 case DISASSEM_COMMAND
:
430 case SRC_DISASSEM_COMMAND
:
431 case DISASSEM_DATA_COMMAND
:
432 gdbarch
= TUI_DISASM_WIN
->gdbarch
;
433 addr
= TUI_DISASM_WIN
->start_line_or_addr
.u
.addr
;
440 *gdbarch_p
= gdbarch
;
445 /* Answer the previous layout to cycle to. */
446 static enum tui_layout_type
451 new_layout
= tui_current_layout ();
452 if (new_layout
== UNDEFINED_LAYOUT
)
453 new_layout
= SRC_COMMAND
;
457 if (new_layout
== UNDEFINED_LAYOUT
)
458 new_layout
= SRC_COMMAND
;
461 return (enum tui_layout_type
) new_layout
;
465 /* Answer the next layout to cycle to. */
466 static enum tui_layout_type
471 new_layout
= tui_current_layout ();
472 if (new_layout
== SRC_COMMAND
)
473 new_layout
= DISASSEM_DATA_COMMAND
;
477 if (new_layout
== UNDEFINED_LAYOUT
)
478 new_layout
= DISASSEM_DATA_COMMAND
;
481 return (enum tui_layout_type
) new_layout
;
484 /* Show the Source/Command layout. */
486 show_source_command (void)
488 show_source_or_disasm_and_command (SRC_COMMAND
);
492 /* Show the Dissassem/Command layout. */
494 show_disasm_command (void)
496 show_source_or_disasm_and_command (DISASSEM_COMMAND
);
500 /* Show the Source/Disassem/Command layout. */
502 show_source_disasm_command (void)
504 if (tui_current_layout () != SRC_DISASSEM_COMMAND
)
506 int cmd_height
, src_height
, asm_height
;
508 if (TUI_CMD_WIN
!= NULL
)
509 cmd_height
= TUI_CMD_WIN
->height
;
511 cmd_height
= tui_term_height () / 3;
513 src_height
= (tui_term_height () - cmd_height
) / 2;
514 asm_height
= tui_term_height () - (src_height
+ cmd_height
);
516 if (TUI_SRC_WIN
== NULL
)
517 tui_win_list
[SRC_WIN
] = new tui_source_window ();
518 TUI_SRC_WIN
->reset (src_height
,
522 TUI_SRC_WIN
->make_visible (true);
523 TUI_SRC_WIN
->m_has_locator
= false;
525 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
526 gdb_assert (locator
!= nullptr);
528 tui_show_source_content (TUI_SRC_WIN
);
529 if (TUI_DISASM_WIN
== NULL
)
530 tui_win_list
[DISASSEM_WIN
] = new tui_disasm_window ();
531 TUI_DISASM_WIN
->reset (asm_height
,
535 TUI_DISASM_WIN
->make_visible (true);
536 locator
->reset (2 /* 1 */ ,
539 (src_height
+ asm_height
) - 1);
540 TUI_SRC_WIN
->m_has_locator
= false;
541 TUI_DISASM_WIN
->m_has_locator
= true;
542 locator
->make_visible (true);
543 tui_show_locator_content ();
544 tui_show_source_content (TUI_DISASM_WIN
);
546 if (TUI_CMD_WIN
== NULL
)
547 tui_win_list
[CMD_WIN
] = new tui_cmd_window ();
548 TUI_CMD_WIN
->reset (cmd_height
,
551 tui_term_height () - cmd_height
);
552 /* FIXME tui_cmd_window won't recreate the handle on
553 make_visible, so we need this instead. */
554 tui_make_window (TUI_CMD_WIN
, DONT_BOX_WINDOW
);
555 current_layout
= SRC_DISASSEM_COMMAND
;
560 /* Show the Source/Data/Command or the Dissassembly/Data/Command
563 show_data (enum tui_layout_type new_layout
)
565 int total_height
= (tui_term_height () - TUI_CMD_WIN
->height
);
566 int src_height
, data_height
;
567 enum tui_win_type win_type
;
569 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
570 gdb_assert (locator
!= nullptr);
572 data_height
= total_height
/ 2;
573 src_height
= total_height
- data_height
;
574 tui_make_all_invisible ();
575 locator
->make_visible (false);
576 if (tui_win_list
[DATA_WIN
] == nullptr)
577 tui_win_list
[DATA_WIN
] = new tui_data_window ();
578 tui_win_list
[DATA_WIN
]->reset (data_height
, tui_term_width (), 0, 0);
579 tui_win_list
[DATA_WIN
]->make_visible (true);
581 if (new_layout
== SRC_DATA_COMMAND
)
584 win_type
= DISASSEM_WIN
;
586 if (tui_win_list
[win_type
] == NULL
)
588 if (win_type
== SRC_WIN
)
589 tui_win_list
[win_type
] = new tui_source_window ();
591 tui_win_list
[win_type
] = new tui_disasm_window ();
594 tui_source_window_base
*base
595 = (tui_source_window_base
*) tui_win_list
[win_type
];
596 tui_win_list
[win_type
]->reset (src_height
,
600 locator
->reset (2 /* 1 */ ,
604 base
->make_visible (true);
605 base
->m_has_locator
= true;
606 locator
->make_visible (true);
607 tui_show_locator_content ();
608 tui_add_to_source_windows (base
);
609 current_layout
= new_layout
;
613 tui_gen_win_info::reset (int height_
, int width_
,
614 int origin_x_
, int origin_y_
)
622 viewport_height
= h
- 1;
628 origin
.x
= origin_x_
;
629 origin
.y
= origin_y_
;
632 /* Show the Source/Command or the Disassem layout. */
634 show_source_or_disasm_and_command (enum tui_layout_type layout_type
)
636 if (tui_current_layout () != layout_type
)
638 struct tui_source_window_base
*win_info
;
639 int src_height
, cmd_height
;
640 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
641 gdb_assert (locator
!= nullptr);
643 if (TUI_CMD_WIN
!= NULL
)
644 cmd_height
= TUI_CMD_WIN
->height
;
646 cmd_height
= tui_term_height () / 3;
647 src_height
= tui_term_height () - cmd_height
;
649 if (layout_type
== SRC_COMMAND
)
651 if (tui_win_list
[SRC_WIN
] == nullptr)
652 tui_win_list
[SRC_WIN
] = new tui_source_window ();
653 win_info
= TUI_SRC_WIN
;
657 if (tui_win_list
[DISASSEM_WIN
] == nullptr)
658 tui_win_list
[DISASSEM_WIN
] = new tui_disasm_window ();
659 win_info
= TUI_DISASM_WIN
;
662 locator
->reset (2 /* 1 */ ,
666 win_info
->reset (src_height
- 1,
670 win_info
->make_visible (true);
673 win_info
->m_has_locator
= true;
674 locator
->make_visible (true);
675 tui_show_locator_content ();
676 tui_show_source_content (win_info
);
678 if (TUI_CMD_WIN
== NULL
)
679 tui_win_list
[CMD_WIN
] = new tui_cmd_window ();
680 TUI_CMD_WIN
->reset (cmd_height
,
684 /* FIXME tui_cmd_window won't recreate the handle on
685 make_visible, so we need this instead. */
686 tui_make_window (TUI_CMD_WIN
, DONT_BOX_WINDOW
);
687 current_layout
= layout_type
;