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 /***************************************
60 ***************************************/
62 /* Show the screen layout defined. */
64 show_layout (enum tui_layout_type layout
)
66 enum tui_layout_type cur_layout
= tui_current_layout ();
68 if (layout
!= cur_layout
)
70 /* Since the new layout may cause changes in window size, we
71 should free the content and reallocate on next display of
73 tui_clear_source_windows ();
74 if (layout
== SRC_DATA_COMMAND
75 || layout
== DISASSEM_DATA_COMMAND
)
82 /* First make the current layout be invisible. */
83 tui_make_all_invisible ();
84 tui_locator_win_info_ptr ()->make_visible (false);
88 /* Now show the new layout. */
90 show_source_command ();
91 tui_add_to_source_windows (TUI_SRC_WIN
);
93 case DISASSEM_COMMAND
:
94 show_disasm_command ();
95 tui_add_to_source_windows (TUI_DISASM_WIN
);
97 case SRC_DISASSEM_COMMAND
:
98 show_source_disasm_command ();
99 tui_add_to_source_windows (TUI_SRC_WIN
);
100 tui_add_to_source_windows (TUI_DISASM_WIN
);
110 /* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
111 SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. */
113 tui_set_layout (enum tui_layout_type layout_type
)
115 gdb_assert (layout_type
!= UNDEFINED_LAYOUT
);
117 enum tui_layout_type cur_layout
= tui_current_layout ();
118 struct gdbarch
*gdbarch
;
120 struct tui_win_info
*win_with_focus
= tui_win_with_focus ();
121 struct tui_layout_def
*layout_def
= tui_layout_def ();
123 extract_display_start_addr (&gdbarch
, &addr
);
125 enum tui_layout_type new_layout
= layout_type
;
127 if (new_layout
!= cur_layout
)
129 show_layout (new_layout
);
131 /* Now determine where focus should be. */
132 if (win_with_focus
!= TUI_CMD_WIN
)
137 tui_set_win_focus_to (TUI_SRC_WIN
);
138 layout_def
->display_mode
= SRC_WIN
;
140 case DISASSEM_COMMAND
:
141 /* The previous layout was not showing code.
142 This can happen if there is no source
145 1. if the source file is in another dir OR
146 2. if target was compiled without -g
147 We still want to show the assembly though! */
149 tui_get_begin_asm_address (&gdbarch
, &addr
);
150 tui_set_win_focus_to (TUI_DISASM_WIN
);
151 layout_def
->display_mode
= DISASSEM_WIN
;
153 case SRC_DISASSEM_COMMAND
:
154 /* The previous layout was not showing code.
155 This can happen if there is no source
158 1. if the source file is in another dir OR
159 2. if target was compiled without -g
160 We still want to show the assembly though! */
162 tui_get_begin_asm_address (&gdbarch
, &addr
);
163 if (win_with_focus
== TUI_SRC_WIN
)
164 tui_set_win_focus_to (TUI_SRC_WIN
);
166 tui_set_win_focus_to (TUI_DISASM_WIN
);
168 case SRC_DATA_COMMAND
:
169 if (win_with_focus
!= TUI_DATA_WIN
)
170 tui_set_win_focus_to (TUI_SRC_WIN
);
172 tui_set_win_focus_to (TUI_DATA_WIN
);
173 layout_def
->display_mode
= SRC_WIN
;
175 case DISASSEM_DATA_COMMAND
:
176 /* The previous layout was not showing code.
177 This can happen if there is no source
180 1. if the source file is in another dir OR
181 2. if target was compiled without -g
182 We still want to show the assembly though! */
184 tui_get_begin_asm_address (&gdbarch
, &addr
);
185 if (win_with_focus
!= TUI_DATA_WIN
)
186 tui_set_win_focus_to (TUI_DISASM_WIN
);
188 tui_set_win_focus_to (TUI_DATA_WIN
);
189 layout_def
->display_mode
= DISASSEM_WIN
;
196 * Now update the window content.
198 tui_update_source_windows_with_addr (gdbarch
, addr
);
199 if (new_layout
== SRC_DATA_COMMAND
200 || new_layout
== DISASSEM_DATA_COMMAND
)
201 tui_show_registers (TUI_DATA_WIN
->current_group
);
205 /* Add the specified window to the layout in a logical way. This
206 means setting up the most logical layout given the window to be
209 tui_add_win_to_layout (enum tui_win_type type
)
211 enum tui_layout_type cur_layout
= tui_current_layout ();
216 if (cur_layout
!= SRC_COMMAND
217 && cur_layout
!= SRC_DISASSEM_COMMAND
218 && cur_layout
!= SRC_DATA_COMMAND
)
220 tui_clear_source_windows_detail ();
221 if (cur_layout
== DISASSEM_DATA_COMMAND
)
222 show_layout (SRC_DATA_COMMAND
);
224 show_layout (SRC_COMMAND
);
228 if (cur_layout
!= DISASSEM_COMMAND
229 && cur_layout
!= SRC_DISASSEM_COMMAND
230 && cur_layout
!= DISASSEM_DATA_COMMAND
)
232 tui_clear_source_windows_detail ();
233 if (cur_layout
== SRC_DATA_COMMAND
)
234 show_layout (DISASSEM_DATA_COMMAND
);
236 show_layout (DISASSEM_COMMAND
);
240 if (cur_layout
!= SRC_DATA_COMMAND
241 && cur_layout
!= DISASSEM_DATA_COMMAND
)
243 if (cur_layout
== DISASSEM_COMMAND
)
244 show_layout (DISASSEM_DATA_COMMAND
);
246 show_layout (SRC_DATA_COMMAND
);
255 /* Answer the height of a window. If it hasn't been created yet,
256 answer what the height of a window would be based upon its type and
259 tui_default_win_height (enum tui_win_type type
,
260 enum tui_layout_type layout
)
264 if (tui_win_list
[type
] != NULL
)
265 h
= tui_win_list
[type
]->height
;
271 case DISASSEM_COMMAND
:
272 if (TUI_CMD_WIN
== NULL
)
273 h
= tui_term_height () / 2;
275 h
= tui_term_height () - TUI_CMD_WIN
->height
;
277 case SRC_DISASSEM_COMMAND
:
278 case SRC_DATA_COMMAND
:
279 case DISASSEM_DATA_COMMAND
:
280 if (TUI_CMD_WIN
== NULL
)
281 h
= tui_term_height () / 3;
283 h
= (tui_term_height () - TUI_CMD_WIN
->height
) / 2;
295 /* Answer the height of a window. If it hasn't been created yet,
296 answer what the height of a window would be based upon its type and
299 tui_default_win_viewport_height (enum tui_win_type type
,
300 enum tui_layout_type layout
)
304 h
= tui_default_win_height (type
, layout
);
306 if (tui_win_list
[type
] == TUI_CMD_WIN
)
314 /* Complete possible layout names. TEXT is the complete text entered so
315 far, WORD is the word currently being completed. */
318 layout_completer (struct cmd_list_element
*ignore
,
319 completion_tracker
&tracker
,
320 const char *text
, const char *word
)
322 static const char *layout_names
[] =
323 { "src", "asm", "split", "regs", "next", "prev", NULL
};
325 complete_on_enum (tracker
, layout_names
, text
, word
);
328 /* Function to initialize gdb commands, for tui window layout
332 _initialize_tui_layout (void)
334 struct cmd_list_element
*cmd
;
336 cmd
= add_com ("layout", class_tui
, tui_layout_command
, _("\
337 Change the layout of windows.\n\
338 Usage: layout prev | next | LAYOUT-NAME\n\
340 src : Displays source and command windows.\n\
341 asm : Displays disassembly and command windows.\n\
342 split : Displays source, disassembly and command windows.\n\
343 regs : Displays register window. If existing layout\n\
344 is source/command or assembly/command, the \n\
345 register window is displayed. If the\n\
346 source/assembly/command (split) is displayed, \n\
347 the register window is displayed with \n\
348 the window that has current logical focus."));
349 set_cmd_completer (cmd
, layout_completer
);
353 /*************************
354 ** STATIC LOCAL FUNCTIONS
355 **************************/
358 /* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
361 tui_layout_command (const char *layout_name
, int from_tty
)
364 enum tui_layout_type new_layout
= UNDEFINED_LAYOUT
;
365 enum tui_layout_type cur_layout
= tui_current_layout ();
367 if (layout_name
== NULL
)
368 error (_("Usage: layout prev | next | LAYOUT-NAME"));
370 std::string copy
= layout_name
;
371 for (i
= 0; i
< copy
.size (); i
++)
372 copy
[i
] = toupper (copy
[i
]);
373 const char *buf_ptr
= copy
.c_str ();
375 /* First check for ambiguous input. */
376 if (strlen (buf_ptr
) <= 1 && *buf_ptr
== 'S')
377 error (_("Ambiguous command input."));
379 if (subset_compare (buf_ptr
, "SRC"))
380 new_layout
= SRC_COMMAND
;
381 else if (subset_compare (buf_ptr
, "ASM"))
382 new_layout
= DISASSEM_COMMAND
;
383 else if (subset_compare (buf_ptr
, "SPLIT"))
384 new_layout
= SRC_DISASSEM_COMMAND
;
385 else if (subset_compare (buf_ptr
, "REGS"))
387 if (cur_layout
== SRC_COMMAND
388 || cur_layout
== SRC_DATA_COMMAND
)
389 new_layout
= SRC_DATA_COMMAND
;
391 new_layout
= DISASSEM_DATA_COMMAND
;
393 else if (subset_compare (buf_ptr
, "NEXT"))
394 new_layout
= next_layout ();
395 else if (subset_compare (buf_ptr
, "PREV"))
396 new_layout
= prev_layout ();
398 error (_("Unrecognized layout: %s"), layout_name
);
400 /* Make sure the curses mode is enabled. */
402 tui_set_layout (new_layout
);
407 extract_display_start_addr (struct gdbarch
**gdbarch_p
, CORE_ADDR
*addr_p
)
409 enum tui_layout_type cur_layout
= tui_current_layout ();
410 struct gdbarch
*gdbarch
= get_current_arch ();
413 struct symtab_and_line cursal
= get_current_source_symtab_and_line ();
418 case SRC_DATA_COMMAND
:
419 gdbarch
= TUI_SRC_WIN
->gdbarch
;
420 find_line_pc (cursal
.symtab
,
421 TUI_SRC_WIN
->start_line_or_addr
.u
.line_no
,
425 case DISASSEM_COMMAND
:
426 case SRC_DISASSEM_COMMAND
:
427 case DISASSEM_DATA_COMMAND
:
428 gdbarch
= TUI_DISASM_WIN
->gdbarch
;
429 addr
= TUI_DISASM_WIN
->start_line_or_addr
.u
.addr
;
436 *gdbarch_p
= gdbarch
;
441 /* Answer the previous layout to cycle to. */
442 static enum tui_layout_type
447 new_layout
= tui_current_layout ();
448 if (new_layout
== UNDEFINED_LAYOUT
)
449 new_layout
= SRC_COMMAND
;
453 if (new_layout
== UNDEFINED_LAYOUT
)
454 new_layout
= SRC_COMMAND
;
457 return (enum tui_layout_type
) new_layout
;
461 /* Answer the next layout to cycle to. */
462 static enum tui_layout_type
467 new_layout
= tui_current_layout ();
468 if (new_layout
== SRC_COMMAND
)
469 new_layout
= DISASSEM_DATA_COMMAND
;
473 if (new_layout
== UNDEFINED_LAYOUT
)
474 new_layout
= DISASSEM_DATA_COMMAND
;
477 return (enum tui_layout_type
) new_layout
;
480 /* Show the Source/Command layout. */
482 show_source_command (void)
484 show_source_or_disasm_and_command (SRC_COMMAND
);
488 /* Show the Dissassem/Command layout. */
490 show_disasm_command (void)
492 show_source_or_disasm_and_command (DISASSEM_COMMAND
);
496 /* Show the Source/Disassem/Command layout. */
498 show_source_disasm_command (void)
500 if (tui_current_layout () != SRC_DISASSEM_COMMAND
)
502 int cmd_height
, src_height
, asm_height
;
504 if (TUI_CMD_WIN
!= NULL
)
505 cmd_height
= TUI_CMD_WIN
->height
;
507 cmd_height
= tui_term_height () / 3;
509 src_height
= (tui_term_height () - cmd_height
) / 2;
510 asm_height
= tui_term_height () - (src_height
+ cmd_height
);
512 if (TUI_SRC_WIN
== NULL
)
513 tui_win_list
[SRC_WIN
] = new tui_source_window ();
514 TUI_SRC_WIN
->reset (src_height
,
518 TUI_SRC_WIN
->make_visible (true);
519 TUI_SRC_WIN
->m_has_locator
= false;
521 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
522 gdb_assert (locator
!= nullptr);
524 tui_show_source_content (TUI_SRC_WIN
);
525 if (TUI_DISASM_WIN
== NULL
)
526 tui_win_list
[DISASSEM_WIN
] = new tui_disasm_window ();
527 TUI_DISASM_WIN
->reset (asm_height
,
531 TUI_DISASM_WIN
->make_visible (true);
532 locator
->reset (2 /* 1 */ ,
535 (src_height
+ asm_height
) - 1);
536 TUI_SRC_WIN
->m_has_locator
= false;
537 TUI_DISASM_WIN
->m_has_locator
= true;
538 locator
->make_visible (true);
539 tui_show_locator_content ();
540 tui_show_source_content (TUI_DISASM_WIN
);
542 if (TUI_CMD_WIN
== NULL
)
543 tui_win_list
[CMD_WIN
] = new tui_cmd_window ();
544 TUI_CMD_WIN
->reset (cmd_height
,
547 tui_term_height () - cmd_height
);
548 /* FIXME tui_cmd_window won't recreate the handle on
549 make_visible, so we need this instead. */
550 tui_make_window (TUI_CMD_WIN
, DONT_BOX_WINDOW
);
551 tui_set_current_layout_to (SRC_DISASSEM_COMMAND
);
556 /* Show the Source/Data/Command or the Dissassembly/Data/Command
559 show_data (enum tui_layout_type new_layout
)
561 int total_height
= (tui_term_height () - TUI_CMD_WIN
->height
);
562 int src_height
, data_height
;
563 enum tui_win_type win_type
;
565 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
566 gdb_assert (locator
!= nullptr);
568 data_height
= total_height
/ 2;
569 src_height
= total_height
- data_height
;
570 tui_make_all_invisible ();
571 locator
->make_visible (false);
572 if (tui_win_list
[DATA_WIN
] == nullptr)
573 tui_win_list
[DATA_WIN
] = new tui_data_window ();
574 tui_win_list
[DATA_WIN
]->reset (data_height
, tui_term_width (), 0, 0);
575 tui_win_list
[DATA_WIN
]->make_visible (true);
577 if (new_layout
== SRC_DATA_COMMAND
)
580 win_type
= DISASSEM_WIN
;
582 if (tui_win_list
[win_type
] == NULL
)
584 if (win_type
== SRC_WIN
)
585 tui_win_list
[win_type
] = new tui_source_window ();
587 tui_win_list
[win_type
] = new tui_disasm_window ();
590 tui_source_window_base
*base
591 = (tui_source_window_base
*) tui_win_list
[win_type
];
592 tui_win_list
[win_type
]->reset (src_height
,
596 locator
->reset (2 /* 1 */ ,
600 base
->make_visible (true);
601 base
->m_has_locator
= true;
602 locator
->make_visible (true);
603 tui_show_locator_content ();
604 tui_add_to_source_windows (base
);
605 tui_set_current_layout_to (new_layout
);
609 tui_gen_win_info::reset (int height_
, int width_
,
610 int origin_x_
, int origin_y_
)
618 viewport_height
= h
- 1;
624 origin
.x
= origin_x_
;
625 origin
.y
= origin_y_
;
628 /* Show the Source/Command or the Disassem layout. */
630 show_source_or_disasm_and_command (enum tui_layout_type layout_type
)
632 if (tui_current_layout () != layout_type
)
634 struct tui_source_window_base
*win_info
;
635 int src_height
, cmd_height
;
636 struct tui_locator_window
*locator
= tui_locator_win_info_ptr ();
637 gdb_assert (locator
!= nullptr);
639 if (TUI_CMD_WIN
!= NULL
)
640 cmd_height
= TUI_CMD_WIN
->height
;
642 cmd_height
= tui_term_height () / 3;
643 src_height
= tui_term_height () - cmd_height
;
645 if (layout_type
== SRC_COMMAND
)
647 if (tui_win_list
[SRC_WIN
] == nullptr)
648 tui_win_list
[SRC_WIN
] = new tui_source_window ();
649 win_info
= TUI_SRC_WIN
;
653 if (tui_win_list
[DISASSEM_WIN
] == nullptr)
654 tui_win_list
[DISASSEM_WIN
] = new tui_disasm_window ();
655 win_info
= TUI_DISASM_WIN
;
658 locator
->reset (2 /* 1 */ ,
662 win_info
->reset (src_height
- 1,
666 win_info
->make_visible (true);
669 win_info
->m_has_locator
= true;
670 locator
->make_visible (true);
671 tui_show_locator_content ();
672 tui_show_source_content (win_info
);
674 if (TUI_CMD_WIN
== NULL
)
675 tui_win_list
[CMD_WIN
] = new tui_cmd_window ();
676 TUI_CMD_WIN
->reset (cmd_height
,
680 /* FIXME tui_cmd_window won't recreate the handle on
681 make_visible, so we need this instead. */
682 tui_make_window (TUI_CMD_WIN
, DONT_BOX_WINDOW
);
683 tui_set_current_layout_to (layout_type
);