public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 21/24] Make some tui_source_window_base members "protected"
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (19 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 02/24] Simplify tui_add_win_to_layout Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 08/24] Add the "tui new-layout" command Tom Tromey
                   ` (3 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This renames a few members of tui_source_window_base, and makes them
"protected".

2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-layout.c (extract_display_start_addr): Rewrite.
	* tui/tui-disasm.h (struct tui_disasm_window)
	<display_start_addr>: Declare.
	* tui/tui-source.h (struct tui_source_window)
	<display_start_addr>: Declare.
	* tui/tui-winsource.h (struct tui_source_window_base)
	<show_source_line, display_start_addr>: New methods.
	<m_horizontal_offset, m_start_line_or_addr, m_gdbarch, m_content>:
	Rename and move to protected section.
	* tui/tui-winsource.c (tui_source_window_base::update_source_window)
	(tui_source_window_base::do_erase_source_content): Update.
	(tui_source_window_base::show_source_line): Now a method.
	(tui_source_window_base::show_source_content)
	(tui_source_window_base::tui_source_window_base)
	(tui_source_window_base::rerender)
	(tui_source_window_base::refill)
	(tui_source_window_base::do_scroll_horizontal)
	(tui_source_window_base::set_is_exec_point_at)
	(tui_source_window_base::update_breakpoint_info)
	(tui_source_window_base::update_exec_info): Update.
	* tui/tui-source.c (tui_source_window::set_contents)
	(tui_source_window::showing_source_p)
	(tui_source_window::do_scroll_vertical)
	(tui_source_window::location_matches_p)
	(tui_source_window::line_is_displayed): Update.
	(tui_source_window::display_start_addr): New method.
	* tui/tui-disasm.c (tui_disasm_window::set_contents)
	(tui_disasm_window::do_scroll_vertical)
	(tui_disasm_window::location_matches_p): Update.
	(tui_disasm_window::display_start_addr): New method.

Change-Id: I74d72b9da5f458664427db643a108634690c6e19
---
 gdb/ChangeLog           | 33 +++++++++++++++++
 gdb/tui/tui-disasm.c    | 40 ++++++++++++---------
 gdb/tui/tui-disasm.h    |  3 ++
 gdb/tui/tui-layout.c    | 22 +++---------
 gdb/tui/tui-source.c    | 43 ++++++++++++++---------
 gdb/tui/tui-source.h    |  3 ++
 gdb/tui/tui-winsource.c | 78 ++++++++++++++++++++---------------------
 gdb/tui/tui-winsource.h | 23 +++++++-----
 8 files changed, 148 insertions(+), 97 deletions(-)

diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c
index f482086ca2e..741d0cad222 100644
--- a/gdb/tui/tui-disasm.c
+++ b/gdb/tui/tui-disasm.c
@@ -203,7 +203,7 @@ tui_disasm_window::set_contents (struct gdbarch *arch,
 				 const struct symtab_and_line &sal)
 {
   int i;
-  int offset = horizontal_offset;
+  int offset = m_horizontal_offset;
   int max_lines, line_width;
   CORE_ADDR cur_pc;
   struct tui_locator_window *locator = tui_locator_win_info_ptr ();
@@ -214,9 +214,9 @@ tui_disasm_window::set_contents (struct gdbarch *arch,
   if (pc == 0)
     return false;
 
-  gdbarch = arch;
-  start_line_or_addr.loa = LOA_ADDRESS;
-  start_line_or_addr.u.addr = pc;
+  m_gdbarch = arch;
+  m_start_line_or_addr.loa = LOA_ADDRESS;
+  m_start_line_or_addr.u.addr = pc;
   cur_pc = locator->addr;
 
   /* Window size, excluding highlight box.  */
@@ -226,16 +226,16 @@ tui_disasm_window::set_contents (struct gdbarch *arch,
   /* Get temporary table that will hold all strings (addr & insn).  */
   std::vector<tui_asm_line> asm_lines (max_lines);
   size_t addr_size = 0;
-  tui_disassemble (gdbarch, asm_lines, pc, 0, max_lines, &addr_size);
+  tui_disassemble (m_gdbarch, asm_lines, pc, 0, max_lines, &addr_size);
 
   /* Align instructions to the same column.  */
   insn_pos = (1 + (addr_size / tab_len)) * tab_len;
 
   /* Now construct each line.  */
-  content.resize (max_lines);
+  m_content.resize (max_lines);
   for (i = 0; i < max_lines; i++)
     {
-      tui_source_element *src = &content[i];
+      tui_source_element *src = &m_content[i];
 
       std::string line
 	= (asm_lines[i].addr_string
@@ -321,11 +321,11 @@ tui_get_low_disassembly_address (struct gdbarch *gdbarch,
 void
 tui_disasm_window::do_scroll_vertical (int num_to_scroll)
 {
-  if (!content.empty ())
+  if (!m_content.empty ())
     {
       CORE_ADDR pc;
 
-      pc = start_line_or_addr.u.addr;
+      pc = m_start_line_or_addr.u.addr;
       if (num_to_scroll >= 0)
 	num_to_scroll++;
       else
@@ -333,16 +333,16 @@ tui_disasm_window::do_scroll_vertical (int num_to_scroll)
 
       symtab_and_line sal {};
       sal.pspace = current_program_space;
-      sal.pc = tui_find_disassembly_address (gdbarch, pc, num_to_scroll);
-      update_source_window_as_is (gdbarch, sal);
+      sal.pc = tui_find_disassembly_address (m_gdbarch, pc, num_to_scroll);
+      update_source_window_as_is (m_gdbarch, sal);
     }
 }
 
 bool
 tui_disasm_window::location_matches_p (struct bp_location *loc, int line_no)
 {
-  return (content[line_no].line_or_addr.loa == LOA_ADDRESS
-	  && content[line_no].line_or_addr.u.addr == loc->address);
+  return (m_content[line_no].line_or_addr.loa == LOA_ADDRESS
+	  && m_content[line_no].line_or_addr.u.addr == loc->address);
 }
 
 bool
@@ -352,11 +352,11 @@ tui_disasm_window::addr_is_displayed (CORE_ADDR addr) const
   int threshold = SCROLL_THRESHOLD;
 
   int i = 0;
-  while (i < content.size () - threshold && !is_displayed)
+  while (i < m_content.size () - threshold && !is_displayed)
     {
       is_displayed
-	= (content[i].line_or_addr.loa == LOA_ADDRESS
-	   && content[i].line_or_addr.u.addr == addr);
+	= (m_content[i].line_or_addr.loa == LOA_ADDRESS
+	   && m_content[i].line_or_addr.u.addr == addr);
       i++;
     }
 
@@ -394,3 +394,11 @@ tui_disasm_window::maybe_update (struct frame_info *fi, symtab_and_line sal)
       set_is_exec_point_at (a);
     }
 }
+
+void
+tui_disasm_window::display_start_addr (struct gdbarch **gdbarch_p,
+				       CORE_ADDR *addr_p)
+{
+  *gdbarch_p = m_gdbarch;
+  *addr_p = m_start_line_or_addr.u.addr;
+}
diff --git a/gdb/tui/tui-disasm.h b/gdb/tui/tui-disasm.h
index dd020310746..0eb6c9e7290 100644
--- a/gdb/tui/tui-disasm.h
+++ b/gdb/tui/tui-disasm.h
@@ -48,6 +48,9 @@ struct tui_disasm_window : public tui_source_window_base
     do_erase_source_content (_("[ No Assembly Available ]"));
   }
 
+  void display_start_addr (struct gdbarch **gdbarch_p,
+			   CORE_ADDR *addr_p) override;
+
 protected:
 
   void do_scroll_vertical (int num_to_scroll) override;
diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index d55660f89f6..352de57f551 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -274,27 +274,15 @@ tui_remove_some_windows ()
 static void
 extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
 {
-  struct gdbarch *gdbarch = nullptr;
-  CORE_ADDR addr = 0;
-  CORE_ADDR pc;
-  struct symtab_and_line cursal = get_current_source_symtab_and_line ();
-
   if (TUI_SRC_WIN != nullptr)
-    {
-      gdbarch = TUI_SRC_WIN->gdbarch;
-      find_line_pc (cursal.symtab,
-		    TUI_SRC_WIN->start_line_or_addr.u.line_no,
-		    &pc);
-      addr = pc;
-    }
+    TUI_SRC_WIN->display_start_addr (gdbarch_p, addr_p);
   else if (TUI_DISASM_WIN != nullptr)
+    TUI_DISASM_WIN->display_start_addr (gdbarch_p, addr_p);
+  else
     {
-      gdbarch = TUI_DISASM_WIN->gdbarch;
-      addr = TUI_DISASM_WIN->start_line_or_addr.u.addr;
+      *gdbarch_p = nullptr;
+      *addr_p = 0;
     }
-
-  *gdbarch_p = gdbarch;
-  *addr_p = addr;
 }
 
 void
diff --git a/gdb/tui/tui-source.c b/gdb/tui/tui-source.c
index e028b724d23..ead4c7cf522 100644
--- a/gdb/tui/tui-source.c
+++ b/gdb/tui/tui-source.c
@@ -74,9 +74,9 @@ tui_source_window::set_contents (struct gdbarch *arch,
   m_fullname = make_unique_xstrdup (symtab_to_fullname (s));
 
   cur_line = 0;
-  gdbarch = get_objfile_arch (SYMTAB_OBJFILE (s));
-  start_line_or_addr.loa = LOA_LINE;
-  cur_line_no = start_line_or_addr.u.line_no = line_no;
+  m_gdbarch = get_objfile_arch (SYMTAB_OBJFILE (s));
+  m_start_line_or_addr.loa = LOA_LINE;
+  cur_line_no = m_start_line_or_addr.u.line_no = line_no;
 
   int digits = 0;
   if (compact_source)
@@ -88,16 +88,15 @@ tui_source_window::set_contents (struct gdbarch *arch,
     }
 
   const char *iter = srclines.c_str ();
-  content.resize (nlines);
+  m_content.resize (nlines);
   while (cur_line < nlines)
     {
-      struct tui_source_element *element
-	= &content[cur_line];
+      struct tui_source_element *element = &m_content[cur_line];
 
       std::string text;
       if (*iter != '\0')
 	text = tui_copy_source_line (&iter, cur_line_no,
-				     horizontal_offset,
+				     m_horizontal_offset,
 				     line_width, digits);
 
       /* Set whether element is the execution point
@@ -109,7 +108,7 @@ tui_source_window::set_contents (struct gdbarch *arch,
 			 symtab_to_fullname (s)) == 0
 	   && cur_line_no == locator->line_no);
 
-      content[cur_line].line = std::move (text);
+      m_content[cur_line].line = std::move (text);
 
       cur_line++;
       cur_line_no++;
@@ -124,7 +123,7 @@ tui_source_window::set_contents (struct gdbarch *arch,
 bool
 tui_source_window::showing_source_p (const char *fullname) const
 {
-  return (!content.empty ()
+  return (!m_content.empty ()
 	  && (filename_cmp (tui_locator_win_info_ptr ()->full_name.c_str (),
 			    fullname) == 0));
 }
@@ -134,7 +133,7 @@ tui_source_window::showing_source_p (const char *fullname) const
 void
 tui_source_window::do_scroll_vertical (int num_to_scroll)
 {
-  if (!content.empty ())
+  if (!m_content.empty ())
     {
       struct tui_line_or_address l;
       struct symtab *s;
@@ -146,12 +145,12 @@ tui_source_window::do_scroll_vertical (int num_to_scroll)
 	s = cursal.symtab;
 
       l.loa = LOA_LINE;
-      l.u.line_no = start_line_or_addr.u.line_no
+      l.u.line_no = m_start_line_or_addr.u.line_no
 	+ num_to_scroll;
       const std::vector<off_t> *offsets;
       if (g_source_cache.get_line_charpos (s, &offsets)
 	  && l.u.line_no > offsets->size ())
-	l.u.line_no = start_line_or_addr.u.line_no;
+	l.u.line_no = m_start_line_or_addr.u.line_no;
       if (l.u.line_no <= 0)
 	l.u.line_no = 1;
 
@@ -162,8 +161,8 @@ tui_source_window::do_scroll_vertical (int num_to_scroll)
 bool
 tui_source_window::location_matches_p (struct bp_location *loc, int line_no)
 {
-  return (content[line_no].line_or_addr.loa == LOA_LINE
-	  && content[line_no].line_or_addr.u.line_no == loc->line_number
+  return (m_content[line_no].line_or_addr.loa == LOA_LINE
+	  && m_content[line_no].line_or_addr.u.line_no == loc->line_number
 	  && loc->symtab != NULL
 	  && filename_cmp (m_fullname.get (),
 			   symtab_to_fullname (loc->symtab)) == 0);
@@ -177,11 +176,11 @@ tui_source_window::line_is_displayed (int line) const
   bool is_displayed = false;
   int threshold = SCROLL_THRESHOLD;
   int i = 0;
-  while (i < content.size () - threshold && !is_displayed)
+  while (i < m_content.size () - threshold && !is_displayed)
     {
       is_displayed
-	= (content[i].line_or_addr.loa == LOA_LINE
-	   && content[i].line_or_addr.u.line_no == line);
+	= (m_content[i].line_or_addr.loa == LOA_LINE
+	   && m_content[i].line_or_addr.u.line_no == line);
       i++;
     }
 
@@ -212,3 +211,13 @@ tui_source_window::maybe_update (struct frame_info *fi, symtab_and_line sal)
       set_is_exec_point_at (l);
     }
 }
+
+void
+tui_source_window::display_start_addr (struct gdbarch **gdbarch_p,
+				       CORE_ADDR *addr_p)
+{
+  struct symtab_and_line cursal = get_current_source_symtab_and_line ();
+
+  *gdbarch_p = m_gdbarch;
+  find_line_pc (cursal.symtab, m_start_line_or_addr.u.line_no, addr_p);
+}
diff --git a/gdb/tui/tui-source.h b/gdb/tui/tui-source.h
index 58dc5e88cf7..1df84cf304c 100644
--- a/gdb/tui/tui-source.h
+++ b/gdb/tui/tui-source.h
@@ -53,6 +53,9 @@ struct tui_source_window : public tui_source_window_base
     do_erase_source_content (_("[ No Source Available ]"));
   }
 
+  void display_start_addr (struct gdbarch **gdbarch_p,
+			   CORE_ADDR *addr_p) override;
+
 protected:
 
   void do_scroll_vertical (int num_to_scroll) override;
diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c
index bd7a34ebbd5..592115a7347 100644
--- a/gdb/tui/tui-winsource.c
+++ b/gdb/tui/tui-winsource.c
@@ -169,7 +169,7 @@ tui_source_window_base::update_source_window
   (struct gdbarch *gdbarch,
    const struct symtab_and_line &sal)
 {
-  horizontal_offset = 0;
+  m_horizontal_offset = 0;
   update_source_window_as_is (gdbarch, sal);
 }
 
@@ -228,7 +228,7 @@ tui_source_window_base::do_erase_source_content (const char *str)
   int x_pos;
   int half_width = (width - 2) / 2;
 
-  content.clear ();
+  m_content.clear ();
   if (handle != NULL)
     {
       werase (handle.get ());
@@ -249,37 +249,37 @@ tui_source_window_base::do_erase_source_content (const char *str)
 
 
 /* Redraw the complete line of a source or disassembly window.  */
-static void
-tui_show_source_line (struct tui_source_window_base *win_info, int lineno)
+void
+tui_source_window_base::show_source_line (int lineno)
 {
   struct tui_source_element *line;
   int x;
 
-  line = &win_info->content[lineno - 1];
+  line = &m_content[lineno - 1];
   if (line->is_exec_point)
-    tui_set_reverse_mode (win_info->handle.get (), true);
+    tui_set_reverse_mode (handle.get (), true);
 
-  wmove (win_info->handle.get (), lineno, TUI_EXECINFO_SIZE);
-  tui_puts (line->line.c_str (), win_info->handle.get ());
+  wmove (handle.get (), lineno, TUI_EXECINFO_SIZE);
+  tui_puts (line->line.c_str (), handle.get ());
   if (line->is_exec_point)
-    tui_set_reverse_mode (win_info->handle.get (), false);
+    tui_set_reverse_mode (handle.get (), false);
 
   /* Clear to end of line but stop before the border.  */
-  x = getcurx (win_info->handle.get ());
-  while (x + 1 < win_info->width)
+  x = getcurx (handle.get ());
+  while (x + 1 < width)
     {
-      waddch (win_info->handle.get (), ' ');
-      x = getcurx (win_info->handle.get ());
+      waddch (handle.get (), ' ');
+      x = getcurx (handle.get ());
     }
 }
 
 void
 tui_source_window_base::show_source_content ()
 {
-  gdb_assert (!content.empty ());
+  gdb_assert (!m_content.empty ());
 
-  for (int lineno = 1; lineno <= content.size (); lineno++)
-    tui_show_source_line (this, lineno);
+  for (int lineno = 1; lineno <= m_content.size (); lineno++)
+    show_source_line (lineno);
 
   check_and_display_highlight_if_needed ();
   refresh_window ();
@@ -287,8 +287,8 @@ tui_source_window_base::show_source_content ()
 
 tui_source_window_base::tui_source_window_base ()
 {
-  start_line_or_addr.loa = LOA_ADDRESS;
-  start_line_or_addr.u.addr = 0;
+  m_start_line_or_addr.loa = LOA_ADDRESS;
+  m_start_line_or_addr.u.addr = 0;
 
   gdb::observers::source_styling_changed.attach
     (std::bind (&tui_source_window::style_changed, this),
@@ -312,16 +312,16 @@ tui_source_window_base::update_tab_width ()
 void
 tui_source_window_base::rerender ()
 {
-  if (!content.empty ())
+  if (!m_content.empty ())
     {
       struct symtab_and_line cursal
 	= get_current_source_symtab_and_line ();
 
-      if (start_line_or_addr.loa == LOA_LINE)
-	cursal.line = start_line_or_addr.u.line_no;
+      if (m_start_line_or_addr.loa == LOA_LINE)
+	cursal.line = m_start_line_or_addr.u.line_no;
       else
-	cursal.pc = start_line_or_addr.u.addr;
-      update_source_window (gdbarch, cursal);
+	cursal.pc = m_start_line_or_addr.u.addr;
+      update_source_window (m_gdbarch, cursal);
     }
   else if (deprecated_safe_get_selected_frame () != NULL)
     {
@@ -356,12 +356,12 @@ tui_source_window_base::refill ()
   if (sal.pspace == nullptr)
     sal.pspace = current_program_space;
 
-  if (start_line_or_addr.loa == LOA_LINE)
-    sal.line = start_line_or_addr.u.line_no;
+  if (m_start_line_or_addr.loa == LOA_LINE)
+    sal.line = m_start_line_or_addr.u.line_no;
   else
-    sal.pc = start_line_or_addr.u.addr;
+    sal.pc = m_start_line_or_addr.u.addr;
 
-  update_source_window_as_is (gdbarch, sal);
+  update_source_window_as_is (m_gdbarch, sal);
 }
 
 /* Scroll the source forward or backward horizontally.  */
@@ -369,12 +369,12 @@ tui_source_window_base::refill ()
 void
 tui_source_window_base::do_scroll_horizontal (int num_to_scroll)
 {
-  if (!content.empty ())
+  if (!m_content.empty ())
     {
-      int offset = horizontal_offset + num_to_scroll;
+      int offset = m_horizontal_offset + num_to_scroll;
       if (offset < 0)
 	offset = 0;
-      horizontal_offset = offset;
+      m_horizontal_offset = offset;
       refill ();
     }
 }
@@ -390,11 +390,11 @@ tui_source_window_base::set_is_exec_point_at (struct tui_line_or_address l)
   int i;
 
   i = 0;
-  while (i < content.size ())
+  while (i < m_content.size ())
     {
       bool new_state;
       struct tui_line_or_address content_loa =
-	content[i].line_or_addr;
+	m_content[i].line_or_addr;
 
       if (content_loa.loa == l.loa
 	  && ((l.loa == LOA_LINE && content_loa.u.line_no == l.u.line_no)
@@ -402,11 +402,11 @@ tui_source_window_base::set_is_exec_point_at (struct tui_line_or_address l)
         new_state = true;
       else
 	new_state = false;
-      if (new_state != content[i].is_exec_point)
+      if (new_state != m_content[i].is_exec_point)
         {
           changed = true;
-          content[i].is_exec_point = new_state;
-          tui_show_source_line (this, i + 1);
+          m_content[i].is_exec_point = new_state;
+          show_source_line (i + 1);
         }
       i++;
     }
@@ -440,11 +440,11 @@ tui_source_window_base::update_breakpoint_info
   int i;
   bool need_refresh = false;
 
-  for (i = 0; i < content.size (); i++)
+  for (i = 0; i < m_content.size (); i++)
     {
       struct tui_source_element *line;
 
-      line = &content[i];
+      line = &m_content[i];
       if (current_only && !line->is_exec_point)
          continue;
 
@@ -493,9 +493,9 @@ void
 tui_source_window_base::update_exec_info ()
 {
   update_breakpoint_info (nullptr, true);
-  for (int i = 0; i < content.size (); i++)
+  for (int i = 0; i < m_content.size (); i++)
     {
-      struct tui_source_element *src_element = &content[i];
+      struct tui_source_element *src_element = &m_content[i];
       char element[TUI_EXECINFO_SIZE] = "   ";
 
       /* Now update the exec info content based upon the state
diff --git a/gdb/tui/tui-winsource.h b/gdb/tui/tui-winsource.h
index 4ac20d80502..501dd31ccfd 100644
--- a/gdb/tui/tui-winsource.h
+++ b/gdb/tui/tui-winsource.h
@@ -90,6 +90,18 @@ protected:
   virtual bool set_contents (struct gdbarch *gdbarch,
 			     const struct symtab_and_line &sal) = 0;
 
+  /* Redraw the complete line of a source or disassembly window.  */
+  void show_source_line (int lineno);
+
+  /* Used for horizontal scroll.  */
+  int m_horizontal_offset = 0;
+  struct tui_line_or_address m_start_line_or_addr;
+
+  /* Architecture associated with code at this location.  */
+  struct gdbarch *m_gdbarch = nullptr;
+
+  std::vector<tui_source_element> m_content;
+
 public:
 
   /* Refill the source window's source cache and update it.  If this
@@ -125,14 +137,9 @@ public:
   /* Erase the source content.  */
   virtual void erase_source_content () = 0;
 
-  /* Used for horizontal scroll.  */
-  int horizontal_offset = 0;
-  struct tui_line_or_address start_line_or_addr;
-
-  /* Architecture associated with code at this location.  */
-  struct gdbarch *gdbarch = nullptr;
-
-  std::vector<tui_source_element> content;
+  /* Return the start address and gdbarch.  */
+  virtual void display_start_addr (struct gdbarch **gdbarch_p,
+				   CORE_ADDR *addr_p) = 0;
 
 private:
 
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 04/24] Simplify TUI C-x 2 binding
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (13 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 01/24] Use TUI_DISASM_WIN instead of tui_win_list array Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 15/24] Remove tui_delete_invisible_windows and tui_make_all_invisible Tom Tromey
                   ` (9 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

The TUI "C-x 2" binding tries to switch to a different layout based on
the current layout.  Once user-defined layouts are available, this
won't really make sense.  I wasn't entirely sure how to handle this.

This patch changes the binding to simply cycle through the existing
layouts.  I considered this a reasonable, though not ideal,
compromise.

gdb/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui.c (tui_rl_change_windows): Call tui_next_layout.
	* tui/tui-layout.h (tui_next_layout): Declare.
	* tui/tui-layout.c (tui_next_layout): New function.

Change-Id: Ic101f0e3831a4235a048b3090ef60f025f7449bb
---
 gdb/ChangeLog        |  6 ++++++
 gdb/tui/tui-layout.c |  7 +++++++
 gdb/tui/tui-layout.h |  3 +++
 gdb/tui/tui.c        | 38 ++------------------------------------
 4 files changed, 18 insertions(+), 36 deletions(-)

diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index 8be98e9ba48..016cab649d4 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -276,6 +276,13 @@ tui_layout_command (const char *layout_name, int from_tty)
   tui_set_layout (new_layout);
 }
 
+/* See tui-layout.h.  */
+
+void
+tui_next_layout ()
+{
+  tui_layout_command ("next", 0);
+}
 
 static void
 extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h
index 37f07c24e4f..7e4b7b7a816 100644
--- a/gdb/tui/tui-layout.h
+++ b/gdb/tui/tui-layout.h
@@ -181,6 +181,9 @@ extern void tui_add_win_to_layout (enum tui_win_type);
 
 extern void tui_set_layout (enum tui_layout_type);
 
+/* Switch to the next layout.  */
+extern void tui_next_layout ();
+
 /* Apply the current layout.  */
 extern void tui_apply_current_layout ();
 
