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