32#include <unordered_set>
46#include "gdbsupport/gdb-safe-ctype.h"
51static std::vector<std::unique_ptr<tui_layout_split>>
layouts;
78 win_info->make_visible (
false);
81 preserve_cmd_win_size_p);
94 std::vector<tui_win_info *> new_tui_windows;
101 if (!win_info->is_visible ())
103 if (focus == win_info)
138 std::string old_fingerprint;
145 std::string new_fingerprint =
applied_layout->layout_fingerprint ();
146 bool preserve_command_window_size
147 = (
TUI_CMD_WIN !=
nullptr && old_fingerprint == new_fingerprint);
179 for (
size_t i = 0; i <
layouts.size (); ++i)
184 gdb_assert_not_reached (
"layout not found!?");
277 if (focus ==
nullptr)
279 if (focus ==
nullptr)
291 TUI_SRC_WIN->display_start_addr (gdbarch_p, addr_p);
296 *gdbarch_p =
nullptr;
303 int origin_x_,
int origin_y_)
306 &&
x == origin_x_ &&
y == origin_y_
320 wmove (
handle.get (), 0, 0);
337template<enum tui_win_type V,
class T>
366 if (
name == window->name ())
371 error (_(
"Unknown window type \"%s\""),
name.c_str ());
374 if (result ==
nullptr)
375 error (_(
"Could not create window \"%s\""),
name.c_str ());
388 make_standard_window<CMD_WIN, tui_cmd_window>);
405 std::string name_copy =
name;
409 error (_(
"Window type \"%s\" is built-in"),
name);
411 for (
const char &c : name_copy)
414 error (_(
"invalid whitespace character in window name"));
416 if (!ISALNUM (c) && strchr (
"-_.", c) ==
nullptr)
417 error (_(
"invalid character '%c' in window name"), c);
420 if (!ISALPHA (name_copy[0]))
421 error (_(
"window name must start with a letter, not '%c'"), name_copy[0]);
432 std::move (factory));
437std::unique_ptr<tui_layout_base>
441 return std::unique_ptr<tui_layout_base> (result);
448 bool preserve_cmd_win_size_p)
532 if (strcmp (
get_name (),
"cmd") == 0)
544 split s = {weight, std::move (layout)};
554 split s = {weight, std::unique_ptr<tui_layout_base> (result)};
560std::unique_ptr<tui_layout_base>
566 std::unique_ptr<tui_layout_base> next = item.layout->clone ();
568 result->
m_splits.push_back (std::move (s));
570 return std::unique_ptr<tui_layout_base> (result);
582 bool first_time =
true;
585 int new_min, new_max;
586 item.layout->get_sizes (
height, &new_min, &new_max);
592 *min_value += new_min;
593 *max_value += new_max;
597 *min_value = std::max (*min_value, new_min);
598 *max_value = std::min (*max_value, new_max);
603 tui_debug_printf (
"min_value = %d, max_value = %d", *min_value, *max_value);
613 return m_splits[0].layout->first_edge_has_border_p ();
623 return m_splits.back ().layout->last_edge_has_border_p ();
631 for (
int i = 0; i <
m_splits.size (); ++i)
643 for (
int i = 0; i <
m_splits.size (); ++i)
647 str += string_printf (
"[%d] %d", i,
m_splits[i].weight);
657 (
const std::vector<tui_layout_split::size_info> &
info)
662 for (
int i = 0; i < info.size (); ++i)
663 tui_debug_printf (
" [%d] { size = %d, min = %d, max = %d, share_box = %d }",
664 i, info[i].
size, info[i].min_size,
665 info[i].max_size, info[i].share_box);
676 this,
name, new_size);
681 int found_index = -1;
682 for (
int i = 0; i <
m_splits.size (); ++i)
686 adjusted =
m_splits[i].layout->set_width (
name, new_size);
688 adjusted =
m_splits[i].layout->set_height (
name, new_size);
691 if (adjusted ==
FOUND)
700 if (found_index == -1)
702 int curr_size = (set_width_p
703 ?
m_splits[found_index].layout->width
704 :
m_splits[found_index].layout->height);
705 if (curr_size == new_size)
711 int delta =
m_splits[found_index].weight - new_size;
712 m_splits[found_index].weight = new_size;
721 bool found_window_that_can_grow_p =
true;
722 for (
int i = 0; delta != 0; i = (i + 1) %
m_splits.size ())
724 int index = (found_index + 1 + i) %
m_splits.size ();
725 if (index == found_index)
727 if (!found_window_that_can_grow_p)
729 found_window_that_can_grow_p =
false;
733 int new_min, new_max;
740 if (
m_splits[index].weight > new_min)
744 found_window_that_can_grow_p =
true;
751 if (
m_splits[index].weight < new_max)
755 found_window_that_can_grow_p =
true;
769 warning (_(
"Invalid window width specified"));
771 warning (_(
"Invalid window height specified"));
791 bool preserve_cmd_win_size_p)
807 old_size_info (
int index_,
int min_size_,
int max_size_)
809 min_size (min_size_),
822 gdb::optional<old_size_info> old_cmd_info;
824 std::vector<size_info> info (
m_splits.size ());
835 int total_weight = 0;
836 for (
int i = 0; i <
m_splits.size (); ++i)
838 bool cmd_win_already_exists =
TUI_CMD_WIN !=
nullptr;
846 if (preserve_cmd_win_size_p
847 && cmd_win_already_exists
848 &&
m_splits[i].layout->get_name () !=
nullptr
849 && strcmp (
m_splits[i].layout->get_name (),
"cmd") == 0)
853 old_cmd_info.emplace (i, info[i].min_size, info[i].max_size);
864 info[i].max_size = info[i].min_size;
867 if (info[i].min_size == info[i].max_size)
868 available_size -= info[i].min_size;
878 &&
m_splits[i - 1].layout->last_edge_has_border_p ()
879 &&
m_splits[i].layout->first_edge_has_border_p ())
880 info[i].share_box =
true;
887 gdb_assert (last_index == -1 || total_weight > 0);
893 for (
int i = 0; i <
m_splits.size (); ++i)
895 if (info[i].min_size != info[i].max_size)
898 info[i].size = available_size *
m_splits[i].weight / total_weight;
899 if (info[i].
size > info[i].max_size)
900 info[i].size = info[i].max_size;
901 if (info[i].
size < info[i].min_size)
902 info[i].size = info[i].min_size;
908 used_size += info[i].size;
909 if (info[i].share_box)
913 info[i].size = info[i].min_size;
920 available_size, used_size);
922 total_weight, last_index);
933 if (last_index == -1 && old_cmd_info.has_value ())
934 last_index = old_cmd_info->index;
937 if (available_size != used_size && last_index != -1)
942 bool found_window_that_can_grow_p =
true;
943 for (
int idx = last_index;
944 available_size != used_size;
959 if (idx == last_index)
973 if (old_cmd_info.has_value ()
974 && ((available_size < used_size)
975 || !found_window_that_can_grow_p))
977 info[old_cmd_info->index].min_size = old_cmd_info->min_size;
978 info[old_cmd_info->index].max_size = old_cmd_info->max_size;
980 (
"restoring index %d (cmd) size limits, min = %d, max = %d",
981 old_cmd_info->index, old_cmd_info->min_size,
982 old_cmd_info->max_size);
983 old_cmd_info.reset ();
985 else if (!found_window_that_can_grow_p)
987 found_window_that_can_grow_p =
false;
990 if (available_size > used_size
991 && info[idx].
size < info[idx].max_size)
993 found_window_that_can_grow_p =
true;
997 else if (available_size < used_size
998 && info[idx].
size > info[idx].min_size)
1000 found_window_that_can_grow_p =
true;
1001 info[idx].size -= 1;
1010 available_size, used_size);
1012 total_weight, last_index);
1020 for (
int i = 0; i <
m_splits.size (); ++i)
1024 if (size_accum + info[i].
size > maximum)
1025 size_accum = maximum - info[i].size;
1026 else if (info[i].share_box)
1030 preserve_cmd_win_size_p);
1033 preserve_cmd_win_size_p);
1034 size_accum += info[i].size;
1043 for (
int i = 0; i <
m_splits.size (); ++i)
1045 const char *this_name =
m_splits[i].layout->get_name ();
1046 if (this_name ==
nullptr)
1048 else if (strcmp (this_name,
name) == 0
1049 || strcmp (this_name,
CMD_NAME) == 0
1068 item.layout->replace_window (
name, new_window);
1088 item.layout->specification (output, depth + 1);
1103 std::string fp = item.layout->layout_fingerprint ();
1104 if (!fp.empty () &&
m_splits.size () != 1)
1105 return std::string (
m_vertical ?
"V" :
"H") + fp;
1143 gdb::unique_xmalloc_ptr<char>
doc
1144 = xstrprintf (_(
"Apply the \"%s\" layout.\n\
1145This layout was created using:\n\
1146 tui new-layout %s %s"),
1156 layouts.emplace_back (layout);
1192 layouts.emplace_back (layout);
1200 layouts.emplace_back (layout);
1222 if (new_name.empty ())
1223 error (_(
"No layout name specified"));
1224 if (new_name[0] ==
'-')
1225 error (_(
"Layout name cannot start with '-'"));
1227 bool is_vertical =
true;
1228 spec = skip_spaces (spec);
1230 is_vertical =
false;
1232 std::vector<std::unique_ptr<tui_layout_split>> splits;
1234 std::unordered_set<std::string> seen_windows;
1237 spec = skip_spaces (spec);
1238 if (spec[0] ==
'\0')
1244 spec = skip_spaces (spec + 1);
1246 is_vertical =
false;
1251 bool is_close =
false;
1257 if (splits.size () == 1)
1258 error (_(
"Extra '}' in layout specification"));
1266 error (_(
"Unknown window \"%s\""),
name.c_str ());
1267 if (seen_windows.find (
name) != seen_windows.end ())
1268 error (_(
"Window \"%s\" seen twice in layout"),
name.c_str ());
1272 if ((
int) weight != weight)
1273 error (_(
"Weight out of range: %s"), pulongest (weight));
1276 std::unique_ptr<tui_layout_split> last_split
1277 = std::move (splits.back ());
1279 splits.back ()->add_split (std::move (last_split), weight);
1283 splits.back ()->add_window (
name.c_str (), weight);
1284 seen_windows.insert (
name);
1287 if (splits.size () > 1)
1288 error (_(
"Missing '}' in layout specification"));
1289 if (seen_windows.empty ())
1290 error (_(
"New layout does not contain any windows"));
1291 if (seen_windows.find (
CMD_NAME) == seen_windows.end ())
1292 error (_(
"New layout does not contain the \"" CMD_NAME "\" window"));
1294 gdb::unique_xmalloc_ptr<char> cmd_name
1295 = make_unique_xstrdup (new_name.c_str ());
1296 std::unique_ptr<tui_layout_split> new_layout = std::move (splits.back ());
1300 cmd_name.release ();
1301 new_layout.release ();
1313Change the layout of windows.\n\
1314Usage: tui layout prev | next | LAYOUT-NAME"),
1319 _(
"Apply the next TUI layout."),
1322 _(
"Apply the previous TUI layout."),
1325 _(
"Apply the TUI register layout."),
1329 _(
"Create a new TUI layout.\n\
1330Usage: tui new-layout [-horizontal] NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\
1331Create a new TUI layout. The new layout will be named NAME,\n\
1332and can be accessed using \"layout NAME\".\n\
1333The windows will be displayed in the specified order.\n\
1334A WINDOW can also be of the form:\n\
1335 { [-horizontal] NAME WEIGHT [NAME WEIGHT]... }\n\
1336This form indicates a sub-frame.\n\
1337Each WEIGHT is an integer, which holds the relative size\n\
1338to be allocated to the window."),
constexpr string_view get()
const char * c_str() const
void specification(ui_file *output, int depth) override
void set_weights_from_sizes()
std::string tui_debug_weights_to_string() const
bool first_edge_has_border_p() const override
void get_sizes(bool height, int *min_value, int *max_value) override
static void tui_debug_print_size_info(const std::vector< size_info > &info)
std::vector< split > m_splits
std::unique_ptr< tui_layout_base > clone() const override
void remove_windows(const char *name) override
tui_adjust_result set_size(const char *name, int new_size, bool set_width_p)
void add_split(std::unique_ptr< tui_layout_split > &&layout, int weight)
tui_layout_split(bool vertical=true)
void replace_window(const char *name, const char *new_window) override
void add_window(const char *name, int weight)
bool last_edge_has_border_p() const override
void apply(int x, int y, int width, int height, bool preserve_cmd_win_size_p) override
std::string layout_fingerprint() const override
void get_sizes(bool height, int *min_value, int *max_value) override
const char * get_name() const override
bool last_edge_has_border_p() const override
std::unique_ptr< tui_layout_base > clone() const override
bool first_edge_has_border_p() const override
tui_layout_window(const char *name)
void replace_window(const char *name, const char *new_window) override
void apply(int x, int y, int width, int height, bool preserve_cmd_win_size_p) override
void specification(ui_file *output, int depth) override
std::string layout_fingerprint() const override
struct cmd_list_element * add_cmd(const char *name, enum command_class theclass, const char *doc, struct cmd_list_element **list)
cmd_list_element * add_com_alias(const char *name, cmd_list_element *target, command_class theclass, int abbrev_flag)
void help_list(struct cmd_list_element *list, const char *cmdtype, enum command_class theclass, struct ui_file *stream)
struct cmd_list_element * add_prefix_cmd(const char *name, enum command_class theclass, cmd_simple_func_ftype *fun, const char *doc, struct cmd_list_element **subcommands, int allow_unknown, struct cmd_list_element **list)
ULONGEST get_ulongest(const char **pp, int trailer)
int check_for_argument(const char **str, const char *arg, int arg_len)
std::string extract_arg(const char **arg)
unsigned int doc_allocated
void(* destroyer)(struct cmd_list_element *self, void *context)
unsigned int name_allocated
void set_context(void *context)
virtual bool can_box() const
virtual void resize(int height, int width, int origin_x, int origin_y)
virtual const char * name() const =0
virtual void make_visible(bool visible)
virtual int min_height() const
virtual void make_window()
std::unique_ptr< WINDOW, curses_deleter > handle
virtual int max_height() const
void tui_set_win_focus_to(struct tui_win_info *win_info)
int tui_term_height(void)
struct tui_win_info * tui_win_list[MAX_MAJOR_WINDOWS]
struct tui_win_info * tui_win_with_focus(void)
void tui_get_begin_asm_address(struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
void tui_set_initial_layout()
static tui_layout_split * src_regs_layout
void tui_add_win_to_layout(enum tui_win_type type)
void _initialize_tui_layout()
static void tui_set_layout(tui_layout_split *layout)
static void extract_display_start_addr(struct gdbarch **, CORE_ADDR *)
void tui_register_window(const char *name, window_factory &&factory)
static void tui_next_layout_command(const char *arg, int from_tty)
static tui_layout_split * applied_skeleton
static tui_layout_split * asm_regs_layout
static void initialize_known_windows()
static void tui_new_layout_command(const char *spec, int from_tty)
void tui_adjust_window_height(struct tui_win_info *win, int new_height)
static void tui_apply_layout(const char *args, int from_tty, cmd_list_element *command)
static void tui_prev_layout_command(const char *arg, int from_tty)
static size_t find_layout(tui_layout_split *layout)
static bool validate_window_name(const std::string &name)
static std::unique_ptr< tui_layout_base > applied_layout
static void destroy_layout(struct cmd_list_element *self, void *context)
static void tui_layout_command(const char *args, int from_tty)
static void tui_regs_layout_command(const char *arg, int from_tty)
static tui_win_info * tui_get_window_by_name(const std::string &name)
std::vector< tui_win_info * > tui_windows
static std::vector< std::unique_ptr< tui_layout_split > > layouts
static tui_win_info * make_standard_window(const char *)
static void initialize_layouts()
void tui_remove_some_windows()
static window_types_map known_window_types
void tui_apply_current_layout(bool preserve_cmd_win_size_p)
static struct cmd_list_element * layout_list
known_window_names_range all_known_window_names()
static struct cmd_list_element * add_layout_command(const char *name, tui_layout_split *layout)
void tui_adjust_window_width(struct tui_win_info *win, int new_width)
std::unordered_map< std::string, window_factory > window_types_map
iterator_range< known_window_names_iterator > known_window_names_range
std::function< tui_win_info *(const char *name) window_factory)
struct cmd_list_element ** tui_get_cmd_list(void)
void tui_update_source_windows_with_addr(struct gdbarch *gdbarch, CORE_ADDR addr)
#define tui_debug_printf(fmt,...)
#define TUI_SCOPED_DEBUG_ENTER_EXIT
void gdb_printf(struct ui_file *stream, const char *format,...)
void gdb_puts(const char *linebuffer, struct ui_file *stream)