diff --git a/gdb/tui/tui.c b/gdb/tui/tui.c
index 7ff5825ece2..780d3bae9c0 100644
--- a/gdb/tui/tui.c
+++ b/gdb/tui/tui.c
@@ -139,8 +139,7 @@ tui_rl_switch_mode (int notused1, int notused2)
 /* TUI readline command.
    Change the TUI layout to show a next layout.
    This function is bound to CTRL-X 2.  It is intended to provide
-   a functionality close to the Emacs split-window command.  We
-   always show two windows (src+asm), (src+regs) or (asm+regs).  */
+   a functionality close to the Emacs split-window command.  */
 static int
 tui_rl_change_windows (int notused1, int notused2)
 {
@@ -148,41 +147,8 @@ tui_rl_change_windows (int notused1, int notused2)
     tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
 
   if (tui_active)
-    {
-      enum tui_layout_type new_layout;
-
-      new_layout = tui_current_layout ();
-
-      /* Select a new layout to have a rolling layout behavior with
-	 always two windows (except when undefined).  */
-      switch (new_layout)
-	{
-	case SRC_COMMAND:
-	  new_layout = SRC_DISASSEM_COMMAND;
-	  break;
-
-	case DISASSEM_COMMAND:
-	  new_layout = SRC_DISASSEM_COMMAND;
-	  break;
-
-	case SRC_DATA_COMMAND:
-	  new_layout = SRC_DISASSEM_COMMAND;
-	  break;
-
-	case SRC_DISASSEM_COMMAND:
-	  new_layout = DISASSEM_DATA_COMMAND;
-	  break;
-	  
-	case DISASSEM_DATA_COMMAND:
-	  new_layout = SRC_DATA_COMMAND;
-	  break;
+    tui_next_layout ();
 
-	default:
-	  new_layout = SRC_COMMAND;
-	  break;
-	}
-      tui_set_layout (new_layout);
-    }
   return 0;
 }
 
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 12/24] Change TUI window iteration
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (8 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 18/24] Remove tui_set_win_focus_to Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 11/24] Add horizontal splitting to TUI layout Tom Tromey
                   ` (14 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This changes the TUI to track all the instantiated windows in a new
global vector.  After this, iteration over TUI windows is done by
simply iterating over this vector.

This approach makes it simpler to define new window types.  In
particular, a subsequent patch will add the ability to define a TUI
window from Python.

Note that this series will not remove tui_win_list.  This will
continue to exist in parallel, only because it was simpler to leave
this alone.  Perhaps it could still be removed in the future.

2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-winsource.h (struct tui_source_window_iterator)
	<inner_iterator>: New etytypedef.
	<tui_source_window_iterator>: Take "end" parameter.
	<tui_source_window_iterator>: Take iterator.
	<operator*, advance>: Update.
	<m_iter>: Change type.
	<m_end>: New field.
	(struct tui_source_windows) <begin, end>: Update.
	* tui/tui-layout.c (tui_windows): New global.
	(tui_apply_current_layout): Clear tui_windows.
	(tui_layout_window::apply): Update tui_windows.
	* tui/tui-data.h (tui_windows): Declare.
	(all_tui_windows): Now inline function.
	(class tui_window_iterator, struct all_tui_windows): Remove.

Change-Id: I6ab77976d6326f427178f725434f8f82046e0bbf
---
 gdb/ChangeLog           | 17 ++++++++++
 gdb/tui/tui-data.h      | 74 +++++------------------------------------
 gdb/tui/tui-layout.c    |  6 ++++
 gdb/tui/tui-winsource.h | 26 +++++++++------
 4 files changed, 47 insertions(+), 76 deletions(-)

diff --git a/gdb/tui/tui-data.h b/gdb/tui/tui-data.h
index 570b55b1962..a5e4940666c 100644
--- a/gdb/tui/tui-data.h
+++ b/gdb/tui/tui-data.h
@@ -231,74 +231,16 @@ extern struct tui_win_info *tui_win_list[MAX_MAJOR_WINDOWS];
 #define TUI_DATA_WIN    ((tui_data_window *) tui_win_list[DATA_WIN])
 #define TUI_CMD_WIN     ((tui_cmd_window *) tui_win_list[CMD_WIN])
 
-/* An iterator that iterates over all windows.  */
+/* All the windows that are currently instantiated, in layout
+   order.  */
+extern std::vector<tui_win_info *> tui_windows;
 
-class tui_window_iterator
+/* Return a range adapter for iterating over TUI windows.  */
+static inline std::vector<tui_win_info *> &
+all_tui_windows ()
 {
-public:
-
-  typedef tui_window_iterator self_type;
-  typedef struct tui_win_info *value_type;
-  typedef struct tui_win_info *&reference;
-  typedef struct tui_win_info **pointer;
-  typedef std::forward_iterator_tag iterator_category;
-  typedef int difference_type;
-
-  explicit tui_window_iterator (enum tui_win_type type)
-    : m_type (type)
-  {
-    advance ();
-  }
-
-  tui_window_iterator ()
-    : m_type (MAX_MAJOR_WINDOWS)
-  {
-  }
-
-  bool operator!= (const self_type &other) const
-  {
-    return m_type != other.m_type;
-  }
-
-  value_type operator* () const
-  {
-    gdb_assert (m_type < MAX_MAJOR_WINDOWS);
-    return tui_win_list[m_type];
-  }
-
-  self_type &operator++ ()
-  {
-    ++m_type;
-    advance ();
-    return *this;
-  }
-
-private:
-
-  void advance ()
-  {
-    while (m_type < MAX_MAJOR_WINDOWS && tui_win_list[m_type] == nullptr)
-      ++m_type;
-  }
-
-  int m_type;
-};
-
-/* A range adapter for iterating over TUI windows.  */
-
-struct all_tui_windows
-{
-  tui_window_iterator begin () const
-  {
-    return tui_window_iterator (SRC_WIN);
-  }
-
-  tui_window_iterator end () const
-  {
-    return tui_window_iterator ();
-  }
-};
-
+  return tui_windows;
+}
 
 /* Data Manipulation Functions.  */
 extern int tui_term_height (void);
diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index f33317beee8..9ad91ce713b 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -61,11 +61,15 @@ static tui_layout_split *applied_skeleton;
 static tui_layout_split *src_regs_layout;
 static tui_layout_split *asm_regs_layout;
 
+/* See tui-data.h.  */
+std::vector<tui_win_info *> tui_windows;
+
 /* See tui-layout.h.  */
 
 void
 tui_apply_current_layout ()
 {
+  tui_windows.clear ();
   applied_layout->apply (0, 0, tui_term_width (), tui_term_height ());
 }
 
@@ -350,6 +354,8 @@ tui_layout_window::apply (int x_, int y_, int width_, int height_)
   height = height_;
   gdb_assert (m_window != nullptr);
   m_window->resize (height, width, x, y);
+  if (dynamic_cast<tui_win_info *> (m_window) != nullptr)
+    tui_windows.push_back ((tui_win_info *) m_window);
 }
 
 /* See tui-layout.h.  */
diff --git a/gdb/tui/tui-winsource.h b/gdb/tui/tui-winsource.h
index 87bd3b61d97..cae535fab07 100644
--- a/gdb/tui/tui-winsource.h
+++ b/gdb/tui/tui-winsource.h
@@ -153,6 +153,8 @@ struct tui_source_window_iterator
 {
 public:
 
+  typedef std::vector<tui_win_info *>::iterator inner_iterator;
+
   typedef tui_source_window_iterator self_type;
   typedef struct tui_source_window_base *value_type;
   typedef struct tui_source_window_base *&reference;
@@ -160,14 +162,16 @@ public:
   typedef std::forward_iterator_tag iterator_category;
   typedef int difference_type;
 
-  explicit tui_source_window_iterator (bool dummy)
-    : m_iter (SRC_WIN)
+  explicit tui_source_window_iterator (const inner_iterator &it,
+				       const inner_iterator &end)
+    : m_iter (it),
+      m_end (end)
   {
     advance ();
   }
 
-  tui_source_window_iterator ()
-    : m_iter (tui_win_type (DISASSEM_WIN + 1))
+  explicit tui_source_window_iterator (const inner_iterator &it)
+    : m_iter (it)
   {
   }
 
@@ -178,7 +182,7 @@ public:
 
   value_type operator* () const
   {
-    return (value_type) *m_iter;
+    return dynamic_cast<tui_source_window_base *> (*m_iter);
   }
 
   self_type &operator++ ()
@@ -192,12 +196,13 @@ private:
 
   void advance ()
   {
-    tui_window_iterator end;
-    while (m_iter != end && *m_iter == nullptr)
+    while (m_iter != m_end
+	   && dynamic_cast<tui_source_window_base *> (*m_iter) == nullptr)
       ++m_iter;
   }
 
-  tui_window_iterator m_iter;
+  inner_iterator m_iter;
+  inner_iterator m_end;
 };
 
 /* A range adapter for source windows.  */
@@ -206,12 +211,13 @@ struct tui_source_windows
 {
   tui_source_window_iterator begin () const
   {
-    return tui_source_window_iterator (true);
+    return tui_source_window_iterator (tui_windows.begin (),
+				       tui_windows.end ());
   }
 
   tui_source_window_iterator end () const
   {
-    return tui_source_window_iterator ();
+    return tui_source_window_iterator (tui_windows.end ());
   }
 };
 
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 02/24] Simplify tui_add_win_to_layout
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (18 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 24/24] Fix cast in TUI_DISASM_WIN Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 21/24] Make some tui_source_window_base members "protected" Tom Tromey
                   ` (4 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

tui_add_win_to_layout is only ever called for the source or assembly
windows.  This simplifies the function by removing the DATA_WIN case.

gdb/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-layout.h (tui_add_win_to_layout): Add comment.
	* tui/tui-layout.c (tui_add_win_to_layout): Add assert.  Remove
	DATA_WIN case.

Change-Id: Idfca902c6c90153acc5d19af4c33aa74bc3caf31
---
 gdb/ChangeLog        |  6 ++++++
 gdb/tui/tui-layout.c | 19 ++++---------------
 gdb/tui/tui-layout.h |  5 +++++
 3 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index 1e9c5c53e3f..8be98e9ba48 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -185,12 +185,13 @@ tui_set_layout (enum tui_layout_type layout_type)
     }
 }
 
-/* Add the specified window to the layout in a logical way.  This
-   means setting up the most logical layout given the window to be
-   added.  */
+/* See tui-layout.h.  */
+
 void
 tui_add_win_to_layout (enum tui_win_type type)
 {
+  gdb_assert (type == SRC_WIN || type == DISASSEM_WIN);
+
   enum tui_layout_type cur_layout = tui_current_layout ();
 
   switch (type)
@@ -217,18 +218,6 @@ tui_add_win_to_layout (enum tui_win_type type)
 	    show_layout (DISASSEM_COMMAND);
 	}
       break;
-    case DATA_WIN:
-      if (cur_layout != SRC_DATA_COMMAND
-	  && cur_layout != DISASSEM_DATA_COMMAND)
-	{
-	  if (cur_layout == DISASSEM_COMMAND)
-	    show_layout (DISASSEM_DATA_COMMAND);
-	  else
-	    show_layout (SRC_DATA_COMMAND);
-	}
-      break;
-    default:
-      break;
     }
 }
 
diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h
index c2380b3c0a7..37f07c24e4f 100644
--- a/gdb/tui/tui-layout.h
+++ b/gdb/tui/tui-layout.h
@@ -173,7 +173,12 @@ private:
   bool m_applied = false;
 };
 
+/* Add the specified window to the layout in a logical way.  This
+   means setting up the most logical layout given the window to be
+   added.  Only the source or disassembly window can be added this
+   way.  */
 extern void tui_add_win_to_layout (enum tui_win_type);
+
 extern void tui_set_layout (enum tui_layout_type);
 
 /* Apply the current layout.  */
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 13/24] Reimplement tui_next_win and tui_prev_win
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (10 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 11/24] Add horizontal splitting to TUI layout Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 07/24] Remove hard-coded TUI layouts Tom Tromey
                   ` (12 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This reimplements tui_next_win and tui_prev_win.  Now they account for
the possibility of windows not on tui_win_list.

2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-data.c (tui_next_win, tui_prev_win): Reimplement.

Change-Id: Ifcd402f76fe0a16e0fe9275a185d550279c01660
---
 gdb/ChangeLog      |  4 ++++
 gdb/tui/tui-data.c | 55 +++++++++++-----------------------------------
 2 files changed, 17 insertions(+), 42 deletions(-)

diff --git a/gdb/tui/tui-data.c b/gdb/tui/tui-data.c
index 06bd42ee536..5d42fafccca 100644
--- a/gdb/tui/tui-data.c
+++ b/gdb/tui/tui-data.c
@@ -26,6 +26,7 @@
 #include "tui/tui-wingeneral.h"
 #include "tui/tui-winsource.h"
 #include "gdb_curses.h"
+#include <algorithm>
 
 struct tui_win_info *tui_win_list[MAX_MAJOR_WINDOWS];
 
@@ -103,28 +104,13 @@ tui_set_term_width_to (int w)
 struct tui_win_info *
 tui_next_win (struct tui_win_info *cur_win)
 {
-  int type = cur_win->type;
-  struct tui_win_info *next_win = NULL;
-
-  if (cur_win->type == CMD_WIN)
-    type = SRC_WIN;
-  else
-    type = cur_win->type + 1;
-  while (type != cur_win->type && (next_win == NULL))
-    {
-      if (tui_win_list[type]
-	  && tui_win_list[type]->is_visible ())
-	next_win = tui_win_list[type];
-      else
-	{
-	  if (type == CMD_WIN)
-	    type = SRC_WIN;
-	  else
-	    type++;
-	}
-    }
+  auto iter = std::find (tui_windows.begin (), tui_windows.end (), cur_win);
+  gdb_assert (iter != tui_windows.end ());
 
-  return next_win;
+  ++iter;
+  if (iter == tui_windows.end ())
+    return tui_windows[0];
+  return *iter;
 }
 
 
@@ -133,28 +119,13 @@ tui_next_win (struct tui_win_info *cur_win)
 struct tui_win_info *
 tui_prev_win (struct tui_win_info *cur_win)
 {
-  int type = cur_win->type;
-  struct tui_win_info *prev = NULL;
-
-  if (cur_win->type == SRC_WIN)
-    type = CMD_WIN;
-  else
-    type = cur_win->type - 1;
-  while (type != cur_win->type && (prev == NULL))
-    {
-      if (tui_win_list[type]
-	  && tui_win_list[type]->is_visible ())
-	prev = tui_win_list[type];
-      else
-	{
-	  if (type == SRC_WIN)
-	    type = CMD_WIN;
-	  else
-	    type--;
-	}
-    }
+  auto iter = std::find (tui_windows.begin (), tui_windows.end (), cur_win);
+  gdb_assert (iter != tui_windows.end ());
 
-  return prev;
+  if (iter == tui_windows.begin ())
+    return tui_windows.back ();
+  --iter;
+  return *iter;
 }
 
 
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 00/24] Horizontal TUI layout + windows in Python
@ 2020-01-04 18:34 Tom Tromey
  2020-01-04 18:34 ` [PATCH 14/24] Handle ambiguity in tui_partial_win_by_name Tom Tromey
                   ` (24 more replies)
  0 siblings, 25 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches

This series adds some new features to the TUI: user-defined layouts,
horizontal layouts, and the ability to write windows in Python.

Much of the series is refactoring in preparation for the new
additions.

A couple of other visible changes were needed.  It wasn't entirely
clear to me how the C-x 1 and C-x 2 bindings should be handled; see
patch 4 and patch 5.

The Python API is currently pretty simple.  I may add some new
features to it.  For example, right now you can't write a replacement
for the locator window, because there's no way for a Python window to
set its maximum size.  It might also be useful to have a mode where
gdb manages scrolling, rather than having to do it manually in Python;
or a way to control whether wrapping is done when writing to a window.

I didn't add a "winwidth" command to change the width of a window.
Perhaps this is needed.  Also maybe "info win" should show more
information now?

Let me know what you think.

Tom


^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 01/24] Use TUI_DISASM_WIN instead of tui_win_list array
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (12 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 07/24] Remove hard-coded TUI layouts Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 04/24] Simplify TUI C-x 2 binding Tom Tromey
                   ` (10 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This is a minor cleanup to change tui_get_low_disassembly_address to
use TUI_DISASM_WIN, rather than the tui_win_list array.  This is more
in line with what the rest of the TUI code does.

gdb/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-disasm.c (tui_get_low_disassembly_address): Use
	TUI_DISASM_WIN, not tui_win_list.

Change-Id: I999335ee3f63a4b570e84f320236b78f2bd5b780
---
 gdb/ChangeLog        | 5 +++++
 gdb/tui/tui-disasm.c | 4 ++--
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c
index c72b50730b0..f482086ca2e 100644
--- a/gdb/tui/tui-disasm.c
+++ b/gdb/tui/tui-disasm.c
@@ -302,8 +302,8 @@ tui_get_low_disassembly_address (struct gdbarch *gdbarch,
 
   /* Determine where to start the disassembly so that the pc is about
      in the middle of the viewport.  */
-  if (tui_win_list[DISASSEM_WIN] != NULL)
-    pos = tui_win_list[DISASSEM_WIN]->height;
+  if (TUI_DISASM_WIN != NULL)
+    pos = TUI_DISASM_WIN->height;
   else if (TUI_CMD_WIN == NULL)
     pos = tui_term_height () / 2 - 2;
   else
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 07/24] Remove hard-coded TUI layouts
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (11 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 13/24] Reimplement tui_next_win and tui_prev_win Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 01/24] Use TUI_DISASM_WIN instead of tui_win_list array Tom Tromey
                   ` (11 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This changes the TUI so that the available layouts are no longer
completely hard-coded.  "enum tui_layout_type" is removed, and then
all the fallout from this is fixed up.

This patch also reimplements the "layout" command to be a prefix
command.  The concrete layouts are simply sub-commands now.  This
provides completion and correct abbreviation behavior for free.

gdb/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui.c (tui_enable): Call tui_set_initial_layout.
	* tui/tui-win.c (window_name_completer): Update comment.
	* tui/tui-layout.h (class tui_layout_base) <replace_window>:
	Declare method.
	(class tui_layout_window) <replace_window>: Likewise.
	(class tui_layout_split) <replace_window>: Likewise.
	(tui_set_layout): Don't declare.
	(tui_set_initial_layout): Declare function.
	* tui/tui-layout.c (layouts, applied_skeleton, src_regs_layout)
	(asm_regs_layout): New globals.
	(tui_current_layout, show_layout): Remove.
	(tui_set_layout, tui_add_win_to_layout): Rewrite.
	(find_layout, tui_apply_layout): New function.
	(layout_completer): Remove.
	(tui_next_layout): Reimplement.
	(tui_next_layout_command): New function.
	(tui_set_initial_layout, tui_prev_layout_command): New functions.
	(tui_regs_layout): Reimplement.
	(tui_regs_layout_command): New function.
	(extract_display_start_addr): Rewrite.
	(next_layout, prev_layout): Remove.
	(tui_layout_window::replace_window): New method.
	(tui_layout_split::replace_window): New method.
	(destroy_layout): New function.
	(layout_list): New global.
	(add_layout_command): New function.
	(initialize_layouts): Update.
	(tui_layout_command): New function.
	(_initialize_tui_layout): Install "layout" commands.
	* tui/tui-data.h (enum tui_layout_type): Remove.
	(tui_current_layout): Don't declare.

Change-Id: I9b5f7ab3ce838d6b340b8c373ef649a8e0a74b73
---
 gdb/ChangeLog        |  34 +++
 gdb/tui/tui-data.h   |  12 --
 gdb/tui/tui-layout.c | 495 +++++++++++++++++++------------------------
 gdb/tui/tui-layout.h |  11 +-
 gdb/tui/tui-win.c    |   2 +-
 gdb/tui/tui.c        |   2 +-
 6 files changed, 267 insertions(+), 289 deletions(-)

diff --git a/gdb/tui/tui-data.h b/gdb/tui/tui-data.h
index ffdd5e37491..66866dbc23f 100644
--- a/gdb/tui/tui-data.h
+++ b/gdb/tui/tui-data.h
@@ -124,17 +124,6 @@ public:
 /* Strings to display in the TUI status line.  */
 #define SINGLE_KEY              "(SingleKey)"
 
-/* The kinds of layouts available.  */
-enum tui_layout_type
-{
-  SRC_COMMAND,
-  DISASSEM_COMMAND,
-  SRC_DISASSEM_COMMAND,
-  SRC_DATA_COMMAND,
-  DISASSEM_DATA_COMMAND,
-  UNDEFINED_LAYOUT
-};
-
 enum tui_line_or_address_kind
 {
   LOA_LINE,
@@ -303,7 +292,6 @@ struct all_tui_windows
 
 
 /* Data Manipulation Functions.  */
-extern enum tui_layout_type tui_current_layout (void);
 extern int tui_term_height (void);
 extern void tui_set_term_height_to (int);
 extern int tui_term_width (void);
diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index 68a55179d98..72a8d27df40 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -25,6 +25,8 @@
 #include "symtab.h"
 #include "frame.h"
 #include "source.h"
+#include "cli/cli-cmds.h"
+#include "cli/cli-decode.h"
 #include <ctype.h>
 
 #include "tui/tui.h"
@@ -40,27 +42,22 @@
 #include "tui/tui-source.h"
 #include "gdb_curses.h"
 
-static void show_layout (enum tui_layout_type);
-static enum tui_layout_type next_layout (void);
-static enum tui_layout_type prev_layout (void);
 static void tui_layout_command (const char *, int);
 static void extract_display_start_addr (struct gdbarch **, CORE_ADDR *);
 
-
-/* The pre-defined layouts.  */
-static tui_layout_split *standard_layouts[UNDEFINED_LAYOUT];
+/* The layouts.  */
+static std::vector<std::unique_ptr<tui_layout_split>> layouts;
 
 /* The layout that is currently applied.  */
 static std::unique_ptr<tui_layout_base> applied_layout;
 
-static enum tui_layout_type current_layout = UNDEFINED_LAYOUT;
+/* The "skeleton" version of the layout that is currently applied.  */
+static tui_layout_split *applied_skeleton;
 
-/* Accessor for the current layout.  */
-enum tui_layout_type
-tui_current_layout (void)
-{
-  return current_layout;
-}
+/* The two special "regs" layouts.  Note that these aren't registered
+   as commands and so can never be deleted.  */
+static tui_layout_split *src_regs_layout;
+static tui_layout_split *asm_regs_layout;
 
 /* See tui-layout.h.  */
 
@@ -78,111 +75,24 @@ tui_adjust_window_height (struct tui_win_info *win, int new_height)
   applied_layout->adjust_size (win->name (), new_height);
 }
 
-/* Show the screen layout defined.  */
-static void
-show_layout (enum tui_layout_type layout)
-{
-  enum tui_layout_type cur_layout = tui_current_layout ();
-
-  if (layout != cur_layout)
-    {
-      tui_make_all_invisible ();
-      applied_layout = standard_layouts[layout]->clone ();
-      tui_apply_current_layout ();
-      current_layout = layout;
-      tui_delete_invisible_windows ();
-    }
-}
-
+/* Set the current layout to LAYOUT.  */
 
-/* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
-   SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND.  */
-void
-tui_set_layout (enum tui_layout_type layout_type)
+static void
+tui_set_layout (tui_layout_split *layout)
 {
-  gdb_assert (layout_type != UNDEFINED_LAYOUT);
-
-  enum tui_layout_type cur_layout = tui_current_layout ();
   struct gdbarch *gdbarch;
   CORE_ADDR addr;
-  struct tui_win_info *win_with_focus = tui_win_with_focus ();
 
   extract_display_start_addr (&gdbarch, &addr);
+  tui_make_all_invisible ();
+  applied_skeleton = layout;
+  applied_layout = layout->clone ();
+  tui_apply_current_layout ();
+  tui_delete_invisible_windows ();
 
-  enum tui_layout_type new_layout = layout_type;
-
-  if (new_layout != cur_layout)
-    {
-      show_layout (new_layout);
-
-      /* Now determine where focus should be.  */
-      if (win_with_focus != TUI_CMD_WIN)
-	{
-	  switch (new_layout)
-	    {
-	    case SRC_COMMAND:
-	      tui_set_win_focus_to (TUI_SRC_WIN);
-	      break;
-	    case DISASSEM_COMMAND:
-	      /* The previous layout was not showing code.
-		 This can happen if there is no source
-		 available:
-
-		 1. if the source file is in another dir OR
-		 2. if target was compiled without -g
-		 We still want to show the assembly though!  */
-
-	      tui_get_begin_asm_address (&gdbarch, &addr);
-	      tui_set_win_focus_to (TUI_DISASM_WIN);
-	      break;
-	    case SRC_DISASSEM_COMMAND:
-	      /* The previous layout was not showing code.
-		 This can happen if there is no source
-		 available:
-
-		 1. if the source file is in another dir OR
-		 2. if target was compiled without -g
-		 We still want to show the assembly though!  */
-
-	      tui_get_begin_asm_address (&gdbarch, &addr);
-	      if (win_with_focus == TUI_SRC_WIN)
-		tui_set_win_focus_to (TUI_SRC_WIN);
-	      else
-		tui_set_win_focus_to (TUI_DISASM_WIN);
-	      break;
-	    case SRC_DATA_COMMAND:
-	      if (win_with_focus != TUI_DATA_WIN)
-		tui_set_win_focus_to (TUI_SRC_WIN);
-	      else
-		tui_set_win_focus_to (TUI_DATA_WIN);
-	      break;
-	    case DISASSEM_DATA_COMMAND:
-	      /* The previous layout was not showing code.
-		 This can happen if there is no source
-		 available:
-
-		 1. if the source file is in another dir OR
-		 2. if target was compiled without -g
-		 We still want to show the assembly though!  */
-
-	      tui_get_begin_asm_address (&gdbarch, &addr);
-	      if (win_with_focus != TUI_DATA_WIN)
-		tui_set_win_focus_to (TUI_DISASM_WIN);
-	      else
-		tui_set_win_focus_to (TUI_DATA_WIN);
-	      break;
-	    default:
-	      break;
-	    }
-	}
-      /*
-       * Now update the window content.
-       */
-      tui_update_source_windows_with_addr (gdbarch, addr);
-      if (new_layout == SRC_DATA_COMMAND
-	  || new_layout == DISASSEM_DATA_COMMAND)
-	TUI_DATA_WIN->show_registers (TUI_DATA_WIN->get_current_group ());
-    }
+  if (gdbarch == nullptr && TUI_DISASM_WIN != nullptr)
+    tui_get_begin_asm_address (&gdbarch, &addr);
+  tui_update_source_windows_with_addr (gdbarch, addr);
 }
 
 /* See tui-layout.h.  */
@@ -192,104 +102,113 @@ tui_add_win_to_layout (enum tui_win_type type)
 {
   gdb_assert (type == SRC_WIN || type == DISASSEM_WIN);
 
-  enum tui_layout_type cur_layout = tui_current_layout ();
+  /* If the window already exists, no need to add it.  */
+  if (tui_win_list[type] != nullptr)
+    return;
+
+  /* If the window we are trying to replace doesn't exist, we're
+     done.  */
+  enum tui_win_type other = type == SRC_WIN ? DISASSEM_WIN : SRC_WIN;
+  if (tui_win_list[other] == nullptr)
+    return;
+
+  const char *name = type == SRC_WIN ? SRC_NAME : DISASSEM_NAME;
+  applied_layout->replace_window (tui_win_list[other]->name (), name);
+  tui_apply_current_layout ();
+  tui_delete_invisible_windows ();
+}
 
-  switch (type)
+/* Find LAYOUT in the "layouts" global and return its index.  */
+
+static size_t
+find_layout (tui_layout_split *layout)
+{
+  for (size_t i = 0; i < layouts.size (); ++i)
     {
-    case SRC_WIN:
-      if (cur_layout != SRC_COMMAND
-	  && cur_layout != SRC_DISASSEM_COMMAND
-	  && cur_layout != SRC_DATA_COMMAND)
-	{
-	  if (cur_layout == DISASSEM_DATA_COMMAND)
-	    show_layout (SRC_DATA_COMMAND);
-	  else
-	    show_layout (SRC_COMMAND);
-	}
-      break;
-    case DISASSEM_WIN:
-      if (cur_layout != DISASSEM_COMMAND
-	  && cur_layout != SRC_DISASSEM_COMMAND
-	  && cur_layout != DISASSEM_DATA_COMMAND)
-	{
-	  if (cur_layout == SRC_DATA_COMMAND)
-	    show_layout (DISASSEM_DATA_COMMAND);
-	  else
-	    show_layout (DISASSEM_COMMAND);
-	}
-      break;
+      if (layout == layouts[i].get ())
+	return i;
     }
+  gdb_assert_not_reached (_("layout not found!?"));
 }
 
-/* Complete possible layout names.  TEXT is the complete text entered so
-   far, WORD is the word currently being completed.  */
+/* Function to set the layout. */
 
 static void
-layout_completer (struct cmd_list_element *ignore,
-		  completion_tracker &tracker,
-		  const char *text, const char *word)
+tui_apply_layout (struct cmd_list_element *command,
+		  const char *args, int from_tty)
 {
-  static const char *layout_names [] =
-    { "src", "asm", "split", "regs", "next", "prev", NULL };
+  tui_layout_split *layout
+    = (tui_layout_split *) get_cmd_context (command);
 
-  complete_on_enum (tracker, layout_names, text, word);
+  /* Make sure the curses mode is enabled.  */
+  tui_enable ();
+  tui_set_layout (layout);
 }
 
-/* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
-   REGS. */
-static void
-tui_layout_command (const char *layout_name, int from_tty)
-{
-  enum tui_layout_type new_layout = UNDEFINED_LAYOUT;
-  enum tui_layout_type cur_layout = tui_current_layout ();
-
-  if (layout_name == NULL || *layout_name == '\0')
-    error (_("Usage: layout prev | next | LAYOUT-NAME"));
+/* See tui-layout.h.  */
 
-  /* First check for ambiguous input.  */
-  if (strcmp (layout_name, "s") == 0)
-    error (_("Ambiguous command input."));
+void
+tui_next_layout ()
+{
+  size_t index = find_layout (applied_skeleton);
+  ++index;
+  if (index == layouts.size ())
+    index = 0;
+  tui_set_layout (layouts[index].get ());
+}
 
-  if (subset_compare (layout_name, "src"))
-    new_layout = SRC_COMMAND;
-  else if (subset_compare (layout_name, "asm"))
-    new_layout = DISASSEM_COMMAND;
-  else if (subset_compare (layout_name, "split"))
-    new_layout = SRC_DISASSEM_COMMAND;
-  else if (subset_compare (layout_name, "regs"))
-    {
-      if (cur_layout == SRC_COMMAND
-	  || cur_layout == SRC_DATA_COMMAND)
-	new_layout = SRC_DATA_COMMAND;
-      else
-	new_layout = DISASSEM_DATA_COMMAND;
-    }
-  else if (subset_compare (layout_name, "next"))
-    new_layout = next_layout ();
-  else if (subset_compare (layout_name, "prev"))
-    new_layout = prev_layout ();
-  else
-    error (_("Unrecognized layout: %s"), layout_name);
+/* Implement the "layout next" command.  */
 
-  /* Make sure the curses mode is enabled.  */
+static void
+tui_next_layout_command (const char *arg, int from_tty)
+{
   tui_enable ();
-  tui_set_layout (new_layout);
+  tui_next_layout ();
 }
 
 /* See tui-layout.h.  */
 
 void
-tui_next_layout ()
+tui_set_initial_layout ()
+{
+  tui_set_layout (layouts[0].get ());
+}
+
+/* Implement the "layout prev" command.  */
+
+static void
+tui_prev_layout_command (const char *arg, int from_tty)
 {
-  tui_layout_command ("next", 0);
+  tui_enable ();
+  size_t index = find_layout (applied_skeleton);
+  if (index == 0)
+    index = layouts.size ();
+  --index;
+  tui_set_layout (layouts[index].get ());
 }
 
+
 /* See tui-layout.h.  */
 
 void
 tui_regs_layout ()
 {
-  tui_layout_command ("regs", 0);
+  /* If there's already a register window, we're done.  */
+  if (TUI_DATA_WIN != nullptr)
+    return;
+
+  tui_set_layout (TUI_DISASM_WIN != nullptr
+		  ? asm_regs_layout
+		  : src_regs_layout);
+}
+
+/* Implement the "layout regs" command.  */
+
+static void
+tui_regs_layout_command (const char *arg, int from_tty)
+{
+  tui_enable ();
+  tui_regs_layout ();
 }
 
 /* See tui-layout.h.  */
@@ -317,77 +236,29 @@ tui_remove_some_windows ()
 static void
 extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
 {
-  enum tui_layout_type cur_layout = tui_current_layout ();
-  struct gdbarch *gdbarch = get_current_arch ();
-  CORE_ADDR addr;
+  struct gdbarch *gdbarch = nullptr;
+  CORE_ADDR addr = 0;
   CORE_ADDR pc;
   struct symtab_and_line cursal = get_current_source_symtab_and_line ();
 
-  switch (cur_layout)
+  if (TUI_SRC_WIN != nullptr)
     {
-    case SRC_COMMAND:
-    case SRC_DATA_COMMAND:
       gdbarch = TUI_SRC_WIN->gdbarch;
       find_line_pc (cursal.symtab,
 		    TUI_SRC_WIN->start_line_or_addr.u.line_no,
 		    &pc);
       addr = pc;
-      break;
-    case DISASSEM_COMMAND:
-    case SRC_DISASSEM_COMMAND:
-    case DISASSEM_DATA_COMMAND:
+    }
+  else if (TUI_DISASM_WIN != nullptr)
+    {
       gdbarch = TUI_DISASM_WIN->gdbarch;
       addr = TUI_DISASM_WIN->start_line_or_addr.u.addr;
-      break;
-    default:
-      addr = 0;
-      break;
     }
 
   *gdbarch_p = gdbarch;
   *addr_p = addr;
 }
 
-
-/* Answer the previous layout to cycle to.  */
-static enum tui_layout_type
-next_layout (void)
-{
-  int new_layout;
-
-  new_layout = tui_current_layout ();
-  if (new_layout == UNDEFINED_LAYOUT)
-    new_layout = SRC_COMMAND;
-  else
-    {
-      new_layout++;
-      if (new_layout == UNDEFINED_LAYOUT)
-	new_layout = SRC_COMMAND;
-    }
-
-  return (enum tui_layout_type) new_layout;
-}
-
-
-/* Answer the next layout to cycle to.  */
-static enum tui_layout_type
-prev_layout (void)
-{
-  int new_layout;
-
-  new_layout = tui_current_layout ();
-  if (new_layout == SRC_COMMAND)
-    new_layout = DISASSEM_DATA_COMMAND;
-  else
-    {
-      new_layout--;
-      if (new_layout == UNDEFINED_LAYOUT)
-	new_layout = DISASSEM_DATA_COMMAND;
-    }
-
-  return (enum tui_layout_type) new_layout;
-}
-
 void
 tui_gen_win_info::resize (int height_, int width_,
 			  int origin_x_, int origin_y_)
@@ -510,6 +381,22 @@ tui_layout_window::bottom_boxed_p () const
 
 /* See tui-layout.h.  */
 
+void
+tui_layout_window::replace_window (const char *name, const char *new_window)
+{
+  if (m_contents == name)
+    {
+      m_contents = new_window;
+      if (m_window != nullptr)
+	{
+	  m_window->make_visible (false);
+	  m_window = tui_get_window_by_name (m_contents);
+	}
+    }
+}
+
+/* See tui-layout.h.  */
+
 tui_layout_split *
 tui_layout_split::add_split (int weight)
 {
@@ -802,62 +689,122 @@ tui_layout_split::remove_windows (const char *name)
     }
 }
 
+/* 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);
+}
+
+/* Destroy the layout associated with SELF.  */
+
 static void
-initialize_layouts ()
+destroy_layout (struct cmd_list_element *self, void *context)
 {
-  standard_layouts[SRC_COMMAND] = new tui_layout_split ();
-  standard_layouts[SRC_COMMAND]->add_window ("src", 2);
-  standard_layouts[SRC_COMMAND]->add_window ("locator", 0);
-  standard_layouts[SRC_COMMAND]->add_window ("cmd", 1);
+  tui_layout_split *layout = (tui_layout_split *) context;
+  size_t index = find_layout (layout);
+  layouts.erase (layouts.begin () + index);
+}
 
-  standard_layouts[DISASSEM_COMMAND] = new tui_layout_split ();
-  standard_layouts[DISASSEM_COMMAND]->add_window ("asm", 2);
-  standard_layouts[DISASSEM_COMMAND]->add_window ("locator", 0);
-  standard_layouts[DISASSEM_COMMAND]->add_window ("cmd", 1);
+/* List holding the sub-commands of "layout".  */
 
-  standard_layouts[SRC_DATA_COMMAND] = new tui_layout_split ();
-  standard_layouts[SRC_DATA_COMMAND]->add_window ("regs", 1);
-  standard_layouts[SRC_DATA_COMMAND]->add_window ("src", 1);
-  standard_layouts[SRC_DATA_COMMAND]->add_window ("locator", 0);
-  standard_layouts[SRC_DATA_COMMAND]->add_window ("cmd", 1);
+static struct cmd_list_element *layout_list;
 
-  standard_layouts[DISASSEM_DATA_COMMAND] = new tui_layout_split ();
-  standard_layouts[DISASSEM_DATA_COMMAND]->add_window ("regs", 1);
-  standard_layouts[DISASSEM_DATA_COMMAND]->add_window ("asm", 1);
-  standard_layouts[DISASSEM_DATA_COMMAND]->add_window ("locator", 0);
-  standard_layouts[DISASSEM_DATA_COMMAND]->add_window ("cmd", 1);
+/* Add a "layout" command with name NAME that switches to LAYOUT.  */
+
+static void
+add_layout_command (const char *name, tui_layout_split *layout)
+{
+  struct cmd_list_element *cmd;
 
-  standard_layouts[SRC_DISASSEM_COMMAND] = new tui_layout_split ();
-  standard_layouts[SRC_DISASSEM_COMMAND]->add_window ("src", 1);
-  standard_layouts[SRC_DISASSEM_COMMAND]->add_window ("asm", 1);
-  standard_layouts[SRC_DISASSEM_COMMAND]->add_window ("locator", 0);
-  standard_layouts[SRC_DISASSEM_COMMAND]->add_window ("cmd", 1);
+  gdb::unique_xmalloc_ptr<char> doc (xstrprintf (_("Apply the \"%s\" layout"),
+						 name));
+
+  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);
+}
+
+/* Initialize the standard layouts.  */
+
+static void
+initialize_layouts ()
+{
+  tui_layout_split *layout;
+
+  layout = new tui_layout_split ();
+  layout->add_window ("src", 2);
+  layout->add_window ("locator", 0);
+  layout->add_window ("cmd", 1);
+  add_layout_command ("src", layout);
+
+  layout = new tui_layout_split ();
+  layout->add_window ("asm", 2);
+  layout->add_window ("locator", 0);
+  layout->add_window ("cmd", 1);
+  add_layout_command ("asm", layout);
+
+  layout = new tui_layout_split ();
+  layout->add_window ("src", 1);
+  layout->add_window ("asm", 1);
+  layout->add_window ("locator", 0);
+  layout->add_window ("cmd", 1);
+  add_layout_command ("split", layout);
+
+  layout = new tui_layout_split ();
+  layout->add_window ("regs", 1);
+  layout->add_window ("src", 1);
+  layout->add_window ("locator", 0);
+  layout->add_window ("cmd", 1);
+  layouts.emplace_back (layout);
+  src_regs_layout = layout;
+
+  layout = new tui_layout_split ();
+  layout->add_window ("regs", 1);
+  layout->add_window ("asm", 1);
+  layout->add_window ("locator", 0);
+  layout->add_window ("cmd", 1);
+  layouts.emplace_back (layout);
+  asm_regs_layout = layout;
 }
 
 \f
 
+/* Base command for "layout".  */
+
+static void
+tui_layout_command (const char *layout_name, int from_tty)
+{
+  help_list (layout_list, "layout ", all_commands, gdb_stdout);
+}
+
 /* Function to initialize gdb commands, for tui window layout
    manipulation.  */
 
 void
 _initialize_tui_layout (void)
 {
-  struct cmd_list_element *cmd;
-
-  cmd = add_com ("layout", class_tui, tui_layout_command, _("\
+  add_prefix_cmd ("layout", class_tui, tui_layout_command, _("\
 Change the layout of windows.\n\
-Usage: layout prev | next | LAYOUT-NAME\n\
-Layout names are:\n\
-   src   : Displays source and command windows.\n\
-   asm   : Displays disassembly and command windows.\n\
-   split : Displays source, disassembly and command windows.\n\
-   regs  : Displays register window. If existing layout\n\
-           is source/command or assembly/command, the \n\
-           register window is displayed. If the\n\
-           source/assembly/command (split) is displayed, \n\
-           the register window is displayed with \n\
-           the window that has current logical focus."));
-  set_cmd_completer (cmd, layout_completer);
+Usage: layout prev | next | LAYOUT-NAME"),
+		  &layout_list, "layout ", 0, &cmdlist);
+
+  add_cmd ("next", class_tui, tui_next_layout_command,
+	   _("Apply the next TUI layout"),
+	   &layout_list);
+  add_cmd ("prev", class_tui, tui_prev_layout_command,
+	   _("Apply the previous TUI layout"),
+	   &layout_list);
+  add_cmd ("regs", class_tui, tui_regs_layout_command,
+	   _("Apply the TUI register layout"),
+	   &layout_list);
 
   initialize_layouts ();
 }
diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h
index 05089ab8fff..98bd548aaee 100644
--- a/gdb/tui/tui-layout.h
+++ b/gdb/tui/tui-layout.h
@@ -68,6 +68,10 @@ public:
      and the window being passed in here.  */
   virtual void remove_windows (const char *name) = 0;
 
+  /* Replace the window named NAME in the layout with the window named
+     NEW_WINDOW.  */
+  virtual void replace_window (const char *name, const char *new_window) = 0;
+
   /* The most recent space allocation.  */
   int x = 0;
   int y = 0;
@@ -114,6 +118,8 @@ public:
   {
   }
 
+  void replace_window (const char *name, const char *new_window) override;
+
 protected:
 
   void get_sizes (int *min_height, int *max_height) override;
@@ -159,6 +165,8 @@ public:
 
   void remove_windows (const char *name) override;
 
+  void replace_window (const char *name, const char *new_window) override;
+
 protected:
 
   void get_sizes (int *min_height, int *max_height) override;
@@ -189,7 +197,8 @@ private:
    way.  */
 extern void tui_add_win_to_layout (enum tui_win_type);
 
-extern void tui_set_layout (enum tui_layout_type);
+/* Set the initial layout.  */
+extern void tui_set_initial_layout ();
 
 /* Switch to the next layout.  */
 extern void tui_next_layout ();
diff --git a/gdb/tui/tui-win.c b/gdb/tui/tui-win.c
index df9bf43681e..4f90c765b53 100644
--- a/gdb/tui/tui-win.c
+++ b/gdb/tui/tui-win.c
@@ -385,7 +385,7 @@ window_name_completer (completion_tracker &tracker,
   /* If no windows are considered visible then the TUI has not yet been
      initialized.  But still "focus src" and "focus cmd" will work because
      invoking the focus command will entail initializing the TUI which sets the
-     default layout to SRC_COMMAND.  */
+     default layout to "src".  */
   if (completion_name_vec.empty ())
     {
       completion_name_vec.push_back (SRC_NAME);
diff --git a/gdb/tui/tui.c b/gdb/tui/tui.c
index b93f9f79b38..bc8c0159740 100644
--- a/gdb/tui/tui.c
+++ b/gdb/tui/tui.c
@@ -421,7 +421,7 @@ tui_enable (void)
       def_prog_mode ();
 
       tui_show_frame_info (0);
-      tui_set_layout (SRC_COMMAND);
+      tui_set_initial_layout ();
       tui_set_win_focus_to (TUI_SRC_WIN);
       keypad (TUI_CMD_WIN->handle.get (), TRUE);
       wrefresh (TUI_CMD_WIN->handle.get ());
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 18/24] Remove tui_set_win_focus_to
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (7 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 03/24] Fix latent display bug in tui_data_window Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 12/24] Change TUI window iteration Tom Tromey
                   ` (15 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

I noticed that the TUI had two functions with similar names:
tui_set_win_focus_to and tui_set_win_with_focus.

However, the former was just an implementation detail of the latter.
So, this patch removes the former entirely, to avoid any temptation to
call it.

2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-win.c (tui_set_win_focus_to): Move to tui-data.c.
	* tui/tui-data.h (tui_set_win_with_focus): Don't declare.
	* tui/tui-data.c (tui_set_win_with_focus): Remove.
	(tui_set_win_focus_to): Move from tui-win.c.

Change-Id: Idffddab773436bdf80d55480906d76b292981ef2
---
 gdb/ChangeLog      |  7 +++++++
 gdb/tui/tui-data.c | 11 ++++++++---
 gdb/tui/tui-data.h |  1 -
 gdb/tui/tui-win.c  | 15 ---------------
 4 files changed, 15 insertions(+), 19 deletions(-)

diff --git a/gdb/tui/tui-data.c b/gdb/tui/tui-data.c
index db637d8fbe6..1d822c9090f 100644
--- a/gdb/tui/tui-data.c
+++ b/gdb/tui/tui-data.c
@@ -59,11 +59,16 @@ tui_win_with_focus (void)
 }
 
 
