32#include <unordered_map>
33#include <unordered_set>
47#include "safe-ctype.h"
52static std::vector<std::unique_ptr<tui_layout_split>>
layouts;
79 win_info->make_visible (
false);
82 preserve_cmd_win_size_p);
95 std::vector<tui_win_info *> new_tui_windows;
102 if (!win_info->is_visible ())
104 if (focus == win_info)
139 std::string old_fingerprint;
146 std::string new_fingerprint =
applied_layout->layout_fingerprint ();
147 bool preserve_command_window_size
148 = (
TUI_CMD_WIN !=
nullptr && old_fingerprint == new_fingerprint);
180 for (
size_t i = 0; i <
layouts.size (); ++i)
185 gdb_assert_not_reached (
"layout not found!?");
278 if (focus ==
nullptr)
280 if (focus ==
nullptr)
292 TUI_SRC_WIN->display_start_addr (gdbarch_p, addr_p);
297 *gdbarch_p =
nullptr;
304 int origin_x_,
int origin_y_)
307 &&
x == origin_x_ &&
y == origin_y_
321 wmove (
handle.get (), 0, 0);
338template<enum tui_win_type V,
class T>
362 if (
name == window->name ())
367 error (_(
"Unknown window type \"%s\""),
name.c_str ());
370 if (result ==
nullptr)
371 error (_(
"Could not create window \"%s\""),
name.c_str ());
386 make_standard_window<CMD_WIN, tui_cmd_window>);
403 std::string name_copy =
name;
407 error (_(
"Window type \"%s\" is built-in"),
name);
409 for (
const char &c : name_copy)
412 error (_(
"invalid whitespace character in window name"));
414 if (!ISALNUM (c) && strchr (
"-_.", c) ==
nullptr)
415 error (_(
"invalid character '%c' in window name"), c);
418 if (!ISALPHA (name_copy[0]))
419 error (_(
"window name must start with a letter, not '%c'"), name_copy[0]);
422 std::move (factory));
427std::unique_ptr<tui_layout_base>
431 return std::unique_ptr<tui_layout_base> (result);
438 bool preserve_cmd_win_size_p)
522 if (strcmp (
get_name (),
"cmd") == 0)
534 split s = {weight, std::move (layout)};
544 split s = {weight, std::unique_ptr<tui_layout_base> (result)};
550std::unique_ptr<tui_layout_base>
556 std::unique_ptr<tui_layout_base> next = item.layout->clone ();
558 result->
m_splits.push_back (std::move (s));
560 return std::unique_ptr<tui_layout_base> (result);
572 bool first_time =
true;
575 int new_min, new_max;
576 item.layout->get_sizes (
height, &new_min, &new_max);
582 *min_value += new_min;
583 *max_value += new_max;
587 *min_value = std::max (*min_value, new_min);
588 *max_value = std::min (*max_value, new_max);
593 tui_debug_printf (
"min_value = %d, max_value = %d", *min_value, *max_value);
603 return m_splits[0].layout->first_edge_has_border_p ();
613 return m_splits.back ().layout->last_edge_has_border_p ();
621 for (
int i = 0; i <
m_splits.size (); ++i)
633 for (
int i = 0; i <
m_splits.size (); ++i)
637 str += string_printf (
"[%d] %d", i,
m_splits[i].weight);
647 (
const std::vector<tui_layout_split::size_info> &
info)
652 for (
int i = 0; i < info.size (); ++i)
653 tui_debug_printf (
" [%d] { size = %d, min = %d, max = %d, share_box = %d }",
654 i, info[i].
size, info[i].min_size,
655 info[i].max_size, info[i].share_box);
666 this,
name, new_size);
671 int found_index = -1;
672 for (
int i = 0; i <
m_splits.size (); ++i)
676 adjusted =
m_splits[i].layout->set_width (
name, new_size);
678 adjusted =
m_splits[i].layout->set_height (
name, new_size);
681 if (adjusted ==
FOUND)
690 if (found_index == -1)
692 int curr_size = (set_width_p
693 ?
m_splits[found_index].layout->width
694 :
m_splits[found_index].layout->height);
695 if (curr_size == new_size)
701 int delta =
m_splits[found_index].weight - new_size;
702 m_splits[found_index].weight = new_size;
711 bool found_window_that_can_grow_p =
true;
712 for (
int i = 0; delta != 0; i = (i + 1) %
m_splits.size ())
714 int index = (found_index + 1 + i) %
m_splits.size ();
715 if (index == found_index)
717 if (!found_window_that_can_grow_p)
719 found_window_that_can_grow_p =
false;
723 int new_min, new_max;
730 if (
m_splits[index].weight > new_min)
734 found_window_that_can_grow_p =
true;
741 if (
m_splits[index].weight < new_max)
745 found_window_that_can_grow_p =
true;
759 warning (_(
"Invalid window width specified"));
761 warning (_(
"Invalid window height specified"));
781 bool preserve_cmd_win_size_p)
797 old_size_info (
int index_,
int min_size_,
int max_size_)
799 min_size (min_size_),
812 gdb::optional<old_size_info> old_cmd_info;
814 std::vector<size_info> info (
m_splits.size ());
825 int total_weight = 0;
826 for (
int i = 0; i <
m_splits.size (); ++i)
828 bool cmd_win_already_exists =
TUI_CMD_WIN !=
nullptr;
836 if (preserve_cmd_win_size_p
837 && cmd_win_already_exists
838 &&
m_splits[i].layout->get_name () !=
nullptr
839 && strcmp (
m_splits[i].layout->get_name (),
"cmd") == 0)
843 old_cmd_info.emplace (i, info[i].min_size, info[i].max_size);
854 info[i].max_size = info[i].min_size;
857 if (info[i].min_size == info[i].max_size)
858 available_size -= info[i].min_size;
868 &&
m_splits[i - 1].layout->last_edge_has_border_p ()
869 &&
m_splits[i].layout->first_edge_has_border_p ())
870 info[i].share_box =
true;
877 gdb_assert (last_index == -1 || total_weight > 0);
883 for (
int i = 0; i <
m_splits.size (); ++i)
885 if (info[i].min_size != info[i].max_size)
888 info[i].size = available_size *
m_splits[i].weight / total_weight;
889 if (info[i].
size > info[i].max_size)
890 info[i].size = info[i].max_size;
891 if (info[i].
size < info[i].min_size)
892 info[i].size = info[i].min_size;
898 used_size += info[i].size;
899 if (info[i].share_box)
903 info[i].size = info[i].min_size;
910 available_size, used_size);
912 total_weight, last_index);
923 if (last_index == -1 && old_cmd_info.has_value ())
924 last_index = old_cmd_info->index;
927 if (available_size != used_size && last_index != -1)
932 bool found_window_that_can_grow_p =
true;
933 for (
int idx = last_index;
934 available_size != used_size;
949 if (idx == last_index)
963 if (old_cmd_info.has_value ()
964 && ((available_size < used_size)
965 || !found_window_that_can_grow_p))
967 info[old_cmd_info->index].min_size = old_cmd_info->min_size;
968 info[old_cmd_info->index].max_size = old_cmd_info->max_size;
970 (
"restoring index %d (cmd) size limits, min = %d, max = %d",
971 old_cmd_info->index, old_cmd_info->min_size,
972 old_cmd_info->max_size);
973 old_cmd_info.reset ();
975 else if (!found_window_that_can_grow_p)
977 found_window_that_can_grow_p =
false;
980 if (available_size > used_size
981 && info[idx].
size < info[idx].max_size)
983 found_window_that_can_grow_p =
true;
987 else if (available_size < used_size
988 && info[idx].
size > info[idx].min_size)
990 found_window_that_can_grow_p =
true;
1000 available_size, used_size);
1002 total_weight, last_index);
1010 for (
int i = 0; i <
m_splits.size (); ++i)
1014 if (size_accum + info[i].
size > maximum)
1015 size_accum = maximum - info[i].size;
1016 else if (info[i].share_box)
1020 preserve_cmd_win_size_p);
1023 preserve_cmd_win_size_p);
1024 size_accum += info[i].size;
1033 for (
int i = 0; i <
m_splits.size (); ++i)
1035 const char *this_name =
m_splits[i].layout->get_name ();
1036 if (this_name ==
nullptr)
1038 else if (strcmp (this_name,
name) == 0
1039 || strcmp (this_name,
CMD_NAME) == 0
1058 item.layout->replace_window (
name, new_window);
1078 item.layout->specification (output, depth + 1);
1093 std::string fp = item.layout->layout_fingerprint ();
1095 return std::string (
m_vertical ?
"V" :
"H") + fp;
1133 gdb::unique_xmalloc_ptr<char>
doc
1134 = xstrprintf (_(
"Apply the \"%s\" layout.\n\
1135This layout was created using:\n\
1136 tui new-layout %s %s"),
1146 layouts.emplace_back (layout);
1182 layouts.emplace_back (layout);
1190 layouts.emplace_back (layout);
1212 if (new_name.empty ())
1213 error (_(
"No layout name specified"));
1214 if (new_name[0] ==
'-')
1215 error (_(
"Layout name cannot start with '-'"));
1217 bool is_vertical =
true;
1218 spec = skip_spaces (spec);
1220 is_vertical =
false;
1222 std::vector<std::unique_ptr<tui_layout_split>> splits;
1224 std::unordered_set<std::string> seen_windows;
1227 spec = skip_spaces (spec);
1228 if (spec[0] ==
'\0')
1234 spec = skip_spaces (spec + 1);
1236 is_vertical =
false;
1241 bool is_close =
false;
1247 if (splits.size () == 1)
1248 error (_(
"Extra '}' in layout specification"));
1256 error (_(
"Unknown window \"%s\""),
name.c_str ());
1257 if (seen_windows.find (
name) != seen_windows.end ())
1258 error (_(
"Window \"%s\" seen twice in layout"),
name.c_str ());
1262 if ((
int) weight != weight)
1263 error (_(
"Weight out of range: %s"), pulongest (weight));
1266 std::unique_ptr<tui_layout_split> last_split
1267 = std::move (splits.back ());
1269 splits.back ()->add_split (std::move (last_split), weight);
1273 splits.back ()->add_window (
name.c_str (), weight);
1274 seen_windows.insert (
name);
1277 if (splits.size () > 1)
1278 error (_(
"Missing '}' in layout specification"));
1279 if (seen_windows.empty ())
1280 error (_(
"New layout does not contain any windows"));
1281 if (seen_windows.find (
CMD_NAME) == seen_windows.end ())
1282 error (_(
"New layout does not contain the \"" CMD_NAME "\" window"));
1284 gdb::unique_xmalloc_ptr<char> cmd_name
1285 = make_unique_xstrdup (new_name.c_str ());
1286 std::unique_ptr<tui_layout_split> new_layout = std::move (splits.back ());
1290 cmd_name.release ();
1291 new_layout.release ();
1303Change the layout of windows.\n\
1304Usage: tui layout prev | next | LAYOUT-NAME"),
1309 _(
"Apply the next TUI layout."),
1312 _(
"Apply the previous TUI layout."),
1315 _(
"Apply the TUI register layout."),
1319 _(
"Create a new TUI layout.\n\
1320Usage: tui new-layout [-horizontal] NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\
1321Create a new TUI layout. The new layout will be named NAME,\n\
1322and can be accessed using \"layout NAME\".\n\
1323The windows will be displayed in the specified order.\n\
1324A WINDOW can also be of the form:\n\
1325 { [-horizontal] NAME WEIGHT [NAME WEIGHT]... }\n\
1326This form indicates a sub-frame.\n\
1327Each WEIGHT is an integer, which holds the relative size\n\
1328to 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)
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
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)
static std::unordered_map< std::string, window_factory > * known_window_types
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()
void tui_apply_current_layout(bool preserve_cmd_win_size_p)
static struct cmd_list_element * layout_list
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::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)