194 lines
4.3 KiB
C
194 lines
4.3 KiB
C
#include <SDL.h>
|
|
#include <CoreServices/CoreServices.h>
|
|
|
|
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; i<monitor->count; 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; i<monitor->count; 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; }
|