-/* Set the window that has the logical focus.  */
+/* Set the logical focus to win_info.  */
 void
-tui_set_win_with_focus (struct tui_win_info *win_info)
+tui_set_win_focus_to (struct tui_win_info *win_info)
 {
-  win_with_focus = win_info;
+  if (win_info != NULL)
+    {
+      tui_unhighlight_win (win_with_focus);
+      win_with_focus = win_info;
+      tui_highlight_win (win_info);
+    }
 }
 
 
diff --git a/gdb/tui/tui-data.h b/gdb/tui/tui-data.h
index 56600926636..0583c4a5c99 100644
--- a/gdb/tui/tui-data.h
+++ b/gdb/tui/tui-data.h
@@ -244,7 +244,6 @@ extern int tui_term_width (void);
 extern void tui_set_term_width_to (int);
 extern struct tui_locator_window *tui_locator_win_info_ptr (void);
 extern struct tui_win_info *tui_win_with_focus (void);
-extern void tui_set_win_with_focus (struct tui_win_info *);
 extern bool tui_win_resized ();
 extern void tui_set_win_resized_to (bool);
 
diff --git a/gdb/tui/tui-win.c b/gdb/tui/tui-win.c
index f8a57732cca..1cd0878b1b9 100644
--- a/gdb/tui/tui-win.c
+++ b/gdb/tui/tui-win.c
@@ -452,21 +452,6 @@ tui_update_gdb_sizes (void)
 }
 
 
-/* Set the logical focus to win_info.  */
-void
-tui_set_win_focus_to (struct tui_win_info *win_info)
-{
-  if (win_info != NULL)
-    {
-      struct tui_win_info *win_with_focus = tui_win_with_focus ();
-
-      tui_unhighlight_win (win_with_focus);
-      tui_set_win_with_focus (win_info);
-      tui_highlight_win (win_info);
-    }
-}
-
-
 void
 tui_win_info::forward_scroll (int num_to_scroll)
 {
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 10/24] Change return type of tui_layout_base::adjust_size
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (2 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 16/24] TUI windows do not need to store their type Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 09/24] Allow TUI sub-layouts in "new-layout" command Tom Tromey
                   ` (20 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This changes tui_layout_base::adjust_size to return a new enum type.
I broke this out into a separate patch because it simplifies a
subsequent patch.

gdb/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-layout.h (enum tui_adjust_result): New.
	(class tui_layout_base) <adjust_size>: Return tui_adjust_result.
	(class tui_layout_window) <adjust_size>: Return
	tui_adjust_result.  Rewrite.
	(class tui_layout_split) <adjust_size>: Return tui_adjust_result.
	* tui/tui-layout.c (tui_layout_split::adjust_size): Update.

Change-Id: I821b48ab06a9b9485875e147bd08a3bc46b900a0
---
 gdb/ChangeLog        |  9 +++++++++
 gdb/tui/tui-layout.c | 17 +++++++++--------
 gdb/tui/tui-layout.h | 20 ++++++++++++++++----
 3 files changed, 34 insertions(+), 12 deletions(-)

diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index 3604d7e06bc..be6c754d022 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -487,7 +487,7 @@ tui_layout_split::set_weights_from_heights ()
 
 /* See tui-layout.h.  */
 
-bool
+tui_adjust_result
 tui_layout_split::adjust_size (const char *name, int new_height)
 {
   /* Look through the children.  If one is a layout holding the named
@@ -496,10 +496,11 @@ tui_layout_split::adjust_size (const char *name, int new_height)
   int found_index = -1;
   for (int i = 0; i < m_splits.size (); ++i)
     {
-      if (m_splits[i].layout->adjust_size (name, new_height))
-	return true;
-      const char *win_name = m_splits[i].layout->get_name ();
-      if (win_name != nullptr && strcmp (name, win_name) == 0)
+      tui_adjust_result adjusted
+	= m_splits[i].layout->adjust_size (name, new_height);
+      if (adjusted == HANDLED)
+	return HANDLED;
+      if (adjusted == FOUND)
 	{
 	  found_index = i;
 	  break;
@@ -507,9 +508,9 @@ tui_layout_split::adjust_size (const char *name, int new_height)
     }
 
   if (found_index == -1)
-    return false;
+    return NOT_FOUND;
   if (m_splits[found_index].layout->height == new_height)
-    return true;
+    return HANDLED;
 
   set_weights_from_heights ();
   int delta = m_splits[found_index].weight - new_height;
@@ -557,7 +558,7 @@ tui_layout_split::adjust_size (const char *name, int new_height)
       apply (x, y, width, height);
     }
 
-  return true;
+  return HANDLED;
 }
 
 /* See tui-layout.h.  */
diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h
index 4351e260720..969e4dfd231 100644
--- a/gdb/tui/tui-layout.h
+++ b/gdb/tui/tui-layout.h
@@ -27,6 +27,18 @@
 #include "tui/tui.h"
 #include "tui/tui-data.h"
 
+/* Values that can be returned when handling a request to adjust a
+   window's size.  */
+enum tui_adjust_result
+{
+  /* Requested window was not found here.  */
+  NOT_FOUND,
+  /* Window was found but not handled.  */
+  FOUND,
+  /* Window was found and handled.  */
+  HANDLED
+};
+
 /* The basic object in a TUI layout.  This represents a single piece
    of screen real estate.  Subclasses determine the exact
    behavior.  */
@@ -64,7 +76,7 @@ public:
 
   /* Adjust the size of the window named NAME to NEW_HEIGHT, updating
      the sizes of the other windows around it.  */
-  virtual bool adjust_size (const char *name, int new_height) = 0;
+  virtual tui_adjust_result adjust_size (const char *name, int new_height) = 0;
 
   /* Remove some windows from the layout, leaving the command window
      and the window being passed in here.  */
@@ -111,9 +123,9 @@ public:
     return m_contents.c_str ();
   }
 
-  bool adjust_size (const char *name, int new_height) override
+  tui_adjust_result adjust_size (const char *name, int new_height) override
   {
-    return false;
+    return m_contents == name ? FOUND : NOT_FOUND;
   }
 
   bool top_boxed_p () const override;
@@ -165,7 +177,7 @@ public:
 
   void apply (int x, int y, int width, int height) override;
 
-  bool adjust_size (const char *name, int new_height) override;
+  tui_adjust_result adjust_size (const char *name, int new_height) override;
 
   bool top_boxed_p () const override;
 
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 08/24] Add the "tui new-layout" command
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (20 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 21/24] Make some tui_source_window_base members "protected" Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:44   ` Eli Zaretskii
  2020-01-04 18:34 ` [PATCH 19/24] Remove the TUI annotation hack Tom Tromey
                   ` (2 subsequent siblings)
  24 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This adds a new command, "tui new-layout".  This command can be used
to define a new TUI window layout.

The command is used like:

(gdb) tui new-layout name src 1 regs 1 locator 0 cmd 1

The first argument is the name of the layout.  In this example, it is
"name", so the new layout could be seen by "layout name".

Subsequent arguments come in pairs, where the first item in a pair is
the name of a window, and the second item in a pair is the window's
weight.  A weight is just an integer -- a window's allocated size is
proportional to the total of the weights given.  So, in the above
example, all windows will have the same size (the locator's weight
does not matter, because it has fixed height).

gdb/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* NEWS: Add "tui new-layout" item.
	* tui/tui-layout.c (add_layout_command): Return cmd_list_element.
	Add new-layout command to help text.
	(validate_window_name): New function.
	(tui_new_layout_command): New function.
	(_initialize_tui_layout): Register "new-layout".
	(tui_layout_window::specification): New method.
	(tui_layout_window::specification): New method.
	* tui/tui-layout.h (class tui_layout_base) <specification>: New
	method.
	(class tui_layout_window) <specification>: New method.
	(class tui_layout_split) <specification>: New method.

gdb/doc/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* gdb.texinfo (TUI Overview): Mention user layouts.
	(TUI Commands): Document "tui new-layout".

gdb/testsuite/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* gdb.tui/new-layout.exp: New file.

Change-Id: Id7c3ace20ab1e8924f8f4ad788f40210f58a5c05
---
 gdb/ChangeLog                        |  15 ++++
 gdb/NEWS                             |   6 ++
 gdb/doc/ChangeLog                    |   5 ++
 gdb/doc/gdb.texinfo                  |  37 +++++++++-
 gdb/testsuite/ChangeLog              |   4 ++
 gdb/testsuite/gdb.tui/new-layout.exp |  54 ++++++++++++++
 gdb/tui/tui-layout.c                 | 103 ++++++++++++++++++++++++++-
 gdb/tui/tui-layout.h                 |   9 +++
 8 files changed, 227 insertions(+), 6 deletions(-)
 create mode 100644 gdb/testsuite/gdb.tui/new-layout.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index f51a989fef1..b8939693f4e 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -7,6 +7,12 @@
   that support it (see entry for GDB 9, below), providing faster
   performance for programs with many symbols.
 
+* New commands
+
+tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]...
+  Define a new TUI layout, specifying its name and the windows that
+  will be displayed.
+
 *** Changes in GDB 9
 
 * 'thread-exited' event is now available in the annotations interface.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 65137b17396..147d0c28c92 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -27666,6 +27666,8 @@ source and registers, or
 assembly and registers.
 @end itemize
 
+These are the standard layouts, but other layouts can be defined.
+
 A status line above the command window shows the following information:
 
 @table @emph
@@ -27902,11 +27904,40 @@ Disable TUI mode, returning to the console interpreter.
 @kindex info win
 List and give the size of all displayed windows.
 
+@item tui new-layout @var{name} @var{window} @var{weight} @r{[}@var{window} @var{weight}@dots{}@r{]}
+@kindex tui new-layout
+Create a new TUI layout.  The new layout will be named @var{name}, and
+can be accessed using the @code{layout} command (see below).
+
+Each @var{window} parameter is the name of a window to display.  The
+windows will be displayed from top to bottom in the order listed.  The
+names of the windows are the same as the ones given to the
+@code{focus} command (see below); additional, the @code{locator}
+window can be specified.
+
+Each @var{weight} is an integer.  It is the weight of this window
+relative to all the other windows in the layout.  These numbers are
+used to calculate how much of the screen is given to each window.
+
+For example:
+
+@example
+(gdb) tui new-layout example src 1 regs 1 locator 0 cmd 1
+@end example
+
+Here, the new layout is called @samp{example}.  It shows the source
+and register windows, followed by the locator, and then finally the
+command window.  The non-locator windows all have the same weight, so
+the terminal will be split into three roughly equal sections.
+
 @item layout @var{name}
 @kindex layout
-Changes which TUI windows are displayed.  In each layout the command
-window is always displayed, the @var{name} parameter controls which
-additional windows are displayed, and can be any of the following:
+Changes which TUI windows are displayed.  The @var{name} parameter
+controls which layout is shown.  It can be either one of the built-in
+layout names, or the name of a layout defined by the user using
+@code{tui new-layout}.
+
+The built-in layouts are as follows:
 
 @table @code
 @item next
diff --git a/gdb/testsuite/gdb.tui/new-layout.exp b/gdb/testsuite/gdb.tui/new-layout.exp
new file mode 100644
index 00000000000..8475a9db295
--- /dev/null
+++ b/gdb/testsuite/gdb.tui/new-layout.exp
@@ -0,0 +1,54 @@
+# Copyright 2020 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test "tui new-layout".
+
+load_lib "tuiterm.exp"
+
+standard_testfile tui-layout.c
+
+if {[build_executable "failed to prepare" ${testfile} ${srcfile}] == -1} {
+    return -1
+}
+
+Term::clean_restart 24 80 $testfile
+
+gdb_test "tui new-layout" \
+    "No layout name specified"
+gdb_test "tui new-layout example" \
+    "New layout does not contain any windows"
+gdb_test "tui new-layout example zzq" \
+    "Unknown window \"zzq\""
+gdb_test "tui new-layout example src 1 src 1" \
+    "Window \"src\" seen twice in layout"
+gdb_test "tui new-layout example src 1" \
+    "New layout does not contain the \"cmd\" window"
+
+gdb_test_no_output "tui new-layout example asm 1 locator 0 cmd 1"
+
+gdb_test "help layout example" \
+    "Apply the \"example\" layout.*tui new-layout example asm 1 locator 0 cmd 1"
+
+if {![Term::enter_tui]} {
+    unsupported "TUI not supported"
+}
+
+set text [Term::get_all_lines]
+gdb_assert {![string match "No Source Available" $text]} \
+    "initial source listing"
+
+Term::command "layout example"
+Term::check_contents "example layout shows assembly" \
+    "No Assembly Available"
diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index 72a8d27df40..438a3a03828 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -27,7 +27,9 @@
 #include "source.h"
 #include "cli/cli-cmds.h"
 #include "cli/cli-decode.h"
+#include "cli/cli-utils.h"
 #include <ctype.h>
+#include <unordered_set>
 
 #include "tui/tui.h"
 #include "tui/tui-command.h"
@@ -397,6 +399,14 @@ tui_layout_window::replace_window (const char *name, const char *new_window)
 
 /* See tui-layout.h.  */
 
+void
+tui_layout_window::specification (ui_file *output)
+{
+  fputs_unfiltered (get_name (), output);
+}
+
+/* See tui-layout.h.  */
+
 tui_layout_split *
 tui_layout_split::add_split (int weight)
 {
@@ -698,6 +708,22 @@ tui_layout_split::replace_window (const char *name, const char *new_window)
     item.layout->replace_window (name, new_window);
 }
 
