bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

classic Classic list List threaded Threaded
18 messages Options
Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

Alan Third
On Thu, Jan 28, 2021 at 09:48:25AM -0600, Aaron Jensen wrote:

> From emacs -Q:
>
> (dotimes (n 10)
>   (set-frame-parameter nil 'width (+ 80 n))
>   (sit-for 0.1))
>
> This was previously fixed in bug#30699
>
> I don't know if it was reverted at some point and I didn't notice, or it
> was started flickering again after Alan's recent (fantastic) performance
> improvements.
>
> This reproduces on master (non-native-comp) as of ac102bb966 as well.

Apple deprecated the functions we were using to block screen drawing.

It's possible we can have a neater work-around now since we're drawing
to an offscreen buffer and therefore have greater control over what's
displayed. I'll have to look into it again.
--
Alan Third



Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

Alan Third
On Thu, Jan 28, 2021 at 04:39:49PM +0000, Alan Third wrote:

> On Thu, Jan 28, 2021 at 09:48:25AM -0600, Aaron Jensen wrote:
> > From emacs -Q:
> >
> > (dotimes (n 10)
> >   (set-frame-parameter nil 'width (+ 80 n))
> >   (sit-for 0.1))
> >
> > This was previously fixed in bug#30699
> >
> > I don't know if it was reverted at some point and I didn't notice, or it
> > was started flickering again after Alan's recent (fantastic) performance
> > improvements.
> >
> > This reproduces on master (non-native-comp) as of ac102bb966 as well.
>
> Apple deprecated the functions we were using to block screen drawing.
>
> It's possible we can have a neater work-around now since we're drawing
> to an offscreen buffer and therefore have greater control over what's
> displayed. I'll have to look into it again.
Well... I tried something ridiculous and it appears to work...

I suspect forcing redisplay this way within the NS run loop is bad
form, but it appears to work.
--
Alan Third

0001-Fix-flicker-when-resizing-NS-frame-programmatically-.patch (1K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

Aaron Jensen
On Sun, Jan 31, 2021 at 2:28 PM Alan Third <[hidden email]> wrote:

>
> On Thu, Jan 28, 2021 at 04:39:49PM +0000, Alan Third wrote:
> > On Thu, Jan 28, 2021 at 09:48:25AM -0600, Aaron Jensen wrote:
> > > From emacs -Q:
> > >
> > > (dotimes (n 10)
> > >   (set-frame-parameter nil 'width (+ 80 n))
> > >   (sit-for 0.1))
> > >
> > > This was previously fixed in bug#30699
> > >
> > > I don't know if it was reverted at some point and I didn't notice, or it
> > > was started flickering again after Alan's recent (fantastic) performance
> > > improvements.
> > >
> > > This reproduces on master (non-native-comp) as of ac102bb966 as well.
> >
> > Apple deprecated the functions we were using to block screen drawing.
> >
> > It's possible we can have a neater work-around now since we're drawing
> > to an offscreen buffer and therefore have greater control over what's
> > displayed. I'll have to look into it again.
>
> Well... I tried something ridiculous and it appears to work...
>
> I suspect forcing redisplay this way within the NS run loop is bad
> form, but it appears to work.

Awesome, it works for me. It also fixes an issue I've had when
launching Emacs and resizing it and it remaining blank for an extended
period of time (probably while it's busy, but it's still rather
unsightly)

I'll give it a shot for a while and report back.



Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

Aaron Jensen
On Sun, Jan 31, 2021 at 4:05 PM Aaron Jensen <[hidden email]> wrote:

> I'll give it a shot for a while and report back.

No problems with this, as far as I can tell.



Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

Aaron Jensen
On Mon, Feb 8, 2021 at 9:25 AM Aaron Jensen <[hidden email]> wrote:
>
> On Sun, Jan 31, 2021 at 4:05 PM Aaron Jensen <[hidden email]> wrote:
>
> > I'll give it a shot for a while and report back.
>
> No problems with this, as far as I can tell.

Mini frame only buffers still flicker on resize, see
https://github.com/muffinmad/emacs-mini-frame/issues/31

Repro (thanks to Andrii Kolomoiets):

emacs -Q
M-: (setq resize-mini-frames t)
M-: (make-frame '((minibuffer . only)))
M-x
Type random letters



Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

martin rudalics
 > Mini frame only buffers still flicker on resize, see
 > https://github.com/muffinmad/emacs-mini-frame/issues/31
 >
 > Repro (thanks to Andrii Kolomoiets):
 >
 > emacs -Q
 > M-: (setq resize-mini-frames t)
 > M-: (make-frame '((minibuffer . only)))
 > M-x
 > Type random letters

Where do you type those letters?  Into the normal frame?

I suppose 'fit-frame-to-buffer' is to blame here.  What happens when you
set 'resize-mini-frames' to 'ignore?  Some other function that resizes
the frame more conservatively or sporadically?

martin



Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

Andrii Kolomoiets
martin rudalics <[hidden email]> writes:

>> emacs -Q
>> M-: (setq resize-mini-frames t)
>> M-: (make-frame '((minibuffer . only)))
>> M-x
>> Type random letters
>
> Where do you type those letters?  Into the normal frame?

No, into the minibuffer-only frame.  After `make-frame` the
minibuffer-only frame became focused and accept input.

> I suppose 'fit-frame-to-buffer' is to blame here.  What happens when
> you set 'resize-mini-frames' to 'ignore?

The minibuffer-only frame doesn't resized and the text is not flicker.

> Some other function that resizes the frame more conservatively or
> sporadically?

I've set the `resize-mini-frames` to this function:

    (defun test/resize (frame)
      (modify-frame-parameters
       frame `((width . ,(+ 80 (random 20))))))

After each letter typed, the minibuffer-only frame is resized several
times.  The text is not visible during resize.



Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

martin rudalics
 >> Where do you type those letters?  Into the normal frame?
 >
 > No, into the minibuffer-only frame.  After `make-frame` the
 > minibuffer-only frame became focused and accept input.

Works here on Debian without problems, the minibuffer-only frame expands
by one character as expected.  I still doubt that this is an NS problem.

 >> Some other function that resizes the frame more conservatively or
 >> sporadically?
 >
 > I've set the `resize-mini-frames` to this function:
 >
 >      (defun test/resize (frame)
 >        (modify-frame-parameters
 >         frame `((width . ,(+ 80 (random 20))))))
 >
 > After each letter typed, the minibuffer-only frame is resized several
 > times.  The text is not visible during resize.

Can you try with a function that explicitly keeps the height constant -
i.e., calls 'fit-frame-to-buffer' with ONLY set to 'horizontally'.

martin



Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

Alan Third
On Tue, Feb 09, 2021 at 11:49:55AM +0100, martin rudalics wrote:
> >> Where do you type those letters?  Into the normal frame?
> >
> > No, into the minibuffer-only frame.  After `make-frame` the
> > minibuffer-only frame became focused and accept input.
>
> Works here on Debian without problems, the minibuffer-only frame expands
> by one character as expected.  I still doubt that this is an NS problem.

In case it matters, the background here is that after a resize Cocoa
doesn't retain the contents of the frame, but since the frame is
garbaged Emacs won't draw anything until redisplay is completed, but
Cocoa won't wait for redisplay, so we end up with a brief blank frame.

The patch Aaron and Andrii are using calls redisplay() just before the
frame is drawn, but only if it is garbaged.

My assumption is that something in this repro recipe is causing
redisplay to refuse to draw the frame until something else has
occurred. I've no idea what that could be and haven't investigated
yet.
--
Alan Third



Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

Andrii Kolomoiets
In reply to this post by martin rudalics
martin rudalics <[hidden email]> writes:

>>  >      (defun test/resize (frame)
>>  >        (modify-frame-parameters
>>  >         frame `((width . ,(+ 80 (random 20))))))
>>  >
>>  > After each letter typed, the minibuffer-only frame is resized several
>>  > times.  The text is not visible during resize.
>>
>> Can you try with a function that explicitly keeps the height constant -
>> i.e., calls 'fit-frame-to-buffer' with ONLY set to 'horizontally'.
>
> But I see that 'test/resize' does that already.  Is that function called
> more than once each time you type a letter?

Yes.  Almost each time I type or delete a letter.  Same on recent master
version under X (Gnome).  After typing C-g that function is called even
more times.



Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

Alan Third
In reply to this post by Alan Third
On Tue, Feb 09, 2021 at 11:05:08AM +0000, Alan Third wrote:
>
> The patch Aaron and Andrii are using calls redisplay() just before the
> frame is drawn, but only if it is garbaged.

I see from a subsequent email that Andrii isn't using the NS port, so
that bit of my message is wrong.
--
Alan Third



Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

Andrii Kolomoiets
Alan Third <[hidden email]> writes:

> On Tue, Feb 09, 2021 at 11:05:08AM +0000, Alan Third wrote:
>>
>> The patch Aaron and Andrii are using calls redisplay() just before the
>> frame is drawn, but only if it is garbaged.
>
> I see from a subsequent email that Andrii isn't using the NS port, so
> that bit of my message is wrong.

Sorry for kind of misleading you.  I indeed use NS port. The receipt for
minibuffer-only frame flickering was made on nearly recent master
version with your patch applied.  (I must say resizing and fullscreen
transition looks awesome now, thanks!)

I used GTK port under X in the VirtualBox to test the issue with the
minibuffer-only frame resized more than once even if the text is not
changed.



Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

martin rudalics
In reply to this post by Andrii Kolomoiets
 >> But I see that 'test/resize' does that already.  Is that function called
 >> more than once each time you type a letter?
 >
 > Yes.  Almost each time I type or delete a letter.  Same on recent master
 > version under X (Gnome).  After typing C-g that function is called even
 > more times.

Hmmm ... When I load with emacs -Q


(setq default-frame-alist '((minibuffer . nil)))

(setq frame-size-history '(100))

(defvar foo 0)

(defun foo (frame)
   (setq foo (1+ foo))
   (fit-frame-to-buffer frame))

(setq resize-mini-frames 'foo)


and leave Emacs alone for a while, 'foo' has increased by about 30 (I'd
attribute 20 of them to 'blink-cursor-mode').  So 'fit-frame-to-buffer'
apparently does get called way too often.  But if I now evaluate

(frame--size-history (window-frame (minibuffer-window)))

and look into the *frame-size-history* buffer, I see no excessive number
of calls to resize the frame's window here.  Maybe things are different
under Gnome or NS.

martin



Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

Alan Third
In reply to this post by Andrii Kolomoiets
On Tue, Feb 09, 2021 at 06:29:22PM +0200, Andrii Kolomoiets wrote:

> Alan Third <[hidden email]> writes:
>
> > On Tue, Feb 09, 2021 at 11:05:08AM +0000, Alan Third wrote:
> >>
> >> The patch Aaron and Andrii are using calls redisplay() just before the
> >> frame is drawn, but only if it is garbaged.
> >
> > I see from a subsequent email that Andrii isn't using the NS port, so
> > that bit of my message is wrong.
>
> Sorry for kind of misleading you.  I indeed use NS port. The receipt for
> minibuffer-only frame flickering was made on nearly recent master
> version with your patch applied.  (I must say resizing and fullscreen
> transition looks awesome now, thanks!)
>
> I used GTK port under X in the VirtualBox to test the issue with the
> minibuffer-only frame resized more than once even if the text is not
> changed.

Ah, OK. I guess it probably is exclusive to NS then.

The obvious solution IMO is to retain a copy of the old frame contents
and draw them in after resizing, before we try calling redisplay().

On the other hand, it would be nice to know why redisplay() isn't
drawing anything...
--
Alan Third



Reply | Threaded
Open this post in threaded view
|

bug#46155: 28.0.50; Regression: buffer contents flicker on macOS frames when

Aaron Jensen
On Tue, Feb 9, 2021 at 2:08 PM Alan Third <[hidden email]> wrote:

>
> On Tue, Feb 09, 2021 at 06:29:22PM +0200, Andrii Kolomoiets wrote:
> > Alan Third <[hidden email]> writes:
> >
> > > On Tue, Feb 09, 2021 at 11:05:08AM +0000, Alan Third wrote:
> > >>
> > >> The patch Aaron and Andrii are using calls redisplay() just before the
> > >> frame is drawn, but only if it is garbaged.
> > >
> > > I see from a subsequent email that Andrii isn't using the NS port, so
> > > that bit of my message is wrong.
> >
> > Sorry for kind of misleading you.  I indeed use NS port. The receipt for
> > minibuffer-only frame flickering was made on nearly recent master
> > version with your patch applied.  (I must say resizing and fullscreen
> > transition looks awesome now, thanks!)
> >
> > I used GTK port under X in the VirtualBox to test the issue with the
> > minibuffer-only frame resized more than once even if the text is not
> > changed.
>
> Ah, OK. I guess it probably is exclusive to NS then.
>
> The obvious solution IMO is to retain a copy of the old frame contents
> and draw them in after resizing, before we try calling redisplay().
>
> On the other hand, it would be nice to know why redisplay() isn't
> drawing anything...

inhibit-redisplay appears to be t when miniframes are asked to resize.
Could that be related? I tried letting it to nil and that didn't help.

It also happens that setting the resize to happen via run-with-timer
fixes the flicker:
https://github.com/muffinmad/emacs-mini-frame/pull/32/files#diff-8289c4c5300044ca6d7f9f6f60067a1b5e0d61b6ad0b58720a7c694662ea13abR207

Unfortunately, that prevents resizing when displaying a prompt like
`yes-or-no-p`.

The other different thing about the minibuffer resizing is it all
happens within `read-from-minibuffer`



Reply | Threaded
Open this post in threaded view
|

bug#46155: [PATCH v2] Fix flicker when resizing NS frame programmatically (bug#46155)

Alan Third
In reply to this post by Aaron Jensen
; 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 is 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 1b2328628e..ab898184f5 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -7339,6 +7339,8 @@ - (void)viewDidResize:(NSNotification *)notification
 
       [surface release];
       surface = nil;
+
+      [self setNeedsDisplay:YES];
     }
 #endif
 
@@ -7510,6 +7512,16 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f
   [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
@@ -8452,6 +8464,34 @@ - (void)copyRect:(NSRect)srcRect to:(NSRect)dstRect
 }
 
 
+#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
 {
@@ -8469,6 +8509,13 @@ - (void)updateLayer
 {
   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.29.2


--
Alan Third



Reply | Threaded
Open this post in threaded view
|

bug#46155: [PATCH v2] Fix flicker when resizing NS frame programmatically (bug#46155)

Aaron Jensen
On Thu, Feb 11, 2021 at 4:16 PM Alan Third <[hidden email]> wrote:
> ...

Awesome, this works well for me on first try. Thank you. I'll use it
for a while and report back.

Aaron



Reply | Threaded
Open this post in threaded view
|

bug#46155: [PATCH v2] Fix flicker when resizing NS frame programmatically (bug#46155)

Alan Third
On Thu, Feb 11, 2021 at 10:06:33PM -0600, Aaron Jensen wrote:
> On Thu, Feb 11, 2021 at 4:16 PM Alan Third <[hidden email]> wrote:
> > ...
>
> Awesome, this works well for me on first try. Thank you. I'll use it
> for a while and report back.

I've pushed this change to master. If we see any problems (I've not
yet) we can reopen this bug report and revert the commit.
--
Alan Third