[vlc-commits] [Git][videolan/vlc][master] macosx: Fix crashing when switching library segments during detail view animation

Felix Paul Kühne (@fkuehne) gitlab at videolan.org
Mon Aug 10 15:17:21 UTC 2026



Felix Paul Kühne pushed to branch master at VideoLAN / VLC


Commits:
62f27a55 by Claudio Cambra at 2026-08-10T17:06:19+02:00
macosx: Fix crashing when switching library segments during detail view animation

Signed-off-by: Claudio Cambra <developer at claudiocambra.com>

- - - - -


1 changed file:

- modules/gui/macosx/library/VLCLibraryCollectionViewFlowLayout.m


Changes:

=====================================
modules/gui/macosx/library/VLCLibraryCollectionViewFlowLayout.m
=====================================
@@ -53,13 +53,6 @@ typedef NS_ENUM(NSUInteger, VLCExpandAnimationType) {
     VLCExpandAnimationTypeHorizontalLarge,
 };
 
-static CVReturn detailViewAnimationCallback(CVDisplayLinkRef displayLink,
-                                            const CVTimeStamp *inNow,
-                                            const CVTimeStamp *inOutputTime,
-                                            CVOptionFlags flagsIn,
-                                            CVOptionFlags *flagsOut,
-                                            void *displayLinkContext);
-
 #pragma mark - VLCLibraryCollectionViewFlowLayout
 @interface VLCLibraryCollectionViewFlowLayout ()
 {
@@ -75,6 +68,7 @@ static CVReturn detailViewAnimationCallback(CVDisplayLinkRef displayLink,
 
     BOOL _invalidateAll;
     CGFloat _previousWidth;
+    NSUInteger _displayLinkGeneration;
 }
 
 @property (nonatomic, readwrite) BOOL detailViewIsAnimating;
@@ -86,6 +80,11 @@ static CVReturn detailViewAnimationCallback(CVDisplayLinkRef displayLink,
 
 @implementation VLCLibraryCollectionViewFlowLayout
 
+- (void)dealloc
+{
+    [self releaseDisplayLink];
+}
+
 + (instancetype)standardLayout
 {
     const CGFloat collectionItemSpacing = VLCUIUnits.collectionViewItemSpacing;
@@ -461,64 +460,73 @@ static CVReturn detailViewAnimationCallback(CVDisplayLinkRef displayLink,
         return;
     }
 
-    CVDisplayLinkSetOutputCallback(_displayLinkRef, detailViewAnimationCallback, (__bridge void *)self);
-    CVDisplayLinkStart(_displayLinkRef);
-}
+    const NSUInteger displayLinkGeneration = ++_displayLinkGeneration;
+    CVDisplayLinkRef const expectedDisplayLink = _displayLinkRef;
+    __weak VLCLibraryCollectionViewFlowLayout * const weakSelf = self;
+    const CVReturn handlerResult = CVDisplayLinkSetOutputHandler(_displayLinkRef, ^CVReturn(
+        CVDisplayLinkRef displayLink __unused,
+        const CVTimeStamp *inNow __unused,
+        const CVTimeStamp *inOutputTime __unused,
+        CVOptionFlags flagsIn __unused,
+        CVOptionFlags *flagsOut __unused) {
+        dispatch_async(dispatch_get_main_queue(), ^{
+            VLCLibraryCollectionViewFlowLayout * const strongSelf = weakSelf;
+            if (strongSelf == nil || strongSelf->_displayLinkGeneration != displayLinkGeneration ||
+                strongSelf->_displayLinkRef != expectedDisplayLink) {
+                return;
+            }
+            [strongSelf advanceDetailViewAnimation];
+        });
+        return kCVReturnSuccess;
+    });
 
-- (void)releaseDisplayLink
-{
-    if (_displayLinkRef == NULL ) {
-        return;
+    if (handlerResult != kCVReturnSuccess || CVDisplayLinkStart(_displayLinkRef) != kCVReturnSuccess) {
+        [self releaseDisplayLink];
+        _detailViewIsAnimating = NO;
     }
-
-    CVDisplayLinkStop(_displayLinkRef);
-    CVDisplayLinkRelease(_displayLinkRef);
-
-    _displayLinkRef = NULL;
 }
 
- at end
-
-static CVReturn detailViewAnimationCallback(
-                                            CVDisplayLinkRef displayLink __unused,
-                                            const CVTimeStamp *inNow __unused,
-                                            const CVTimeStamp *inOutputTime __unused,
-                                            CVOptionFlags flagsIn __unused,
-                                            CVOptionFlags *flagsOut __unused,
-                                            void *displayLinkContext)
+- (void)advanceDetailViewAnimation
 {
-    if (displayLinkContext == nil) {
-        return kCVReturnError;
-    }
-
-    VLCLibraryCollectionViewFlowLayout *bridgedSelf = (__bridge VLCLibraryCollectionViewFlowLayout *)displayLinkContext;
     BOOL animationFinished = NO;
 
-    if(bridgedSelf.detailViewIsAnimating) {
-        if (bridgedSelf.animationIsCollapse) {
-            --bridgedSelf.animationIndex;
-            animationFinished = (bridgedSelf.animationIndex == kWrapAroundValue);
+    if (self.detailViewIsAnimating) {
+        if (self.animationIsCollapse) {
+            --self.animationIndex;
+            animationFinished = (self.animationIndex == kWrapAroundValue);
         } else {
-            ++bridgedSelf.animationIndex;
-            animationFinished = (bridgedSelf.animationIndex == kAnimationSteps);
+            ++self.animationIndex;
+            animationFinished = (self.animationIndex == kAnimationSteps);
         }
     }
 
-    if (bridgedSelf.detailViewIsAnimating == NO || animationFinished) {
-        bridgedSelf.detailViewIsAnimating = NO;
-        [bridgedSelf releaseDisplayLink];
+    if (self.detailViewIsAnimating == NO || animationFinished) {
+        self.detailViewIsAnimating = NO;
+        [self releaseDisplayLink];
 
-        if (bridgedSelf.animationIsCollapse) {
-            bridgedSelf.selectedIndexPath = nil;
-            bridgedSelf.animationIndex = 0;
+        if (self.animationIsCollapse) {
+            self.selectedIndexPath = nil;
+            self.animationIndex = 0;
         } else {
-            bridgedSelf.animationIndex = kAnimationSteps - 1;
+            self.animationIndex = kAnimationSteps - 1;
         }
     }
 
-    dispatch_async(dispatch_get_main_queue(), ^(void){
-        [bridgedSelf invalidateLayout];
-    });
+    [self invalidateLayout];
+}
+
+- (void)releaseDisplayLink
+{
+    if (_displayLinkRef == NULL ) {
+        return;
+    }
 
-    return kCVReturnSuccess;
+    CVDisplayLinkRef const displayLink = _displayLinkRef;
+    _displayLinkRef = NULL;
+    ++_displayLinkGeneration;
+
+    CVDisplayLinkStop(displayLink);
+    CVDisplayLinkRelease(displayLink);
 }
+
+ at end



View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/62f27a55c1a659a5f6f5020e8fdff0e1c834024c

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/62f27a55c1a659a5f6f5020e8fdff0e1c834024c
You're receiving this email because of your account on code.videolan.org. Manage all notifications: https://code.videolan.org/-/profile/notifications | Help: https://code.videolan.org/help




More information about the vlc-commits mailing list