File: programming/cocoa/Filie.zip/Filie/UliKit/UKKQueue.m


/* =============================================================================
	FILE:		UKKQueue.m
	PROJECT:	Filie
    
    COPYRIGHT:  (c) 2003 M. Uli Kusterer, all rights reserved.
    
	AUTHORS:	M. Uli Kusterer - UK
    
    LICENSES:   MIT License
 
	REVISIONS:
		2006-03-13	UK	Clarified license, streamlined UKFileWatcher stuff,
						Changed notifications to be useful and turned off by
						default some deprecated stuff.
        2004-12-28  UK  Several threading fixes.
		2003-12-21	UK	Created.
   ========================================================================== */
 
// -----------------------------------------------------------------------------
//  Headers:
// -----------------------------------------------------------------------------
 
#import "UKKQueue.h"
#import "UKMainThreadProxy.h"
#import <unistd.h>
#import <fcntl.h>
#include <sys/stat.h>
 
 
// -----------------------------------------------------------------------------
//  Macros:
// -----------------------------------------------------------------------------
 
// @synchronized isn't available prior to 10.3, so we use a typedef so
//  this class is thread-safe on Panther but still compiles on older OSs.
 
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3
#define AT_SYNCHRONIZED(n)      @synchronized(n)
#else
#define AT_SYNCHRONIZED(n)
#endif
 
 
// -----------------------------------------------------------------------------
//  Globals:
// -----------------------------------------------------------------------------
// Object to which we send notifications so they get put in the main thread.
// Deprecated:
#if UKKQUEUE_OLD_SINGLETON_ACCESSOR_NAME
#endif
 
// -----------------------------------------------------------------------------
//  sharedQueue:
//		Returns a singleton queue object. In many apps (especially those that
//      subscribe to the notifications) there will only be one kqueue instance,
//      and in that case you can use this.
//
//      For all other cases, feel free to create additional instances to use
//      independently.
//
//	REVISIONS:
//		2006-03-13	UK	Renamed from sharedQueue.
//      2005-07-02  UK  Created.
// -----------------------------------------------------------------------------
// This is a singleton, and thus an intentional "leak".
// -----------------------------------------------------------------------------
//	* CONSTRUCTOR:
//		Creates a new KQueue and starts that thread we use for our
//		notifications.
//
//	REVISIONS:
//      2004-11-12  UK  Doesn't pass self as parameter to watcherThread anymore,
//                      because detachNewThreadSelector retains target and args,
//                      which would cause us to never be released.
//		2004-03-13	UK	Documented.
// -----------------------------------------------------------------------------
// Start new thread that fetches and processes our events:
// -----------------------------------------------------------------------------
//	release:
//		Since NSThread retains its target, we need this method to terminate the
//      thread when we reach a retain-count of two. The thread is terminated by
//      setting keepThreadRunning to NO.
//
//	REVISIONS:
//		2004-11-12	UK	Created.
// -----------------------------------------------------------------------------
//NSLog(@"%@ (%d)", self, [self retainCount]);
// -----------------------------------------------------------------------------
//	* DESTRUCTOR:
//		Releases the kqueue again.
//
//	REVISIONS:
//		2004-03-13	UK	Documented.
// -----------------------------------------------------------------------------
// Close all our file descriptors so the files can be deleted:
//NSLog(@"kqueue released.");
// Close all our file descriptors so the files can be deleted:
"dealloc: Couldn't close file descriptor (%d)"// -----------------------------------------------------------------------------
//	queueFD:
//		Returns a Unix file descriptor for the KQueue this uses. The descriptor
//		is owned by this object. Do not close it!
//
//	REVISIONS:
//		2004-03-13	UK	Documented.
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//	addPathToQueue:
//		Tell this queue to listen for all interesting notifications sent for
//		the object at the specified path. If you want more control, use the
//		addPathToQueue:notifyingAbout: variant instead.
//
//	REVISIONS:
//		2004-03-13	UK	Documented.
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//	addPathToQueue:notfyingAbout:
//		Tell this queue to listen for the specified notifications sent for
//		the object at the specified path.
//
//	REVISIONS:
//      2005-06-29  UK  Files are now opened using O_EVTONLY instead of O_RDONLY
//                      which allows ejecting or deleting watched files/folders.
//                      Thanks to Phil Hargett for finding this flag in the docs.
//		2004-03-13	UK	Documented.
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//	removePathFromQueue:
//		Stop listening for changes to the specified path. This removes all
//		notifications. Use this to balance both addPathToQueue:notfyingAbout:
//		as well as addPathToQueue:.
//
//	REVISIONS:
//		2004-03-13	UK	Documented.
// -----------------------------------------------------------------------------
"removePathFromQueue: Couldn't find path %@ to unsubscribe.""removePathFromQueue: Couldn't close file descriptor (%d)"// -----------------------------------------------------------------------------
//	removeAllPathsFromQueue:
//		Stop listening for changes to all paths. This removes all
//		notifications.
//
//  REVISIONS:
//      2004-12-28  UK  Added as suggested by bbum.
// -----------------------------------------------------------------------------
/*-(NSString*)	filePathForFileDescriptor:(const int)fd oldPath: (NSString*)oldPath
{
   struct stat fileStatus;
   struct stat currentFileStatus;
   
   // Get file status
   if( fstat(fd, &fileStatus) == -1 )
       return nil;
   
   NSString*		basePath = [oldPath stringByDeletingLastPathComponent];
   NSEnumerator *dirEnumerator;
   dirEnumerator = [[NSFileManager defaultManager] enumeratorAtPath: basePath];
 
   NSString *path;
   while( (path = [dirEnumerator nextObject]) )
   {
       NSString *fullPath = [basePath stringByAppendingPathComponent:path];
       if( stat([fullPath fileSystemRepresentation], &currentFileStatus) == 0 )
       {
           if ((currentFileStatus.st_dev == fileStatus.st_dev) &&
               (currentFileStatus.st_ino == fileStatus.st_ino))
           {
               // Found file
               return fullPath;
           }
       }
   }
   
   // Didn't find file
   return nil;
}*/
 
 
// -----------------------------------------------------------------------------
//	watcherThread:
//		This method is called by our NSThread to loop and poll for any file
//		changes that our kqueue wants to tell us about. This sends separate
//		notifications for the different kinds of changes that can happen.
//		All messages are sent via the postNotification:forFile: main bottleneck.
//
//		This also calls sharedWorkspace's noteFileSystemChanged.
//
//      To terminate this method (and its thread), set keepThreadRunning to NO.
//
//	REVISIONS:
//		2005-08-27	UK	Changed to use keepThreadRunning instead of kqueueFD
//						being -1 as termination criterion, and to close the
//						queue in this thread so the main thread isn't blocked.
//		2004-11-12	UK	Fixed docs to include termination criterion, added
//                      timeout to make sure the bugger gets disposed.
//		2004-03-13	UK	Documented.
// -----------------------------------------------------------------------------
// 5 seconds timeout.
// So we don't have to risk accessing iVars when the thread is terminated.
"watcherThread started."// In case one of the notified folks removes the path.
						//NSLog(@"UKKQueue: Detected file change: %@", fpath);
