Add the "tui new-layout" command
[deliverable/binutils-gdb.git] / gdb / tui / tui-layout.c
1 /* TUI layout window management.
2
3 Copyright (C) 1998-2020 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 "cli/cli-cmds.h"
29 #include "cli/cli-decode.h"
30 #include "cli/cli-utils.h"
31 #include <ctype.h>
32 #include <unordered_set>
33
34 #include "tui/tui.h"
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"
46
47 static void tui_layout_command (const char *, int);
48 static void extract_display_start_addr (struct gdbarch **, CORE_ADDR *);
49
50 /* The layouts. */
51 static std::vector<std::unique_ptr<tui_layout_split>> layouts;
52
53 /* The layout that is currently applied. */
54 static std::unique_ptr<tui_layout_base> applied_layout;
55
56 /* The "skeleton" version of the layout that is currently applied. */
57 static tui_layout_split *applied_skeleton;
58
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;
63
64 /* See tui-layout.h. */
65
66 void
67 tui_apply_current_layout ()
68 {
69 applied_layout->apply (0, 0, tui_term_width (), tui_term_height ());
70 }
71
72 /* See tui-layout. */
73
74 void
75 tui_adjust_window_height (struct tui_win_info *win, int new_height)
76 {
77 applied_layout->adjust_size (win->name (), new_height);
78 }
79
80 /* Set the current layout to LAYOUT. */
81
82 static void
83 tui_set_layout (tui_layout_split *layout)
84 {
85 struct gdbarch *gdbarch;
86 CORE_ADDR addr;
87
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 ();
94
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);
98 }
99
100 /* See tui-layout.h. */
101
102 void
103 tui_add_win_to_layout (enum tui_win_type type)
104 {
105 gdb_assert (type == SRC_WIN || type == DISASSEM_WIN);
106
107 /* If the window already exists, no need to add it. */
108 if (tui_win_list[type] != nullptr)
109 return;
110
111 /* If the window we are trying to replace doesn't exist, we're
112 done. */
113 enum tui_win_type other = type == SRC_WIN ? DISASSEM_WIN : SRC_WIN;
114 if (tui_win_list[other] == nullptr)
115 return;
116
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 ();
121 }
122
123 /* Find LAYOUT in the "layouts" global and return its index. */
124
125 static size_t
126 find_layout (tui_layout_split *layout)
127 {
128 for (size_t i = 0; i < layouts.size (); ++i)
129 {
130 if (layout == layouts[i].get ())
131 return i;
132 }
133 gdb_assert_not_reached (_("layout not found!?"));
134 }
135
136 /* Function to set the layout. */
137
138 static void
139 tui_apply_layout (struct cmd_list_element *command,
140 const char *args, int from_tty)
141 {
142 tui_layout_split *layout
143 = (tui_layout_split *) get_cmd_context (command);
144
145 /* Make sure the curses mode is enabled. */
146 tui_enable ();
147 tui_set_layout (layout);
148 }
149
150 /* See tui-layout.h. */
151
152 void
153 tui_next_layout ()
154 {
155 size_t index = find_layout (applied_skeleton);
156 ++index;
157 if (index == layouts.size ())
158 index = 0;
159 tui_set_layout (layouts[index].get ());
160 }
161
162 /* Implement the "layout next" command. */
163
164 static void
165 tui_next_layout_command (const char *arg, int from_tty)
166 {
167 tui_enable ();
168 tui_next_layout ();
169 }
170
171 /* See tui-layout.h. */
172
173 void
174 tui_set_initial_layout ()
175 {
176 tui_set_layout (layouts[0].get ());
177 }
178
179 /* Implement the "layout prev" command. */
180
181 static void
182 tui_prev_layout_command (const char *arg, int from_tty)
183 {
184 tui_enable ();
185 size_t index = find_layout (applied_skeleton);
186 if (index == 0)
187 index = layouts.size ();
188 --index;
189 tui_set_layout (layouts[index].get ());
190 }
191
192
193 /* See tui-layout.h. */
194
195 void
196 tui_regs_layout ()
197 {
198 /* If there's already a register window, we're done. */
199 if (TUI_DATA_WIN != nullptr)
200 return;
201
202 tui_set_layout (TUI_DISASM_WIN != nullptr
203 ? asm_regs_layout
204 : src_regs_layout);
205 }
206
207 /* Implement the "layout regs" command. */
208
209 static void
210 tui_regs_layout_command (const char *arg, int from_tty)
211 {
212 tui_enable ();
213 tui_regs_layout ();
214 }
215
216 /* See tui-layout.h. */
217
218 void
219 tui_remove_some_windows ()
220 {
221 tui_win_info *focus = tui_win_with_focus ();
222
223 if (strcmp (focus->name (), "cmd") == 0)
224 {
225 /* Try leaving the source or disassembly window. If neither
226 exists, just do nothing. */
227 focus = TUI_SRC_WIN;
228 if (focus == nullptr)
229 focus = TUI_DISASM_WIN;
230 if (focus == nullptr)
231 return;
232 }
233
234 applied_layout->remove_windows (focus->name ());
235 tui_apply_current_layout ();
236 }
237
238 static void
239 extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
240 {
241 struct gdbarch *gdbarch = nullptr;
242 CORE_ADDR addr = 0;
243 CORE_ADDR pc;
244 struct symtab_and_line cursal = get_current_source_symtab_and_line ();
245
246 if (TUI_SRC_WIN != nullptr)
247 {
248 gdbarch = TUI_SRC_WIN->gdbarch;
249 find_line_pc (cursal.symtab,
250 TUI_SRC_WIN->start_line_or_addr.u.line_no,
251 &pc);
252 addr = pc;
253 }
254 else if (TUI_DISASM_WIN != nullptr)
255 {
256 gdbarch = TUI_DISASM_WIN->gdbarch;
257 addr = TUI_DISASM_WIN->start_line_or_addr.u.addr;
258 }
259
260 *gdbarch_p = gdbarch;
261 *addr_p = addr;
262 }
263
264 void
265 tui_gen_win_info::resize (int height_, int width_,
266 int origin_x_, int origin_y_)
267 {
268 if (width == width_ && height == height_
269 && x == origin_x_ && y == origin_y_
270 && handle != nullptr)
271 return;
272
273 width = width_;
274 height = height_;
275 x = origin_x_;
276 y = origin_y_;
277
278 if (handle != nullptr)
279 {
280 #ifdef HAVE_WRESIZE
281 wresize (handle.get (), height, width);
282 mvwin (handle.get (), y, x);
283 wmove (handle.get (), 0, 0);
284 #else
285 handle.reset (nullptr);
286 #endif
287 }
288
289 if (handle == nullptr)
290 make_window ();
291
292 rerender ();
293 }
294
295 \f
296
297 /* Helper function that returns a TUI window, given its name. */
298
299 static tui_gen_win_info *
300 tui_get_window_by_name (const std::string &name)
301 {
302 if (name == "src")
303 {
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];
307 }
308 else if (name == "cmd")
309 {
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];
313 }
314 else if (name == "regs")
315 {
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];
319 }
320 else if (name == "asm")
321 {
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];
325 }
326 else
327 {
328 gdb_assert (name == "status");
329 return tui_locator_win_info_ptr ();
330 }
331 }
332
333 /* See tui-layout.h. */
334
335 std::unique_ptr<tui_layout_base>
336 tui_layout_window::clone () const
337 {
338 tui_layout_window *result = new tui_layout_window (m_contents.c_str ());
339 return std::unique_ptr<tui_layout_base> (result);
340 }
341
342 /* See tui-layout.h. */
343
344 void
345 tui_layout_window::apply (int x_, int y_, int width_, int height_)
346 {
347 x = x_;
348 y = y_;
349 width = width_;
350 height = height_;
351 gdb_assert (m_window != nullptr);
352 m_window->resize (height, width, x, y);
353 }
354
355 /* See tui-layout.h. */
356
357 void
358 tui_layout_window::get_sizes (int *min_height, int *max_height)
359 {
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 ();
364 }
365
366 /* See tui-layout.h. */
367
368 bool
369 tui_layout_window::top_boxed_p () const
370 {
371 gdb_assert (m_window != nullptr);
372 return m_window->can_box ();
373 }
374
375 /* See tui-layout.h. */
376
377 bool
378 tui_layout_window::bottom_boxed_p () const
379 {
380 gdb_assert (m_window != nullptr);
381 return m_window->can_box ();
382 }
383
384 /* See tui-layout.h. */
385
386 void
387 tui_layout_window::replace_window (const char *name, const char *new_window)
388 {
389 if (m_contents == name)
390 {
391 m_contents = new_window;
392 if (m_window != nullptr)
393 {
394 m_window->make_visible (false);
395 m_window = tui_get_window_by_name (m_contents);
396 }
397 }
398 }
399
400 /* See tui-layout.h. */
401
402 void
403 tui_layout_window::specification (ui_file *output)
404 {
405 fputs_unfiltered (get_name (), output);
406 }
407
408 /* See tui-layout.h. */
409
410 tui_layout_split *
411 tui_layout_split::add_split (int weight)
412 {
413 tui_layout_split *result = new tui_layout_split ();
414 split s = {weight, std::unique_ptr<tui_layout_base> (result)};
415 m_splits.push_back (std::move (s));
416 return result;
417 }
418
419 /* See tui-layout.h. */
420
421 void
422 tui_layout_split::add_window (const char *name, int weight)
423 {
424 tui_layout_window *result = new tui_layout_window (name);
425 split s = {weight, std::unique_ptr<tui_layout_base> (result)};
426 m_splits.push_back (std::move (s));
427 }
428
429 /* See tui-layout.h. */
430
431 std::unique_ptr<tui_layout_base>
432 tui_layout_split::clone () const
433 {
434 tui_layout_split *result = new tui_layout_split ();
435 for (const split &item : m_splits)
436 {
437 std::unique_ptr<tui_layout_base> next = item.layout->clone ();
438 split s = {item.weight, std::move (next)};
439 result->m_splits.push_back (std::move (s));
440 }
441 return std::unique_ptr<tui_layout_base> (result);
442 }
443
444 /* See tui-layout.h. */
445
446 void
447 tui_layout_split::get_sizes (int *min_height, int *max_height)
448 {
449 *min_height = 0;
450 *max_height = 0;
451 for (const split &item : m_splits)
452 {
453 int new_min, new_max;
454 item.layout->get_sizes (&new_min, &new_max);
455 *min_height += new_min;
456 *max_height += new_max;
457 }
458 }
459
460 /* See tui-layout.h. */
461
462 bool
463 tui_layout_split::top_boxed_p () const
464 {
465 if (m_splits.empty ())
466 return false;
467 return m_splits[0].layout->top_boxed_p ();
468 }
469
470 /* See tui-layout.h. */
471
472 bool
473 tui_layout_split::bottom_boxed_p () const
474 {
475 if (m_splits.empty ())
476 return false;
477 return m_splits.back ().layout->top_boxed_p ();
478 }
479
480 /* See tui-layout.h. */
481
482 void
483 tui_layout_split::set_weights_from_heights ()
484 {
485 for (int i = 0; i < m_splits.size (); ++i)
486 m_splits[i].weight = m_splits[i].layout->height;
487 }
488
489 /* See tui-layout.h. */
490
491 bool
492 tui_layout_split::adjust_size (const char *name, int new_height)
493 {
494 /* Look through the children. If one is a layout holding the named
495 window, we're done; or if one actually is the named window,
496 update it. */
497 int found_index = -1;
498 for (int i = 0; i < m_splits.size (); ++i)
499 {
500 if (m_splits[i].layout->adjust_size (name, new_height))
501 return true;
502 const char *win_name = m_splits[i].layout->get_name ();
503 if (win_name != nullptr && strcmp (name, win_name) == 0)
504 {
505 found_index = i;
506 break;
507 }
508 }
509
510 if (found_index == -1)
511 return false;
512 if (m_splits[found_index].layout->height == new_height)
513 return true;
514
515 set_weights_from_heights ();
516 int delta = m_splits[found_index].weight - new_height;
517 m_splits[found_index].weight = new_height;
518
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)
523 {
524 int index = (found_index + 1 + i) % m_splits.size ();
525
526 int new_min, new_max;
527 m_splits[index].layout->get_sizes (&new_min, &new_max);
528
529 if (delta < 0)
530 {
531 /* The primary window grew, so we are trying to shrink other
532 windows. */
533 int available = m_splits[index].weight - new_min;
534 int shrink_by = std::min (available, -delta);
535 m_splits[index].weight -= shrink_by;
536 delta += shrink_by;
537 }
538 else
539 {
540 /* The primary window shrank, so we are trying to grow other
541 windows. */
542 int available = new_max - m_splits[index].weight;
543 int grow_by = std::min (available, delta);
544 m_splits[index].weight += grow_by;
545 delta -= grow_by;
546 }
547 }
548
549 if (delta != 0)
550 {
551 warning (_("Invalid window height specified"));
552 /* Effectively undo any modifications made here. */
553 set_weights_from_heights ();
554 }
555 else
556 {
557 /* Simply re-apply the updated layout. */
558 apply (x, y, width, height);
559 }
560
561 return true;
562 }
563
564 /* See tui-layout.h. */
565
566 void
567 tui_layout_split::apply (int x_, int y_, int width_, int height_)
568 {
569 x = x_;
570 y = y_;
571 width = width_;
572 height = height_;
573
574 struct height_info
575 {
576 int height;
577 int min_height;
578 int max_height;
579 /* True if this window will share a box border with the previous
580 window in the list. */
581 bool share_box;
582 };
583
584 std::vector<height_info> info (m_splits.size ());
585
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;
591 int last_index = -1;
592 int total_weight = 0;
593 for (int i = 0; i < m_splits.size (); ++i)
594 {
595 bool cmd_win_already_exists = TUI_CMD_WIN != nullptr;
596
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);
601
602 if (!m_applied
603 && cmd_win_already_exists
604 && m_splits[i].layout->get_name () != nullptr
605 && strcmp (m_splits[i].layout->get_name (), "cmd") == 0)
606 {
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
612 this window. */
613 info[i].min_height = TUI_CMD_WIN->height;
614 info[i].max_height = TUI_CMD_WIN->height;
615 }
616
617 if (info[i].min_height == info[i].max_height)
618 available_height -= info[i].min_height;
619 else
620 {
621 last_index = i;
622 total_weight += m_splits[i].weight;
623 }
624
625 /* Two adjacent boxed windows will share a border, making a bit
626 more height available. */
627 if (i > 0
628 && m_splits[i - 1].layout->bottom_boxed_p ()
629 && m_splits[i].layout->top_boxed_p ())
630 info[i].share_box = true;
631 }
632
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
635 their weight. */
636 int used_height = 0;
637 for (int i = 0; i < m_splits.size (); ++i)
638 {
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
649 last window. */
650 if (info[i].min_height != info[i].max_height)
651 {
652 used_height += info[i].height;
653 if (info[i].share_box)
654 --used_height;
655 }
656 }
657
658 /* Allocate any leftover height. */
659 if (available_height >= used_height && last_index != -1)
660 info[last_index].height += available_height - used_height;
661
662 /* Step 3: Resize. */
663 int height_accum = 0;
664 for (int i = 0; i < m_splits.size (); ++i)
665 {
666 /* If we fall off the bottom, just make allocations overlap.
667 GIGO. */
668 if (height_accum + info[i].height > height)
669 height_accum = height - info[i].height;
670 else if (info[i].share_box)
671 --height_accum;
672 m_splits[i].layout->apply (x, y + height_accum, width, info[i].height);
673 height_accum += info[i].height;
674 }
675
676 m_applied = true;
677 }
678
679 /* See tui-layout.h. */
680
681 void
682 tui_layout_split::remove_windows (const char *name)
683 {
684 for (int i = 0; i < m_splits.size (); ++i)
685 {
686 const char *this_name = m_splits[i].layout->get_name ();
687 if (this_name == nullptr)
688 m_splits[i].layout->remove_windows (name);
689 else
690 {
691 if (strcmp (this_name, name) == 0
692 || strcmp (this_name, "cmd") == 0)
693 {
694 /* Keep. */
695 }
696 m_splits.erase (m_splits.begin () + i);
697 --i;
698 }
699 }
700 }
701
702 /* See tui-layout.h. */
703
704 void
705 tui_layout_split::replace_window (const char *name, const char *new_window)
706 {
707 for (auto &item : m_splits)
708 item.layout->replace_window (name, new_window);
709 }
710
711 /* See tui-layout.h. */
712
713 void
714 tui_layout_split::specification (ui_file *output)
715 {
716 bool first = true;
717 for (auto &item : m_splits)
718 {
719 if (!first)
720 fputs_unfiltered (" ", output);
721 first = false;
722 item.layout->specification (output);
723 fprintf_unfiltered (output, " %d", item.weight);
724 }
725 }
726
727 /* Destroy the layout associated with SELF. */
728
729 static void
730 destroy_layout (struct cmd_list_element *self, void *context)
731 {
732 tui_layout_split *layout = (tui_layout_split *) context;
733 size_t index = find_layout (layout);
734 layouts.erase (layouts.begin () + index);
735 }
736
737 /* List holding the sub-commands of "layout". */
738
739 static struct cmd_list_element *layout_list;
740
741 /* Add a "layout" command with name NAME that switches to LAYOUT. */
742
743 static struct cmd_list_element *
744 add_layout_command (const char *name, tui_layout_split *layout)
745 {
746 struct cmd_list_element *cmd;
747
748 string_file spec;
749 layout->specification (&spec);
750
751 gdb::unique_xmalloc_ptr<char> doc
752 (xstrprintf (_("Apply the \"%s\" layout.\n\
753 This layout was created using:\n\
754 tui new-layout %s %s"),
755 name, name, spec.c_str ()));
756
757 cmd = add_cmd (name, class_tui, nullptr, doc.get (), &layout_list);
758 set_cmd_context (cmd, layout);
759 /* There is no API to set this. */
760 cmd->func = tui_apply_layout;
761 cmd->destroyer = destroy_layout;
762 cmd->doc_allocated = 1;
763 doc.release ();
764 layouts.emplace_back (layout);
765
766 return cmd;
767 }
768
769 /* Initialize the standard layouts. */
770
771 static void
772 initialize_layouts ()
773 {
774 tui_layout_split *layout;
775
776 layout = new tui_layout_split ();
777 layout->add_window ("src", 2);
778 layout->add_window ("status", 0);
779 layout->add_window ("cmd", 1);
780 add_layout_command ("src", layout);
781
782 layout = new tui_layout_split ();
783 layout->add_window ("asm", 2);
784 layout->add_window ("status", 0);
785 layout->add_window ("cmd", 1);
786 add_layout_command ("asm", layout);
787
788 layout = new tui_layout_split ();
789 layout->add_window ("src", 1);
790 layout->add_window ("asm", 1);
791 layout->add_window ("status", 0);
792 layout->add_window ("cmd", 1);
793 add_layout_command ("split", layout);
794
795 layout = new tui_layout_split ();
796 layout->add_window ("regs", 1);
797 layout->add_window ("src", 1);
798 layout->add_window ("status", 0);
799 layout->add_window ("cmd", 1);
800 layouts.emplace_back (layout);
801 src_regs_layout = layout;
802
803 layout = new tui_layout_split ();
804 layout->add_window ("regs", 1);
805 layout->add_window ("asm", 1);
806 layout->add_window ("status", 0);
807 layout->add_window ("cmd", 1);
808 layouts.emplace_back (layout);
809 asm_regs_layout = layout;
810 }
811
812 \f
813
814 /* A helper function that returns true if NAME is the name of an
815 available window. */
816
817 static bool
818 validate_window_name (const std::string &name)
819 {
820 return (name == "src" || name == "cmd"
821 || name == "regs" || name == "asm"
822 || name == "status");
823 }
824
825 /* Implementation of the "tui new-layout" command. */
826
827 static void
828 tui_new_layout_command (const char *spec, int from_tty)
829 {
830 std::string new_name = extract_arg (&spec);
831 if (new_name.empty ())
832 error (_("No layout name specified"));
833 if (new_name[0] == '-')
834 error (_("Layout name cannot start with '-'"));
835
836 std::unique_ptr<tui_layout_split> new_layout (new tui_layout_split);
837 std::unordered_set<std::string> seen_windows;
838 while (true)
839 {
840 std::string name = extract_arg (&spec);
841 if (name.empty ())
842 break;
843 if (!validate_window_name (name))
844 error (_("Unknown window \"%s\""), name.c_str ());
845 if (seen_windows.find (name) != seen_windows.end ())
846 error (_("Window \"%s\" seen twice in layout"), name.c_str ());
847 ULONGEST weight = get_ulongest (&spec);
848 if ((int) weight != weight)
849 error (_("Weight out of range: %s"), pulongest (weight));
850 new_layout->add_window (name.c_str (), weight);
851 seen_windows.insert (name);
852 }
853 if (seen_windows.empty ())
854 error (_("New layout does not contain any windows"));
855 if (seen_windows.find ("cmd") == seen_windows.end ())
856 error (_("New layout does not contain the \"cmd\" window"));
857
858 gdb::unique_xmalloc_ptr<char> cmd_name
859 = make_unique_xstrdup (new_name.c_str ());
860 struct cmd_list_element *cmd
861 = add_layout_command (cmd_name.get (), new_layout.get ());
862 cmd->name_allocated = 1;
863 cmd_name.release ();
864 new_layout.release ();
865 }
866
867 /* Base command for "layout". */
868
869 static void
870 tui_layout_command (const char *layout_name, int from_tty)
871 {
872 help_list (layout_list, "layout ", all_commands, gdb_stdout);
873 }
874
875 /* Function to initialize gdb commands, for tui window layout
876 manipulation. */
877
878 void _initialize_tui_layout ();
879 void
880 _initialize_tui_layout ()
881 {
882 add_prefix_cmd ("layout", class_tui, tui_layout_command, _("\
883 Change the layout of windows.\n\
884 Usage: layout prev | next | LAYOUT-NAME"),
885 &layout_list, "layout ", 0, &cmdlist);
886
887 add_cmd ("next", class_tui, tui_next_layout_command,
888 _("Apply the next TUI layout"),
889 &layout_list);
890 add_cmd ("prev", class_tui, tui_prev_layout_command,
891 _("Apply the previous TUI layout"),
892 &layout_list);
893 add_cmd ("regs", class_tui, tui_regs_layout_command,
894 _("Apply the TUI register layout"),
895 &layout_list);
896
897 add_cmd ("new-layout", class_tui, tui_new_layout_command,
898 _("Create a new TUI layout.\n\
899 Usage: tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\
900 Create a new TUI layout. The new layout will be named NAME,\n\
901 and can be accessed using \"layout NAME\".\n\
902 The windows will be displayed in the specified order.\n\
903 Each WEIGHT is an integer, which holds the relative size\n\
904 to be allocated to the window."),
905 tui_get_cmd_list ());
906
907 initialize_layouts ();
908 }
This page took 0.214237 seconds and 5 git commands to generate.