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 /* First make the current layout be invisible. */
84 tui_make_all_invisible ();
85 tui_locator_win_info_ptr ()->make_visible (false);
86 if (layout
== SRC_DATA_COMMAND
87 || layout
== DISASSEM_DATA_COMMAND
)
96 /* Now show the new layout. */
98 show_source_command ();
99 tui_add_to_source_windows (TUI_SRC_WIN
);
101 case DISASSEM_COMMAND
:
102 show_disasm_command ();
103 tui_add_to_source_windows (TUI_DISASM_WIN
);
105 case SRC_DISASSEM_COMMAND
:
106 show_source_disasm_command ();
107 tui_add_to_source_windows (TUI_SRC_WIN
);
108 tui_add_to_source_windows (TUI_DISASM_WIN
);
118 /* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
119 SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. */
121 tui_set_layout (enum tui_layout_type layout_type
)
123 gdb_assert (layout_type
!= UNDEFINED_LAYOUT
);
125 enum tui_layout_type cur_layout
= tui_current_layout ();
126 struct gdbarch
*gdbarch
;
128 struct tui_win_info
*win_with_focus
= tui_win_with_focus ();
130 extract_display_start_addr (&gdbarch
, &addr
);
132 enum tui_layout_type new_layout
= layout_type
;
134 if (new_layout
!= cur_layout
)
136 show_layout (new_layout
);
138 /* Now determine where focus should be. */
139 if (win_with_focus
!= TUI_CMD_WIN
)
144 tui_set_win_focus_to (TUI_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
);
158 case SRC_DISASSEM_COMMAND
:
159 /* The previous layout was not showing code.
160 This can happen if there is no source
163 1. if the source file is in another dir OR
164 2. if target was compiled without -g
165 We still want to show the assembly though! */
167 tui_get_begin_asm_address (&gdbarch
, &addr
);
168 if (win_with_focus
== TUI_SRC_WIN
)
169 tui_set_win_focus_to (TUI_SRC_WIN
);
171 tui_set_win_focus_to (TUI_DISASM_WIN
);
173 case SRC_DATA_COMMAND
:
174 if (win_with_focus
!= TUI_DATA_WIN
)
175 tui_set_win_focus_to (TUI_SRC_WIN
);
177 tui_set_win_focus_to (TUI_DATA_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
);
199 * Now update the window content.
201 tui_update_source_windows_with_addr (gdbarch
, addr
);
202 if (new_layout
== SRC_DATA_COMMAND
203 || new_layout
== DISASSEM_DATA_COMMAND
)
204 tui_show_registers (TUI_DATA_WIN
->current_group
);
208 /* Add the specified window to the layout in a logical way. This
209 means setting up the most logical layout given the window to be
212 tui_add_win_to_layout (enum tui_win_type type
)
214 enum tui_layout_type cur_layout
= tui_current_layout ();
219 if (cur_layout
!= SRC_COMMAND
220 && cur_layout
!= SRC_DISASSEM_COMMAND
221 && cur_layout
!= SRC_DATA_COMMAND
)
223 tui_clear_source_windows_detail ();
224 if (cur_layout
== DISASSEM_DATA_COMMAND
)
225 show_layout (SRC_DATA_COMMAND
);
227 show_layout (SRC_COMMAND
);
231 if (cur_layout
!= DISASSEM_COMMAND
232 && cur_layout
!= SRC_DISASSEM_COMMAND
233 && cur_layout
!= DISASSEM_DATA_COMMAND
)
235 tui_clear_source_windows_detail ();
236 if (cur_layout
== SRC_DATA_COMMAND
)
237 show_layout (DISASSEM_DATA_COMMAND
);
239 show_layout (DISASSEM_COMMAND
);
243 if (cur_layout
!= SRC_DATA_COMMAND
244 && cur_layout
!= DISASSEM_DATA_COMMAND
)
246 if (cur_layout
== DISASSEM_COMMAND
)
247 show_layout (DISASSEM_DATA_COMMAND
);
249 show_layout (SRC_DATA_COMMAND
);
258 /* Answer the height of a window. If it hasn't been created yet,
259 answer what the height of a window would be based upon its type and
262 tui_default_win_height (enum tui_win_type type
,
263 enum tui_layout_type layout
)
267 if (tui_win_list
[type
] != NULL
)
268 h
= tui_win_list
[type
]->height
;
274 case DISASSEM_COMMAND
:
275 if (TUI_CMD_WIN
== NULL
)
276 h
= tui_term_height () / 2;
278 h
= tui_term_height () - TUI_CMD_WIN
->height
;
280 case SRC_DISASSEM_COMMAND
:
281 case SRC_DATA_COMMAND
:
282 case DISASSEM_DATA_COMMAND
:
283 if (TUI_CMD_WIN
== NULL
)
284 h
= tui_term_height () / 3;
286 h
= (tui_term_height () - TUI_CMD_WIN
->height
) / 2;
298 /* Answer the height of a window. If it hasn't been created yet,
299 answer what the height of a window would be based upon its type and
302 tui_default_win_viewport_height (enum tui_win_type type
,
303 enum tui_layout_type layout
)
307 h
= tui_default_win_height (type
, layout
);
309 if (tui_win_list
[type
] == TUI_CMD_WIN
)
317 /* Complete possible layout names. TEXT is the complete text entered so
318 far, WORD is the word currently being completed. */
321 layout_completer (struct cmd_list_element
*ignore
,
322 completion_tracker
&tracker
,
323 const char *text
, const char *word
)
325 static const char *layout_names
[] =
326 { "src", "asm", "split", "regs", "next", "prev", NULL
};
328 complete_on_enum (tracker
, layout_names
, text
, word
);
331 /* Function to initialize gdb commands, for tui window layout
335 _initialize_tui_layout (void)
337 struct cmd_list_element
*cmd
;
339 cmd
= add_com ("layout", class_tui
, tui_layout_command
, _("\
340 Change the layout of windows.\n\
341 Usage: layout prev | next | LAYOUT-NAME\n\
343 src : Displays source and command windows.\n\
344 asm : Displays disassembly and command windows.\n\
345 split : Displays source, disassembly and command windows.\n\
346 regs : Displays register window. If existing layout\n\
347 is source/command or assembly/command, the \n\
348 register window is displayed. If the\n\
349 source/assembly/command (split) is displayed, \n\
350 the register window is displayed with \n\
351 the window that has current logical focus."));
352 set_cmd_completer (cmd
, layout_completer
);
356 /*************************
357 ** STATIC LOCAL FUNCTIONS
358 **************************/
361 /* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
364 tui_layout_command (const char *layout_name
, int from_tty
)
367 enum tui_layout_type new_layout
= UNDEFINED_LAYOUT
;
368 enum tui_layout_type cur_layout
= tui_current_layout ();
370 if (layout_name
== NULL
)
371 error (_("Usage: layout prev | next | LAYOUT-NAME"));
373 std::string copy
= layout_name
;
374 for (i
= 0; i
< copy
.size (); i
++)
375 copy
[i
] = toupper (copy
[i
]);
376 const char *buf_ptr
= copy
.c_str ();
378 /* First check for ambiguous input. */
379 if (strlen (buf_ptr
) <= 1 && *buf_ptr
== 'S')
380 error (_("Ambiguous command input."));
382 if (subset_compare (buf_ptr
, "SRC"))
383 new_layout
= SRC_COMMAND
;
384 else if (subset_compare (buf_ptr
, "ASM"))
385 new_layout
= DISASSEM_COMMAND
;
386 else if (subset_compare (buf_ptr
, "SPLIT"))
387 new_layout
= SRC_DISASSEM_COMMAND
;
388 else if (subset_compare (buf_ptr
, "REGS"))
390 if (cur_layout
== SRC_COMMAND
391 || cur_layout
== SRC_DATA_COMMAND
)
392 new_layout
= SRC_DATA_COMMAND
;
394 new_layout
= DISASSEM_DATA_COMMAND
;
396 else if (subset_compare (buf_ptr
, "NEXT"))
397 new_layout
= next_layout ();
398 else if (subset_compare (buf_ptr
, "PREV"))
399 new_layout
= prev_layout ();
401 error (_("Unrecognized layout: %s"), layout_name
);
403 /* Make sure the curses mode is enabled. */
405 tui_set_layout (new_layout
);
410 extract_display_start_addr (struct gdbarch
**gdbarch_p
, CORE_ADDR
*addr_p
)
412 enum tui_layout_type cur_layout
= tui_current_layout ();
413 struct gdbarch
*gdbarch
= get_current_arch ();
416 struct symtab_and_line cursal
= get_current_source_symtab_and_line ();
421 case SRC_DATA_COMMAND
:
422 gdbarch
= TUI_SRC_WIN
->gdbarch
;
423 find_line_pc (cursal
.symtab
,
424 TUI_SRC_WIN
->start_line_or_addr
.u
.line_no
,
428 case DISASSEM_COMMAND
:
429 case SRC_DISASSEM_COMMAND
:
430 case DISASSEM_DATA_COMMAND
:
431 gdbarch
= TUI_DISASM_WIN
->gdbarch
;
432 addr
= TUI_DISASM_WIN
->start_line_or_addr
.u
.addr
;
439 *gdbarch_p
= gdbarch
;
444 /* Answer the previous layout to cycle to. */
445 static enum tui_layout_type
450 new_layout
= tui_current_layout ();
451 if (new_layout
== UNDEFINED_LAYOUT
)
452 new_layout
= SRC_COMMAND
;
456 if (new_layout
== UNDEFINED_LAYOUT
)
457 new_layout
= SRC_COMMAND
;
460 return (enum tui_layout_type
) new_layout
;
464 /* Answer the next layout to cycle to. */
465 static enum tui_layout_type
470 new_layout
= tui_current_layout ();
471 if (new_layout
== SRC_COMMAND
)
472 new_layout
= DISASSEM_DATA_COMMAND
;
476 if (new_layout
== UNDEFINED_LAYOUT
)
477 new_layout
= DISASSEM_DATA_COMMAND
;
480 return (enum tui_layout_type
) new_layout
;
483 /* Show the Source/Command layout. */
485 show_source_command (void)
487 show_source_or_disasm_and_command (SRC_COMMAND
);
491 /* Show the Dissassem/Command layout. */
493 show_disasm_command (void)
495 show_source_or_disasm_and_command (DISASSEM_COMMAND
);
499 /* Show the Source/Disassem/Command layout. */
501 show_source_disasm_command (void)
503 if (tui_current_layout () != SRC_DISASSEM_COMMAND
)
505 int cmd_height
, src_height
, asm_height
;
507 if (TUI_CMD_WIN
!= NULL
)
508 cmd_height
= TUI_CMD_WIN
->height
;
510 cmd_height
= tui_term_height () / 3;
512 src_height
= (tui_term_height () - cmd_height
) / 2;
513 asm_height
= tui_term_height () - (src_height
+ cmd_height
);
515 if (TUI_SRC_WIN
== NULL
)
516 tui_win_list
[SRC_WIN
] = new tui_source_window ();
517 TUI_SRC_WIN
->reset (src_height
,
521 TUI_SRC_WIN
->make_visible (true);
522 TUI_SRC_WIN
->m_has_locator
= false;
524 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
525 gdb_assert (locator
!= nullptr);
527 tui_show_source_content (TUI_SRC_WIN
);
528 if (TUI_DISASM_WIN
== NULL
)
529 tui_win_list
[DISASSEM_WIN
] = new tui_disasm_window ();
530 TUI_DISASM_WIN
->reset (asm_height
,
534 TUI_DISASM_WIN
->make_visible (true);
535 locator
->reset (2 /* 1 */ ,
538 (src_height
+ asm_height
) - 1);
539 TUI_SRC_WIN
->m_has_locator
= false;
540 TUI_DISASM_WIN
->m_has_locator
= true;
541 locator
->make_visible (true);
542 tui_show_locator_content ();
543 tui_show_source_content (TUI_DISASM_WIN
);
545 if (TUI_CMD_WIN
== NULL
)
546 tui_win_list
[CMD_WIN
] = new tui_cmd_window ();
547 TUI_CMD_WIN
->reset (cmd_height
,
550 tui_term_height () - cmd_height
);
551 /* FIXME tui_cmd_window won't recreate the handle on
552 make_visible, so we need this instead. */
553 tui_make_window (TUI_CMD_WIN
, DONT_BOX_WINDOW
);
554 current_layout
= SRC_DISASSEM_COMMAND
;
559 /* Show the Source/Data/Command or the Dissassembly/Data/Command
562 show_data (enum tui_layout_type new_layout
)
564 int total_height
= (tui_term_height () - TUI_CMD_WIN
->height
);
565 int src_height
, data_height
;
566 enum tui_win_type win_type
;
568 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
569 gdb_assert (locator
!= nullptr);
571 data_height
= total_height
/ 2;
572 src_height
= total_height
- data_height
;
573 if (tui_win_list
[DATA_WIN
] == nullptr)
574 tui_win_list
[DATA_WIN
] = new tui_data_window ();
575 tui_win_list
[DATA_WIN
]->reset (data_height
, tui_term_width (), 0, 0);
576 tui_win_list
[DATA_WIN
]->make_visible (true);
578 if (new_layout
== SRC_DATA_COMMAND
)
581 win_type
= DISASSEM_WIN
;
583 if (tui_win_list
[win_type
] == NULL
)
585 if (win_type
== SRC_WIN
)
586 tui_win_list
[win_type
] = new tui_source_window ();
588 tui_win_list
[win_type
] = new tui_disasm_window ();
591 tui_source_window_base
*base
592 = (tui_source_window_base
*) tui_win_list
[win_type
];
593 tui_win_list
[win_type
]->reset (src_height
,
597 locator
->reset (2 /* 1 */ ,
601 base
->make_visible (true);
602 base
->m_has_locator
= true;
603 locator
->make_visible (true);
604 tui_show_locator_content ();
605 tui_add_to_source_windows (base
);
606 current_layout
= new_layout
;
610 tui_gen_win_info::reset (int height_
, int width_
,
611 int origin_x_
, int origin_y_
)
619 viewport_height
= h
- 1;
625 origin
.x
= origin_x_
;
626 origin
.y
= origin_y_
;
629 /* Show the Source/Command or the Disassem layout. */
631 show_source_or_disasm_and_command (enum tui_layout_type layout_type
)
633 if (tui_current_layout () != layout_type
)
635 struct tui_source_window_base
*win_info
;
636 int src_height
, cmd_height
;
637 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
638 gdb_assert (locator
!= nullptr);
640 if (TUI_CMD_WIN
!= NULL
)
641 cmd_height
= TUI_CMD_WIN
->height
;
643 cmd_height
= tui_term_height () / 3;
644 src_height
= tui_term_height () - cmd_height
;
646 if (layout_type
== SRC_COMMAND
)
648 if (tui_win_list
[SRC_WIN
] == nullptr)
649 tui_win_list
[SRC_WIN
] = new tui_source_window ();
650 win_info
= TUI_SRC_WIN
;
654 if (tui_win_list
[DISASSEM_WIN
] == nullptr)
655 tui_win_list
[DISASSEM_WIN
] = new tui_disasm_window ();
656 win_info
= TUI_DISASM_WIN
;
659 locator
->reset (2 /* 1 */ ,
663 win_info
->reset (src_height
- 1,
667 win_info
->make_visible (true);
670 win_info
->m_has_locator
= true;
671 locator
->make_visible (true);
672 tui_show_locator_content ();
673 tui_show_source_content (win_info
);
675 if (TUI_CMD_WIN
== NULL
)
676 tui_win_list
[CMD_WIN
] = new tui_cmd_window ();
677 TUI_CMD_WIN
->reset (cmd_height
,
681 /* FIXME tui_cmd_window won't recreate the handle on
682 make_visible, so we need this instead. */
683 tui_make_window (TUI_CMD_WIN
, DONT_BOX_WINDOW
);
684 current_layout
= layout_type
;