emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master da6778d1ce: Fix multiple sources of flicker under X


From: Po Lu
Subject: master da6778d1ce: Fix multiple sources of flicker under X
Date: Sun, 16 Oct 2022 02:05:14 -0400 (EDT)

branch: master
commit da6778d1ce55843cd52da7db66bcb518c441e46e
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Fix multiple sources of flicker under X
    
    Fix three kinds of flicker.  The first is if you do:
    
      (while t (sit-for 1) (redraw-display))
    
    and press a key, the frame will turn blank until you C-g.  The
    second is where handling async input happens in the middle of
    drawing and causes a buffer flip to happen.  The third is where
    unmapping the hourglass window causes exposures.
    
    * src/dispnew.c (redraw_frame): Garbage the frame if it is a
    window system frame.
    * src/xterm.c (x_update_begin): Clear complete flag.
    (x_flip_and_flush, XTframe_up_to_date): Set complete flag.
    (x_show_hourglass): Fix hourglass window class.
    (flush_dirty_back_buffer_on): Rename to
    x_flush_dirty_back_buffer_on.
    (x_flush_dirty_back_buffer_on): Check if the frame is complete
    before trying to flip.
    (handle_one_xevent): Flush frames in a more detailed fashion.
    * src/xterm.h (struct x_output): New flag `complete'.
    (FRAME_X_COMPLETE_P): New macro.
---
 src/dispnew.c |   9 +++++
 src/xterm.c   | 117 ++++++++++++++++++++++++++++++++++++++--------------------
 src/xterm.h   |  21 ++++++++---
 3 files changed, 102 insertions(+), 45 deletions(-)

diff --git a/src/dispnew.c b/src/dispnew.c
index 2568ba1086..5a9ba8909e 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -3152,10 +3152,19 @@ redraw_frame (struct frame *f)
   update_begin (f);
   if (FRAME_MSDOS_P (f))
     FRAME_TERMINAL (f)->set_terminal_modes_hook (FRAME_TERMINAL (f));
+
+  if (FRAME_WINDOW_P (f))
+    /* Garbage the frame now.  Otherwise, platforms that support
+       double buffering will display the blank contents of the frame
+       even though the frame should be redrawn at some point in the
+       future.  */
+    SET_FRAME_GARBAGED (f);
+
   clear_frame (f);
   clear_current_matrices (f);
   update_end (f);
   fset_redisplay (f);
+
   /* Mark all windows as inaccurate, so that every window will have
      its redisplay done.  */
   mark_window_display_accurate (FRAME_ROOT_WINDOW (f), 0);
diff --git a/src/xterm.c b/src/xterm.c
index d35af7a8de..ee6db62bb9 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -7044,6 +7044,13 @@ x_update_begin (struct frame *f)
 #else
   /* Nothing to do.  */
 #endif
+
+#ifdef HAVE_XDBE
+  if (FRAME_X_DOUBLE_BUFFERED_P (f))
+    /* The frame is no longer complete, as it is in the midst of an
+       update.  */
+    FRAME_X_COMPLETE_P (f) = false;
+#endif
 }
 
 /* Draw a vertical window border from (x,y0) to (x,y1)  */
@@ -7190,6 +7197,10 @@ x_flip_and_flush (struct frame *f)
 #ifdef HAVE_XDBE
   if (FRAME_X_NEED_BUFFER_FLIP (f))
     show_back_buffer (f);
+
+  /* The frame is complete again as its contents were just
+     flushed.  */
+  FRAME_X_COMPLETE_P (f) = true;
 #endif
   x_flush (f);
   unblock_input ();
@@ -7240,6 +7251,9 @@ XTframe_up_to_date (struct frame *f)
   if (!buffer_flipping_blocked_p ()
       && FRAME_X_NEED_BUFFER_FLIP (f))
     show_back_buffer (f);
+
+  /* The frame is now complete, as its contents have been drawn.  */
+  FRAME_X_COMPLETE_P (f) = true;
 #endif
 
 #ifdef HAVE_XSYNC
@@ -10806,6 +10820,7 @@ x_clear_frame (struct frame *f)
   /* We have to clear the scroll bars.  If we have changed colors or
      something like that, then they should be notified.  */
   x_scroll_bar_clear (f);
+
   unblock_input ();
 }
 
@@ -10857,7 +10872,7 @@ x_show_hourglass (struct frame *f)
                                (xcb_window_t) x->hourglass_window,
                                parent, 0, 0, FRAME_PIXEL_WIDTH (f),
                                FRAME_PIXEL_HEIGHT (f), 0,
-                               XCB_WINDOW_CLASS_INPUT_OUTPUT,
+                               XCB_WINDOW_CLASS_INPUT_ONLY,
                                XCB_COPY_FROM_PARENT, XCB_CW_CURSOR,
                                &cursor);
 #endif
@@ -17033,18 +17048,21 @@ x_net_wm_state (struct frame *f, Window window)
 
 /* Flip back buffers on F if it has undrawn content.  */
 
-#ifdef HAVE_XDBE
 static void
-flush_dirty_back_buffer_on (struct frame *f)
+x_flush_dirty_back_buffer_on (struct frame *f)
 {
-  block_input ();
-  if (!FRAME_GARBAGED_P (f)
-      && !buffer_flipping_blocked_p ()
-      && FRAME_X_NEED_BUFFER_FLIP (f))
-    show_back_buffer (f);
-  unblock_input ();
-}
+#ifdef HAVE_XDBE
+  if (FRAME_GARBAGED_P (f)
+      || buffer_flipping_blocked_p ()
+      /* If the frame is not already up to date, do not flush buffers
+        on input, as that will result in flicker.  */
+      || !FRAME_X_COMPLETE_P (f)
+      || !FRAME_X_NEED_BUFFER_FLIP (f))
+    return;
+
+  show_back_buffer (f);
 #endif
+}
 
 #ifdef HAVE_GTK3
 void
@@ -17824,7 +17842,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
   Time gen_help_time UNINIT;
 #endif
   ptrdiff_t nbytes = 0;
-  struct frame *any, *f = NULL;
+  struct frame *any, *f = NULL, *mouse_frame;
   Mouse_HLInfo *hlinfo = &dpyinfo->mouse_highlight;
   /* This holds the state XLookupString needs to implement dead keys
      and other tricks known as "compose processing".  _X Window System_
@@ -19148,9 +19166,14 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              || !EQ (f->tab_bar_window, hlinfo->mouse_face_window))
          )
         {
-          clear_mouse_face (hlinfo);
-          hlinfo->mouse_face_hidden = true;
-        }
+         mouse_frame = hlinfo->mouse_face_mouse_frame;
+
+         clear_mouse_face (hlinfo);
+         hlinfo->mouse_face_hidden = true;
+
+         if (mouse_frame)
+           x_flush_dirty_back_buffer_on (mouse_frame);
+       }
 
 #if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
       if (f == 0)
@@ -19630,6 +19653,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              {
                clear_mouse_face (hlinfo);
                hlinfo->mouse_face_mouse_frame = 0;
+               x_flush_dirty_back_buffer_on (xvw->frame);
              }
 
            if (any_help_event_p)
@@ -19783,6 +19807,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  certainly no longer on any text in the frame.  */
               clear_mouse_face (hlinfo);
               hlinfo->mouse_face_mouse_frame = 0;
+             x_flush_dirty_back_buffer_on (f);
             }
 
           /* Generate a nil HELP_EVENT to cancel a help-echo.
@@ -19840,7 +19865,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
         help_echo_string = Qnil;
 
        if (hlinfo->mouse_face_hidden)
-          {
+         {
             hlinfo->mouse_face_hidden = false;
             clear_mouse_face (hlinfo);
           }
@@ -20171,6 +20196,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
         if (!NILP (help_echo_string)
             || !NILP (previous_help_echo_string))
          do_help = 1;
+
+       if (f)
+         x_flush_dirty_back_buffer_on (f);
         goto OTHER;
       }
 
@@ -20837,9 +20865,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                 tab_bar_p = EQ (window, f->tab_bar_window);
 
                 if (tab_bar_p)
-                 tab_bar_arg = handle_tab_bar_click
-                   (f, x, y, event->xbutton.type == ButtonPress,
-                    x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state));
+                 {
+                   tab_bar_arg = handle_tab_bar_click
+                     (f, x, y, event->xbutton.type == ButtonPress,
+                      x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state));
+                   x_flush_dirty_back_buffer_on (f);
+                 }
               }
 
 #if ! defined (USE_GTK)
@@ -20857,9 +20888,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                  || f->last_tool_bar_item != -1));
 
                 if (tool_bar_p && event->xbutton.button < 4)
-                 handle_tool_bar_click
-                   (f, x, y, event->xbutton.type == ButtonPress,
-                    x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state));
+                 {
+                   handle_tool_bar_click
+                     (f, x, y, event->xbutton.type == ButtonPress,
+                      x_x_to_emacs_modifiers (dpyinfo, event->xbutton.state));
+                   x_flush_dirty_back_buffer_on (f);
+                 }
               }
 #endif /* !USE_GTK */
 
@@ -21398,6 +21432,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                         certainly no longer on any text in the frame.  */
                      clear_mouse_face (hlinfo);
                      hlinfo->mouse_face_mouse_frame = 0;
+                     x_flush_dirty_back_buffer_on (f);
                    }
 
                  /* Generate a nil HELP_EVENT to cancel a help-echo.
@@ -22073,6 +22108,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
                  do_help = 1;
                }
+
+             if (f)
+               x_flush_dirty_back_buffer_on (f);
              goto XI_OTHER;
            }
 
@@ -22592,9 +22630,12 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                      tab_bar_p = EQ (window, f->tab_bar_window);
 
                      if (tab_bar_p)
-                       tab_bar_arg = handle_tab_bar_click
-                         (f, x, y, xev->evtype == XI_ButtonPress,
-                          x_x_to_emacs_modifiers (dpyinfo, bv.state));
+                       {
+                         tab_bar_arg = handle_tab_bar_click
+                           (f, x, y, xev->evtype == XI_ButtonPress,
+                            x_x_to_emacs_modifiers (dpyinfo, bv.state));
+                         x_flush_dirty_back_buffer_on (f);
+                       }
                    }
 
 #if ! defined (USE_GTK)
@@ -22619,10 +22660,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                                        || f->last_tool_bar_item != -1));
 
                      if (tool_bar_p && xev->detail < 4)
-                       handle_tool_bar_click_with_device
-                         (f, x, y, xev->evtype == XI_ButtonPress,
-                          x_x_to_emacs_modifiers (dpyinfo, bv.state),
-                          source ? source->name : Qt);
+                       {
+                         handle_tool_bar_click_with_device
+                           (f, x, y, xev->evtype == XI_ButtonPress,
+                            x_x_to_emacs_modifiers (dpyinfo, bv.state),
+                            source ? source->name : Qt);
+                         x_flush_dirty_back_buffer_on (f);
+                       }
                    }
 #endif /* !USE_GTK */
 
@@ -22919,8 +22963,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                      || !EQ (f->tab_bar_window, hlinfo->mouse_face_window))
                  )
                {
+                 mouse_frame = hlinfo->mouse_face_mouse_frame;
+
                  clear_mouse_face (hlinfo);
                  hlinfo->mouse_face_hidden = true;
+
+                 if (mouse_frame)
+                   x_flush_dirty_back_buffer_on (mouse_frame);
                }
 
              if (f != 0)
@@ -24084,18 +24133,6 @@ handle_one_xevent (struct x_display_info *dpyinfo,
       count++;
     }
 
-  /* Sometimes event processing draws to either F or ANY outside
-     redisplay.  To ensure that these changes become visible, draw
-     them here.  */
-
-#ifdef HAVE_XDBE
-  if (f)
-    flush_dirty_back_buffer_on (f);
-
-  if (any && any != f)
-    flush_dirty_back_buffer_on (any);
-#endif
-
   SAFE_FREE ();
   return count;
 }
diff --git a/src/xterm.h b/src/xterm.h
index b68a234faa..55fd193a29 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -916,11 +916,6 @@ struct x_output
   Picture picture;
 #endif
 
-  /* Flag that indicates whether we've modified the back buffer and
-     need to publish our modifications to the front buffer at a
-     convenient time.  */
-  bool need_buffer_flip;
-
   /* The X window used for the bitmap icon;
      or 0 if we don't have a bitmap icon.  */
   Window icon_desc;
@@ -1091,6 +1086,18 @@ struct x_output
      and inactive states.  */
   bool_bf alpha_identical_p : 1;
 
+#ifdef HAVE_XDBE
+  /* Flag that indicates whether we've modified the back buffer and
+     need to publish our modifications to the front buffer at a
+     convenient time.  */
+  bool_bf need_buffer_flip : 1;
+
+  /* Flag that indicates whether or not the frame contents are
+     complete and can be safely flushed while handling async
+     input.  */
+  bool_bf complete : 1;
+#endif
+
 #ifdef HAVE_X_I18N
   /* Input context (currently, this means Compose key handler setup).  */
   XIC xic;
@@ -1248,6 +1255,10 @@ extern void x_mark_frame_dirty (struct frame *f);
 
 /* Return the need-buffer-flip flag for frame F.  */
 #define FRAME_X_NEED_BUFFER_FLIP(f) ((f)->output_data.x->need_buffer_flip)
+
+/* Return whether or not the frame F has been completely drawn.  Used
+   while handling async input.  */
+#define FRAME_X_COMPLETE_P(f) ((f)->output_data.x->complete)
 #endif
 
 /* Return the outermost X window associated with the frame F.  */



reply via email to

[Prev in Thread] Current Thread [Next in Thread]