Steve Lhomme pushed to branch master at VideoLAN / VLC
Commits: 643e452d by Claudio Cambra at 2026-06-10T07:25:40+00:00 macosx: Remove unused setupTableViews Signed-off-by: Claudio Cambra <[email protected]> - - - - - ffbb976b by Claudio Cambra at 2026-06-10T07:25:40+00:00 macosx: More strictly verify expected view data source state Signed-off-by: Claudio Cambra <[email protected]> - - - - - fce3a137 by Claudio Cambra at 2026-06-10T07:25:40+00:00 macosx: Verify the data source supports connect/disconnect Signed-off-by: Claudio Cambra <[email protected]> - - - - - da183ffe by Claudio Cambra at 2026-06-10T07:25:40+00:00 macosx: Set up table and collection views in expected order in audio view controller Signed-off-by: Claudio Cambra <[email protected]> - - - - - d09cc51f by Claudio Cambra at 2026-06-10T07:25:40+00:00 macosx: Configure content views immediately on property set in audio data source Signed-off-by: Claudio Cambra <[email protected]> - - - - - 02220ef1 by Claudio Cambra at 2026-06-10T07:25:40+00:00 macosx: Fix race crashing in audio views when media items are deleted Signed-off-by: Claudio Cambra <[email protected]> - - - - - 8 changed files: - modules/gui/macosx/library/VLCLibraryAbstractMediaLibrarySegmentViewController.m - modules/gui/macosx/library/audio-library/VLCLibraryAudioDataSource.h - modules/gui/macosx/library/audio-library/VLCLibraryAudioDataSource.m - modules/gui/macosx/library/audio-library/VLCLibraryAudioGroupDataSource.h - modules/gui/macosx/library/audio-library/VLCLibraryAudioGroupDataSource.m - modules/gui/macosx/library/audio-library/VLCLibraryAudioViewController.m - modules/gui/macosx/library/favorites-library/VLCLibraryFavoritesDataSource.m - modules/gui/macosx/library/video-library/VLCLibraryVideoDataSource.m Changes: ===================================== modules/gui/macosx/library/VLCLibraryAbstractMediaLibrarySegmentViewController.m ===================================== @@ -40,13 +40,19 @@ - (void)connect { - [self.currentDataSource connect]; + id<VLCLibraryDataSource> const dataSource = self.currentDataSource; + if ([dataSource respondsToSelector:@selector(connect)]) { + [dataSource connect]; + } _connected = YES; } - (void)disconnect { - [self.currentDataSource disconnect]; + id<VLCLibraryDataSource> const dataSource = self.currentDataSource; + if ([dataSource respondsToSelector:@selector(disconnect)]) { + [dataSource disconnect]; + } _connected = NO; } ===================================== modules/gui/macosx/library/audio-library/VLCLibraryAudioDataSource.h ===================================== @@ -66,11 +66,11 @@ extern NSString * const VLCLibraryAudioDataSourceDisplayedCollectionChangedNotif @interface VLCLibraryAudioDataSource : NSObject <VLCLibraryTableViewDataSource, VLCLibraryCollectionViewDataSource, iCarouselDataSource> @property (readwrite, weak) VLCLibraryModel *libraryModel; -@property (readwrite, weak) NSTableView *collectionSelectionTableView; -@property (readwrite, weak) NSTableView *songsTableView; -@property (readwrite, weak) NSCollectionView *collectionView; -@property (readwrite, weak) iCarousel *carouselView; -@property (readwrite, weak) NSTableView *gridModeListTableView; +@property (readwrite, weak, nonatomic) NSTableView *collectionSelectionTableView; +@property (readwrite, weak, nonatomic) NSTableView *songsTableView; +@property (readwrite, weak, nonatomic) NSCollectionView *collectionView; +@property (readwrite, weak, nonatomic) iCarousel *carouselView; +@property (readwrite, weak, nonatomic) NSTableView *gridModeListTableView; @property (readwrite, weak, nullable) id<VLCLibraryGroupHeaderDelegate> headerDelegate; @property (nonatomic, readwrite, assign) VLCAudioLibrarySegment audioLibrarySegment; ===================================== modules/gui/macosx/library/audio-library/VLCLibraryAudioDataSource.m ===================================== @@ -88,6 +88,40 @@ NSString * const VLCLibraryAudioDataSourceDisplayedCollectionChangedNotification @synthesize currentParentType = _currentParentType; +- (void)setCollectionView:(NSCollectionView *)collectionView +{ + _collectionView = collectionView; + if (_collectionView != nil) { + [VLCLibraryAudioDataSource setupCollectionView:_collectionView]; + } +} + +- (void)setSongsTableView:(NSTableView *)songsTableView +{ + _songsTableView = songsTableView; + if (_songsTableView != nil) { + [self setupSongsTableView]; + } +} + +- (void)setCollectionSelectionTableView:(NSTableView *)collectionSelectionTableView +{ + _collectionSelectionTableView = collectionSelectionTableView; + if (_collectionSelectionTableView != nil) { + _collectionSelectionTableView.target = self; + _collectionSelectionTableView.doubleAction = @selector(collectionSelectionDoubleClickAction:); + } +} + +- (void)setGridModeListTableView:(NSTableView *)gridModeListTableView +{ + _gridModeListTableView = gridModeListTableView; + if (_gridModeListTableView != nil) { + _gridModeListTableView.target = self; + _gridModeListTableView.doubleAction = @selector(groupSelectionDoubleClickAction:); + } +} + - (instancetype)init { self = [super init]; @@ -329,8 +363,6 @@ NSString * const VLCLibraryAudioDataSourceDisplayedCollectionChangedNotification - (void)setup { - [VLCLibraryAudioDataSource setupCollectionView:self.collectionView]; - [self setupTableViews]; // Force setAudioLibrarySegment to do something always on first try _audioLibrarySegment = VLCAudioLibraryUnknownSegment; [self connect]; @@ -413,6 +445,8 @@ NSString * const VLCLibraryAudioDataSourceDisplayedCollectionChangedNotification + (void)setupCollectionView:(NSCollectionView *)collectionView { + NSAssert(collectionView != nil, @"Collection view must not be nil"); + [collectionView registerClass:[VLCLibraryCollectionViewItem class] forItemWithIdentifier:VLCLibraryCellIdentifier]; NSNib * const albumSupplementaryDetailView = @@ -428,19 +462,10 @@ NSString * const VLCLibraryAudioDataSourceDisplayedCollectionChangedNotification withIdentifier:VLCLibraryCollectionViewMediaItemSupplementaryDetailViewIdentifier]; } -- (void)setupTableViews -{ - self.collectionSelectionTableView.target = self; - self.collectionSelectionTableView.doubleAction = @selector(collectionSelectionDoubleClickAction:); - - self.gridModeListTableView.target = self; - self.gridModeListTableView.doubleAction = @selector(groupSelectionDoubleClickAction:); - - [self setupSongsTableView]; -} - - (void)setupSongsTableView { + NSAssert(self.songsTableView != nil, @"Songs table view must not be nil"); + self.songsTableView.target = self; self.songsTableView.doubleAction = @selector(songDoubleClickAction:); @@ -555,21 +580,20 @@ NSString * const VLCLibraryAudioDataSourceDisplayedCollectionChangedNotification self->_displayedCollectionUpdating = NO; [self resetLayoutsForOperation:^{ - if (self.collectionView.dataSource == self) { - [self.collectionView reloadData]; - } - if (self.gridModeListTableView.dataSource == self) { - [self.gridModeListTableView reloadData]; - } - if (self.collectionSelectionTableView.dataSource == self) { - [self.collectionSelectionTableView reloadData]; - } - if (self.songsTableView.dataSource == self) { - [self.songsTableView reloadData]; - } - if (self.carouselView.dataSource == self) { - [self.carouselView reloadData]; - } + NSAssert(self.collectionView == nil || self.collectionView.dataSource == self, @"Cannot reload a collection view with a different data source"); + [self.collectionView reloadData]; + + NSAssert(self.gridModeListTableView == nil || self.gridModeListTableView.dataSource == self, @"Cannot reload a table view with a different data source"); + [self.gridModeListTableView reloadData]; + + NSAssert(self.collectionSelectionTableView == nil || self.collectionSelectionTableView.dataSource == self, @"Cannot reload a table view with a different data source"); + [self.collectionSelectionTableView reloadData]; + + NSAssert(self.songsTableView == nil || self.songsTableView.dataSource == self, @"Cannot reload a table view with a different data source"); + [self.songsTableView reloadData]; + + NSAssert(self.carouselView == nil || self.carouselView.dataSource == (id)self, @"Cannot reload a carousel view with a different data source"); + [self.carouselView reloadData]; }]; [NSNotificationCenter.defaultCenter postNotificationName:VLCLibraryAudioDataSourceDisplayedCollectionChangedNotification object:self]; @@ -618,17 +642,16 @@ NSString * const VLCLibraryAudioDataSourceDisplayedCollectionChangedNotification return; } - [self.displayedCollection removeObjectAtIndex:index]; - NSIndexPath * const indexPath = [NSIndexPath indexPathForItem:index inSection:0]; NSIndexSet * const rowIndexSet = [NSIndexSet indexSetWithIndex:index]; - [self.collectionView deleteItemsAtIndexPaths:[NSSet setWithObject:indexPath]]; - [self.songsTableView removeRowsAtIndexes:rowIndexSet withAnimation:NSTableViewAnimationSlideUp]; - - // Comment in reloadDataForMediaLibraryItem will be informative - - [self.carouselView reloadData]; + [self.collectionView performBatchUpdates:^{ + [self.displayedCollection removeObjectAtIndex:index]; + [self.collectionView deleteItemsAtIndexPaths:[NSSet setWithObject:indexPath]]; + } completionHandler:^(BOOL __unused finished) { + [self.songsTableView removeRowsAtIndexes:rowIndexSet withAnimation:NSTableViewAnimationSlideUp]; + [self.carouselView reloadData]; + }]; }]; } ===================================== modules/gui/macosx/library/audio-library/VLCLibraryAudioGroupDataSource.h ===================================== @@ -37,7 +37,7 @@ NS_ASSUME_NONNULL_BEGIN @property (readwrite, nonatomic, retain, nullable) id<VLCMediaLibraryAudioGroupProtocol> representedAudioGroup; @property (readwrite, atomic, retain) NSArray <NSTableView *> *tableViews; -@property (readwrite, atomic, retain) NSArray <NSCollectionView *> *collectionViews; +@property (readwrite, atomic, retain) NSCollectionView *collectionView; + (void)setupCollectionView:(NSCollectionView *)collectionView; ===================================== modules/gui/macosx/library/audio-library/VLCLibraryAudioGroupDataSource.m ===================================== @@ -56,6 +56,8 @@ + (void)setupCollectionView:(NSCollectionView *)collectionView { + NSAssert(collectionView != nil, @"Collection view must not be nil"); + [collectionView registerClass:VLCLibraryHeaderView.class forSupplementaryViewOfKind:NSCollectionElementKindSectionHeader withIdentifier:VLCLibraryHeaderViewIdentifier]; @@ -87,7 +89,7 @@ } if ([keyPath isEqualToString:@"collectionViews"]) { - [self reloadCollectionViews]; + [self reloadCollectionView]; } else if ([keyPath isEqualToString:@"tableViews"]) { [self reloadTableViews]; } @@ -157,10 +159,12 @@ NSIndexSet * const columnIndexSet = [NSIndexSet indexSetWithIndex:0]; NSSet * const indexPaths = [NSSet setWithObject:[NSIndexPath indexPathForItem:row inSection:0]]; - [self performActionOnTableViews:^(NSTableView * const tableView){ - [tableView reloadDataForRowIndexes:indexSet columnIndexes:columnIndexSet]; - } onCollectionViews:^(NSCollectionView * const collectionView){ - [collectionView reloadItemsAtIndexPaths:indexPaths]; + [self.collectionView performBatchUpdates:^{ + [self.collectionView reloadItemsAtIndexPaths:indexPaths]; + } completionHandler:^(BOOL __unused finished) { + [self performActionOnTableViews:^(NSTableView * const tableView){ + [tableView reloadDataForRowIndexes:indexSet columnIndexes:columnIndexSet]; + }]; }]; } @@ -183,19 +187,14 @@ } - (void)performActionOnTableViews:(void (^)(NSTableView *))tableViewAction - onCollectionViews:(void (^)(NSCollectionView *))collectionViewAction { - NSParameterAssert(tableViewAction != nil && collectionViewAction != nil); + NSParameterAssert(tableViewAction != nil); NSArray<NSTableView *> * const tableViews = self.tableViews; for (NSTableView * const tableView in tableViews) { + NSAssert(tableView.dataSource == self, @"Cannot perform action on a table view with a different data source"); tableViewAction(tableView); } - - NSArray<NSCollectionView *> * const collectionViews = self.collectionViews; - for (NSCollectionView * const collectionView in collectionViews) { - collectionViewAction(collectionView); - } } - (void)libraryModelAudioMediaItemsReset:(NSNotification *)notification @@ -240,15 +239,17 @@ NSMutableArray * const mutableCopy = [self.representedListOfAlbums mutableCopy]; [mutableCopy removeObjectAtIndex:row]; - self.representedListOfAlbums = [mutableCopy copy]; NSIndexSet * const indexSet = [NSIndexSet indexSetWithIndex:row]; NSSet * const indexPaths = [NSSet setWithObject:[NSIndexPath indexPathForItem:row inSection:0]]; - [self performActionOnTableViews:^(NSTableView * const tableView){ - [tableView removeRowsAtIndexes:indexSet withAnimation:NSTableViewAnimationSlideUp]; - } onCollectionViews:^(NSCollectionView * const collectionView){ - [collectionView deleteItemsAtIndexPaths:indexPaths]; + [self.collectionView performBatchUpdates:^{ + self.representedListOfAlbums = [mutableCopy copy]; + [self.collectionView deleteItemsAtIndexPaths:indexPaths]; + } completionHandler:^(BOOL __unused finished) { + [self performActionOnTableViews:^(NSTableView * const tableView){ + [tableView removeRowsAtIndexes:indexSet withAnimation:NSTableViewAnimationSlideUp]; + }]; }]; } @@ -256,31 +257,27 @@ { NSArray<NSTableView *> * const tableViews = self.tableViews; for (NSTableView * const tableView in tableViews) { - if (tableView.dataSource == self) { - [tableView reloadData]; - } + NSAssert(tableView == nil || tableView.dataSource == self, @"Cannot perform action on a table view with a different data source"); + [tableView reloadData]; } } -- (void)reloadCollectionViews +- (void)reloadCollectionView { - NSArray<NSCollectionView *> * const collectionViews = self.collectionViews; - for (NSCollectionView * const collectionView in collectionViews) { - if (collectionView.dataSource != self) { - continue; - } - NSCollectionViewLayout * const collectionViewLayout = collectionView.collectionViewLayout; - if ([collectionViewLayout isKindOfClass:VLCLibraryCollectionViewFlowLayout.class]) { - [(VLCLibraryCollectionViewFlowLayout *)collectionViewLayout resetLayout]; - } - [collectionView reloadData]; + NSCollectionView * const collectionView = self.collectionView; + NSAssert(collectionView == nil || collectionView.dataSource == self, @"Cannot perform action on a collection view with a different data source"); + + NSCollectionViewLayout * const collectionViewLayout = collectionView.collectionViewLayout; + if ([collectionViewLayout isKindOfClass:VLCLibraryCollectionViewFlowLayout.class]) { + [(VLCLibraryCollectionViewFlowLayout *)collectionViewLayout resetLayout]; } + [collectionView reloadData]; } - (void)reloadData { [self reloadTableViews]; - [self reloadCollectionViews]; + [self reloadCollectionView]; } - (void)updateRepresentedListOfAlbums ===================================== modules/gui/macosx/library/audio-library/VLCLibraryAudioViewController.m ===================================== @@ -156,21 +156,16 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi { _audioDataSource = [[VLCLibraryAudioDataSource alloc] init]; _audioDataSource.libraryModel = VLCMain.sharedInstance.libraryController.libraryModel; - _audioDataSource.collectionSelectionTableView = _audioCollectionSelectionTableView; - _audioDataSource.songsTableView = _audioSongTableView; - _audioDataSource.collectionView = _audioLibraryCollectionView; - _audioDataSource.gridModeListTableView = _audioLibraryGridModeSplitViewListTableView; _audioDataSource.headerDelegate = self; [_audioDataSource setup]; _audioGroupDataSource = [[VLCLibraryAudioGroupDataSource alloc] init]; - _audioGroupDataSource.tableViews = @[_audioGroupSelectionTableView]; - _audioGroupDataSource.collectionViews = @[_audioLibraryGridModeSplitViewListSelectionCollectionView]; _audioDataSource.audioGroupDataSource = _audioGroupDataSource; } - (void)setupAudioCollectionView { + _audioDataSource.collectionView = _audioLibraryCollectionView; _audioLibraryCollectionView.dataSource = _audioDataSource; _audioLibraryCollectionView.delegate = _audioLibraryCollectionViewDelegate; @@ -184,6 +179,7 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi { _audioLibrarySplitView.delegate = _splitViewDelegate; + _audioDataSource.collectionSelectionTableView = _audioCollectionSelectionTableView; _audioCollectionSelectionTableView.dataSource = _audioDataSource; _audioCollectionSelectionTableView.delegate = _audioLibraryTableViewDelegate; @@ -192,13 +188,22 @@ NSString *VLCLibraryPlaceholderAudioViewIdentifier = @"VLCLibraryPlaceholderAudi _audioGroupSelectionTableView.tableColumns.firstObject.headerCell = [VLCLibraryHeaderCell new]; _audioGroupSelectionTableView.dataSource = _audioGroupDataSource; + _audioGroupDataSource.tableViews = @[_audioGroupSelectionTableView]; _audioGroupSelectionTableView.delegate = _audioGroupLibraryTableViewDelegate; if(@available(macOS 11.0, *)) { _audioGroupSelectionTableView.style = NSTableViewStyleFullWidth; } + _audioDataSource.songsTableView = _audioSongTableView; _audioSongTableView.dataSource = _audioDataSource; + + _audioDataSource.gridModeListTableView = _audioLibraryGridModeSplitViewListTableView; + _audioLibraryGridModeSplitViewListTableView.dataSource = _audioDataSource; + + _audioLibraryGridModeSplitViewListSelectionCollectionView.dataSource = _audioGroupDataSource; + _audioGroupDataSource.collectionView = _audioLibraryGridModeSplitViewListSelectionCollectionView; + _audioSongTableView.delegate = _audioLibraryTableViewDelegate; [_audioDataSource applySelectionForTableView:_audioCollectionSelectionTableView]; ===================================== modules/gui/macosx/library/favorites-library/VLCLibraryFavoritesDataSource.m ===================================== @@ -291,18 +291,17 @@ NSString * const VLCLibraryFavoritesDataSourceDisplayedCollectionChangedNotifica [self updateHeaderForMasterSelection]; const NSInteger selectedRow = self.masterTableView.selectedRow; - if (self.masterTableView.dataSource == self) { - [self.masterTableView reloadData]; - if (selectedRow != -1 && selectedRow < [self.masterTableView numberOfRows]) { - [self.masterTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow] byExtendingSelection:NO]; - } - } - if (self.detailTableView.dataSource == self) { - [self.detailTableView reloadData]; - } - if (self.collectionView.dataSource == self) { - [self.collectionView reloadData]; + NSAssert(self.masterTableView == nil || self.masterTableView.dataSource == self, @"Cannot reload a table view with a different data source"); + [self.masterTableView reloadData]; + if (selectedRow != -1 && selectedRow < [self.masterTableView numberOfRows]) { + [self.masterTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:selectedRow] byExtendingSelection:NO]; } + + NSAssert(self.detailTableView == nil || self.detailTableView.dataSource == self, @"Cannot reload a table view with a different data source"); + [self.detailTableView reloadData]; + + NSAssert(self.collectionView == nil || self.collectionView.dataSource == self, @"Cannot reload a collection view with a different data source"); + [self.collectionView reloadData]; [NSNotificationCenter.defaultCenter postNotificationName:VLCLibraryFavoritesDataSourceDisplayedCollectionChangedNotification object:self ===================================== modules/gui/macosx/library/video-library/VLCLibraryVideoDataSource.m ===================================== @@ -251,12 +251,12 @@ NSString * const VLCLibraryVideoDataSourceDisplayedCollectionChangedNotification [self rebuildFlattenedRows]; - if (self.tableView.dataSource == self) { - [self.tableView reloadData]; - } - if (self.collectionView.dataSource == self) { - [self.collectionView reloadData]; - } + NSAssert(self.tableView == nil || self.tableView.dataSource == self, @"Cannot reload a table view with a different data source"); + [self.tableView reloadData]; + + NSAssert(self.collectionView == nil || self.collectionView.dataSource == self, @"Cannot reload a collection view with a different data source"); + [self.collectionView reloadData]; + [NSNotificationCenter.defaultCenter postNotificationName:VLCLibraryVideoDataSourceDisplayedCollectionChangedNotification object:self userInfo:nil]; @@ -303,7 +303,8 @@ NSString * const VLCLibraryVideoDataSourceDisplayedCollectionChangedNotification completionHandler(rowIndexSet); // Targeted table view update using flattened row index - if (flatRowIndex != NSNotFound && self.tableView.dataSource == self) { + if (flatRowIndex != NSNotFound) { + NSAssert(self.tableView.dataSource == self, @"Cannot reload a table view with a different data source"); [self.tableView reloadDataForRowIndexes:[NSIndexSet indexSetWithIndex:flatRowIndex] columnIndexes:[NSIndexSet indexSetWithIndex:0]]; } @@ -324,12 +325,11 @@ NSString * const VLCLibraryVideoDataSourceDisplayedCollectionChangedNotification } completionHandler:^(NSIndexSet * const rowIndexSet) { - if (self.collectionView.dataSource == self) { - const NSInteger section = [self videoGroupToRow:group]; - NSSet<NSIndexPath *> * const indexPathSet = - [rowIndexSet indexPathSetWithSection:section]; - [self.collectionView reloadItemsAtIndexPaths:indexPathSet]; - } + NSAssert(self.collectionView.dataSource == self, @"Cannot reload a collection view with a different data source"); + const NSInteger section = [self videoGroupToRow:group]; + NSSet<NSIndexPath *> * const indexPathSet = + [rowIndexSet indexPathSetWithSection:section]; + [self.collectionView reloadItemsAtIndexPaths:indexPathSet]; }]; } @@ -344,12 +344,11 @@ NSString * const VLCLibraryVideoDataSourceDisplayedCollectionChangedNotification } completionHandler:^(NSIndexSet * const rowIndexSet) { - if (self.collectionView.dataSource == self) { - const NSInteger section = [self videoGroupToRow:group]; - NSSet<NSIndexPath *> * const indexPathSet = - [rowIndexSet indexPathSetWithSection:section]; - [self.collectionView deleteItemsAtIndexPaths:indexPathSet]; - } + NSAssert(self.collectionView.dataSource == self, @"Cannot reload a collection view with a different data source"); + const NSInteger section = [self videoGroupToRow:group]; + NSSet<NSIndexPath *> * const indexPathSet = + [rowIndexSet indexPathSetWithSection:section]; + [self.collectionView deleteItemsAtIndexPaths:indexPathSet]; }]; } View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/8635abbe1ba1af4452c308643c5fb5fee7d60ebd...02220ef10c24166f3ebddacdb7fb3c6c96fcc155 -- View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/8635abbe1ba1af4452c308643c5fb5fee7d60ebd...02220ef10c24166f3ebddacdb7fb3c6c96fcc155 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
_______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
