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 27C4FileMonitor::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 38C4FileMonitor::~C4FileMonitor() 39{ 40 if (fStarted) 41 StopStream(); 42} 43 44static 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 70void 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 78void C4FileMonitor::StopStream() 79{ 80 if (fStarted) 81 { 82 fStarted = false; 83 FSEventStreamStop(eventStream); 84 FSEventStreamInvalidate(eventStream); 85 FSEventStreamRelease(eventStream); 86 } 87} 88 89void C4FileMonitor::StartMonitoring() 90{ 91 StartStream(); 92 fStarted = true; 93} 94 95void 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 104void C4FileMonitor::OnThreadEvent(C4InteractiveEventType eEvent, void* pEventData) 105{ 106 if (eEvent != Ev_FileChange) return; 107 pCallback((const char *)pEventData, 0); 108} 109 110void C4FileMonitor::GetFDs(std::vector<struct pollfd> & FDs) { } 111 112bool C4FileMonitor::Execute(int iTimeout, pollfd *) { return true; } 113 114#endif 115