diff --git a/dlls/winemac.drv/cocoa_window.h b/dlls/winemac.drv/cocoa_window.h index 5d581b2cf80..19e57789950 100644 --- a/dlls/winemac.drv/cocoa_window.h +++ b/dlls/winemac.drv/cocoa_window.h @@ -44,6 +44,7 @@ @interface WineWindow : NSPanel pthread_mutex_t* surface_mutex; CGDirectDisplayID _lastDisplayID; + NSTimeInterval _lastDisplayTime; NSBezierPath* shape; NSData* shapeData; diff --git a/dlls/winemac.drv/cocoa_window.m b/dlls/winemac.drv/cocoa_window.m index 49afd18e080..15fa16f0153 100644 --- a/dlls/winemac.drv/cocoa_window.m +++ b/dlls/winemac.drv/cocoa_window.m @@ -161,6 +161,9 @@ @interface WineDisplayLink : NSObject CGDirectDisplayID _displayID; CVDisplayLinkRef _link; NSMutableSet* _windows; + + NSTimeInterval _actualRefreshPeriod; + NSTimeInterval _nominalRefreshPeriod; } - (id) initWithDisplayID:(CGDirectDisplayID)displayID; @@ -168,6 +171,10 @@ - (id) initWithDisplayID:(CGDirectDisplayID)displayID; - (void) addWindow:(WineWindow*)window; - (void) removeWindow:(WineWindow*)window; + - (NSTimeInterval) refreshPeriod; + + - (void) start; + @end @implementation WineDisplayLink @@ -234,12 +241,41 @@ - (void) fire windows = [_windows copy]; } dispatch_async(dispatch_get_main_queue(), ^{ + BOOL anyDisplayed = FALSE; for (WineWindow* window in windows) - [window displayIfNeeded]; + { + if ([window viewsNeedDisplay]) + { + [window displayIfNeeded]; + anyDisplayed = YES; + } + } + if (!anyDisplayed) + CVDisplayLinkStop(_link); }); [windows release]; } + - (NSTimeInterval) refreshPeriod + { + if (_actualRefreshPeriod || (_actualRefreshPeriod = CVDisplayLinkGetActualOutputVideoRefreshPeriod(_link))) + return _actualRefreshPeriod; + + if (_nominalRefreshPeriod) + return _nominalRefreshPeriod; + + CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(_link); + if (time.flags & kCVTimeIsIndefinite) + return 1.0 / 60.0; + _nominalRefreshPeriod = time.timeValue / (double)time.timeScale; + return _nominalRefreshPeriod; + } + + - (void) start + { + CVDisplayLinkStart(_link); + } + static CVReturn WineDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow, const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) { WineDisplayLink* link = displayLinkContext; @@ -690,6 +726,7 @@ + (WineWindow*) createWindowWithFeatures:(const struct macdrv_window_features*)w window->savedContentMinSize = NSZeroSize; window->savedContentMaxSize = NSMakeSize(FLT_MAX, FLT_MAX); window->resizable = wf->resizable; + window->_lastDisplayTime = [[NSDate distantPast] timeIntervalSinceReferenceDate]; [window registerForDraggedTypes:[NSArray arrayWithObjects:(NSString*)kUTTypeData, (NSString*)kUTTypeContent, @@ -1663,21 +1700,8 @@ - (void) endWindowDragging } } - - (void) checkWineDisplayLink + - (NSMutableDictionary*) displayIDToDisplayLinkMap { - NSScreen* screen = self.screen; - if (![self isVisible] || ![self isOnActiveSpace] || [self isMiniaturized] || [self isEmptyShaped]) - screen = nil; -#if defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 - if ([self respondsToSelector:@selector(occlusionState)] && !(self.occlusionState & NSWindowOcclusionStateVisible)) - screen = nil; -#endif - - NSNumber* displayIDNumber = [screen.deviceDescription objectForKey:@"NSScreenNumber"]; - CGDirectDisplayID displayID = [displayIDNumber unsignedIntValue]; - if (displayID == _lastDisplayID) - return; - static NSMutableDictionary* displayIDToDisplayLinkMap; if (!displayIDToDisplayLinkMap) { @@ -1693,6 +1717,34 @@ - (void) checkWineDisplayLink [displayIDToDisplayLinkMap removeObjectsForKeys:[badDisplayIDs allObjects]]; }]; } + return displayIDToDisplayLinkMap; + } + + - (WineDisplayLink*) wineDisplayLink + { + if (!_lastDisplayID) + return nil; + + NSMutableDictionary* displayIDToDisplayLinkMap = [self displayIDToDisplayLinkMap]; + return [displayIDToDisplayLinkMap objectForKey:[NSNumber numberWithUnsignedInt:_lastDisplayID]]; + } + + - (void) checkWineDisplayLink + { + NSScreen* screen = self.screen; + if (![self isVisible] || ![self isOnActiveSpace] || [self isMiniaturized] || [self isEmptyShaped]) + screen = nil; +#if defined(MAC_OS_X_VERSION_10_9) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_9 + if ([self respondsToSelector:@selector(occlusionState)] && !(self.occlusionState & NSWindowOcclusionStateVisible)) + screen = nil; +#endif + + NSNumber* displayIDNumber = [screen.deviceDescription objectForKey:@"NSScreenNumber"]; + CGDirectDisplayID displayID = [displayIDNumber unsignedIntValue]; + if (displayID == _lastDisplayID) + return; + + NSMutableDictionary* displayIDToDisplayLinkMap = [self displayIDToDisplayLinkMap]; if (_lastDisplayID) { @@ -2026,6 +2078,40 @@ - (void) toggleFullScreen:(id)sender [super toggleFullScreen:sender]; } + - (void) setViewsNeedDisplay:(BOOL)value + { + if (value && ![self viewsNeedDisplay]) + { + WineDisplayLink* link = [self wineDisplayLink]; + if (link) + { + NSTimeInterval now = [[NSProcessInfo processInfo] systemUptime]; + if (_lastDisplayTime + [link refreshPeriod] < now) + [self setAutodisplay:YES]; + else + { + [link start]; + _lastDisplayTime = now; + } + } + } + [super setViewsNeedDisplay:value]; + } + + - (void) display + { + _lastDisplayTime = [[NSProcessInfo processInfo] systemUptime]; + [super display]; + [self setAutodisplay:NO]; + } + + - (void) displayIfNeeded + { + _lastDisplayTime = [[NSProcessInfo processInfo] systemUptime]; + [super displayIfNeeded]; + [self setAutodisplay:NO]; + } + - (NSArray*) childWineWindows { NSArray* childWindows = self.childWindows;