Remove flickering from the TUI
authorTom Tromey <tom@tromey.com>
Fri, 27 Dec 2019 15:47:41 +0000 (08:47 -0700)
committerTom Tromey <tom@tromey.com>
Sun, 19 Jan 2020 20:08:49 +0000 (13:08 -0700)
In some cases, the TUI flickers when redrawing.  This can be seen
mostly easily when switching layouts.

This patch fixes the problem by exploiting the double buffering that
curses already does.  In some spots, the TUI will now disable flushing
the curses buffers to the screen; and then flush them all at once when
the rendering is complete.

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

* tui/tui.c (tui_show_assembly): Use tui_suppress_output.
* tui/tui-wingeneral.h (class tui_suppress_output): New.
(tui_wrefresh): Declare.
* tui/tui-wingeneral.c (suppress_output): New global.
(tui_suppress_output, ~tui_suppress_output): New constructor and
destructor.
(tui_wrefresh): New function.
(tui_gen_win_info::refresh_window): Use tui_wrefresh.
(tui_gen_win_info::make_window): Call wnoutrefresh when needed.
* tui/tui-regs.h (struct tui_data_window) <no_refresh>: Declare
method.
* tui/tui-regs.c (tui_data_window::erase_data_content): Call
tui_wrefresh.
(tui_data_window::no_refresh): New method.
(tui_data_item_window::refresh_window): Call tui_wrefresh.
(tui_reg_command): Use tui_suppress_output
* tui/tui-layout.c (tui_set_layout): Use tui_suppress_output.
* tui/tui-data.h (struct tui_gen_win_info) <no_refresh>: New
method.
* tui/tui-command.c (tui_refresh_cmd_win): Call tui_wrefresh.

Change-Id: Icb832ae100b861de3af3307488e636fa928d5c9f

gdb/ChangeLog
gdb/tui/tui-command.c
gdb/tui/tui-data.h
gdb/tui/tui-layout.c
gdb/tui/tui-regs.c
gdb/tui/tui-regs.h
gdb/tui/tui-wingeneral.c
gdb/tui/tui-wingeneral.h
gdb/tui/tui.c

index d8482aaaa5614371561d994216847b26331d1a05..a25f7216721ac4c7a9e30900f113894e15d39c28 100644 (file)
@@ -1,3 +1,26 @@
+2020-01-19  Tom Tromey  <tom@tromey.com>
+
+       * tui/tui.c (tui_show_assembly): Use tui_suppress_output.
+       * tui/tui-wingeneral.h (class tui_suppress_output): New.
+       (tui_wrefresh): Declare.
+       * tui/tui-wingeneral.c (suppress_output): New global.
+       (tui_suppress_output, ~tui_suppress_output): New constructor and
+       destructor.
+       (tui_wrefresh): New function.
+       (tui_gen_win_info::refresh_window): Use tui_wrefresh.
+       (tui_gen_win_info::make_window): Call wnoutrefresh when needed.
+       * tui/tui-regs.h (struct tui_data_window) <no_refresh>: Declare
+       method.
+       * tui/tui-regs.c (tui_data_window::erase_data_content): Call
+       tui_wrefresh.
+       (tui_data_window::no_refresh): New method.
+       (tui_data_item_window::refresh_window): Call tui_wrefresh.
+       (tui_reg_command): Use tui_suppress_output
+       * tui/tui-layout.c (tui_set_layout): Use tui_suppress_output.
+       * tui/tui-data.h (struct tui_gen_win_info) <no_refresh>: New
+       method.
+       * tui/tui-command.c (tui_refresh_cmd_win): Call tui_wrefresh.
+
 2020-01-19  Tom Tromey  <tom@tromey.com>
 
        * tui/tui-winsource.c (tui_update_source_windows_with_line):
index ba2a802287b160c16671126dabe98968f4522783..42fc59aac6b5bdf1a0b8bf70a7e63126cc9108e4 100644 (file)
@@ -70,7 +70,7 @@ tui_refresh_cmd_win (void)
 {
   WINDOW *w = TUI_CMD_WIN->handle.get ();
 
-  wrefresh (w);
+  tui_wrefresh (w);
 
   /* FIXME: It's not clear why this is here.
      It was present in the original tui_puts code and is kept in order to
index ffdd5e37491c3e109c447fd76e029b926bc391ef..6f86122f58f1a467270c2c363da0c9912503e6ff 100644 (file)
@@ -99,6 +99,13 @@ public:
     return handle != nullptr;
   }
 
+  /* Disable output until the next call to doupdate.  */
+  virtual void no_refresh ()
+  {
+    if (handle != nullptr)
+      wnoutrefresh (handle.get ());
+  }
+
   /* Window handle.  */
   std::unique_ptr<WINDOW, curses_deleter> handle;
   /* Type of window.  */
index 01961f550c260bacb4aabc2eb312f74c89fb86c1..3d1e349196acea9639d9edd492b490aab71d9e52 100644 (file)
@@ -113,6 +113,8 @@ tui_set_layout (enum tui_layout_type layout_type)
 
   if (new_layout != cur_layout)
     {
+      tui_suppress_output suppress;
+
       show_layout (new_layout);
 
       /* Now determine where focus should be.  */
index 80d1a270e637ab99b74a93683b1ade092cec47e1..bedf55cab8b12810f011230f0cc19712f7010e4e 100644 (file)
@@ -381,7 +381,7 @@ tui_data_window::erase_data_content (const char *prompt)
        x_pos = half_width - strlen (prompt);
       mvwaddstr (handle.get (), (height / 2), x_pos, (char *) prompt);
     }
-  wrefresh (handle.get ());
+  tui_wrefresh (handle.get ());
 }
 
 /* See tui-regs.h.  */
