[vlc-commits] [Git][videolan/vlc][master] 7 commits: macosx: Add VLCMediaSourceNodeObservation protocol

Steve Lhomme (@robUx4) gitlab at videolan.org
Wed Aug 5 10:44:08 UTC 2026



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
36cbb4b8 by Claudio Cambra at 2026-08-05T09:51:14+00:00
macosx: Add VLCMediaSourceNodeObservation protocol

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

- - - - -
b4f7ac1a by Claudio Cambra at 2026-08-05T09:51:14+00:00
macosx: Add node observation method to VLCMediaSource

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

- - - - -
1f76ee47 by Claudio Cambra at 2026-08-05T09:51:14+00:00
macosx: Add VLCLocalMediaSourceNodeObservation

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

- - - - -
b1ac7760 by Claudio Cambra at 2026-08-05T09:51:14+00:00
macosx: Add VLCLocalMediaSource

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

- - - - -
8b0c3341 by Claudio Cambra at 2026-08-05T09:51:14+00:00
macosx: Use VLCLocalMediaSource for my folders and local devices

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

- - - - -
f9ca4733 by Claudio Cambra at 2026-08-05T09:51:14+00:00
macosx: Use local media source for local URLs in base data source

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

- - - - -
26e02eae by Claudio Cambra at 2026-08-05T09:51:14+00:00
macosx: Replace local change handling within media source data source with use of local media source

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

# Conflicts:
#	modules/gui/macosx/library/media-source/VLCMediaSourceDataSource.m

- - - - -


12 changed files:

- extras/package/macosx/VLC.xcodeproj/project.pbxproj
- modules/gui/macosx/Makefile.am
- + modules/gui/macosx/library/media-source/VLCLocalMediaSource.h
- + modules/gui/macosx/library/media-source/VLCLocalMediaSource.m
- + modules/gui/macosx/library/media-source/VLCLocalMediaSourceNodeObservation.h
- + modules/gui/macosx/library/media-source/VLCLocalMediaSourceNodeObservation.m
- modules/gui/macosx/library/media-source/VLCMediaSource.h
- modules/gui/macosx/library/media-source/VLCMediaSource.m
- modules/gui/macosx/library/media-source/VLCMediaSourceBaseDataSource.m
- modules/gui/macosx/library/media-source/VLCMediaSourceDataSource.m
- + modules/gui/macosx/library/media-source/VLCMediaSourceNodeObservation.h
- modules/gui/macosx/library/media-source/VLCMediaSourceProvider.m


Changes:

=====================================
extras/package/macosx/VLC.xcodeproj/project.pbxproj
=====================================
@@ -276,6 +276,8 @@
 		7DFBDCB7226CDFD600B700A5 /* VLCImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCB6226CDFD600B700A5 /* VLCImageView.m */; };
 		7DFBDCBB226CED6300B700A5 /* VLCMediaSourceProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCBA226CED6300B700A5 /* VLCMediaSourceProvider.m */; };
 		7DFBDCBE226CED7200B700A5 /* VLCMediaSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCBD226CED7200B700A5 /* VLCMediaSource.m */; };
+		7DFBDCDF226CED7200B700A5 /* VLCLocalMediaSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCDE226CED7200B700A5 /* VLCLocalMediaSource.m */; };
+		7DFBDCE2226CED7200B700A5 /* VLCLocalMediaSourceNodeObservation.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCE1226CED7200B700A5 /* VLCLocalMediaSourceNodeObservation.m */; };
 		7DFBDCC1226DC16200B700A5 /* VLCInputItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCC0226DC16200B700A5 /* VLCInputItem.m */; };
 		7DFBDCC4226E445500B700A5 /* VLCMediaSourceBaseDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFBDCC3226E445500B700A5 /* VLCMediaSourceBaseDataSource.m */; };
 		7DFFF90123682D4800C8B0C9 /* VLCDetachedAudioWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DFFF90023682D4800C8B0C9 /* VLCDetachedAudioWindow.m */; };
