diff --git a/Tools/xcodecapp-cocoa/AppController.m b/Tools/xcodecapp-cocoa/AppController.m index 5fef5c165..94285f7dc 100644 --- a/Tools/xcodecapp-cocoa/AppController.m +++ b/Tools/xcodecapp-cocoa/AppController.m @@ -30,6 +30,12 @@ */ - (void)awakeFromNib { +#if (ACTIVATE_DATE_BASED_MODE == 1) + NSLog(@"XCC is working using the 10.6 mode (dirty)"); +#else + NSLog(@"XCC is working using the 10.7+ mode (clean)"); +#endif + if (!growlDelegateRef) growlDelegateRef = [[[PRHEmptyGrowlDelegate alloc] init] autorelease]; @@ -219,6 +225,7 @@ - (void)updateErrorTable { [errorsTable reloadData]; + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; [errorsPanel orderFront:self]; } @@ -241,6 +248,7 @@ [helpTextView readRTFDFromFile:[[NSBundle mainBundle] pathForResource:@"help" ofType:@"rtfd"]]; [helpWindow center]; + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; [helpWindow makeKeyAndOrderFront:aSender]; } diff --git a/Tools/xcodecapp-cocoa/FSEventCallback.h b/Tools/xcodecapp-cocoa/FSEventCallback.h index cb7fd79a1..9c54b7460 100644 --- a/Tools/xcodecapp-cocoa/FSEventCallback.h +++ b/Tools/xcodecapp-cocoa/FSEventCallback.h @@ -20,6 +20,8 @@ #define xcodecapp_cocoa_FSEventCallback_h #import "TNXCodeCapp.h" +#import +#import "defines.h" void fsevents_callback(ConstFSEventStreamRef, void*, size_t, void*, const FSEventStreamEventFlags*, const FSEventStreamEventId*); diff --git a/Tools/xcodecapp-cocoa/FSEventCallback.m b/Tools/xcodecapp-cocoa/FSEventCallback.m index 26553cecd..22beb1dd0 100644 --- a/Tools/xcodecapp-cocoa/FSEventCallback.m +++ b/Tools/xcodecapp-cocoa/FSEventCallback.m @@ -18,8 +18,10 @@ #import "FSEventCallback.h" +#if (ACTIVATE_DATE_BASED_MODE == 0) + /*! - This is the FSEvent callback + This is the FSEvent callback for 10.7 */ void fsevents_callback(ConstFSEventStreamRef streamRef, void *userData, @@ -34,12 +36,6 @@ void fsevents_callback(ConstFSEventStreamRef streamRef, for(i = 0; i < numEvents; i++) { NSString *path = [(NSArray *)eventPaths objectAtIndex:i]; - - // /!\ IMPORTANT /!\ - // - // This is a test. Maybe these values where present as - // private API in 10.6, and maybe not - // If not, we will drop support for 10.6 // kFSEventStreamEventFlagItemIsFile = 0x00010000 if (!(eventFlags[i] & 0x00010000) @@ -49,14 +45,59 @@ void fsevents_callback(ConstFSEventStreamRef streamRef, // kFSEventStreamEventFlagItemRemoved = 0x00000200 if (eventFlags[i] & 0x00000200) - { [xcc handleFileRemoval:path]; - } else - { - NSLog(@"this file has been modified or created"); [xcc handleFileModification:path notify:YES]; - } + [xcc updateLastEventId:eventIds[i]]; } -} \ No newline at end of file +} + + +#else + +/*! + This is the FSEvent callback for 10.6 + */ +void fsevents_callback(ConstFSEventStreamRef streamRef, + void *userData, + size_t numEvents, + void *eventPaths, + const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[]) +{ + TNXCodeCapp *xcc = (TNXCodeCapp *)userData; + size_t i; + + for(i = 0; i < numEvents; i++) + { + NSString *path = [(NSArray *)eventPaths objectAtIndex:i]; + + // TEST on 10.7 + // BOOL isDir; + // [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir]; + // if (!isDir) + // continue; + // END TEST + + NSArray *subpaths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL]; + + for(NSString *currentPath in subpaths) + { + [xcc updateLastModificationDateForPath:currentPath]; + + currentPath = [NSString stringWithFormat:@"%@/%@", path, currentPath]; + + NSDate *lastModifiedDate = [xcc lastModificationDateForPath:currentPath]; + NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:currentPath error:nil]; + NSDate *fileModDate = [fileAttributes objectForKey:NSFileModificationDate]; + + if([fileModDate compare:lastModifiedDate] == NSOrderedDescending) + [xcc handleFileModification:currentPath notify:YES]; + + [xcc updateLastEventId:eventIds[i]]; + } + } +} + +#endif diff --git a/Tools/xcodecapp-cocoa/TNXCodeCapp.h b/Tools/xcodecapp-cocoa/TNXCodeCapp.h index 74e584017..581d1b080 100644 --- a/Tools/xcodecapp-cocoa/TNXCodeCapp.h +++ b/Tools/xcodecapp-cocoa/TNXCodeCapp.h @@ -19,6 +19,7 @@ #import #import "PRHEmptyGrowlDelegate.h" #import "FSEventCallback.h" +#import "defines.h" extern NSString * const XCCDidPopulateProjectNotification; extern NSString * const XCCConversionStartNotification; @@ -45,6 +46,11 @@ extern NSString * const XCCListeningStartNotification; NSURL *XCodeSupportProjectSources; PRHEmptyGrowlDelegate *growlDelegateRef; NSObject *delegate; + NSDate *appStartedTimestamp; + +#if (ACTIVATE_DATE_BASED_MODE == 1) + NSMutableDictionary *pathModificationDates; +#endif } @property (retain) NSObject* delegate; @@ -69,5 +75,15 @@ extern NSString * const XCCListeningStartNotification; - (void)clear; - (void)start; +@end + + +#if (ACTIVATE_DATE_BASED_MODE == 1) +@interface TNXCodeCapp (SnowLeopard) + +- (void)updateLastModificationDateForPath:(NSString *)path; +- (NSDate*)lastModificationDateForPath:(NSString *)path; @end +#endif + diff --git a/Tools/xcodecapp-cocoa/TNXCodeCapp.m b/Tools/xcodecapp-cocoa/TNXCodeCapp.m index 8240cdaec..30753c269 100644 --- a/Tools/xcodecapp-cocoa/TNXCodeCapp.m +++ b/Tools/xcodecapp-cocoa/TNXCodeCapp.m @@ -46,6 +46,7 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification ignoredFilePaths = [NSMutableArray new]; parserPath = [[NSBundle mainBundle] pathForResource:@"parser" ofType:@"j"]; lastEventId = [[NSUserDefaults standardUserDefaults] objectForKey:@"lastEventId"]; + appStartedTimestamp = [NSDate date]; if([fm fileExistsAtPath:[@"~/.bash_profile" stringByExpandingTildeInPath]]) profilePath = [@"source ~/.bash_profile" stringByExpandingTildeInPath]; @@ -101,9 +102,11 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification NSTimeInterval latency = 2.0; free(stream); + + NSLog(@"Initializing the FSEventStream at file level (clean)"); stream = FSEventStreamCreate(NULL, &fsevents_callback, &context, (CFArrayRef) pathsToWatch, [lastEventId unsignedLongLongValue], (CFAbsoluteTime) latency, kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagNoDefer | 0x00000010 ); - + FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); FSEventStreamStart(stream); } @@ -506,3 +509,52 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification } @end + + +#if (ACTIVATE_DATE_BASED_MODE == 1) +@implementation TNXCodeCapp (SnowLeopard) + +- (void)initializeEventStreamWithPath:(NSString*)aPath +{ + NSArray *pathsToWatch = [NSArray arrayWithObject:aPath]; + void *appPointer = (void *)self; + FSEventStreamContext context = {0, appPointer, NULL, NULL, NULL}; + NSTimeInterval latency = 2.0; + free(stream); + NSLog(@"Initializing the FSEventStream at folder level (dirty)"); + stream = FSEventStreamCreate(NULL, &fsevents_callback, &context, (CFArrayRef) pathsToWatch, + [lastEventId unsignedLongLongValue], (CFAbsoluteTime) latency, kFSEventStreamCreateFlagUseCFTypes); + + FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + FSEventStreamStart(stream); +} + +- (void)updateLastModificationDateForPath:(NSString *)path +{ + if (!pathModificationDates) + { + pathModificationDates = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"pathModificationDates"] mutableCopy]; + if (!pathModificationDates) + pathModificationDates = [NSMutableDictionary new]; + } + + [pathModificationDates setObject:[NSDate date] forKey:path]; + [[NSUserDefaults standardUserDefaults] setObject:pathModificationDates forKey:@"pathModificationDates"]; +} + +- (NSDate*)lastModificationDateForPath:(NSString *)path +{ + if (!pathModificationDates) + { + pathModificationDates = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"pathModificationDates"] mutableCopy]; + if (!pathModificationDates) + pathModificationDates = [NSMutableDictionary new]; + } + + if([pathModificationDates valueForKey:path] != nil) + return [pathModificationDates valueForKey:path]; + else + return appStartedTimestamp; +} +@end +#endif diff --git a/Tools/xcodecapp-cocoa/defines.h b/Tools/xcodecapp-cocoa/defines.h new file mode 100644 index 000000000..a586296ce --- /dev/null +++ b/Tools/xcodecapp-cocoa/defines.h @@ -0,0 +1,18 @@ +// +// defines.h +// xcodecapp-cocoa +// +// Created by Antoine Mercadal on 04/11/11. +// Copyright (c) 2011 __MyCompanyName__. All rights reserved. +// + +#ifndef xcodecapp_cocoa_defines_h +#define xcodecapp_cocoa_defines_h + +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7) +#define ACTIVATE_DATE_BASED_MODE 0 +#else +#define ACTIVATE_DATE_BASED_MODE 1 +#endif + +#endif diff --git a/Tools/xcodecapp-cocoa/xcodecapp-cocoa.xcodeproj/project.pbxproj b/Tools/xcodecapp-cocoa/xcodecapp-cocoa.xcodeproj/project.pbxproj index 5bae6fd9d..c9c499b17 100644 --- a/Tools/xcodecapp-cocoa/xcodecapp-cocoa.xcodeproj/project.pbxproj +++ b/Tools/xcodecapp-cocoa/xcodecapp-cocoa.xcodeproj/project.pbxproj @@ -59,6 +59,7 @@ 027FE4BC1462F7EB00B1AB92 /* FSEventCallback.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSEventCallback.m; sourceTree = ""; }; 02998CEA1369BF7D006C73DB /* Growl Registration Ticket.growlRegDict */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "Growl Registration Ticket.growlRegDict"; sourceTree = ""; }; 02998CF61369C339006C73DB /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Growl.framework; sourceTree = ""; }; + 02D00BD514635F9B0071080E /* defines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = defines.h; sourceTree = ""; }; 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; @@ -99,6 +100,7 @@ 027FE49C1462D74C00B1AB92 /* TNXCodeCapp.m */, 027FE4BB1462F7D600B1AB92 /* FSEventCallback.h */, 027FE4BC1462F7EB00B1AB92 /* FSEventCallback.m */, + 02D00BD514635F9B0071080E /* defines.h */, ); name = Classes; sourceTree = "";