4e914b79ea0aaee165ad6f4f7d613f19d711d667
[deliverable/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-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"
41
42 /*******************************
43 ** Static Local Decls
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 struct tui_win_info *make_command_window (int, int);
48 static struct tui_win_info *make_source_window (int, int);
49 static struct tui_win_info *make_disasm_window (int, int);
50 static void show_source_command (void);
51 static void show_disasm_command (void);
52 static void show_source_disasm_command (void);
53 static void show_data (enum tui_layout_type);
54 static enum tui_layout_type next_layout (void);
55 static enum tui_layout_type prev_layout (void);
56 static void tui_layout_command (const char *, int);
57 static void extract_display_start_addr (struct gdbarch **, CORE_ADDR *);
58
59
60 /***************************************
61 ** DEFINITIONS
62 ***************************************/
63
64 /* Show the screen layout defined. */
65 static void
66 show_layout (enum tui_layout_type layout)
67 {
68 enum tui_layout_type cur_layout = tui_current_layout ();
69
70 if (layout != cur_layout)
71 {
72 /* Since the new layout may cause changes in window size, we
73 should free the content and reallocate on next display of
74 source/asm. */
75 tui_clear_source_windows ();
76 if (layout == SRC_DATA_COMMAND
77 || layout == DISASSEM_DATA_COMMAND)
78 {
79 show_data (layout);
80 tui_refresh_all ();
81 }
82 else
83 {
84 /* First make the current layout be invisible. */
85 tui_make_all_invisible ();
86 tui_make_invisible (tui_locator_win_info_ptr ());
87
88 switch (layout)
89 {
90 /* Now show the new layout. */
91 case SRC_COMMAND:
92 show_source_command ();
93 tui_add_to_source_windows (TUI_SRC_WIN);
94 break;
95 case DISASSEM_COMMAND:
96 show_disasm_command ();
97 tui_add_to_source_windows (TUI_DISASM_WIN);
98 break;
99 case SRC_DISASSEM_COMMAND:
100 show_source_disasm_command ();
101 tui_add_to_source_windows (TUI_SRC_WIN);
102 tui_add_to_source_windows (TUI_DISASM_WIN);
103 break;
104 default:
105 break;
106 }
107 }
108 }
109 }
110
111
112 /* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
113 SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. */
114 void
115 tui_set_layout (enum tui_layout_type layout_type)
116 {
117 gdb_assert (layout_type != UNDEFINED_LAYOUT);
118
119 enum tui_layout_type cur_layout = tui_current_layout ();
120 struct gdbarch *gdbarch;
121 CORE_ADDR addr;
122 struct tui_win_info *win_with_focus = tui_win_with_focus ();
123 struct tui_layout_def *layout_def = tui_layout_def ();
124
125 extract_display_start_addr (&gdbarch, &addr);
126
127 enum tui_layout_type new_layout = layout_type;
128
129 if (new_layout != cur_layout)
130 {
131 show_layout (new_layout);
132
133 /* Now determine where focus should be. */
134 if (win_with_focus != TUI_CMD_WIN)
135 {
136 switch (new_layout)
137 {
138 case SRC_COMMAND:
139 tui_set_win_focus_to (TUI_SRC_WIN);
140 layout_def->display_mode = SRC_WIN;
141 break;
142 case DISASSEM_COMMAND:
143 /* The previous layout was not showing code.
144 This can happen if there is no source
145 available:
146
147 1. if the source file is in another dir OR
148 2. if target was compiled without -g
149 We still want to show the assembly though! */
150
151 tui_get_begin_asm_address (&gdbarch, &addr);
152 tui_set_win_focus_to (TUI_DISASM_WIN);
153 layout_def->display_mode = DISASSEM_WIN;
154 break;
155 case SRC_DISASSEM_COMMAND:
156 /* The previous layout was not showing code.
157 This can happen if there is no source
158 available:
159
160 1. if the source file is in another dir OR
161 2. if target was compiled without -g
162 We still want to show the assembly though! */
163
164 tui_get_begin_asm_address (&gdbarch, &addr);
165 if (win_with_focus == TUI_SRC_WIN)
166 tui_set_win_focus_to (TUI_SRC_WIN);
167 else
168 tui_set_win_focus_to (TUI_DISASM_WIN);
169 break;
170 case SRC_DATA_COMMAND:
171 if (win_with_focus != TUI_DATA_WIN)
172 tui_set_win_focus_to (TUI_SRC_WIN);
173 else
174 tui_set_win_focus_to (TUI_DATA_WIN);
175 layout_def->display_mode = SRC_WIN;
176 break;
177 case DISASSEM_DATA_COMMAND:
178 /* The previous layout was not showing code.
179 This can happen if there is no source
180 available:
181
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! */
185
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);
189 else
190 tui_set_win_focus_to (TUI_DATA_WIN);
191 layout_def->display_mode = DISASSEM_WIN;
192 break;
193 default:
194 break;
195 }
196 }
197 /*
198 * Now update the window content.
199 */
200 tui_update_source_windows_with_addr (gdbarch, addr);
201 if (new_layout == SRC_DATA_COMMAND
202 || new_layout == DISASSEM_DATA_COMMAND)
203 tui_show_registers (TUI_DATA_WIN->current_group);
204 }
205 }
206
207 /* Add the specified window to the layout in a logical way. This
208 means setting up the most logical layout given the window to be
209 added. */
210 void
211 tui_add_win_to_layout (enum tui_win_type type)
212 {
213 enum tui_layout_type cur_layout = tui_current_layout ();
214
215 switch (type)
216 {
217 case SRC_WIN:
218 if (cur_layout != SRC_COMMAND
219 && cur_layout != SRC_DISASSEM_COMMAND
220 && cur_layout != SRC_DATA_COMMAND)
221 {
222 tui_clear_source_windows_detail ();
223 if (cur_layout == DISASSEM_DATA_COMMAND)
224 show_layout (SRC_DATA_COMMAND);
225 else
226 show_layout (SRC_COMMAND);
227 }
228 break;
229 case DISASSEM_WIN:
230 if (cur_layout != DISASSEM_COMMAND
231 && cur_layout != SRC_DISASSEM_COMMAND
232 && cur_layout != DISASSEM_DATA_COMMAND)
233 {
234 tui_clear_source_windows_detail ();
235 if (cur_layout == SRC_DATA_COMMAND)
236 show_layout (DISASSEM_DATA_COMMAND);
237 else
238 show_layout (DISASSEM_COMMAND);
239 }
240 break;
241 case DATA_WIN:
242 if (cur_layout != SRC_DATA_COMMAND
243 && cur_layout != DISASSEM_DATA_COMMAND)
244 {
245 if (cur_layout == DISASSEM_COMMAND)
246 show_layout (DISASSEM_DATA_COMMAND);
247 else
248 show_layout (SRC_DATA_COMMAND);
249 }
250 break;
251 default:
252 break;
253 }
254 }
255
256
257 /* Answer the height of a window. If it hasn't been created yet,
258 answer what the height of a window would be based upon its type and
259 the layout. */
260 int
261 tui_default_win_height (enum tui_win_type type,
262 enum tui_layout_type layout)
263 {
264 int h;
265
266 if (tui_win_list[type] != NULL)
267 h = tui_win_list[type]->height;
268 else
269 {
270 switch (layout)
271 {
272 case SRC_COMMAND:
273 case DISASSEM_COMMAND:
274 if (TUI_CMD_WIN == NULL)
275 h = tui_term_height () / 2;
276 else
277 h = tui_term_height () - TUI_CMD_WIN->height;
278 break;
279 case SRC_DISASSEM_COMMAND:
280 case SRC_DATA_COMMAND:
281 case DISASSEM_DATA_COMMAND:
282 if (TUI_CMD_WIN == NULL)
283 h = tui_term_height () / 3;
284 else
285 h = (tui_term_height () - TUI_CMD_WIN->height) / 2;
286 break;
287 default:
288 h = 0;
289 break;
290 }
291 }
292
293 return h;
294 }
295
296
297 /* Answer the height of a window. If it hasn't been created yet,
298 answer what the height of a window would be based upon its type and
299 the layout. */
300 int
301 tui_default_win_viewport_height (enum tui_win_type type,
302 enum tui_layout_type layout)
303 {
304 int h;
305
306 h = tui_default_win_height (type, layout);
307
308 if (tui_win_list[type] == TUI_CMD_WIN)
309 h -= 1;
310 else
311 h -= 2;
312
313 return h;
314 }
315
316 /* Complete possible layout names. TEXT is the complete text entered so
317 far, WORD is the word currently being completed. */
318
319 static void
320 layout_completer (struct cmd_list_element *ignore,
321 completion_tracker &tracker,
322 const char *text, const char *word)
323 {
324 static const char *layout_names [] =
325 { "src", "asm", "split", "regs", "next", "prev", NULL };
326
327 complete_on_enum (tracker, layout_names, text, word);
328 }
329
330 /* Function to initialize gdb commands, for tui window layout
331 manipulation. */
332
333 void
334 _initialize_tui_layout (void)
335 {
336 struct cmd_list_element *cmd;
337
338 cmd = add_com ("layout", class_tui, tui_layout_command, _("\
339 Change the layout of windows.\n\
340 Usage: layout prev | next | LAYOUT-NAME\n\
341 Layout names are:\n\
342 src : Displays source and command windows.\n\
343 asm : Displays disassembly and command windows.\n\
344 split : Displays source, disassembly and command windows.\n\
345 regs : Displays register window. If existing layout\n\
346 is source/command or assembly/command, the \n\
347 register window is displayed. If the\n\
348 source/assembly/command (split) is displayed, \n\
349 the register window is displayed with \n\
350 the window that has current logical focus."));
351 set_cmd_completer (cmd, layout_completer);
352 }
353
354
355 /*************************
356 ** STATIC LOCAL FUNCTIONS
357 **************************/
358
359
360 /* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
361 REGS. */
362 static void
363 tui_layout_command (const char *layout_name, int from_tty)
364 {
365 int i;
366 enum tui_layout_type new_layout = UNDEFINED_LAYOUT;
367 enum tui_layout_type cur_layout = tui_current_layout ();
368
369 if (layout_name == NULL)
370 error (_("Usage: layout prev | next | LAYOUT-NAME"));
371
372 std::string copy = layout_name;
373 for (i = 0; i < copy.size (); i++)
374 copy[i] = toupper (copy[i]);
375 const char *buf_ptr = copy.c_str ();
376
377 /* First check for ambiguous input. */
378 if (strlen (buf_ptr) <= 1 && *buf_ptr == 'S')
379 error (_("Ambiguous command input."));
380
381 if (subset_compare (buf_ptr, "SRC"))
382 new_layout = SRC_COMMAND;
383 else if (subset_compare (buf_ptr, "ASM"))
384 new_layout = DISASSEM_COMMAND;
385 else if (subset_compare (buf_ptr, "SPLIT"))
386 new_layout = SRC_DISASSEM_COMMAND;
387 else if (subset_compare (buf_ptr, "REGS"))
388 {
389 if (cur_layout == SRC_COMMAND
390 || cur_layout == SRC_DATA_COMMAND)
391 new_layout = SRC_DATA_COMMAND;
392 else
393 new_layout = DISASSEM_DATA_COMMAND;
394 }
395 else if (subset_compare (buf_ptr, "NEXT"))
396 new_layout = next_layout ();
397 else if (subset_compare (buf_ptr, "PREV"))
398 new_layout = prev_layout ();
399 else
400 error (_("Unrecognized layout: %s"), layout_name);
401
402 /* Make sure the curses mode is enabled. */
403 tui_enable ();
404 tui_set_layout (new_layout);
405 }
406
407
408 static void
409 extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
410 {
411 enum tui_layout_type cur_layout = tui_current_layout ();
412 struct gdbarch *gdbarch = get_current_arch ();
413 CORE_ADDR addr;
414 CORE_ADDR pc;
415 struct symtab_and_line cursal = get_current_source_symtab_and_line ();
416
417 switch (cur_layout)
418 {
419 case SRC_COMMAND:
420 case SRC_DATA_COMMAND:
421 gdbarch = TUI_SRC_WIN->gdbarch;
422 find_line_pc (cursal.symtab,
423 TUI_SRC_WIN->start_line_or_addr.u.line_no,
424 &pc);
425 addr = pc;
426 break;
427 case DISASSEM_COMMAND:
428 case SRC_DISASSEM_COMMAND:
429 case DISASSEM_DATA_COMMAND:
430 gdbarch = TUI_DISASM_WIN->gdbarch;
431 addr = TUI_DISASM_WIN->start_line_or_addr.u.addr;
432 break;
433 default:
434 addr = 0;
435 break;
436 }
437
438 *gdbarch_p = gdbarch;
439 *addr_p = addr;
440 }
441
442
443 /* Answer the previous layout to cycle to. */
444 static enum tui_layout_type
445 next_layout (void)
446 {
447 int new_layout;
448
449 new_layout = tui_current_layout ();
450 if (new_layout == UNDEFINED_LAYOUT)
451 new_layout = SRC_COMMAND;
452 else
453 {
454 new_layout++;
455 if (new_layout == UNDEFINED_LAYOUT)
456 new_layout = SRC_COMMAND;
457 }
458
459 return (enum tui_layout_type) new_layout;
460 }
461
462
463 /* Answer the next layout to cycle to. */
464 static enum tui_layout_type
465 prev_layout (void)
466 {
467 int new_layout;
468
469 new_layout = tui_current_layout ();
470 if (new_layout == SRC_COMMAND)
471 new_layout = DISASSEM_DATA_COMMAND;
472 else
473 {
474 new_layout--;
475 if (new_layout == UNDEFINED_LAYOUT)
476 new_layout = DISASSEM_DATA_COMMAND;
477 }
478
479 return (enum tui_layout_type) new_layout;
480 }
481
482
483
484 static struct tui_win_info *
485 make_command_window (int height, int origin_y)
486 {
487 struct tui_win_info *result = new tui_cmd_window ();
488 result->reset (height, tui_term_width (), 0, origin_y);
489 tui_make_window (result, DONT_BOX_WINDOW);
490 return result;
491 }
492
493
494 /* make_source_window().
495 */
496 static struct tui_win_info *
497 make_source_window (int height, int origin_y)
498 {
499 tui_win_info *result = new tui_source_window ();
500 result->reset (height, tui_term_width (), 0, origin_y);
501 result->make_visible (true);
502 return result;
503 }
504
505
506 /* make_disasm_window().
507 */
508 static struct tui_win_info *
509 make_disasm_window (int height, int origin_y)
510 {
511 tui_win_info *result = new tui_disasm_window ();
512 result->reset (height, tui_term_width (), 0, origin_y);
513 result->make_visible (true);
514 return result;
515 }
516
517
518 static tui_win_info *
519 make_data_window (int height, int origin_y)
520 {
521 tui_win_info *result = new tui_data_window ();
522 result->reset (height, tui_term_width (), 0, origin_y);
523 result->make_visible (true);
524 return result;
525 }
526
527
528
529 /* Show the Source/Command layout. */
530 static void
531 show_source_command (void)
532 {
533 show_source_or_disasm_and_command (SRC_COMMAND);
534 }
535
536
537 /* Show the Dissassem/Command layout. */
538 static void
539 show_disasm_command (void)
540 {
541 show_source_or_disasm_and_command (DISASSEM_COMMAND);
542 }
543
544
545 /* Show the Source/Disassem/Command layout. */
546 static void
547 show_source_disasm_command (void)
548 {
549 if (tui_current_layout () != SRC_DISASSEM_COMMAND)
550 {
551 int cmd_height, src_height, asm_height;
552
553 if (TUI_CMD_WIN != NULL)
554 cmd_height = TUI_CMD_WIN->height;
555 else
556 cmd_height = tui_term_height () / 3;
557
558 src_height = (tui_term_height () - cmd_height) / 2;
559 asm_height = tui_term_height () - (src_height + cmd_height);
560
561 if (TUI_SRC_WIN == NULL)
562 tui_win_list[SRC_WIN] = new tui_source_window ();
563 TUI_SRC_WIN->reset (src_height,
564 tui_term_width (),
565 0,
566 0);
567 tui_make_visible (TUI_SRC_WIN);
568 TUI_SRC_WIN->m_has_locator = false;
569
570 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
571 gdb_assert (locator != nullptr);
572
573 tui_show_source_content (TUI_SRC_WIN);
574 if (TUI_DISASM_WIN == NULL)
575 tui_win_list[DISASSEM_WIN] = new tui_disasm_window ();
576 TUI_DISASM_WIN->reset (asm_height,
577 tui_term_width (),
578 0,
579 src_height - 1);
580 tui_make_visible (TUI_DISASM_WIN);
581 locator->reset (2 /* 1 */ ,
582 tui_term_width (),
583 0,
584 (src_height + asm_height) - 1);
585 TUI_SRC_WIN->m_has_locator = false;
586 TUI_DISASM_WIN->m_has_locator = true;
587 tui_make_visible (locator);
588 tui_show_locator_content ();
589 tui_show_source_content (TUI_DISASM_WIN);
590
591 if (TUI_CMD_WIN == NULL)
592 tui_win_list[CMD_WIN]
593 = make_command_window (cmd_height, tui_term_height () - cmd_height);
594 else
595 {
596 TUI_CMD_WIN->reset (TUI_CMD_WIN->height,
597 TUI_CMD_WIN->width,
598 0,
599 TUI_CMD_WIN->origin.y);
600 tui_make_visible (TUI_CMD_WIN);
601 }
602 tui_set_current_layout_to (SRC_DISASSEM_COMMAND);
603 }
604 }
605
606
607 /* Show the Source/Data/Command or the Dissassembly/Data/Command
608 layout. */
609 static void
610 show_data (enum tui_layout_type new_layout)
611 {
612 int total_height = (tui_term_height () - TUI_CMD_WIN->height);
613 int src_height, data_height;
614 enum tui_win_type win_type;
615
616 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
617 gdb_assert (locator != nullptr);
618
619 data_height = total_height / 2;
620 src_height = total_height - data_height;
621 tui_make_all_invisible ();
622 tui_make_invisible (locator);
623 if (tui_win_list[DATA_WIN] == nullptr)
624 tui_win_list[DATA_WIN] = make_data_window (data_height, 0);
625 else
626 tui_win_list[DATA_WIN]->reset (data_height, tui_term_width (), 0, 0);
627 tui_win_list[DATA_WIN]->make_visible (true);
628
629 if (new_layout == SRC_DATA_COMMAND)
630 win_type = SRC_WIN;
631 else
632 win_type = DISASSEM_WIN;
633
634 tui_source_window_base *base;
635 if (tui_win_list[win_type] == NULL)
636 {
637 if (win_type == SRC_WIN)
638 tui_win_list[win_type]
639 = make_source_window (src_height, data_height - 1);
640 else
641 tui_win_list[win_type]
642 = make_disasm_window (src_height, data_height - 1);
643 locator->reset (2 /* 1 */ ,
644 tui_term_width (),
645 0,
646 total_height - 1);
647 base = (tui_source_window_base *) tui_win_list[win_type];
648 }
649 else
650 {
651 base = (tui_source_window_base *) tui_win_list[win_type];
652 tui_win_list[win_type]->reset (src_height,
653 tui_term_width (),
654 0,
655 data_height - 1);
656 tui_make_visible (tui_win_list[win_type]);
657 locator->reset (2 /* 1 */ ,
658 tui_term_width (),
659 0,
660 total_height - 1);
661 }
662 base->m_has_locator = true;
663 tui_make_visible (locator);
664 tui_show_locator_content ();
665 tui_add_to_source_windows
666 ((tui_source_window_base *) tui_win_list[win_type]);
667 tui_set_current_layout_to (new_layout);
668 }
669
670 void
671 tui_gen_win_info::reset (int height_, int width_,
672 int origin_x_, int origin_y_)
673 {
674 int h = height_;
675
676 width = width_;
677 height = h;
678 if (h > 1)
679 {
680 viewport_height = h - 1;
681 if (type != CMD_WIN)
682 viewport_height--;
683 }
684 else
685 viewport_height = 1;
686 origin.x = origin_x_;
687 origin.y = origin_y_;
688 }
689
690 /* Show the Source/Command or the Disassem layout. */
691 static void
692 show_source_or_disasm_and_command (enum tui_layout_type layout_type)
693 {
694 if (tui_current_layout () != layout_type)
695 {
696 struct tui_win_info **win_info_ptr;
697 int src_height, cmd_height;
698 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
699 gdb_assert (locator != nullptr);
700
701 if (TUI_CMD_WIN != NULL)
702 cmd_height = TUI_CMD_WIN->height;
703 else
704 cmd_height = tui_term_height () / 3;
705 src_height = tui_term_height () - cmd_height;
706
707 if (layout_type == SRC_COMMAND)
708 win_info_ptr = &tui_win_list[SRC_WIN];
709 else
710 win_info_ptr = &tui_win_list[DISASSEM_WIN];
711
712 tui_source_window_base *base;
713 if ((*win_info_ptr) == NULL)
714 {
715 if (layout_type == SRC_COMMAND)
716 *win_info_ptr = make_source_window (src_height - 1, 0);
717 else
718 *win_info_ptr = make_disasm_window (src_height - 1, 0);
719 locator->reset (2 /* 1 */ ,
720 tui_term_width (),
721 0,
722 src_height - 1);
723 base = (tui_source_window_base *) *win_info_ptr;
724 }
725 else
726 {
727 base = (tui_source_window_base *) *win_info_ptr;
728 locator->reset (2 /* 1 */ ,
729 tui_term_width (),
730 0,
731 src_height - 1);
732 base->m_has_locator = true;
733 (*win_info_ptr)->reset (src_height - 1,
734 tui_term_width (),
735 0,
736 0);
737 tui_make_visible (*win_info_ptr);
738 }
739
740 base->m_has_locator = true;
741 tui_make_visible (locator);
742 tui_show_locator_content ();
743 tui_show_source_content (base);
744
745 if (TUI_CMD_WIN == NULL)
746 {
747 tui_win_list[CMD_WIN] = make_command_window (cmd_height,
748 src_height);
749 }
750 else
751 {
752 TUI_CMD_WIN->reset (TUI_CMD_WIN->height,
753 TUI_CMD_WIN->width,
754 TUI_CMD_WIN->origin.x,
755 TUI_CMD_WIN->origin.y);
756 tui_make_visible (TUI_CMD_WIN);
757 }
758 tui_set_current_layout_to (layout_type);
759 }
760 }
This page took 0.046137 seconds and 4 git commands to generate.