From 68bd6f3ea9c05637501139c46f1f4304482db95f Mon Sep 17 00:00:00 2001 From: Alan Third Date: Sun, 31 Jan 2021 20:19:53 +0000 Subject: [PATCH] Fix flicker when resizing NS frame programmatically (bug#46155) ; Incidentally fixes bug#21326. * src/nsterm.m ([EmacsView viewWillDraw]): New function. ([EmacsView viewDidResize:]): We now have to mark the frame for display on resize. ([EmacsView initFrameFromEmacs:]): Retain frame contents on resize. ([EmacsView updateLayer]): Don't update the layer if the frame is still garbaged. --- src/nsterm.m | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/nsterm.m b/src/nsterm.m index ca240eb55f1..b0cf5952fd5 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -7350,6 +7350,8 @@ not_in_argv (NSString *arg) [surface release]; surface = nil; + + [self setNeedsDisplay:YES]; } #endif @@ -7521,6 +7523,16 @@ not_in_argv (NSString *arg) [self initWithFrame: r]; [self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable]; +#ifdef NS_DRAW_TO_BUFFER + /* These settings mean AppKit will retain the contents of the frame + on resize. Unfortunately it also means the frame will not be + automatically marked for display, but we can do that ourselves in + viewDidResize. */ + [self setLayerContentsRedrawPolicy: + NSViewLayerContentsRedrawOnSetNeedsDisplay]; + [self setLayerContentsPlacement:NSViewLayerContentsPlacementTopLeft]; +#endif + FRAME_NS_VIEW (f) = self; emacsframe = f; #ifdef NS_IMPL_COCOA @@ -8463,6 +8475,34 @@ not_in_argv (NSString *arg) } +#ifdef NS_IMPL_COCOA +/* If the frame has been garbaged but the toolkit wants to draw, for + example when resizing the frame, we end up with a blank screen. + Sometimes this results in an unpleasant flicker, so try to + redisplay before drawing. */ +- (void)viewWillDraw +{ + if (FRAME_GARBAGED_P (emacsframe) + && !redisplaying_p) + { + /* If there is IO going on when redisplay is run here Emacs + crashes. I think it's because this code will always be run + within the run loop and for whatever reason processing input + is dangerous. This technique was stolen wholesale from + nsmenu.m and seems to work. */ + bool owfi = waiting_for_input; + waiting_for_input = 0; + block_input (); + + redisplay (); + + unblock_input (); + waiting_for_input = owfi; + } +} +#endif + + #ifdef NS_DRAW_TO_BUFFER - (BOOL)wantsUpdateLayer { @@ -8480,6 +8520,13 @@ not_in_argv (NSString *arg) { NSTRACE ("[EmacsView updateLayer]"); + /* We run redisplay on frames that are garbaged, but marked for + display, before updateLayer is called so if the frame is still + garbaged that means the last redisplay must have refused to + update the frame. */ + if (FRAME_GARBAGED_P (emacsframe)) + return; + /* This can fail to update the screen if the same surface is provided twice in a row, even if its contents have changed. There's a private method, -[CALayer setContentsChanged], that we -- 2.39.2