]> git.eshelyaron.com Git - emacs.git/commitdiff
Make frame synchronization more robust
authorPo Lu <luangruo@yahoo.com>
Sun, 27 Nov 2022 11:17:38 +0000 (19:17 +0800)
committerPo Lu <luangruo@yahoo.com>
Sun, 27 Nov 2022 11:21:03 +0000 (19:21 +0800)
* src/xterm.c (x_sync_wait_for_frame_drawn_event)
(x_sync_handle_frame_drawn): Only cancel frame synchronization
if hanging twice or more in a row.
* src/xterm.h (struct x_output, FRAME_X_DRAW_JUST_HUNG): New
flag.

src/xterm.c
src/xterm.h

index ec605f5e914da4082ba8ed60ceef8a3987d6458f..7eaf59d54b19eb1185fd8d892e58da566347609e 100644 (file)
@@ -6919,13 +6919,27 @@ x_sync_wait_for_frame_drawn_event (struct frame *f)
                  x_sync_is_frame_drawn_event, (XPointer) f,
                  make_timespec (1, 0)))
     {
-      /* TODO: display this warning in the echo area.  */
-      fprintf (stderr, "Warning: compositing manager spent more than 1 second "
-              "drawing a frame.  Frame synchronization has been disabled\n");
-      FRAME_X_OUTPUT (f)->use_vsync_p = false;
+      /* The first time a draw hangs, treat it as a random fluctuation
+        on the part of the compositor.  If the next draw continues to
+        hang, disable frame synchronization.  */
+      if (FRAME_X_DRAW_JUST_HUNG (f))
+       {
+         fprintf (stderr, "Warning: compositing manager spent more than 1 "
+                  "second drawing a frame.  Frame synchronization has "
+                  "been disabled\n");
+         FRAME_X_OUTPUT (f)->use_vsync_p = false;
 
-      /* Also change the frame parameter to reflect the new state.  */
-      store_frame_param (f, Quse_frame_synchronization, Qnil);
+         /* Also change the frame parameter to reflect the new
+            state.  */
+         store_frame_param (f, Quse_frame_synchronization, Qnil);
+       }
+      else
+       {
+         fprintf (stderr, "Warning: compositing manager spent more than 1 "
+                  "second drawing a frame.  Frame synchronization will be "
+                  "disabled if this happens again\n");
+         FRAME_X_DRAW_JUST_HUNG (f) = true;
+       }
     }
   else
     x_sync_note_frame_times (FRAME_DISPLAY_INFO (f), f, &event);
@@ -7128,8 +7142,26 @@ static void
 x_sync_handle_frame_drawn (struct x_display_info *dpyinfo,
                           XEvent *message, struct frame *f)
 {
+  XSyncValue value, counter;
+
   if (FRAME_OUTER_WINDOW (f) == message->xclient.window)
-    FRAME_X_WAITING_FOR_DRAW (f) = false;
+    {
+      counter = FRAME_X_COUNTER_VALUE (f);
+
+      /* Check that the counter in the message is the same as the
+        counter in the frame.  */
+      XSyncIntsToValue (&value,
+                       message->xclient.data.l[0] & 0xffffffff,
+                       message->xclient.data.l[1] & 0xffffffff);
+
+      if (XSyncValueEqual (value, counter))
+       FRAME_X_WAITING_FOR_DRAW (f) = false;
+
+      /* As long as a _NET_WM_FRAME_DRAWN message arrives, we know
+        that the compositor is still sending events, so avoid timing
+        out.  */
+      FRAME_X_DRAW_JUST_HUNG (f) = false;
+    }
 
   x_sync_note_frame_times (dpyinfo, f, message);
 }
index c36920081d3d7ecc5fae6e9003d73d61b87a337c..ee429e9c68d7dd2bfcd3e171b34001d87e53454d 100644 (file)
@@ -1179,6 +1179,10 @@ struct x_output
      frame.  */
   bool_bf waiting_for_frame_p : 1;
 
+  /* Whether or not Emacs just skipped waiting for a frame due to a
+     timeout.  */
+  bool_bf draw_just_hung_p : 1;
+
 #if !defined USE_GTK && defined HAVE_CLOCK_GETTIME
   /* Whether or not Emacs should wait for the compositing manager to
      draw frames before starting a new frame.  */
@@ -1392,6 +1396,8 @@ extern void x_mark_frame_dirty (struct frame *f);
   FRAME_X_OUTPUT (f)->extended_frame_counter
 #define FRAME_X_WAITING_FOR_DRAW(f)            \
   FRAME_X_OUTPUT (f)->waiting_for_frame_p
+#define FRAME_X_DRAW_JUST_HUNG(f)              \
+  FRAME_X_OUTPUT (f)->draw_just_hung_p
 #define FRAME_X_COUNTER_VALUE(f)               \
   FRAME_X_OUTPUT (f)->current_extended_counter_value
 #endif