返回 DeepSeek-Reasonix
workspace_watcher_darwin.c
根目录 / desktop / workspace_watcher_darwin.c
1 //go:build darwin && cgo
2
3 #include <CoreServices/CoreServices.h>
4 #include <dispatch/dispatch.h>
5 #include <stdint.h>
6 #include <stdlib.h>
7
8 extern void reasonixFSEventsEvent(uintptr_t token, char *path, uint32_t flags);
9
10 typedef struct reasonix_fsevents_subscription {
11 FSEventStreamRef stream;
12 dispatch_queue_t queue;
13 } reasonix_fsevents_subscription;
14
15 static void reasonix_fsevents_callback(
16 ConstFSEventStreamRef stream_ref,
17 void *callback_info,
18 size_t event_count,
19 void *event_paths,
20 const FSEventStreamEventFlags event_flags[],
21 const FSEventStreamEventId event_ids[]
22 ) {
23 (void)stream_ref;
24 (void)event_ids;
25 char **paths = event_paths;
26 uintptr_t token = (uintptr_t)callback_info;
27 for (size_t index = 0; index < event_count; index++) {
28 if (paths[index] != NULL) {
29 reasonixFSEventsEvent(token, paths[index], (uint32_t)event_flags[index]);
30 }
31 }
32 }
33
34 static void reasonix_fsevents_barrier(void *context) {
35 (void)context;
36 }
37
38 reasonix_fsevents_subscription *reasonix_fsevents_start(
39 const char *path,
40 uintptr_t token,
41 double latency,
42 int *error_code
43 ) {
44 if (error_code != NULL) {
45 *error_code = 0;
46 }
47 if (path == NULL || path[0] == '\0') {
48 if (error_code != NULL) {
49 *error_code = 1;
50 }
51 return NULL;
52 }
53
54 reasonix_fsevents_subscription *subscription = calloc(1, sizeof(*subscription));
55 if (subscription == NULL) {
56 if (error_code != NULL) {
57 *error_code = 2;
58 }
59 return NULL;
60 }
61
62 CFStringRef path_string = CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path);
63 if (path_string == NULL) {
64 if (error_code != NULL) {
65 *error_code = 1;
66 }
67 free(subscription);
68 return NULL;
69 }
70 const void *values[] = { path_string };
71 CFArrayRef paths = CFArrayCreate(kCFAllocatorDefault, values, 1, &kCFTypeArrayCallBacks);
72 CFRelease(path_string);
73 if (paths == NULL) {
74 if (error_code != NULL) {
75 *error_code = 2;
76 }
77 free(subscription);
78 return NULL;
79 }
80
81 subscription->queue = dispatch_queue_create("com.reasonix.workspace-fsevents", DISPATCH_QUEUE_SERIAL);
82 if (subscription->queue == NULL) {
83 if (error_code != NULL) {
84 *error_code = 3;
85 }
86 CFRelease(paths);
87 free(subscription);
88 return NULL;
89 }
90
91 FSEventStreamContext context = {0, (void *)token, NULL, NULL, NULL};
92 FSEventStreamCreateFlags flags = kFSEventStreamCreateFlagFileEvents |
93 kFSEventStreamCreateFlagWatchRoot |
94 kFSEventStreamCreateFlagNoDefer;
95 subscription->stream = FSEventStreamCreate(
96 kCFAllocatorDefault,
97 reasonix_fsevents_callback,
98 &context,
99 paths,
100 kFSEventStreamEventIdSinceNow,
101 latency,
102 flags
103 );
104 CFRelease(paths);
105 if (subscription->stream == NULL) {
106 if (error_code != NULL) {
107 *error_code = 4;
108 }
109 #if !OS_OBJECT_USE_OBJC
110 dispatch_release(subscription->queue);
111 #endif
112 free(subscription);
113 return NULL;
114 }
115
116 FSEventStreamSetDispatchQueue(subscription->stream, subscription->queue);
117 if (!FSEventStreamStart(subscription->stream)) {
118 if (error_code != NULL) {
119 *error_code = 5;
120 }
121 FSEventStreamInvalidate(subscription->stream);
122 FSEventStreamRelease(subscription->stream);
123 #if !OS_OBJECT_USE_OBJC
124 dispatch_release(subscription->queue);
125 #endif
126 free(subscription);
127 return NULL;
128 }
129 return subscription;
130 }
131
132 void reasonix_fsevents_stop(reasonix_fsevents_subscription *subscription) {
133 if (subscription == NULL) {
134 return;
135 }
136 FSEventStreamStop(subscription->stream);
137 FSEventStreamInvalidate(subscription->stream);
138 dispatch_sync_f(subscription->queue, NULL, reasonix_fsevents_barrier);
139 FSEventStreamRelease(subscription->stream);
140 #if !OS_OBJECT_USE_OBJC
141 dispatch_release(subscription->queue);
142 #endif
143 free(subscription);
144 }
145
145 lines C