[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