cog/FileDrawer/UKKQueue/UKFNSubscribeFileWatcher.m

201 lines
6.5 KiB
Objective-C

/* =============================================================================
FILE: UKFNSubscribeFileWatcher.m
PROJECT: Filie
COPYRIGHT: (c) 2005 M. Uli Kusterer, all rights reserved.
AUTHORS: M. Uli Kusterer - UK
LICENSES: MIT License
REVISIONS:
2006-03-13 UK Commented, added singleton, added notifications.
2005-03-02 UK Created.
========================================================================== */
// -----------------------------------------------------------------------------
// Headers:
// -----------------------------------------------------------------------------
#import "UKFNSubscribeFileWatcher.h"
#import <Carbon/Carbon.h>
// -----------------------------------------------------------------------------
// Prototypes:
// -----------------------------------------------------------------------------
void UKFileSubscriptionProc(FNMessage message, OptionBits flags, void *refcon, FNSubscriptionRef subscription);
@implementation UKFNSubscribeFileWatcher
// -----------------------------------------------------------------------------
// sharedFileWatcher:
// Singleton accessor.
// -----------------------------------------------------------------------------
+(id) sharedFileWatcher
{
static UKFNSubscribeFileWatcher* sSharedFileWatcher = nil;
if( !sSharedFileWatcher )
sSharedFileWatcher = [[UKFNSubscribeFileWatcher alloc] init]; // This is a singleton, and thus an intentional "leak".
return sSharedFileWatcher;
}
// -----------------------------------------------------------------------------
// * CONSTRUCTOR:
// -----------------------------------------------------------------------------
-(id) init
{
self = [super init];
if( !self )
return nil;
subscriptions = [[NSMutableDictionary alloc] init];
return self;
}
// -----------------------------------------------------------------------------
// * DESTRUCTOR:
// -----------------------------------------------------------------------------
-(void) dealloc
{
NSEnumerator* enny = [subscriptions objectEnumerator];
NSValue* subValue = nil;
while( (subValue = [enny nextObject]) )
{
FNSubscriptionRef subscription = [subValue pointerValue];
FNUnsubscribe( subscription );
}
[subscriptions release];
[super dealloc];
}
// -----------------------------------------------------------------------------
// addPath:
// Start watching the object at the specified path. This only sends write
// notifications for all changes, as FNSubscribe doesn't tell what actually
// changed about our folder.
// -----------------------------------------------------------------------------
-(void) addPath: (NSString*)path
{
OSStatus err = noErr;
static FNSubscriptionUPP subscriptionUPP = NULL;
FNSubscriptionRef subscription = NULL;
if( !subscriptionUPP )
subscriptionUPP = NewFNSubscriptionUPP( UKFileSubscriptionProc );
err = FNSubscribeByPath( (UInt8*) [path fileSystemRepresentation], subscriptionUPP, (void*)self,
kNilOptions, &subscription );
if( err != noErr )
{
NSLog( @"UKFNSubscribeFileWatcher addPath: %@ failed due to error ID=%ld.", path, err );
return;
}
[subscriptions setObject: [NSValue valueWithPointer: subscription] forKey: path];
}
// -----------------------------------------------------------------------------
// removePath:
// Stop watching the object at the specified path.
// -----------------------------------------------------------------------------
-(void) removePath: (NSString*)path
{
NSValue* subValue = nil;
@synchronized( self )
{
subValue = [[[subscriptions objectForKey: path] retain] autorelease];
[subscriptions removeObjectForKey: path];
}
if( subValue )
{
FNSubscriptionRef subscription = [subValue pointerValue];
FNUnsubscribe( subscription );
}
}
// -----------------------------------------------------------------------------
// sendDelegateMessage:forSubscription:
// Bottleneck for change notifications. This is called by our callback
// function to actually inform the delegate and send out notifications.
//
// This *only* sends out write notifications, as FNSubscribe doesn't tell
// what changed about our folder.
// -----------------------------------------------------------------------------
-(void) sendDelegateMessage: (FNMessage)message forSubscription: (FNSubscriptionRef)subscription
{
NSValue* subValue = [NSValue valueWithPointer: subscription];
NSString* path = [[subscriptions allKeysForObject: subValue] objectAtIndex: 0];
[[[NSWorkspace sharedWorkspace] notificationCenter] postNotificationName: UKFileWatcherWriteNotification
object: self
userInfo: [NSDictionary dictionaryWithObjectsAndKeys: path, @"path", nil]];
[delegate watcher: self receivedNotification: UKFileWatcherWriteNotification forPath: path];
//NSLog( @"UKFNSubscribeFileWatcher noticed change to %@", path ); // DEBUG ONLY!
}
// -----------------------------------------------------------------------------
// delegate:
// Accessor for file watcher delegate.
// -----------------------------------------------------------------------------
-(id) delegate
{
return delegate;
}
// -----------------------------------------------------------------------------
// setDelegate:
// Mutator for file watcher delegate.
// -----------------------------------------------------------------------------
-(void) setDelegate: (id)newDelegate
{
delegate = newDelegate;
}
@end
// -----------------------------------------------------------------------------
// UKFileSubscriptionProc:
// Callback function we hand to Carbon so it can tell us when something
// changed about our watched folders. We set the refcon to a pointer to
// our object. This simply extracts the object and hands the info off to
// sendDelegateMessage:forSubscription: which does the actual work.
// -----------------------------------------------------------------------------
void UKFileSubscriptionProc( FNMessage message, OptionBits flags, void *refcon, FNSubscriptionRef subscription )
{
UKFNSubscribeFileWatcher* obj = (UKFNSubscribeFileWatcher*) refcon;
if( message == kFNDirectoryModifiedMessage ) // No others exist as of 10.4
[obj sendDelegateMessage: message forSubscription: subscription];
else
NSLog( @"UKFileSubscriptionProc: Unknown message %d", message );
}