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 void show_source_command (void);
48 static void show_disasm_command (void);
49 static void show_source_disasm_command (void);
50 static void show_data (enum tui_layout_type
);
51 static enum tui_layout_type
next_layout (void);
52 static enum tui_layout_type
prev_layout (void);
53 static void tui_layout_command (const char *, int);
54 static void extract_display_start_addr (struct gdbarch
**, CORE_ADDR
*);
57 /***************************************
59 ***************************************/
61 /* Show the screen layout defined. */
63 show_layout (enum tui_layout_type layout
)
65 enum tui_layout_type cur_layout
= tui_current_layout ();
67 if (layout
!= cur_layout
)
69 /* Since the new layout may cause changes in window size, we
70 should free the content and reallocate on next display of
72 tui_clear_source_windows ();
73 if (layout
== SRC_DATA_COMMAND
74 || layout
== DISASSEM_DATA_COMMAND
)
81 /* First make the current layout be invisible. */
82 tui_make_all_invisible ();
83 tui_locator_win_info_ptr ()->make_visible (false);
87 /* Now show the new layout. */
89 show_source_command ();
90 tui_add_to_source_windows (TUI_SRC_WIN
);
92 case DISASSEM_COMMAND
:
93 show_disasm_command ();
94 tui_add_to_source_windows (TUI_DISASM_WIN
);
96 case SRC_DISASSEM_COMMAND
:
97 show_source_disasm_command ();
98 tui_add_to_source_windows (TUI_SRC_WIN
);
99 tui_add_to_source_windows (TUI_DISASM_WIN
);
109 /* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
110 SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. */
112 tui_set_layout (enum tui_layout_type layout_type
)
114 gdb_assert (layout_type
!= UNDEFINED_LAYOUT
);
116 enum tui_layout_type cur_layout
= tui_current_layout ();
117 struct gdbarch
*gdbarch
;
119 struct tui_win_info
*win_with_focus
= tui_win_with_focus ();
120 struct tui_layout_def
*layout_def
= tui_layout_def ();
122 extract_display_start_addr (&gdbarch
, &addr
);
124 enum tui_layout_type new_layout
= layout_type
;
126 if (new_layout
!= cur_layout
)
128 show_layout (new_layout
);
130 /* Now determine where focus should be. */
131 if (win_with_focus
!= TUI_CMD_WIN
)
136 tui_set_win_focus_to (TUI_SRC_WIN
);
137 layout_def
->display_mode
= SRC_WIN
;
139 case DISASSEM_COMMAND
:
140 /* The previous layout was not showing code.
141 This can happen if there is no source
144 1. if the source file is in another dir OR
145 2. if target was compiled without -g
146 We still want to show the assembly though! */
148 tui_get_begin_asm_address (&gdbarch
, &addr
);
149 tui_set_win_focus_to (TUI_DISASM_WIN
);
150 layout_def
->display_mode
= DISASSEM_WIN
;
152 case SRC_DISASSEM_COMMAND
:
153 /* The previous layout was not showing code.
154 This can happen if there is no source
157 1. if the source file is in another dir OR
158 2. if target was compiled without -g
159 We still want to show the assembly though! */
161 tui_get_begin_asm_address (&gdbarch
, &addr
);
162 if (win_with_focus
== TUI_SRC_WIN
)
163 tui_set_win_focus_to (TUI_SRC_WIN
);
165 tui_set_win_focus_to (TUI_DISASM_WIN
);
167 case SRC_DATA_COMMAND
:
168 if (win_with_focus
!= TUI_DATA_WIN
)
169 tui_set_win_focus_to (TUI_SRC_WIN
);
171 tui_set_win_focus_to (TUI_DATA_WIN
);
172 layout_def
->display_mode
= SRC_WIN
;
174 case DISASSEM_DATA_COMMAND
:
175 /* The previous layout was not showing code.
176 This can happen if there is no source
179 1. if the source file is in another dir OR
180 2. if target was compiled without -g
181 We still want to show the assembly though! */
183 tui_get_begin_asm_address (&gdbarch
, &addr
);
184 if (win_with_focus
!= TUI_DATA_WIN
)
185 tui_set_win_focus_to (TUI_DISASM_WIN
);
187 tui_set_win_focus_to (TUI_DATA_WIN
);
188 layout_def
->display_mode
= DISASSEM_WIN
;
195 * Now update the window content.
197 tui_update_source_windows_with_addr (gdbarch
, addr
);
198 if (new_layout
== SRC_DATA_COMMAND
199 || new_layout
== DISASSEM_DATA_COMMAND
)
200 tui_show_registers (TUI_DATA_WIN
->current_group
);
204 /* Add the specified window to the layout in a logical way. This
205 means setting up the most logical layout given the window to be
208 tui_add_win_to_layout (enum tui_win_type type
)
210 enum tui_layout_type cur_layout
= tui_current_layout ();
215 if (cur_layout
!= SRC_COMMAND
216 && cur_layout
!= SRC_DISASSEM_COMMAND
217 && cur_layout
!= SRC_DATA_COMMAND
)
219 tui_clear_source_windows_detail ();
220 if (cur_layout
== DISASSEM_DATA_COMMAND
)
221 show_layout (SRC_DATA_COMMAND
);
223 show_layout (SRC_COMMAND
);
227 if (cur_layout
!= DISASSEM_COMMAND
228 && cur_layout
!= SRC_DISASSEM_COMMAND
229 && cur_layout
!= DISASSEM_DATA_COMMAND
)
231 tui_clear_source_windows_detail ();
232 if (cur_layout
== SRC_DATA_COMMAND
)
233 show_layout (DISASSEM_DATA_COMMAND
);
235 show_layout (DISASSEM_COMMAND
);
239 if (cur_layout
!= SRC_DATA_COMMAND
240 && cur_layout
!= DISASSEM_DATA_COMMAND
)
242 if (cur_layout
== DISASSEM_COMMAND
)
243 show_layout (DISASSEM_DATA_COMMAND
);
245 show_layout (SRC_DATA_COMMAND
);
254 /* Answer the height of a window. If it hasn't been created yet,
255 answer what the height of a window would be based upon its type and
258 tui_default_win_height (enum tui_win_type type
,
259 enum tui_layout_type layout
)
263 if (tui_win_list
[type
] != NULL
)
264 h
= tui_win_list
[type
]->height
;
270 case DISASSEM_COMMAND
:
271 if (TUI_CMD_WIN
== NULL
)
272 h
= tui_term_height () / 2;
274 h
= tui_term_height () - TUI_CMD_WIN
->height
;
276 case SRC_DISASSEM_COMMAND
:
277 case SRC_DATA_COMMAND
:
278 case DISASSEM_DATA_COMMAND
:
279 if (TUI_CMD_WIN
== NULL
)
280 h
= tui_term_height () / 3;
282 h
= (tui_term_height () - TUI_CMD_WIN
->height
) / 2;
294 /* Answer the height of a window. If it hasn't been created yet,
295 answer what the height of a window would be based upon its type and
298 tui_default_win_viewport_height (enum tui_win_type type
,
299 enum tui_layout_type layout
)
303 h
= tui_default_win_height (type
, layout
);
305 if (tui_win_list
[type
] == TUI_CMD_WIN
)
313 /* Complete possible layout names. TEXT is the complete text entered so
314 far, WORD is the word currently being completed. */
317 layout_completer (struct cmd_list_element
*ignore
,
318 completion_tracker
&tracker
,
319 const char *text
, const char *word
)
321 static const char *layout_names
[] =
322 { "src", "asm", "split", "regs", "next", "prev", NULL
};
324 complete_on_enum (tracker
, layout_names
, text
, word
);
327 /* Function to initialize gdb commands, for tui window layout
331 _initialize_tui_layout (void)
333 struct cmd_list_element
*cmd
;
335 cmd
= add_com ("layout", class_tui
, tui_layout_command
, _("\
336 Change the layout of windows.\n\
337 Usage: layout prev | next | LAYOUT-NAME\n\
339 src : Displays source and command windows.\n\
340 asm : Displays disassembly and command windows.\n\
341 split : Displays source, disassembly and command windows.\n\
342 regs : Displays register window. If existing layout\n\
343 is source/command or assembly/command, the \n\
344 register window is displayed. If the\n\
345 source/assembly/command (split) is displayed, \n\
346 the register window is displayed with \n\
347 the window that has current logical focus."));
348 set_cmd_completer (cmd
, layout_completer
);
352 /*************************
353 ** STATIC LOCAL FUNCTIONS
354 **************************/
357 /* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
360 tui_layout_command (const char *layout_name
, int from_tty
)
363 enum tui_layout_type new_layout
= UNDEFINED_LAYOUT
;
364 enum tui_layout_type cur_layout
= tui_current_layout ();
366 if (layout_name
== NULL
)
367 error (_("Usage: layout prev | next | LAYOUT-NAME"));
369 std::string copy
= layout_name
;
370 for (i
= 0; i
< copy
.size (); i
++)
371 copy
[i
] = toupper (copy
[i
]);
372 const char *buf_ptr
= copy
.c_str ();
374 /* First check for ambiguous input. */
375 if (strlen (buf_ptr
) <= 1 && *buf_ptr
== 'S')
376 error (_("Ambiguous command input."));
378 if (subset_compare (buf_ptr
, "SRC"))
379 new_layout
= SRC_COMMAND
;
380 else if (subset_compare (buf_ptr
, "ASM"))
381 new_layout
= DISASSEM_COMMAND
;
382 else if (subset_compare (buf_ptr
, "SPLIT"))
383 new_layout
= SRC_DISASSEM_COMMAND
;
384 else if (subset_compare (buf_ptr
, "REGS"))
386 if (cur_layout
== SRC_COMMAND
387 || cur_layout
== SRC_DATA_COMMAND
)
388 new_layout
= SRC_DATA_COMMAND
;
390 new_layout
= DISASSEM_DATA_COMMAND
;
392 else if (subset_compare (buf_ptr
, "NEXT"))
393 new_layout
= next_layout ();
394 else if (subset_compare (buf_ptr
, "PREV"))
395 new_layout
= prev_layout ();
397 error (_("Unrecognized layout: %s"), layout_name
);
399 /* Make sure the curses mode is enabled. */
401 tui_set_layout (new_layout
);
406 extract_display_start_addr (struct gdbarch
**gdbarch_p
, CORE_ADDR
*addr_p
)
408 enum tui_layout_type cur_layout
= tui_current_layout ();
409 struct gdbarch
*gdbarch
= get_current_arch ();
412 struct symtab_and_line cursal
= get_current_source_symtab_and_line ();
417 case SRC_DATA_COMMAND
:
418 gdbarch
= TUI_SRC_WIN
->gdbarch
;
419 find_line_pc (cursal
.symtab
,
420 TUI_SRC_WIN
->start_line_or_addr
.u
.line_no
,
424 case DISASSEM_COMMAND
:
425 case SRC_DISASSEM_COMMAND
:
426 case DISASSEM_DATA_COMMAND
:
427 gdbarch
= TUI_DISASM_WIN
->gdbarch
;
428 addr
= TUI_DISASM_WIN
->start_line_or_addr
.u
.addr
;
435 *gdbarch_p
= gdbarch
;
440 /* Answer the previous layout to cycle to. */
441 static enum tui_layout_type
446 new_layout
= tui_current_layout ();
447 if (new_layout
== UNDEFINED_LAYOUT
)
448 new_layout
= SRC_COMMAND
;
452 if (new_layout
== UNDEFINED_LAYOUT
)
453 new_layout
= SRC_COMMAND
;
456 return (enum tui_layout_type
) new_layout
;
460 /* Answer the next layout to cycle to. */
461 static enum tui_layout_type
466 new_layout
= tui_current_layout ();
467 if (new_layout
== SRC_COMMAND
)
468 new_layout
= DISASSEM_DATA_COMMAND
;
472 if (new_layout
== UNDEFINED_LAYOUT
)
473 new_layout
= DISASSEM_DATA_COMMAND
;
476 return (enum tui_layout_type
) new_layout
;
479 /* Show the Source/Command layout. */
481 show_source_command (void)
483 show_source_or_disasm_and_command (SRC_COMMAND
);
487 /* Show the Dissassem/Command layout. */
489 show_disasm_command (void)
491 show_source_or_disasm_and_command (DISASSEM_COMMAND
);
495 /* Show the Source/Disassem/Command layout. */
497 show_source_disasm_command (void)
499 if (tui_current_layout () != SRC_DISASSEM_COMMAND
)
501 int cmd_height
, src_height
, asm_height
;
503 if (TUI_CMD_WIN
!= NULL
)
504 cmd_height
= TUI_CMD_WIN
->height
;
506 cmd_height
= tui_term_height () / 3;
508 src_height
= (tui_term_height () - cmd_height
) / 2;
509 asm_height
= tui_term_height () - (src_height
+ cmd_height
);
511 if (TUI_SRC_WIN
== NULL
)
512 tui_win_list
[SRC_WIN
] = new tui_source_window ();
513 TUI_SRC_WIN
->reset (src_height
,
517 TUI_SRC_WIN
->make_visible (true);
518 TUI_SRC_WIN
->m_has_locator
= false;
520 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
521 gdb_assert (locator
!= nullptr);
523 tui_show_source_content (TUI_SRC_WIN
);
524 if (TUI_DISASM_WIN
== NULL
)
525 tui_win_list
[DISASSEM_WIN
] = new tui_disasm_window ();
526 TUI_DISASM_WIN
->reset (asm_height
,
530 TUI_DISASM_WIN
->make_visible (true);
531 locator
->reset (2 /* 1 */ ,
534 (src_height
+ asm_height
) - 1);
535 TUI_SRC_WIN
->m_has_locator
= false;
536 TUI_DISASM_WIN
->m_has_locator
= true;
537 locator
->make_visible (true);
538 tui_show_locator_content ();
539 tui_show_source_content (TUI_DISASM_WIN
);
541 if (TUI_CMD_WIN
== NULL
)
542 tui_win_list
[CMD_WIN
] = new tui_cmd_window ();
543 TUI_CMD_WIN
->reset (cmd_height
,
546 tui_term_height () - cmd_height
);
547 /* FIXME tui_cmd_window won't recreate the handle on
548 make_visible, so we need this instead. */
549 tui_make_window (TUI_CMD_WIN
, DONT_BOX_WINDOW
);
550 tui_set_current_layout_to (SRC_DISASSEM_COMMAND
);
555 /* Show the Source/Data/Command or the Dissassembly/Data/Command
558 show_data (enum tui_layout_type new_layout
)
560 int total_height
= (tui_term_height () - TUI_CMD_WIN
->height
);
561 int src_height
, data_height
;
562 enum tui_win_type win_type
;
564 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
565 gdb_assert (locator
!= nullptr);
567 data_height
= total_height
/ 2;
568 src_height
= total_height
- data_height
;
569 tui_make_all_invisible ();
570 locator
->make_visible (false);
571 if (tui_win_list
[DATA_WIN
] == nullptr)
572 tui_win_list
[DATA_WIN
] = new tui_data_window ();
573 tui_win_list
[DATA_WIN
]->reset (data_height
, tui_term_width (), 0, 0);
574 tui_win_list
[DATA_WIN
]->make_visible (true);
576 if (new_layout
== SRC_DATA_COMMAND
)
579 win_type
= DISASSEM_WIN
;
581 if (tui_win_list
[win_type
] == NULL
)
583 if (win_type
== SRC_WIN
)
584 tui_win_list
[win_type
] = new tui_source_window ();
586 tui_win_list
[win_type
] = new tui_disasm_window ();
589 tui_source_window_base
*base
590 = (tui_source_window_base
*) tui_win_list
[win_type
];
591 tui_win_list
[win_type
]->reset (src_height
,
595 locator
->reset (2 /* 1 */ ,
599 base
->make_visible (true);
600 base
->m_has_locator
= true;
601 locator
->make_visible (true);
602 tui_show_locator_content ();
603 tui_add_to_source_windows (base
);
604 tui_set_current_layout_to (new_layout
);
608 tui_gen_win_info::reset (int height_
, int width_
,
609 int origin_x_
, int origin_y_
)
617 viewport_height
= h
- 1;
623 origin
.x
= origin_x_
;
624 origin
.y
= origin_y_
;
627 /* Show the Source/Command or the Disassem layout. */
629 show_source_or_disasm_and_command (enum tui_layout_type layout_type
)
631 if (tui_current_layout () != layout_type
)
633 struct tui_source_window_base
*win_info
;
634 int src_height
, cmd_height
;
635 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
636 gdb_assert (locator
!= nullptr);
638 if (TUI_CMD_WIN
!= NULL
)
639 cmd_height
= TUI_CMD_WIN
->height
;
641 cmd_height
= tui_term_height () / 3;
642 src_height
= tui_term_height () - cmd_height
;
644 if (layout_type
== SRC_COMMAND
)
646 if (tui_win_list
[SRC_WIN
] == nullptr)
647 tui_win_list
[SRC_WIN
] = new tui_source_window ();
648 win_info
= TUI_SRC_WIN
;
652 if (tui_win_list
[DISASSEM_WIN
] == nullptr)
653 tui_win_list
[DISASSEM_WIN
] = new tui_disasm_window ();
654 win_info
= TUI_DISASM_WIN
;
657 locator
->reset (2 /* 1 */ ,
661 win_info
->reset (src_height
- 1,
665 win_info
->make_visible (true);
668 win_info
->m_has_locator
= true;
669 locator
->make_visible (true);
670 tui_show_locator_content ();
671 tui_show_source_content (win_info
);
673 if (TUI_CMD_WIN
== NULL
)
674 tui_win_list
[CMD_WIN
] = new tui_cmd_window ();
675 TUI_CMD_WIN
->reset (cmd_height
,
679 /* FIXME tui_cmd_window won't recreate the handle on
680 make_visible, so we need this instead. */
681 tui_make_window (TUI_CMD_WIN
, DONT_BOX_WINDOW
);
682 tui_set_current_layout_to (layout_type
);