@@ -948,6 +950,11 @@
 		7DFBDCBA226CED6300B700A5 /* VLCMediaSourceProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCMediaSourceProvider.m; sourceTree = "<group>"; };
 		7DFBDCBC226CED7200B700A5 /* VLCMediaSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCMediaSource.h; sourceTree = "<group>"; };
 		7DFBDCBD226CED7200B700A5 /* VLCMediaSource.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCMediaSource.m; sourceTree = "<group>"; };
+		7DFBDCDD226CED7200B700A5 /* VLCLocalMediaSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLocalMediaSource.h; sourceTree = "<group>"; };
+		7DFBDCDE226CED7200B700A5 /* VLCLocalMediaSource.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLocalMediaSource.m; sourceTree = "<group>"; };
+		7DFBDCE0226CED7200B700A5 /* VLCLocalMediaSourceNodeObservation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCLocalMediaSourceNodeObservation.h; sourceTree = "<group>"; };
+		7DFBDCE1226CED7200B700A5 /* VLCLocalMediaSourceNodeObservation.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCLocalMediaSourceNodeObservation.m; sourceTree = "<group>"; };
+		7DFBDCDA226CED7200B700A5 /* VLCMediaSourceNodeObservation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCMediaSourceNodeObservation.h; sourceTree = "<group>"; };
 		7DFBDCBF226DC16200B700A5 /* VLCInputItem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCInputItem.h; sourceTree = "<group>"; };
 		7DFBDCC0226DC16200B700A5 /* VLCInputItem.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCInputItem.m; sourceTree = "<group>"; };
 		7DFBDCC2226E445500B700A5 /* VLCMediaSourceBaseDataSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCMediaSourceBaseDataSource.h; sourceTree = "<group>"; };
@@ -2124,6 +2131,11 @@
 				539668862D37B483005CD9D4 /* VLCLibraryMediaSourceViewNavigationState.m */,
 				7DFBDCBC226CED7200B700A5 /* VLCMediaSource.h */,
 				7DFBDCBD226CED7200B700A5 /* VLCMediaSource.m */,
+				7DFBDCDD226CED7200B700A5 /* VLCLocalMediaSource.h */,
+				7DFBDCDE226CED7200B700A5 /* VLCLocalMediaSource.m */,
+				7DFBDCE0226CED7200B700A5 /* VLCLocalMediaSourceNodeObservation.h */,
+				7DFBDCE1226CED7200B700A5 /* VLCLocalMediaSourceNodeObservation.m */,
+				7DFBDCDA226CED7200B700A5 /* VLCMediaSourceNodeObservation.h */,
 				7DFBDCC2226E445500B700A5 /* VLCMediaSourceBaseDataSource.h */,
 				7DFBDCC3226E445500B700A5 /* VLCMediaSourceBaseDataSource.m */,
 				7D2554C022C8A39300F2D9C2 /* VLCMediaSourceDataSource.h */,
@@ -2401,6 +2413,8 @@
 				5352B37329DF29BF0011CE03 /* VLCMainVideoViewControlsBar.m in Sources */,
 				7D445D812202524000263D34 /* VLCPlayQueueController.m in Sources */,
 				7DFBDCBE226CED7200B700A5 /* VLCMediaSource.m in Sources */,
+				7DFBDCDF226CED7200B700A5 /* VLCLocalMediaSource.m in Sources */,
+				7DFBDCE2226CED7200B700A5 /* VLCLocalMediaSourceNodeObservation.m in Sources */,
 				536283F2291146BC00640C15 /* VLCLibraryCollectionViewMediaItemListSupplementaryDetailView.m in Sources */,
 				5341F1542C9865F8003BDF0A /* VLCLibraryWindowSidebarRootViewController.m in Sources */,
 				6BAF886024DB1CEA001044C8 /* VLCSystemVolume.m in Sources */,


=====================================
modules/gui/macosx/Makefile.am
=====================================
@@ -322,6 +322,11 @@ libmacosx_plugin_la_SOURCES = \
 	gui/macosx/library/media-source/VLCLibraryMediaSourceViewController.m \
 	gui/macosx/library/media-source/VLCMediaSource.h \
 	gui/macosx/library/media-source/VLCMediaSource.m \
