From fdd7db05931df0a9d1318108ed206cb50e311d1a Mon Sep 17 00:00:00 2001 From: Ken Thomases Date: Fri, 2 Sep 2016 03:08:01 -0500 Subject: [PATCH] winemac: Set windows to transparent until they have content to draw, to reduce flicker. When a window is shown, it may not have drawn its content into the backing surface, yet. Cocoa will draw the window, starting with its standard light gray background and then the content view. However, the content view won't have anything to draw, yet, though, so the window background is not drawn over. A short while later, usually, the app will paint its content into the window backing surface and Cocoa will be told to redraw the window. This works, but the user can often see the flash of the window background color first. This is especially visible for windows with dark content. Part of the fix is to set the window background to transparent until the content view has actually drawn once since the window was shown. That's not sufficient on its own, though. We had disabled Cocoa's automatic display mechanism for windows and put display on a display-link timer. This meant that the window was not actually cleared to its transparent color. When the window was shown, the Window Server displayed a white backing buffer. It is the app process which should fill that backing buffer with clear color but, because we had disabled auto-display, that wasn't getting done at the same time the window was displayed. It was happening some time after. Again, the result was a visible flicker of white. So, we now temporarily re-enable auto-display just before showing a window. Signed-off-by: Ken Thomases Signed-off-by: Alexandre Julliard --- dlls/winemac.drv/cocoa_window.h | 1 + dlls/winemac.drv/cocoa_window.m | 31 ++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/dlls/winemac.drv/cocoa_window.h b/dlls/winemac.drv/cocoa_window.h index d52a9d2f8ec..f037b08a254 100644 --- a/dlls/winemac.drv/cocoa_window.h +++ b/dlls/winemac.drv/cocoa_window.h @@ -34,6 +34,7 @@ @interface WineWindow : NSPanel BOOL fullscreen; BOOL pendingMinimize; BOOL savedVisibleState; + BOOL drawnSinceShown; WineWindow* latentParentWindow; NSMutableArray* latentChildWindows; diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index c6e07091dd5..8e8ac9fc993 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -317,6 +317,7 @@ @interface WineWindow () @property (readwrite, nonatomic) BOOL disabled; @property (readwrite, nonatomic) BOOL noActivate; @property (readwrite, nonatomic) BOOL floating; +@property (readwrite, nonatomic) BOOL drawnSinceShown; @property (readwrite, getter=isFakingClose, nonatomic) BOOL fakingClose; @property (retain, nonatomic) NSWindow* latentParentWindow; @@ -346,6 +347,8 @@ - (void) updateForGLSubviews; - (BOOL) becameEligibleParentOrChild; - (void) becameIneligibleChild; + - (void) windowDidDrawContent; + @end @@ -383,7 +386,7 @@ - (void) drawRect:(NSRect)rect if ([window contentView] != self) return; - if (window.shapeChangedSinceLastDraw && window.shape && !window.colorKeyed && !window.usePerPixelAlpha) + if (window.drawnSinceShown && window.shapeChangedSinceLastDraw && window.shape && !window.colorKeyed && !window.usePerPixelAlpha) { [[NSColor clearColor] setFill]; NSRectFill(rect); @@ -441,6 +444,8 @@ - (void) drawRect:(NSRect)rect CGImageRelease(image); } } + + [window windowDidDrawContent]; } pthread_mutex_unlock(window.surface_mutex); @@ -449,7 +454,7 @@ - (void) drawRect:(NSRect)rect // If the window may be transparent, then we have to invalidate the // shadow every time we draw. Also, if this is the first time we've // drawn since changing from transparent to opaque. - if (window.colorKeyed || window.usePerPixelAlpha || window.shapeChangedSinceLastDraw) + if (window.drawnSinceShown && (window.colorKeyed || window.usePerPixelAlpha || window.shapeChangedSinceLastDraw)) { window.shapeChangedSinceLastDraw = FALSE; [window invalidateShadow]; @@ -794,6 +799,7 @@ @implementation WineWindow static WineWindow* causing_becomeKeyWindow; @synthesize disabled, noActivate, floating, fullscreen, fakingClose, latentParentWindow, hwnd, queue; + @synthesize drawnSinceShown; @synthesize surface, surface_mutex; @synthesize shape, shapeData, shapeChangedSinceLastDraw; @synthesize colorKeyed, colorKeyRed, colorKeyGreen, colorKeyBlue; @@ -831,7 +837,8 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w [window setAcceptsMouseMovedEvents:YES]; [window setColorSpace:[NSColorSpace genericRGBColorSpace]]; [window setDelegate:window]; - [window setAutodisplay:NO]; + [window setBackgroundColor:[NSColor clearColor]]; + [window setOpaque:NO]; window.hwnd = hwnd; window.queue = queue; window->savedContentMinSize = NSZeroSize; @@ -1191,6 +1198,8 @@ - (BOOL) addChildWineWindow:(WineWindow*)child assumeVisible:(BOOL)assumeVisible { if ([self level] > [child level]) [child setLevel:[self level]]; + if (![child isVisible]) + [child setAutodisplay:YES]; [self addChildWindow:child ordered:NSWindowAbove]; [child checkWineDisplayLink]; [latentChildWindows removeObjectIdenticalTo:child]; @@ -1455,6 +1464,7 @@ - (void) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next activate:(BOOL)a // Then the levels get fixed by -adjustWindowLevels. if ([self level] != [other level]) [self setLevel:[other level]]; + [self setAutodisplay:YES]; [self orderWindow:orderingMode relativeTo:[other windowNumber]]; [self checkWineDisplayLink]; @@ -1474,6 +1484,7 @@ - (void) orderBelow:(WineWindow*)prev orAbove:(WineWindow*)next activate:(BOOL)a next = [controller frontWineWindow]; if (next && [self level] < [next level]) [self setLevel:[next level]]; + [self setAutodisplay:YES]; [self orderFront:nil]; [self checkWineDisplayLink]; needAdjustWindowLevels = TRUE; @@ -1530,6 +1541,9 @@ - (void) doOrderOut else [self orderOut:nil]; [self checkWineDisplayLink]; + [self setBackgroundColor:[NSColor clearColor]]; + [self setOpaque:NO]; + drawnSinceShown = NO; savedVisibleState = FALSE; if (wasVisible && wasOnActiveSpace && fullscreen) [controller updateFullscreenWindows]; @@ -2266,6 +2280,17 @@ - (void) displayIfNeeded [self setAutodisplay:NO]; } + - (void) windowDidDrawContent + { + if (!drawnSinceShown) + { + drawnSinceShown = YES; + dispatch_async(dispatch_get_main_queue(), ^{ + [self checkTransparency]; + }); + } + } + - (NSArray*) childWineWindows { NSArray* childWindows = self.childWindows;