2 * Code adapted from the Haskell "hfsevents" package.
4 * Copyright (c) 2012, Luite Stegeman
10#if HAVE_DECL_KFSEVENTSTREAMCREATEFLAGFILEEVENTS
12#include <CoreServices/CoreServices.h>
15#include <FileSystem/Event/Darwin.h>
18 * For reference documentaion see:
19 * https://developer.apple.com/documentation/coreservices/file_system_events?language=objc
20 * https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/FSEvents_ProgGuide/UsingtheFSEventsFramework/UsingtheFSEventsFramework.html
22 * An OS thread is started which runs the event loop. A pipe is created
23 * and the events are sent to the pipes. The receiver can read the pipe
24 * output end to get the events.
27/******************************************************************************
29 *****************************************************************************/
31UInt32 FSEventStreamCreateFlagNoDefer () {
32 return kFSEventStreamCreateFlagNoDefer;
34UInt32 FSEventStreamCreateFlagWatchRoot () {
35 return kFSEventStreamCreateFlagWatchRoot;
37UInt32 FSEventStreamCreateFlagFileEvents () {
38 return kFSEventStreamCreateFlagFileEvents;
40UInt32 FSEventStreamCreateFlagIgnoreSelf () {
41 return kFSEventStreamCreateFlagIgnoreSelf;
44UInt32 FSEventStreamCreateFlagFullHistory = kFSEventStreamCreateFlagFullHistory;
47/******************************************************************************
49 *****************************************************************************/
51UInt32 FSEventStreamEventFlagEventIdsWrapped () {
52 return kFSEventStreamEventFlagEventIdsWrapped;
54UInt32 FSEventStreamEventFlagMustScanSubDirs () {
55 return kFSEventStreamEventFlagMustScanSubDirs;
57UInt32 FSEventStreamEventFlagKernelDropped () {
58 return kFSEventStreamEventFlagKernelDropped;
60UInt32 FSEventStreamEventFlagUserDropped () {
61 return kFSEventStreamEventFlagUserDropped;
63UInt32 FSEventStreamEventFlagHistoryDone () {
64 return kFSEventStreamEventFlagHistoryDone;
66UInt32 FSEventStreamEventFlagRootChanged () {
67 return kFSEventStreamEventFlagRootChanged;
69UInt32 FSEventStreamEventFlagMount () {
70 return kFSEventStreamEventFlagMount;
72UInt32 FSEventStreamEventFlagUnmount () {
73 return kFSEventStreamEventFlagUnmount;
75UInt32 FSEventStreamEventFlagItemChangeOwner () {
76 return kFSEventStreamEventFlagItemChangeOwner;
78UInt32 FSEventStreamEventFlagItemInodeMetaMod () {
79 return kFSEventStreamEventFlagItemInodeMetaMod;
81UInt32 FSEventStreamEventFlagItemFinderInfoMod () {
82 return kFSEventStreamEventFlagItemFinderInfoMod;
84UInt32 FSEventStreamEventFlagItemXattrMod () {
85 return kFSEventStreamEventFlagItemXattrMod;
87UInt32 FSEventStreamEventFlagItemCreated () {
88 return kFSEventStreamEventFlagItemCreated;
90UInt32 FSEventStreamEventFlagItemRemoved () {
91 return kFSEventStreamEventFlagItemRemoved;
93UInt32 FSEventStreamEventFlagItemRenamed () {
94 return kFSEventStreamEventFlagItemRenamed;
96UInt32 FSEventStreamEventFlagItemModified () {
97 return kFSEventStreamEventFlagItemModified;
99#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101300
100UInt32 FSEventStreamEventFlagItemCloned () {
101 return kFSEventStreamEventFlagItemCloned;
104UInt32 FSEventStreamEventFlagItemIsDir () {
105 return kFSEventStreamEventFlagItemIsDir;
107UInt32 FSEventStreamEventFlagItemIsFile () {
108 return kFSEventStreamEventFlagItemIsFile;
110UInt32 FSEventStreamEventFlagItemIsSymlink () {
111 return kFSEventStreamEventFlagItemIsSymlink;
113#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
114UInt32 FSEventStreamEventFlagItemIsHardlink () {
115 return kFSEventStreamEventFlagItemIsHardlink;
118UInt32 FSEventStreamEventFlagItemIsLastHardlink () {
119 return kFSEventStreamEventFlagItemIsLastHardlink;
122/******************************************************************************
124 *****************************************************************************/
126/* Write an event to the pipe input fd */
127static void writeEvent(int fd, UInt64 eventId, UInt64 eventFlags, char* path)
132 /* XXX Is the path string in UTF-8? */
133 buf[2] = (UInt64)strlen(path);
134 write(fd, buf, 3 * sizeof(UInt64));
135 write(fd, path, strlen(path));
141 FSEventStreamRef eventStream;
142 CFRunLoopRef runLoop;
147/* Just writes the event to the pipe input fd */
148static void watchCallback
149 ( ConstFSEventStreamRef streamRef
150 , void *clientCallBackInfo
153 , const FSEventStreamEventFlags eventFlags[]
154 , const FSEventStreamEventId eventIds[]
158 struct watch *w = clientCallBackInfo;
159 char **paths = eventPaths;
161 for (i = 0; i < n; i++) {
162 writeEvent(w->writefd, eventIds[i], eventFlags[i], paths[i]);
166/******************************************************************************
167 * Start a watch event loop
168 *****************************************************************************/
170/* Event loop run in a pthread */
171static void *watchRunLoop(void *vw)
173 struct watch* w = (struct watch*) vw;
174 CFRunLoopRef rl = CFRunLoopGetCurrent();
177 FSEventStreamScheduleWithRunLoop(w->eventStream, rl, kCFRunLoopDefaultMode);
178 FSEventStreamStart(w->eventStream);
179 pthread_mutex_unlock(&w->mut);
184#define MAX_WATCH_PATHS 4096
187 ( struct pathName* folders
188 , int n /* number of entries in folders */
196 if (n > MAX_WATCH_PATHS) {
206 * XXX We can possibly use since == 0 to get all events since
210 since = kFSEventStreamEventIdSinceNow;
213 /* Setup paths array */
214 CFStringRef *cffolders = malloc(n * sizeof(CFStringRef));
216 for(i = 0; i < n; i++) {
217 cffolders[i] = CFStringCreateWithBytes
219 , folders[i].pathBytes
221 , kCFStringEncodingUTF8
225 CFArrayRef paths = CFArrayCreate(NULL, (const void **)cffolders, n, NULL);
228 struct watch *w = malloc(sizeof(struct watch));
229 FSEventStreamContext ctx;
234 ctx.copyDescription = NULL;
236 /* Create watch using paths and context*/
237 FSEventStreamRef es = FSEventStreamCreate
238 (NULL, &watchCallback, &ctx, paths, since, latency, createFlags);
240 /* Run the event loop in a pthread */
244 w->writefd = pfds[1];
248 /* Lock to prevent race against watch destroy */
249 pthread_mutex_init(&w->mut, NULL);
250 pthread_mutex_lock(&w->mut);
252 pthread_create(&t, NULL, &watchRunLoop, (void*)w);
254 /* return the out fd and the watch struct */
267 for (i = 0; i < n; i++) {
268 CFRelease (cffolders[i]);
275/******************************************************************************
276 * Stop a watch event loop
277 *****************************************************************************/
279void destroyWatch(struct watch* w) {
280 /* Stop the loop so the thread will exit */
281 pthread_mutex_lock(&w->mut);
282 FSEventStreamStop(w->eventStream);
283 FSEventStreamInvalidate(w->eventStream);
284 CFRunLoopStop(w->runLoop);
285 CFRelease(w->runLoop);
286 FSEventStreamRelease(w->eventStream);
288 pthread_mutex_unlock(&w->mut);
291 pthread_mutex_destroy(&w->mut);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list