+/* See tui-layout.h.  */
+
+void
+tui_layout_split::specification (ui_file *output)
+{
+  bool first = true;
+  for (auto &item : m_splits)
+    {
+      if (!first)
+	fputs_unfiltered (" ", output);
+      first = false;
+      item.layout->specification (output);
+      fprintf_unfiltered (output, " %d", item.weight);
+    }
+}
+
 /* Destroy the layout associated with SELF.  */
 
 static void
@@ -714,13 +740,19 @@ static struct cmd_list_element *layout_list;
 
 /* Add a "layout" command with name NAME that switches to LAYOUT.  */
 
-static void
+static struct cmd_list_element *
 add_layout_command (const char *name, tui_layout_split *layout)
 {
   struct cmd_list_element *cmd;
 
-  gdb::unique_xmalloc_ptr<char> doc (xstrprintf (_("Apply the \"%s\" layout"),
-						 name));
+  string_file spec;
+  layout->specification (&spec);
+
+  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);
@@ -730,6 +762,8 @@ add_layout_command (const char *name, tui_layout_split *layout)
   cmd->doc_allocated = 1;
   doc.release ();
   layouts.emplace_back (layout);
+
+  return cmd;
 }
 
 /* Initialize the standard layouts.  */
@@ -777,6 +811,59 @@ initialize_layouts ()
 
 \f
 
+/* A helper function that returns true if NAME is the name of an
+   available window.  */
+
+static bool
+validate_window_name (const std::string &name)
+{
+  return (name == "src" || name == "cmd"
+	  || name == "regs" || name == "asm"
+	  || name == "locator");
+}
+
+/* Implementation of the "tui new-layout" command.  */
+
+static void
+tui_new_layout_command (const char *spec, int from_tty)
+{
+  std::string new_name = extract_arg (&spec);
+  if (new_name.empty ())
+    error (_("No layout name specified"));
+  if (new_name[0] == '-')
+    error (_("Layout name cannot start with '-'"));
+
+  std::unique_ptr<tui_layout_split> new_layout (new tui_layout_split);
+  std::unordered_set<std::string> seen_windows;
+  while (true)
+    {
+      std::string name = extract_arg (&spec);
+      if (name.empty ())
+	break;
+      if (!validate_window_name (name))
+	error (_("Unknown window \"%s\""), name.c_str ());
+      if (seen_windows.find (name) != seen_windows.end ())
+	error (_("Window \"%s\" seen twice in layout"), name.c_str ());
+      ULONGEST weight = get_ulongest (&spec);
+      if ((int) weight != weight)
+	error (_("Weight out of range: %s"), pulongest (weight));
+      new_layout->add_window (name.c_str (), weight);
+      seen_windows.insert (name);
+    }
+  if (seen_windows.empty ())
+    error (_("New layout does not contain any windows"));
+  if (seen_windows.find ("cmd") == seen_windows.end ())
+    error (_("New layout does not contain the \"cmd\" window"));
+
+  gdb::unique_xmalloc_ptr<char> cmd_name
+    = make_unique_xstrdup (new_name.c_str ());
+  struct cmd_list_element *cmd
+    = add_layout_command (cmd_name.get (), new_layout.get ());
+  cmd->name_allocated = 1;
+  cmd_name.release ();
+  new_layout.release ();
+}
+
 /* Base command for "layout".  */
 
 static void
@@ -806,5 +893,15 @@ Usage: layout prev | next | LAYOUT-NAME"),
 	   _("Apply the TUI register layout"),
 	   &layout_list);
 
+  add_cmd ("new-layout", class_tui, tui_new_layout_command,
+	   _("Create a new TUI layout.\n\
+Usage: tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\
+Create a new TUI layout.  The new layout will be named NAME,\n\
+and can be accessed using \"layout NAME\".\n\
+The windows will be displayed in the specified order.\n\
+Each WEIGHT is an integer, which holds the relative size\n\
+to be allocated to the window."),
+	   tui_get_cmd_list ());
+
   initialize_layouts ();
 }
diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h
index 98bd548aaee..c2249a783f8 100644
--- a/gdb/tui/tui-layout.h
+++ b/gdb/tui/tui-layout.h
@@ -22,6 +22,8 @@
 #ifndef TUI_TUI_LAYOUT_H
 #define TUI_TUI_LAYOUT_H
 
+#include "ui-file.h"
+
 #include "tui/tui.h"
 #include "tui/tui-data.h"
 
@@ -72,6 +74,9 @@ public:
      NEW_WINDOW.  */
   virtual void replace_window (const char *name, const char *new_window) = 0;
 
+  /* Append the specification to this window to OUTPUT.  */
+  virtual void specification (ui_file *output) = 0;
+
   /* The most recent space allocation.  */
   int x = 0;
   int y = 0;
@@ -120,6 +125,8 @@ public:
 
   void replace_window (const char *name, const char *new_window) override;
 
+  void specification (ui_file *output) override;
+
 protected:
 
   void get_sizes (int *min_height, int *max_height) override;
@@ -167,6 +174,8 @@ public:
 
   void replace_window (const char *name, const char *new_window) override;
 
