From ad90e3944745566e66be50fe36bee46a6c61b051 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Thu, 9 Apr 2026 10:43:56 +0200 Subject: [PATCH] Modernize macOS file system watcher impl --- .../Platform/Mac/MacFileSystemWatcher.cpp | 71 ++++++++----------- .../Platform/Mac/MacFileSystemWatcher.h | 18 ++--- 2 files changed, 37 insertions(+), 52 deletions(-) diff --git a/Source/Engine/Platform/Mac/MacFileSystemWatcher.cpp b/Source/Engine/Platform/Mac/MacFileSystemWatcher.cpp index 39310f2b2..69b8e0d7c 100644 --- a/Source/Engine/Platform/Mac/MacFileSystemWatcher.cpp +++ b/Source/Engine/Platform/Mac/MacFileSystemWatcher.cpp @@ -1,6 +1,7 @@ // Copyright (c) Wojciech Figat. All rights reserved. #if PLATFORM_MAC + #include "MacFileSystemWatcher.h" #include "Engine/Platform/Apple/AppleUtils.h" #include "Engine/Platform/CriticalSection.h" @@ -9,47 +10,32 @@ #include "Engine/Core/Collections/Array.h" #include "Engine/Core/Types/StringView.h" -void DirectoryWatchCallback( ConstFSEventStreamRef StreamRef, void* FileWatcherPtr, size_t EventCount, void* EventPaths, const FSEventStreamEventFlags EventFlags[], const FSEventStreamEventId EventIDs[] ) +void DirectoryWatchCallback( ConstFSEventStreamRef StreamRef, void* FileWatcherPtr, size_t EventCount, void* EventPaths, const FSEventStreamEventFlags EventFlags[], const FSEventStreamEventId EventIDs[]) { MacFileSystemWatcher* macFileSystemWatcher = (MacFileSystemWatcher*)FileWatcherPtr; if (macFileSystemWatcher) { CFArrayRef EventPathArray = (CFArrayRef)EventPaths; - for( size_t EventIndex = 0; EventIndex < EventCount; ++EventIndex ) + for (size_t eventIndex = 0; eventIndex < EventCount; eventIndex++) { - const FSEventStreamEventFlags Flags = EventFlags[EventIndex]; - if( !(Flags & kFSEventStreamEventFlagItemIsFile) && !(Flags & kFSEventStreamEventFlagItemIsDir) ) + const FSEventStreamEventFlags flags = EventFlags[eventIndex]; + if (!(flags & kFSEventStreamEventFlagItemIsFile) && !(flags & kFSEventStreamEventFlagItemIsDir)) { - // events about symlinks don't concern us + // Events about symlinks don't concern us continue; } - + auto action = FileSystemAction::Unknown; - - const bool added = ( Flags & kFSEventStreamEventFlagItemCreated ); - const bool renamed = ( Flags & kFSEventStreamEventFlagItemRenamed ); - const bool modified = ( Flags & kFSEventStreamEventFlagItemModified ); - const bool removed = ( Flags & kFSEventStreamEventFlagItemRemoved ); - - if (added) - { + if (flags & kFSEventStreamEventFlagItemCreated) action = FileSystemAction::Create; - } - if (renamed) - { + if (flags & kFSEventStreamEventFlagItemRenamed) action = FileSystemAction::Rename; - } - if (modified) - { + if (flags & kFSEventStreamEventFlagItemModified) action = FileSystemAction::Modify; - } - if (removed) - { + if (flags & kFSEventStreamEventFlagItemRemoved) action = FileSystemAction::Delete; - } - - const String resolvedPath = AppleUtils::ToString((CFStringRef)CFArrayGetValueAtIndex(EventPathArray,EventIndex)); - + + const String resolvedPath = AppleUtils::ToString((CFStringRef)CFArrayGetValueAtIndex(EventPathArray, eventIndex)); macFileSystemWatcher->OnEvent(resolvedPath, action); } } @@ -61,9 +47,8 @@ MacFileSystemWatcher::MacFileSystemWatcher(const String& directory, bool withSub CFStringRef FullPathMac = AppleUtils::ToString(StringView(directory)); CFArrayRef PathsToWatch = CFArrayCreate(NULL, (const void**)&FullPathMac, 1, NULL); - + CFAbsoluteTime Latency = 0.2; - FSEventStreamContext Context; Context.version = 0; Context.info = this; @@ -71,7 +56,7 @@ MacFileSystemWatcher::MacFileSystemWatcher(const String& directory, bool withSub Context.release = NULL; Context.copyDescription = NULL; - EventStream = FSEventStreamCreate( NULL, + _eventStream = FSEventStreamCreate(NULL, &DirectoryWatchCallback, &Context, PathsToWatch, @@ -82,21 +67,27 @@ MacFileSystemWatcher::MacFileSystemWatcher(const String& directory, bool withSub CFRelease(PathsToWatch); CFRelease(FullPathMac); - - FSEventStreamScheduleWithRunLoop( EventStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); - FSEventStreamStart( EventStream ); - - IsRunning = true; + + _queue = dispatch_queue_create("MacFileSystemWatcher", NULL); + FSEventStreamSetDispatchQueue(_eventStream, _queue); + FSEventStreamStart(_eventStream); } MacFileSystemWatcher::~MacFileSystemWatcher() { - if (IsRunning) + if (_eventStream) { - FSEventStreamStop(EventStream); - FSEventStreamUnscheduleFromRunLoop(EventStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - FSEventStreamInvalidate(EventStream); - FSEventStreamRelease(EventStream); + FSEventStreamStop(_eventStream); + FSEventStreamSetDispatchQueue(_eventStream, nullptr); + FSEventStreamInvalidate(_eventStream); + FSEventStreamRelease(_eventStream); + _eventStream = nullptr; + } + if (_queue != nullptr) + { + dispatch_release(_queue); + _queue = nullptr; } } + #endif diff --git a/Source/Engine/Platform/Mac/MacFileSystemWatcher.h b/Source/Engine/Platform/Mac/MacFileSystemWatcher.h index b0edd1df3..576d34c75 100644 --- a/Source/Engine/Platform/Mac/MacFileSystemWatcher.h +++ b/Source/Engine/Platform/Mac/MacFileSystemWatcher.h @@ -3,18 +3,20 @@ #pragma once #if PLATFORM_MAC + #include "Engine/Platform/Base/FileSystemWatcherBase.h" - #include - /// /// Mac platform implementation of the file system watching object. /// class FLAXENGINE_API MacFileSystemWatcher : public FileSystemWatcherBase { -public: +private: + FSEventStreamRef _eventStream; + dispatch_queue_t _queue; +public: /// /// Initializes a new instance of the class. /// @@ -26,14 +28,6 @@ public: /// Finalizes an instance of the class. /// ~MacFileSystemWatcher(); - -public: - - - -private: - - FSEventStreamRef EventStream; - bool IsRunning; }; + #endif