Subject: bug#32932: 27.0.50; render bugs on macOS Mojave

From: Alan Third <[email-masked]>
Date: Thu, 8 Nov 2018 15:21:17 +0000

I’ve finally worked out what’s happening.

We have an NSWindow, that is opaque, and drawn over that is the NSView
we use to display Emacs, which is not opaque.

When we ask for a display Cocoa/GNUstep back up to the first opaque
ancestor, in this case the NSWindow, and draws it, then moves up to
the NSView and draws it.

This means the first thing it does is draw the blank NSWindow
contents, which is why anything that is marked as dirty gets blanked
out.

Setting the NSView to be opaque solves the blanking issue, but
ns_clear_area and friends don’t do anything as they’re not called
during expose_frame.

We could work around that by queueing up the clear requests and
calling them in drawRect, however if the user set the background to be
transparent then I think we would immediately run into the exact same
issue as we have now where the first opaque ancestor (the WM root)
will overdraw when we’re not expecting it.

I think the root of this problem is that the NS toolkits expect
drawRect to ALWAYS be able to redraw the contents of the view at any
time so they have no issue with modifying it. Emacs seems to expect
the contents of the window to remain intact in many of these
circumstances.

We could try and force Emacs to bend to the NS way by forcing
expose_frame and friends to draw WHENEVER REQUESTED, but I don’t know
how practical that is, and it would mean making changes in xdisp.c
which may be unwelcome.

This leaves us with the solution Yamamoto Mitsuharu has used in the
Mac port of drawing to an offscreen buffer and leaving drawRect to
basically just copy that buffer to the screen.

It doesn’t feel like as neat a solution, but it should, more or less,
Just Work. Although I currently have no idea how to do it.

-- 
Alan Third