Remove tui_delete_invisible_windows and tui_make_all_invisible
[deliverable/binutils-gdb.git] / gdb / tui / tui-layout.c
CommitLineData
f377b406 1/* TUI layout window management.
f33c6cbf 2
b811d2c2 3 Copyright (C) 1998-2020 Free Software Foundation, Inc.
f33c6cbf 4
f377b406 5 Contributed by Hewlett-Packard Company.
c906108c 6
f377b406
SC
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
a9762ec7 11 the Free Software Foundation; either version 3 of the License, or
f377b406
SC
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
a9762ec7 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c
SS
21
22#include "defs.h"
957b8b5a 23#include "arch-utils.h"
c906108c
SS
24#include "command.h"
25#include "symtab.h"
26#include "frame.h"
52575520 27#include "source.h"
416eb92d
TT
28#include "cli/cli-cmds.h"
29#include "cli/cli-decode.h"
ee325b61 30#include "cli/cli-utils.h"
84b1e7c7 31#include <ctype.h>
ee325b61 32#include <unordered_set>
c906108c 33
d7b2e967 34#include "tui/tui.h"
ce38393b 35#include "tui/tui-command.h"
d7b2e967 36#include "tui/tui-data.h"
d7b2e967
AC
37#include "tui/tui-wingeneral.h"
38#include "tui/tui-stack.h"
39#include "tui/tui-regs.h"
40#include "tui/tui-win.h"
41#include "tui/tui-winsource.h"
42#include "tui/tui-disasm.h"
2c0b251b 43#include "tui/tui-layout.h"
bfad4537 44#include "tui/tui-source.h"
6a83354a 45#include "gdb_curses.h"
96ec9981 46
0b39b52e 47static void tui_layout_command (const char *, int);
13274fc3 48static void extract_display_start_addr (struct gdbarch **, CORE_ADDR *);
c906108c 49
416eb92d
TT
50/* The layouts. */
51static std::vector<std::unique_ptr<tui_layout_split>> layouts;
2192a9d3
TT
52
53/* The layout that is currently applied. */
54static std::unique_ptr<tui_layout_base> applied_layout;
55
416eb92d
TT
56/* The "skeleton" version of the layout that is currently applied. */
57static tui_layout_split *applied_skeleton;
62cf57fe 58
416eb92d
TT
59/* The two special "regs" layouts. Note that these aren't registered
60 as commands and so can never be deleted. */
61static tui_layout_split *src_regs_layout;
62static tui_layout_split *asm_regs_layout;
62cf57fe 63
7eed1a8e
TT
64/* See tui-data.h. */
65std::vector<tui_win_info *> tui_windows;
66
2192a9d3
TT
67/* See tui-layout.h. */
68
69void
70tui_apply_current_layout ()
71{
865a5aec
TT
72 struct gdbarch *gdbarch;
73 CORE_ADDR addr;
74
75 extract_display_start_addr (&gdbarch, &addr);
76
77 std::vector<tui_win_info *> saved_windows = std::move (tui_windows);
7eed1a8e 78 tui_windows.clear ();
865a5aec
TT
79
80 for (tui_win_info *win_info : saved_windows)
81 win_info->make_visible (false);
82
2192a9d3 83 applied_layout->apply (0, 0, tui_term_width (), tui_term_height ());
865a5aec
TT
84
85 /* Keep the list of internal windows up-to-date. */
86 for (int win_type = SRC_WIN; (win_type < MAX_MAJOR_WINDOWS); win_type++)
87 if (tui_win_list[win_type] != nullptr
88 && !tui_win_list[win_type]->is_visible ())
89 tui_win_list[win_type] = nullptr;
90
91 /* This should always be made visible by a layout. */
92 gdb_assert (TUI_CMD_WIN->is_visible ());
93
94 /* Now delete any window that was not re-applied. */
95 tui_win_info *focus = tui_win_with_focus ();
96 for (tui_win_info *win_info : saved_windows)
97 {
98 if (!win_info->is_visible ())
99 {
100 if (focus == win_info)
101 tui_set_win_focus_to (tui_windows[0]);
102 delete win_info;
103 }
104 }
105
106 if (gdbarch == nullptr && TUI_DISASM_WIN != nullptr)
107 tui_get_begin_asm_address (&gdbarch, &addr);
108 tui_update_source_windows_with_addr (gdbarch, addr);
2192a9d3 109}
c906108c 110
d4eeccfe
TT
111/* See tui-layout. */
112
113void
114tui_adjust_window_height (struct tui_win_info *win, int new_height)
115{
116 applied_layout->adjust_size (win->name (), new_height);
117}
118
416eb92d 119/* Set the current layout to LAYOUT. */
c906108c 120
416eb92d
TT
121static void
122tui_set_layout (tui_layout_split *layout)
c906108c 123{
416eb92d
TT
124 applied_skeleton = layout;
125 applied_layout = layout->clone ();
126 tui_apply_current_layout ();
bc712bbf 127}
c906108c 128
59b8b5d2
TT
129/* See tui-layout.h. */
130
c906108c 131void
080ce8c0 132tui_add_win_to_layout (enum tui_win_type type)
c906108c 133{
59b8b5d2
TT
134 gdb_assert (type == SRC_WIN || type == DISASSEM_WIN);
135
416eb92d
TT
136 /* If the window already exists, no need to add it. */
137 if (tui_win_list[type] != nullptr)
138 return;
139
140 /* If the window we are trying to replace doesn't exist, we're
141 done. */
142 enum tui_win_type other = type == SRC_WIN ? DISASSEM_WIN : SRC_WIN;
143 if (tui_win_list[other] == nullptr)
144 return;
145
146 const char *name = type == SRC_WIN ? SRC_NAME : DISASSEM_NAME;
147 applied_layout->replace_window (tui_win_list[other]->name (), name);
148 tui_apply_current_layout ();
416eb92d
TT
149}
150
151/* Find LAYOUT in the "layouts" global and return its index. */
c906108c 152
416eb92d
TT
153static size_t
154find_layout (tui_layout_split *layout)
155{
156 for (size_t i = 0; i < layouts.size (); ++i)
c906108c 157 {
416eb92d
TT
158 if (layout == layouts[i].get ())
159 return i;
c906108c 160 }
416eb92d 161 gdb_assert_not_reached (_("layout not found!?"));
6ba8e26f 162}
c906108c 163
416eb92d 164/* Function to set the layout. */
a0145030 165
eb3ff9a5 166static void
416eb92d
TT
167tui_apply_layout (struct cmd_list_element *command,
168 const char *args, int from_tty)
a0145030 169{
416eb92d
TT
170 tui_layout_split *layout
171 = (tui_layout_split *) get_cmd_context (command);
a0145030 172
416eb92d
TT
173 /* Make sure the curses mode is enabled. */
174 tui_enable ();
175 tui_set_layout (layout);
a0145030
AB
176}
177
416eb92d 178/* See tui-layout.h. */
c906108c 179
416eb92d
TT
180void
181tui_next_layout ()
182{
183 size_t index = find_layout (applied_skeleton);
184 ++index;
185 if (index == layouts.size ())
186 index = 0;
187 tui_set_layout (layouts[index].get ());
188}
c906108c 189
416eb92d 190/* Implement the "layout next" command. */
c906108c 191
416eb92d
TT
192static void
193tui_next_layout_command (const char *arg, int from_tty)
194{
0379b883 195 tui_enable ();
416eb92d 196 tui_next_layout ();
e8b915dc 197}
c906108c 198
427326a8
TT
199/* See tui-layout.h. */
200
201void
416eb92d
TT
202tui_set_initial_layout ()
203{
204 tui_set_layout (layouts[0].get ());
205}
206
207/* Implement the "layout prev" command. */
208
209static void
210tui_prev_layout_command (const char *arg, int from_tty)
427326a8 211{
416eb92d
TT
212 tui_enable ();
213 size_t index = find_layout (applied_skeleton);
214 if (index == 0)
215 index = layouts.size ();
216 --index;
217 tui_set_layout (layouts[index].get ());
427326a8 218}
c906108c 219
416eb92d 220
5afe342e
TT
221/* See tui-layout.h. */
222
0dbc2fc7
TT
223void
224tui_regs_layout ()
225{
416eb92d
TT
226 /* If there's already a register window, we're done. */
227 if (TUI_DATA_WIN != nullptr)
228 return;
229
230 tui_set_layout (TUI_DISASM_WIN != nullptr
231 ? asm_regs_layout
232 : src_regs_layout);
233}
234
235/* Implement the "layout regs" command. */
236
237static void
238tui_regs_layout_command (const char *arg, int from_tty)
239{
240 tui_enable ();
241 tui_regs_layout ();
0dbc2fc7
TT
242}
243
244/* See tui-layout.h. */
245
5afe342e
TT
246void
247tui_remove_some_windows ()
248{
249 tui_win_info *focus = tui_win_with_focus ();
250
251 if (strcmp (focus->name (), "cmd") == 0)
252 {
253 /* Try leaving the source or disassembly window. If neither
254 exists, just do nothing. */
255 focus = TUI_SRC_WIN;
256 if (focus == nullptr)
257 focus = TUI_DISASM_WIN;
258 if (focus == nullptr)
259 return;
260 }
261
262 applied_layout->remove_windows (focus->name ());
263 tui_apply_current_layout ();
264}
265
13274fc3
UW
266static void
267extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
c906108c 268{
416eb92d
TT
269 struct gdbarch *gdbarch = nullptr;
270 CORE_ADDR addr = 0;
84b1e7c7 271 CORE_ADDR pc;
52575520 272 struct symtab_and_line cursal = get_current_source_symtab_and_line ();
c906108c 273
416eb92d 274 if (TUI_SRC_WIN != nullptr)
c906108c 275 {
e6e41501 276 gdbarch = TUI_SRC_WIN->gdbarch;
52575520 277 find_line_pc (cursal.symtab,
e6e41501 278 TUI_SRC_WIN->start_line_or_addr.u.line_no,
84b1e7c7 279 &pc);
c774cec6 280 addr = pc;
416eb92d
TT
281 }
282 else if (TUI_DISASM_WIN != nullptr)
283 {
e6e41501
TT
284 gdbarch = TUI_DISASM_WIN->gdbarch;
285 addr = TUI_DISASM_WIN->start_line_or_addr.u.addr;
c906108c
SS
286 }
287
13274fc3
UW
288 *gdbarch_p = gdbarch;
289 *addr_p = addr;
6ba8e26f 290}
c906108c 291
d6ba6a11 292void
ee556432
TT
293tui_gen_win_info::resize (int height_, int width_,
294 int origin_x_, int origin_y_)
c906108c 295{
cdaa6eb4 296 if (width == width_ && height == height_
fb3184d8 297 && x == origin_x_ && y == origin_y_
cdaa6eb4
TT
298 && handle != nullptr)
299 return;
300
d6ba6a11 301 width = width_;
db502012 302 height = height_;
fb3184d8
TT
303 x = origin_x_;
304 y = origin_y_;
db502012
TT
305
306 if (handle != nullptr)
307 {
308#ifdef HAVE_WRESIZE
7523da63 309 wresize (handle.get (), height, width);
fb3184d8 310 mvwin (handle.get (), y, x);
7523da63 311 wmove (handle.get (), 0, 0);
db502012 312#else
7523da63 313 handle.reset (nullptr);
db502012
TT
314#endif
315 }
316
317 if (handle == nullptr)
ab0e1f1a 318 make_window ();
3df505f6
TT
319
320 rerender ();
d6ba6a11 321}
c906108c 322
d9fcefd5
TT
323\f
324
389e7ddb
TT
325/* Helper function that returns a TUI window, given its name. */
326
327static tui_gen_win_info *
328tui_get_window_by_name (const std::string &name)
329{
330 if (name == "src")
331 {
332 if (tui_win_list[SRC_WIN] == nullptr)
333 tui_win_list[SRC_WIN] = new tui_source_window ();
334 return tui_win_list[SRC_WIN];
335 }
336 else if (name == "cmd")
337 {
338 if (tui_win_list[CMD_WIN] == nullptr)
339 tui_win_list[CMD_WIN] = new tui_cmd_window ();
340 return tui_win_list[CMD_WIN];
341 }
342 else if (name == "regs")
343 {
344 if (tui_win_list[DATA_WIN] == nullptr)
345 tui_win_list[DATA_WIN] = new tui_data_window ();
346 return tui_win_list[DATA_WIN];
347 }
348 else if (name == "asm")
349 {
350 if (tui_win_list[DISASSEM_WIN] == nullptr)
351 tui_win_list[DISASSEM_WIN] = new tui_disasm_window ();
352 return tui_win_list[DISASSEM_WIN];
353 }
354 else
355 {
416eb92d 356 gdb_assert (name == "status");
389e7ddb
TT
357 return tui_locator_win_info_ptr ();
358 }
359}
360
361/* See tui-layout.h. */
362
363std::unique_ptr<tui_layout_base>
364tui_layout_window::clone () const
365{
366 tui_layout_window *result = new tui_layout_window (m_contents.c_str ());
367 return std::unique_ptr<tui_layout_base> (result);
368}
369
370/* See tui-layout.h. */
371
372void
373tui_layout_window::apply (int x_, int y_, int width_, int height_)
374{
375 x = x_;
376 y = y_;
377 width = width_;
378 height = height_;
379 gdb_assert (m_window != nullptr);
380 m_window->resize (height, width, x, y);
7eed1a8e
TT
381 if (dynamic_cast<tui_win_info *> (m_window) != nullptr)
382 tui_windows.push_back ((tui_win_info *) m_window);
389e7ddb
TT
383}
384
385/* See tui-layout.h. */
386
387void
7c043ba6 388tui_layout_window::get_sizes (bool height, int *min_value, int *max_value)
389e7ddb
TT
389{
390 if (m_window == nullptr)
391 m_window = tui_get_window_by_name (m_contents);
7c043ba6
TT
392 if (height)
393 {
394 *min_value = m_window->min_height ();
395 *max_value = m_window->max_height ();
396 }
397 else
398 {
399 *min_value = m_window->min_width ();
400 *max_value = m_window->max_width ();
401 }
389e7ddb
TT
402}
403
404/* See tui-layout.h. */
405
406bool
407tui_layout_window::top_boxed_p () const
408{
409 gdb_assert (m_window != nullptr);
410 return m_window->can_box ();
411}
412
413/* See tui-layout.h. */
414
415bool
416tui_layout_window::bottom_boxed_p () const
417{
418 gdb_assert (m_window != nullptr);
419 return m_window->can_box ();
420}
421
422/* See tui-layout.h. */
423
416eb92d
TT
424void
425tui_layout_window::replace_window (const char *name, const char *new_window)
426{
427 if (m_contents == name)
428 {
429 m_contents = new_window;
430 if (m_window != nullptr)
431 {
432 m_window->make_visible (false);
433 m_window = tui_get_window_by_name (m_contents);
434 }
435 }
436}
437
438/* See tui-layout.h. */
439
ee325b61 440void
c22fef7e 441tui_layout_window::specification (ui_file *output, int depth)
ee325b61
TT
442{
443 fputs_unfiltered (get_name (), output);
444}
445
446/* See tui-layout.h. */
447
c22fef7e
TT
448void
449tui_layout_split::add_split (std::unique_ptr<tui_layout_split> &&layout,
450 int weight)
389e7ddb 451{
c22fef7e 452 split s = {weight, std::move (layout)};
389e7ddb 453 m_splits.push_back (std::move (s));
389e7ddb
TT
454}
455
456/* See tui-layout.h. */
457
458void
459tui_layout_split::add_window (const char *name, int weight)
460{
461 tui_layout_window *result = new tui_layout_window (name);
462 split s = {weight, std::unique_ptr<tui_layout_base> (result)};
463 m_splits.push_back (std::move (s));
464}
465
466/* See tui-layout.h. */
467
468std::unique_ptr<tui_layout_base>
469tui_layout_split::clone () const
470{
7c043ba6 471 tui_layout_split *result = new tui_layout_split (m_vertical);
389e7ddb
TT
472 for (const split &item : m_splits)
473 {
474 std::unique_ptr<tui_layout_base> next = item.layout->clone ();
475 split s = {item.weight, std::move (next)};
476 result->m_splits.push_back (std::move (s));
477 }
478 return std::unique_ptr<tui_layout_base> (result);
479}
480
481/* See tui-layout.h. */
482
483void
7c043ba6 484tui_layout_split::get_sizes (bool height, int *min_value, int *max_value)
389e7ddb 485{
7c043ba6
TT
486 *min_value = 0;
487 *max_value = 0;
488 bool first_time = true;
389e7ddb
TT
489 for (const split &item : m_splits)
490 {
491 int new_min, new_max;
7c043ba6
TT
492 item.layout->get_sizes (height, &new_min, &new_max);
493 /* For the mismatch case, the first time through we want to set
494 the min and max to the computed values -- the "first_time"
495 check here is just a funny way of doing that. */
496 if (height == m_vertical || first_time)
497 {
498 *min_value += new_min;
499 *max_value += new_max;
500 }
501 else
502 {
503 *min_value = std::max (*min_value, new_min);
504 *max_value = std::min (*max_value, new_max);
505 }
506 first_time = false;
389e7ddb
TT
507 }
508}
509
510/* See tui-layout.h. */
511
512bool
513tui_layout_split::top_boxed_p () const
514{
515 if (m_splits.empty ())
516 return false;
517 return m_splits[0].layout->top_boxed_p ();
518}
519
520/* See tui-layout.h. */
521
522bool
523tui_layout_split::bottom_boxed_p () const
524{
525 if (m_splits.empty ())
526 return false;
527 return m_splits.back ().layout->top_boxed_p ();
528}
529
530/* See tui-layout.h. */
531
532void
533tui_layout_split::set_weights_from_heights ()
534{
535 for (int i = 0; i < m_splits.size (); ++i)
536 m_splits[i].weight = m_splits[i].layout->height;
537}
538
539/* See tui-layout.h. */
540
6bc56648 541tui_adjust_result
389e7ddb
TT
542tui_layout_split::adjust_size (const char *name, int new_height)
543{
544 /* Look through the children. If one is a layout holding the named
545 window, we're done; or if one actually is the named window,
546 update it. */
547 int found_index = -1;
548 for (int i = 0; i < m_splits.size (); ++i)
549 {
6bc56648
TT
550 tui_adjust_result adjusted
551 = m_splits[i].layout->adjust_size (name, new_height);
552 if (adjusted == HANDLED)
553 return HANDLED;
554 if (adjusted == FOUND)
389e7ddb 555 {
7c043ba6
TT
556 if (!m_vertical)
557 return FOUND;
389e7ddb
TT
558 found_index = i;
559 break;
560 }
561 }
562
563 if (found_index == -1)
6bc56648 564 return NOT_FOUND;
389e7ddb 565 if (m_splits[found_index].layout->height == new_height)
6bc56648 566 return HANDLED;
389e7ddb
TT
567
568 set_weights_from_heights ();
569 int delta = m_splits[found_index].weight - new_height;
570 m_splits[found_index].weight = new_height;
571
572 /* Distribute the "delta" over the next window; but if the next
573 window cannot hold it all, keep going until we either find a
574 window that does, or until we loop all the way around. */
575 for (int i = 0; delta != 0 && i < m_splits.size () - 1; ++i)
576 {
577 int index = (found_index + 1 + i) % m_splits.size ();
578
579 int new_min, new_max;
7c043ba6 580 m_splits[index].layout->get_sizes (m_vertical, &new_min, &new_max);
389e7ddb
TT
581
582 if (delta < 0)
583 {
584 /* The primary window grew, so we are trying to shrink other
585 windows. */
586 int available = m_splits[index].weight - new_min;
587 int shrink_by = std::min (available, -delta);
588 m_splits[index].weight -= shrink_by;
589 delta += shrink_by;
590 }
591 else
592 {
593 /* The primary window shrank, so we are trying to grow other
594 windows. */
595 int available = new_max - m_splits[index].weight;
596 int grow_by = std::min (available, delta);
597 m_splits[index].weight += grow_by;
598 delta -= grow_by;
599 }
600 }
601
602 if (delta != 0)
603 {
604 warning (_("Invalid window height specified"));
605 /* Effectively undo any modifications made here. */
606 set_weights_from_heights ();
607 }
608 else
609 {
610 /* Simply re-apply the updated layout. */
611 apply (x, y, width, height);
612 }
613
6bc56648 614 return HANDLED;
389e7ddb
TT
615}
616
617/* See tui-layout.h. */
618
619void
620tui_layout_split::apply (int x_, int y_, int width_, int height_)
621{
622 x = x_;
623 y = y_;
624 width = width_;
625 height = height_;
626
7c043ba6 627 struct size_info
389e7ddb 628 {
7c043ba6
TT
629 int size;
630 int min_size;
631 int max_size;
389e7ddb
TT
632 /* True if this window will share a box border with the previous
633 window in the list. */
634 bool share_box;
635 };
636
7c043ba6 637 std::vector<size_info> info (m_splits.size ());
389e7ddb 638
7c043ba6
TT
639 /* Step 1: Find the min and max size of each sub-layout.
640 Fixed-sized layouts are given their desired size, and then the
389e7ddb
TT
641 remaining space is distributed among the remaining windows
642 according to the weights given. */
7c043ba6 643 int available_size = m_vertical ? height : width;
389e7ddb
TT
644 int last_index = -1;
645 int total_weight = 0;
646 for (int i = 0; i < m_splits.size (); ++i)
647 {
648 bool cmd_win_already_exists = TUI_CMD_WIN != nullptr;
649
650 /* Always call get_sizes, to ensure that the window is
651 instantiated. This is a bit gross but less gross than adding
652 special cases for this in other places. */
7c043ba6
TT
653 m_splits[i].layout->get_sizes (m_vertical, &info[i].min_size,
654 &info[i].max_size);
389e7ddb
TT
655
656 if (!m_applied
657 && cmd_win_already_exists
658 && m_splits[i].layout->get_name () != nullptr
659 && strcmp (m_splits[i].layout->get_name (), "cmd") == 0)
660 {
661 /* If this layout has never been applied, then it means the
662 user just changed the layout. In this situation, it's
663 desirable to keep the size of the command window the
7c043ba6 664 same. Setting the min and max sizes this way ensures
389e7ddb
TT
665 that the resizing step, below, does the right thing with
666 this window. */
7c043ba6
TT
667 info[i].min_size = (m_vertical
668 ? TUI_CMD_WIN->height
669 : TUI_CMD_WIN->width);
670 info[i].max_size = info[i].min_size;
389e7ddb
TT
671 }
672
7c043ba6
TT
673 if (info[i].min_size == info[i].max_size)
674 available_size -= info[i].min_size;
389e7ddb
TT
675 else
676 {
677 last_index = i;
678 total_weight += m_splits[i].weight;
679 }
680
681 /* Two adjacent boxed windows will share a border, making a bit
7c043ba6 682 more size available. */
389e7ddb
TT
683 if (i > 0
684 && m_splits[i - 1].layout->bottom_boxed_p ()
685 && m_splits[i].layout->top_boxed_p ())
686 info[i].share_box = true;
687 }
688
7c043ba6 689 /* Step 2: Compute the size of each sub-layout. Fixed-sized items
389e7ddb
TT
690 are given their fixed size, while others are resized according to
691 their weight. */
7c043ba6 692 int used_size = 0;
389e7ddb
TT
693 for (int i = 0; i < m_splits.size (); ++i)
694 {
695 /* Compute the height and clamp to the allowable range. */
7c043ba6
TT
696 info[i].size = available_size * m_splits[i].weight / total_weight;
697 if (info[i].size > info[i].max_size)
698 info[i].size = info[i].max_size;
699 if (info[i].size < info[i].min_size)
700 info[i].size = info[i].min_size;
701 /* If there is any leftover size, just redistribute it to the
389e7ddb 702 last resizeable window, by dropping it from the allocated
7c043ba6
TT
703 size. We could try to be fancier here perhaps, by
704 redistributing this size among all windows, not just the
389e7ddb 705 last window. */
7c043ba6 706 if (info[i].min_size != info[i].max_size)
389e7ddb 707 {
7c043ba6 708 used_size += info[i].size;
389e7ddb 709 if (info[i].share_box)
7c043ba6 710 --used_size;
389e7ddb
TT
711 }
712 }
713
7c043ba6
TT
714 /* Allocate any leftover size. */
715 if (available_size >= used_size && last_index != -1)
716 info[last_index].size += available_size - used_size;
389e7ddb
TT
717
718 /* Step 3: Resize. */
7c043ba6
TT
719 int size_accum = 0;
720 const int maximum = m_vertical ? height : width;
389e7ddb
TT
721 for (int i = 0; i < m_splits.size (); ++i)
722 {
723 /* If we fall off the bottom, just make allocations overlap.
724 GIGO. */
7c043ba6
TT
725 if (size_accum + info[i].size > maximum)
726 size_accum = maximum - info[i].size;
389e7ddb 727 else if (info[i].share_box)
7c043ba6
TT
728 --size_accum;
729 if (m_vertical)
730 m_splits[i].layout->apply (x, y + size_accum, width, info[i].size);
731 else
732 m_splits[i].layout->apply (x + size_accum, y, info[i].size, height);
733 size_accum += info[i].size;
389e7ddb
TT
734 }
735
736 m_applied = true;
737}
738
5afe342e
TT
739/* See tui-layout.h. */
740
741void
742tui_layout_split::remove_windows (const char *name)
743{
744 for (int i = 0; i < m_splits.size (); ++i)
745 {
746 const char *this_name = m_splits[i].layout->get_name ();
747 if (this_name == nullptr)
748 m_splits[i].layout->remove_windows (name);
749 else
750 {
751 if (strcmp (this_name, name) == 0
752 || strcmp (this_name, "cmd") == 0)
753 {
754 /* Keep. */
755 }
756 m_splits.erase (m_splits.begin () + i);
757 --i;
758 }
759 }
760}
761
416eb92d
TT
762/* See tui-layout.h. */
763
764void
765tui_layout_split::replace_window (const char *name, const char *new_window)
766{
767 for (auto &item : m_splits)
768 item.layout->replace_window (name, new_window);
769}
770
ee325b61
TT
771/* See tui-layout.h. */
772
773void
c22fef7e 774tui_layout_split::specification (ui_file *output, int depth)
ee325b61 775{
c22fef7e
TT
776 if (depth > 0)
777 fputs_unfiltered ("{", output);
778
7c043ba6
TT
779 if (!m_vertical)
780 fputs_unfiltered ("-horizontal ", output);
781
ee325b61
TT
782 bool first = true;
783 for (auto &item : m_splits)
784 {
785 if (!first)
786 fputs_unfiltered (" ", output);
787 first = false;
c22fef7e 788 item.layout->specification (output, depth + 1);
ee325b61
TT
789 fprintf_unfiltered (output, " %d", item.weight);
790 }
c22fef7e
TT
791
792 if (depth > 0)
793 fputs_unfiltered ("}", output);
ee325b61
TT
794}
795
416eb92d
TT
796/* Destroy the layout associated with SELF. */
797
2192a9d3 798static void
416eb92d
TT
799destroy_layout (struct cmd_list_element *self, void *context)
800{
801 tui_layout_split *layout = (tui_layout_split *) context;
802 size_t index = find_layout (layout);
803 layouts.erase (layouts.begin () + index);
804}
805
806/* List holding the sub-commands of "layout". */
807
808static struct cmd_list_element *layout_list;
809
810/* Add a "layout" command with name NAME that switches to LAYOUT. */
811
ee325b61 812static struct cmd_list_element *
416eb92d 813add_layout_command (const char *name, tui_layout_split *layout)
2192a9d3 814{
416eb92d 815 struct cmd_list_element *cmd;
2192a9d3 816
ee325b61 817 string_file spec;
c22fef7e 818 layout->specification (&spec, 0);
ee325b61
TT
819
820 gdb::unique_xmalloc_ptr<char> doc
821 (xstrprintf (_("Apply the \"%s\" layout.\n\
822This layout was created using:\n\
823 tui new-layout %s %s"),
824 name, name, spec.c_str ()));
2192a9d3 825
416eb92d
TT
826 cmd = add_cmd (name, class_tui, nullptr, doc.get (), &layout_list);
827 set_cmd_context (cmd, layout);
828 /* There is no API to set this. */
829 cmd->func = tui_apply_layout;
830 cmd->destroyer = destroy_layout;
831 cmd->doc_allocated = 1;
832 doc.release ();
833 layouts.emplace_back (layout);
ee325b61
TT
834
835 return cmd;
416eb92d 836}
2192a9d3 837
416eb92d 838/* Initialize the standard layouts. */
2192a9d3 839
416eb92d
TT
840static void
841initialize_layouts ()
842{
843 tui_layout_split *layout;
844
845 layout = new tui_layout_split ();
846 layout->add_window ("src", 2);
847 layout->add_window ("status", 0);
848 layout->add_window ("cmd", 1);
849 add_layout_command ("src", layout);
850
851 layout = new tui_layout_split ();
852 layout->add_window ("asm", 2);
853 layout->add_window ("status", 0);
854 layout->add_window ("cmd", 1);
855 add_layout_command ("asm", layout);
856
857 layout = new tui_layout_split ();
858 layout->add_window ("src", 1);
859 layout->add_window ("asm", 1);
860 layout->add_window ("status", 0);
861 layout->add_window ("cmd", 1);
862 add_layout_command ("split", layout);
863
864 layout = new tui_layout_split ();
865 layout->add_window ("regs", 1);
866 layout->add_window ("src", 1);
867 layout->add_window ("status", 0);
868 layout->add_window ("cmd", 1);
869 layouts.emplace_back (layout);
870 src_regs_layout = layout;
871
872 layout = new tui_layout_split ();
873 layout->add_window ("regs", 1);
874 layout->add_window ("asm", 1);
875 layout->add_window ("status", 0);
876 layout->add_window ("cmd", 1);
877 layouts.emplace_back (layout);
878 asm_regs_layout = layout;
2192a9d3
TT
879}
880
389e7ddb
TT
881\f
882
ee325b61
TT
883/* A helper function that returns true if NAME is the name of an
884 available window. */
885
886static bool
887validate_window_name (const std::string &name)
888{
889 return (name == "src" || name == "cmd"
890 || name == "regs" || name == "asm"
891 || name == "status");
892}
893
894/* Implementation of the "tui new-layout" command. */
895
896static void
897tui_new_layout_command (const char *spec, int from_tty)
898{
899 std::string new_name = extract_arg (&spec);
900 if (new_name.empty ())
901 error (_("No layout name specified"));
902 if (new_name[0] == '-')
903 error (_("Layout name cannot start with '-'"));
904
7c043ba6
TT
905 bool is_vertical = true;
906 spec = skip_spaces (spec);
907 if (check_for_argument (&spec, "-horizontal"))
908 is_vertical = false;
909
c22fef7e 910 std::vector<std::unique_ptr<tui_layout_split>> splits;
7c043ba6 911 splits.emplace_back (new tui_layout_split (is_vertical));
ee325b61
TT
912 std::unordered_set<std::string> seen_windows;
913 while (true)
914 {
c22fef7e
TT
915 spec = skip_spaces (spec);
916 if (spec[0] == '\0')
ee325b61 917 break;
c22fef7e
TT
918
919 if (spec[0] == '{')
920 {
7c043ba6
TT
921 is_vertical = true;
922 spec = skip_spaces (spec + 1);
923 if (check_for_argument (&spec, "-horizontal"))
924 is_vertical = false;
925 splits.emplace_back (new tui_layout_split (is_vertical));
c22fef7e
TT
926 continue;
927 }
928
929 bool is_close = false;
930 std::string name;
931 if (spec[0] == '}')
932 {
933 is_close = true;
934 ++spec;
935 if (splits.size () == 1)
936 error (_("Extra '}' in layout specification"));
937 }
938 else
939 {
940 name = extract_arg (&spec);
941 if (name.empty ())
942 break;
943 if (!validate_window_name (name))
944 error (_("Unknown window \"%s\""), name.c_str ());
945 if (seen_windows.find (name) != seen_windows.end ())
946 error (_("Window \"%s\" seen twice in layout"), name.c_str ());
947 }
948
949 ULONGEST weight = get_ulongest (&spec, '}');
ee325b61
TT
950 if ((int) weight != weight)
951 error (_("Weight out of range: %s"), pulongest (weight));
c22fef7e
TT
952 if (is_close)
953 {
954 std::unique_ptr<tui_layout_split> last_split
955 = std::move (splits.back ());
956 splits.pop_back ();
957 splits.back ()->add_split (std::move (last_split), weight);
958 }
959 else
960 {
961 splits.back ()->add_window (name.c_str (), weight);
962 seen_windows.insert (name);
963 }
ee325b61 964 }
c22fef7e
TT
965 if (splits.size () > 1)
966 error (_("Missing '}' in layout specification"));
ee325b61
TT
967 if (seen_windows.empty ())
968 error (_("New layout does not contain any windows"));
969 if (seen_windows.find ("cmd") == seen_windows.end ())
970 error (_("New layout does not contain the \"cmd\" window"));
971
972 gdb::unique_xmalloc_ptr<char> cmd_name
973 = make_unique_xstrdup (new_name.c_str ());
c22fef7e 974 std::unique_ptr<tui_layout_split> new_layout = std::move (splits.back ());
ee325b61
TT
975 struct cmd_list_element *cmd
976 = add_layout_command (cmd_name.get (), new_layout.get ());
977 cmd->name_allocated = 1;
978 cmd_name.release ();
979 new_layout.release ();
980}
981
416eb92d
TT
982/* Base command for "layout". */
983
984static void
985tui_layout_command (const char *layout_name, int from_tty)
986{
987 help_list (layout_list, "layout ", all_commands, gdb_stdout);
988}
989
d9fcefd5
TT
990/* Function to initialize gdb commands, for tui window layout
991 manipulation. */
992
6c265988 993void _initialize_tui_layout ();
d9fcefd5 994void
6c265988 995_initialize_tui_layout ()
d9fcefd5 996{
416eb92d 997 add_prefix_cmd ("layout", class_tui, tui_layout_command, _("\
d9fcefd5 998Change the layout of windows.\n\
416eb92d
TT
999Usage: layout prev | next | LAYOUT-NAME"),
1000 &layout_list, "layout ", 0, &cmdlist);
1001
1002 add_cmd ("next", class_tui, tui_next_layout_command,
1003 _("Apply the next TUI layout"),
1004 &layout_list);
1005 add_cmd ("prev", class_tui, tui_prev_layout_command,
1006 _("Apply the previous TUI layout"),
1007 &layout_list);
1008 add_cmd ("regs", class_tui, tui_regs_layout_command,
1009 _("Apply the TUI register layout"),
1010 &layout_list);
2192a9d3 1011
ee325b61
TT
1012 add_cmd ("new-layout", class_tui, tui_new_layout_command,
1013 _("Create a new TUI layout.\n\
7c043ba6 1014Usage: tui new-layout [-horizontal] NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\
ee325b61
TT
1015Create a new TUI layout. The new layout will be named NAME,\n\
1016and can be accessed using \"layout NAME\".\n\
1017The windows will be displayed in the specified order.\n\
c22fef7e 1018A WINDOW can also be of the form:\n\
7c043ba6 1019 { [-horizontal] NAME WEIGHT [NAME WEIGHT]... }\n\
c22fef7e 1020This form indicates a sub-frame.\n\
ee325b61
TT
1021Each WEIGHT is an integer, which holds the relative size\n\
1022to be allocated to the window."),
1023 tui_get_cmd_list ());
1024
2192a9d3 1025 initialize_layouts ();
d9fcefd5 1026}
This page took 2.551846 seconds and 4 git commands to generate.