+ /* Two adjacent boxed windows will share a border, making a bit
+ more size available. */
+ if (i > 0
+ && m_splits[i - 1].layout->bottom_boxed_p ()
+ && m_splits[i].layout->top_boxed_p ())
+ info[i].share_box = true;
+ }
+
+ /* Step 2: Compute the size of each sub-layout. Fixed-sized items
+ are given their fixed size, while others are resized according to
+ their weight. */
+ int used_size = 0;
+ for (int i = 0; i < m_splits.size (); ++i)
+ {
+ /* Compute the height and clamp to the allowable range. */
+ info[i].size = available_size * m_splits[i].weight / total_weight;
+ if (info[i].size > info[i].max_size)
+ info[i].size = info[i].max_size;
+ if (info[i].size < info[i].min_size)
+ info[i].size = info[i].min_size;
+ /* If there is any leftover size, just redistribute it to the
+ last resizeable window, by dropping it from the allocated
+ size. We could try to be fancier here perhaps, by
+ redistributing this size among all windows, not just the
+ last window. */
+ if (info[i].min_size != info[i].max_size)
+ {
+ used_size += info[i].size;
+ if (info[i].share_box)
+ --used_size;
+ }
+ }
+
+ /* Allocate any leftover size. */
+ if (available_size >= used_size && last_index != -1)
+ info[last_index].size += available_size - used_size;
+
+ /* Step 3: Resize. */
+ int size_accum = 0;
+ const int maximum = m_vertical ? height : width;
+ for (int i = 0; i < m_splits.size (); ++i)
+ {
+ /* If we fall off the bottom, just make allocations overlap.
+ GIGO. */
+ if (size_accum + info[i].size > maximum)
+ size_accum = maximum - info[i].size;
+ else if (info[i].share_box)
+ --size_accum;
+ if (m_vertical)
+ m_splits[i].layout->apply (x, y + size_accum, width, info[i].size);
+ else
+ m_splits[i].layout->apply (x + size_accum, y, info[i].size, height);
+ size_accum += info[i].size;
+ }
+
+ m_applied = true;
+}
+
+/* See tui-layout.h. */
+
+void
+tui_layout_split::remove_windows (const char *name)
+{
+ for (int i = 0; i < m_splits.size (); ++i)
+ {
+ const char *this_name = m_splits[i].layout->get_name ();
+ if (this_name == nullptr)
+ m_splits[i].layout->remove_windows (name);
+ else if (strcmp (this_name, name) == 0
+ || strcmp (this_name, CMD_NAME) == 0
+ || strcmp (this_name, STATUS_NAME) == 0)
+ {
+ /* Keep. */
+ }
+ else
+ {
+ m_splits.erase (m_splits.begin () + i);
+ --i;
+ }
+ }
+}
+
+/* See tui-layout.h. */
+
+void
+tui_layout_split::replace_window (const char *name, const char *new_window)
+{
+ for (auto &item : m_splits)
+ item.layout->replace_window (name, new_window);
+}
+
+/* See tui-layout.h. */
+
+void
+tui_layout_split::specification (ui_file *output, int depth)
+{
+ if (depth > 0)
+ fputs_unfiltered ("{", output);
+
+ if (!m_vertical)
+ fputs_unfiltered ("-horizontal ", output);
+
+ bool first = true;
+ for (auto &item : m_splits)
+ {
+ if (!first)
+ fputs_unfiltered (" ", output);
+ first = false;
+ item.layout->specification (output, depth + 1);
+ fprintf_unfiltered (output, " %d", item.weight);
+ }
+
+ if (depth > 0)
+ fputs_unfiltered ("}", output);
+}
+
+/* Destroy the layout associated with SELF. */
+
+static void
+destroy_layout (struct cmd_list_element *self, void *context)
+{
+ tui_layout_split *layout = (tui_layout_split *) context;
+ size_t index = find_layout (layout);
+ layouts.erase (layouts.begin () + index);
+}
+
+/* List holding the sub-commands of "layout". */
+
+static struct cmd_list_element *layout_list;
+
+/* Add a "layout" command with name NAME that switches to LAYOUT. */
+
+static struct cmd_list_element *
+add_layout_command (const char *name, tui_layout_split *layout)
+{
+ struct cmd_list_element *cmd;
+
+ string_file spec;
+ layout->specification (&spec, 0);
+
+ gdb::unique_xmalloc_ptr<char> doc
+ (xstrprintf (_("Apply the \"%s\" layout.\n\
+This layout was created using:\n\
+ tui new-layout %s %s"),
+ name, name, spec.c_str ()));
+
+ cmd = add_cmd (name, class_tui, nullptr, doc.get (), &layout_list);
+ set_cmd_context (cmd, layout);
+ /* There is no API to set this. */
+ cmd->func = tui_apply_layout;
+ cmd->destroyer = destroy_layout;
+ cmd->doc_allocated = 1;
+ doc.release ();
+ layouts.emplace_back (layout);
+
+ return cmd;
+}
+
+/* Initialize the standard layouts. */
+
+static void
+initialize_layouts ()
+{
+ tui_layout_split *layout;
+
+ layout = new tui_layout_split ();
+ layout->add_window (SRC_NAME, 2);
+ layout->add_window (STATUS_NAME, 0);
+ layout->add_window (CMD_NAME, 1);
+ add_layout_command (SRC_NAME, layout);
+
+ layout = new tui_layout_split ();
+ layout->add_window (DISASSEM_NAME, 2);
+ layout->add_window (STATUS_NAME, 0);
+ layout->add_window (CMD_NAME, 1);
+ add_layout_command (DISASSEM_NAME, layout);
+
+ layout = new tui_layout_split ();
+ layout->add_window (SRC_NAME, 1);
+ layout->add_window (DISASSEM_NAME, 1);
+ layout->add_window (STATUS_NAME, 0);
+ layout->add_window (CMD_NAME, 1);
+ add_layout_command ("split", layout);
+
+ layout = new tui_layout_split ();
+ layout->add_window (DATA_NAME, 1);
+ layout->add_window (SRC_NAME, 1);
+ layout->add_window (STATUS_NAME, 0);
+ layout->add_window (CMD_NAME, 1);
+ layouts.emplace_back (layout);
+ src_regs_layout = layout;
+
+ layout = new tui_layout_split ();
+ layout->add_window (DATA_NAME, 1);
+ layout->add_window (DISASSEM_NAME, 1);
+ layout->add_window (STATUS_NAME, 0);
+ layout->add_window (CMD_NAME, 1);
+ layouts.emplace_back (layout);
+ asm_regs_layout = layout;