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