1 /* TUI layout window management.
3 Copyright (C) 1998-2020 Free Software Foundation, Inc.
5 Contributed by Hewlett-Packard Company.
7 This file is part of GDB.
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.
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.
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/>. */
23 #include "arch-utils.h"
28 #include "cli/cli-cmds.h"
29 #include "cli/cli-decode.h"
30 #include "cli/cli-utils.h"
32 #include <unordered_set>
35 #include "tui/tui-command.h"
36 #include "tui/tui-data.h"
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"
43 #include "tui/tui-layout.h"
44 #include "tui/tui-source.h"
45 #include "gdb_curses.h"
47 static void tui_layout_command (const char *, int);
48 static void extract_display_start_addr (struct gdbarch
**, CORE_ADDR
*);
51 static std::vector
<std::unique_ptr
<tui_layout_split
>> layouts
;
53 /* The layout that is currently applied. */
54 static std::unique_ptr
<tui_layout_base
> applied_layout
;
56 /* The "skeleton" version of the layout that is currently applied. */
57 static tui_layout_split
*applied_skeleton
;
59 /* The two special "regs" layouts. Note that these aren't registered
60 as commands and so can never be deleted. */
61 static tui_layout_split
*src_regs_layout
;
62 static tui_layout_split
*asm_regs_layout
;
64 /* See tui-layout.h. */
67 tui_apply_current_layout ()
69 applied_layout
->apply (0, 0, tui_term_width (), tui_term_height ());
75 tui_adjust_window_height (struct tui_win_info
*win
, int new_height
)
77 applied_layout
->adjust_size (win
->name (), new_height
);
80 /* Set the current layout to LAYOUT. */
83 tui_set_layout (tui_layout_split
*layout
)
85 struct gdbarch
*gdbarch
;
88 extract_display_start_addr (&gdbarch
, &addr
);
89 tui_make_all_invisible ();
90 applied_skeleton
= layout
;
91 applied_layout
= layout
->clone ();
92 tui_apply_current_layout ();
93 tui_delete_invisible_windows ();
95 if (gdbarch
== nullptr && TUI_DISASM_WIN
!= nullptr)
96 tui_get_begin_asm_address (&gdbarch
, &addr
);
97 tui_update_source_windows_with_addr (gdbarch
, addr
);
100 /* See tui-layout.h. */
103 tui_add_win_to_layout (enum tui_win_type type
)
105 gdb_assert (type
== SRC_WIN
|| type
== DISASSEM_WIN
);
107 /* If the window already exists, no need to add it. */
108 if (tui_win_list
[type
] != nullptr)
111 /* If the window we are trying to replace doesn't exist, we're
113 enum tui_win_type other
= type
== SRC_WIN
? DISASSEM_WIN
: SRC_WIN
;
114 if (tui_win_list
[other
] == nullptr)
117 const char *name
= type
== SRC_WIN
? SRC_NAME
: DISASSEM_NAME
;
118 applied_layout
->replace_window (tui_win_list
[other
]->name (), name
);
119 tui_apply_current_layout ();
120 tui_delete_invisible_windows ();
123 /* Find LAYOUT in the "layouts" global and return its index. */
126 find_layout (tui_layout_split
*layout
)
128 for (size_t i
= 0; i
< layouts
.size (); ++i
)
130 if (layout
== layouts
[i
].get ())
133 gdb_assert_not_reached (_("layout not found!?"));
136 /* Function to set the layout. */
139 tui_apply_layout (struct cmd_list_element
*command
,
140 const char *args
, int from_tty
)
142 tui_layout_split
*layout
143 = (tui_layout_split
*) get_cmd_context (command
);
145 /* Make sure the curses mode is enabled. */
147 tui_set_layout (layout
);
150 /* See tui-layout.h. */
155 size_t index
= find_layout (applied_skeleton
);
157 if (index
== layouts
.size ())
159 tui_set_layout (layouts
[index
].get ());
162 /* Implement the "layout next" command. */
165 tui_next_layout_command (const char *arg
, int from_tty
)
171 /* See tui-layout.h. */
174 tui_set_initial_layout ()
176 tui_set_layout (layouts
[0].get ());
179 /* Implement the "layout prev" command. */
182 tui_prev_layout_command (const char *arg
, int from_tty
)
185 size_t index
= find_layout (applied_skeleton
);
187 index
= layouts
.size ();
189 tui_set_layout (layouts
[index
].get ());
193 /* See tui-layout.h. */
198 /* If there's already a register window, we're done. */
199 if (TUI_DATA_WIN
!= nullptr)
202 tui_set_layout (TUI_DISASM_WIN
!= nullptr
207 /* Implement the "layout regs" command. */
210 tui_regs_layout_command (const char *arg
, int from_tty
)
216 /* See tui-layout.h. */
219 tui_remove_some_windows ()
221 tui_win_info
*focus
= tui_win_with_focus ();
223 if (strcmp (focus
->name (), "cmd") == 0)
225 /* Try leaving the source or disassembly window. If neither
226 exists, just do nothing. */
228 if (focus
== nullptr)
229 focus
= TUI_DISASM_WIN
;
230 if (focus
== nullptr)
234 applied_layout
->remove_windows (focus
->name ());
235 tui_apply_current_layout ();
239 extract_display_start_addr (struct gdbarch
**gdbarch_p
, CORE_ADDR
*addr_p
)
241 struct gdbarch
*gdbarch
= nullptr;
244 struct symtab_and_line cursal
= get_current_source_symtab_and_line ();
246 if (TUI_SRC_WIN
!= nullptr)
248 gdbarch
= TUI_SRC_WIN
->gdbarch
;
249 find_line_pc (cursal
.symtab
,
250 TUI_SRC_WIN
->start_line_or_addr
.u
.line_no
,
254 else if (TUI_DISASM_WIN
!= nullptr)
256 gdbarch
= TUI_DISASM_WIN
->gdbarch
;
257 addr
= TUI_DISASM_WIN
->start_line_or_addr
.u
.addr
;
260 *gdbarch_p
= gdbarch
;
265 tui_gen_win_info::resize (int height_
, int width_
,
266 int origin_x_
, int origin_y_
)
268 if (width
== width_
&& height
== height_
269 && x
== origin_x_
&& y
== origin_y_
270 && handle
!= nullptr)
278 if (handle
!= nullptr)
281 wresize (handle
.get (), height
, width
);
282 mvwin (handle
.get (), y
, x
);
283 wmove (handle
.get (), 0, 0);
285 handle
.reset (nullptr);
289 if (handle
== nullptr)
297 /* Helper function that returns a TUI window, given its name. */
299 static tui_gen_win_info
*
300 tui_get_window_by_name (const std::string
&name
)
304 if (tui_win_list
[SRC_WIN
] == nullptr)
305 tui_win_list
[SRC_WIN
] = new tui_source_window ();
306 return tui_win_list
[SRC_WIN
];
308 else if (name
== "cmd")
310 if (tui_win_list
[CMD_WIN
] == nullptr)
311 tui_win_list
[CMD_WIN
] = new tui_cmd_window ();
312 return tui_win_list
[CMD_WIN
];
314 else if (name
== "regs")
316 if (tui_win_list
[DATA_WIN
] == nullptr)
317 tui_win_list
[DATA_WIN
] = new tui_data_window ();
318 return tui_win_list
[DATA_WIN
];
320 else if (name
== "asm")
322 if (tui_win_list
[DISASSEM_WIN
] == nullptr)
323 tui_win_list
[DISASSEM_WIN
] = new tui_disasm_window ();
324 return tui_win_list
[DISASSEM_WIN
];
328 gdb_assert (name
== "status");
329 return tui_locator_win_info_ptr ();
333 /* See tui-layout.h. */
335 std::unique_ptr
<tui_layout_base
>
336 tui_layout_window::clone () const
338 tui_layout_window
*result
= new tui_layout_window (m_contents
.c_str ());
339 return std::unique_ptr
<tui_layout_base
> (result
);
342 /* See tui-layout.h. */
345 tui_layout_window::apply (int x_
, int y_
, int width_
, int height_
)
351 gdb_assert (m_window
!= nullptr);
352 m_window
->resize (height
, width
, x
, y
);
355 /* See tui-layout.h. */
358 tui_layout_window::get_sizes (int *min_height
, int *max_height
)
360 if (m_window
== nullptr)
361 m_window
= tui_get_window_by_name (m_contents
);
362 *min_height
= m_window
->min_height ();
363 *max_height
= m_window
->max_height ();
366 /* See tui-layout.h. */
369 tui_layout_window::top_boxed_p () const
371 gdb_assert (m_window
!= nullptr);
372 return m_window
->can_box ();
375 /* See tui-layout.h. */
378 tui_layout_window::bottom_boxed_p () const
380 gdb_assert (m_window
!= nullptr);
381 return m_window
->can_box ();
384 /* See tui-layout.h. */
387 tui_layout_window::replace_window (const char *name
, const char *new_window
)
389 if (m_contents
== name
)
391 m_contents
= new_window
;
392 if (m_window
!= nullptr)
394 m_window
->make_visible (false);
395 m_window
= tui_get_window_by_name (m_contents
);
400 /* See tui-layout.h. */
403 tui_layout_window::specification (ui_file
*output
, int depth
)
405 fputs_unfiltered (get_name (), output
);
408 /* See tui-layout.h. */
411 tui_layout_split::add_split (std::unique_ptr
<tui_layout_split
> &&layout
,
414 split s
= {weight
, std::move (layout
)};
415 m_splits
.push_back (std::move (s
));
418 /* See tui-layout.h. */
421 tui_layout_split::add_window (const char *name
, int weight
)
423 tui_layout_window
*result
= new tui_layout_window (name
);
424 split s
= {weight
, std::unique_ptr
<tui_layout_base
> (result
)};
425 m_splits
.push_back (std::move (s
));
428 /* See tui-layout.h. */
430 std::unique_ptr
<tui_layout_base
>
431 tui_layout_split::clone () const
433 tui_layout_split
*result
= new tui_layout_split ();
434 for (const split
&item
: m_splits
)
436 std::unique_ptr
<tui_layout_base
> next
= item
.layout
->clone ();
437 split s
= {item
.weight
, std::move (next
)};
438 result
->m_splits
.push_back (std::move (s
));
440 return std::unique_ptr
<tui_layout_base
> (result
);
443 /* See tui-layout.h. */
446 tui_layout_split::get_sizes (int *min_height
, int *max_height
)
450 for (const split
&item
: m_splits
)
452 int new_min
, new_max
;
453 item
.layout
->get_sizes (&new_min
, &new_max
);
454 *min_height
+= new_min
;
455 *max_height
+= new_max
;
459 /* See tui-layout.h. */
462 tui_layout_split::top_boxed_p () const
464 if (m_splits
.empty ())
466 return m_splits
[0].layout
->top_boxed_p ();
469 /* See tui-layout.h. */
472 tui_layout_split::bottom_boxed_p () const
474 if (m_splits
.empty ())
476 return m_splits
.back ().layout
->top_boxed_p ();
479 /* See tui-layout.h. */
482 tui_layout_split::set_weights_from_heights ()
484 for (int i
= 0; i
< m_splits
.size (); ++i
)
485 m_splits
[i
].weight
= m_splits
[i
].layout
->height
;
488 /* See tui-layout.h. */
491 tui_layout_split::adjust_size (const char *name
, int new_height
)
493 /* Look through the children. If one is a layout holding the named
494 window, we're done; or if one actually is the named window,
496 int found_index
= -1;
497 for (int i
= 0; i
< m_splits
.size (); ++i
)
499 tui_adjust_result adjusted
500 = m_splits
[i
].layout
->adjust_size (name
, new_height
);
501 if (adjusted
== HANDLED
)
503 if (adjusted
== FOUND
)
510 if (found_index
== -1)
512 if (m_splits
[found_index
].layout
->height
== new_height
)
515 set_weights_from_heights ();
516 int delta
= m_splits
[found_index
].weight
- new_height
;
517 m_splits
[found_index
].weight
= new_height
;
519 /* Distribute the "delta" over the next window; but if the next
520 window cannot hold it all, keep going until we either find a
521 window that does, or until we loop all the way around. */
522 for (int i
= 0; delta
!= 0 && i
< m_splits
.size () - 1; ++i
)
524 int index
= (found_index
+ 1 + i
) % m_splits
.size ();
526 int new_min
, new_max
;
527 m_splits
[index
].layout
->get_sizes (&new_min
, &new_max
);
531 /* The primary window grew, so we are trying to shrink other
533 int available
= m_splits
[index
].weight
- new_min
;
534 int shrink_by
= std::min (available
, -delta
);
535 m_splits
[index
].weight
-= shrink_by
;
540 /* The primary window shrank, so we are trying to grow other
542 int available
= new_max
- m_splits
[index
].weight
;
543 int grow_by
= std::min (available
, delta
);
544 m_splits
[index
].weight
+= grow_by
;
551 warning (_("Invalid window height specified"));
552 /* Effectively undo any modifications made here. */
553 set_weights_from_heights ();
557 /* Simply re-apply the updated layout. */
558 apply (x
, y
, width
, height
);
564 /* See tui-layout.h. */
567 tui_layout_split::apply (int x_
, int y_
, int width_
, int height_
)
579 /* True if this window will share a box border with the previous
580 window in the list. */
584 std::vector
<height_info
> info (m_splits
.size ());
586 /* Step 1: Find the min and max height of each sub-layout.
587 Fixed-sized layouts are given their desired height, and then the
588 remaining space is distributed among the remaining windows
589 according to the weights given. */
590 int available_height
= height
;
592 int total_weight
= 0;
593 for (int i
= 0; i
< m_splits
.size (); ++i
)
595 bool cmd_win_already_exists
= TUI_CMD_WIN
!= nullptr;
597 /* Always call get_sizes, to ensure that the window is
598 instantiated. This is a bit gross but less gross than adding
599 special cases for this in other places. */
600 m_splits
[i
].layout
->get_sizes (&info
[i
].min_height
, &info
[i
].max_height
);
603 && cmd_win_already_exists
604 && m_splits
[i
].layout
->get_name () != nullptr
605 && strcmp (m_splits
[i
].layout
->get_name (), "cmd") == 0)
607 /* If this layout has never been applied, then it means the
608 user just changed the layout. In this situation, it's
609 desirable to keep the size of the command window the
610 same. Setting the min and max heights this way ensures
611 that the resizing step, below, does the right thing with
613 info
[i
].min_height
= TUI_CMD_WIN
->height
;
614 info
[i
].max_height
= TUI_CMD_WIN
->height
;
617 if (info
[i
].min_height
== info
[i
].max_height
)
618 available_height
-= info
[i
].min_height
;
622 total_weight
+= m_splits
[i
].weight
;
625 /* Two adjacent boxed windows will share a border, making a bit
626 more height available. */
628 && m_splits
[i
- 1].layout
->bottom_boxed_p ()
629 && m_splits
[i
].layout
->top_boxed_p ())
630 info
[i
].share_box
= true;
633 /* Step 2: Compute the height of each sub-layout. Fixed-sized items
634 are given their fixed size, while others are resized according to
637 for (int i
= 0; i
< m_splits
.size (); ++i
)
639 /* Compute the height and clamp to the allowable range. */
640 info
[i
].height
= available_height
* m_splits
[i
].weight
/ total_weight
;
641 if (info
[i
].height
> info
[i
].max_height
)
642 info
[i
].height
= info
[i
].max_height
;
643 if (info
[i
].height
< info
[i
].min_height
)
644 info
[i
].height
= info
[i
].min_height
;
645 /* If there is any leftover height, just redistribute it to the
646 last resizeable window, by dropping it from the allocated
647 height. We could try to be fancier here perhaps, by
648 redistributing this height among all windows, not just the
650 if (info
[i
].min_height
!= info
[i
].max_height
)
652 used_height
+= info
[i
].height
;
653 if (info
[i
].share_box
)
658 /* Allocate any leftover height. */
659 if (available_height
>= used_height
&& last_index
!= -1)
660 info
[last_index
].height
+= available_height
- used_height
;
662 /* Step 3: Resize. */
663 int height_accum
= 0;
664 for (int i
= 0; i
< m_splits
.size (); ++i
)
666 /* If we fall off the bottom, just make allocations overlap.
668 if (height_accum
+ info
[i
].height
> height
)
669 height_accum
= height
- info
[i
].height
;
670 else if (info
[i
].share_box
)
672 m_splits
[i
].layout
->apply (x
, y
+ height_accum
, width
, info
[i
].height
);
673 height_accum
+= info
[i
].height
;
679 /* See tui-layout.h. */
682 tui_layout_split::remove_windows (const char *name
)
684 for (int i
= 0; i
< m_splits
.size (); ++i
)
686 const char *this_name
= m_splits
[i
].layout
->get_name ();
687 if (this_name
== nullptr)
688 m_splits
[i
].layout
->remove_windows (name
);
691 if (strcmp (this_name
, name
) == 0
692 || strcmp (this_name
, "cmd") == 0)
696 m_splits
.erase (m_splits
.begin () + i
);
702 /* See tui-layout.h. */
705 tui_layout_split::replace_window (const char *name
, const char *new_window
)
707 for (auto &item
: m_splits
)
708 item
.layout
->replace_window (name
, new_window
);
711 /* See tui-layout.h. */
714 tui_layout_split::specification (ui_file
*output
, int depth
)
717 fputs_unfiltered ("{", output
);
720 for (auto &item
: m_splits
)
723 fputs_unfiltered (" ", output
);
725 item
.layout
->specification (output
, depth
+ 1);
726 fprintf_unfiltered (output
, " %d", item
.weight
);
730 fputs_unfiltered ("}", output
);
733 /* Destroy the layout associated with SELF. */
736 destroy_layout (struct cmd_list_element
*self
, void *context
)
738 tui_layout_split
*layout
= (tui_layout_split
*) context
;
739 size_t index
= find_layout (layout
);
740 layouts
.erase (layouts
.begin () + index
);
743 /* List holding the sub-commands of "layout". */
745 static struct cmd_list_element
*layout_list
;
747 /* Add a "layout" command with name NAME that switches to LAYOUT. */
749 static struct cmd_list_element
*
750 add_layout_command (const char *name
, tui_layout_split
*layout
)
752 struct cmd_list_element
*cmd
;
755 layout
->specification (&spec
, 0);
757 gdb::unique_xmalloc_ptr
<char> doc
758 (xstrprintf (_("Apply the \"%s\" layout.\n\
759 This layout was created using:\n\
760 tui new-layout %s %s"),
761 name
, name
, spec
.c_str ()));
763 cmd
= add_cmd (name
, class_tui
, nullptr, doc
.get (), &layout_list
);
764 set_cmd_context (cmd
, layout
);
765 /* There is no API to set this. */
766 cmd
->func
= tui_apply_layout
;
767 cmd
->destroyer
= destroy_layout
;
768 cmd
->doc_allocated
= 1;
770 layouts
.emplace_back (layout
);
775 /* Initialize the standard layouts. */
778 initialize_layouts ()
780 tui_layout_split
*layout
;
782 layout
= new tui_layout_split ();
783 layout
->add_window ("src", 2);
784 layout
->add_window ("status", 0);
785 layout
->add_window ("cmd", 1);
786 add_layout_command ("src", layout
);
788 layout
= new tui_layout_split ();
789 layout
->add_window ("asm", 2);
790 layout
->add_window ("status", 0);
791 layout
->add_window ("cmd", 1);
792 add_layout_command ("asm", layout
);
794 layout
= new tui_layout_split ();
795 layout
->add_window ("src", 1);
796 layout
->add_window ("asm", 1);
797 layout
->add_window ("status", 0);
798 layout
->add_window ("cmd", 1);
799 add_layout_command ("split", layout
);
801 layout
= new tui_layout_split ();
802 layout
->add_window ("regs", 1);
803 layout
->add_window ("src", 1);
804 layout
->add_window ("status", 0);
805 layout
->add_window ("cmd", 1);
806 layouts
.emplace_back (layout
);
807 src_regs_layout
= layout
;
809 layout
= new tui_layout_split ();
810 layout
->add_window ("regs", 1);
811 layout
->add_window ("asm", 1);
812 layout
->add_window ("status", 0);
813 layout
->add_window ("cmd", 1);
814 layouts
.emplace_back (layout
);
815 asm_regs_layout
= layout
;
820 /* A helper function that returns true if NAME is the name of an
824 validate_window_name (const std::string
&name
)
826 return (name
== "src" || name
== "cmd"
827 || name
== "regs" || name
== "asm"
828 || name
== "status");
831 /* Implementation of the "tui new-layout" command. */
834 tui_new_layout_command (const char *spec
, int from_tty
)
836 std::string new_name
= extract_arg (&spec
);
837 if (new_name
.empty ())
838 error (_("No layout name specified"));
839 if (new_name
[0] == '-')
840 error (_("Layout name cannot start with '-'"));
842 std::vector
<std::unique_ptr
<tui_layout_split
>> splits
;
843 splits
.emplace_back (new tui_layout_split
);
844 std::unordered_set
<std::string
> seen_windows
;
847 spec
= skip_spaces (spec
);
853 splits
.emplace_back (new tui_layout_split
);
858 bool is_close
= false;
864 if (splits
.size () == 1)
865 error (_("Extra '}' in layout specification"));
869 name
= extract_arg (&spec
);
872 if (!validate_window_name (name
))
873 error (_("Unknown window \"%s\""), name
.c_str ());
874 if (seen_windows
.find (name
) != seen_windows
.end ())
875 error (_("Window \"%s\" seen twice in layout"), name
.c_str ());
878 ULONGEST weight
= get_ulongest (&spec
, '}');
879 if ((int) weight
!= weight
)
880 error (_("Weight out of range: %s"), pulongest (weight
));
883 std::unique_ptr
<tui_layout_split
> last_split
884 = std::move (splits
.back ());
886 splits
.back ()->add_split (std::move (last_split
), weight
);
890 splits
.back ()->add_window (name
.c_str (), weight
);
891 seen_windows
.insert (name
);
894 if (splits
.size () > 1)
895 error (_("Missing '}' in layout specification"));
896 if (seen_windows
.empty ())
897 error (_("New layout does not contain any windows"));
898 if (seen_windows
.find ("cmd") == seen_windows
.end ())
899 error (_("New layout does not contain the \"cmd\" window"));
901 gdb::unique_xmalloc_ptr
<char> cmd_name
902 = make_unique_xstrdup (new_name
.c_str ());
903 std::unique_ptr
<tui_layout_split
> new_layout
= std::move (splits
.back ());
904 struct cmd_list_element
*cmd
905 = add_layout_command (cmd_name
.get (), new_layout
.get ());
906 cmd
->name_allocated
= 1;
908 new_layout
.release ();
911 /* Base command for "layout". */
914 tui_layout_command (const char *layout_name
, int from_tty
)
916 help_list (layout_list
, "layout ", all_commands
, gdb_stdout
);
919 /* Function to initialize gdb commands, for tui window layout
922 void _initialize_tui_layout ();
924 _initialize_tui_layout ()
926 add_prefix_cmd ("layout", class_tui
, tui_layout_command
, _("\
927 Change the layout of windows.\n\
928 Usage: layout prev | next | LAYOUT-NAME"),
929 &layout_list
, "layout ", 0, &cmdlist
);
931 add_cmd ("next", class_tui
, tui_next_layout_command
,
932 _("Apply the next TUI layout"),
934 add_cmd ("prev", class_tui
, tui_prev_layout_command
,
935 _("Apply the previous TUI layout"),
937 add_cmd ("regs", class_tui
, tui_regs_layout_command
,
938 _("Apply the TUI register layout"),
941 add_cmd ("new-layout", class_tui
, tui_new_layout_command
,
942 _("Create a new TUI layout.\n\
943 Usage: tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\
944 Create a new TUI layout. The new layout will be named NAME,\n\
945 and can be accessed using \"layout NAME\".\n\
946 The windows will be displayed in the specified order.\n\
947 A WINDOW can also be of the form:\n\
948 { NAME WEIGHT [NAME WEIGHT]... }\n\
949 This form indicates a sub-frame.\n\
950 Each WEIGHT is an integer, which holds the relative size\n\
951 to be allocated to the window."),
952 tui_get_cmd_list ());
954 initialize_layouts ();