+  void specification (ui_file *output) override;
+
 protected:
 
   void get_sizes (int *min_height, int *max_height) override;
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 23/24] Add "usage" text to all TUI command help
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (16 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 05/24] Reimplement TUI "C-x 1" binding Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 24/24] Fix cast in TUI_DISASM_WIN Tom Tromey
                   ` (6 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This adds "usage" text to the help for all all the TUI commands.  In
some cases the usage is borderline, but I tend to think being complete
is preferable.

2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-win.c (_initialize_tui_win): Add usage text.
	* tui/tui-stack.c (_initialize_tui_stack): Add usage text.
	* tui/tui-regs.c (_initialize_tui_regs): Add usage text.
	* tui/tui.c (_initialize_tui): Add usage text.

Change-Id: I727f7a7cfc03efa248ef98f30a18be393819e30b
---
 gdb/ChangeLog       | 7 +++++++
 gdb/tui/tui-regs.c  | 4 +++-
 gdb/tui/tui-stack.c | 3 ++-
 gdb/tui/tui-win.c   | 3 ++-
 gdb/tui/tui.c       | 6 ++++--
 5 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/gdb/tui/tui-regs.c b/gdb/tui/tui-regs.c
index ad57069968c..520fe5838aa 100644
--- a/gdb/tui/tui-regs.c
+++ b/gdb/tui/tui-regs.c
@@ -643,6 +643,8 @@ _initialize_tui_regs (void)
   tuicmd = tui_get_cmd_list ();
 
   cmd = add_cmd ("reg", class_tui, tui_reg_command, _("\
-TUI command to control the register window."), tuicmd);
+TUI command to control the register window.\n\
+Usage: tui reg NAME\n\
+NAME is the name of the register group to display"), tuicmd);
   set_cmd_completer (cmd, tui_reggroup_completer);
 }
diff --git a/gdb/tui/tui-stack.c b/gdb/tui/tui-stack.c
index 18e91882770..e42c0bda845 100644
--- a/gdb/tui/tui-stack.c
+++ b/gdb/tui/tui-stack.c
@@ -375,5 +375,6 @@ _initialize_tui_stack (void)
 {
   add_com ("update", class_tui, tui_update_command,
 	   _("Update the source window and locator to "
-	     "display the current execution point."));
+	     "display the current execution point.\n\
+Usage: update"));
 }
diff --git a/gdb/tui/tui-win.c b/gdb/tui/tui-win.c
index 4f9478b62a0..0d022baf25f 100644
--- a/gdb/tui/tui-win.c
+++ b/gdb/tui/tui-win.c
@@ -1034,7 +1034,8 @@ Use \"info win\" to see the names of the windows currently being displayed."));
   add_com_alias ("wh", "winheight", class_tui, 0);
   set_cmd_completer (cmd, winheight_completer);
   add_info ("win", tui_all_windows_info,
-	    _("List of all displayed windows."));
+	    _("List of all displayed windows.\n\
+Usage: info win"));
   cmd = add_com ("focus", class_tui, tui_set_focus_command, _("\
 Set focus to named window or next/prev window.\n\
 Usage: focus [WINDOW-NAME | next | prev]\n\
diff --git a/gdb/tui/tui.c b/gdb/tui/tui.c
index bc8c0159740..399d5916b39 100644
--- a/gdb/tui/tui.c
+++ b/gdb/tui/tui.c
@@ -557,9 +557,11 @@ _initialize_tui (void)
   tuicmd = tui_get_cmd_list ();
 
   add_cmd ("enable", class_tui, tui_enable_command,
-	   _("Enable TUI display mode."),
+	   _("Enable TUI display mode.\n\
+Usage: tui enable"),
 	   tuicmd);
   add_cmd ("disable", class_tui, tui_disable_command,
-	   _("Disable TUI display mode."),
+	   _("Disable TUI display mode.\n\
+Usage: tui disable"),
 	   tuicmd);
 }
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 22/24] Use error_no_arg in TUI
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (5 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 06/24] Reimplement "tui reg" command Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 03/24] Fix latent display bug in tui_data_window Tom Tromey
                   ` (17 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This changes a couple of TUI commands to use error_no_arg.  The
commands are also simplified a bit, and chnaged to use other gdb CLI
utility functions like skip_to_space.  This lets us removes a couple
of defines that don't interact properly with gettext.

2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-win.c (tui_set_focus_command)
	(tui_set_win_height_command): Use error_no_arg.
	(_initialize_tui_win): Update help text.
	(FOCUS_USAGE, WIN_HEIGHT_USAGE): Don't define.

Change-Id: I2bf95c2e5cfe1472d068388fa39f0cf07591b76c
---
 gdb/ChangeLog     |   7 ++
 gdb/tui/tui-win.c | 160 ++++++++++++++++++++--------------------------
 2 files changed, 77 insertions(+), 90 deletions(-)

diff --git a/gdb/tui/tui-win.c b/gdb/tui/tui-win.c
index 1cd0878b1b9..4f9478b62a0 100644
--- a/gdb/tui/tui-win.c
+++ b/gdb/tui/tui-win.c
@@ -68,9 +68,6 @@ static void parse_scrolling_args (const char *,
 				  int *);
 
 
-#define WIN_HEIGHT_USAGE    "Usage: winheight WINDOW-NAME [+ | -] NUM-LINES\n"
-#define FOCUS_USAGE         "Usage: focus [WINDOW-NAME | next | prev]\n"
-
 #ifndef ACS_LRCORNER
 #  define ACS_LRCORNER '+'
 #endif
@@ -707,29 +704,27 @@ tui_set_focus_command (const char *arg, int from_tty)
 {
   tui_enable ();
 
-  if (arg != NULL)
-    {
-      struct tui_win_info *win_info = NULL;
-
-      if (subset_compare (arg, "next"))
-	win_info = tui_next_win (tui_win_with_focus ());
-      else if (subset_compare (arg, "prev"))
-	win_info = tui_prev_win (tui_win_with_focus ());
-      else
-	win_info = tui_partial_win_by_name (arg);
+  if (arg == NULL)
+    error_no_arg (_("name of window to focus"));
 
-      if (win_info == NULL)
-	error (_("Unrecognized window name \"%s\""), arg);
-      if (!win_info->is_visible ())
-	error (_("Window \"%s\" is not visible"), arg);
+  struct tui_win_info *win_info = NULL;
 
-      tui_set_win_focus_to (win_info);
-      keypad (TUI_CMD_WIN->handle.get (), win_info != TUI_CMD_WIN);
-      printf_filtered (_("Focus set to %s window.\n"),
-		       tui_win_with_focus ()->name ());
-    }
+  if (subset_compare (arg, "next"))
+    win_info = tui_next_win (tui_win_with_focus ());
+  else if (subset_compare (arg, "prev"))
+    win_info = tui_prev_win (tui_win_with_focus ());
   else
-    error (_("Incorrect Number of Arguments.\n%s"), FOCUS_USAGE);
+    win_info = tui_partial_win_by_name (arg);
+
+  if (win_info == NULL)
+    error (_("Unrecognized window name \"%s\""), arg);
+  if (!win_info->is_visible ())
+    error (_("Window \"%s\" is not visible"), arg);
+
+  tui_set_win_focus_to (win_info);
+  keypad (TUI_CMD_WIN->handle.get (), win_info != TUI_CMD_WIN);
+  printf_filtered (_("Focus set to %s window.\n"),
+		   tui_win_with_focus ()->name ());
 }
 
 static void
@@ -875,66 +870,59 @@ tui_set_win_height_command (const char *arg, int from_tty)
 {
   /* Make sure the curses mode is enabled.  */
   tui_enable ();
-  if (arg != NULL)
-    {
-      const char *buf = arg;
-      const char *buf_ptr = buf;
-      int new_height;
-      struct tui_win_info *win_info;
+  if (arg == NULL)
+    error_no_arg (_("name of window"));
 
-      buf_ptr = strchr (buf_ptr, ' ');
-      if (buf_ptr != NULL)
-	{
-	  /* Validate the window name.  */
-	  gdb::string_view wname (buf, buf_ptr - buf);
-	  win_info = tui_partial_win_by_name (wname);
+  const char *buf = arg;
+  const char *buf_ptr = buf;
+  int new_height;
+  struct tui_win_info *win_info;
 
-	  if (win_info == NULL)
-	    error (_("Unrecognized window name \"%s\""), arg);
-	  if (!win_info->is_visible ())
-	    error (_("Window \"%s\" is not visible"), arg);
+  buf_ptr = skip_to_space (buf_ptr);
 
-	  /* Process the size.  */
-	  buf_ptr = skip_spaces (buf_ptr);
+  /* Validate the window name.  */
+  gdb::string_view wname (buf, buf_ptr - buf);
+  win_info = tui_partial_win_by_name (wname);
 
-	  if (*buf_ptr != '\0')
-	    {
-	      bool negate = false;
-	      bool fixed_size = true;
-	      int input_no;;
-
-	      if (*buf_ptr == '+' || *buf_ptr == '-')
-		{
-		  if (*buf_ptr == '-')
-		    negate = true;
-		  fixed_size = false;
-		  buf_ptr++;
-		}
-	      input_no = atoi (buf_ptr);
-	      if (input_no > 0)
-		{
-		  if (negate)
-		    input_no *= (-1);
-		  if (fixed_size)
-		    new_height = input_no;
-		  else
-		    new_height = win_info->height + input_no;
-
-		  /* Now change the window's height, and adjust
-		     all other windows around it.  */
-		  tui_adjust_window_height (win_info, new_height);
-		  tui_update_gdb_sizes ();
-		}
-	      else
-		warning (_("Invalid window height specified.\n%s"),
-			 WIN_HEIGHT_USAGE);
-	    }
+  if (win_info == NULL)
+    error (_("Unrecognized window name \"%s\""), arg);
+  if (!win_info->is_visible ())
+    error (_("Window \"%s\" is not visible"), arg);
+
+  /* Process the size.  */
+  buf_ptr = skip_spaces (buf_ptr);
+
+  if (*buf_ptr != '\0')
+    {
+      bool negate = false;
+      bool fixed_size = true;
+      int input_no;;
+
+      if (*buf_ptr == '+' || *buf_ptr == '-')
+	{
+	  if (*buf_ptr == '-')
+	    negate = true;
+	  fixed_size = false;
+	  buf_ptr++;
+	}
+      input_no = atoi (buf_ptr);
+      if (input_no > 0)
+	{
+	  if (negate)
+	    input_no *= (-1);
+	  if (fixed_size)
+	    new_height = input_no;
+	  else
+	    new_height = win_info->height + input_no;
+
+	  /* Now change the window's height, and adjust
+	     all other windows around it.  */
+	  tui_adjust_window_height (win_info, new_height);
+	  tui_update_gdb_sizes ();
 	}
       else
-	printf_filtered (WIN_HEIGHT_USAGE);
+	error (_("Invalid window height specified"));
     }
-  else
-    printf_filtered (WIN_HEIGHT_USAGE);
 }
 
 /* See tui-data.h.  */
@@ -1040,25 +1028,17 @@ Usage: tabset N"));
   deprecate_cmd (cmd, "set tui tab-width");
 
   cmd = add_com ("winheight", class_tui, tui_set_win_height_command, _("\
-Set or modify the height of a specified window.\n"
-WIN_HEIGHT_USAGE
-"Window names are:\n\
-   src  : the source window\n\
-   cmd  : the command window\n\
-   asm  : the disassembly window\n\
-   regs : the register display"));
+Set or modify the height of a specified window.\n\
+Usage: winheight WINDOW-NAME [+ | -] NUM-LINES\n\
+Use \"info win\" to see the names of the windows currently being displayed."));
   add_com_alias ("wh", "winheight", class_tui, 0);
   set_cmd_completer (cmd, winheight_completer);
   add_info ("win", tui_all_windows_info,
 	    _("List of all displayed windows."));
   cmd = add_com ("focus", class_tui, tui_set_focus_command, _("\
-Set focus to named window or next/prev window.\n"
-FOCUS_USAGE
-"Valid Window names are:\n\
-   src  : the source window\n\
-   asm  : the disassembly window\n\
-   regs : the register display\n\
-   cmd  : the command window"));
+Set focus to named window or next/prev window.\n\
+Usage: focus [WINDOW-NAME | next | prev]\n\
+Use \"info win\" to see the names of the windows currently being displayed."));
   add_com_alias ("fs", "focus", class_tui, 0);
   set_cmd_completer (cmd, focus_completer);
   add_com ("+", class_tui, tui_scroll_forward_command, _("\
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 05/24] Reimplement TUI "C-x 1" binding
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (15 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 15/24] Remove tui_delete_invisible_windows and tui_make_all_invisible Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 23/24] Add "usage" text to all TUI command help Tom Tromey
                   ` (7 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

The TUI "C-x 1" key binding removes TUI windows, based on the current
layout.  With user-defined layouts, this is no longer easy to do.

This patch changes "C-x 1" to simply delete windows, leaving just the
focus window, the locator, and the command window.

gdb/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui.c (tui_rl_delete_other_windows): Call
	tui_remove_some_windows.
	* tui/tui-layout.h (class tui_layout_base) <remove_windows>:
	Declare method.
	(class tui_layout_window) <remove_windows>: New method.
	(class tui_layout_split) <remove_windows>: Declare.
	(tui_remove_some_windows): Declare.
	* tui/tui-layout.c (tui_remove_some_windows): New function.
	(tui_layout_split::remove_windows): New method.

Change-Id: If186f9c3f263913e963b965204481d1b4385c6d4
---
 gdb/ChangeLog        | 12 ++++++++++++
 gdb/tui/tui-layout.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
 gdb/tui/tui-layout.h | 15 +++++++++++++++
 gdb/tui/tui.c        | 22 +---------------------
 4 files changed, 73 insertions(+), 21 deletions(-)

diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index 016cab649d4..86b496d273e 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -284,6 +284,28 @@ tui_next_layout ()
   tui_layout_command ("next", 0);
 }
 
+/* See tui-layout.h.  */
+
+void
+tui_remove_some_windows ()
+{
+  tui_win_info *focus = tui_win_with_focus ();
+
+  if (strcmp (focus->name (), "cmd") == 0)
+    {
+      /* Try leaving the source or disassembly window.  If neither
+	 exists, just do nothing.  */
+      focus = TUI_SRC_WIN;
+      if (focus == nullptr)
+	focus = TUI_DISASM_WIN;
+      if (focus == nullptr)
+	return;
+    }
+
+  applied_layout->remove_windows (focus->name ());
+  tui_apply_current_layout ();
+}
+
 static void
 extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
 {
@@ -749,6 +771,29 @@ tui_layout_split::apply (int x_, int y_, int width_, int height_)
   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") == 0)
+	    {
+	      /* Keep.  */
+	    }
+	  m_splits.erase (m_splits.begin () + i);
+	  --i;
+	}
+    }
+}
+
 static void
 initialize_layouts ()
 {
diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h
index 7e4b7b7a816..f711b004b84 100644
--- a/gdb/tui/tui-layout.h
+++ b/gdb/tui/tui-layout.h
@@ -64,6 +64,10 @@ public:
      the sizes of the other windows around it.  */
   virtual bool adjust_size (const char *name, int new_height) = 0;
 
+  /* Remove some windows from the layout, leaving the command window
+     and the window being passed in here.  */
+  virtual void remove_windows (const char *name) = 0;
+
   /* The most recent space allocation.  */
   int x = 0;
   int y = 0;
@@ -106,6 +110,10 @@ public:
 
   bool bottom_boxed_p () const override;
 
+  void remove_windows (const char *name) override
+  {
+  }
+
 protected:
 
   void get_sizes (int *min_height, int *max_height) override;
@@ -149,6 +157,8 @@ public:
 
   bool bottom_boxed_p () const override;
 
+  void remove_windows (const char *name) override;
+
 protected:
 
   void get_sizes (int *min_height, int *max_height) override;
@@ -184,6 +194,11 @@ extern void tui_set_layout (enum tui_layout_type);
 /* Switch to the next layout.  */
 extern void tui_next_layout ();
 
+/* Remove some windows from the layout, leaving only the focused
+   window and the command window; if no window has the focus, then
+   some other window is chosen to remain.  */
+extern void tui_remove_some_windows ();
+
 /* Apply the current layout.  */
 extern void tui_apply_current_layout ();
 
diff --git a/gdb/tui/tui.c b/gdb/tui/tui.c
index 780d3bae9c0..b93f9f79b38 100644
--- a/gdb/tui/tui.c
+++ b/gdb/tui/tui.c
@@ -161,28 +161,8 @@ tui_rl_delete_other_windows (int notused1, int notused2)
     tui_rl_switch_mode (0 /* notused */, 0 /* notused */);
 
   if (tui_active)
-    {
-      enum tui_layout_type new_layout;
-
-      new_layout = tui_current_layout ();
+    tui_remove_some_windows ();
 
-      /* Kill one window.  */
-      switch (new_layout)
-	{
-	case SRC_COMMAND:
-	case SRC_DATA_COMMAND:
-	case SRC_DISASSEM_COMMAND:
-	default:
-	  new_layout = SRC_COMMAND;
-	  break;
-
-	case DISASSEM_COMMAND:
-	case DISASSEM_DATA_COMMAND:
-	  new_layout = DISASSEM_COMMAND;
-	  break;
-	}
-      tui_set_layout (new_layout);
-    }
   return 0;
 }
 
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 16/24] TUI windows do not need to store their type
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
  2020-01-04 18:34 ` [PATCH 14/24] Handle ambiguity in tui_partial_win_by_name Tom Tromey
  2020-01-04 18:34 ` [PATCH 20/24] Allow TUI windows in Python Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 10/24] Change return type of tui_layout_base::adjust_size Tom Tromey
                   ` (21 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

TUI windows no longer need to store their type -- there's only a
single spot that uses this information, and it can be changed to use
dynamic_cast.  (It could be cleaned up even more, by using a virtual
method, but I haven't done so.)  This patch removes the "type" field
from tui_gen_win_info, and this in turn allows removing a couple of
enumerator constants.

2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui.h (enum tui_win_type) <LOCATOR_WIN, DATA_ITEM_WIN>:
	Remove constants.
	* tui/tui-winsource.h (struct tui_source_window_base)
	<tui_source_window_base>: Remove parameter.
	* tui/tui-winsource.c
	(tui_source_window_base::tui_source_window_base): Remove
	parameter.
	(tui_source_window_base::refill): Update.
	* tui/tui-stack.h (struct tui_locator_window)
	<tui_locator_window>: Update.
	* tui/tui-source.h (struct tui_source_window) <tui_source_window>:
	Default the constructor.
	* tui/tui-regs.h (struct tui_data_item_window)
	<tui_data_item_window>: Default the constructor.
	(struct tui_data_window) <tui_data_window>: Likewise.
	* tui/tui-disasm.h (struct tui_disasm_window) <tui_disasm_window>:
	Default the constructor.
	* tui/tui-data.h (struct tui_gen_win_info) <tui_gen_win_info>:
	Default the constructor.
	<type>: Remove.
	(struct tui_win_info) <tui_win_info>: Default the constructor.
	* tui/tui-data.c (tui_win_info::tui_win_info): Remove.
	* tui/tui-command.h (struct tui_cmd_window) <tui_cmd_window>:
	Default the constructor.

Change-Id: I594cd07d2e0bba71ad594a6fb263904ce2febcd6
---
 gdb/ChangeLog           | 27 +++++++++++++++++++++++++++
 gdb/tui/tui-command.h   |  5 +----
 gdb/tui/tui-data.c      |  5 -----
 gdb/tui/tui-data.h      | 11 +++--------
 gdb/tui/tui-disasm.h    |  5 +----
 gdb/tui/tui-regs.h      | 10 ++--------
 gdb/tui/tui-source.h    |  5 +----
 gdb/tui/tui-stack.h     |  1 -
 gdb/tui/tui-winsource.c |  8 +++-----
 gdb/tui/tui-winsource.h |  2 +-
 gdb/tui/tui.h           |  3 ---
 11 files changed, 39 insertions(+), 43 deletions(-)

diff --git a/gdb/tui/tui-command.h b/gdb/tui/tui-command.h
index fca1f545730..211d0c8d8a2 100644
--- a/gdb/tui/tui-command.h
+++ b/gdb/tui/tui-command.h
@@ -27,10 +27,7 @@
 /* The TUI command window.  */
 struct tui_cmd_window : public tui_win_info
 {
-  tui_cmd_window ()
-    : tui_win_info (CMD_WIN)
-  {
-  }
+  tui_cmd_window () = default;
 
   DISABLE_COPY_AND_ASSIGN (tui_cmd_window);
 
diff --git a/gdb/tui/tui-data.c b/gdb/tui/tui-data.c
index ead8b1043ca..db637d8fbe6 100644
--- a/gdb/tui/tui-data.c
+++ b/gdb/tui/tui-data.c
@@ -129,11 +129,6 @@ tui_prev_win (struct tui_win_info *cur_win)
 }
 
 
-tui_win_info::tui_win_info (enum tui_win_type type)
-  : tui_gen_win_info (type)
-{
-}
-
 void
 tui_win_info::rerender ()
 {
diff --git a/gdb/tui/tui-data.h b/gdb/tui/tui-data.h
index 96265bb4215..56600926636 100644
--- a/gdb/tui/tui-data.h
+++ b/gdb/tui/tui-data.h
@@ -22,7 +22,7 @@
 #ifndef TUI_TUI_DATA_H
 #define TUI_TUI_DATA_H
 
-#include "tui/tui.h"	/* For enum tui_win_type.  */
+#include "tui/tui.h"
 #include "gdb_curses.h"	/* For WINDOW.  */
 #include "observable.h"
 
@@ -44,10 +44,7 @@ struct tui_gen_win_info
 {
 protected:
 
-  explicit tui_gen_win_info (enum tui_win_type t)
-    : type (t)
-  {
-  }
+  tui_gen_win_info () = default;
 
   /* This is called after the window is resized, and should update the
      window's contents.  */
@@ -110,8 +107,6 @@ public:
 
   /* Window handle.  */
   std::unique_ptr<WINDOW, curses_deleter> handle;
-  /* Type of window.  */
-  enum tui_win_type type;
   /* Window width.  */
   int width = 0;
   /* Window height.  */
@@ -155,7 +150,7 @@ struct tui_win_info : public tui_gen_win_info
 {
 protected:
 
-  explicit tui_win_info (enum tui_win_type type);
+  tui_win_info () = default;
   DISABLE_COPY_AND_ASSIGN (tui_win_info);
 
   /* Scroll the contents vertically.  This is only called via
diff --git a/gdb/tui/tui-disasm.h b/gdb/tui/tui-disasm.h
index 416be95fd8b..dd020310746 100644
--- a/gdb/tui/tui-disasm.h
+++ b/gdb/tui/tui-disasm.h
@@ -30,10 +30,7 @@
 
 struct tui_disasm_window : public tui_source_window_base
 {
-  tui_disasm_window ()
-    : tui_source_window_base (DISASSEM_WIN)
-  {
-  }
+  tui_disasm_window () = default;
 
   DISABLE_COPY_AND_ASSIGN (tui_disasm_window);
 
diff --git a/gdb/tui/tui-regs.h b/gdb/tui/tui-regs.h
index 97e02b1a47d..8c49888373f 100644
--- a/gdb/tui/tui-regs.h
+++ b/gdb/tui/tui-regs.h
@@ -28,10 +28,7 @@
 
 struct tui_data_item_window : public tui_gen_win_info
 {
-  tui_data_item_window ()
-    : tui_gen_win_info (DATA_ITEM_WIN)
-  {
-  }
+  tui_data_item_window () = default;
 
   DISABLE_COPY_AND_ASSIGN (tui_data_item_window);
 
@@ -61,10 +58,7 @@ struct tui_data_item_window : public tui_gen_win_info
 /* The TUI registers window.  */
 struct tui_data_window : public tui_win_info
 {
-  tui_data_window ()
-    : tui_win_info (DATA_WIN)
-  {
-  }
+  tui_data_window () = default;
 
   DISABLE_COPY_AND_ASSIGN (tui_data_window);
 
diff --git a/gdb/tui/tui-source.h b/gdb/tui/tui-source.h
index 06ca8d52fe4..58dc5e88cf7 100644
--- a/gdb/tui/tui-source.h
+++ b/gdb/tui/tui-source.h
@@ -31,10 +31,7 @@ struct symtab;
 
 struct tui_source_window : public tui_source_window_base
 {
-  tui_source_window ()
-    : tui_source_window_base (SRC_WIN)
-  {
-  }
+  tui_source_window () = default;
 
   DISABLE_COPY_AND_ASSIGN (tui_source_window);
 
diff --git a/gdb/tui/tui-stack.h b/gdb/tui/tui-stack.h
index bea3e79279b..fde7c6dd2c9 100644
--- a/gdb/tui/tui-stack.h
+++ b/gdb/tui/tui-stack.h
@@ -31,7 +31,6 @@ struct frame_info;
 struct tui_locator_window : public tui_gen_win_info
 {
   tui_locator_window ()
-    : tui_gen_win_info (LOCATOR_WIN)
   {
     full_name[0] = 0;
     proc_name[0] = 0;
diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c
index 69070115ec6..bd7a34ebbd5 100644
--- a/gdb/tui/tui-winsource.c
+++ b/gdb/tui/tui-winsource.c
@@ -285,10 +285,8 @@ tui_source_window_base::show_source_content ()
   refresh_window ();
 }
 
-tui_source_window_base::tui_source_window_base (enum tui_win_type type)
-  : tui_win_info (type)
+tui_source_window_base::tui_source_window_base ()
 {
-  gdb_assert (type == SRC_WIN || type == DISASSEM_WIN);
   start_line_or_addr.loa = LOA_ADDRESS;
   start_line_or_addr.u.addr = 0;
 
@@ -333,7 +331,7 @@ tui_source_window_base::rerender ()
       struct gdbarch *gdbarch = get_frame_arch (frame);
 
       struct symtab *s = find_pc_line_symtab (get_frame_pc (frame));
-      if (type != SRC_WIN)
+      if (this != TUI_SRC_WIN)
 	find_line_pc (s, cursal.line, &cursal.pc);
       update_source_window (gdbarch, cursal);
     }
@@ -348,7 +346,7 @@ tui_source_window_base::refill ()
 {
   symtab_and_line sal {};
 
-  if (type == SRC_WIN)
+  if (this == TUI_SRC_WIN)
     {
       sal = get_current_source_symtab_and_line ();
       if (sal.symtab == NULL)
diff --git a/gdb/tui/tui-winsource.h b/gdb/tui/tui-winsource.h
index cae535fab07..4ac20d80502 100644
--- a/gdb/tui/tui-winsource.h
+++ b/gdb/tui/tui-winsource.h
@@ -75,7 +75,7 @@ struct tui_source_element
 struct tui_source_window_base : public tui_win_info
 {
 protected:
-  explicit tui_source_window_base (enum tui_win_type type);
+  tui_source_window_base ();
   ~tui_source_window_base ();
 
   DISABLE_COPY_AND_ASSIGN (tui_source_window_base);
diff --git a/gdb/tui/tui.h b/gdb/tui/tui.h
index 6605901f21a..816b1e92851 100644
--- a/gdb/tui/tui.h
+++ b/gdb/tui/tui.h
@@ -40,9 +40,6 @@ enum tui_win_type
   CMD_WIN,
   /* This must ALWAYS be AFTER the major windows last.  */
   MAX_MAJOR_WINDOWS,
-  /* Auxiliary windows.  */
-  LOCATOR_WIN,
-  DATA_ITEM_WIN
 };
 
 extern CORE_ADDR tui_get_low_disassembly_address (struct gdbarch *,
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 06/24] Reimplement "tui reg" command
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (4 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 09/24] Allow TUI sub-layouts in "new-layout" command Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 22/24] Use error_no_arg in TUI Tom Tromey
                   ` (18 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This reimplements the low-level layout function that is used by the
"tui reg" command.  Now it simply calls into the existing "layout"
command, though this will be changed again in a subsequent patch.  The
rationale for this patch is that it makes it simpler to remove
"enum tui_layout_type".

gdb/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-regs.c (tui_reg_layout): Remove.
	(tui_reg_command): Use tui_regs_layout.
	* tui/tui-layout.h (tui_reg_command): Declare.
	* tui/tui-layout.c (tui_reg_command): New function.

Change-Id: I0ca6884e2967005e7d3fbf5f13a0ac8f9c3298cf
---
 gdb/ChangeLog        |  7 +++++++
 gdb/tui/tui-layout.c |  8 ++++++++
 gdb/tui/tui-layout.h |  3 +++
 gdb/tui/tui-regs.c   | 17 +----------------
 4 files changed, 19 insertions(+), 16 deletions(-)

diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index 86b496d273e..68a55179d98 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -286,6 +286,14 @@ tui_next_layout ()
 
 /* See tui-layout.h.  */
 
+void
+tui_regs_layout ()
+{
+  tui_layout_command ("regs", 0);
+}
+
+/* See tui-layout.h.  */
+
 void
 tui_remove_some_windows ()
 {
diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h
index f711b004b84..05089ab8fff 100644
--- a/gdb/tui/tui-layout.h
+++ b/gdb/tui/tui-layout.h
@@ -194,6 +194,9 @@ extern void tui_set_layout (enum tui_layout_type);
 /* Switch to the next layout.  */
 extern void tui_next_layout ();
 
+/* Show the register window.  Like "layout regs".  */
+extern void tui_regs_layout ();
+
 /* Remove some windows from the layout, leaving only the focused
    window and the command window; if no window has the focus, then
    some other window is chosen to remain.  */
diff --git a/gdb/tui/tui-regs.c b/gdb/tui/tui-regs.c
index 41b8f0d933c..ad57069968c 100644
--- a/gdb/tui/tui-regs.c
+++ b/gdb/tui/tui-regs.c
@@ -542,21 +542,6 @@ tui_reg_prev (struct reggroup *current_group, struct gdbarch *gdbarch)
   return group;
 }
 
-/* A helper function to display the register window in the appropriate
-   way.  */
-
-static void
-tui_reg_layout ()
-{
-  enum tui_layout_type cur_layout = tui_current_layout ();
-  enum tui_layout_type new_layout;
-  if (cur_layout == SRC_COMMAND || cur_layout == SRC_DATA_COMMAND)
-    new_layout = SRC_DATA_COMMAND;
-  else
-    new_layout = DISASSEM_DATA_COMMAND;
-  tui_set_layout (new_layout);
-}
-
 /* Implement the 'tui reg' command.  Changes the register group displayed
    in the tui register window.  Displays the tui register window if it is
    not already on display.  */
@@ -578,7 +563,7 @@ tui_reg_command (const char *args, int from_tty)
 	 appropriate layout.  We need to do this before trying to run the
 	 'next' or 'prev' commands.  */
       if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->is_visible ())
-	tui_reg_layout ();
+	tui_regs_layout ();
 
       struct reggroup *current_group = TUI_DATA_WIN->get_current_group ();
       if (strncmp (args, "next", len) == 0)
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 14/24] Handle ambiguity in tui_partial_win_by_name
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 20/24] Allow TUI windows in Python Tom Tromey
                   ` (23 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This changes tui_partial_win_by_name to correctly handle an ambiguous
name prefix.  This will be important once the user can register new
window types.

2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-win.c (tui_partial_win_by_name): Handle ambiguity
	correctly.

Change-Id: I59aaacd697eeab649164183457ef722dae58d60d
---
 gdb/ChangeLog     |  5 +++++
 gdb/tui/tui-win.c | 13 +++++++++++--
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/gdb/tui/tui-win.c b/gdb/tui/tui-win.c
index 8206f3e6965..6eab125d731 100644
--- a/gdb/tui/tui-win.c
+++ b/gdb/tui/tui-win.c
@@ -694,18 +694,27 @@ tui_scroll_right_command (const char *arg, int from_tty)
 static struct tui_win_info *
 tui_partial_win_by_name (gdb::string_view name)
 {
+  struct tui_win_info *best = nullptr;
+
   if (name != NULL)
     {
       for (tui_win_info *item : all_tui_windows ())
 	{
 	  const char *cur_name = item->name ();
 
-	  if (startswith (cur_name, name))
+	  if (name == cur_name)
 	    return item;
+	  if (startswith (cur_name, name))
+	    {
+	      if (best != nullptr)
+		error (_("Window name \"%*s\" is ambiguous"),
+		       (int) name.size (), name.data ());
+	      best = item;
+	    }
 	}
     }
 
-  return NULL;
+  return best;
 }
 
 /* Set focus to the window named by 'arg'.  */
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 20/24] Allow TUI windows in Python
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
  2020-01-04 18:34 ` [PATCH 14/24] Handle ambiguity in tui_partial_win_by_name Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:57   ` Eli Zaretskii
  2020-03-10 22:23   ` Simon Marchi
  2020-01-04 18:34 ` [PATCH 16/24] TUI windows do not need to store their type Tom Tromey
                   ` (22 subsequent siblings)
  24 siblings, 2 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This patch adds support for writing new TUI windows in Python.

2020-01-04  Tom Tromey  <tom@tromey.com>

	* NEWS: Add entry for gdb.register_window_type.
	* tui/tui-layout.h (window_factory): New typedef.
	(tui_register_window): Declare.
	* tui/tui-layout.c (saved_tui_windows): New global.
	(tui_apply_current_layout): Use it.
	(tui_register_window): New function.
	* python/python.c (do_start_initialization): Call
	gdbpy_initialize_tui.
	(python_GdbMethods): Add "register_window_type" function.
	* python/python-internal.h (gdbpy_register_tui_window)
	(gdbpy_initialize_tui): Declare.
	* python/py-tui.c: New file.
	* Makefile.in (SUBDIR_PYTHON_SRCS): Add py-tui.c.

gdb/doc/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* python.texi (Python API): Add menu item.
	(TUI Windows In Python): New node.

gdb/testsuite/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* gdb.python/tui-window.exp: New file.
	* gdb.python/tui-window.py: New file.

Change-Id: I85fbfb923a1840450a00a7dce113a05d7f048baa
---
 gdb/ChangeLog                           |  16 +
 gdb/Makefile.in                         |   1 +
 gdb/NEWS                                |   5 +
 gdb/doc/ChangeLog                       |   5 +
 gdb/doc/python.texi                     | 101 +++++
 gdb/python/py-tui.c                     | 510 ++++++++++++++++++++++++
 gdb/python/python-internal.h            |   4 +
 gdb/python/python.c                     |  10 +-
 gdb/testsuite/ChangeLog                 |   5 +
 gdb/testsuite/gdb.python/tui-window.exp |  51 +++
 gdb/testsuite/gdb.python/tui-window.py  |  37 ++
 gdb/tui/tui-layout.c                    |  28 +-
 gdb/tui/tui-layout.h                    |  10 +
 13 files changed, 779 insertions(+), 4 deletions(-)
 create mode 100644 gdb/python/py-tui.c
 create mode 100644 gdb/testsuite/gdb.python/tui-window.exp
 create mode 100644 gdb/testsuite/gdb.python/tui-window.py

diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 448a495bb3b..adfe607dc87 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -401,6 +401,7 @@ SUBDIR_PYTHON_SRCS = \
 	python/py-symbol.c \
 	python/py-symtab.c \
 	python/py-threadevent.c \
+	python/py-tui.c \
 	python/py-type.c \
 	python/py-unwind.c \
 	python/py-utils.c \
diff --git a/gdb/NEWS b/gdb/NEWS
index a936620c0a8..f15c5f5c15f 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -15,6 +15,11 @@ tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]...
   Define a new TUI layout, specifying its name and the windows that
   will be displayed.
 
+* Python API
+
+  ** gdb.register_window_type can be used to implement new TUI windows
+     in Python.
+
 *** Changes in GDB 9
 
 * 'thread-exited' event is now available in the annotations interface.
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 8124077ab33..d0ce9ea35e7 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -163,6 +163,7 @@ optional arguments while skipping others.  Example:
                                 using Python.
 * Lazy Strings In Python::      Python representation of lazy strings.
 * Architectures In Python::     Python representation of architectures.
+* TUI Windows In Python::       Implementing new TUI windows.
 @end menu
 
 @node Basic Python
@@ -5673,6 +5674,106 @@ instruction in bytes.
 @end table
 @end defun
 
+@node TUI Windows In Python
+@subsubsection Implementing new TUI windows
+@cindex Python TUI Windows
+
+New TUI (@pxref{TUI}) windows can be implemented in Python.
+
+@findex gdb.register_window_type
+@defun gdb.register_window_type (@var{name}, @var{factory})
+Because TUI windows are created and destroyed depending on the layout
+the user chooses, new window types are implemented by registering a
+factory function with @value{GDBN}.
+
+@var{name} is the name of the new window.  It's an error to try to
+replace one of the built-in windows, but other window types can be
+replaced.
+
+@var{function} is a factory function that is called to create the TUI
+window.  This is called with a single argument of type
+@code{gdb.TuiWindow}, described below.  It should return an object
+that implements the TUI window protocol, also described below.
+@end defun
+
+As mentioned above, when a factory function is called, it is passed a
+an object of type @code{gdb.TuiWindow}.  This object has these
+methods and attributes:
+
+@defun TuiWindow.is_valid ()
+This method returns @code{True} when this window is valid.  When the
+user changes the TUI layout, windows no longer visible in the new
+layout will be destroyed.  At this point, the @code{gdb.TuiWindow}
+will no longer be valid, and methods (and attributes) other than
+@code{is_valid} will throw an exception.
+@end defun
+
+@defvar TuiWindow.width
+This attribute holds the width of the window.  It is not writable.
+@end defvar
+
+@defvar TuiWindow.height
+This attribute holds the height of the window.  It is not writable.
+@end defvar
+
+@defvar TuiWindow.title
+This attribute holds the window's title, a string.  This is normally
+displayed above the window.  This attribute can be modified.
+@end defvar
+
+@defun TuiWindow.erase ()
+Remove all the contents of the window.
+@end defun
+
+@defun TuiWindow.write (@var{string})
+Write @var{string} to the window.  @var{string} can contain ANSI
+terminal escape styling sequences; @value{GDBN} will convert translate
+these as appropriate for the terminal.
+@end defun
+
+The factory function that you supply should return an object
+conforming to the TUI window protocol.  These are the method that can
+be called on this object, which is referred to below as the ``window
+object''.  The methods documented below are optional; if the object
+does not implement one of these methods, @value{GDBN} will not attempt
+to call it.  Additional new methods may be added to the window
+protocol in the future.  @value{GDBN} guarantees that they will begin
+with a lower-case letter, so you can start implementation methods with
+upper-case letters or underscore to avoid any future conflicts.
+
+@defun Window.close ()
+When the TUI window is closed, the @code{gdb.TuiWindow} object will be
+put into an invalid state.  At this time, @value{GDBN} will call
+@code{close} method on the window object.
+
+After this method is called, @value{GDBN} will discard any references
+it holds on this window object, and will no longer call methods on
+this object.
+@end defun
+
+@defun Window.render ()
+In some situations, a TUI window can change size.  For example, this
+can happen if the user resizes the terminal, or changes the layout.
+When this happens, @value{GDBN} will call the @code{render} method on
+the window object.
+
+If your window is intended to update in response to changes in the
+inferior, you will probably also want to register event listeners and
+send output to the @code{gdb.TuiWindow}.
+@end defun
+
+@defun Window.hscroll (@var{num})
+This is a request to scroll the window horizontally.  @var{num} is the
+amount by which to scroll, with negative numbers meaning to scroll
+right.
+@end defun
+
+@defun Window.vscroll (@var{num})
+This is a request to scroll the window vertically.  @var{num} is the
+amount by which to scroll, with negative numbers meaning to scroll
+backward.
+@end defun
+
 @node Python Auto-loading
 @subsection Python Auto-loading
 @cindex Python auto-loading
diff --git a/gdb/python/py-tui.c b/gdb/python/py-tui.c
new file mode 100644
index 00000000000..4cb86ae75da
--- /dev/null
+++ b/gdb/python/py-tui.c
@@ -0,0 +1,510 @@
+/* TUI windows implemented in Python
+
+   Copyright (C) 2020 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "python-internal.h"
+#include "gdb_curses.h"
+
+#ifdef TUI
+
+#include "tui/tui-data.h"
+#include "tui/tui-io.h"
+#include "tui/tui-layout.h"
+#include "tui/tui-wingeneral.h"
+#include "tui/tui-winsource.h"
+
+class tui_py_window;
+
+/* A PyObject representing a TUI window.  */
+
+struct gdbpy_tui_window
+{
+  PyObject_HEAD
+
+  /* The TUI window, or nullptr if the window has been deleted.  */
+  tui_py_window *window;
+};
+
+extern PyTypeObject gdbpy_tui_window_object_type
+    CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("gdbpy_tui_window");
+
+/* A TUI window written in Python.  */
+
+class tui_py_window : public tui_win_info
+{
+public:
+
+  tui_py_window (const char *name, gdbpy_ref<gdbpy_tui_window> wrapper)
+    : m_name (name),
+      m_wrapper (std::move (wrapper))
+  {
+    m_wrapper->window = this;
+  }
+
+  ~tui_py_window ();
+
+  DISABLE_COPY_AND_ASSIGN (tui_py_window);
+
+  /* Set the "user window" to the indicated reference.  The user
+     window is the object returned the by user-defined window
+     constructor.  */
+  void set_user_window (gdbpy_ref<> &&user_window)
+  {
+    m_window = std::move (user_window);
+  }
+
+  const char *name () const override
+  {
+    return m_name.c_str ();
+  }
+
+  void rerender () override;
+  void do_scroll_vertical (int num_to_scroll) override;
+  void do_scroll_horizontal (int num_to_scroll) override;
+
+  /* Erase and re-box the window.  */
+  void erase ()
+  {
+    if (is_visible ())
+      {
+	werase (handle.get ());
+	check_and_display_highlight_if_needed ();
+	cursor_x = 0;
+	cursor_y = 0;
+      }
+  }
+
+  /* Write STR to the window.  */
+  void output (const char *str);
+
+  /* A helper function to compute the viewport width.  */
+  int viewport_width () const
+  {
+    return std::max (0, width - 2);
+  }
+
+  /* A helper function to compute the viewport height.  */
+  int viewport_height () const
+  {
+    return std::max (0, height - 2);
+  }
+
+private:
+
+  /* Location of the cursor.  */
+  int cursor_x = 0;
+  int cursor_y = 0;
+
+  /* The name of this window.  */
+  std::string m_name;
+
+  /* The underlying Python window object.  */
+  gdbpy_ref<> m_window;
+
+  /* The Python wrapper for this object.  */
+  gdbpy_ref<gdbpy_tui_window> m_wrapper;
+};
+
+tui_py_window::~tui_py_window ()
+{
+  gdbpy_enter enter_py (get_current_arch (), current_language);
+
+  if (PyObject_HasAttrString (m_window.get (), "close"))
+    {
+      gdbpy_ref<> result (PyObject_CallMethod (m_window.get (), "close",
+					       nullptr));
+      if (result == nullptr)
+	gdbpy_print_stack ();
+    }
+
+  /* Unlink.  */
+  m_wrapper->window = nullptr;
+  /* Explicitly free the Python references.  We have to do this
+     manually because we need to hold the GIL while doing so.  */
+  m_wrapper.reset (nullptr);
+  m_window.reset (nullptr);
+}
+
+void
+tui_py_window::rerender ()
+{
+  gdbpy_enter enter_py (get_current_arch (), current_language);
+
+  if (PyObject_HasAttrString (m_window.get (), "render"))
+    {
+      gdbpy_ref<> result (PyObject_CallMethod (m_window.get (), "render",
+					       nullptr));
+      if (result == nullptr)
+	gdbpy_print_stack ();
+    }
+}
+
+void
+tui_py_window::do_scroll_horizontal (int num_to_scroll)
+{
+  gdbpy_enter enter_py (get_current_arch (), current_language);
+
+  if (PyObject_HasAttrString (m_window.get (), "hscroll"))
+    {
+      gdbpy_ref<> result (PyObject_CallMethod (m_window.get(), "hscroll",
+					       "i", num_to_scroll, nullptr));
+      if (result == nullptr)
+	gdbpy_print_stack ();
+    }
+}
+
+void
+tui_py_window::do_scroll_vertical (int num_to_scroll)
+{
+  gdbpy_enter enter_py (get_current_arch (), current_language);
+
+  if (PyObject_HasAttrString (m_window.get (), "vscroll"))
+    {
+      gdbpy_ref<> result (PyObject_CallMethod (m_window.get (), "vscroll",
+					       "i", num_to_scroll, nullptr));
+      if (result == nullptr)
+	gdbpy_print_stack ();
+    }
+}
+
+void
+tui_py_window::output (const char *text)
+{
+  int vwidth = viewport_width ();
+
+  while (cursor_y < viewport_height () && *text != '\0')
+    {
+      wmove (handle.get (), cursor_y + 1, cursor_x + 1);
+
+      std::string line = tui_copy_source_line (&text, 0, 0,
+					       vwidth - cursor_x, 0);
+      tui_puts (line.c_str (), handle.get ());
+
+      if (*text == '\n')
+	{
+	  ++text;
+	  ++cursor_y;
+	  cursor_x = 0;
+	}
+      else
+	cursor_x = getcurx (handle.get ()) - 1;
+    }
+
+  wrefresh (handle.get ());
+}
+
+\f
+
+/* A callable that is used to create a TUI window.  It wraps the
+   user-supplied window constructor.  */
+
+class gdbpy_tui_window_maker
+{
+public:
+
+  explicit gdbpy_tui_window_maker (gdbpy_ref<> &&constr)
+    : m_constr (std::move (constr))
+  {
+  }
+
+  ~gdbpy_tui_window_maker ();
+
+  gdbpy_tui_window_maker (gdbpy_tui_window_maker &&other)
+    : m_constr (std::move (other.m_constr))
+  {
+  }
+
+  gdbpy_tui_window_maker (const gdbpy_tui_window_maker &other)
+  {
+    gdbpy_enter enter_py (get_current_arch (), current_language);
+    m_constr = other.m_constr;
+  }
+
+  gdbpy_tui_window_maker &operator= (gdbpy_tui_window_maker &&other)
+  {
+    m_constr = std::move (other.m_constr);
+    return *this;
+  }
+
+  gdbpy_tui_window_maker &operator= (const gdbpy_tui_window_maker &other)
+  {
+    gdbpy_enter enter_py (get_current_arch (), current_language);
+    m_constr = other.m_constr;
+    return *this;
+  }
+
+  tui_win_info *operator() (const char *name);
+
+private:
+
+  /* A constructor that is called to make a TUI window.  */
+  gdbpy_ref<> m_constr;
+};
+
+gdbpy_tui_window_maker::~gdbpy_tui_window_maker ()
+{
+  gdbpy_enter enter_py (get_current_arch (), current_language);
+  m_constr.reset (nullptr);
+}
+
+tui_win_info *
+gdbpy_tui_window_maker::operator() (const char *win_name)
+{
+  gdbpy_enter enter_py (get_current_arch (), current_language);
+
+  gdbpy_ref<gdbpy_tui_window> wrapper
+    (PyObject_New (gdbpy_tui_window, &gdbpy_tui_window_object_type));
+  if (wrapper == nullptr)
+    {
+      gdbpy_print_stack ();
+      return nullptr;
+    }
+
+  std::unique_ptr<tui_py_window> window
+    (new tui_py_window (win_name, wrapper));
+
+  gdbpy_ref<> user_window
+    (PyObject_CallFunctionObjArgs (m_constr.get (),
+				   (PyObject *) wrapper.get (),
+				   nullptr));
+  if (user_window == nullptr)
+    {
+      gdbpy_print_stack ();
+      return nullptr;
+    }
+
+  window->set_user_window (std::move (user_window));
+  /* Window is now owned by the TUI.  */
+  return window.release ();
+}
+
+/* Implement "gdb.register_window_type".  */
+
+PyObject *
+gdbpy_register_tui_window (PyObject *self, PyObject *args, PyObject *kw)
+{
+  static const char *keywords[] = { "name", "constructor", nullptr };
+
+  const char *name;
+  PyObject *cons_obj;
+
+  if (!gdb_PyArg_ParseTupleAndKeywords (args, kw, "sO", keywords,
+					&name, &cons_obj))
+    return nullptr;
+
+  try
+    {
+      gdbpy_tui_window_maker constr (gdbpy_ref<>::new_reference (cons_obj));
+      tui_register_window (name, constr);
+    }
+  catch (const gdb_exception &except)
+    {
+      gdbpy_convert_exception (except);
+      return nullptr;
+    }
+
+  Py_RETURN_NONE;
+}
+
+\f
+
+/* Require that "Window" be a valid window.  */
+
+#define REQUIRE_WINDOW(Window)					\
+    do {							\
+      if ((Window)->window == nullptr)				\
+        return PyErr_Format (PyExc_RuntimeError,		\
+                             _("TUI window is invalid."));	\
+    } while (0)
+
+/* Python function which checks the validity of a TUI window
+   object.  */
+static PyObject *
+gdbpy_tui_is_valid (PyObject *self, PyObject *args)
+{
+  gdbpy_tui_window *win = (gdbpy_tui_window *) self;
+
+  if (win->window != nullptr)
+    Py_RETURN_TRUE;
+  Py_RETURN_FALSE;
+}
+
+/* Python function that erases the TUI window.  */
+static PyObject *
+gdbpy_tui_erase (PyObject *self, PyObject *args)
+{
+  gdbpy_tui_window *win = (gdbpy_tui_window *) self;
+
+  REQUIRE_WINDOW (win);
+
+  win->window->erase ();
+
+  Py_RETURN_NONE;
+}
+
+/* Python function that writes some text to a TUI window.  */
+static PyObject *
+gdbpy_tui_write (PyObject *self, PyObject *args)
+{
+  gdbpy_tui_window *win = (gdbpy_tui_window *) self;
+  const char *text;
+
+  if (!PyArg_ParseTuple (args, "s", &text))
+    return nullptr;
+
+  REQUIRE_WINDOW (win);
+
+  win->window->output (text);
+
+  Py_RETURN_NONE;
+}
+
+/* Return the width of the TUI window.  */
+static PyObject *
+gdbpy_tui_width (PyObject *self, void *closure)
+{
+  gdbpy_tui_window *win = (gdbpy_tui_window *) self;
+  REQUIRE_WINDOW (win);
+  return PyLong_FromLong (win->window->viewport_width ());
+}
+
+/* Return the height of the TUI window.  */
+static PyObject *
+gdbpy_tui_height (PyObject *self, void *closure)
+{
+  gdbpy_tui_window *win = (gdbpy_tui_window *) self;
+  REQUIRE_WINDOW (win);
+  return PyLong_FromLong (win->window->viewport_height ());
+}
+
+/* Return the title of the TUI window.  */
+static PyObject *
+gdbpy_tui_title (PyObject *self, void *closure)
+{
+  gdbpy_tui_window *win = (gdbpy_tui_window *) self;
+  REQUIRE_WINDOW (win);
+  return host_string_to_python_string (win->window->title.c_str ()).release ();
+}
+
+/* Set the title of the TUI window.  */
+static int
+gdbpy_tui_set_title (PyObject *self, PyObject *newvalue, void *closure)
+{
+  gdbpy_tui_window *win = (gdbpy_tui_window *) self;
+
+  if (win->window == nullptr)
+    {
+      PyErr_Format (PyExc_RuntimeError, _("TUI window is invalid."));
+      return -1;
+    }
+
+  if (win->window == nullptr)
+    {
+      PyErr_Format (PyExc_TypeError, _("Cannot delete \"title\" attribute."));
+      return -1;
+    }
+
+  gdb::unique_xmalloc_ptr<char> value
+    = python_string_to_host_string (newvalue);
+  if (value == nullptr)
+    return -1;
+
+  win->window->title = value.get ();
+  return 0;
+}
+
+static gdb_PyGetSetDef tui_object_getset[] =
+{
+  { "width", gdbpy_tui_width, NULL, "Width of the window.", NULL },
+  { "height", gdbpy_tui_height, NULL, "Height of the window.", NULL },
+  { "title", gdbpy_tui_title, gdbpy_tui_set_title, "Title of the window.",
+    NULL },
+  { NULL }  /* Sentinel */
+};
+
+static PyMethodDef tui_object_methods[] =
+{
+  { "is_valid", gdbpy_tui_is_valid, METH_NOARGS,
+    "is_valid () -> Boolean\n\
+Return true if this TUI window is valid, false if not." },
+  { "erase", gdbpy_tui_erase, METH_NOARGS,
+    "Erase the TUI window." },
+  { "write", (PyCFunction) gdbpy_tui_write, METH_VARARGS,
+    "Append a string to the TUI window." },
+  { NULL } /* Sentinel.  */
+};
+
+PyTypeObject gdbpy_tui_window_object_type =
+{
+  PyVarObject_HEAD_INIT (NULL, 0)
+  "gdb.TuiWindow",		  /*tp_name*/
+  sizeof (gdbpy_tui_window),	  /*tp_basicsize*/
+  0,				  /*tp_itemsize*/
+  0,				  /*tp_dealloc*/
+  0,				  /*tp_print*/
+  0,				  /*tp_getattr*/
+  0,				  /*tp_setattr*/
+  0,				  /*tp_compare*/
+  0,				  /*tp_repr*/
+  0,				  /*tp_as_number*/
+  0,				  /*tp_as_sequence*/
+  0,				  /*tp_as_mapping*/
+  0,				  /*tp_hash */
+  0,				  /*tp_call*/
+  0,				  /*tp_str*/
+  0,				  /*tp_getattro*/
+  0,				  /*tp_setattro */
+  0,				  /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  /*tp_flags*/
+  "GDB TUI window object",	  /* tp_doc */
+  0,				  /* tp_traverse */
+  0,				  /* tp_clear */
+  0,				  /* tp_richcompare */
+  0,				  /* tp_weaklistoffset */
+  0,				  /* tp_iter */
+  0,				  /* tp_iternext */
+  tui_object_methods,		  /* tp_methods */
+  0,				  /* tp_members */
+  tui_object_getset,		  /* tp_getset */
+  0,				  /* tp_base */
+  0,				  /* tp_dict */
+  0,				  /* tp_descr_get */
+  0,				  /* tp_descr_set */
+  0,				  /* tp_dictoffset */
+  0,				  /* tp_init */
+  0,				  /* tp_alloc */
+};
+
+#endif /* TUI */
+
+/* Initialize this module.  */
+
+int
+gdbpy_initialize_tui ()
+{
+#ifdef TUI
+  gdbpy_tui_window_object_type.tp_new = PyType_GenericNew;
+  if (PyType_Ready (&gdbpy_tui_window_object_type) < 0)
+    return -1;
+#endif	/* TUI */
+
+  return 0;
+}
diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h
index e2464548a7e..bbb66bd0f5c 100644
--- a/gdb/python/python-internal.h
+++ b/gdb/python/python-internal.h
@@ -447,6 +447,8 @@ PyObject *gdbpy_parameter_value (enum var_types type, void *var);
 char *gdbpy_parse_command_name (const char *name,
 				struct cmd_list_element ***base_list,
 				struct cmd_list_element **start_list);
+PyObject *gdbpy_register_tui_window (PyObject *self, PyObject *args,
+				     PyObject *kw);
 
 PyObject *symtab_and_line_to_sal_object (struct symtab_and_line sal);
 PyObject *symtab_to_symtab_object (struct symtab *symtab);
@@ -543,6 +545,8 @@ int gdbpy_initialize_xmethods (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 int gdbpy_initialize_unwind (void)
   CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
+int gdbpy_initialize_tui ()
+  CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION;
 
 /* A wrapper for PyErr_Fetch that handles reference counting for the
    caller.  */
diff --git a/gdb/python/python.c b/gdb/python/python.c
index bf214fae6e2..55103de2bd1 100644
--- a/gdb/python/python.c
+++ b/gdb/python/python.c
@@ -1686,7 +1686,8 @@ do_start_initialization ()
       || gdbpy_initialize_event () < 0
       || gdbpy_initialize_arch () < 0
       || gdbpy_initialize_xmethods () < 0
-      || gdbpy_initialize_unwind () < 0)
+      || gdbpy_initialize_unwind () < 0
+      || gdbpy_initialize_tui () < 0)
     return false;
 
 #define GDB_PY_DEFINE_EVENT_TYPE(name, py_name, doc, base)	\
@@ -2038,6 +2039,13 @@ or None if not set." },
     "convenience_variable (NAME, VALUE) -> None.\n\
 Set the value of the convenience variable $NAME." },
 
+#ifdef TUI
+  { "register_window_type", (PyCFunction) gdbpy_register_tui_window,
+    METH_VARARGS | METH_KEYWORDS,
+    "register_window_type (NAME, CONSTRUCSTOR) -> None\n\
+Register a TUI window constructor." },
+#endif	/* TUI */
+
   {NULL, NULL, 0, NULL}
 };
 
diff --git a/gdb/testsuite/gdb.python/tui-window.exp b/gdb/testsuite/gdb.python/tui-window.exp
new file mode 100644
index 00000000000..5c8909d4079
--- /dev/null
+++ b/gdb/testsuite/gdb.python/tui-window.exp
@@ -0,0 +1,51 @@
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test a TUI window implemented in Python.
+
+load_lib gdb-python.exp
+load_lib tuiterm.exp
+
+# This test doesn't care about the inferior.
+standard_testfile py-arch.c
+
+if {[build_executable "failed to prepare" ${testfile} ${srcfile}] == -1} {
+    return -1
+}
+
+Term::clean_restart 24 80 $testfile
+
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+set remote_python_file [gdb_remote_download host \
+			    ${srcdir}/${subdir}/${testfile}.py]
+gdb_test_no_output "source ${remote_python_file}" \
+    "source ${testfile}.py"
+
+gdb_test_no_output "tui new-layout test test 1 locator 0 cmd 1"
+
+if {![Term::enter_tui]} {
+    unsupported "TUI not supported"
+}
+
+Term::command "layout test"
+Term::check_contents "test title" \
+    "This Is The Title"
+Term::check_contents "Window display" "Test: 0"
+
+Term::resize 51 51
+# Remember that a resize request actually does two resizes...
+Term::check_contents "Window was updated" "Test: 2"
diff --git a/gdb/testsuite/gdb.python/tui-window.py b/gdb/testsuite/gdb.python/tui-window.py
new file mode 100644
index 00000000000..4deb585f138
--- /dev/null
+++ b/gdb/testsuite/gdb.python/tui-window.py
@@ -0,0 +1,37 @@
+# Copyright (C) 2020 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# A TUI window implemented in Python.
+
+import gdb
+
+the_window = None
+
+class TestWindow:
+    def __init__(self, win):
+        global the_window
+        the_window = win
+        self.count = 0
+        self.win = win
+        win.title = "This Is The Title"
+
+    def render(self):
+        self.win.erase()
+        w = self.win.width
+        h = self.win.height
+        self.win.write("Test: " + str(self.count) + " " + str(w) + "x" + str(h))
+        self.count = self.count + 1
+
+gdb.register_window_type("test", TestWindow)
diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index 797acc6e8b7..d55660f89f6 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -65,6 +65,11 @@ static tui_layout_split *asm_regs_layout;
 /* See tui-data.h.  */
 std::vector<tui_win_info *> tui_windows;
 
+/* When applying a layout, this is the list of all windows that were
+   in the previous layout.  This is used to re-use windows when
+   changing a layout.  */
+static std::vector<tui_win_info *> saved_tui_windows;
+
 /* See tui-layout.h.  */
 
 void
@@ -75,10 +80,10 @@ tui_apply_current_layout ()
 
   extract_display_start_addr (&gdbarch, &addr);
 
-  std::vector<tui_win_info *> saved_windows = std::move (tui_windows);
+  saved_tui_windows = std::move (tui_windows);
   tui_windows.clear ();
 
-  for (tui_win_info *win_info : saved_windows)
+  for (tui_win_info *win_info : saved_tui_windows)
     win_info->make_visible (false);
 
   applied_layout->apply (0, 0, tui_term_width (), tui_term_height ());
@@ -94,7 +99,7 @@ tui_apply_current_layout ()
 
   /* Now delete any window that was not re-applied.  */
   tui_win_info *focus = tui_win_with_focus ();
-  for (tui_win_info *win_info : saved_windows)
+  for (tui_win_info *win_info : saved_tui_windows)
     {
       if (!win_info->is_visible ())
 	{
@@ -107,6 +112,8 @@ tui_apply_current_layout ()
   if (gdbarch == nullptr && TUI_DISASM_WIN != nullptr)
     tui_get_begin_asm_address (&gdbarch, &addr);
   tui_update_source_windows_with_addr (gdbarch, addr);
+
+  saved_tui_windows.clear ();
 }
 
 /* See tui-layout.  */
@@ -395,6 +402,21 @@ initialize_known_windows ()
 
 /* See tui-layout.h.  */
 
+void
+tui_register_window (const char *name, window_factory &&factory)
+{
+  std::string name_copy = name;
+
+  if (name_copy == "src" || name_copy == "cmd" || name_copy == "regs"
+      || name_copy == "asm" || name_copy == "locator")
+    error (_("Window type \"%s\" is built-in"), name);
+
+  known_window_types->emplace (std::move (name_copy),
+			       std::move (factory));
+}
+
+/* See tui-layout.h.  */
+
 std::unique_ptr<tui_layout_base>
 tui_layout_window::clone () const
 {
diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h
index 6607e8d40d8..90618377e17 100644
--- a/gdb/tui/tui-layout.h
+++ b/gdb/tui/tui-layout.h
@@ -249,4 +249,14 @@ extern void tui_apply_current_layout ();
 extern void tui_adjust_window_height (struct tui_win_info *win,
 				      int new_height);
 
+/* The type of a function that is used to create a TUI window.  */
+
+typedef std::function<tui_gen_win_info * (const char *name)> window_factory;
+
+/* Register a new TUI window type.  NAME is the name of the window
+   type.  FACTORY is a function that can be called to instantiate the
+   window.  */
+
+extern void tui_register_window (const char *name, window_factory &&factory);
+
 #endif /* TUI_TUI_LAYOUT_H */
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 19/24] Remove the TUI annotation hack
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (21 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 08/24] Add the "tui new-layout" command Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:54 ` [PATCH 17/24] Change how TUI windows are instantiated Tom Tromey
  2020-02-22 20:22 ` [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

do_tui_putc has some code to remove annotations from gdb output.  This
was added in 2001, see commit a198b876bbcb.

However, I think this code is not needed.  It seems very unlikely to
enable both annotations and the TUI, and in any case I think this is
something that should not be supported.

So, this patch removes this code.

2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-io.c (do_tui_putc): Don't omit annotations.

Change-Id: I05728110365a362d37c9821df9c8779316100bb8
---
 gdb/ChangeLog    |  4 ++++
 gdb/tui/tui-io.c | 36 +++++++++++-------------------------
 2 files changed, 15 insertions(+), 25 deletions(-)

diff --git a/gdb/tui/tui-io.c b/gdb/tui/tui-io.c
index 9cb41104fe9..7f23ef9daf1 100644
--- a/gdb/tui/tui-io.c
+++ b/gdb/tui/tui-io.c
@@ -138,35 +138,21 @@ static int tui_readline_pipe[2];
 static void
 do_tui_putc (WINDOW *w, char c)
 {
-  static int tui_skip_line = -1;
-
-  /* Catch annotation and discard them.  We need two \032 and discard
-     until a \n is seen.  */
-  if (c == '\032')
-    {
-      tui_skip_line++;
-    }
-  else if (tui_skip_line != 1)
+  /* Expand TABs, since ncurses on MS-Windows doesn't.  */
+  if (c == '\t')
     {
-      tui_skip_line = -1;
-      /* Expand TABs, since ncurses on MS-Windows doesn't.  */
-      if (c == '\t')
-	{
-	  int col;
+      int col;
 
-	  col = getcurx (w);
-	  do
-	    {
-	      waddch (w, ' ');
-	      col++;
-	    }
-	  while ((col % 8) != 0);
+      col = getcurx (w);
+      do
+	{
+	  waddch (w, ' ');
+	  col++;
 	}
-      else
-	waddch (w, c);
+      while ((col % 8) != 0);
     }
-  else if (c == '\n')
-    tui_skip_line = -1;
+  else
+    waddch (w, c);
 }
 
 /* Update the cached value of the command window's start line based on
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 11/24] Add horizontal splitting to TUI layout
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (9 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 12/24] Change TUI window iteration Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:47   ` Eli Zaretskii
  2020-01-04 18:34 ` [PATCH 13/24] Reimplement tui_next_win and tui_prev_win Tom Tromey
                   ` (13 subsequent siblings)
  24 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This changes the TUI layout engine to add horizontal splitting.  Now,
windows can be side-by-side.

A horizontal split is defined using the "-horizontal" parameter to
"tui new-layout".

This also adds the first "winheight" test to the test suite.  One open
question is whether we want a new "winwidth" command, now that
horizontal layouts are possible.  This is easily done using the
generic layout code.

gdb/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	PR tui/17850:
	* tui/tui-win.c (tui_gen_win_info::max_width): New method.
	* tui/tui-layout.h (class tui_layout_base) <get_sizes>: Add
	"height" argument.
	(class tui_layout_window) <get_sizes>: Likewise.
	(class tui_layout_split) <tui_layout_split>: Add "vertical"
	argument.
	<get_sizes>: Add "height" argument.
	<m_vertical>: New field.
	* tui/tui-layout.c (tui_layout_split::clone): Update.
	(tui_layout_split::get_sizes): Add "height" argument.
	(tui_layout_split::adjust_size, tui_layout_split::apply): Update.
	(tui_new_layout_command): Parse "-horizontal".
	(_initialize_tui_layout): Update help string.
	(tui_layout_split::specification): Add "-horizontal" when needed.
	* tui/tui-layout.c (tui_layout_window::get_sizes): Add "height"
	argument.
	* tui/tui-data.h (struct tui_gen_win_info) <max_width, min_width>:
	New methods.

gdb/doc/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	PR tui/17850:
	* gdb.texinfo (TUI Commands): Document horizontal layouts.

gdb/testsuite/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	PR tui/17850:
	* gdb.tui/new-layout.exp: Add horizontal layout and winheight
	tests.

Change-Id: I38b35e504f34698578af86686be03c0fefd954ae
---
 gdb/ChangeLog                        |  22 ++++
 gdb/NEWS                             |   2 +
 gdb/doc/ChangeLog                    |   5 +
 gdb/doc/gdb.texinfo                  |  31 +++++-
 gdb/testsuite/ChangeLog              |   6 ++
 gdb/testsuite/gdb.tui/new-layout.exp |  21 +++-
 gdb/tui/tui-data.h                   |   9 ++
 gdb/tui/tui-layout.c                 | 147 +++++++++++++++++----------
 gdb/tui/tui-layout.h                 |  19 +++-
 gdb/tui/tui-win.c                    |   8 ++
 10 files changed, 207 insertions(+), 63 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index b8939693f4e..a936620c0a8 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -7,6 +7,8 @@
   that support it (see entry for GDB 9, below), providing faster
   performance for programs with many symbols.
 
+* TUI windows can now be arranged horizontally.
+
 * New commands
 
 tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]...
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 147d0c28c92..e011e992ba7 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -27909,11 +27909,23 @@ List and give the size of all displayed windows.
 Create a new TUI layout.  The new layout will be named @var{name}, and
 can be accessed using the @code{layout} command (see below).
 
-Each @var{window} parameter is the name of a window to display.  The
-windows will be displayed from top to bottom in the order listed.  The
-names of the windows are the same as the ones given to the
+Each @var{window} parameter is either the name of a window to display,
+or a window description.  The windows will be displayed from top to
+bottom in the order listed.
+
+The names of the windows are the same as the ones given to the
 @code{focus} command (see below); additional, the @code{locator}
-window can be specified.
+window can be specified.  Note that, because it is of fixed height,
+the weight assigned to the locator is of no importance.  It is
+conventional to use @samp{0} here.
+
+A window description looks a bit like an invocation of @code{tui
+new-layout}, and is of the form
+@{@r{[}@code{-horizontal}@r{]}@var{window} @var{weight} @r{[}@var{window} @var{weight}@dots{}@r{]}@}.
+
+This specifies a sub-layout.  If @code{-horizontal} is given, the
+windows in this description will be arranged side-by-side, rather than
+top-to-bottom.
 
 Each @var{weight} is an integer.  It is the weight of this window
 relative to all the other windows in the layout.  These numbers are
@@ -27930,6 +27942,17 @@ and register windows, followed by the locator, and then finally the
 command window.  The non-locator windows all have the same weight, so
 the terminal will be split into three roughly equal sections.
 
+Here is a more complex example, showing a horizontal layout:
+
+@example
+(gdb) tui new-layout example @{-horizontal src 1 asm 1@} 2 locator 0 cmd 1
+@end example
+
+This will result in side-by-side source and assembly windows; with the
+locator and command window being beneath these, filling the entire
+width of the terminal.  Because they have weight 2, the source and
+assembly windows will be twice the height of the command window.
+
 @item layout @var{name}
 @kindex layout
 Changes which TUI windows are displayed.  The @var{name} parameter
diff --git a/gdb/testsuite/gdb.tui/new-layout.exp b/gdb/testsuite/gdb.tui/new-layout.exp
index 406d9b25f08..61f878532e6 100644
--- a/gdb/testsuite/gdb.tui/new-layout.exp
+++ b/gdb/testsuite/gdb.tui/new-layout.exp
@@ -52,6 +52,11 @@ gdb_test_no_output "tui new-layout example2 {asm 1 locator 0} 1 cmd 1"
 gdb_test "help layout example2" \
     "Apply the \"example2\" layout.*tui new-layout example2 {asm 1 locator 0} 1 cmd 1"
 
+gdb_test_no_output "tui new-layout h {-horizontal asm 1 src 1} 1 locator 0 cmd 1"
+
+gdb_test "help layout h" \
+    "Apply the \"h\" layout.*tui new-layout h {-horizontal asm 1 src 1} 1 locator 0 cmd 1"
+
 if {![Term::enter_tui]} {
     unsupported "TUI not supported"
 }
@@ -62,4 +67,18 @@ gdb_assert {![string match "No Source Available" $text]} \
 
 Term::command "layout example"
 Term::check_contents "example layout shows assembly" \
-    "No Assembly Available"
+    "$hex <main>"
+
+Term::command "layout h"
+Term::check_box "left window box" 0 0 40 15
+Term::check_box "right window box" 39 0 41 15
+Term::check_contents "horizontal display" \
+    "$hex <main>.*21.*return 0"
+
+Term::command "winheight src - 5"
+Term::check_box "left window box after shrink" 0 0 40 10
+Term::check_box "right window box after shrink" 39 0 41 10
+
+Term::command "winheight src + 5"
+Term::check_box "left window box after grow" 0 0 40 15
+Term::check_box "right window box after grow" 39 0 41 15
diff --git a/gdb/tui/tui-data.h b/gdb/tui/tui-data.h
index 66866dbc23f..570b55b1962 100644
--- a/gdb/tui/tui-data.h
+++ b/gdb/tui/tui-data.h
@@ -82,6 +82,15 @@ public:
   /* Compute the minimum height of this window.  */
   virtual int min_height () const = 0;
 
+  /* Compute the maximum width of this window.  */
+  int max_width () const;
+
+  /* Compute the minimum width of this window.  */
+  int min_width () const
+  {
+    return 3;
+  }
+
   /* Return true if this window can be boxed.  */
   virtual bool can_box () const
   {
diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index be6c754d022..f33317beee8 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -355,12 +355,20 @@ tui_layout_window::apply (int x_, int y_, int width_, int height_)
 /* See tui-layout.h.  */
 
 void
-tui_layout_window::get_sizes (int *min_height, int *max_height)
+tui_layout_window::get_sizes (bool height, int *min_value, int *max_value)
 {
   if (m_window == nullptr)
     m_window = tui_get_window_by_name (m_contents);
-  *min_height = m_window->min_height ();
-  *max_height = m_window->max_height ();
+  if (height)
+    {
+      *min_value = m_window->min_height ();
+      *max_value = m_window->max_height ();
+    }
+  else
+    {
+      *min_value = m_window->min_width ();
+      *max_value = m_window->max_width ();
+    }
 }
 
 /* See tui-layout.h.  */
@@ -430,7 +438,7 @@ tui_layout_split::add_window (const char *name, int weight)
 std::unique_ptr<tui_layout_base>
 tui_layout_split::clone () const
 {
-  tui_layout_split *result = new tui_layout_split ();
+  tui_layout_split *result = new tui_layout_split (m_vertical);
   for (const split &item : m_splits)
     {
       std::unique_ptr<tui_layout_base> next = item.layout->clone ();
@@ -443,16 +451,29 @@ tui_layout_split::clone () const
 /* See tui-layout.h.  */
 
 void
-tui_layout_split::get_sizes (int *min_height, int *max_height)
+tui_layout_split::get_sizes (bool height, int *min_value, int *max_value)
 {
-  *min_height = 0;
-  *max_height = 0;
+  *min_value = 0;
+  *max_value = 0;
+  bool first_time = true;
   for (const split &item : m_splits)
     {
       int new_min, new_max;
-      item.layout->get_sizes (&new_min, &new_max);
-      *min_height += new_min;
-      *max_height += new_max;
+      item.layout->get_sizes (height, &new_min, &new_max);
+      /* For the mismatch case, the first time through we want to set
+	 the min and max to the computed values -- the "first_time"
+	 check here is just a funny way of doing that.  */
+      if (height == m_vertical || first_time)
+	{
+	  *min_value += new_min;
+	  *max_value += new_max;
+	}
+      else
+	{
+	  *min_value = std::max (*min_value, new_min);
+	  *max_value = std::min (*max_value, new_max);
+	}
+      first_time = false;
     }
 }
 
@@ -502,6 +523,8 @@ tui_layout_split::adjust_size (const char *name, int new_height)
 	return HANDLED;
       if (adjusted == FOUND)
 	{
+	  if (!m_vertical)
+	    return FOUND;
 	  found_index = i;
 	  break;
 	}
@@ -524,7 +547,7 @@ tui_layout_split::adjust_size (const char *name, int new_height)
       int index = (found_index + 1 + i) % m_splits.size ();
 
       int new_min, new_max;
-      m_splits[index].layout->get_sizes (&new_min, &new_max);
+      m_splits[index].layout->get_sizes (m_vertical, &new_min, &new_max);
 
       if (delta < 0)
 	{
@@ -571,23 +594,23 @@ tui_layout_split::apply (int x_, int y_, int width_, int height_)
   width = width_;
   height = height_;
 
-  struct height_info
+  struct size_info
   {
-    int height;
-    int min_height;
-    int max_height;
+    int size;
+    int min_size;
+    int max_size;
     /* True if this window will share a box border with the previous
        window in the list.  */
     bool share_box;
   };
 
-  std::vector<height_info> info (m_splits.size ());
+  std::vector<size_info> info (m_splits.size ());
 
-  /* Step 1: Find the min and max height of each sub-layout.
-     Fixed-sized layouts are given their desired height, and then the
+  /* Step 1: Find the min and max size of each sub-layout.
+     Fixed-sized layouts are given their desired size, and then the
      remaining space is distributed among the remaining windows
      according to the weights given.  */
-  int available_height = height;
+  int available_size = m_vertical ? height : width;
   int last_index = -1;
   int total_weight = 0;
   for (int i = 0; i < m_splits.size (); ++i)
@@ -597,7 +620,8 @@ tui_layout_split::apply (int x_, int y_, int width_, int height_)
       /* Always call get_sizes, to ensure that the window is
 	 instantiated.  This is a bit gross but less gross than adding
 	 special cases for this in other places.  */
-      m_splits[i].layout->get_sizes (&info[i].min_height, &info[i].max_height);
+      m_splits[i].layout->get_sizes (m_vertical, &info[i].min_size,
+				     &info[i].max_size);
 
       if (!m_applied
 	  && cmd_win_already_exists
@@ -607,15 +631,17 @@ tui_layout_split::apply (int x_, int y_, int width_, int height_)
 	  /* If this layout has never been applied, then it means the
 	     user just changed the layout.  In this situation, it's
 	     desirable to keep the size of the command window the
-	     same.  Setting the min and max heights this way ensures
+	     same.  Setting the min and max sizes this way ensures
 	     that the resizing step, below, does the right thing with
 	     this window.  */
-	  info[i].min_height = TUI_CMD_WIN->height;
-	  info[i].max_height = TUI_CMD_WIN->height;
+	  info[i].min_size = (m_vertical
+			      ? TUI_CMD_WIN->height
+			      : TUI_CMD_WIN->width);
+	  info[i].max_size = info[i].min_size;
 	}
 
-      if (info[i].min_height == info[i].max_height)
-	available_height -= info[i].min_height;
+      if (info[i].min_size == info[i].max_size)
+	available_size -= info[i].min_size;
       else
 	{
 	  last_index = i;
@@ -623,54 +649,58 @@ tui_layout_split::apply (int x_, int y_, int width_, int height_)
 	}
 
       /* Two adjacent boxed windows will share a border, making a bit
-	 more height available.  */
+	 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 height of each sub-layout.  Fixed-sized items
+  /* 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_height = 0;
+  int used_size = 0;
   for (int i = 0; i < m_splits.size (); ++i)
     {
       /* Compute the height and clamp to the allowable range.  */
-      info[i].height = available_height * m_splits[i].weight / total_weight;
-      if (info[i].height > info[i].max_height)
-	info[i].height = info[i].max_height;
-      if (info[i].height < info[i].min_height)
-	info[i].height = info[i].min_height;
-      /* If there is any leftover height, just redistribute it to the
+      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
-	 height.  We could try to be fancier here perhaps, by
-	 redistributing this height among all windows, not just the
+	 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_height != info[i].max_height)
+      if (info[i].min_size != info[i].max_size)
 	{
-	  used_height += info[i].height;
+	  used_size += info[i].size;
 	  if (info[i].share_box)
-	    --used_height;
+	    --used_size;
 	}
     }
 
-  /* Allocate any leftover height.  */
-  if (available_height >= used_height && last_index != -1)
-    info[last_index].height += available_height - used_height;
+  /* Allocate any leftover size.  */
+  if (available_size >= used_size && last_index != -1)
+    info[last_index].size += available_size - used_size;
 
   /* Step 3: Resize.  */
-  int height_accum = 0;
+  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 (height_accum + info[i].height > height)
-	height_accum = height - info[i].height;
+      if (size_accum + info[i].size > maximum)
+	size_accum = maximum - info[i].size;
       else if (info[i].share_box)
-	--height_accum;
-      m_splits[i].layout->apply (x, y + height_accum, width, info[i].height);
-      height_accum += info[i].height;
+	--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;
@@ -716,6 +746,9 @@ 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)
     {
@@ -839,8 +872,13 @@ tui_new_layout_command (const char *spec, int from_tty)
   if (new_name[0] == '-')
     error (_("Layout name cannot start with '-'"));
 
+  bool is_vertical = true;
+  spec = skip_spaces (spec);
+  if (check_for_argument (&spec, "-horizontal"))
+    is_vertical = false;
+
   std::vector<std::unique_ptr<tui_layout_split>> splits;
-  splits.emplace_back (new tui_layout_split);
+  splits.emplace_back (new tui_layout_split (is_vertical));
   std::unordered_set<std::string> seen_windows;
   while (true)
     {
@@ -850,8 +888,11 @@ tui_new_layout_command (const char *spec, int from_tty)
 
       if (spec[0] == '{')
 	{
-	  splits.emplace_back (new tui_layout_split);
-	  ++spec;
+	  is_vertical = true;
+	  spec = skip_spaces (spec + 1);
+	  if (check_for_argument (&spec, "-horizontal"))
+	    is_vertical = false;
+	  splits.emplace_back (new tui_layout_split (is_vertical));
 	  continue;
 	}
 
@@ -939,12 +980,12 @@ Usage: layout prev | next | LAYOUT-NAME"),
 
   add_cmd ("new-layout", class_tui, tui_new_layout_command,
 	   _("Create a new TUI layout.\n\
-Usage: tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\
+Usage: tui new-layout [-horizontal] NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\
 Create a new TUI layout.  The new layout will be named NAME,\n\
 and can be accessed using \"layout NAME\".\n\
 The windows will be displayed in the specified order.\n\
 A WINDOW can also be of the form:\n\
-  { NAME WEIGHT [NAME WEIGHT]... }\n\
+  { [-horizontal] NAME WEIGHT [NAME WEIGHT]... }\n\
 This form indicates a sub-frame.\n\
 Each WEIGHT is an integer, which holds the relative size\n\
 to be allocated to the window."),
diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h
index 969e4dfd231..6607e8d40d8 100644
--- a/gdb/tui/tui-layout.h
+++ b/gdb/tui/tui-layout.h
@@ -58,8 +58,9 @@ public:
   /* Change the size and location of this layout.  */
   virtual void apply (int x, int y, int width, int height) = 0;
 
-  /* Return the minimum and maximum height of this layout.  */
-  virtual void get_sizes (int *min_height, int *max_height) = 0;
+  /* Return the minimum and maximum height or width of this layout.
+     HEIGHT is true to fetch height, false to fetch width.  */
+  virtual void get_sizes (bool height, int *min_value, int *max_value) = 0;
 
   /* True if the topmost item in this layout is boxed.  */
   virtual bool top_boxed_p () const = 0;
@@ -142,7 +143,7 @@ public:
 
 protected:
 
-  void get_sizes (int *min_height, int *max_height) override;
+  void get_sizes (bool height, int *min_value, int *max_value) override;
 
 private:
 
@@ -159,7 +160,12 @@ class tui_layout_split : public tui_layout_base
 {
 public:
 
-  tui_layout_split () = default;
+  /* Create a new layout.  If VERTICAL is true, then windows in this
+     layout will be arranged vertically.  */
+  explicit tui_layout_split (bool vertical = true)
+    : m_vertical (vertical)
+  {
+  }
 
   DISABLE_COPY_AND_ASSIGN (tui_layout_split);
 
@@ -191,7 +197,7 @@ public:
 
 protected:
 
-  void get_sizes (int *min_height, int *max_height) override;
+  void get_sizes (bool height, int *min_value, int *max_value) override;
 
 private:
 
@@ -209,6 +215,9 @@ private:
   /* The splits.  */
   std::vector<split> m_splits;
 
+  /* True if the windows in this split are arranged vertically.  */
+  bool m_vertical;
+
   /* True if this layout has already been applied at least once.  */
   bool m_applied = false;
 };
diff --git a/gdb/tui/tui-win.c b/gdb/tui/tui-win.c
index 4f90c765b53..8206f3e6965 100644
--- a/gdb/tui/tui-win.c
+++ b/gdb/tui/tui-win.c
@@ -952,6 +952,14 @@ tui_win_info::max_height () const
   return tui_term_height () - 2;
 }
 
+/* See tui-data.h.  */
+
+int
+tui_gen_win_info::max_width () const
+{
+  return tui_term_width () - 2;
+}
+
 static void
 parse_scrolling_args (const char *arg, 
 		      struct tui_win_info **win_to_scroll,
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 24/24] Fix cast in TUI_DISASM_WIN
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (17 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 23/24] Add "usage" text to all TUI command help Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 02/24] Simplify tui_add_win_to_layout Tom Tromey
                   ` (5 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

I noticed that the TUI_DISASM_WIN macro cast the disassembly window to
a base type, rather than its correct type.  This patch fixes this
oversight.

2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-data.h (TUI_DISASM_WIN): Cast to tui_disasm_window.

Change-Id: Ied3dbac9ef3dc48ceb9e0850fe4ada3c316dd769
---
 gdb/ChangeLog      | 4 ++++
 gdb/tui/tui-data.h | 3 ++-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/gdb/tui/tui-data.h b/gdb/tui/tui-data.h
index 0583c4a5c99..7f68b1c4219 100644
--- a/gdb/tui/tui-data.h
+++ b/gdb/tui/tui-data.h
@@ -29,6 +29,7 @@
 struct tui_cmd_window;
 struct tui_source_window_base;
 struct tui_source_window;
+struct tui_disasm_window;
 
 /* A deleter that calls delwin.  */
 struct curses_deleter
@@ -222,7 +223,7 @@ public:
 extern struct tui_win_info *tui_win_list[MAX_MAJOR_WINDOWS];
 
 #define TUI_SRC_WIN     ((tui_source_window *) tui_win_list[SRC_WIN])
-#define TUI_DISASM_WIN	((tui_source_window_base *) tui_win_list[DISASSEM_WIN])
+#define TUI_DISASM_WIN	((tui_disasm_window *) tui_win_list[DISASSEM_WIN])
 #define TUI_DATA_WIN    ((tui_data_window *) tui_win_list[DATA_WIN])
 #define TUI_CMD_WIN     ((tui_cmd_window *) tui_win_list[CMD_WIN])
 
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 09/24] Allow TUI sub-layouts in "new-layout" command
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (3 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 10/24] Change return type of tui_layout_base::adjust_size Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 06/24] Reimplement "tui reg" command Tom Tromey
                   ` (19 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

The new TUI layout engine has support for "sub-layouts" -- this is a
layout that includes another layout as a child.  A sub-layout is
treated as a unit when allocating space.

There's not a very strong reason to use sub-layouts currently.  This
patch exists to introduce the idea, and to simplify the subsequent
patch that adds horizontal layouts -- where sub-layouts are needed.

Because this patch won't go in on its own, I chose to defer
documenting this change until the subsequent horizontal layout patch.

gdb/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-layout.h (class tui_layout_split) <add_split>: Change
	parameter and return types.
	(class tui_layout_base) <specification>: Add "depth".
	(class tui_layout_window) <specification>: Add "depth".
	(class tui_layout_split) <specification>: Add "depth".
	* tui/tui-layout.c (tui_layout_split::add_split): Change parameter
	and return types.
	(tui_new_layout_command): Parse sub-layouts.
	(_initialize_tui_layout): Update help string.
	(tui_layout_window::specification): Add "depth".
	(add_layout_command): Update.

gdb/testsuite/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* gdb.tui/new-layout.exp: Add sub-layout tests.

Change-Id: Iddf52d067a552c168b8a67f29caf7ac86404b10c
---
 gdb/ChangeLog                        | 14 +++++
 gdb/testsuite/ChangeLog              |  4 ++
 gdb/testsuite/gdb.tui/new-layout.exp | 11 ++++
 gdb/tui/tui-layout.c                 | 84 +++++++++++++++++++++-------
 gdb/tui/tui-layout.h                 | 11 ++--
 5 files changed, 100 insertions(+), 24 deletions(-)

diff --git a/gdb/testsuite/gdb.tui/new-layout.exp b/gdb/testsuite/gdb.tui/new-layout.exp
index 8475a9db295..406d9b25f08 100644
--- a/gdb/testsuite/gdb.tui/new-layout.exp
+++ b/gdb/testsuite/gdb.tui/new-layout.exp
@@ -35,12 +35,23 @@ gdb_test "tui new-layout example src 1 src 1" \
     "Window \"src\" seen twice in layout"
 gdb_test "tui new-layout example src 1" \
     "New layout does not contain the \"cmd\" window"
+gdb_test "tui new-layout example src 1}" \
+    "Extra '}' in layout specification"
+gdb_test "tui new-layout example {src 1} 1}" \
+    "Extra '}' in layout specification"
+gdb_test "tui new-layout example {src 1" \
+    "Missing '}' in layout specification"
 
 gdb_test_no_output "tui new-layout example asm 1 locator 0 cmd 1"
 
 gdb_test "help layout example" \
     "Apply the \"example\" layout.*tui new-layout example asm 1 locator 0 cmd 1"
 
+gdb_test_no_output "tui new-layout example2 {asm 1 locator 0} 1 cmd 1"
+
+gdb_test "help layout example2" \
+    "Apply the \"example2\" layout.*tui new-layout example2 {asm 1 locator 0} 1 cmd 1"
+
 if {![Term::enter_tui]} {
     unsupported "TUI not supported"
 }
diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index 438a3a03828..3604d7e06bc 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -400,20 +400,19 @@ tui_layout_window::replace_window (const char *name, const char *new_window)
 /* See tui-layout.h.  */
 
 void
-tui_layout_window::specification (ui_file *output)
+tui_layout_window::specification (ui_file *output, int depth)
 {
   fputs_unfiltered (get_name (), output);
 }
 
 /* See tui-layout.h.  */
 
-tui_layout_split *
-tui_layout_split::add_split (int weight)
+void
+tui_layout_split::add_split (std::unique_ptr<tui_layout_split> &&layout,
+			     int weight)
 {
-  tui_layout_split *result = new tui_layout_split ();
-  split s = {weight, std::unique_ptr<tui_layout_base> (result)};
+  split s = {weight, std::move (layout)};
   m_splits.push_back (std::move (s));
-  return result;
 }
 
 /* See tui-layout.h.  */
@@ -711,17 +710,23 @@ tui_layout_split::replace_window (const char *name, const char *new_window)
 /* See tui-layout.h.  */
 
 void
-tui_layout_split::specification (ui_file *output)
+tui_layout_split::specification (ui_file *output, int depth)
 {
+  if (depth > 0)
+    fputs_unfiltered ("{", output);
+
   bool first = true;
   for (auto &item : m_splits)
     {
       if (!first)
 	fputs_unfiltered (" ", output);
       first = false;
-      item.layout->specification (output);
+      item.layout->specification (output, depth + 1);
       fprintf_unfiltered (output, " %d", item.weight);
     }
+
+  if (depth > 0)
+    fputs_unfiltered ("}", output);
 }
 
 /* Destroy the layout associated with SELF.  */
@@ -746,7 +751,7 @@ add_layout_command (const char *name, tui_layout_split *layout)
   struct cmd_list_element *cmd;
 
   string_file spec;
-  layout->specification (&spec);
+  layout->specification (&spec, 0);
 
   gdb::unique_xmalloc_ptr<char> doc
     (xstrprintf (_("Apply the \"%s\" layout.\n\
@@ -833,23 +838,60 @@ tui_new_layout_command (const char *spec, int from_tty)
   if (new_name[0] == '-')
     error (_("Layout name cannot start with '-'"));
 
-  std::unique_ptr<tui_layout_split> new_layout (new tui_layout_split);
+  std::vector<std::unique_ptr<tui_layout_split>> splits;
+  splits.emplace_back (new tui_layout_split);
   std::unordered_set<std::string> seen_windows;
   while (true)
     {
-      std::string name = extract_arg (&spec);
-      if (name.empty ())
+      spec = skip_spaces (spec);
+      if (spec[0] == '\0')
 	break;
-      if (!validate_window_name (name))
-	error (_("Unknown window \"%s\""), name.c_str ());
-      if (seen_windows.find (name) != seen_windows.end ())
-	error (_("Window \"%s\" seen twice in layout"), name.c_str ());
-      ULONGEST weight = get_ulongest (&spec);
+
+      if (spec[0] == '{')
+	{
+	  splits.emplace_back (new tui_layout_split);
+	  ++spec;
+	  continue;
+	}
+
+      bool is_close = false;
+      std::string name;
+      if (spec[0] == '}')
+	{
+	  is_close = true;
+	  ++spec;
+	  if (splits.size () == 1)
+	    error (_("Extra '}' in layout specification"));
+	}
+      else
+	{
+	  name = extract_arg (&spec);
+	  if (name.empty ())
+	    break;
+	  if (!validate_window_name (name))
+	    error (_("Unknown window \"%s\""), name.c_str ());
+	  if (seen_windows.find (name) != seen_windows.end ())
+	    error (_("Window \"%s\" seen twice in layout"), name.c_str ());
+	}
+
+      ULONGEST weight = get_ulongest (&spec, '}');
       if ((int) weight != weight)
 	error (_("Weight out of range: %s"), pulongest (weight));
-      new_layout->add_window (name.c_str (), weight);
-      seen_windows.insert (name);
+      if (is_close)
+	{
+	  std::unique_ptr<tui_layout_split> last_split
+	    = std::move (splits.back ());
+	  splits.pop_back ();
+	  splits.back ()->add_split (std::move (last_split), weight);
+	}
+      else
+	{
+	  splits.back ()->add_window (name.c_str (), weight);
+	  seen_windows.insert (name);
+	}
     }
+  if (splits.size () > 1)
+    error (_("Missing '}' in layout specification"));
   if (seen_windows.empty ())
     error (_("New layout does not contain any windows"));
   if (seen_windows.find ("cmd") == seen_windows.end ())
@@ -857,6 +899,7 @@ tui_new_layout_command (const char *spec, int from_tty)
 
   gdb::unique_xmalloc_ptr<char> cmd_name
     = make_unique_xstrdup (new_name.c_str ());
+  std::unique_ptr<tui_layout_split> new_layout = std::move (splits.back ());
   struct cmd_list_element *cmd
     = add_layout_command (cmd_name.get (), new_layout.get ());
   cmd->name_allocated = 1;
@@ -899,6 +942,9 @@ Usage: tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]...\n\
 Create a new TUI layout.  The new layout will be named NAME,\n\
 and can be accessed using \"layout NAME\".\n\
 The windows will be displayed in the specified order.\n\
+A WINDOW can also be of the form:\n\
+  { NAME WEIGHT [NAME WEIGHT]... }\n\
+This form indicates a sub-frame.\n\
 Each WEIGHT is an integer, which holds the relative size\n\
 to be allocated to the window."),
 	   tui_get_cmd_list ());
diff --git a/gdb/tui/tui-layout.h b/gdb/tui/tui-layout.h
index c2249a783f8..4351e260720 100644
--- a/gdb/tui/tui-layout.h
+++ b/gdb/tui/tui-layout.h
@@ -74,8 +74,9 @@ public:
      NEW_WINDOW.  */
   virtual void replace_window (const char *name, const char *new_window) = 0;
 
-  /* Append the specification to this window to OUTPUT.  */
-  virtual void specification (ui_file *output) = 0;
+  /* Append the specification to this window to OUTPUT.  DEPTH is the
+     depth of this layout in the hierarchy (zero-based).  */
+  virtual void specification (ui_file *output, int depth) = 0;
 
   /* The most recent space allocation.  */
   int x = 0;
@@ -125,7 +126,7 @@ public:
 
   void replace_window (const char *name, const char *new_window) override;
 
-  void specification (ui_file *output) override;
+  void specification (ui_file *output, int depth) override;
 
 protected:
 
@@ -153,7 +154,7 @@ public:
   /* Add a new split layout to this layout.  WEIGHT is the desired
      size, which is relative to the other weights given in this
      layout.  */
-  tui_layout_split *add_split (int weight);
+  void add_split (std::unique_ptr<tui_layout_split> &&layout, int weight);
 
   /* Add a new window to this layout.  NAME is the name of the window
      to add.  WEIGHT is the desired size, which is relative to the
@@ -174,7 +175,7 @@ public:
 
   void replace_window (const char *name, const char *new_window) override;
 
-  void specification (ui_file *output) override;
+  void specification (ui_file *output, int depth) override;
 
 protected:
 
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 03/24] Fix latent display bug in tui_data_window
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (6 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 22/24] Use error_no_arg in TUI Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 18/24] Remove tui_set_win_focus_to Tom Tromey
                   ` (16 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

tui_data_window creates new curses windows, but does not pass in
coordinates relative to the data window's origin.  This means that the
data window could only ever be displayed as the topmost window in a
layout.  This is not a currently problem, because all the existing
layouts do this; but a subsequent patch will add user-defined layouts,
which could do otherwise.

gdb/ChangeLog
2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-regs.c (tui_data_window::display_registers_from): Use
	correct coordinates.

Change-Id: I5101f2b2869557b87381ebdeebd9b7fd28687831
---
 gdb/ChangeLog      | 5 +++++
 gdb/tui/tui-regs.c | 2 +-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/gdb/tui/tui-regs.c b/gdb/tui/tui-regs.c
index 50b3e72e510..41b8f0d933c 100644
--- a/gdb/tui/tui-regs.c
+++ b/gdb/tui/tui-regs.c
@@ -274,7 +274,7 @@ tui_data_window::display_registers_from (int start_element_no)
 	{
 	  /* Create the window if necessary.  */
 	  m_regs_content[i].resize (1, item_win_width,
-				    (item_win_width * j) + 1, cur_y);
+				    x + (item_win_width * j) + 1, y + cur_y);
 	  i++;		/* Next register.  */
 	}
       cur_y++;		/* Next row.  */
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 15/24] Remove tui_delete_invisible_windows and tui_make_all_invisible
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (14 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 04/24] Simplify TUI C-x 2 binding Tom Tromey
@ 2020-01-04 18:34 ` Tom Tromey
  2020-01-04 18:34 ` [PATCH 05/24] Reimplement TUI "C-x 1" binding Tom Tromey
                   ` (8 subsequent siblings)
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:34 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

tui_delete_invisible_windows is only needed after applying a layout,
and tui_make_all_invisible is only needed before applying a layout.

This patch removes these functions, in favor of doing this management
directly in tui_apply_current_layout.  This is needed so that the
lifetimes of non-built-in windows will be properly managed.

2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-wingeneral.h (tui_make_all_invisible): Don't declare.
	* tui/tui-wingeneral.c (tui_make_all_invisible): Remove.
	* tui/tui-win.c (tui_resize_all): Don't call
	tui_delete_invisible_windows.
	* tui/tui-layout.c (tui_apply_current_layout): Delete windows when
	done.
	(tui_set_layout): Update.
	(tui_add_win_to_layout): Don't call tui_delete_invisible_windows.
	* tui/tui-data.h (tui_delete_invisible_windows): Don't declare.
	* tui/tui-data.c (tui_delete_invisible_windows): Remove.

Change-Id: Ia3603b021dcb7ec31700a4a32640cd09b00b8f3b
---
 gdb/ChangeLog            | 13 ++++++++++++
 gdb/tui/tui-data.c       | 23 --------------------
 gdb/tui/tui-data.h       |  5 -----
 gdb/tui/tui-layout.c     | 46 ++++++++++++++++++++++++++++++----------
 gdb/tui/tui-win.c        |  1 -
 gdb/tui/tui-wingeneral.c |  9 --------
 gdb/tui/tui-wingeneral.h |  3 ---
 7 files changed, 48 insertions(+), 52 deletions(-)

diff --git a/gdb/tui/tui-data.c b/gdb/tui/tui-data.c
index 5d42fafccca..ead8b1043ca 100644
--- a/gdb/tui/tui-data.c
+++ b/gdb/tui/tui-data.c
@@ -129,29 +129,6 @@ tui_prev_win (struct tui_win_info *cur_win)
 }
 
 
-/* See tui-data.h.  */
-
-void
-tui_delete_invisible_windows ()
-{
-  for (int win_type = SRC_WIN; (win_type < MAX_MAJOR_WINDOWS); win_type++)
-    {
-      if (tui_win_list[win_type] != NULL
-	  && !tui_win_list[win_type]->is_visible ())
-	{
-	  /* This should always be made visible before a call to this
-	     function.  */
-	  gdb_assert (win_type != CMD_WIN);
-
-	  if (win_with_focus == tui_win_list[win_type])
-	    win_with_focus = nullptr;
-
-	  delete tui_win_list[win_type];
-	  tui_win_list[win_type] = NULL;
-	}
-    }
-}
-
 tui_win_info::tui_win_info (enum tui_win_type type)
   : tui_gen_win_info (type)
 {
diff --git a/gdb/tui/tui-data.h b/gdb/tui/tui-data.h
index a5e4940666c..96265bb4215 100644
--- a/gdb/tui/tui-data.h
+++ b/gdb/tui/tui-data.h
@@ -256,11 +256,6 @@ extern void tui_set_win_resized_to (bool);
 extern struct tui_win_info *tui_next_win (struct tui_win_info *);
 extern struct tui_win_info *tui_prev_win (struct tui_win_info *);
 
-/* Delete all the invisible windows.  Note that it is an error to call
-   this when the command window is invisible -- we don't allow the
-   command window to be removed from the layout.  */
-extern void tui_delete_invisible_windows ();
-
 extern unsigned int tui_tab_width;
 
 #endif /* TUI_TUI_DATA_H */
diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index 9ad91ce713b..898d2f0b8d2 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -69,8 +69,43 @@ std::vector<tui_win_info *> tui_windows;
 void
 tui_apply_current_layout ()
 {
+  struct gdbarch *gdbarch;
+  CORE_ADDR addr;
+
+  extract_display_start_addr (&gdbarch, &addr);
+
+  std::vector<tui_win_info *> saved_windows = std::move (tui_windows);
   tui_windows.clear ();
+
+  for (tui_win_info *win_info : saved_windows)
+    win_info->make_visible (false);
+
   applied_layout->apply (0, 0, tui_term_width (), tui_term_height ());
+
+  /* Keep the list of internal windows up-to-date.  */
+  for (int win_type = SRC_WIN; (win_type < MAX_MAJOR_WINDOWS); win_type++)
+    if (tui_win_list[win_type] != nullptr
+	&& !tui_win_list[win_type]->is_visible ())
+      tui_win_list[win_type] = nullptr;
+
+  /* This should always be made visible by a layout.  */
+  gdb_assert (TUI_CMD_WIN->is_visible ());
+
+  /* Now delete any window that was not re-applied.  */
+  tui_win_info *focus = tui_win_with_focus ();
+  for (tui_win_info *win_info : saved_windows)
+    {
+      if (!win_info->is_visible ())
+	{
+	  if (focus == win_info)
+	    tui_set_win_focus_to (tui_windows[0]);
+	  delete win_info;
+	}
+    }
+
+  if (gdbarch == nullptr && TUI_DISASM_WIN != nullptr)
+    tui_get_begin_asm_address (&gdbarch, &addr);
+  tui_update_source_windows_with_addr (gdbarch, addr);
 }
 
 /* See tui-layout.  */
@@ -86,19 +121,9 @@ tui_adjust_window_height (struct tui_win_info *win, int new_height)
 static void
 tui_set_layout (tui_layout_split *layout)
 {
-  struct gdbarch *gdbarch;
-  CORE_ADDR addr;
-
-  extract_display_start_addr (&gdbarch, &addr);
-  tui_make_all_invisible ();
   applied_skeleton = layout;
   applied_layout = layout->clone ();
   tui_apply_current_layout ();
-  tui_delete_invisible_windows ();
-
-  if (gdbarch == nullptr && TUI_DISASM_WIN != nullptr)
-    tui_get_begin_asm_address (&gdbarch, &addr);
-  tui_update_source_windows_with_addr (gdbarch, addr);
 }
 
 /* See tui-layout.h.  */
@@ -121,7 +146,6 @@ tui_add_win_to_layout (enum tui_win_type type)
   const char *name = type == SRC_WIN ? SRC_NAME : DISASSEM_NAME;
   applied_layout->replace_window (tui_win_list[other]->name (), name);
   tui_apply_current_layout ();
-  tui_delete_invisible_windows ();
 }
 
 /* Find LAYOUT in the "layouts" global and return its index.  */
diff --git a/gdb/tui/tui-win.c b/gdb/tui/tui-win.c
index 6eab125d731..f8a57732cca 100644
--- a/gdb/tui/tui-win.c
+++ b/gdb/tui/tui-win.c
@@ -550,7 +550,6 @@ tui_resize_all (void)
       erase ();
       clearok (curscr, TRUE);
       tui_apply_current_layout ();
-      tui_delete_invisible_windows ();
       /* Turn keypad back on, unless focus is in the command
 	 window.  */
       if (win_with_focus != TUI_CMD_WIN)
diff --git a/gdb/tui/tui-wingeneral.c b/gdb/tui/tui-wingeneral.c
index dae4255ada2..9c571204e2a 100644
--- a/gdb/tui/tui-wingeneral.c
+++ b/gdb/tui/tui-wingeneral.c
@@ -159,15 +159,6 @@ tui_gen_win_info::make_visible (bool visible)
     handle.reset (nullptr);
 }
 
-/* See tui-wingeneral.h.  */
-
-void
-tui_make_all_invisible (void)
-{
-  for (tui_win_info *win_info : all_tui_windows ())
-    win_info->make_visible (false);
-}
-
 /* Function to refresh all the windows currently displayed.  */
 
 void
diff --git a/gdb/tui/tui-wingeneral.h b/gdb/tui/tui-wingeneral.h
index e32dbed2995..797a8a927e8 100644
--- a/gdb/tui/tui-wingeneral.h
+++ b/gdb/tui/tui-wingeneral.h
@@ -26,9 +26,6 @@
 
 struct tui_win_info;
 
-/* Makes all windows invisible.  */
-extern void tui_make_all_invisible (void);
-
 extern void tui_unhighlight_win (struct tui_win_info *);
 extern void tui_highlight_win (struct tui_win_info *);
 extern void tui_refresh_all ();
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 08/24] Add the "tui new-layout" command
  2020-01-04 18:34 ` [PATCH 08/24] Add the "tui new-layout" command Tom Tromey
@ 2020-01-04 18:44   ` Eli Zaretskii
  0 siblings, 0 replies; 36+ messages in thread
From: Eli Zaretskii @ 2020-01-04 18:44 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

> From: Tom Tromey <tom@tromey.com>
> Cc: Tom Tromey <tom@tromey.com>
> Date: Sat,  4 Jan 2020 11:33:54 -0700
> 
> gdb/ChangeLog
> 2020-01-04  Tom Tromey  <tom@tromey.com>
> 
> 	* NEWS: Add "tui new-layout" item.
> 	* tui/tui-layout.c (add_layout_command): Return cmd_list_element.
> 	Add new-layout command to help text.
> 	(validate_window_name): New function.
> 	(tui_new_layout_command): New function.
> 	(_initialize_tui_layout): Register "new-layout".
> 	(tui_layout_window::specification): New method.
> 	(tui_layout_window::specification): New method.
> 	* tui/tui-layout.h (class tui_layout_base) <specification>: New
> 	method.
> 	(class tui_layout_window) <specification>: New method.
> 	(class tui_layout_split) <specification>: New method.
> 
> gdb/doc/ChangeLog
> 2020-01-04  Tom Tromey  <tom@tromey.com>
> 
> 	* gdb.texinfo (TUI Overview): Mention user layouts.
> 	(TUI Commands): Document "tui new-layout".
> 
> gdb/testsuite/ChangeLog
> 2020-01-04  Tom Tromey  <tom@tromey.com>
> 
> 	* gdb.tui/new-layout.exp: New file.

OK for the documentation parts.

Thanks.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 11/24] Add horizontal splitting to TUI layout
  2020-01-04 18:34 ` [PATCH 11/24] Add horizontal splitting to TUI layout Tom Tromey
@ 2020-01-04 18:47   ` Eli Zaretskii
  0 siblings, 0 replies; 36+ messages in thread
From: Eli Zaretskii @ 2020-01-04 18:47 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

> From: Tom Tromey <tom@tromey.com>
> Cc: Tom Tromey <tom@tromey.com>
> Date: Sat,  4 Jan 2020 11:33:57 -0700
> 
> gdb/ChangeLog
> 2020-01-04  Tom Tromey  <tom@tromey.com>
> 
> 	PR tui/17850:
> 	* tui/tui-win.c (tui_gen_win_info::max_width): New method.
> 	* tui/tui-layout.h (class tui_layout_base) <get_sizes>: Add
> 	"height" argument.
> 	(class tui_layout_window) <get_sizes>: Likewise.
> 	(class tui_layout_split) <tui_layout_split>: Add "vertical"
> 	argument.
> 	<get_sizes>: Add "height" argument.
> 	<m_vertical>: New field.
> 	* tui/tui-layout.c (tui_layout_split::clone): Update.
> 	(tui_layout_split::get_sizes): Add "height" argument.
> 	(tui_layout_split::adjust_size, tui_layout_split::apply): Update.
> 	(tui_new_layout_command): Parse "-horizontal".
> 	(_initialize_tui_layout): Update help string.
> 	(tui_layout_split::specification): Add "-horizontal" when needed.
> 	* tui/tui-layout.c (tui_layout_window::get_sizes): Add "height"
> 	argument.
> 	* tui/tui-data.h (struct tui_gen_win_info) <max_width, min_width>:
> 	New methods.
> 
> gdb/doc/ChangeLog
> 2020-01-04  Tom Tromey  <tom@tromey.com>
> 
> 	PR tui/17850:
> 	* gdb.texinfo (TUI Commands): Document horizontal layouts.
> 
> gdb/testsuite/ChangeLog
> 2020-01-04  Tom Tromey  <tom@tromey.com>
> 
> 	PR tui/17850:
> 	* gdb.tui/new-layout.exp: Add horizontal layout and winheight
> 	tests.

Thanks, the documentation parts are OK.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 17/24] Change how TUI windows are instantiated
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (22 preceding siblings ...)
  2020-01-04 18:34 ` [PATCH 19/24] Remove the TUI annotation hack Tom Tromey
@ 2020-01-04 18:54 ` Tom Tromey
  2020-02-22 20:22 ` [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-01-04 18:54 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

This adds a new global that maps from window names to window
constructor functions, and then changes tui_get_window_by_name and
validate_window_name to use it.  This is another step toward
user-defined window types.

2020-01-04  Tom Tromey  <tom@tromey.com>

	* tui/tui-layout.c (make_standard_window, get_locator_window): New
	functions.
	(known_window_types): New global.
	(tui_get_window_by_name): Reimplement.
	(initialize_known_windows): New function.
	(validate_window_name): Rewrite.
	(_initialize_tui_layout): Call initialize_known_windows.

Change-Id: I9037aac550299b9d945899220a30c2d3af9dd0de
---
 gdb/ChangeLog        | 10 +++++
 gdb/tui/tui-layout.c | 99 ++++++++++++++++++++++++++++++--------------
 2 files changed, 77 insertions(+), 32 deletions(-)

diff --git a/gdb/tui/tui-layout.c b/gdb/tui/tui-layout.c
index 898d2f0b8d2..797acc6e8b7 100644
--- a/gdb/tui/tui-layout.c
+++ b/gdb/tui/tui-layout.c
@@ -29,6 +29,7 @@
 #include "cli/cli-decode.h"
 #include "cli/cli-utils.h"
 #include <ctype.h>
+#include <unordered_map>
 #include <unordered_set>
 
 #include "tui/tui.h"
@@ -322,40 +323,74 @@ tui_gen_win_info::resize (int height_, int width_,
 
 \f
 
+/* Helper function to create one of the built-in (non-locator)
+   windows.  */
+
+template<enum tui_win_type V, class T>
+static tui_gen_win_info *
+make_standard_window (const char *)
+{
+  if (tui_win_list[V] == nullptr)
+    tui_win_list[V] = new T ();
+  return tui_win_list[V];
+}
+
+/* Helper function to wrap tui_locator_win_info_ptr for
+   tui_get_window_by_name.  */
+
+static tui_gen_win_info *
+get_locator_window (const char *)
+{
+  return tui_locator_win_info_ptr ();
+}
+
+/* A map holding all the known window types, keyed by name.  Note that
+   this is heap-allocated and "leaked" at gdb exit.  This avoids
+   ordering issues with destroying elements in the map at shutdown.
+   In particular, destroying this map can occur after Python has been
+   shut down, causing crashes if any window destruction requires
+   running Python code.  */
+
+static std::unordered_map<std::string, window_factory> *known_window_types;
+
 /* Helper function that returns a TUI window, given its name.  */
 
 static tui_gen_win_info *
 tui_get_window_by_name (const std::string &name)
 {
-  if (name == "src")
-    {
-      if (tui_win_list[SRC_WIN] == nullptr)
-	tui_win_list[SRC_WIN] = new tui_source_window ();
-      return tui_win_list[SRC_WIN];
-    }
-  else if (name == "cmd")
-    {
-      if (tui_win_list[CMD_WIN] == nullptr)
-	tui_win_list[CMD_WIN] = new tui_cmd_window ();
-      return tui_win_list[CMD_WIN];
-    }
-  else if (name == "regs")
-    {
-      if (tui_win_list[DATA_WIN] == nullptr)
-	tui_win_list[DATA_WIN] = new tui_data_window ();
-      return tui_win_list[DATA_WIN];
-    }
-  else if (name == "asm")
-    {
-      if (tui_win_list[DISASSEM_WIN] == nullptr)
-	tui_win_list[DISASSEM_WIN] = new tui_disasm_window ();
-      return tui_win_list[DISASSEM_WIN];
-    }
-  else
-    {
-      gdb_assert (name == "locator");
-      return tui_locator_win_info_ptr ();
-    }
+  for (tui_win_info *window : saved_tui_windows)
+    if (name == window->name ())
+      return window;
+
+  auto iter = known_window_types->find (name);
+  if (iter == known_window_types->end ())
+    error (_("Unknown window type \"%s\""), name.c_str ());
+
+  tui_gen_win_info *result = iter->second (name.c_str ());
+  if (result == nullptr)
+    error (_("Could not create window \"%s\""), name.c_str ());
+  return result;
+}
+
+/* Initialize the known window types.  */
+
+static void
+initialize_known_windows ()
+{
+  known_window_types = new std::unordered_map<std::string, window_factory>;
+
+  known_window_types->emplace ("src",
+			       make_standard_window<SRC_WIN,
+						    tui_source_window>);
+  known_window_types->emplace ("cmd",
+			       make_standard_window<CMD_WIN, tui_cmd_window>);
+  known_window_types->emplace ("regs",
+			       make_standard_window<DATA_WIN,
+						    tui_data_window>);
+  known_window_types->emplace ("asm",
+			       make_standard_window<DISASSEM_WIN,
+						    tui_disasm_window>);
+  known_window_types->emplace ("locator", get_locator_window);
 }
 
 /* See tui-layout.h.  */
@@ -886,9 +921,8 @@ initialize_layouts ()
 static bool
 validate_window_name (const std::string &name)
 {
-  return (name == "src" || name == "cmd"
-	  || name == "regs" || name == "asm"
-	  || name == "locator");
+  auto iter = known_window_types->find (name);
+  return iter != known_window_types->end ();
 }
 
 /* Implementation of the "tui new-layout" command.  */
@@ -1022,4 +1056,5 @@ to be allocated to the window."),
 	   tui_get_cmd_list ());
 
   initialize_layouts ();
+  initialize_known_windows ();
 }
-- 
2.17.2

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 20/24] Allow TUI windows in Python
  2020-01-04 18:34 ` [PATCH 20/24] Allow TUI windows in Python Tom Tromey
@ 2020-01-04 18:57   ` Eli Zaretskii
  2020-02-22 19:57     ` Tom Tromey
  2020-03-10 22:23   ` Simon Marchi
  1 sibling, 1 reply; 36+ messages in thread
From: Eli Zaretskii @ 2020-01-04 18:57 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

> From: Tom Tromey <tom@tromey.com>
> Cc: Tom Tromey <tom@tromey.com>
> Date: Sat,  4 Jan 2020 11:34:06 -0700
> 
> 2020-01-04  Tom Tromey  <tom@tromey.com>
> 
> 	* NEWS: Add entry for gdb.register_window_type.
> 	* tui/tui-layout.h (window_factory): New typedef.
> 	(tui_register_window): Declare.
> 	* tui/tui-layout.c (saved_tui_windows): New global.
> 	(tui_apply_current_layout): Use it.
> 	(tui_register_window): New function.
> 	* python/python.c (do_start_initialization): Call
> 	gdbpy_initialize_tui.
> 	(python_GdbMethods): Add "register_window_type" function.
> 	* python/python-internal.h (gdbpy_register_tui_window)
> 	(gdbpy_initialize_tui): Declare.
> 	* python/py-tui.c: New file.
> 	* Makefile.in (SUBDIR_PYTHON_SRCS): Add py-tui.c.
> 
> gdb/doc/ChangeLog
> 2020-01-04  Tom Tromey  <tom@tromey.com>
> 
> 	* python.texi (Python API): Add menu item.
> 	(TUI Windows In Python): New node.
> 
> gdb/testsuite/ChangeLog
> 2020-01-04  Tom Tromey  <tom@tromey.com>
> 
> 	* gdb.python/tui-window.exp: New file.
> 	* gdb.python/tui-window.py: New file.

OK for the documentation parts, with two comments.

> +terminal escape styling sequences; @value{GDBN} will convert translate
> +these as appropriate for the terminal.               ^^^^^^^^^^^^^^^^^

One of these two words should be removed.

> +@defun Window.hscroll (@var{num})
> +This is a request to scroll the window horizontally.  @var{num} is the
> +amount by which to scroll, with negative numbers meaning to scroll
> +right.
> +@end defun
> +
> +@defun Window.vscroll (@var{num})
> +This is a request to scroll the window vertically.  @var{num} is the
> +amount by which to scroll, with negative numbers meaning to scroll
> +backward.

There's a well-known source of confusion with describing scrolling
direction: does it refer to scrolling of the text in the window
(i.e. the window is considered to be fixed and the text to be
scrolled) or the other way around?  The confusion stems from the fact
that we say "scroll the window", but what is actually scrolled is the
text.  Can we please make it crystal clear here what will move right
and backward here?

Thanks.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 20/24] Allow TUI windows in Python
  2020-01-04 18:57   ` Eli Zaretskii
@ 2020-02-22 19:57     ` Tom Tromey
  2020-02-22 20:18       ` Eli Zaretskii
  0 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2020-02-22 19:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Tom Tromey, gdb-patches

>>>>> "Eli" == Eli Zaretskii <eliz@gnu.org> writes:

>> +terminal escape styling sequences; @value{GDBN} will convert translate
>> +these as appropriate for the terminal.               ^^^^^^^^^^^^^^^^^

Eli> One of these two words should be removed.

Fixed.

>> +@defun Window.hscroll (@var{num})
>> +This is a request to scroll the window horizontally.  @var{num} is the
>> +amount by which to scroll, with negative numbers meaning to scroll
>> +right.
>> +@end defun
>> +
>> +@defun Window.vscroll (@var{num})
>> +This is a request to scroll the window vertically.  @var{num} is the
>> +amount by which to scroll, with negative numbers meaning to scroll
>> +backward.

Eli> There's a well-known source of confusion with describing scrolling
Eli> direction: does it refer to scrolling of the text in the window
Eli> (i.e. the window is considered to be fixed and the text to be
Eli> scrolled) or the other way around?  The confusion stems from the fact
Eli> that we say "scroll the window", but what is actually scrolled is the
Eli> text.  Can we please make it crystal clear here what will move right
Eli> and backward here?

I did this, like so:

@defun Window.hscroll (@var{num})
This is a request to scroll the window horizontally.  @var{num} is the
amount by which to scroll, with negative numbers meaning to scroll
right.  In the TUI model, it is the viewport that moves, not the
contents.  A positive argument should cause the viewport to move
right, and so the content should appear to move to the left.
@end defun

@defun Window.vscroll (@var{num})
This is a request to scroll the window vertically.  @var{num} is the
amount by which to scroll, with negative numbers meaning to scroll
backward.  In the TUI model, it is the viewport that moves, not the
contents.  A positive argument should cause the viewport to move down,
and so the content should appear to move up.
@end defun



Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 20/24] Allow TUI windows in Python
  2020-02-22 19:57     ` Tom Tromey
@ 2020-02-22 20:18       ` Eli Zaretskii
  0 siblings, 0 replies; 36+ messages in thread
From: Eli Zaretskii @ 2020-02-22 20:18 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

> From: Tom Tromey <tom@tromey.com>
> Cc: Tom Tromey <tom@tromey.com>,  gdb-patches@sourceware.org
> Date: Sat, 22 Feb 2020 12:57:51 -0700
> 
> Eli> There's a well-known source of confusion with describing scrolling
> Eli> direction: does it refer to scrolling of the text in the window
> Eli> (i.e. the window is considered to be fixed and the text to be
> Eli> scrolled) or the other way around?  The confusion stems from the fact
> Eli> that we say "scroll the window", but what is actually scrolled is the
> Eli> text.  Can we please make it crystal clear here what will move right
> Eli> and backward here?
> 
> I did this, like so:

Thanks, this is perfect.

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 00/24] Horizontal TUI layout + windows in Python
  2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
                   ` (23 preceding siblings ...)
  2020-01-04 18:54 ` [PATCH 17/24] Change how TUI windows are instantiated Tom Tromey
@ 2020-02-22 20:22 ` Tom Tromey
  24 siblings, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-02-22 20:22 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

>>>>> "Tom" == Tom Tromey <tom@tromey.com> writes:

Tom> This series adds some new features to the TUI: user-defined layouts,
Tom> horizontal layouts, and the ability to write windows in Python.

I am checking this in now.

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 20/24] Allow TUI windows in Python
  2020-01-04 18:34 ` [PATCH 20/24] Allow TUI windows in Python Tom Tromey
  2020-01-04 18:57   ` Eli Zaretskii
@ 2020-03-10 22:23   ` Simon Marchi
  2020-03-11  0:23     ` Tom Tromey
  1 sibling, 1 reply; 36+ messages in thread
From: Simon Marchi @ 2020-03-10 22:23 UTC (permalink / raw)
  To: Tom Tromey, gdb-patches

On 2020-01-04 1:34 p.m., Tom Tromey wrote:
> This patch adds support for writing new TUI windows in Python.
> 
> 2020-01-04  Tom Tromey  <tom@tromey.com>
> 
> 	* NEWS: Add entry for gdb.register_window_type.
> 	* tui/tui-layout.h (window_factory): New typedef.
> 	(tui_register_window): Declare.
> 	* tui/tui-layout.c (saved_tui_windows): New global.
> 	(tui_apply_current_layout): Use it.
> 	(tui_register_window): New function.
> 	* python/python.c (do_start_initialization): Call
> 	gdbpy_initialize_tui.
> 	(python_GdbMethods): Add "register_window_type" function.
> 	* python/python-internal.h (gdbpy_register_tui_window)
> 	(gdbpy_initialize_tui): Declare.
> 	* python/py-tui.c: New file.
> 	* Makefile.in (SUBDIR_PYTHON_SRCS): Add py-tui.c.
> 
> gdb/doc/ChangeLog
> 2020-01-04  Tom Tromey  <tom@tromey.com>
> 
> 	* python.texi (Python API): Add menu item.
> 	(TUI Windows In Python): New node.
> 
> gdb/testsuite/ChangeLog
> 2020-01-04  Tom Tromey  <tom@tromey.com>
> 
> 	* gdb.python/tui-window.exp: New file.
> 	* gdb.python/tui-window.py: New file.
> 
> Change-Id: I85fbfb923a1840450a00a7dce113a05d7f048baa

Hi Tom,

On a system without ncurses installed, I get:

$ make
  CXX    python/py-tui.o
In file included from /home/smarchi/src/binutils-gdb/gdb/python/py-tui.c:24:
/home/smarchi/src/binutils-gdb/gdb/gdb_curses.h:47:10: fatal error: ncurses.h: No such file or directory
   47 | #include <ncurses.h>
      |          ^~~~~~~~~~~

So I suspect weare missing an #if/#ifdef somwhere.  config.log contains:

/* Define to 1 if you have the <ncursesw/ncurses.h> header file. */
/* #undef HAVE_NCURSESW_NCURSES_H */

/* Define to 1 if you have the <ncurses.h> header file. */
/* #undef HAVE_NCURSES_H */

/* Define to 1 if you have the <ncurses/ncurses.h> header file. */
/* #undef HAVE_NCURSES_NCURSES_H */

Simon


^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 20/24] Allow TUI windows in Python
  2020-03-10 22:23   ` Simon Marchi
@ 2020-03-11  0:23     ` Tom Tromey
  2020-03-11  4:47       ` Simon Marchi
  0 siblings, 1 reply; 36+ messages in thread
From: Tom Tromey @ 2020-03-11  0:23 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Tom Tromey, gdb-patches

>>>>> "Simon" == Simon Marchi <simark@simark.ca> writes:

Simon> In file included from /home/smarchi/src/binutils-gdb/gdb/python/py-tui.c:24:
Simon> /home/smarchi/src/binutils-gdb/gdb/gdb_curses.h:47:10: fatal error: ncurses.h: No such file or directory
Simon>    47 | #include <ncurses.h>
Simon>       |          ^~~~~~~~~~~

Simon> So I suspect weare missing an #if/#ifdef somwhere.  config.log contains:

Simon> /* Define to 1 if you have the <ncursesw/ncurses.h> header file. */
Simon> /* #undef HAVE_NCURSESW_NCURSES_H */

Simon> /* Define to 1 if you have the <ncurses.h> header file. */
Simon> /* #undef HAVE_NCURSES_H */

Simon> /* Define to 1 if you have the <ncurses/ncurses.h> header file. */
Simon> /* #undef HAVE_NCURSES_NCURSES_H */

That is weird because gdb_curses.h says (I marked line 47):

        #if defined (HAVE_NCURSESW_NCURSES_H)
        #include <ncursesw/ncurses.h>
        #elif defined (HAVE_NCURSES_NCURSES_H)
        #include <ncurses/ncurses.h>
        #elif defined (HAVE_NCURSES_H)
--->    #include <ncurses.h>
        #elif defined (HAVE_CURSESX_H)
        #include <cursesX.h>
        #elif defined (HAVE_CURSES_H)
        #include <curses.h>
        #endif

... which sure looks like it is guarded by HAVE_NCURSES_H.

I couldn't find any other code that might define HAVE_NCURSES_H.

I don't know what's going on here :(

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 20/24] Allow TUI windows in Python
  2020-03-11  0:23     ` Tom Tromey
@ 2020-03-11  4:47       ` Simon Marchi
  2020-03-11  5:07         ` Simon Marchi
  2020-03-11 18:05         ` Tom Tromey
  0 siblings, 2 replies; 36+ messages in thread
From: Simon Marchi @ 2020-03-11  4:47 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 2020-03-10 8:23 p.m., Tom Tromey wrote:
>>>>>> "Simon" == Simon Marchi <simark@simark.ca> writes:
> 
> Simon> In file included from /home/smarchi/src/binutils-gdb/gdb/python/py-tui.c:24:
> Simon> /home/smarchi/src/binutils-gdb/gdb/gdb_curses.h:47:10: fatal error: ncurses.h: No such file or directory
> Simon>    47 | #include <ncurses.h>
> Simon>       |          ^~~~~~~~~~~
> 
> Simon> So I suspect weare missing an #if/#ifdef somwhere.  config.log contains:
> 
> Simon> /* Define to 1 if you have the <ncursesw/ncurses.h> header file. */
> Simon> /* #undef HAVE_NCURSESW_NCURSES_H */
> 
> Simon> /* Define to 1 if you have the <ncurses.h> header file. */
> Simon> /* #undef HAVE_NCURSES_H */
> 
> Simon> /* Define to 1 if you have the <ncurses/ncurses.h> header file. */
> Simon> /* #undef HAVE_NCURSES_NCURSES_H */
> 
> That is weird because gdb_curses.h says (I marked line 47):
> 
>         #if defined (HAVE_NCURSESW_NCURSES_H)
>         #include <ncursesw/ncurses.h>
>         #elif defined (HAVE_NCURSES_NCURSES_H)
>         #include <ncurses/ncurses.h>
>         #elif defined (HAVE_NCURSES_H)
> --->    #include <ncurses.h>
>         #elif defined (HAVE_CURSESX_H)
>         #include <cursesX.h>
>         #elif defined (HAVE_CURSES_H)
>         #include <curses.h>
>         #endif
> 
> ... which sure looks like it is guarded by HAVE_NCURSES_H.
> 
> I couldn't find any other code that might define HAVE_NCURSES_H.
> 
> I don't know what's going on here :(
> 
> Tom
> 

Sorry for being terse earlier, I didn't have much time.  I took another look,
I built the file with -save-temps and inspected the .ii file.  The
HAVE_NCURSES_H comes from pyconfig.h, which comes from the Python installation.

For example, on my Ubuntu here, it's at:

  /usr/include/x86_64-linux-gnu/python3.8/pyconfig.h

This file tells us Python was built with ncurses, which doesn't mean the
ncurses development headers are installed and available to GDB.  I find it
very odd that Python exposes these very generically-named macros in the global
namespace.  Almost any of these HAVE_FOO macros from Python could clash with
our own macros.

Anyway, I was able to reproduce it starting from a scratch Ubuntu 20.04 docker
container, installing everything required to build GDB except the ncurses
development headers.

One way to fix it is to make sure "python-internal.h" is included after
"gdb_curses.h", in py-tui.c.

Simon

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 20/24] Allow TUI windows in Python
  2020-03-11  4:47       ` Simon Marchi
@ 2020-03-11  5:07         ` Simon Marchi
  2020-03-11 18:05         ` Tom Tromey
  1 sibling, 0 replies; 36+ messages in thread
From: Simon Marchi @ 2020-03-11  5:07 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

On 2020-03-11 12:47 a.m., Simon Marchi wrote:
> Sorry for being terse earlier, I didn't have much time.  I took another look,
> I built the file with -save-temps and inspected the .ii file.  The
> HAVE_NCURSES_H comes from pyconfig.h, which comes from the Python installation.
> 
> For example, on my Ubuntu here, it's at:
> 
>   /usr/include/x86_64-linux-gnu/python3.8/pyconfig.h
> 
> This file tells us Python was built with ncurses, which doesn't mean the
> ncurses development headers are installed and available to GDB.  I find it
> very odd that Python exposes these very generically-named macros in the global
> namespace.  Almost any of these HAVE_FOO macros from Python could clash with
> our own macros.
> 
> Anyway, I was able to reproduce it starting from a scratch Ubuntu 20.04 docker
> container, installing everything required to build GDB except the ncurses
> development headers.
> 
> One way to fix it is to make sure "python-internal.h" is included after
> "gdb_curses.h", in py-tui.c.

Or, maybe we can say that this falls in the "mis-configuration" bucket.

If we are building against a Python that claims to have been built with
ncurses.h present, then ncurses.h ought to be present.  Then the fix is
for the user to install the ncurses development package.

Simon

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 20/24] Allow TUI windows in Python
  2020-03-11  4:47       ` Simon Marchi
  2020-03-11  5:07         ` Simon Marchi
@ 2020-03-11 18:05         ` Tom Tromey
  1 sibling, 0 replies; 36+ messages in thread
From: Tom Tromey @ 2020-03-11 18:05 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Tom Tromey, gdb-patches

>>>>> "Simon" == Simon Marchi <simark@simark.ca> writes:

Simon> This file tells us Python was built with ncurses, which doesn't mean the
Simon> ncurses development headers are installed and available to GDB.  I find it
Simon> very odd that Python exposes these very generically-named macros in the global
Simon> namespace.  Almost any of these HAVE_FOO macros from Python could clash with
Simon> our own macros.

Yes, it's a bad practice.  Unfortunately autoconf never really provided
an easy-enough way to do the right thing here, so I think plenty of
packages have bad hygiene this way.

Simon> One way to fix it is to make sure "python-internal.h" is included after
Simon> "gdb_curses.h", in py-tui.c.

Feel free to put that in, I guess with a comment.

Another option might be to check whether HAVE_NCURSES_H is undefined
before including the Python headers, but defined afterward and #error in
this case.  That way we could perhaps give a less confusing error
message.

Tom

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2020-03-11 18:05 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-04 18:34 [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey
2020-01-04 18:34 ` [PATCH 14/24] Handle ambiguity in tui_partial_win_by_name Tom Tromey
2020-01-04 18:34 ` [PATCH 20/24] Allow TUI windows in Python Tom Tromey
2020-01-04 18:57   ` Eli Zaretskii
2020-02-22 19:57     ` Tom Tromey
2020-02-22 20:18       ` Eli Zaretskii
2020-03-10 22:23   ` Simon Marchi
2020-03-11  0:23     ` Tom Tromey
2020-03-11  4:47       ` Simon Marchi
2020-03-11  5:07         ` Simon Marchi
2020-03-11 18:05         ` Tom Tromey
2020-01-04 18:34 ` [PATCH 16/24] TUI windows do not need to store their type Tom Tromey
2020-01-04 18:34 ` [PATCH 10/24] Change return type of tui_layout_base::adjust_size Tom Tromey
2020-01-04 18:34 ` [PATCH 09/24] Allow TUI sub-layouts in "new-layout" command Tom Tromey
2020-01-04 18:34 ` [PATCH 06/24] Reimplement "tui reg" command Tom Tromey
2020-01-04 18:34 ` [PATCH 22/24] Use error_no_arg in TUI Tom Tromey
2020-01-04 18:34 ` [PATCH 03/24] Fix latent display bug in tui_data_window Tom Tromey
2020-01-04 18:34 ` [PATCH 18/24] Remove tui_set_win_focus_to Tom Tromey
2020-01-04 18:34 ` [PATCH 12/24] Change TUI window iteration Tom Tromey
2020-01-04 18:34 ` [PATCH 11/24] Add horizontal splitting to TUI layout Tom Tromey
2020-01-04 18:47   ` Eli Zaretskii
2020-01-04 18:34 ` [PATCH 13/24] Reimplement tui_next_win and tui_prev_win Tom Tromey
2020-01-04 18:34 ` [PATCH 07/24] Remove hard-coded TUI layouts Tom Tromey
2020-01-04 18:34 ` [PATCH 01/24] Use TUI_DISASM_WIN instead of tui_win_list array Tom Tromey
2020-01-04 18:34 ` [PATCH 04/24] Simplify TUI C-x 2 binding Tom Tromey
2020-01-04 18:34 ` [PATCH 15/24] Remove tui_delete_invisible_windows and tui_make_all_invisible Tom Tromey
2020-01-04 18:34 ` [PATCH 05/24] Reimplement TUI "C-x 1" binding Tom Tromey
2020-01-04 18:34 ` [PATCH 23/24] Add "usage" text to all TUI command help Tom Tromey
2020-01-04 18:34 ` [PATCH 24/24] Fix cast in TUI_DISASM_WIN Tom Tromey
2020-01-04 18:34 ` [PATCH 02/24] Simplify tui_add_win_to_layout Tom Tromey
2020-01-04 18:34 ` [PATCH 21/24] Make some tui_source_window_base members "protected" Tom Tromey
2020-01-04 18:34 ` [PATCH 08/24] Add the "tui new-layout" command Tom Tromey
2020-01-04 18:44   ` Eli Zaretskii
2020-01-04 18:34 ` [PATCH 19/24] Remove the TUI annotation hack Tom Tromey
2020-01-04 18:54 ` [PATCH 17/24] Change how TUI windows are instantiated Tom Tromey
2020-02-22 20:22 ` [PATCH 00/24] Horizontal TUI layout + windows in Python Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).