Subject: bug#30699: 26.0.91; buffer contents flicker on macOS frames when frames are resized

From: Alan Third <[email-masked]>
Date: Sat, 10 Mar 2018 00:25:55 +0000

On Fri, Mar 09, 2018 at 11:24:15PM +0000, Alan Third wrote:
> The other solution I have is to use NSDisableScreenUpdates to prevent
> updates being flushed to the screen until after redisplay, but that
> completely breaks resizing with the mouse.

I just realised that this isn’t actually hard to get right.

Patch attached. I think this is a better solution than the last one.

Disabling screen updates just stops them being flushed to the screen,
when they’re enabled all the updates happen at once (including the
window manager’s frame resize). I guess it’s like drawing to an
off‐screen buffer then swapping.
-- 
Alan Third
>From c382338d44c3ff833e965e1d92106a90b75edec5 Mon Sep 17 00:00:00 2001
From: Alan Third <[email-masked]>
Date: Sat, 10 Mar 2018 00:09:09 +0000
Subject: [PATCH] Fix frame resize flicker on macOS (bug#30699)

* src/nsterm.h (ns_enable_screen_updates): New function.
* src/nsterm.m (ns_enable_screen_updates):
(ns_disable_screen_updates): New functions.
(disable_screen_updates_count): Count of number of times we've called
NSDisableScreenUpdates.
(x_set_window_size): Disable screen updates when not in a live resize
loop.
* src/xdisp.c (redisplay_internal): Reenable NS screenupdates at end
of redisplay.
---
 src/nsterm.h |  3 +++
 src/nsterm.m | 30 ++++++++++++++++++++++++++++++
 src/xdisp.c  |  3 +++
 3 files changed, 36 insertions(+)

diff --git a/src/nsterm.h b/src/nsterm.h
index 8b985930ec..df59a7dbd9 100644
--- a/src/nsterm.h
+++ b/src/nsterm.h
@@ -1160,6 +1160,9 @@ extern void ns_release_autorelease_pool (void *);
 extern const char *ns_get_defaults_value (const char *key);
 extern void ns_init_locale (void);
 
+#ifdef NS_IMPL_COCOA
+extern void ns_enable_screen_updates (void);
+#endif
 
 /* in nsmenu */
 extern void update_frame_tool_bar (struct frame *f);
diff --git a/src/nsterm.m b/src/nsterm.m
index 1919c6defa..b4ec384aaf 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -288,6 +288,7 @@ - (NSColor *)colorUsingDefaultColorSpace
 static BOOL ns_fake_keydown = NO;
 #ifdef NS_IMPL_COCOA
 static BOOL ns_menu_bar_is_hidden = NO;
+static int disable_screen_updates_count = 0;
 #endif
 /*static int debug_lock = 0; */
 
@@ -727,6 +728,26 @@ Free a pool and temporary objects it refers to (callable from C)
 }

+#ifdef NS_IMPL_COCOA
+static void
+ns_disable_screen_updates (void)
+{
+  NSDisableScreenUpdates ();
+  disable_screen_updates_count++;
+}
+
+void
+ns_enable_screen_updates (void)
+{
+  while (disable_screen_updates_count > 0)
+    {
+      NSEnableScreenUpdates ();
+      disable_screen_updates_count--;
+    }
+}
+#endif
+
+
 static BOOL
 ns_menu_bar_should_be_hidden (void)
 /* True, if the menu bar should be hidden.  */
@@ -1877,6 +1898,15 @@ -(void)remove
 
   block_input ();
 
+#ifdef NS_IMPL_COCOA
+  /* To prevent showing the user a blank frame, stop updates being
+     flushed to the screen until after redisplay has completed.  This
+     breaks live resize (resizing with a mouse), so don't do it if
+     we're in a live resize loop.  */
+  if (![view inLiveResize])
+    ns_disable_screen_updates ();
+#endif
+
   if (pixelwise)
     {
       pixelwidth = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
diff --git a/src/xdisp.c b/src/xdisp.c
index 9170d6b777..d4fdb44b32 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -14599,6 +14599,9 @@ redisplay_internal (void)
  end_of_redisplay:
 #ifdef HAVE_NS
   ns_set_doc_edited ();
+#ifdef NS_IMPL_COCOA
+  ns_enable_screen_updates ();
+#endif
 #endif
   if (interrupt_input && interrupts_deferred)
     request_sigio ();
-- 
2.16.1