Ken Thomases : winemac: Set windows to transparent until they have content to draw, to reduce flicker.

Alexandre Julliard julliard at winehq.org
Fri Sep 2 11:41:44 CDT 2016


Module: wine
Branch: master
Commit: fdd7db05931df0a9d1318108ed206cb50e311d1a
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=fdd7db05931df0a9d1318108ed206cb50e311d1a

Author: Ken Thomases <ken at codeweavers.com>
Date:   Fri Sep  2 03:08:01 2016 -0500

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 <ken at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 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 d52a9d2..f037b08 100644
--- a/dlls/winemac.drv/cocoa_window.h
+++ b/dlls/winemac.drv/cocoa_window.h
@@ -34,6 +34,7 @@
     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 c6e0709..8e8ac9f 100644
--- a/dlls/winemac.drv/cocoa_window.m
+++ b/dlls/winemac.drv/cocoa_window.m
@@ -317,6 +317,7 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
 @property (readwrite, nonatomic) BOOL disabled;
 @property (readwrite, nonatomic) BOOL noActivate;
 @property (readwrite, nonatomic) BOOL floating;
+ at property (readwrite, nonatomic) BOOL drawnSinceShown;
 @property (readwrite, getter=isFakingClose, nonatomic) BOOL fakingClose;
 @property (retain, nonatomic) NSWindow* latentParentWindow;
 
@@ -346,6 +347,8 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
     - (BOOL) becameEligibleParentOrChild;
     - (void) becameIneligibleChild;
 
+    - (void) windowDidDrawContent;
+
 @end
 
 
@@ -383,7 +386,7 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
         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 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
                         CGImageRelease(image);
                     }
                 }
+
+                [window windowDidDrawContent];
             }
 
             pthread_mutex_unlock(window.surface_mutex);
@@ -449,7 +454,7 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
         // 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 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
     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 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
         [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 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
         {
             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 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
                     // 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 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
                 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 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
         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 @@ static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTi
         [self setAutodisplay:NO];
     }
 
+    - (void) windowDidDrawContent
+    {
+        if (!drawnSinceShown)
+        {
+            drawnSinceShown = YES;
+            dispatch_async(dispatch_get_main_queue(), ^{
+                [self checkTransparency];
+            });
+        }
+    }
+
     - (NSArray*) childWineWindows
     {
         NSArray* childWindows = self.childWindows;




More information about the wine-cvs mailing list