//NSLog(@"ev.flags = %u",ev.fflags);	// DEBUG ONLY!
						
						/*int		idx = [watchedPaths indexOfObject: fpath];
						int		fd = [[watchedFDs objectAtIndex: idx] intValue];
						
						NSLog( @"newpath: %@", [self filePathForFileDescriptor: fd oldPath: fpath] );*/"Error in UKKQueue watcherThread: %@"// Close our kqueue's file descriptor:
"watcherThread: Couldn't close main kqueue (%d)"//NSLog(@"exiting kqueue watcher thread.");
}
 
 
// -----------------------------------------------------------------------------
//	postNotification:forFile:
//		This is the main bottleneck for posting notifications. If you don't want
//		the notifications to go through NSWorkspace, override this method and
//		send them elsewhere.
//
//	REVISIONS:
//      2004-02-27  UK  Changed this to send new notification, and the old one
//                      only to objects that respond to it. The old category on
//                      NSObject could cause problems with the proxy itself.
//		2004-10-31	UK	Helloween fun: Make this use a mainThreadProxy and
//						allow sending the notification even if we have a
//						delegate.
//		2004-03-13	UK	Documented.
// -----------------------------------------------------------------------------
#if UKKQUEUE_BACKWARDS_COMPATIBLE
#endif
#if UKKQUEUE_SEND_STUPID_NOTIFICATIONS
// Deprecated. Not thread-safe and useless info in notification, hard to subscribe to selectively.
		#else
"path"// The proxy sends the notification on the main thread.
		#endif
// -----------------------------------------------------------------------------
//	Flag to send a notification even if we have a delegate:
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//	description:
//		This method can be used to help in debugging. It provides the value
//      used by NSLog & co. when you request to print this object using the
//      %@ format specifier.
//
//	REVISIONS:
//		2004-11-12	UK	Created.
// -----------------------------------------------------------------------------
"%@ { watchedPaths = %@, alwaysNotify = %@ }""YES" : @"NO"

This code uses the PclZip Zip File reading code, which is subject to the GNU LGPL. It also uses the GeSHi syntax highlighter, subject to the GPL. Ask if you want this for your own web site, it's free.