OpenClonk
C4FileMonitorMac.mm
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2010-2016, The OpenClonk Team and contributors
5  *
6  * Distributed under the terms of the ISC license; see accompanying file
7  * "COPYING" for details.
8  *
9  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
10  * See accompanying file "TRADEMARK" for details.
11  *
12  * To redistribute this file separately, substitute the full license texts
13  * for the above references.
14  */
15 
16 #ifdef __APPLE__
17 
18 #include "C4Include.h"
19 #include "platform/C4FileMonitor.h"
20 
21 #include "game/C4Application.h"
22 
23 #import <Foundation/Foundation.h>
24 
25 // Implementation using FSEvents
26 
27 C4FileMonitor::C4FileMonitor(ChangeNotify pCallback): fStarted(false), pCallback(pCallback)
28 {
29  eventStream = NULL;
30  context.version = 0;
31  context.info = this;
32  context.retain = NULL;
33  context.release = NULL;
34  context.copyDescription = NULL;
35  setObjectiveCObject([NSMutableArray arrayWithCapacity:10]);
36 }
37 
39 {
40  if (fStarted)
41  StopStream();
42 }
43 
44 static void FSEvents_Callback(
45  ConstFSEventStreamRef streamRef,
46  void *clientCallBackInfo,
47  size_t numEvents,
48  void *eventPaths,
49  const FSEventStreamEventFlags eventFlags[],
50  const FSEventStreamEventId eventIds[])
51 {
52  // FSEvents only tells us about directories in which some files were modified
53  char** paths = (char**)eventPaths;
54  C4FileMonitor* mon = (C4FileMonitor*)clientCallBackInfo;
55  for (unsigned int i = 0; i < numEvents; i++)
56  {
57  NSString* dir = [NSString stringWithUTF8String:paths[i]];
58  NSArray* filesInDir = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dir error:NULL];
59  for (NSString* str in filesInDir)
60  {
61  NSString* fullPath = [dir stringByAppendingPathComponent:str];
62  NSDictionary* attribs = [[NSFileManager defaultManager] attributesOfItemAtPath:fullPath error:NULL];
63  NSDate* modified = [attribs fileModificationDate];
64  if (modified && -[modified timeIntervalSinceNow] <= 3.0)
65  mon->OnThreadEvent(Ev_FileChange, (void*)[fullPath UTF8String]);
66  }
67  }
68 }
69 
70 void C4FileMonitor::StartStream()
71 {
72  eventStream = FSEventStreamCreate(kCFAllocatorDefault, &FSEvents_Callback, &context, (__bridge CFArrayRef)objectiveCObject<NSMutableArray>(), kFSEventStreamEventIdSinceNow, 0.3,
73  kFSEventStreamCreateFlagNone);
74  FSEventStreamScheduleWithRunLoop(eventStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
75  FSEventStreamStart(eventStream);
76 }
77 
78 void C4FileMonitor::StopStream()
79 {
80  if (fStarted)
81  {
82  fStarted = false;
83  FSEventStreamStop(eventStream);
84  FSEventStreamInvalidate(eventStream);
85  FSEventStreamRelease(eventStream);
86  }
87 }
88 
90 {
91  StartStream();
92  fStarted = true;
93 }
94 
95 void C4FileMonitor::AddDirectory(const char *szDir)
96 {
97  NSString* path = [NSString stringWithUTF8String:szDir];
98  NSString* fullPath = [path characterAtIndex:0] == '/'
99  ? path
100  : [NSString stringWithFormat:@"%@/%@", [[NSFileManager defaultManager] currentDirectoryPath], path];
101  [objectiveCObject<NSMutableArray>() addObject:fullPath];
102 }
103 
104 void C4FileMonitor::OnThreadEvent(C4InteractiveEventType eEvent, void* pEventData)
105 {
106  if (eEvent != Ev_FileChange) return;
107  pCallback((const char *)pEventData, 0);
108 }
109 
110 void C4FileMonitor::GetFDs(std::vector<struct pollfd> & FDs) { }
111 
112 bool C4FileMonitor::Execute(int iTimeout, pollfd *) { return true; }
113 
114 #endif
C4InteractiveEventType
@ Ev_FileChange
void GetFDs(std::vector< struct pollfd > &FDs) override
void StartMonitoring()
void OnThreadEvent(C4InteractiveEventType eEvent, void *pEventData) override
bool Execute(int iTimeout=-1, pollfd *=nullptr) override
~C4FileMonitor() override
void AddDirectory(const char *szDir)
C4FileMonitor(ChangeNotify pCallback)