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.