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
;
65 std::vector
<tui_win_info
*> tui_windows
;
67 /* See tui-layout.h. */
70 tui_apply_current_layout ()
73 applied_layout
->apply (0, 0, tui_term_width (), tui_term_height ());
79 tui_adjust_window_height (struct tui_win_info
*win
, int new_height
)
81 applied_layout
->adjust_size (win
->name (), new_height
);
84 /* Set the current layout to LAYOUT. */
87 tui_set_layout (tui_layout_split
*layout
)
89 struct gdbarch
*gdbarch
;
92 extract_display_start_addr (&gdbarch
, &addr
);
93 tui_make_all_invisible ();
94 applied_skeleton
= layout
;
95 applied_layout
= layout
->clone ();
96 tui_apply_current_layout ();
97 tui_delete_invisible_windows ();
99 if (gdbarch
== nullptr && TUI_DISASM_WIN
!= nullptr)
100 tui_get_begin_asm_address (&gdbarch
, &addr
);
101 tui_update_source_windows_with_addr (gdbarch
, addr
);
104 /* See tui-layout.h. */
107 tui_add_win_to_layout (enum tui_win_type type
)
109 gdb_assert (type
== SRC_WIN
|| type
== DISASSEM_WIN
);
111 /* If the window already exists, no need to add it. */
112 if (tui_win_list
[type
] != nullptr)
115 /* If the window we are trying to replace doesn't exist, we're
117 enum tui_win_type other
= type
== SRC_WIN
? DISASSEM_WIN
: SRC_WIN
;
118 if (tui_win_list
[other
] == nullptr)
121 const char *name
= type
== SRC_WIN
? SRC_NAME
: DISASSEM_NAME
;
122 applied_layout
->replace_window (tui_win_list
[other
]->name (), name
);
123 tui_apply_current_layout ();
124 tui_delete_invisible_windows ();
127 /* Find LAYOUT in the "layouts" global and return its index. */
130 find_layout (tui_layout_split
*layout
)
132 for (size_t i
= 0; i
< layouts
.size (); ++i
)
134 if (layout
== layouts
[i
].get ())
137 gdb_assert_not_reached (_("layout not found!?"));
140 /* Function to set the layout. */
143 tui_apply_layout (struct cmd_list_element
*command
,
144 const char *args
, int from_tty
)
146 tui_layout_split
*layout
147 = (tui_layout_split
*) get_cmd_context (command
);
149 /* Make sure the curses mode is enabled. */
151 tui_set_layout (layout
);
154 /* See tui-layout.h. */
159 size_t index
= find_layout (applied_skeleton
);
161 if (index
== layouts
.size ())
163 tui_set_layout (layouts
[index
].get ());
166 /* Implement the "layout next" command. */
169 tui_next_layout_command (const char *arg
, int from_tty
)
175 /* See tui-layout.h. */
178 tui_set_initial_layout ()
180 tui_set_layout (layouts
[0].get ());
183 /* Implement the "layout prev" command. */
186 tui_prev_layout_command (const char *arg
, int from_tty
)
189 size_t index
= find_layout (applied_skeleton
);
191 index
= layouts
.size ();
193 tui_set_layout (layouts
[index
].get ());
197 /* See tui-layout.h. */
202 /* If there's already a register window, we're done. */
203 if (TUI_DATA_WIN
!= nullptr)
206 tui_set_layout (TUI_DISASM_WIN
!= nullptr
211 /* Implement the "layout regs" command. */
214 tui_regs_layout_command (const char *arg
, int from_tty
)
220 /* See tui-layout.h. */
223 tui_remove_some_windows ()
225 tui_win_info
*focus
= tui_win_with_focus ();
227 if (strcmp (focus
->name (), "cmd") == 0)
229 /* Try leaving the source or disassembly window. If neither
230 exists, just do nothing. */
232 if (focus
== nullptr)
233 focus
= TUI_DISASM_WIN
;
234 if (focus
== nullptr)
238 applied_layout
->remove_windows (focus
->name ());
239 tui_apply_current_layout ();
243 extract_display_start_addr (struct gdbarch
**gdbarch_p
, CORE_ADDR
*addr_p
)
245 struct gdbarch
*gdbarch
= nullptr;
248 struct symtab_and_line cursal
= get_current_source_symtab_and_line ();
250 if (TUI_SRC_WIN
!= nullptr)
252 gdbarch
= TUI_SRC_WIN
->gdbarch
;
253 find_line_pc (cursal
.symtab
,
254 TUI_SRC_WIN
->start_line_or_addr
.u
.line_no
,
258 else if (TUI_DISASM_WIN
!= nullptr)
260 gdbarch
= TUI_DISASM_WIN
->gdbarch
;
261 addr
= TUI_DISASM_WIN
->start_line_or_addr
.u
.addr
;
264 *gdbarch_p
= gdbarch
;
269 tui_gen_win_info::resize (int height_
, int width_
,
270 int origin_x_
, int origin_y_
)
272 if (width
== width_
&& height
== height_
273 && x
== origin_x_
&& y
== origin_y_
274 && handle
!= nullptr)
282 if (handle
!= nullptr)
285 wresize (handle
.get (), height
, width
);
286 mvwin (handle
.get (), y
, x
);
287 wmove (handle
.get (), 0, 0);
289 handle
.reset (nullptr);
293 if (handle
== nullptr)
301 /* Helper function that returns a TUI window, given its name. */
303 static tui_gen_win_info
*
304 tui_get_window_by_name (const std::string
&name
)
308 if (tui_win_list
[SRC_WIN
] == nullptr)
309 tui_win_list
[SRC_WIN
] = new tui_source_window ();
310 return tui_win_list
[SRC_WIN
];
312 else if (name
== "cmd")
314 if (tui_win_list
[CMD_WIN
] == nullptr)
315 tui_win_list
[CMD_WIN
] = new tui_cmd_window ();
316 return tui_win_list
[CMD_WIN
];
318 else if (name
== "regs")
320 if (tui_win_list
[DATA_WIN
] == nullptr)
321 tui_win_list
[DATA_WIN
] = new tui_data_window ();
322 return tui_win_list
[DATA_WIN
];
324 else if (name
== "asm")
326 if (tui_win_list
[DISASSEM_WIN
] == nullptr)
327 tui_win_list
[DISASSEM_WIN
] = new tui_disasm_window ();
328 return tui_win_list
[DISASSEM_WIN
];
332 gdb_assert (name
== "status");
333 return tui_locator_win_info_ptr ();
337 /* See tui-layout.h. */
339 std::unique_ptr
<tui_layout_base
>
340 tui_layout_window::clone () const
342 tui_layout_window
*result
= new tui_layout_window (m_contents
.c_str ());
343 return std::unique_ptr
<tui_layout_base
> (result
);
346 /* See tui-layout.h. */
349 tui_layout_window::apply (int x_
, int y_
, int width_
, int height_
)
355 gdb_assert (m_window
!= nullptr);
356 m_window
->resize (height
, width
, x
, y
);
357 if (dynamic_cast<tui_win_info
*> (m_window
) != nullptr)
358 tui_windows
.push_back ((tui_win_info
*) m_window
);
361 /* See tui-layout.h. */
364 tui_layout_window::get_sizes (bool height
, int *min_value
, int *max_value
)
366 if (m_window
== nullptr)
367 m_window
= tui_get_window_by_name (m_contents
);
370 *min_value
= m_window
->min_height ();
371 *max_value
= m_window
->max_height ();
375 *min_value
= m_window
->min_width ();
376 *max_value
= m_window
->max_width ();
380 /* See tui-layout.h. */
383 tui_layout_window::top_boxed_p () const
385 gdb_assert (m_window
!= nullptr);
386 return m_window
->can_box ();
389 /* See tui-layout.h. */
392 tui_layout_window::bottom_boxed_p () const
394 gdb_assert (m_window
!= nullptr);
395 return m_window
->can_box ();
398 /* See tui-layout.h. */
401 tui_layout_window::replace_window (const char *name
, const char *new_window
)
403 if (m_contents
== name
)
405 m_contents
= new_window
;
406 if (m_window
!= nullptr)
408 m_window
->make_visible (false);
409 m_window
= tui_get_window_by_name (m_contents
);
414 /* See tui-layout.h. */
417 tui_layout_window::specification (ui_file
*output
, int depth
)
419 fputs_unfiltered (get_name (), output
);
422 /* See tui-layout.h. */
425 tui_layout_split::add_split (std::unique_ptr
<tui_layout_split
> &&layout
,
428 split s
= {weight
, std::move (layout
)};
429 m_splits
.push_back (std::move (s
));
432 /* See tui-layout.h. */
435 tui_layout_split::add_window (const char *name
, int weight
)
437 tui_layout_window
*result
= new tui_layout_window (name
);
438 split s
= {weight
, std::unique_ptr
<tui_layout_base
> (result
)};
439 m_splits
.push_back (std::move (s
));
442 /* See tui-layout.h. */
444 std::unique_ptr
<tui_layout_base
>
445 tui_layout_split::clone () const
447 tui_layout_split
*result
= new tui_layout_split (m_vertical
);
448 for (const split
&item
: m_splits
)
450 std::unique_ptr
<tui_layout_base
> next
= item
.layout
->clone ();
451 split s
= {item
.weight
, std::move (next
)};
452 result
->m_splits
.push_back (std::move (s
));
454 return std::unique_ptr
<tui_layout_base
> (result
);
457 /* See tui-layout.h. */
460 tui_layout_split::get_sizes (bool height
, int *min_value
, int *max_value
)
464 bool first_time
= true;
465 for (const split
&item
: m_splits
)
467 int new_min
, new_max
;
468 item
.layout
->get_sizes (height
, &new_min
, &new_max
);
469 /* For the mismatch case, the first time through we want to set
470 the min and max to the computed values -- the "first_time"
471 check here is just a funny way of doing that. */
472 if (height
== m_vertical
|| first_time
)
474 *min_value
+= new_min
;
475 *max_value
+= new_max
;
479 *min_value
= std::max (*min_value
, new_min
);
480 *max_value
= std::min (*max_value
, new_max
);
486 /* See tui-layout.h. */
489 tui_layout_split::top_boxed_p () const
491 if (m_splits
.empty ())
493 return m_splits
[0].layout
->top_boxed_p ();
496 /* See tui-layout.h. */
499 tui_layout_split::bottom_boxed_p () const
501 if (m_splits
.empty ())
503 return m_splits
.back ().layout
->top_boxed_p ();
506 /* See tui-layout.h. */
509 tui_layout_split::set_weights_from_heights ()
511 for (int i
= 0; i
< m_splits
.size (); ++i
)
512 m_splits
[i
].weight
= m_splits
[i
].layout
->height
;
515 /* See tui-layout.h. */
518 tui_layout_split::adjust_size (const char *name
, int new_height
)
520 /* Look through the children. If one is a layout holding the named
521 window, we're done; or if one actually is the named window,
523 int found_index
= -1;
524 for (int i
= 0; i
< m_splits
.size (); ++i
)
526 tui_adjust_result adjusted
527 = m_splits
[i
].layout
->adjust_size (name
, new_height
);
528 if (adjusted
== HANDLED
)
530 if (adjusted
== FOUND
)
539 if (found_index
== -1)
541 if (m_splits
[found_index
].layout
->height
== new_height
)
544 set_weights_from_heights ();
545 int delta
= m_splits
[found_index
].weight
- new_height
;
546 m_splits
[found_index
].weight
= new_height
;
548 /* Distribute the "delta" over the next window; but if the next
549 window cannot hold it all, keep going until we either find a
550 window that does, or until we loop all the way around. */
551 for (int i
= 0; delta
!= 0 && i
< m_splits
.size () - 1; ++i
)
553 int index
= (found_index
+ 1 + i
) % m_splits
.size ();
555 int new_min
, new_max
;
556 m_splits
[index
].layout
->get_sizes (m_vertical
, &new_min
, &new_max
);
560 /* The primary window grew, so we are trying to shrink other
562 int available
= m_splits
[index
].weight
- new_min
;
563 int shrink_by
= std::min (available
, -delta
);
564 m_splits
[index
].weight
-= shrink_by
;
569 /* The primary window shrank, so we are trying to grow other
571 int available
= new_max
- m_splits
[index
].weight
;
572 int grow_by
= std::min (available
, delta
);
573 m_splits
[index
].weight
+= grow_by
;
580 warning (_("Invalid window height specified"));
581 /* Effectively undo any modifications made here. */
582 set_weights_from_heights ();
586 /* Simply re-apply the updated layout. */
587 apply (x
, y
, width
, height
);
593 /* See tui-layout.h. */
596 tui_layout_split::apply (int x_
, int y_
, int width_
, int height_
)
608 /* True if this window will share a box border with the previous
609 window in the list. */
613 std::vector
<size_info
> info (m_splits
.size ());
615 /* Step 1: Find the min and max size of each sub-layout.
616 Fixed-sized layouts are given their desired size, and then the
617 remaining space is distributed among the remaining windows
618 according to the weights given. */
619 int available_size
= m_vertical
? height
: width
;
621 int total_weight
= 0;
622 for (int i
= 0; i
< m_splits
.size (); ++i
)
624 bool cmd_win_already_exists
= TUI_CMD_WIN
!= nullptr;
626 /* Always call get_sizes, to ensure that the window is
627 instantiated. This is a bit gross but less gross than adding
628 special cases for this in other places. */
629 m_splits
[i
].layout
->get_sizes (m_vertical
, &info
[i
].min_size
,
633 && cmd_win_already_exists
634 && m_splits
[i
].layout
->get_name () != nullptr
635 && strcmp (m_splits
[i
].layout
->get_name (), "cmd") == 0)
637 /* If this layout has never been applied, then it means the
638 user just changed the layout. In this situation, it's
639 desirable to keep the size of the command window the
640 same. Setting the min and max sizes this way ensures
641 that the resizing step, below, does the right thing with
643 info
[i
].min_size
= (m_vertical
644 ? TUI_CMD_WIN
->height
645 : TUI_CMD_WIN
->width
);
646 info
[i
].max_size
= info
[i
].min_size
;
649 if (info
[i
].min_size
== info
[i
].max_size
)
650 available_size
-= info
[i
].min_size
;
654 total_weight
+= m_splits
[i
].weight
;
657 /* Two adjacent boxed windows will share a border, making a bit
658 more size available. */
660 && m_splits
[i
- 1].layout
->bottom_boxed_p ()
661 && m_splits
[i
].layout
->top_boxed_p ())
662 info
[i
].share_box
= true;
665 /* Step 2: Compute the size of each sub-layout. Fixed-sized items
666 are given their fixed size, while others are resized according to
669 for (int i
= 0; i
< m_splits
.size (); ++i
)
671 /* Compute the height and clamp to the allowable range. */
672 info
[i
].size
= available_size
* m_splits
[i
].weight
/ total_weight
;
673 if (info
[i
].size
> info
[i
].max_size
)
674 info
[i
].size
= info
[i
].max_size
;
675 if (info
[i
].size
< info
[i
].min_size
)
676 info
[i
].size
= info
[i
].min_size
;
677 /* If there is any leftover size, just redistribute it to the
678 last resizeable window, by dropping it from the allocated
679 size. We could try to be fancier here perhaps, by
680 redistributing this size among all windows, not just the
682 if (info
[i
].min_size
!= info
[i
].max_size
)
684 used_size
+= info
[i
].size
;
685 if (info
[i
].share_box
)
690 /* Allocate any leftover size. */
691 if (available_size
>= used_size
&& last_index
!= -1)
692 info
[last_index
].size
+= available_size
- used_size
;
694 /* Step 3: Resize. */
696 const int maximum
= m_vertical
? height
: width
;
697 for (int i
= 0; i
< m_splits
.size (); ++i
)
699 /* If we fall off the bottom, just make allocations overlap.
701 if (size_accum
+ info
[i
].size
> maximum
)
702 size_accum
= maximum
- info
[i
].size
;
703 else if (info
[i
].share_box
)
706 m_splits
[i
].layout
->apply (x
, y
+ size_accum
, width
, info
[i
].size
);
708 m_splits
[i
].layout
->apply (x
+ size_accum
, y
, info
[i
].size
, height
);
709 size_accum
+= info
[i
].size
;
715 /* See tui-layout.h. */
718 tui_layout_split::remove_windows (const char *name
)
720 for (int i
= 0; i
< m_splits
.size (); ++i
)
722 const char *this_name
= m_splits
[i
].layout
->get_name ();
723 if (this_name
== nullptr)
724 m_splits
[i
].layout
->remove_windows (name
);
727 if (strcmp (this_name
, name
) == 0
728 || strcmp (this_name
, "cmd") == 0)
732 m_splits
.erase (m_splits
.begin () + i
);
738 /* See tui-layout.h. */
741 tui_layout_split::replace_window (const char *name
, const char *new_window
)
743 for (auto &item
: m_splits
)
744 item
.layout
->replace_window (name
, new_window
);
747 /* See tui-layout.h. */
750 tui_layout_split::specification (ui_file
*output
, int depth
)
753 fputs_unfiltered ("{", output
);
756 fputs_unfiltered ("-horizontal ", output
);
759 for (auto &item
: m_splits
)
762 fputs_unfiltered (" ", output
);
764 item
.layout
->specification (output
, depth
+ 1);
765 fprintf_unfiltered (output
, " %d", item
.weight
);
769 fputs_unfiltered ("}", output
);
772 /* Destroy the layout associated with SELF. */
775 destroy_layout (struct cmd_list_element
*self
, void *context
)
777 tui_layout_split
*layout
= (tui_layout_split
*) context
;
778 size_t index
= find_layout (layout
);
779 layouts
.erase (layouts
.begin () + index
);
782 /* List holding the sub-commands of "layout". */
784 static struct cmd_list_element
*layout_list
;
786 /* Add a "layout" command with name NAME that switches to LAYOUT. */
788 static struct cmd_list_element
*
789 add_layout_command (const char *name
, tui_layout_split
*layout
)
791 struct cmd_list_element
*cmd
;
794 layout
->specification (&spec
, 0);
796 gdb::unique_xmalloc_ptr
<char> doc
797 (xstrprintf (_("Apply the \"%s\" layout.\n\
798 This layout was created using:\n\
799 tui new-layout %s %s"),
800 name
, name
, spec
.c_str ()));
802 cmd
= add_cmd (name
, class_tui
, nullptr, doc
.get (), &layout_list
);
803 set_cmd_context (cmd
, layout
);
804 /* There is no API to set this. */
805 cmd
->func
= tui_apply_layout
;
806 cmd
->destroyer
= destroy_layout
;
807 cmd
->doc_allocated
= 1;
809 layouts
.emplace_back (layout
);
814 /* Initialize the standard layouts. */
817 initialize_layouts ()
819 tui_layout_split
*layout
;
821 layout
= new tui_layout_split ();
822 layout
->add_window ("src", 2);
823 layout
->add_window ("status", 0);
824 layout
->add_window ("cmd", 1);
825 add_layout_command ("src", layout
);
827 layout
= new tui_layout_split ();
828 layout
->add_window ("asm", 2);
829 layout
->add_window ("status", 0);
830 layout
->add_window ("cmd", 1);
831 add_layout_command ("asm", layout
);
833 layout
= new tui_layout_split ();
834 layout
->add_window ("src", 1);
835 layout
->add_window ("asm", 1);
836 layout
->add_window ("status", 0);
837 layout
->add_window ("cmd", 1);
838 add_layout_command ("split", layout
);
840 layout
= new tui_layout_split ();
841 layout
->add_window ("regs", 1);
842 layout
->add_window ("src", 1);
843 layout
->add_window ("status", 0);
844 layout
->add_window ("cmd", 1);
845 layouts
.emplace_back (layout
);
846 src_regs_layout
= layout
;
848 layout
= new tui_layout_split ();
849 layout
->add_window ("regs", 1);
850 layout
->add_window ("asm", 1);
851 layout
->add_window ("status", 0);
852 layout
->add_window ("cmd", 1);
853 layouts
.emplace_back (layout
);
854 asm_regs_layout
= layout
;
859 /* A helper function that returns true if NAME is the name of an
863 validate_window_name (const std::string
&name
)
865 return (name
== "src" || name
== "cmd"
866 || name
== "regs" || name
== "asm"
867 || name
== "status");
870 /* Implementation of the "tui new-layout" command. */
873 tui_new_layout_command (const char *spec
, int from_tty
)
875 std::string new_name
= extract_arg (&spec
);
876 if (new_name
.empty ())
877 error (_("No layout name specified"));
878 if (new_name
[0] == '-')
879 error (_("Layout name cannot start with '-'"));
881 bool is_vertical
= true;
882 spec
= skip_spaces (spec
);
883 if (check_for_argument (&spec
, "-horizontal"))
886 std::vector
<std::unique_ptr
<tui_layout_split
>> splits
;
887 splits
.emplace_back (new tui_layout_split (is_vertical
));
888 std::unordered_set
<std::string
> seen_windows
;
891 spec
= skip_spaces (spec
);
898 spec
= skip_spaces (spec
+ 1);
899 if (check_for_argument (&spec
, "-horizontal"))
901 splits
.emplace_back (new tui_layout_split (is_vertical
));
905 bool is_close
= false;
911 if (splits
.size () == 1)
912 error (_("Extra '}' in layout specification"));
916 name
= extract_arg (&spec
);
919 if (!validate_window_name (name
))
920 error (_("Unknown window \"%s\""), name
.c_str ());
921 if (seen_windows
.find (name
) != seen_windows
.end ())
922 error (_("Window \"%s\" seen twice in layout"), name
.c_str ());
925 ULONGEST weight
= get_ulongest (&spec
, '}');
926 if ((int) weight
!= weight
)
927 error (_("Weight out of range: %s"), pulongest (weight
));
930 std::unique_ptr
<tui_layout_split
> last_split
931 = std::move (splits
.back ());
933 splits
.back ()->add_split (std::move (last_split
), weight
);
937 splits
.back ()->add_window (name
.c_str (), weight
);
938 seen_windows
.insert (name
);
941 if (splits
.size () > 1)
942 error (_("Missing '}' in layout specification"));
943 if (seen_windows
.empty ())
944 error (_("New layout does not contain any windows"));
945 if (seen_windows
.find ("cmd") == seen_windows
.end ())
946 error (_("New layout does not contain the \"cmd\" window"));
948 gdb::unique_xmalloc_ptr
<char> cmd_name
949 = make_unique_xstrdup (new_name
.c_str ());
950 std::unique_ptr
<tui_layout_split
> new_layout
= std::move (splits
.back ());
951 struct cmd_list_element
*cmd
952 = add_layout_command (cmd_name
.get (), new_layout
.get ());
953 cmd
->name_allocated
= 1;
955 new_layout
.release ();
958 /* Base command for "layout". */
961 tui_layout_command (const char *layout_name
, int from_tty
)
963 help_list (layout_list
, "layout ", all_commands
, gdb_stdout
);
966 /* Function to initialize gdb commands, for tui window layout
969 void _initialize_tui_layout ();
971 _initialize_tui_layout ()
973 add_prefix_cmd ("layout", class_tui
, tui_layout_command
, _("\
974 Change the layout of windows.\n\
975 Usage: layout prev | next | LAYOUT-NAME"),
976 &layout_list
, "layout ", 0, &cmdlist
);
978 add_cmd ("next", class_tui
, tui_next_layout_command
,
979 _("Apply the next TUI layout"),
981 add_cmd ("prev", class_tui
, tui_prev_layout_command
,
982 _("Apply the previous TUI layout"),
984 add_cmd ("regs", class_tui
, tui_regs_layout_command
,
985 _("Apply the TUI register layout"),
988 add_cmd ("new-layout", class_tui
, tui_new_layout_command
,
989 _("Create a new TUI layout.\n\
990 Usage: tui new-layout [-horizontal] NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\
991 Create a new TUI layout. The new layout will be named NAME,\n\
992 and can be accessed using \"layout NAME\".\n\
993 The windows will be displayed in the specified order.\n\
994 A WINDOW can also be of the form:\n\
995 { [-horizontal] NAME WEIGHT [NAME WEIGHT]... }\n\
996 This form indicates a sub-frame.\n\
997 Each WEIGHT is an integer, which holds the relative size\n\
998 to be allocated to the window."),
999 tui_get_cmd_list ());
1001 initialize_layouts ();