diff --git a/Anvil.xcodeproj/project.pbxproj b/Anvil.xcodeproj/project.pbxproj index bbad1e3..3f72fd6 100644 --- a/Anvil.xcodeproj/project.pbxproj +++ b/Anvil.xcodeproj/project.pbxproj @@ -11,6 +11,7 @@ 4F0B716216234A82007246F9 /* index.html in Resources */ = {isa = PBXBuildFile; fileRef = 4F0B716116234A82007246F9 /* index.html */; }; 4F0DA4BA1609CED500D21ABE /* BFImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F0DA4B81609CED500D21ABE /* BFImage.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 4F107C681610CF0E00624611 /* InstallPow.sh in Resources */ = {isa = PBXBuildFile; fileRef = 4F107C671610CF0E00624611 /* InstallPow.sh */; }; + 4F1247F11916D98400F1C105 /* CDEvents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F1247F01916D98400F1C105 /* CDEvents.framework */; }; 4F2CCA10176384060010AB4B /* NVGroupHeaderTableCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F2CCA0F176384060010AB4B /* NVGroupHeaderTableCellView.m */; }; 4F361366160C9816008584A0 /* NVPopupButtonCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4F361365160C9816008584A0 /* NVPopupButtonCell.m */; }; 4F4AFFED1778AACF0081BBD3 /* Anvil.icns in Resources */ = {isa = PBXBuildFile; fileRef = 4F4AFFEC1778AACF0081BBD3 /* Anvil.icns */; }; @@ -85,7 +86,7 @@ 4FB9E81216061096005B50A4 /* NVTableRowView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FB9E81116061096005B50A4 /* NVTableRowView.m */; }; 4FB9E815160610A1005B50A4 /* NVTableCellView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4FB9E814160610A1005B50A4 /* NVTableCellView.m */; }; 4FBABB051613442200D4174B /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4FBABB041613442200D4174B /* Sparkle.framework */; }; - 4FBABB081613443A00D4174B /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4FBABB041613442200D4174B /* Sparkle.framework */; }; + 4FBABB081613443A00D4174B /* Sparkle.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 4FBABB041613442200D4174B /* Sparkle.framework */; }; 4FBABB0A161344D600D4174B /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = 4FBABB09161344D600D4174B /* dsa_pub.pem */; }; 4FBFA35B15C6F85800BA8209 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4FBFA35A15C6F85800BA8209 /* Cocoa.framework */; }; 4FBFA36515C6F85800BA8209 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 4FBFA36315C6F85800BA8209 /* InfoPlist.strings */; }; @@ -109,14 +110,15 @@ /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ - 4FBABB071613443100D4174B /* CopyFiles */ = { + 4FBABB071613443100D4174B /* Copy Files */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( - 4FBABB081613443A00D4174B /* Sparkle.framework in CopyFiles */, + 4FBABB081613443A00D4174B /* Sparkle.framework in Copy Files */, ); + name = "Copy Files"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ @@ -128,6 +130,7 @@ 4F0DA4B81609CED500D21ABE /* BFImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BFImage.m; sourceTree = ""; }; 4F0DA4B91609CED500D21ABE /* BFImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BFImage.h; sourceTree = ""; }; 4F107C671610CF0E00624611 /* InstallPow.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = InstallPow.sh; sourceTree = ""; }; + 4F1247F01916D98400F1C105 /* CDEvents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CDEvents.framework; sourceTree = ""; }; 4F2CCA0E176384060010AB4B /* NVGroupHeaderTableCellView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NVGroupHeaderTableCellView.h; sourceTree = ""; }; 4F2CCA0F176384060010AB4B /* NVGroupHeaderTableCellView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NVGroupHeaderTableCellView.m; sourceTree = ""; }; 4F361364160C9816008584A0 /* NVPopupButtonCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NVPopupButtonCell.h; sourceTree = ""; }; @@ -269,6 +272,7 @@ files = ( 4FAB52731611D78400BD03F8 /* QuartzCore.framework in Frameworks */, 4FBFA35B15C6F85800BA8209 /* Cocoa.framework in Frameworks */, + 4F1247F11916D98400F1C105 /* CDEvents.framework in Frameworks */, 4FBABB051613442200D4174B /* Sparkle.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -483,6 +487,7 @@ 4FBFA35915C6F85800BA8209 /* Frameworks */ = { isa = PBXGroup; children = ( + 4F1247F01916D98400F1C105 /* CDEvents.framework */, 4FBABB041613442200D4174B /* Sparkle.framework */, 4FBFA35A15C6F85800BA8209 /* Cocoa.framework */, 4FBFA35C15C6F85800BA8209 /* Other Frameworks */, @@ -694,7 +699,7 @@ 4FBFA35215C6F85800BA8209 /* Sources */, 4FBFA35315C6F85800BA8209 /* Frameworks */, 4FBFA35415C6F85800BA8209 /* Resources */, - 4FBABB071613443100D4174B /* CopyFiles */, + 4FBABB071613443100D4174B /* Copy Files */, ); buildRules = ( ); @@ -934,7 +939,8 @@ COMBINE_HIDPI_IMAGES = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)\"", + "$(SRCROOT)", + "$(PROJECT_DIR)", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Anvil/Anvil-Prefix.pch"; @@ -953,7 +959,8 @@ COMBINE_HIDPI_IMAGES = NO; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "\"$(SRCROOT)\"", + "$(SRCROOT)", + "$(PROJECT_DIR)", ); GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Anvil/Anvil-Prefix.pch"; diff --git a/Anvil/NVAppDelegate.m b/Anvil/NVAppDelegate.m index c809129..4f3ada6 100644 --- a/Anvil/NVAppDelegate.m +++ b/Anvil/NVAppDelegate.m @@ -50,9 +50,9 @@ - (void)applicationDidFinishLaunching:(NSNotification *)notification { // Initialize it [self panelController]; - NSTimer *mainLoopTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(readSites) userInfo:nil repeats:YES]; - [[NSRunLoop currentRunLoop] addTimer:mainLoopTimer forMode:NSEventTrackingRunLoopMode]; - +// NSTimer *mainLoopTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(readSites) userInfo:nil repeats:YES]; +// [[NSRunLoop currentRunLoop] addTimer:mainLoopTimer forMode:NSEventTrackingRunLoopMode]; + // Todo: open window (unless the computer's just started up) } diff --git a/Anvil/NVDataSource.m b/Anvil/NVDataSource.m index ba235d7..7f46fac 100644 --- a/Anvil/NVDataSource.m +++ b/Anvil/NVDataSource.m @@ -10,9 +10,12 @@ // It uses two separate arrays: apps and hammerApps. #import "NVDataSource.h" +#import @interface NVDataSource () +@property (strong, atomic) CDEvents *powEvents; +@property (strong, atomic) CDEvents *hammerEvents; @property (strong, readwrite, nonatomic) NSMutableArray *apps; @property (strong, readwrite, nonatomic) NSMutableArray *hammerApps; @property (strong, nonatomic) NSFileManager *fileManager; @@ -40,6 +43,8 @@ - (id)init { if (!self.fileManager) self.fileManager = [NSFileManager defaultManager]; if (!self.apps) self.apps = [[NSMutableArray alloc] init]; if (!self.hammerApps) self.hammerApps = [[NSMutableArray alloc] init]; + + [self startWatching]; } return self; @@ -179,7 +184,7 @@ - (void)importNewHammerSites { NSMutableArray *appsToRemove = [[NSMutableArray alloc] init]; NSMutableArray *urlsAdded = [[NSMutableArray alloc] init]; - for (NVApp *app in self.hammerApps) { + for (NVApp *app in [self.hammerApps copy]) { BOOL found = NO; int i = 0; @@ -402,4 +407,39 @@ - (NSInteger *)numberOfHammerSites { return self.hammerApps.count; } +#pragma mark - FSEvents + +- (void)startWatching { + + NSString *hammerPath = [[@"~/Library/Containers/com.riot.hammer/Data/Library/Application Support/Riot/Hammer/AppData/Apps.plist" stringByExpandingTildeInPath] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + NSURL *hammerURL = [NSURL URLWithString:hammerPath]; + NSArray *hammerURLs = [[NSMutableArray alloc] initWithObjects:hammerURL, nil]; + CDEvents *hammerEvents = [[CDEvents alloc] initWithURLs:hammerURLs block:^(CDEvents *watcher, CDEvent *event) { + + [self clearOldHammerSymlinks]; + [self importNewHammerSites]; + } onRunLoop:[NSRunLoop mainRunLoop] + sinceEventIdentifier:kFSEventStreamEventIdSinceNow + notificationLantency:0.5 + ignoreEventsFromSubDirs:NO + excludeURLs:@[] + streamCreationFlags:kCDEventsDefaultEventStreamFlags|kFSEventStreamCreateFlagFileEvents]; + self.hammerEvents = hammerEvents; + + NSString *powPath = [@"~/.pow/" stringByExpandingTildeInPath]; + NSURL *powURL = [NSURL URLWithString:powPath]; + NSArray *urls = [[NSMutableArray alloc] initWithObjects:powURL, nil]; + CDEvents *powEvents = [[CDEvents alloc] initWithURLs:urls block:^(CDEvents *watcher, CDEvent *event) { + + [self importFromPowdirectory]; + } onRunLoop:[NSRunLoop mainRunLoop] + sinceEventIdentifier:kFSEventStreamEventIdSinceNow + notificationLantency:0.5 + ignoreEventsFromSubDirs:NO + excludeURLs:@[] + streamCreationFlags:kCDEventsDefaultEventStreamFlags|kFSEventStreamCreateFlagFileEvents]; + + self.powEvents = powEvents; +} + @end \ No newline at end of file diff --git a/Anvil/NVPanelController.m b/Anvil/NVPanelController.m index 06fe86d..16e2c31 100644 --- a/Anvil/NVPanelController.m +++ b/Anvil/NVPanelController.m @@ -149,7 +149,7 @@ - (void)awakeFromNib { self.powCheckerTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(switchSwitchViewToPowStatus) userInfo:nil repeats:YES]; [[NSRunLoop mainRunLoop] addTimer:self.powCheckerTimer forMode:NSRunLoopCommonModes]; - + // Draw it off-screen sure // [self.window setFrameOrigin:NSMakePoint(10000, 10000)]; // [self.window makeKeyAndOrderFront:nil]; diff --git a/CDEvents.framework/CDEvents b/CDEvents.framework/CDEvents new file mode 120000 index 0000000..92fee1b --- /dev/null +++ b/CDEvents.framework/CDEvents @@ -0,0 +1 @@ +Versions/Current/CDEvents \ No newline at end of file diff --git a/CDEvents.framework/Headers b/CDEvents.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/CDEvents.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/CDEvents.framework/Resources b/CDEvents.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/CDEvents.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/CDEvents.framework/Versions/A/CDEvents b/CDEvents.framework/Versions/A/CDEvents new file mode 100755 index 0000000..90b145e Binary files /dev/null and b/CDEvents.framework/Versions/A/CDEvents differ diff --git a/CDEvents.framework/Versions/A/Headers/CDEvent.h b/CDEvents.framework/Versions/A/Headers/CDEvent.h new file mode 100755 index 0000000..d26f3bf --- /dev/null +++ b/CDEvents.framework/Versions/A/Headers/CDEvent.h @@ -0,0 +1,408 @@ +/** + * CDEvents + * + * Copyright (c) 2010-2012 Aron Cedercrantz + * http://github.com/rastersize/CDEvents/ + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @headerfile CDEvent.h CDEvents/CDEvent.h + * A class that wraps the data from a FSEvents event callback. + * + * A class that wraps the data from a FSEvents event callback. Inspired and + * based upon the open source project SCEvents created by Stuart Connolly + * http://stuconnolly.com/projects/code/ + */ + +#import +#import + +#pragma mark - +#pragma mark CDEvent types +/** + * The event identifier type. + * + * @since 1.0.0 + */ +typedef FSEventStreamEventId CDEventIdentifier; + +/** + * The event stream event flags type. + * + * @since 1.0.1 + */ +typedef FSEventStreamEventFlags CDEventFlags; + + +#pragma mark - +#pragma mark CDEvent interface +/** + * An Objective-C wrapper for a FSEvents event data. + * + * @note Inspired by SCEvent class of the SCEvents project by Stuart Connolly. + * @note The class is immutable. + * + * @see FSEvents.h in CoreServices + * + * @since 1.0.0 + */ +@interface CDEvent : NSObject {} + +#pragma mark Properties +/** @name Getting Event Properties */ +/** + * The event identifier. + * + * The event identifier as returned by FSEvents. + * + * @return The event identifier. + * + * @since 1.0.0 + */ +@property (readonly) CDEventIdentifier identifier; + +/** + * An approximate date and time the event occured. + * + * @return The approximate date and time the event occured. + * + * @since 1.0.0 + */ +@property (strong, readonly) NSDate *date; + +/** + * The URL of the item which changed. + * + * @return The URL of the item which changed. + * + * @since 1.0.0 + */ +@property (strong, readonly) NSURL *URL; + + +/** @name Getting Event Flags */ +/** + * The flags of the event. + * + * The flags of the event as returned by FSEvents. + * + * @return The flags of the event. + * + * @see FSEventStreamEventFlags + * + * @since 1.0.0 + */ +@property (readonly) CDEventFlags flags; + +#pragma mark Specific flag properties +/** + * Wheter there was some change in the directory at the specific path supplied in this event. + * + * @return YES if there was some change in the directory, otherwise NO. + * + * @see kFSEventStreamEventFlagNone + * @see flags + * @see mustRescanSubDirectories + * @see isUserDropped + * @see isKernelDropped + * @see isEventIdentifiersWrapped + * @see isHistoryDone + * @see isRootChanged + * @see didVolumeMount + * @see didVolumeUnmount + * + * @since 1.1.0 + */ +@property (readonly) BOOL isGenericChange; + +/** + * Wheter you must rescan the whole URL including its children. + * + * Wheter your application must rescan not just the URL given in the event, but + * all its children, recursively. This can happen if there was a problem whereby + * events were coalesced hierarchically. For example, an event in + * /Users/jsmith/Music and an event in + * /Users/jsmith/Pictures might be coalesced into an event with + * this flag set and URL = /Users/jsmith. If this flag is set + * you may be able to get an idea of whether the bottleneck happened in the + * kernel (less likely) or in your client (more likely) by checking if + * isUserDropped or isKernelDropped returns YES. + * + * @return YES if you must rescan the whole directory including its children, otherwise NO. + * + * @see kFSEventStreamEventFlagMustScanSubDirs + * @see flags + * @see isGenericChange + * @see isUserDropped + * @see isKernelDropped + * @see isEventIdentifiersWrapped + * @see isHistoryDone + * @see isRootChanged + * @see didVolumeMount + * @see didVolumeUnmount + * + * @since 1.1.0 + */ +@property (readonly) BOOL mustRescanSubDirectories; + +/** + * Provides some information as to what might have caused the need to rescan the URL including its children. + * + * @return YES if mustRescanSubDirectories returns YES and the cause were in userland, otherwise NO. + * + * @see kFSEventStreamEventFlagUserDropped + * @see flags + * @see isGenericChange + * @see mustRescanSubDirectories + * @see isKernelDropped + * @see isEventIdentifiersWrapped + * @see isHistoryDone + * @see isRootChanged + * @see didVolumeMount + * @see didVolumeUnmount + * + * @since 1.1.0 + */ +@property (readonly) BOOL isUserDropped; + +/** + * Provides some information as to what might have caused the need to rescan the URL including its children. + * + * @return YES if mustRescanSubDirectories returns YES and the cause were in kernelspace, otherwise NO. + * + * @see kFSEventStreamEventFlagKernelDropped + * @see flags + * @see isGenericChange + * @see mustRescanSubDirectories + * @see isUserDropped + * @see isEventIdentifiersWrapped + * @see isHistoryDone + * @see isRootChanged + * @see didVolumeMount + * @see didVolumeUnmount + * + * @since 1.1.0 + */ +@property (readonly) BOOL isKernelDropped; + +/** + * Wheter the 64-bit event identifier counter has wrapped around. + * + * Wheter the 64-bit event identifier counter has wrapped around. As a result, + * previously-issued event identifiers are no longer valid arguments for the + * sinceEventIdentifier parameter of the CDEvents init methods. + * + * @return YES if the 64-bit event identifier counter has wrapped around, otherwise NO. + * + * @see kFSEventStreamEventFlagEventIdsWrapped + * @see flags + * @see isGenericChange + * @see mustRescanSubDirectories + * @see isUserDropped + * @see isKernelDropped + * @see isHistoryDone + * @see isRootChanged + * @see didVolumeMount + * @see didVolumeUnmount + * + * @since 1.1.0 + */ +@property (readonly) BOOL isEventIdentifiersWrapped; + +/** + * Denotes a sentinel event sent to mark the end of the "historical" events sent. + * + * Denotes a sentinel event sent to mark the end of the "historical" events sent + * as a result of specifying a sinceEventIdentifier argument other than + * kCDEventsSinceEventNow with the CDEvents init methods. + * + * @return YES if if the event is sent to mark the end of the "historical" events sent, otherwise NO. + * + * @see kFSEventStreamEventFlagHistoryDone + * @see flags + * @see isGenericChange + * @see mustRescanSubDirectories + * @see isUserDropped + * @see isKernelDropped + * @see isEventIdentifiersWrapped + * @see isRootChanged + * @see didVolumeMount + * @see didVolumeUnmount + * @see kCDEventsSinceEventNow + * @see CDEvents + * + * @since 1.1.0 + */ +@property (readonly) BOOL isHistoryDone; + +/** + * Denotes a special event sent when there is a change to one of the URLs you asked to watch. + * + * Denotes a special event sent when there is a change to one of the URLs you + * asked to watch. When this method returns YES, the event + * identifier is zero and the URL corresponds to one of the URLs + * you asked to watch (specifically, the one that changed). The URL may no + * longer exist because it or one of its parents was deleted or renamed. Events + * with this flag set will only be sent if you passed the flag + * kFSEventStreamCreateFlagWatchRoot to the CDEvents. + * + * @return YES if there is a change to one of the URLs you asked to watch, otherwise NO. + * + * @see kFSEventStreamEventFlagRootChanged + * @see flags + * @see isGenericChange + * @see mustRescanSubDirectories + * @see isUserDropped + * @see isKernelDropped + * @see isEventIdentifiersWrapped + * @see isHistoryDone + * @see didVolumeMount + * @see didVolumeUnmount + * @see CDEvents + * @see kCDEventsDefaultEventStreamFlags + * + * @since 1.1.0 + */ +@property (readonly) BOOL isRootChanged; + +/** + * Denotes a special event sent when a volume is mounted underneath one of the URLs being watched. + * + * Denotes a special event sent when a volume is mounted underneath one of the + * URLs being watched. The URL in the event is the URL to the newly-mounted + * volume. You will receive one of these notifications for every volume mount + * event inside the kernel (independent of DiskArbitration). Beware that a + * newly-mounted volume could contain an arbitrarily large directory hierarchy. + * Avoid pitfalls like triggering a recursive scan of a non-local filesystem, + * which you can detect by checking for the absence of the + * MNT_LOCAL flag in the f_flags returned by statfs(). + * Also be aware of the MNT_DONTBROWSE flag that is set for volumes + * which should not be displayed by user interface elements. + * + * @return YES if a volumen is mounted underneath one of the URLs being watched, otherwise NO. + * + * @see kFSEventStreamEventFlagMount + * @see flags + * @see isGenericChange + * @see mustRescanSubDirectories + * @see isUserDropped + * @see isKernelDropped + * @see isEventIdentifiersWrapped + * @see isHistoryDone + * @see isRootChanged + * @see didVolumeUnmount + * + * @since 1.1.0 + */ +@property (readonly) BOOL didVolumeMount; + +/** + * Denotes a special event sent when a volume is unmounted underneath one of the URLs being watched. + * + * Denotes a special event sent when a volume is unmounted underneath one of the + * URLs being watched. The URL in the event is the URL to the directory from + * which the volume was unmounted. You will receive one of these notifications + * for every volume unmount event inside the kernel. This is not a substitute + * for the notifications provided by the DiskArbitration framework; you only get + * notified after the unmount has occurred. Beware that unmounting a volume + * could uncover an arbitrarily large directory hierarchy, although Mac OS X + * never does that. + * + * @return YES if a volume is unmounted underneath one of the URLs being watched, otherwise NO. + * + * @see kFSEventStreamEventFlagUnmount + * @see flags + * @see isGenericChange + * @see mustRescanSubDirectories + * @see isUserDropped + * @see isKernelDropped + * @see isEventIdentifiersWrapped + * @see isHistoryDone + * @see isRootChanged + * @see didVolumeMount + * + * @since 1.1.0 + */ +@property (readonly) BOOL didVolumeUnmount; + + +/** + * The entirety of the documentation on file level events in lion is 3 sentences + * long. Rename behavior is odd, making the combination of events and flags + * somewhat confusing for atomic writes. It also appears possible to get a + * singular event where a file has been created, modified, and removed. + */ +@property (readonly) BOOL isCreated; +@property (readonly) BOOL isRemoved; +@property (readonly) BOOL isInodeMetadataModified; +@property (readonly) BOOL isRenamed; +@property (readonly) BOOL isModified; +@property (readonly) BOOL isFinderInfoModified; +@property (readonly) BOOL didChangeOwner; +@property (readonly) BOOL isXattrModified; +@property (readonly) BOOL isFile; +@property (readonly) BOOL isDir; +@property (readonly) BOOL isSymlink; + +#pragma mark Class object creators +/** @name Creating CDEvent Objects */ +/** + * Returns an CDEvent created with the given identifier, date, URL and flags. + * + * @param identifier The identifier of the the event. + * @param date The date when the event occured. + * @param URL The URL of the item the event concerns. + * @param flags The flags of the event. + * @return An CDEvent created with the given identifier, date, URL and flags. + * + * @see FSEventStreamEventFlags + * @see initWithIdentifier:date:URL:flags: + * + * @since 1.0.0 + */ ++ (CDEvent *)eventWithIdentifier:(NSUInteger)identifier + date:(NSDate *)date + URL:(NSURL *)URL + flags:(CDEventFlags)flags; + +#pragma mark Init methods +/** + * Returns an CDEvent object initialized with the given identifier, date, URL and flags. + * + * @param identifier The identifier of the the event. + * @param date The date when the event occured. + * @param URL The URL of the item the event concerns. + * @param flags The flags of the event. + * @return An CDEvent object initialized with the given identifier, date, URL and flags. + * @see FSEventStreamEventFlags + * @see eventWithIdentifier:date:URL:flags: + * + * @since 1.0.0 + */ +- (id)initWithIdentifier:(NSUInteger)identifier + date:(NSDate *)date + URL:(NSURL *)URL + flags:(CDEventFlags)flags; + +@end diff --git a/CDEvents.framework/Versions/A/Headers/CDEvents.h b/CDEvents.framework/Versions/A/Headers/CDEvents.h new file mode 100755 index 0000000..c89cf69 --- /dev/null +++ b/CDEvents.framework/Versions/A/Headers/CDEvents.h @@ -0,0 +1,454 @@ +/** + * CDEvents + * + * Copyright (c) 2010-2012 Aron Cedercrantz + * http://github.com/rastersize/CDEvents/ + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @headerfile CDEvents.h CDEvents/CDEvents.h + * A class that wraps the FSEvents C API. + * + * A class that wraps the FSEvents C API. Inspired and based + * upon the open source project SCEvents created by Stuart Connolly + * http://stuconnolly.com/projects/code/ + */ + +#import +#import + +#import "CDEvent.h" + +@protocol CDEventsDelegate; + + +#pragma mark - +#pragma mark CDEvents types +/** + * The event stream creation flags type. + * + * @since 1.0.2 + */ +typedef FSEventStreamCreateFlags CDEventsEventStreamCreationFlags; + + +#pragma mark - +#pragma mark CDEvents custom exceptions +/** + * The exception raised if CDEvents failed to create the event stream. + * + * @since 1.0.0 + */ +extern NSString *const CDEventsEventStreamCreationFailureException; + + +#pragma mark - +#pragma mark Default values +/** + * The default notificaion latency. + * + * @since 1.0.0 + */ +#define CD_EVENTS_DEFAULT_NOTIFICATION_LATENCY ((NSTimeInterval)3.0) + +/** + * The default value whether events from sub directories should be ignored or not. + * + * @since 1.0.0 + */ +#define CD_EVENTS_DEFAULT_IGNORE_EVENT_FROM_SUB_DIRS NO + +/** + * The default event stream creation flags. + * + * @since 1.0.0 + */ +extern const CDEventsEventStreamCreationFlags kCDEventsDefaultEventStreamFlags; + +/** + * Use this to get all event since now when initializing a CDEvents object. + * + * @since 1.1.0 + */ +extern const CDEventIdentifier kCDEventsSinceEventNow; + + +#pragma mark - +#pragma mark CDEvents Block Type +@class CDEvents; +/** + * Type of the block which gets called when an event occurs. + * + * @since head + */ +typedef void (^CDEventsEventBlock)(CDEvents *watcher, CDEvent *event); + + +#pragma mark - +#pragma mark CDEvents interface +/** + * An Objective-C wrapper for the FSEvents C API. + * + * @note Inspired by SCEvents class of the SCEvents project by Stuart Connolly. + * + * @see FSEvents.h in CoreServices + * + * @since 1.0.0 + */ +@interface CDEvents : NSObject {} + +#pragma mark Properties +/** @name Managing the Delegate */ +/** + * The delegate object the CDEvents object calls when it recieves an event. + * + * @param delegate Delegate for the events object. nil removes the delegate. + * @return The events's delegate. + * + * @see CDEventsDelegate + * + * @since 1.0.0 + */ +@property (unsafe_unretained) id delegate; + +/** @name Getting Event Block */ +/** + * The event block. + * + * @return The CDEventsEventBlock block which is executed when an event occurs. + * + * @since head + */ +@property (readonly) CDEventsEventBlock eventBlock; + +/** @name Getting Event Watcher Properties */ +/** + * The (approximate) time intervall between notifications sent to the delegate. + * + * @return The time intervall between notifications. + * + * @since 1.0.0 + */ +@property (readonly) CFTimeInterval notificationLatency; + +/** + * The event identifier from which events will be supplied to the delegate. + * + * @return The event identifier from which events will be supplied to the delegate. + * + * @since 1.0.0 + */ +@property (readonly) CDEventIdentifier sinceEventIdentifier; + +/** + * The last event that occured and has been delivered to the delegate. + * + * @return The last event that occured and has been delivered to the delegate. + * + * @since 1.0.0 + */ +@property (strong, readonly) CDEvent *lastEvent; + +/** + * The URLs that we watch for events. + * + * @return An array of NSURL object for the URLs which we watch for events. + * + * @since 1.0.0 + */ +@property (copy, readonly) NSArray *watchedURLs; + + +/** @name Configuring the Event watcher */ +/** + * The URLs that we should ignore events from. + * + * @return An array of NSURL object for the URLs which we want to ignore. + * @discussion Events from concerning these URLs and there sub-directories will not be delivered to the delegate. + * + * @since 1.0.0 + */ +@property (copy) NSArray *excludedURLs; + +/** + * Wheter events from sub-directories of the watched URLs should be ignored or not. + * + * @param flag Wheter events from sub-directories of the watched URLs shouled be ignored or not. + * @return YES if events from sub-directories should be ignored, otherwise NO. + * + * @since 1.0.0 + */ +@property (assign) BOOL ignoreEventsFromSubDirectories; + + +#pragma mark Event identifier class methods +/** @name Current Event Identifier */ +/** + * The current event identifier. + * + * @return The current event identifier. + * + * @see FSEventsGetCurrentEventId(void) + * + * @since 1.0.0 + */ ++ (CDEventIdentifier)currentEventIdentifier; + + +#pragma mark Creating CDEvents Objects With a Delegate +/** @name Creating CDEvents Objects With a Delegate */ +/** + * Returns an CDEvents object initialized with the given URLs to watch. + * + * @param URLs An array of URLs we want to watch. + * @param delegate The delegate object the CDEvents object calls when it recieves an event. + * @return An CDEvents object initialized with the given URLs to watch. + * @throws NSInvalidArgumentException if URLs is empty or points to nil. + * @throws NSInvalidArgumentException if delegateis nil. + * @throws CDEventsEventStreamCreationFailureException if we failed to create a event stream. + * + * @see initWithURLs:delegate:onRunLoop: + * @see initWithURLs:delegate:onRunLoop:sinceEventIdentifier:notificationLantency:ignoreEventsFromSubDirs:excludeURLs:streamCreationFlags: + * @see CDEventsDelegate + * @see kCDEventsDefaultEventStreamFlags + * @see kCDEventsSinceEventNow + * + * @discussion Calls initWithURLs:delegate:onRunLoop:sinceEventIdentifier:notificationLantency:ignoreEventsFromSubDirs:excludeURLs:streamCreationFlags: + * with sinceEventIdentifier with the event identifier for "event + * since now", notificationLatency set to 3.0 seconds, + * ignoreEventsFromSubDirectories set to NO, + * excludedURLs to nil, the event stream creation + * flags will be set to kCDEventsDefaultEventStreamFlags and + * schedueled on the current run loop. + * + * @since 1.0.0 + */ +- (id)initWithURLs:(NSArray *)URLs delegate:(id)delegate; + +/** + * Returns an CDEvents object initialized with the given URLs to watch and schedules the watcher on the given run loop. + * + * @param URLs An array of URLs we want to watch. + * @param delegate The delegate object the CDEvents object calls when it recieves an event. + * @param runLoop The run loop which the which the watcher should be schedueled on. + * @return An CDEvents object initialized with the given URLs to watch. + * @throws NSInvalidArgumentException if URLs is empty or points to nil. + * @throws NSInvalidArgumentException if delegateis nil. + * @throws CDEventsEventStreamCreationFailureException if we failed to create a event stream. + * + * @see initWithURLs:delegate: + * @see initWithURLs:delegate:onRunLoop:sinceEventIdentifier:notificationLantency:ignoreEventsFromSubDirs:excludeURLs:streamCreationFlags: + * @see CDEventsDelegate + * @see kCDEventsDefaultEventStreamFlags + * @see kCDEventsSinceEventNow + * + * @discussion Calls initWithURLs:delegate:onRunLoop:sinceEventIdentifier:notificationLantency:ignoreEventsFromSubDirs:excludeURLs:streamCreationFlags: + * with sinceEventIdentifier with the event identifier for "event + * since now", notificationLatency set to 3.0 seconds, + * ignoreEventsFromSubDirectories set to NO, + * excludedURLs to nil and the event stream creation + * flags will be set to kCDEventsDefaultEventStreamFlags. + * + * @since 1.0.0 + */ +- (id)initWithURLs:(NSArray *)URLs + delegate:(id)delegate + onRunLoop:(NSRunLoop *)runLoop; + +/** + * Returns an CDEvents object initialized with the given URLs to watch, URLs to exclude, whether events from sub-directories are ignored or not and schedules the watcher on the given run loop. + * + * @param URLs An array of URLs (NSURL) we want to watch. + * @param delegate The delegate object the CDEvents object calls when it recieves an event. + * @param runLoop The run loop which the which the watcher should be schedueled on. + * @param sinceEventIdentifier Events that have happened after the given event identifier will be supplied. + * @param notificationLatency The (approximate) time intervall between notifications sent to the delegate. + * @param ignoreEventsFromSubDirs Wheter events from sub-directories of the watched URLs should be ignored or not. + * @param exludeURLs An array of URLs that we should ignore events from. Pass nil if none should be excluded. + * @param streamCreationFlags The event stream creation flags. + * @return An CDEvents object initialized with the given URLs to watch, URLs to exclude, whether events from sub-directories are ignored or not and run on the given run loop. + * @throws NSInvalidArgumentException if the parameter URLs is empty or points to nil. + * @throws NSInvalidArgumentException if delegateis nil. + * @throws CDEventsEventStreamCreationFailureException if we failed to create a event stream. + * + * @see initWithURLs:delegate: + * @see initWithURLs:delegate:onRunLoop: + * @see ignoreEventsFromSubDirectories + * @see excludedURLs + * @see CDEventsDelegate + * @see FSEventStreamCreateFlags + * + * @discussion To ask for events "since now" pass the return value of + * currentEventIdentifier as the parameter sinceEventIdentifier. + * CDEventStreamCreationFailureException should be extremely rare. + * + * @since 1.0.0 + */ +- (id)initWithURLs:(NSArray *)URLs + delegate:(id)delegate + onRunLoop:(NSRunLoop *)runLoop +sinceEventIdentifier:(CDEventIdentifier)sinceEventIdentifier +notificationLantency:(CFTimeInterval)notificationLatency +ignoreEventsFromSubDirs:(BOOL)ignoreEventsFromSubDirs + excludeURLs:(NSArray *)exludeURLs + streamCreationFlags:(CDEventsEventStreamCreationFlags)streamCreationFlags; + +#pragma mark Creating CDEvents Objects With a Block +/** @name Creating CDEvents Objects With a Block */ +/** + * Returns an CDEvents object initialized with the given URLs to watch. + * + * @param URLs An array of URLs we want to watch. + * @param block The block which the CDEvents object executes when it recieves an event. + * @return An CDEvents object initialized with the given URLs to watch. + * @throws NSInvalidArgumentException if URLs is empty or points to nil. + * @throws NSInvalidArgumentException if delegateis nil. + * @throws CDEventsEventStreamCreationFailureException if we failed to create a event stream. + * + * @see initWithURLs:delegate:onRunLoop: + * @see initWithURLs:delegate:onRunLoop:sinceEventIdentifier:notificationLantency:ignoreEventsFromSubDirs:excludeURLs:streamCreationFlags: + * @see CDEventsEventBlock + * @see kCDEventsDefaultEventStreamFlags + * @see kCDEventsSinceEventNow + * + * @discussion Calls initWithURLs:block:onRunLoop:sinceEventIdentifier:notificationLantency:ignoreEventsFromSubDirs:excludeURLs:streamCreationFlags: + * with sinceEventIdentifier with the event identifier for "event + * since now", notificationLatency set to 3.0 seconds, + * ignoreEventsFromSubDirectories set to NO, + * excludedURLs to nil, the event stream creation + * flags will be set to kCDEventsDefaultEventStreamFlags and + * schedueled on the current run loop. + * + * @since head + */ +- (id)initWithURLs:(NSArray *)URLs block:(CDEventsEventBlock)block; + +/** + * Returns an CDEvents object initialized with the given URLs to watch and schedules the watcher on the given run loop. + * + * @param URLs An array of URLs we want to watch. + * @param block The block which the CDEvents object executes when it recieves an event. + * @param runLoop The run loop which the which the watcher should be schedueled on. + * @return An CDEvents object initialized with the given URLs to watch. + * @throws NSInvalidArgumentException if URLs is empty or points to nil. + * @throws NSInvalidArgumentException if delegateis nil. + * @throws CDEventsEventStreamCreationFailureException if we failed to create a event stream. + * + * @see initWithURLs:delegate: + * @see initWithURLs:delegate:onRunLoop:sinceEventIdentifier:notificationLantency:ignoreEventsFromSubDirs:excludeURLs:streamCreationFlags: + * @see CDEventsEventBlock + * @see kCDEventsDefaultEventStreamFlags + * @see kCDEventsSinceEventNow + * + * @discussion Calls initWithURLs:delegate:onRunLoop:sinceEventIdentifier:notificationLantency:ignoreEventsFromSubDirs:excludeURLs:streamCreationFlags: + * with sinceEventIdentifier with the event identifier for "event + * since now", notificationLatency set to 3.0 seconds, + * ignoreEventsFromSubDirectories set to NO, + * excludedURLs to nil and the event stream creation + * flags will be set to kCDEventsDefaultEventStreamFlags. + * + * @since head + */ +- (id)initWithURLs:(NSArray *)URLs + block:(CDEventsEventBlock)block + onRunLoop:(NSRunLoop *)runLoop; + +/** + * Returns an CDEvents object initialized with the given URLs to watch, URLs to exclude, whether events from sub-directories are ignored or not and schedules the watcher on the given run loop. + * + * @param URLs An array of URLs (NSURL) we want to watch. + * @param block The block which the CDEvents object executes when it recieves an event. + * @param runLoop The run loop which the which the watcher should be schedueled on. + * @param sinceEventIdentifier Events that have happened after the given event identifier will be supplied. + * @param notificationLatency The (approximate) time intervall between notifications sent to the delegate. + * @param ignoreEventsFromSubDirs Wheter events from sub-directories of the watched URLs should be ignored or not. + * @param exludeURLs An array of URLs that we should ignore events from. Pass nil if none should be excluded. + * @param streamCreationFlags The event stream creation flags. + * @return An CDEvents object initialized with the given URLs to watch, URLs to exclude, whether events from sub-directories are ignored or not and run on the given run loop. + * @throws NSInvalidArgumentException if the parameter URLs is empty or points to nil. + * @throws NSInvalidArgumentException if delegateis nil. + * @throws CDEventsEventStreamCreationFailureException if we failed to create a event stream. + * + * @see initWithURLs:delegate: + * @see initWithURLs:delegate:onRunLoop: + * @see ignoreEventsFromSubDirectories + * @see excludedURLs + * @see CDEventsEventBlock + * @see FSEventStreamCreateFlags + * + * @discussion To ask for events "since now" pass the return value of + * currentEventIdentifier as the parameter sinceEventIdentifier. + * CDEventStreamCreationFailureException should be extremely rare. + * + * @since head + */ +- (id)initWithURLs:(NSArray *)URLs + block:(CDEventsEventBlock)block + onRunLoop:(NSRunLoop *)runLoop +sinceEventIdentifier:(CDEventIdentifier)sinceEventIdentifier +notificationLantency:(CFTimeInterval)notificationLatency +ignoreEventsFromSubDirs:(BOOL)ignoreEventsFromSubDirs + excludeURLs:(NSArray *)exludeURLs +streamCreationFlags:(CDEventsEventStreamCreationFlags)streamCreationFlags; + +#pragma mark Flush methods +/** @name Flushing Events */ +/** + * Flushes the event stream synchronously. + * + * Flushes the event stream synchronously by sending events that have already occurred but not yet delivered. + * + * @see flushAsynchronously + * + * @since 1.0.0 + */ +- (void)flushSynchronously; + +/** + * Flushes the event stream asynchronously. + * + * Flushes the event stream asynchronously by sending events that have already occurred but not yet delivered. + * + * @see flushSynchronously + * + * @since 1.0.0 + */ +- (void)flushAsynchronously; + +#pragma mark Misc methods +/** @name Events Description */ +/** + * Returns a NSString containing the description of the current event stream. + * + * @return A NSString containing the description of the current event stream. + * + * @see FSEventStreamCopyDescription + * + * @discussion For debugging only. + * + * @since 1.0.0 + */ +- (NSString *)streamDescription; + +@end diff --git a/CDEvents.framework/Versions/A/Headers/CDEventsDelegate.h b/CDEvents.framework/Versions/A/Headers/CDEventsDelegate.h new file mode 100755 index 0000000..1e44aef --- /dev/null +++ b/CDEvents.framework/Versions/A/Headers/CDEventsDelegate.h @@ -0,0 +1,71 @@ +/** + * CDEvents + * + * Copyright (c) 2010-2012 Aron Cedercrantz + * http://github.com/rastersize/CDEvents/ + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +/** + * @headerfile CDEventsDelegate.h CDEvents/CDEventsDelegate.h + + * + * A protocol that that delegates of CDEvents conform to. Inspired and based + * upon the open source project SCEvents created by Stuart Connolly + * http://stuconnolly.com/projects/code/ + */ + +@class CDEvents; +@class CDEvent; + + +/** + * The CDEventsDelegate protocol defines the required methods implemented by delegates of CDEvents objects. + * + * @see CDEvents + * @see CDEvent + * + * @since 1.0.0 + */ +@protocol CDEventsDelegate + +@required +/** + * The method called by the CDEvents object on its delegate object. + * + * @param URLWatcher The CDEvents object which the event was recieved thru. + * @param event The event data. + * + * @see CDEvents + * @see CDEvent + * + * @discussion Conforming objects' implementation of this method will be called + * whenever an event occurs. The instance of CDEvents which received the event + * and the event itself are passed as parameters. + * + * @since 1.0.0 + */ +- (void)URLWatcher:(CDEvents *)URLWatcher eventOccurred:(CDEvent *)event; + +@end + diff --git a/CDEvents.framework/Versions/A/Resources/English.lproj/InfoPlist.strings b/CDEvents.framework/Versions/A/Resources/English.lproj/InfoPlist.strings new file mode 100644 index 0000000..5e45963 Binary files /dev/null and b/CDEvents.framework/Versions/A/Resources/English.lproj/InfoPlist.strings differ diff --git a/CDEvents.framework/Versions/A/Resources/Info.plist b/CDEvents.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..01956ae --- /dev/null +++ b/CDEvents.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,40 @@ + + + + + BuildMachineOSBuild + 12D78 + CFBundleDevelopmentRegion + English + CFBundleExecutable + CDEvents + CFBundleIdentifier + com.cedercrantz.CDEvents + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + CDEvents + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.2.0 + CFBundleSignature + ???? + CFBundleVersion + 1.2.0 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 4H1003 + DTPlatformVersion + GM + DTSDKBuild + 12D75 + DTSDKName + macosx10.8 + DTXcode + 0462 + DTXcodeBuild + 4H1003 + + diff --git a/CDEvents.framework/Versions/Current b/CDEvents.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/CDEvents.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file