lite-xl/src/api/dirmonitor/fsevents.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; }