[vlc-commits] [Git][videolan/vlc][master] 3 commits: macosx/renderer-discovery: run callbacks on main-thread

Felix Paul Kühne (@fkuehne) gitlab at videolan.org
Thu May 28 14:03:37 UTC 2026



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


Commits:
9b4c8a5c by Felix Paul Kühne at 2026-05-28T15:51:49+02:00
macosx/renderer-discovery: run callbacks on main-thread

- - - - -
53b2153e by Felix Paul Kühne at 2026-05-28T15:51:49+02:00
macosx/renderer menu: fix missing init and move data handling to MT

- - - - -
dd296d71 by Felix Paul Kühne at 2026-05-28T15:51:49+02:00
macosx/renderer-discovery: zero delegate on dealloc

Fixes a crash when a discovery callback fires on the main thread
after the delegate has been deallocated. The assign property left
a dangling pointer; weak makes ARC zero it on dealloc.

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSXPCInterfaceProxy_NSOSPServiceExportedToHostProtocol removedRendererItem:from:]:
unrecognized selector sent to instance 0x7479c1cc0'
*** First throw call stack:
(
0   CoreFoundation                      0x000000018fb491c0 __exceptionPreprocess + 176
1   libobjc.A.dylib                     0x000000018f5d291c objc_exception_throw + 88
2   CoreFoundation                      0x000000018fc0a250 -[NSObject(NSObject) __retain_OA] + 0
3   CoreFoundation                      0x000000018fab9f38 ___forwarding___ + 1480
4   CoreFoundation                      0x000000018fab98b0 _CF_forwarding_prep_0 + 96
5   libmacosx_plugin.dylib              0x0000000108158598 __42-[VLCRendererDiscovery handleItemRemoved:]_block_invoke + 500
6   libdispatch.dylib                   0x000000018f862a28 _dispatch_call_block_and_release + 32

- - - - -


3 changed files:

- modules/gui/macosx/menus/renderers/VLCRendererDiscovery.h
- modules/gui/macosx/menus/renderers/VLCRendererDiscovery.m
- modules/gui/macosx/menus/renderers/VLCRendererMenuController.m


Changes:

=====================================
modules/gui/macosx/menus/renderers/VLCRendererDiscovery.h
=====================================
@@ -39,7 +39,7 @@ extern NSString * const VLCRendererRemovedNotification;
 /**
  The delegate that is called when a \c VLCRendererItem is added or deleted
  */
- at property (assign) id<VLCRendererDiscoveryDelegate> delegate;
+ at property (weak) id<VLCRendererDiscoveryDelegate> delegate;
 
 /**
  The name of the renderer discovery module


=====================================
modules/gui/macosx/menus/renderers/VLCRendererDiscovery.m
=====================================
@@ -38,7 +38,7 @@ NSString * const VLCRendererRemovedNotification = @"VLCRendererRemovedNotificati
 }
 
 - (void)handleItemAdded:(vlc_renderer_item_t *)item;
-- (void)handleItemRemoved:(const vlc_renderer_item_t *)item;
+- (void)handleItemRemoved:(vlc_renderer_item_t *)item;
 
 @end
 
@@ -120,32 +120,38 @@ static void renderer_event_item_removed(vlc_renderer_discovery_t *rd,
 - (void)handleItemAdded:(vlc_renderer_item_t *)base_item
 {
     VLCRendererItem *item = [[VLCRendererItem alloc] initWithRendererItem:base_item];
-    [_rendererItems addObject:item];
-    if (_delegate)
-        [_delegate addedRendererItem:item from:self];
-
-    [NSNotificationCenter.defaultCenter postNotificationName:VLCRendererAddedNotification
-                                                      object:item];
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [self->_rendererItems addObject:item];
+        if (self->_delegate)
+            [self->_delegate addedRendererItem:item from:self];
+
+        [NSNotificationCenter.defaultCenter postNotificationName:VLCRendererAddedNotification
+                                                          object:item];
+    });
 }
 
-- (void)handleItemRemoved:(const vlc_renderer_item_t *)base_item
+- (void)handleItemRemoved:(vlc_renderer_item_t *)base_item
 {
-    VLCRendererItem *result_item = nil;
-    for (VLCRendererItem *item in _rendererItems) {
-        if (item.rendererItem == base_item) {
-            result_item = item;
-            break;
+    VLCRendererItem * const removedItem =
+        [[VLCRendererItem alloc] initWithRendererItem:base_item];
+    dispatch_async(dispatch_get_main_queue(), ^{
+        VLCRendererItem *result_item = nil;
+        for (VLCRendererItem *item in self->_rendererItems) {
+            if (item.rendererItem == removedItem.rendererItem) {
+                result_item = item;
+                break;
+            }
         }
-    }
-    if (result_item) {
-        if (_delegate)
-            [_delegate removedRendererItem:result_item from:self];
-        [_rendererItems removeObject:result_item];
-        [NSNotificationCenter.defaultCenter postNotificationName:VLCRendererRemovedNotification
-                                                          object:result_item];
-    } else {
-        msg_Err(p_intf, "VLCRendererDiscovery could not find item to remove!");
-    }
+        if (result_item) {
+            if (self->_delegate)
+                [self->_delegate removedRendererItem:result_item from:self];
+            [self->_rendererItems removeObject:result_item];
+            [NSNotificationCenter.defaultCenter postNotificationName:VLCRendererRemovedNotification
+                                                              object:result_item];
+        } else {
+            msg_Err(self->p_intf, "VLCRendererDiscovery could not find item to remove!");
+        }
+    });
 }
 
 @end


=====================================
modules/gui/macosx/menus/renderers/VLCRendererMenuController.m
=====================================
@@ -49,6 +49,7 @@
     self = [super init];
     if (self) {
         _rendererDiscoveries = [NSMutableArray array];
+        _rendererItems = @[];
         _isDiscoveryEnabled = NO;
         p_intf = getIntf();
 
@@ -95,22 +96,20 @@
 - (void)addRendererItem:(VLCRendererItem *)item
 {
     NSParameterAssert(item != nil);
+
     NSMutableArray * const mutableRenderers = _rendererItems.mutableCopy;
     [mutableRenderers addObject:item];
     _rendererItems = mutableRenderers.copy;
 
     // Check if the item is already selected
-    if (_selectedItem.representedObject != nil)
-    {
+    if (_selectedItem.representedObject != nil) {
         VLCRendererItem *selected_rd_item = _selectedItem.representedObject;
-        if ([selected_rd_item.identifier isEqualToString:item.identifier])
-        {
+        if ([selected_rd_item.identifier isEqualToString:item.identifier]) {
             [_selectedItem setRepresentedObject:item];
             return;
         }
     }
 
-    // Create a menu item
     NSMenuItem *menuItem = [[NSMenuItem alloc] init];
     menuItem.target = self;
     menuItem.action = @selector(selectRenderer:);
@@ -129,31 +128,25 @@
                    range:[unformattedTitle rangeOfString:item.userReadableType options:NSBackwardsSearch]];
     menuItem.attributedTitle = title;
 
-    // The main menu must only be updated from the main thread
-    dispatch_async(dispatch_get_main_queue(), ^{
-        [_rendererMenu insertItem:menuItem atIndex:[_rendererMenu indexOfItem:_rendererNoneItem] + 1];
-    });
+    [_rendererMenu insertItem:menuItem atIndex:[_rendererMenu indexOfItem:_rendererNoneItem] + 1];
 }
 
 - (void)removeRendererItem:(VLCRendererItem *)item
 {
     NSParameterAssert(item != nil);
 
-    // The main menu must only be updated from the main thread
-    dispatch_async(dispatch_get_main_queue(), ^{
-        NSMutableArray * const mutableRenderers = _rendererItems.mutableCopy;
-        [mutableRenderers removeObject:item];
-        _rendererItems = mutableRenderers.copy;
-
-        const NSInteger index = [_rendererMenu indexOfItemWithRepresentedObject:item];
-        if (index >= 0) {
-            NSMenuItem * const menuItem = [_rendererMenu itemAtIndex:index];
-            // Don't remove selected item
-            if (menuItem != _selectedItem) {
-                [_rendererMenu removeItemAtIndex:index];
-            }
+    NSMutableArray * const mutableRenderers = _rendererItems.mutableCopy;
+    [mutableRenderers removeObject:item];
+    _rendererItems = mutableRenderers.copy;
+
+    const NSInteger index = [_rendererMenu indexOfItemWithRepresentedObject:item];
+    if (index >= 0) {
+        NSMenuItem * const menuItem = [_rendererMenu itemAtIndex:index];
+        // Don't remove selected item
+        if (menuItem != _selectedItem) {
+            [_rendererMenu removeItemAtIndex:index];
         }
-    });
+    }
 }
 
 - (void)startRendererDiscoveries



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/b766af16a3f43f02491b7d12d6527eb4d736a283...dd296d71e301429c24ed84d5ee221ec08b2ac956

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/b766af16a3f43f02491b7d12d6527eb4d736a283...dd296d71e301429c24ed84d5ee221ec08b2ac956
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