ba0b367e16dee79230ece248db90521c9798cf7a
[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-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 static void show_layout (enum tui_layout_type);
44 static void show_source_or_disasm_and_command (enum tui_layout_type);
45 static void show_source_command (void);
46 static void show_disasm_command (void);
47 static void show_source_disasm_command (void);
48 static void show_data (enum tui_layout_type);
49 static enum tui_layout_type next_layout (void);
50 static enum tui_layout_type prev_layout (void);
51 static void tui_layout_command (const char *, int);
52 static void extract_display_start_addr (struct gdbarch **, CORE_ADDR *);
53
54
55 static enum tui_layout_type current_layout = UNDEFINED_LAYOUT;
56
57 /* Accessor for the current layout. */
58 enum tui_layout_type
59 tui_current_layout (void)
60 {
61 return current_layout;
62 }
63
64
65 /* Show the screen layout defined. */
66 static void
67 show_layout (enum tui_layout_type layout)
68 {
69 enum tui_layout_type cur_layout = tui_current_layout ();
70
71 if (layout != cur_layout)
72 {
73 tui_make_all_invisible ();
74 switch (layout)
75 {
76 case SRC_DATA_COMMAND:
77 case DISASSEM_DATA_COMMAND:
78 show_data (layout);
79 break;
80 /* Now show the new layout. */
81 case SRC_COMMAND:
82 show_source_command ();
83 break;
84 case DISASSEM_COMMAND:
85 show_disasm_command ();
86 break;
87 case SRC_DISASSEM_COMMAND:
88 show_source_disasm_command ();
89 break;
90 default:
91 break;
92 }
93
94 current_layout = layout;
95 tui_delete_invisible_windows ();
96 }
97 }
98
99
100 /* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
101 SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND. */
102 void
103 tui_set_layout (enum tui_layout_type layout_type)
104 {
105 gdb_assert (layout_type != UNDEFINED_LAYOUT);
106
107 enum tui_layout_type cur_layout = tui_current_layout ();
108 struct gdbarch *gdbarch;
109 CORE_ADDR addr;
110 struct tui_win_info *win_with_focus = tui_win_with_focus ();
111
112 extract_display_start_addr (&gdbarch, &addr);
113
114 enum tui_layout_type new_layout = layout_type;
115
116 if (new_layout != cur_layout)
117 {
118 show_layout (new_layout);
119
120 /* Now determine where focus should be. */
121 if (win_with_focus != TUI_CMD_WIN)
122 {
123 switch (new_layout)
124 {
125 case SRC_COMMAND:
126 tui_set_win_focus_to (TUI_SRC_WIN);
127 break;
128 case DISASSEM_COMMAND:
129 /* The previous layout was not showing code.
130 This can happen if there is no source
131 available:
132
133 1. if the source file is in another dir OR
134 2. if target was compiled without -g
135 We still want to show the assembly though! */
136
137 tui_get_begin_asm_address (&gdbarch, &addr);
138 tui_set_win_focus_to (TUI_DISASM_WIN);
139 break;
140 case SRC_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 if (win_with_focus == TUI_SRC_WIN)
151 tui_set_win_focus_to (TUI_SRC_WIN);
152 else
153 tui_set_win_focus_to (TUI_DISASM_WIN);
154 break;
155 case SRC_DATA_COMMAND:
156 if (win_with_focus != TUI_DATA_WIN)
157 tui_set_win_focus_to (TUI_SRC_WIN);
158 else
159 tui_set_win_focus_to (TUI_DATA_WIN);
160 break;
161 case DISASSEM_DATA_COMMAND:
162 /* The previous layout was not showing code.
163 This can happen if there is no source
164 available:
165
166 1. if the source file is in another dir OR
167 2. if target was compiled without -g
168 We still want to show the assembly though! */
169
170 tui_get_begin_asm_address (&gdbarch, &addr);
171 if (win_with_focus != TUI_DATA_WIN)
172 tui_set_win_focus_to (TUI_DISASM_WIN);
173 else
174 tui_set_win_focus_to (TUI_DATA_WIN);
175 break;
176 default:
177 break;
178 }
179 }
180 /*
181 * Now update the window content.
182 */
183 tui_update_source_windows_with_addr (gdbarch, addr);
184 if (new_layout == SRC_DATA_COMMAND
185 || new_layout == DISASSEM_DATA_COMMAND)
186 TUI_DATA_WIN->show_registers (TUI_DATA_WIN->get_current_group ());
187 }
188 }
189
190 /* Add the specified window to the layout in a logical way. This
191 means setting up the most logical layout given the window to be
192 added. */
193 void
194 tui_add_win_to_layout (enum tui_win_type type)
195 {
196 enum tui_layout_type cur_layout = tui_current_layout ();
197
198 switch (type)
199 {
200 case SRC_WIN:
201 if (cur_layout != SRC_COMMAND
202 && cur_layout != SRC_DISASSEM_COMMAND
203 && cur_layout != SRC_DATA_COMMAND)
204 {
205 if (cur_layout == DISASSEM_DATA_COMMAND)
206 show_layout (SRC_DATA_COMMAND);
207 else
208 show_layout (SRC_COMMAND);
209 }
210 break;
211 case DISASSEM_WIN:
212 if (cur_layout != DISASSEM_COMMAND
213 && cur_layout != SRC_DISASSEM_COMMAND
214 && cur_layout != DISASSEM_DATA_COMMAND)
215 {
216 if (cur_layout == SRC_DATA_COMMAND)
217 show_layout (DISASSEM_DATA_COMMAND);
218 else
219 show_layout (DISASSEM_COMMAND);
220 }
221 break;
222 case DATA_WIN:
223 if (cur_layout != SRC_DATA_COMMAND
224 && cur_layout != DISASSEM_DATA_COMMAND)
225 {
226 if (cur_layout == DISASSEM_COMMAND)
227 show_layout (DISASSEM_DATA_COMMAND);
228 else
229 show_layout (SRC_DATA_COMMAND);
230 }
231 break;
232 default:
233 break;
234 }
235 }
236
237 /* Complete possible layout names. TEXT is the complete text entered so
238 far, WORD is the word currently being completed. */
239
240 static void
241 layout_completer (struct cmd_list_element *ignore,
242 completion_tracker &tracker,
243 const char *text, const char *word)
244 {
245 static const char *layout_names [] =
246 { "src", "asm", "split", "regs", "next", "prev", NULL };
247
248 complete_on_enum (tracker, layout_names, text, word);
249 }
250
251 /* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
252 REGS. */
253 static void
254 tui_layout_command (const char *layout_name, int from_tty)
255 {
256 enum tui_layout_type new_layout = UNDEFINED_LAYOUT;
257 enum tui_layout_type cur_layout = tui_current_layout ();
258
259 if (layout_name == NULL || *layout_name == '\0')
260 error (_("Usage: layout prev | next | LAYOUT-NAME"));
261
262 /* First check for ambiguous input. */
263 if (strcmp (layout_name, "s") == 0)
264 error (_("Ambiguous command input."));
265
266 if (subset_compare (layout_name, "src"))
267 new_layout = SRC_COMMAND;
268 else if (subset_compare (layout_name, "asm"))
269 new_layout = DISASSEM_COMMAND;
270 else if (subset_compare (layout_name, "split"))
271 new_layout = SRC_DISASSEM_COMMAND;
272 else if (subset_compare (layout_name, "regs"))
273 {
274 if (cur_layout == SRC_COMMAND
275 || cur_layout == SRC_DATA_COMMAND)
276 new_layout = SRC_DATA_COMMAND;
277 else
278 new_layout = DISASSEM_DATA_COMMAND;
279 }
280 else if (subset_compare (layout_name, "next"))
281 new_layout = next_layout ();
282 else if (subset_compare (layout_name, "prev"))
283 new_layout = prev_layout ();
284 else
285 error (_("Unrecognized layout: %s"), layout_name);
286
287 /* Make sure the curses mode is enabled. */
288 tui_enable ();
289 tui_set_layout (new_layout);
290 }
291
292
293 static void
294 extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
295 {
296 enum tui_layout_type cur_layout = tui_current_layout ();
297 struct gdbarch *gdbarch = get_current_arch ();
298 CORE_ADDR addr;
299 CORE_ADDR pc;
300 struct symtab_and_line cursal = get_current_source_symtab_and_line ();
301
302 switch (cur_layout)
303 {
304 case SRC_COMMAND:
305 case SRC_DATA_COMMAND:
306 gdbarch = TUI_SRC_WIN->gdbarch;
307 find_line_pc (cursal.symtab,
308 TUI_SRC_WIN->start_line_or_addr.u.line_no,
309 &pc);
310 addr = pc;
311 break;
312 case DISASSEM_COMMAND:
313 case SRC_DISASSEM_COMMAND:
314 case DISASSEM_DATA_COMMAND:
315 gdbarch = TUI_DISASM_WIN->gdbarch;
316 addr = TUI_DISASM_WIN->start_line_or_addr.u.addr;
317 break;
318 default:
319 addr = 0;
320 break;
321 }
322
323 *gdbarch_p = gdbarch;
324 *addr_p = addr;
325 }
326
327
328 /* Answer the previous layout to cycle to. */
329 static enum tui_layout_type
330 next_layout (void)
331 {
332 int new_layout;
333
334 new_layout = tui_current_layout ();
335 if (new_layout == UNDEFINED_LAYOUT)
336 new_layout = SRC_COMMAND;
337 else
338 {
339 new_layout++;
340 if (new_layout == UNDEFINED_LAYOUT)
341 new_layout = SRC_COMMAND;
342 }
343
344 return (enum tui_layout_type) new_layout;
345 }
346
347
348 /* Answer the next layout to cycle to. */
349 static enum tui_layout_type
350 prev_layout (void)
351 {
352 int new_layout;
353
354 new_layout = tui_current_layout ();
355 if (new_layout == SRC_COMMAND)
356 new_layout = DISASSEM_DATA_COMMAND;
357 else
358 {
359 new_layout--;
360 if (new_layout == UNDEFINED_LAYOUT)
361 new_layout = DISASSEM_DATA_COMMAND;
362 }
363
364 return (enum tui_layout_type) new_layout;
365 }
366
367 /* Show the Source/Command layout. */
368 static void
369 show_source_command (void)
370 {
371 show_source_or_disasm_and_command (SRC_COMMAND);
372 }
373
374
375 /* Show the Dissassem/Command layout. */
376 static void
377 show_disasm_command (void)
378 {
379 show_source_or_disasm_and_command (DISASSEM_COMMAND);
380 }
381
382
383 /* Show the Source/Disassem/Command layout. */
384 static void
385 show_source_disasm_command (void)
386 {
387 int cmd_height, src_height, asm_height;
388
389 if (TUI_CMD_WIN != NULL)
390 cmd_height = TUI_CMD_WIN->height;
391 else
392 cmd_height = tui_term_height () / 3;
393
394 src_height = (tui_term_height () - cmd_height) / 2;
395 asm_height = tui_term_height () - (src_height + cmd_height);
396
397 if (TUI_SRC_WIN == NULL)
398 tui_win_list[SRC_WIN] = new tui_source_window ();
399 TUI_SRC_WIN->resize (src_height,
400 tui_term_width (),
401 0,
402 0);
403
404 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
405 gdb_assert (locator != nullptr);
406
407 if (TUI_DISASM_WIN == NULL)
408 tui_win_list[DISASSEM_WIN] = new tui_disasm_window ();
409 TUI_DISASM_WIN->resize (asm_height,
410 tui_term_width (),
411 0,
412 src_height - 1);
413 locator->resize (1, tui_term_width (),
414 0, (src_height + asm_height) - 1);
415
416 if (TUI_CMD_WIN == NULL)
417 tui_win_list[CMD_WIN] = new tui_cmd_window ();
418 TUI_CMD_WIN->resize (cmd_height,
419 tui_term_width (),
420 0,
421 tui_term_height () - cmd_height);
422 }
423
424
425 /* Show the Source/Data/Command or the Dissassembly/Data/Command
426 layout. */
427 static void
428 show_data (enum tui_layout_type new_layout)
429 {
430 int total_height = (tui_term_height () - TUI_CMD_WIN->height);
431 int src_height, data_height;
432 enum tui_win_type win_type;
433
434 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
435 gdb_assert (locator != nullptr);
436
437 data_height = total_height / 2;
438 src_height = total_height - data_height;
439 if (tui_win_list[DATA_WIN] == nullptr)
440 tui_win_list[DATA_WIN] = new tui_data_window ();
441 tui_win_list[DATA_WIN]->resize (data_height, tui_term_width (), 0, 0);
442
443 if (new_layout == SRC_DATA_COMMAND)
444 win_type = SRC_WIN;
445 else
446 win_type = DISASSEM_WIN;
447
448 if (tui_win_list[win_type] == NULL)
449 {
450 if (win_type == SRC_WIN)
451 tui_win_list[win_type] = new tui_source_window ();
452 else
453 tui_win_list[win_type] = new tui_disasm_window ();
454 }
455
456 tui_win_list[win_type]->resize (src_height,
457 tui_term_width (),
458 0,
459 data_height - 1);
460 locator->resize (1, tui_term_width (),
461 0, total_height - 1);
462 TUI_CMD_WIN->resize (TUI_CMD_WIN->height, tui_term_width (),
463 0, total_height);
464 }
465
466 void
467 tui_gen_win_info::resize (int height_, int width_,
468 int origin_x_, int origin_y_)
469 {
470 if (width == width_ && height == height_
471 && origin.x == origin_x_ && origin.y == origin_y_
472 && handle != nullptr)
473 return;
474
475 width = width_;
476 height = height_;
477 if (height > 1)
478 viewport_height = height - 2;
479 else
480 viewport_height = 1;
481 origin.x = origin_x_;
482 origin.y = origin_y_;
483
484 if (handle != nullptr)
485 {
486 #ifdef HAVE_WRESIZE
487 wresize (handle.get (), height, width);
488 mvwin (handle.get (), origin.y, origin.x);
489 wmove (handle.get (), 0, 0);
490 #else
491 handle.reset (nullptr);
492 #endif
493 }
494
495 if (handle == nullptr)
496 make_window ();
497
498 rerender ();
499 }
500
501 /* Show the Source/Command or the Disassem layout. */
502 static void
503 show_source_or_disasm_and_command (enum tui_layout_type layout_type)
504 {
505 struct tui_source_window_base *win_info;
506 int src_height, cmd_height;
507 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
508 gdb_assert (locator != nullptr);
509
510 if (TUI_CMD_WIN != NULL)
511 cmd_height = TUI_CMD_WIN->height;
512 else
513 cmd_height = tui_term_height () / 3;
514 src_height = tui_term_height () - cmd_height;
515
516 if (layout_type == SRC_COMMAND)
517 {
518 if (tui_win_list[SRC_WIN] == nullptr)
519 tui_win_list[SRC_WIN] = new tui_source_window ();
520 win_info = TUI_SRC_WIN;
521 }
522 else
523 {
524 if (tui_win_list[DISASSEM_WIN] == nullptr)
525 tui_win_list[DISASSEM_WIN] = new tui_disasm_window ();
526 win_info = TUI_DISASM_WIN;
527 }
528
529 locator->resize (1, tui_term_width (),
530 0, src_height - 1);
531 win_info->resize (src_height - 1,
532 tui_term_width (),
533 0,
534 0);
535
536 if (TUI_CMD_WIN == NULL)
537 tui_win_list[CMD_WIN] = new tui_cmd_window ();
538 TUI_CMD_WIN->resize (cmd_height,
539 tui_term_width (),
540 0,
541 src_height);
542 }
543
544 \f
545
546 /* Function to initialize gdb commands, for tui window layout
547 manipulation. */
548
549 void
550 _initialize_tui_layout (void)
551 {
552 struct cmd_list_element *cmd;
553
554 cmd = add_com ("layout", class_tui, tui_layout_command, _("\
555 Change the layout of windows.\n\
556 Usage: layout prev | next | LAYOUT-NAME\n\
557 Layout names are:\n\
558 src : Displays source and command windows.\n\
559 asm : Displays disassembly and command windows.\n\
560 split : Displays source, disassembly and command windows.\n\
561 regs : Displays register window. If existing layout\n\
562 is source/command or assembly/command, the \n\
563 register window is displayed. If the\n\
564 source/assembly/command (split) is displayed, \n\
565 the register window is displayed with \n\
566 the window that has current logical focus."));
567 set_cmd_completer (cmd, layout_completer);
568 }
This page took 0.038794 seconds and 3 git commands to generate.