Modernize macOS file system watcher impl

This commit is contained in:
2026-04-09 10:43:56 +02:00
parent 2f825652e5
commit ad90e39447
2 changed files with 37 additions and 52 deletions
@@ -1,6 +1,7 @@
// Copyright (c) Wojciech Figat. All rights reserved. // Copyright (c) Wojciech Figat. All rights reserved.
#if PLATFORM_MAC #if PLATFORM_MAC
#include "MacFileSystemWatcher.h" #include "MacFileSystemWatcher.h"
#include "Engine/Platform/Apple/AppleUtils.h" #include "Engine/Platform/Apple/AppleUtils.h"
#include "Engine/Platform/CriticalSection.h" #include "Engine/Platform/CriticalSection.h"
@@ -9,47 +10,32 @@
#include "Engine/Core/Collections/Array.h" #include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Types/StringView.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; MacFileSystemWatcher* macFileSystemWatcher = (MacFileSystemWatcher*)FileWatcherPtr;
if (macFileSystemWatcher) if (macFileSystemWatcher)
{ {
CFArrayRef EventPathArray = (CFArrayRef)EventPaths; 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]; const FSEventStreamEventFlags flags = EventFlags[eventIndex];
if( !(Flags & kFSEventStreamEventFlagItemIsFile) && !(Flags & kFSEventStreamEventFlagItemIsDir) ) if (!(flags & kFSEventStreamEventFlagItemIsFile) && !(flags & kFSEventStreamEventFlagItemIsDir))
{ {
// events about symlinks don't concern us // Events about symlinks don't concern us
continue; continue;
} }
auto action = FileSystemAction::Unknown; auto action = FileSystemAction::Unknown;
if (flags & kFSEventStreamEventFlagItemCreated)
const bool added = ( Flags & kFSEventStreamEventFlagItemCreated );
const bool renamed = ( Flags & kFSEventStreamEventFlagItemRenamed );
const bool modified = ( Flags & kFSEventStreamEventFlagItemModified );
const bool removed = ( Flags & kFSEventStreamEventFlagItemRemoved );
if (added)
{
action = FileSystemAction::Create; action = FileSystemAction::Create;
} if (flags & kFSEventStreamEventFlagItemRenamed)
if (renamed)
{
action = FileSystemAction::Rename; action = FileSystemAction::Rename;
} if (flags & kFSEventStreamEventFlagItemModified)
if (modified)
{
action = FileSystemAction::Modify; action = FileSystemAction::Modify;
} if (flags & kFSEventStreamEventFlagItemRemoved)
if (removed)
{
action = FileSystemAction::Delete; 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); macFileSystemWatcher->OnEvent(resolvedPath, action);
} }
} }
@@ -61,9 +47,8 @@ MacFileSystemWatcher::MacFileSystemWatcher(const String& directory, bool withSub
CFStringRef FullPathMac = AppleUtils::ToString(StringView(directory)); CFStringRef FullPathMac = AppleUtils::ToString(StringView(directory));
CFArrayRef PathsToWatch = CFArrayCreate(NULL, (const void**)&FullPathMac, 1, NULL); CFArrayRef PathsToWatch = CFArrayCreate(NULL, (const void**)&FullPathMac, 1, NULL);
CFAbsoluteTime Latency = 0.2; CFAbsoluteTime Latency = 0.2;
FSEventStreamContext Context; FSEventStreamContext Context;
Context.version = 0; Context.version = 0;
Context.info = this; Context.info = this;
@@ -71,7 +56,7 @@ MacFileSystemWatcher::MacFileSystemWatcher(const String& directory, bool withSub
Context.release = NULL; Context.release = NULL;
Context.copyDescription = NULL; Context.copyDescription = NULL;
EventStream = FSEventStreamCreate( NULL, _eventStream = FSEventStreamCreate(NULL,
&DirectoryWatchCallback, &DirectoryWatchCallback,
&Context, &Context,
PathsToWatch, PathsToWatch,
@@ -82,21 +67,27 @@ MacFileSystemWatcher::MacFileSystemWatcher(const String& directory, bool withSub
CFRelease(PathsToWatch); CFRelease(PathsToWatch);
CFRelease(FullPathMac); CFRelease(FullPathMac);
FSEventStreamScheduleWithRunLoop( EventStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode ); _queue = dispatch_queue_create("MacFileSystemWatcher", NULL);
FSEventStreamStart( EventStream ); FSEventStreamSetDispatchQueue(_eventStream, _queue);
FSEventStreamStart(_eventStream);
IsRunning = true;
} }
MacFileSystemWatcher::~MacFileSystemWatcher() MacFileSystemWatcher::~MacFileSystemWatcher()
{ {
if (IsRunning) if (_eventStream)
{ {
FSEventStreamStop(EventStream); FSEventStreamStop(_eventStream);
FSEventStreamUnscheduleFromRunLoop(EventStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); FSEventStreamSetDispatchQueue(_eventStream, nullptr);
FSEventStreamInvalidate(EventStream); FSEventStreamInvalidate(_eventStream);
FSEventStreamRelease(EventStream); FSEventStreamRelease(_eventStream);
_eventStream = nullptr;
}
if (_queue != nullptr)
{
dispatch_release(_queue);
_queue = nullptr;
} }
} }
#endif #endif
@@ -3,18 +3,20 @@
#pragma once #pragma once
#if PLATFORM_MAC #if PLATFORM_MAC
#include "Engine/Platform/Base/FileSystemWatcherBase.h" #include "Engine/Platform/Base/FileSystemWatcherBase.h"
#include <CoreServices/CoreServices.h> #include <CoreServices/CoreServices.h>
/// <summary> /// <summary>
/// Mac platform implementation of the file system watching object. /// Mac platform implementation of the file system watching object.
/// </summary> /// </summary>
class FLAXENGINE_API MacFileSystemWatcher : public FileSystemWatcherBase class FLAXENGINE_API MacFileSystemWatcher : public FileSystemWatcherBase
{ {
public: private:
FSEventStreamRef _eventStream;
dispatch_queue_t _queue;
public:
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MacFileSystemWatcher"/> class. /// Initializes a new instance of the <see cref="MacFileSystemWatcher"/> class.
/// </summary> /// </summary>
@@ -26,14 +28,6 @@ public:
/// Finalizes an instance of the <see cref="MacFileSystemWatcher"/> class. /// Finalizes an instance of the <see cref="MacFileSystemWatcher"/> class.
/// </summary> /// </summary>
~MacFileSystemWatcher(); ~MacFileSystemWatcher();
public:
private:
FSEventStreamRef EventStream;
bool IsRunning;
}; };
#endif #endif