@@ -434,6 +434,14 @@ tui_data_window::refresh_window ()
     win.refresh_window ();
 }
 
+void
+tui_data_window::no_refresh ()
+{
+  tui_gen_win_info::no_refresh ();
+  for (auto &&win : m_regs_content)
+    win.no_refresh ();
+}
+
 /* This function check all displayed registers for changes in values,
    given a particular frame.  If the values have changed, they are
    updated with the new value and highlighted.  */
@@ -502,7 +510,7 @@ tui_data_item_window::refresh_window ()
         windows, which according to the ncurses man pages aren't well
         supported.  */
       touchwin (handle.get ());
-      wrefresh (handle.get ());
+      tui_wrefresh (handle.get ());
     }
 }
 
@@ -574,6 +582,8 @@ tui_reg_command (const char *args, int from_tty)
       /* Make sure the curses mode is enabled.  */
       tui_enable ();
 
+      tui_suppress_output suppress;
+
       /* Make sure the register window is visible.  If not, select an
         appropriate layout.  We need to do this before trying to run the
         'next' or 'prev' commands.  */
index 97e02b1a47d020c4e9a48d6feff60b4588c389a2..eee3689aeacafbe42d997be0707c85cc1636356e 100644 (file)
@@ -70,6 +70,8 @@ struct tui_data_window : public tui_win_info
 
   void refresh_window () override;
 
+  void no_refresh () override;
+
   const char *name () const override
   {
     return DATA_NAME;
index 4331f6363585bace8304a207ba7348c1e83b9bc1..e001a4cd97234d8aaf92f00520029027dc61f5c8 100644 (file)
 
 #include "gdb_curses.h"
 
+/* This is true if we're currently suppressing output, via
+   wnoutrefresh.  This is needed in case we create a new window while
+   in this mode.  */
+
+static bool suppress_output;
+
+/* See tui-data.h.  */
+
+tui_suppress_output::tui_suppress_output ()
+  : m_saved_suppress (suppress_output)
+{
+  suppress_output = true;
+
+  for (const auto &win : all_tui_windows ())
+    win->no_refresh ();
+}
+
+/* See tui-data.h.  */
+
+tui_suppress_output::~tui_suppress_output ()
+{
+  suppress_output = m_saved_suppress;
+  if (!suppress_output)
+    doupdate ();
+
+  for (const auto &win : all_tui_windows ())
+    win->refresh_window ();
+}
+
+/* See tui-data.h.  */
+
+void
+tui_wrefresh (WINDOW *win)
+{
+  if (!suppress_output)
+    wrefresh (win);
+}
+
 /* See tui-data.h.  */
 
 void
 tui_gen_win_info::refresh_window ()
 {
   if (handle != NULL)
-    wrefresh (handle.get ());
+    tui_wrefresh (handle.get ());
 }
 
 /* Draw a border arround the window.  */
@@ -134,7 +172,11 @@ tui_gen_win_info::make_window ()
 {
   handle.reset (newwin (height, width, y, x));
   if (handle != NULL)
-    scrollok (handle.get (), TRUE);
+    {
+      if (suppress_output)
+       wnoutrefresh (handle.get ());
+      scrollok (handle.get (), TRUE);
+    }
 }
 
 void
index e32dbed2995da453d307f949ef8e3617b1ea9044..a28f27c55144cb8842c4af61751149cddc737ccc 100644 (file)
@@ -33,4 +33,27 @@ extern void tui_unhighlight_win (struct tui_win_info *);
 extern void tui_highlight_win (struct tui_win_info *);
 extern void tui_refresh_all ();
 
+/* An RAII class that suppresses output on construction (calling
+   wnoutrefresh on the existing windows), and then flushes the output
+   (via doupdate) when destroyed.  */
+
+class tui_suppress_output
+{
+public:
+
+  tui_suppress_output ();
+  ~tui_suppress_output ();
+
+  DISABLE_COPY_AND_ASSIGN (tui_suppress_output);
+
+private:
+
+  /* Save the state of the suppression global.  */
+  bool m_saved_suppress;
+};
+
+/* Call wrefresh on the given window.  However, if output is being
+   suppressed via tui_suppress_output, do not call wrefresh.  */
+extern void tui_wrefresh (WINDOW *win);
+
 #endif /* TUI_TUI_WINGENERAL_H */
index be19ef701d7b6b7fab673764d5880d4f0b34828b..ae3b9f6072de14950daf7110abe46c929e23621a 100644 (file)
@@ -30,6 +30,7 @@
 #include "tui/tui-regs.h"
 #include "tui/tui-stack.h"
 #include "tui/tui-win.h"
+#include "tui/tui-wingeneral.h"
 #include "tui/tui-winsource.h"
 #include "tui/tui-source.h"
 #include "target.h"
@@ -577,6 +578,7 @@ tui_disable_command (const char *args, int from_tty)
 void
 tui_show_assembly (struct gdbarch *gdbarch, CORE_ADDR addr)
 {
+  tui_suppress_output suppress;
   tui_add_win_to_layout (DISASSEM_WIN);
   tui_update_source_windows_with_addr (gdbarch, addr);
 }