OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
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 #include "game/C4Application.h"
21 
22 #include "platform/StdFile.h"
23 
24 #import <Foundation/Foundation.h>
25 
26 // Implementation using FSEvents
27 
28 C4FileMonitor::C4FileMonitor(ChangeNotify pCallback): fStarted(false), pCallback(pCallback)
29 {
30  eventStream = NULL;
31  context.version = 0;
32  context.info = this;
33  context.retain = NULL;
34  context.release = NULL;
35  context.copyDescription = NULL;
36  setObjectiveCObject([NSMutableArray arrayWithCapacity:10]);
37 }
38 
40 {
41  if (fStarted)
42  StopStream();
43 }
44 
45 static void FSEvents_Callback(
46  ConstFSEventStreamRef streamRef,
47  void *clientCallBackInfo,
48  size_t numEvents,
49  void *eventPaths,
50  const FSEventStreamEventFlags eventFlags[],
51  const FSEventStreamEventId eventIds[])
52 {
53  // FSEvents only tells us about directories in which some files were modified
54  char** paths = (char**)eventPaths;
55  C4FileMonitor* mon = (C4FileMonitor*)clientCallBackInfo;
56  for (unsigned int i = 0; i < numEvents; i++)
57  {
58  NSString* dir = [NSString stringWithUTF8String:paths[i]];
59  NSArray* filesInDir = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:dir error:NULL];
60  for (NSString* str in filesInDir)
61  {
62  NSString* fullPath = [dir stringByAppendingPathComponent:str];
63  NSDictionary* attribs = [[NSFileManager defaultManager] attributesOfItemAtPath:fullPath error:NULL];
64  NSDate* modified = [attribs fileModificationDate];
65  if (modified && -[modified timeIntervalSinceNow] <= 3.0)
66  mon->OnThreadEvent(Ev_FileChange, (void*)[fullPath UTF8String]);
67  }
68  }
69 }
70 
71 void C4FileMonitor::StartStream()
72 {
73  eventStream = FSEventStreamCreate(kCFAllocatorDefault, &FSEvents_Callback, &context, (__bridge CFArrayRef)objectiveCObject<NSMutableArray>(), kFSEventStreamEventIdSinceNow, 0.3,
74  kFSEventStreamCreateFlagNone);
75  FSEventStreamScheduleWithRunLoop(eventStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
76  FSEventStreamStart(eventStream);
77 }
78 
79 void C4FileMonitor::StopStream()
80 {
81  if (fStarted)
82  {
83  fStarted = false;
84  FSEventStreamStop(eventStream);
85  FSEventStreamInvalidate(eventStream);
86  FSEventStreamRelease(eventStream);
87  }
88 }
89 
91 {
92  StartStream();
93  fStarted = true;
94 }
95 
96 void C4FileMonitor::AddDirectory(const char *szDir)
97 {
98  NSString* path = [NSString stringWithUTF8String:szDir];
99  NSString* fullPath = [path characterAtIndex:0] == '/'
100  ? path
101  : [NSString stringWithFormat:@"%@/%@", [[NSFileManager defaultManager] currentDirectoryPath], path];
102  [objectiveCObject<NSMutableArray>() addObject:fullPath];
103 }
104 
105 void C4FileMonitor::OnThreadEvent(C4InteractiveEventType eEvent, void* pEventData)
106 {
107  if (eEvent != Ev_FileChange) return;
108  pCallback((const char *)pEventData, 0);
109 }
110 
111 void C4FileMonitor::GetFDs(std::vector<struct pollfd> & FDs) { }
112 
113 bool C4FileMonitor::Execute(int iTimeout, pollfd *) { return true; }
114 
115 #endif
void AddDirectory(const char *szDir)
void StartMonitoring()
virtual bool Execute(int iTimeout=-1, pollfd *=0)
C4InteractiveEventType
C4FileMonitor(ChangeNotify pCallback)
virtual void OnThreadEvent(C4InteractiveEventType eEvent, void *pEventData)
virtual void GetFDs(std::vector< struct pollfd > &FDs)