a5709c595f338cb8958bfab098641e60be78834e
[binutils-gdb.git] / gdb / tui / tui-layout.c
1 /* TUI layout window management.
2
3 Copyright (C) 1998-2019 Free Software Foundation, Inc.
4
5 Contributed by Hewlett-Packard Company.
6
7 This file is part of GDB.
8
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.
13
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.
18
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/>. */
21
22 #include "defs.h"
23 #include "arch-utils.h"
24 #include "command.h"
25 #include "symtab.h"
26 #include "frame.h"
27 #include "source.h"
28 #include <ctype.h>
29
30 #include "tui/tui.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"
42
43 /*******************************
44 ** Static Local Decls
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 *);
56
57
58 /***************************************
59 ** DEFINITIONS
60 ***************************************/
61
62 /* Show the screen layout defined. */
63 static void
64 show_layout (enum tui_layout_type layout)
65 {
66 enum tui_layout_type cur_layout = tui_current_layout ();
67
68 if (layout != cur_layout)
69 {
70 /* Since the new layout may cause changes in window size, we
71 should free the content and reallocate on next display of
72 source/asm. */
73 tui_clear_source_windows ();
74 if (layout == SRC_DATA_COMMAND
75 || layout == DISASSEM_DATA_COMMAND)
76 {
77 show_data (layout);
78 tui_refresh_all ();
79 }
80 else
81 {
82 /* First make the current layout be invisible. */
83 tui_make_all_invisible ();
84 tui_locator_win_info_ptr ()->make_visible (false);
85
86 switch (layout)
87 {
88 /* Now show the new layout. */
89 case SRC_COMMAND:
90 show_source_command ();
91 tui_add_to_source_windows (TUI_SRC_WIN);
92 break;
93 case DISASSEM_COMMAND:
94 show_disasm_command ();
95 tui_add_to_source_windows (TUI_DISASM_WIN);
96 break;
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);
101 break;
102 default:
103 break;
104 }
105 }
106 }
107 }
108
109
110 /* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
111 SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. */
112 void
113 tui_set_layout (enum tui_layout_type layout_type)
114 {
115 gdb_assert (layout_type != UNDEFINED_LAYOUT);
116
117 enum tui_layout_type cur_layout = tui_current_layout ();
118 struct gdbarch *gdbarch;
119 CORE_ADDR addr;
120 struct tui_win_info *win_with_focus = tui_win_with_focus ();
121 struct tui_layout_def *layout_def = tui_layout_def ();
122
123 extract_display_start_addr (&gdbarch, &addr);
124
125 enum tui_layout_type new_layout = layout_type;
126
127 if (new_layout != cur_layout)
128 {
129 show_layout (new_layout);
130
131 /* Now determine where focus should be. */
132 if (win_with_focus != TUI_CMD_WIN)
133 {
134 switch (new_layout)
135 {
136 case SRC_COMMAND:
137 tui_set_win_focus_to (TUI_SRC_WIN);
138 layout_def->display_mode = SRC_WIN;
139 break;
140 case DISASSEM_COMMAND:
141 /* The previous layout was not showing code.
142 This can happen if there is no source
143 available:
144
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! */
148
149 tui_get_begin_asm_address (&gdbarch, &addr);
150 tui_set_win_focus_to (TUI_DISASM_WIN);
151 layout_def->display_mode = DISASSEM_WIN;
152 break;
153 case SRC_DISASSEM_COMMAND:
154 /* The previous layout was not showing code.
155 This can happen if there is no source
156 available:
157
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! */
161
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);
165 else
166 tui_set_win_focus_to (TUI_DISASM_WIN);
167 break;
168 case SRC_DATA_COMMAND:
169 if (win_with_focus != TUI_DATA_WIN)
170 tui_set_win_focus_to (TUI_SRC_WIN);
171 else
172 tui_set_win_focus_to (TUI_DATA_WIN);
173 layout_def->display_mode = SRC_WIN;
174 break;
175 case DISASSEM_DATA_COMMAND:
176 /* The previous layout was not showing code.
177 This can happen if there is no source
178 available:
179
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! */
183
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);
187 else
188 tui_set_win_focus_to (TUI_DATA_WIN);
189 layout_def->display_mode = DISASSEM_WIN;
190 break;
191 default:
192 break;
193 }
194 }
195 /*
196 * Now update the window content.
197 */
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);
202 }
203 }
204
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
207 added. */
208 void
209 tui_add_win_to_layout (enum tui_win_type type)
210 {
211 enum tui_layout_type cur_layout = tui_current_layout ();
212
213 switch (type)
214 {
215 case SRC_WIN:
216 if (cur_layout != SRC_COMMAND
217 && cur_layout != SRC_DISASSEM_COMMAND
218 && cur_layout != SRC_DATA_COMMAND)
219 {
220 tui_clear_source_windows_detail ();
221 if (cur_layout == DISASSEM_DATA_COMMAND)
222 show_layout (SRC_DATA_COMMAND);
223 else
224 show_layout (SRC_COMMAND);
225 }
226 break;
227 case DISASSEM_WIN:
228 if (cur_layout != DISASSEM_COMMAND
229 && cur_layout != SRC_DISASSEM_COMMAND
230 && cur_layout != DISASSEM_DATA_COMMAND)
231 {
232 tui_clear_source_windows_detail ();
233 if (cur_layout == SRC_DATA_COMMAND)
234 show_layout (DISASSEM_DATA_COMMAND);
235 else
236 show_layout (DISASSEM_COMMAND);
237 }
238 break;
239 case DATA_WIN:
240 if (cur_layout != SRC_DATA_COMMAND
241 && cur_layout != DISASSEM_DATA_COMMAND)
242 {
243 if (cur_layout == DISASSEM_COMMAND)
244 show_layout (DISASSEM_DATA_COMMAND);
245 else
246 show_layout (SRC_DATA_COMMAND);
247 }
248 break;
249 default:
250 break;
251 }
252 }
253
254
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
257 the layout. */
258 int
259 tui_default_win_height (enum tui_win_type type,
260 enum tui_layout_type layout)
261 {
262 int h;
263
264 if (tui_win_list[type] != NULL)
265 h = tui_win_list[type]->height;
266 else
267 {
268 switch (layout)
269 {
270 case SRC_COMMAND:
271 case DISASSEM_COMMAND:
272 if (TUI_CMD_WIN == NULL)
273 h = tui_term_height () / 2;
274 else
275 h = tui_term_height () - TUI_CMD_WIN->height;
276 break;
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;
282 else
283 h = (tui_term_height () - TUI_CMD_WIN->height) / 2;
284 break;
285 default:
286 h = 0;
287 break;
288 }
289 }
290
291 return h;
292 }
293
294
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
297 the layout. */
298 int
299 tui_default_win_viewport_height (enum tui_win_type type,
300 enum tui_layout_type layout)
301 {
302 int h;
303
304 h = tui_default_win_height (type, layout);
305
306 if (tui_win_list[type] == TUI_CMD_WIN)
307 h -= 1;
308 else
309 h -= 2;
310
311 return h;
312 }
313
314 /* Complete possible layout names. TEXT is the complete text entered so
315 far, WORD is the word currently being completed. */
316
317 static void
318 layout_completer (struct cmd_list_element *ignore,
319 completion_tracker &tracker,
320 const char *text, const char *word)
321 {
322 static const char *layout_names [] =
323 { "src", "asm", "split", "regs", "next", "prev", NULL };
324
325 complete_on_enum (tracker, layout_names, text, word);
326 }
327
328 /* Function to initialize gdb commands, for tui window layout
329 manipulation. */
330
331 void
332 _initialize_tui_layout (void)
333 {
334 struct cmd_list_element *cmd;
335
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\
339 Layout names are:\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);
350 }
351
352
353 /*************************
354 ** STATIC LOCAL FUNCTIONS
355 **************************/
356
357
358 /* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
359 REGS. */
360 static void
361 tui_layout_command (const char *layout_name, int from_tty)
362 {
363 int i;
364 enum tui_layout_type new_layout = UNDEFINED_LAYOUT;
365 enum tui_layout_type cur_layout = tui_current_layout ();
366
367 if (layout_name == NULL)
368 error (_("Usage: layout prev | next | LAYOUT-NAME"));
369
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 ();
374
375 /* First check for ambiguous input. */
376 if (strlen (buf_ptr) <= 1 && *buf_ptr == 'S')
377 error (_("Ambiguous command input."));
378
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"))
386 {
387 if (cur_layout == SRC_COMMAND
388 || cur_layout == SRC_DATA_COMMAND)
389 new_layout = SRC_DATA_COMMAND;
390 else
391 new_layout = DISASSEM_DATA_COMMAND;
392 }
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 ();
397 else
398 error (_("Unrecognized layout: %s"), layout_name);
399
400 /* Make sure the curses mode is enabled. */
401 tui_enable ();
402 tui_set_layout (new_layout);
403 }
404
405
406 static void
407 extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
408 {
409 enum tui_layout_type cur_layout = tui_current_layout ();
410 struct gdbarch *gdbarch = get_current_arch ();
411 CORE_ADDR addr;
412 CORE_ADDR pc;
413 struct symtab_and_line cursal = get_current_source_symtab_and_line ();
414
415 switch (cur_layout)
416 {
417 case SRC_COMMAND:
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,
422 &pc);
423 addr = pc;
424 break;
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;
430 break;
431 default:
432 addr = 0;
433 break;
434 }
435
436 *gdbarch_p = gdbarch;
437 *addr_p = addr;
438 }
439
440
441 /* Answer the previous layout to cycle to. */
442 static enum tui_layout_type
443 next_layout (void)
444 {
445 int new_layout;
446
447 new_layout = tui_current_layout ();
448 if (new_layout == UNDEFINED_LAYOUT)
449 new_layout = SRC_COMMAND;
450 else
451 {
452 new_layout++;
453 if (new_layout == UNDEFINED_LAYOUT)
454 new_layout = SRC_COMMAND;
455 }
456
457 return (enum tui_layout_type) new_layout;
458 }
459
460
461 /* Answer the next layout to cycle to. */
462 static enum tui_layout_type
463 prev_layout (void)
464 {
465 int new_layout;
466
467 new_layout = tui_current_layout ();
468 if (new_layout == SRC_COMMAND)
469 new_layout = DISASSEM_DATA_COMMAND;
470 else
471 {
472 new_layout--;
473 if (new_layout == UNDEFINED_LAYOUT)
474 new_layout = DISASSEM_DATA_COMMAND;
475 }
476
477 return (enum tui_layout_type) new_layout;
478 }
479
480 /* Show the Source/Command layout. */
481 static void
482 show_source_command (void)
483 {
484 show_source_or_disasm_and_command (SRC_COMMAND);
485 }
486
487
488 /* Show the Dissassem/Command layout. */
489 static void
490 show_disasm_command (void)
491 {
492 show_source_or_disasm_and_command (DISASSEM_COMMAND);
493 }
494
495
496 /* Show the Source/Disassem/Command layout. */
497 static void
498 show_source_disasm_command (void)
499 {
500 if (tui_current_layout () != SRC_DISASSEM_COMMAND)
501 {
502 int cmd_height, src_height, asm_height;
503
504 if (TUI_CMD_WIN != NULL)
505 cmd_height = TUI_CMD_WIN->height;
506 else
507 cmd_height = tui_term_height () / 3;
508
509 src_height = (tui_term_height () - cmd_height) / 2;
510 asm_height = tui_term_height () - (src_height + cmd_height);
511
512 if (TUI_SRC_WIN == NULL)
513 tui_win_list[SRC_WIN] = new tui_source_window ();
514 TUI_SRC_WIN->reset (src_height,
515 tui_term_width (),
516 0,
517 0);
518 TUI_SRC_WIN->make_visible (true);
519 TUI_SRC_WIN->m_has_locator = false;
520
521 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
522 gdb_assert (locator != nullptr);
523
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,
528 tui_term_width (),
529 0,
530 src_height - 1);
531 TUI_DISASM_WIN->make_visible (true);
532 locator->reset (2 /* 1 */ ,
533 tui_term_width (),
534 0,
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);
541
542 if (TUI_CMD_WIN == NULL)
543 tui_win_list[CMD_WIN] = new tui_cmd_window ();
544 TUI_CMD_WIN->reset (cmd_height,
545 tui_term_width (),
546 0,
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);
552 }
553 }
554
555
556 /* Show the Source/Data/Command or the Dissassembly/Data/Command
557 layout. */
558 static void
559 show_data (enum tui_layout_type new_layout)
560 {
561 int total_height = (tui_term_height () - TUI_CMD_WIN->height);
562 int src_height, data_height;
563 enum tui_win_type win_type;
564
565 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
566 gdb_assert (locator != nullptr);
567
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);
576
577 if (new_layout == SRC_DATA_COMMAND)
578 win_type = SRC_WIN;
579 else
580 win_type = DISASSEM_WIN;
581
582 if (tui_win_list[win_type] == NULL)
583 {
584 if (win_type == SRC_WIN)
585 tui_win_list[win_type] = new tui_source_window ();
586 else
587 tui_win_list[win_type] = new tui_disasm_window ();
588 }
589
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,
593 tui_term_width (),
594 0,
595 data_height - 1);
596 locator->reset (2 /* 1 */ ,
597 tui_term_width (),
598 0,
599 total_height - 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);
606 }
607
608 void
609 tui_gen_win_info::reset (int height_, int width_,
610 int origin_x_, int origin_y_)
611 {
612 int h = height_;
613
614 width = width_;
615 height = h;
616 if (h > 1)
617 {
618 viewport_height = h - 1;
619 if (type != CMD_WIN)
620 viewport_height--;
621 }
622 else
623 viewport_height = 1;
624 origin.x = origin_x_;
625 origin.y = origin_y_;
626 }
627
628 /* Show the Source/Command or the Disassem layout. */
629 static void
630 show_source_or_disasm_and_command (enum tui_layout_type layout_type)
631 {
632 if (tui_current_layout () != layout_type)
633 {
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);
638
639 if (TUI_CMD_WIN != NULL)
640 cmd_height = TUI_CMD_WIN->height;
641 else
642 cmd_height = tui_term_height () / 3;
643 src_height = tui_term_height () - cmd_height;
644
645 if (layout_type == SRC_COMMAND)
646 {
647 if (tui_win_list[SRC_WIN] == nullptr)
648 tui_win_list[SRC_WIN] = new tui_source_window ();
649 win_info = TUI_SRC_WIN;
650 }
651 else
652 {
653 if (tui_win_list[DISASSEM_WIN] == nullptr)
654 tui_win_list[DISASSEM_WIN] = new tui_disasm_window ();
655 win_info = TUI_DISASM_WIN;
656 }
657
658 locator->reset (2 /* 1 */ ,
659 tui_term_width (),
660 0,
661 src_height - 1);
662 win_info->reset (src_height - 1,
663 tui_term_width (),
664 0,
665 0);
666 win_info->make_visible (true);
667
668
669 win_info->m_has_locator = true;
670 locator->make_visible (true);
671 tui_show_locator_content ();
672 tui_show_source_content (win_info);
673
674 if (TUI_CMD_WIN == NULL)
675 tui_win_list[CMD_WIN] = new tui_cmd_window ();
676 TUI_CMD_WIN->reset (cmd_height,
677 tui_term_width (),
678 0,
679 src_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);
684 }
685 }