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);
88 case SRC_DATA_COMMAND
:
89 case DISASSEM_DATA_COMMAND
:
93 /* Now show the new layout. */
95 show_source_command ();
96 tui_add_to_source_windows (TUI_SRC_WIN
);
98 case DISASSEM_COMMAND
:
99 show_disasm_command ();
100 tui_add_to_source_windows (TUI_DISASM_WIN
);
102 case SRC_DISASSEM_COMMAND
:
103 show_source_disasm_command ();
104 tui_add_to_source_windows (TUI_SRC_WIN
);
105 tui_add_to_source_windows (TUI_DISASM_WIN
);
111 tui_delete_invisible_windows ();
116 /* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
117 SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. */
119 tui_set_layout (enum tui_layout_type layout_type
)
121 gdb_assert (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 ();
128 extract_display_start_addr (&gdbarch
, &addr
);
130 enum tui_layout_type new_layout
= layout_type
;
132 if (new_layout
!= cur_layout
)
134 show_layout (new_layout
);
136 /* Now determine where focus should be. */
137 if (win_with_focus
!= TUI_CMD_WIN
)
142 tui_set_win_focus_to (TUI_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
);
156 case SRC_DISASSEM_COMMAND
:
157 /* The previous layout was not showing code.
158 This can happen if there is no source
161 1. if the source file is in another dir OR
162 2. if target was compiled without -g
163 We still want to show the assembly though! */
165 tui_get_begin_asm_address (&gdbarch
, &addr
);
166 if (win_with_focus
== TUI_SRC_WIN
)
167 tui_set_win_focus_to (TUI_SRC_WIN
);
169 tui_set_win_focus_to (TUI_DISASM_WIN
);
171 case SRC_DATA_COMMAND
:
172 if (win_with_focus
!= TUI_DATA_WIN
)
173 tui_set_win_focus_to (TUI_SRC_WIN
);
175 tui_set_win_focus_to (TUI_DATA_WIN
);
177 case DISASSEM_DATA_COMMAND
:
178 /* The previous layout was not showing code.
179 This can happen if there is no source
182 1. if the source file is in another dir OR
183 2. if target was compiled without -g
184 We still want to show the assembly though! */
186 tui_get_begin_asm_address (&gdbarch
, &addr
);
187 if (win_with_focus
!= TUI_DATA_WIN
)
188 tui_set_win_focus_to (TUI_DISASM_WIN
);
190 tui_set_win_focus_to (TUI_DATA_WIN
);
197 * Now update the window content.
199 tui_update_source_windows_with_addr (gdbarch
, addr
);
200 if (new_layout
== SRC_DATA_COMMAND
201 || new_layout
== DISASSEM_DATA_COMMAND
)
202 tui_show_registers (TUI_DATA_WIN
->current_group
);
206 /* Add the specified window to the layout in a logical way. This
207 means setting up the most logical layout given the window to be
210 tui_add_win_to_layout (enum tui_win_type type
)
212 enum tui_layout_type cur_layout
= tui_current_layout ();
217 if (cur_layout
!= SRC_COMMAND
218 && cur_layout
!= SRC_DISASSEM_COMMAND
219 && cur_layout
!= SRC_DATA_COMMAND
)
221 tui_clear_source_windows_detail ();
222 if (cur_layout
== DISASSEM_DATA_COMMAND
)
223 show_layout (SRC_DATA_COMMAND
);
225 show_layout (SRC_COMMAND
);
229 if (cur_layout
!= DISASSEM_COMMAND
230 && cur_layout
!= SRC_DISASSEM_COMMAND
231 && cur_layout
!= DISASSEM_DATA_COMMAND
)
233 tui_clear_source_windows_detail ();
234 if (cur_layout
== SRC_DATA_COMMAND
)
235 show_layout (DISASSEM_DATA_COMMAND
);
237 show_layout (DISASSEM_COMMAND
);
241 if (cur_layout
!= SRC_DATA_COMMAND
242 && cur_layout
!= DISASSEM_DATA_COMMAND
)
244 if (cur_layout
== DISASSEM_COMMAND
)
245 show_layout (DISASSEM_DATA_COMMAND
);
247 show_layout (SRC_DATA_COMMAND
);
256 /* Answer the height of a window. If it hasn't been created yet,
257 answer what the height of a window would be based upon its type and
260 tui_default_win_height (enum tui_win_type type
,
261 enum tui_layout_type layout
)
265 if (tui_win_list
[type
] != NULL
)
266 h
= tui_win_list
[type
]->height
;
272 case DISASSEM_COMMAND
:
273 if (TUI_CMD_WIN
== NULL
)
274 h
= tui_term_height () / 2;
276 h
= tui_term_height () - TUI_CMD_WIN
->height
;
278 case SRC_DISASSEM_COMMAND
:
279 case SRC_DATA_COMMAND
:
280 case DISASSEM_DATA_COMMAND
:
281 if (TUI_CMD_WIN
== NULL
)
282 h
= tui_term_height () / 3;
284 h
= (tui_term_height () - TUI_CMD_WIN
->height
) / 2;
296 /* Answer the height of a window. If it hasn't been created yet,
297 answer what the height of a window would be based upon its type and
300 tui_default_win_viewport_height (enum tui_win_type type
,
301 enum tui_layout_type layout
)
305 h
= tui_default_win_height (type
, layout
);
307 if (tui_win_list
[type
] == TUI_CMD_WIN
)
315 /* Complete possible layout names. TEXT is the complete text entered so
316 far, WORD is the word currently being completed. */
319 layout_completer (struct cmd_list_element
*ignore
,
320 completion_tracker
&tracker
,
321 const char *text
, const char *word
)
323 static const char *layout_names
[] =
324 { "src", "asm", "split", "regs", "next", "prev", NULL
};
326 complete_on_enum (tracker
, layout_names
, text
, word
);
329 /* Function to initialize gdb commands, for tui window layout
333 _initialize_tui_layout (void)
335 struct cmd_list_element
*cmd
;
337 cmd
= add_com ("layout", class_tui
, tui_layout_command
, _("\
338 Change the layout of windows.\n\
339 Usage: layout prev | next | LAYOUT-NAME\n\
341 src : Displays source and command windows.\n\
342 asm : Displays disassembly and command windows.\n\
343 split : Displays source, disassembly and command windows.\n\
344 regs : Displays register window. If existing layout\n\
345 is source/command or assembly/command, the \n\
346 register window is displayed. If the\n\
347 source/assembly/command (split) is displayed, \n\
348 the register window is displayed with \n\
349 the window that has current logical focus."));
350 set_cmd_completer (cmd
, layout_completer
);
354 /*************************
355 ** STATIC LOCAL FUNCTIONS
356 **************************/
359 /* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
362 tui_layout_command (const char *layout_name
, int from_tty
)
365 enum tui_layout_type new_layout
= UNDEFINED_LAYOUT
;
366 enum tui_layout_type cur_layout
= tui_current_layout ();
368 if (layout_name
== NULL
)
369 error (_("Usage: layout prev | next | LAYOUT-NAME"));
371 std::string copy
= layout_name
;
372 for (i
= 0; i
< copy
.size (); i
++)
373 copy
[i
] = toupper (copy
[i
]);
374 const char *buf_ptr
= copy
.c_str ();
376 /* First check for ambiguous input. */
377 if (strlen (buf_ptr
) <= 1 && *buf_ptr
== 'S')
378 error (_("Ambiguous command input."));
380 if (subset_compare (buf_ptr
, "SRC"))
381 new_layout
= SRC_COMMAND
;
382 else if (subset_compare (buf_ptr
, "ASM"))
383 new_layout
= DISASSEM_COMMAND
;
384 else if (subset_compare (buf_ptr
, "SPLIT"))
385 new_layout
= SRC_DISASSEM_COMMAND
;
386 else if (subset_compare (buf_ptr
, "REGS"))
388 if (cur_layout
== SRC_COMMAND
389 || cur_layout
== SRC_DATA_COMMAND
)
390 new_layout
= SRC_DATA_COMMAND
;
392 new_layout
= DISASSEM_DATA_COMMAND
;
394 else if (subset_compare (buf_ptr
, "NEXT"))
395 new_layout
= next_layout ();
396 else if (subset_compare (buf_ptr
, "PREV"))
397 new_layout
= prev_layout ();
399 error (_("Unrecognized layout: %s"), layout_name
);
401 /* Make sure the curses mode is enabled. */
403 tui_set_layout (new_layout
);
408 extract_display_start_addr (struct gdbarch
**gdbarch_p
, CORE_ADDR
*addr_p
)
410 enum tui_layout_type cur_layout
= tui_current_layout ();
411 struct gdbarch
*gdbarch
= get_current_arch ();
414 struct symtab_and_line cursal
= get_current_source_symtab_and_line ();
419 case SRC_DATA_COMMAND
:
420 gdbarch
= TUI_SRC_WIN
->gdbarch
;
421 find_line_pc (cursal
.symtab
,
422 TUI_SRC_WIN
->start_line_or_addr
.u
.line_no
,
426 case DISASSEM_COMMAND
:
427 case SRC_DISASSEM_COMMAND
:
428 case DISASSEM_DATA_COMMAND
:
429 gdbarch
= TUI_DISASM_WIN
->gdbarch
;
430 addr
= TUI_DISASM_WIN
->start_line_or_addr
.u
.addr
;
437 *gdbarch_p
= gdbarch
;
442 /* Answer the previous layout to cycle to. */
443 static enum tui_layout_type
448 new_layout
= tui_current_layout ();
449 if (new_layout
== UNDEFINED_LAYOUT
)
450 new_layout
= SRC_COMMAND
;
454 if (new_layout
== UNDEFINED_LAYOUT
)
455 new_layout
= SRC_COMMAND
;
458 return (enum tui_layout_type
) new_layout
;
462 /* Answer the next layout to cycle to. */
463 static enum tui_layout_type
468 new_layout
= tui_current_layout ();
469 if (new_layout
== SRC_COMMAND
)
470 new_layout
= DISASSEM_DATA_COMMAND
;
474 if (new_layout
== UNDEFINED_LAYOUT
)
475 new_layout
= DISASSEM_DATA_COMMAND
;
478 return (enum tui_layout_type
) new_layout
;
481 /* Show the Source/Command layout. */
483 show_source_command (void)
485 show_source_or_disasm_and_command (SRC_COMMAND
);
489 /* Show the Dissassem/Command layout. */
491 show_disasm_command (void)
493 show_source_or_disasm_and_command (DISASSEM_COMMAND
);
497 /* Show the Source/Disassem/Command layout. */
499 show_source_disasm_command (void)
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 current_layout
= SRC_DISASSEM_COMMAND
;
554 /* Show the Source/Data/Command or the Dissassembly/Data/Command
557 show_data (enum tui_layout_type new_layout
)
559 int total_height
= (tui_term_height () - TUI_CMD_WIN
->height
);
560 int src_height
, data_height
;
561 enum tui_win_type win_type
;
563 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
564 gdb_assert (locator
!= nullptr);
566 data_height
= total_height
/ 2;
567 src_height
= total_height
- data_height
;
568 if (tui_win_list
[DATA_WIN
] == nullptr)
569 tui_win_list
[DATA_WIN
] = new tui_data_window ();
570 tui_win_list
[DATA_WIN
]->reset (data_height
, tui_term_width (), 0, 0);
571 tui_win_list
[DATA_WIN
]->make_visible (true);
573 if (new_layout
== SRC_DATA_COMMAND
)
576 win_type
= DISASSEM_WIN
;
578 if (tui_win_list
[win_type
] == NULL
)
580 if (win_type
== SRC_WIN
)
581 tui_win_list
[win_type
] = new tui_source_window ();
583 tui_win_list
[win_type
] = new tui_disasm_window ();
586 tui_source_window_base
*base
587 = (tui_source_window_base
*) tui_win_list
[win_type
];
588 tui_win_list
[win_type
]->reset (src_height
,
592 locator
->reset (2 /* 1 */ ,
596 base
->make_visible (true);
597 base
->m_has_locator
= true;
598 locator
->make_visible (true);
599 tui_show_locator_content ();
600 tui_add_to_source_windows (base
);
601 TUI_CMD_WIN
->make_visible (true);
602 current_layout
= new_layout
;
606 tui_gen_win_info::reset (int height_
, int width_
,
607 int origin_x_
, int origin_y_
)
615 viewport_height
= h
- 1;
621 origin
.x
= origin_x_
;
622 origin
.y
= origin_y_
;
625 /* Show the Source/Command or the Disassem layout. */
627 show_source_or_disasm_and_command (enum tui_layout_type layout_type
)
629 struct tui_source_window_base
*win_info
;
630 int src_height
, cmd_height
;
631 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
632 gdb_assert (locator
!= nullptr);
634 if (TUI_CMD_WIN
!= NULL
)
635 cmd_height
= TUI_CMD_WIN
->height
;
637 cmd_height
= tui_term_height () / 3;
638 src_height
= tui_term_height () - cmd_height
;
640 if (layout_type
== SRC_COMMAND
)
642 if (tui_win_list
[SRC_WIN
] == nullptr)
643 tui_win_list
[SRC_WIN
] = new tui_source_window ();
644 win_info
= TUI_SRC_WIN
;
648 if (tui_win_list
[DISASSEM_WIN
] == nullptr)
649 tui_win_list
[DISASSEM_WIN
] = new tui_disasm_window ();
650 win_info
= TUI_DISASM_WIN
;
653 locator
->reset (2 /* 1 */ ,
657 win_info
->reset (src_height
- 1,
661 win_info
->make_visible (true);
664 win_info
->m_has_locator
= true;
665 locator
->make_visible (true);
666 tui_show_locator_content ();
667 tui_show_source_content (win_info
);
669 if (TUI_CMD_WIN
== NULL
)
670 tui_win_list
[CMD_WIN
] = new tui_cmd_window ();
671 TUI_CMD_WIN
->reset (cmd_height
,
675 /* FIXME tui_cmd_window won't recreate the handle on
676 make_visible, so we need this instead. */
677 tui_make_window (TUI_CMD_WIN
, DONT_BOX_WINDOW
);
678 current_layout
= layout_type
;