+	gui/macosx/library/media-source/VLCLocalMediaSource.h \
+	gui/macosx/library/media-source/VLCLocalMediaSource.m \
+	gui/macosx/library/media-source/VLCLocalMediaSourceNodeObservation.h \
+	gui/macosx/library/media-source/VLCLocalMediaSourceNodeObservation.m \
+	gui/macosx/library/media-source/VLCMediaSourceNodeObservation.h \
 	gui/macosx/library/media-source/VLCMediaSourceBaseDataSource.h \
 	gui/macosx/library/media-source/VLCMediaSourceBaseDataSource.m \
 	gui/macosx/library/media-source/VLCMediaSourceCollectionViewItem.h \


=====================================
modules/gui/macosx/library/media-source/VLCLocalMediaSource.h
=====================================
@@ -0,0 +1,31 @@
+/*****************************************************************************
+ * VLCLocalMediaSource.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2026 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import "VLCMediaSource.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at interface VLCLocalMediaSource : VLCMediaSource
+
+ at end
+
+NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/media-source/VLCLocalMediaSource.m
=====================================
@@ -0,0 +1,57 @@
+/*****************************************************************************
+ * VLCLocalMediaSource.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2026 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import "VLCLocalMediaSource.h"
+
+#import "library/VLCInputItem.h"
+
+#import "VLCLocalMediaSourceNodeObservation.h"
+
+ at implementation VLCLocalMediaSource
+
+- (nullable id<VLCMediaSourceNodeObservation>)observeInputNode:(VLCInputNode *)inputNode
+                                                      onChange:(void (^)(VLCMediaSourceNodeChange change))changeHandler
+{
+    NSURL * const nodeURL = [NSURL URLWithString:inputNode.inputItem.MRL];
+    if (!nodeURL.isFileURL) {
+        return nil;
+    }
+
+    const __weak typeof(self) weakSelf = self;
+    return [[VLCLocalMediaSourceNodeObservation alloc] initWithURL:nodeURL
+                                                      eventHandler:^(dispatch_source_vnode_flags_t eventFlags) {
+        if ((eventFlags & DISPATCH_VNODE_DELETE) != 0 ||
+            (eventFlags & DISPATCH_VNODE_RENAME) != 0) {
+            changeHandler(VLCMediaSourceNodeChangeInvalidated);
+            return;
+        }
+
+        const typeof(self) strongSelf = weakSelf;
+        if (strongSelf == nil) {
+            return;
+        }
+        [strongSelf generateChildNodesForDirectoryNode:inputNode withUrl:nodeURL];
+        changeHandler(VLCMediaSourceNodeChangeChildrenUpdated);
+    }];
+}
+
+ at end


=====================================
modules/gui/macosx/library/media-source/VLCLocalMediaSourceNodeObservation.h
=====================================
@@ -0,0 +1,34 @@
+/*****************************************************************************
+ * VLCLocalMediaSourceNodeObservation.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2026 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import "VLCMediaSourceNodeObservation.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+ at interface VLCLocalMediaSourceNodeObservation : NSObject <VLCMediaSourceNodeObservation>
+
+- (nullable instancetype)initWithURL:(NSURL *)url
+                        eventHandler:(void (^)(dispatch_source_vnode_flags_t eventFlags))eventHandler;
+
+ at end
+
+NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/media-source/VLCLocalMediaSourceNodeObservation.m
=====================================
@@ -0,0 +1,85 @@
+/*****************************************************************************
+ * VLCLocalMediaSourceNodeObservation.m: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2026 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import "VLCLocalMediaSourceNodeObservation.h"
+
+#include <fcntl.h>
+#include <unistd.h>
+
+ at interface VLCLocalMediaSourceNodeObservation ()
+{
+    dispatch_source_t _dispatchSource;
+}
+ at end
+
+ at implementation VLCLocalMediaSourceNodeObservation
+
+- (nullable instancetype)initWithURL:(NSURL *)url
+                         eventHandler:(void (^)(dispatch_source_vnode_flags_t eventFlags))eventHandler
+{
+    self = [super init];
+    if (self) {
+        const int descriptor = open(url.path.UTF8String, O_EVTONLY);
+        if (descriptor == -1) {
+            return nil;
+        }
+
+        _dispatchSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE,
+                                                 descriptor,
+                                                 DISPATCH_VNODE_WRITE |
+                                                 DISPATCH_VNODE_DELETE |
+                                                 DISPATCH_VNODE_RENAME,
+                                                 dispatch_get_main_queue());
+        if (_dispatchSource == nil) {
+            close(descriptor);
+            return nil;
+        }
+
+        const __weak typeof(self) weakSelf = self;
+        dispatch_source_set_event_handler(_dispatchSource, ^{
+            const typeof(self) strongSelf = weakSelf;
+            if (strongSelf == nil || dispatch_source_testcancel(strongSelf->_dispatchSource)) {
+                return;
+            }
+            eventHandler(dispatch_source_get_data(strongSelf->_dispatchSource));
+        });
+        dispatch_source_set_cancel_handler(_dispatchSource, ^{
+            close(descriptor);
+        });
+        dispatch_resume(_dispatchSource);
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [self cancel];
+}
+
+- (void)cancel
+{
+    if (_dispatchSource != nil) {
+        dispatch_source_cancel(_dispatchSource);
+    }
+}
+
+ at end


=====================================
modules/gui/macosx/library/media-source/VLCMediaSource.h
=====================================
@@ -25,6 +25,8 @@
 #import <vlc_media_source.h>
 #import <vlc_preparser.h>
 
+#import "VLCMediaSourceNodeObservation.h"
+
 @class VLCInputItem;
 @class VLCInputNode;
 
@@ -50,6 +52,8 @@ extern NSString *VLCMediaSourcePreparsingEnded;
 - (void)clearChildNodesForNode:(input_item_node_t*)inputNode;
 - (nullable NSError *)generateChildNodesForDirectoryNode:(VLCInputNode *)directoryInputNode
                                                  withUrl:(NSURL *)directoryUrl;
+- (nullable id<VLCMediaSourceNodeObservation>)observeInputNode:(VLCInputNode *)inputNode
+                                                      onChange:(void (^)(VLCMediaSourceNodeChange change))changeHandler;
 
 @property (nonatomic, readonly) NSString *mediaSourceDescription;
 @property (nonatomic, readonly) VLCInputNode *rootNode;


=====================================
modules/gui/macosx/library/media-source/VLCMediaSource.m
=====================================
@@ -339,6 +339,12 @@ static const char *const remoteBrowseDescription = "Remote Browse";
     return nil;
 }
 
+- (nullable id<VLCMediaSourceNodeObservation>)observeInputNode:(VLCInputNode *const __unused)inputNode
+                                                      onChange:(void (^const __unused)(VLCMediaSourceNodeChange change))changeHandler
+{
+    return nil;
+}
+
 - (void)clearChildNodesForNode:(nonnull input_item_node_t*)inputNode
 {
     NSAssert(inputNode != NULL, @"Could not clear child nodes for input node as node is null");
@@ -634,5 +640,4 @@ static const char *const remoteBrowseDescription = "Remote Browse";
     });
 }
 
-
 @end


=====================================
modules/gui/macosx/library/media-source/VLCMediaSourceBaseDataSource.m
=====================================
@@ -24,6 +24,7 @@
 
 #import "VLCLibraryMediaSourceViewNavigationStack.h"
 #import "VLCMediaSource.h"
+#import "VLCLocalMediaSource.h"
 #import "VLCMediaSourceDataSource.h"
 #import "VLCMediaSourceDeviceCollectionViewItem.h"
 #import "VLCMediaSourceProvider.h"
@@ -767,8 +768,10 @@ referenceSizeForHeaderInSection:(NSInteger)section
 - (void)browseFolderByMrl:(NSString *)mrl
 {
     vlc_preparser_t *p_preparser = getNetworkPreparser();
-    VLCMediaSource * const mediaSource =
-        [[VLCMediaSource alloc] initWithFolderMrl:mrl andPreparser:p_preparser];
+    NSURL * const folderURL = [NSURL URLWithString:mrl];
+    VLCMediaSource * const mediaSource = folderURL.isFileURL
+        ? [[VLCLocalMediaSource alloc] initWithFolderMrl:mrl andPreparser:p_preparser]
+        : [[VLCMediaSource alloc] initWithFolderMrl:mrl andPreparser:p_preparser];
     if (mediaSource == nil) {
         NSLog(@"Could not create valid media source for mrl: %@", mrl);
         return;


=====================================
modules/gui/macosx/library/media-source/VLCMediaSourceDataSource.m
=====================================
@@ -22,11 +22,6 @@
 
 #import "VLCMediaSourceDataSource.h"
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
 #import "VLCLibraryMediaSourceViewNavigationStack.h"
 #import "VLCMediaSource.h"
 #import "VLCMediaSourceBaseDataSource.h"
@@ -61,6 +56,7 @@ NSString * const VLCMediaSourceDataSourceLoadingEnded = @"VLCMediaSourceDataSour
 
 @property (readwrite) dispatch_source_t observedPathDispatchSource;
 @property (readwrite) BOOL preparseOngoing;
+ at property (readwrite, strong, nullable, nonatomic) id<VLCMediaSourceNodeObservation> nodeObservation;
 
 @end
 
@@ -98,6 +94,7 @@ NSString * const VLCMediaSourceDataSourceLoadingEnded = @"VLCMediaSourceDataSour
 
 - (void)dealloc
 {
+    [self.nodeObservation cancel];
     [NSNotificationCenter.defaultCenter removeObserver:self];
 }
 
@@ -121,70 +118,30 @@ NSString * const VLCMediaSourceDataSourceLoadingEnded = @"VLCMediaSourceDataSour
     });
 }
 
-- (dispatch_source_t)observeLocalUrl:(NSURL *)url
-                      forVnodeEvents:(dispatch_source_vnode_flags_t)eventsFlags
-                    withEventHandler:(dispatch_block_t)eventHandlerBlock
-{
-    const uintptr_t descriptor = open(url.path.UTF8String, O_EVTONLY);
-    if (descriptor == (uintptr_t)-1) {
-        return nil;
-    }
-    struct stat fileStat;
-    const int statResult = fstat(descriptor, &fileStat);
-    if (statResult == -1) {
-        NSLog(@"Failed to stat file %@: %s", url.path, strerror(errno));
-        return nil;
-    }
-
-    const dispatch_queue_t globalQueue =
-        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
-    const dispatch_source_t fileDispatchSource =
-        dispatch_source_create(DISPATCH_SOURCE_TYPE_VNODE, descriptor, eventsFlags, globalQueue);
-    dispatch_source_set_event_handler(fileDispatchSource, eventHandlerBlock);
-    dispatch_source_set_cancel_handler(fileDispatchSource, ^{
-        close(descriptor);
-    });
-    dispatch_resume(fileDispatchSource);
-    return fileDispatchSource;
-}
-
 - (void)setNodeToDisplay:(nonnull VLCInputNode*)nodeToDisplay
 {
     NSAssert(nodeToDisplay, @"Nil node to display, will not set");
     _nodeToDisplay = nodeToDisplay;
 
     NSParameterAssert(self.parentBaseDataSource);
-    if (self.parentBaseDataSource.mediaSourceMode == VLCMediaSourceModeLAN) {
-        NSURL * const nodeUrl = [NSURL URLWithString:nodeToDisplay.inputItem.MRL];
-
-        if (nodeUrl.isFileURL) {
-            if (self.observedPathDispatchSource) {
-                dispatch_source_cancel(self.observedPathDispatchSource);
-                self.observedPathDispatchSource = nil;
-            }
+    [self.nodeObservation cancel];
 
-            const __weak typeof(self) weakSelf = self;
-            self.observedPathDispatchSource = [self observeLocalUrl:nodeUrl
-                                                    forVnodeEvents:DISPATCH_VNODE_WRITE |
-                                                                   DISPATCH_VNODE_DELETE |
-                                                                   DISPATCH_VNODE_RENAME
-                                                withEventHandler:^{
-                const uintptr_t eventFlags =
-                    dispatch_source_get_data(weakSelf.observedPathDispatchSource);
-                if (eventFlags & DISPATCH_VNODE_DELETE || eventFlags & DISPATCH_VNODE_RENAME) {
-                    dispatch_async(dispatch_get_main_queue(), ^{
-                        [weakSelf.parentBaseDataSource homeButtonAction:weakSelf];
-                    });
-                } else {
-                    dispatch_async(dispatch_get_main_queue(), ^{
-                        [weakSelf.displayedMediaSource generateChildNodesForDirectoryNode:nodeToDisplay
-                                                                                  withUrl:nodeUrl];
-                        [weakSelf reloadData];
-                    });
-                }
-            }];
+    const __weak typeof(self) weakSelf = self;
+    self.nodeObservation = [self.displayedMediaSource observeInputNode:nodeToDisplay
+                                                              onChange:^(VLCMediaSourceNodeChange change) {
+        const typeof(self) strongSelf = weakSelf;
+        if (strongSelf == nil) {
+            return;
         }
-    }
+        switch (change) {
+            case VLCMediaSourceNodeChangeChildrenUpdated:
+                [strongSelf reloadData];
+                break;
+            case VLCMediaSourceNodeChangeInvalidated:
+                [strongSelf.parentBaseDataSource homeButtonAction:strongSelf];
+                break;
+        }
+    }];
 
     [self reloadData];
     if (self.preparseOngoing) {
@@ -341,10 +298,8 @@ NSString * const VLCMediaSourceDataSourceLoadingEnded = @"VLCMediaSourceDataSour
         if (inputNode.numberOfChildren == 0) {
             cellView.textField.stringValue = NSTR("Loading…");
             dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), ^{
-                NSURL * const inputNodeUrl = [NSURL URLWithString:inputNode.inputItem.MRL];
                 NSError * const error =
-                    [self.displayedMediaSource generateChildNodesForDirectoryNode:inputNode
-                                                                          withUrl:inputNodeUrl];
+                    [self.displayedMediaSource preparseInputNodeWithinTree:inputNode];
                 if (error) {
                     dispatch_async(dispatch_get_main_queue(), ^{
                         cellView.textField.stringValue = NSTR("Unavailable");


=====================================
modules/gui/macosx/library/media-source/VLCMediaSourceNodeObservation.h
=====================================
@@ -0,0 +1,38 @@
+/*****************************************************************************
+ * VLCMediaSourceNodeObservation.h: MacOS X interface module
+ *****************************************************************************
+ * Copyright (C) 2026 VLC authors and VideoLAN
+ *
+ * Authors: Claudio Cambra <developer at claudiocambra.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+typedef NS_ENUM(NSUInteger, VLCMediaSourceNodeChange) {
+    VLCMediaSourceNodeChangeChildrenUpdated,
+    VLCMediaSourceNodeChangeInvalidated,
+};
+
+ at protocol VLCMediaSourceNodeObservation <NSObject>
+
+- (void)cancel;
+
+ at end
+
+NS_ASSUME_NONNULL_END


=====================================
modules/gui/macosx/library/media-source/VLCMediaSourceProvider.m
=====================================
@@ -23,6 +23,7 @@
 #import "VLCMediaSourceProvider.h"
 
 #import "VLCMediaSource.h"
+#import "VLCLocalMediaSource.h"
 
 #import "main/VLCMain.h"
 
@@ -78,8 +79,8 @@ static inline void getMediaSourcesForCategory(NSMutableArray <VLCMediaSource *>
     NSMutableArray<VLCMediaSource *> * const mutableArray = [[NSMutableArray alloc] initWithCapacity:32]; // A sane default
 
     // "My Folders" and "My Machine" entries are a bit of a custom implementation so it gets treated differently
-    VLCMediaSource * const myFoldersMediaSource = [[VLCMediaSource alloc] initMyFoldersMediaSourceWithPreparser:p_preparser];
-    VLCMediaSource * const localDevicesMediaSource = [[VLCMediaSource alloc] initForLocalDevices:p_preparser];
+    VLCMediaSource * const myFoldersMediaSource = [[VLCLocalMediaSource alloc] initMyFoldersMediaSourceWithPreparser:p_preparser];
+    VLCMediaSource * const localDevicesMediaSource = [[VLCLocalMediaSource alloc] initForLocalDevices:p_preparser];
     [mutableArray addObject:myFoldersMediaSource];
     [mutableArray addObject:localDevicesMediaSource];
 



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/5f3b539f668fae5a7f2d07d75f496eff44a8aaa5...26e02eae8da67914d1a65f91a8fa19c67617d378

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/5f3b539f668fae5a7f2d07d75f496eff44a8aaa5...26e02eae8da67914d1a65f91a8fa19c67617d378
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