#include #include struct dirmonitor_internal { SDL_mutex* lock; char** changes; size_t count; FSEventStreamRef stream; int fds[2]; }; CFRunLoopRef main_run_loop; struct dirmonitor_internal* init_dirmonitor() { static bool mainloop_registered = false; if (!mainloop_registered) { main_run_loop = CFRunLoopGetCurrent(); mainloop_registered = true; } struct dirmonitor_internal* monitor = malloc(sizeof(struct dirmonitor_internal)); monitor->stream = NULL; monitor->changes = NULL; monitor->count = 0; monitor->lock = NULL; return monitor; } static void stop_monitor_stream(struct dirmonitor_internal* monitor) { if (monitor->stream) { FSEventStreamStop(monitor->stream); FSEventStreamUnscheduleFromRunLoop( monitor->stream, main_run_loop, kCFRunLoopDefaultMode ); FSEventStreamInvalidate(monitor->stream); FSEventStreamRelease(monitor->stream); monitor->stream = NULL; SDL_LockMutex(monitor->lock); write(monitor->fds[1], "", 1); close(monitor->fds[0]); close(monitor->fds[1]); if (monitor->count > 0) { for (size_t i = 0; icount; i++) { free(monitor->changes[i]); } free(monitor->changes); monitor->changes = NULL; monitor->count = 0; } SDL_UnlockMutex(monitor->lock); SDL_DestroyMutex(monitor->lock); } } void deinit_dirmonitor(struct dirmonitor_internal* monitor) { stop_monitor_stream(monitor); } static void stream_callback( ConstFSEventStreamRef streamRef, void* monitor_ptr, size_t numEvents, void* eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[] ) { if (numEvents <= 0) { return; } struct dirmonitor_internal* monitor = monitor_ptr; char** path_list = eventPaths; SDL_LockMutex(monitor->lock); size_t total = 0; if (monitor->count == 0) { total = numEvents; monitor->changes = calloc(numEvents, sizeof(char*)); } else { total = monitor->count + numEvents; monitor->changes = realloc( monitor->changes, sizeof(char*) * total ); } for (size_t idx = monitor->count; idx < total; idx++) { size_t pidx = idx - monitor->count; monitor->changes[idx] = malloc(strlen(path_list[pidx])+1); strcpy(monitor->changes[idx], path_list[pidx]); } monitor->count = total; if (total > 0) write(monitor->fds[1], "", 1); SDL_UnlockMutex(monitor->lock); } int get_changes_dirmonitor( struct dirmonitor_internal* monitor, char* buffer, int buffer_size ) { char response[1]; read(monitor->fds[0], response, 1); size_t results = 0; SDL_LockMutex(monitor->lock); results = monitor->count; SDL_UnlockMutex(monitor->lock); return results; } int translate_changes_dirmonitor( struct dirmonitor_internal* monitor, char* buffer, int buffer_size, int (*change_callback)(int, const char*, void*), void* L ) { SDL_LockMutex(monitor->lock); if (monitor->count > 0) { for (size_t i = 0; icount; i++) { change_callback(strlen(monitor->changes[i]), monitor->changes[i], L); free(monitor->changes[i]); } free(monitor->changes); monitor->changes = NULL; monitor->count = 0; } SDL_UnlockMutex(monitor->lock); return 0; } int add_dirmonitor(struct dirmonitor_internal* monitor, const char* path) { stop_monitor_stream(monitor); monitor->lock = SDL_CreateMutex(); pipe(monitor->fds); FSEventStreamContext context = { .info = monitor, .retain = NULL, .release = NULL, .copyDescription = NULL, .version = 0 }; CFStringRef paths[] = { CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8) }; monitor->stream = FSEventStreamCreate( NULL, stream_callback, &context, CFArrayCreate(NULL, (const void **)&paths, 1, NULL), kFSEventStreamEventIdSinceNow, 0, kFSEventStreamCreateFlagNone | kFSEventStreamCreateFlagWatchRoot | kFSEventStreamCreateFlagFileEvents ); FSEventStreamScheduleWithRunLoop( monitor->stream, main_run_loop, kCFRunLoopDefaultMode ); if (!FSEventStreamStart(monitor->stream)) { stop_monitor_stream(monitor); return -1; } return 1; } void remove_dirmonitor(struct dirmonitor_internal* monitor, int fd) { stop_monitor_stream(monitor); } int get_mode_dirmonitor() { return 1; }