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