This is NSNotificationQueue.m in view mode; [Download] [Up]
/* NSNotificationQueue.m Copyright (C) 1995, 1996 Ovidiu Predescu and Mircea Oancea. All rights reserved. Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro> This file is part of libFoundation. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. We disclaim all warranties with regard to this software, including all implied warranties of merchantability and fitness, in no event shall we be liable for any special, indirect or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of this software. */ #include <Foundation/NSRunLoop.h> #include <Foundation/NSNotificationQueue.h> #include <Foundation/NSNotification.h> #include <Foundation/NSDictionary.h> #include <Foundation/NSArray.h> #include <Foundation/NSString.h> #include <Foundation/common.h> /* * NSNotificationQueue queue */ typedef struct _NSNotificationQueueRegistration { struct _NSNotificationQueueRegistration* next; struct _NSNotificationQueueRegistration* prev; NSNotification* notification; id name; id object; NSArray* modes; } NSNotificationQueueRegistration; struct _NSNotificationQueueList; typedef struct _NSNotificationQueueList { struct _NSNotificationQueueRegistration* head; struct _NSNotificationQueueRegistration* tail; } NSNotificationQueueList; /* * Queue functions * * Queue Elem Elem Elem * head ---------> prev -----------> prev -----------> prev --> nil * nil <-- next <----------- next <----------- next * tail ---------------------------------------------> */ static void remove_from_queue( NSNotificationQueueList* queue, NSNotificationQueueRegistration* item, NSZone* zone) { if (item->prev) item->prev->next = item->next; else { queue->tail = item->next; if (item->next) item->next->prev = NULL; } if (item->next) item->next->prev = item->prev; else { queue->head = item->prev; if (item->prev) item->prev->next = NULL; } [item->notification release]; [item->modes release]; NSZoneFree(zone, item); } static void add_to_queue( NSNotificationQueueList* queue, NSNotification* notification, NSArray* modes, NSZone* zone) { NSNotificationQueueRegistration* item = NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueRegistration)); item->notification = [notification retain]; item->name = [notification notificationName]; item->object = [notification notificationObject]; item->modes = [modes copyWithZone:[modes zone]]; item->prev = NULL; item->next = queue->tail; queue->tail = item; if (item->next) item->next->prev = item; if (!queue->head) queue->head = item; } /* * Notification Queue calss variables */ typedef struct _InstanceList { struct _InstanceList* next; struct _InstanceList* prev; id queue; } InstanceList; static InstanceList* notificationQueues; static NSNotificationQueue* defaultQueue; /* * NSNotificationQueue class implementation */ @implementation NSNotificationQueue + (void)initialize { // THREAD defaultQueue = [[self alloc] init]; } + (NSNotificationQueue*)defaultQueue { return defaultQueue; } - (id)init { return [self initWithNotificationCenter: [NSNotificationCenter defaultCenter]]; } - (id)initWithNotificationCenter:(NSNotificationCenter*)notificationCenter { InstanceList *regItem; zone = [self zone]; // init queue center = [notificationCenter retain]; asapQueue = NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueList)); idleQueue = NSZoneCalloc(zone, 1, sizeof(NSNotificationQueueList)); // insert in global queue list // THREAD regItem = Calloc(1, sizeof(InstanceList)); regItem->next = notificationQueues; notificationQueues = regItem; return self; } - (void)dealloc { InstanceList *regItem, *theItem; NSNotificationQueueRegistration* item; // remove from classs instances list // THREAD if (notificationQueues->queue == self) notificationQueues = notificationQueues->next; else { for (regItem=notificationQueues; regItem->next; regItem=regItem->next) { if (regItem->next->queue == self) { theItem = regItem->next; regItem->next = theItem->next; Free(theItem); break; } } } // release self for (item = asapQueue->head; item; item=item->prev) remove_from_queue(asapQueue, item, zone); NSZoneFree(zone, asapQueue); for (item = idleQueue->head; item; item=item->prev) remove_from_queue(idleQueue, item, zone); NSZoneFree(zone, idleQueue); [center release]; [super dealloc]; } /* Inserting and Removing Notifications From a Queue */ - (void)dequeueNotificationsMatching:(NSNotification*)notification coalesceMask:(NSNotificationCoalescing)coalesceMask { NSNotificationQueueRegistration* item; NSNotificationQueueRegistration* next; id name = [notification notificationName]; id object = [notification notificationObject]; // find in ASAP notification in queue for (item = asapQueue->tail; item; item=next) { next = item->next; if ((coalesceMask & NSNotificationCoalescingOnName) && [name isEqual:item->name]) { remove_from_queue(asapQueue, item, zone); continue; } if ((coalesceMask & NSNotificationCoalescingOnSender) && (object == item->object)) { remove_from_queue(asapQueue, item, zone); continue; } } // find in idle notification in queue for (item = idleQueue->tail; item; item=next) { next = item->next; if ((coalesceMask & NSNotificationCoalescingOnName) && [name isEqual:item->name]) { remove_from_queue(asapQueue, item, zone); continue; } if ((coalesceMask & NSNotificationCoalescingOnSender) && (object == item->object)) { remove_from_queue(asapQueue, item, zone); continue; } } } - (void)postNotification:(NSNotification*)notification forModes:(NSArray*)modes { BOOL ok = NO; NSString* mode = [[NSRunLoop currentRunLoop] currentMode]; // check to see if run loop is in a valid mode if (!mode || !modes) ok = YES; else { int i; for (i = [modes count]-1; i >= 0; i--) if ([mode isEqual:[modes objectAtIndex:i]]) { ok = YES; break; } } // if mode is valid then post if (ok) [center postNotification:notification]; } - (void)enqueueNotification:(NSNotification*)notification postingStyle:(NSPostingStyle)postingStyle { [self enqueueNotification:notification postingStyle:postingStyle coalesceMask:NSNotificationCoalescingOnName + NSNotificationCoalescingOnSender forModes:nil]; } - (void)enqueueNotification:(NSNotification*)notification postingStyle:(NSPostingStyle)postingStyle coalesceMask:(NSNotificationCoalescing)coalesceMask forModes:(NSArray*)modes { if (coalesceMask != NSNotificationNoCoalescing) [self dequeueNotificationsMatching:notification coalesceMask:coalesceMask]; switch (postingStyle) { case NSPostNow: [self postNotification:notification forModes:modes]; break; case NSPostASAP: add_to_queue(asapQueue, notification, modes, zone); break; case NSPostWhenIdle: add_to_queue(idleQueue, notification, modes, zone); break; } } /* * NotificationQueue internals */ + (void)runLoopIdle { InstanceList* item; for (item=notificationQueues; item; item=item->next) [item->queue notifyIdle]; } + (void)runLoopASAP { InstanceList* item; for (item=notificationQueues; item; item=item->next) [item->queue notifyASAP]; } - (void)notifyIdle { // post next IDLE notification in queue if (idleQueue->head) { [self postNotification:idleQueue->head->notification forModes:idleQueue->head->modes]; remove_from_queue(idleQueue, idleQueue->head, zone); } } - (void)notifyASAP { // post all ASAP notifications in queue while (asapQueue->head) { [self postNotification:asapQueue->head->notification forModes:idleQueue->head->modes]; remove_from_queue(asapQueue, asapQueue->head, zone); } } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.