2005-03-01 15:50:26 +00:00
|
|
|
|
/** Implementation for NSNotificationQueue for GNUStep
|
|
|
|
|
Copyright (C) 1995-1999 Free Software Foundation, Inc.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
Author: Mircea Oancea <mircea@jupiter.elcom.pub.ro>
|
2005-03-01 15:50:26 +00:00
|
|
|
|
Date: 1995
|
1997-09-01 21:59:51 +00:00
|
|
|
|
Modified by: Richard Frith-Macdonald <richard@brainstorm.co.uk>
|
|
|
|
|
Date: 1997
|
1999-07-14 19:31:28 +00:00
|
|
|
|
Rewritten: 1999
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
This file is part of the GNUstep Base Library.
|
|
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
1997-09-01 21:59:51 +00:00
|
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
1997-09-01 21:59:51 +00:00
|
|
|
|
License along with this library; if not, write to the Free
|
2006-06-29 18:01:44 +00:00
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
|
Boston, MA 02111 USA.
|
2005-03-01 15:50:26 +00:00
|
|
|
|
|
|
|
|
|
<title>NSNotificationQueue class reference</title>
|
|
|
|
|
$Date$ $Revision$
|
1997-09-01 21:59:51 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2010-02-19 08:12:46 +00:00
|
|
|
|
#import "common.h"
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#define EXPOSE_NSNotificationQueue_IVARS 1
|
|
|
|
|
#import "Foundation/NSRunLoop.h"
|
|
|
|
|
#import "Foundation/NSNotificationQueue.h"
|
|
|
|
|
#import "Foundation/NSNotification.h"
|
|
|
|
|
#import "Foundation/NSDictionary.h"
|
|
|
|
|
#import "Foundation/NSArray.h"
|
|
|
|
|
#import "Foundation/NSThread.h"
|
|
|
|
|
|
|
|
|
|
#import "GSPrivate.h"
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/* NotificationQueueList by Richard Frith-Macdonald
|
|
|
|
|
These objects are used to maintain lists of NSNotificationQueue objects.
|
|
|
|
|
There is one list per NSThread, with the first object in the list stored
|
|
|
|
|
in the thread dictionary and accessed using the key below.
|
|
|
|
|
*/
|
|
|
|
|
|
2006-06-29 18:01:44 +00:00
|
|
|
|
static NSString* lkey = @"NotificationQueueListThreadKey";
|
|
|
|
|
static NSString* qkey = @"NotificationQueueThreadKey";
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@interface NotificationQueueList : NSObject
|
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
@public
|
|
|
|
|
NotificationQueueList *next;
|
|
|
|
|
NSNotificationQueue *queue;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1999-04-20 16:28:04 +00:00
|
|
|
|
+ (void) registerQueue: (NSNotificationQueue*)q;
|
|
|
|
|
+ (void) unregisterQueue: (NSNotificationQueue*)q;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@end
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
static NotificationQueueList*
|
2002-11-09 16:40:00 +00:00
|
|
|
|
currentList(void)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
NotificationQueueList *list;
|
|
|
|
|
NSMutableDictionary *d;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
d = GSCurrentThreadDictionary();
|
2006-06-29 18:01:44 +00:00
|
|
|
|
list = (NotificationQueueList*)[d objectForKey: lkey];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (list == nil)
|
|
|
|
|
{
|
|
|
|
|
list = [NotificationQueueList new];
|
2006-06-29 18:01:44 +00:00
|
|
|
|
[d setObject: list forKey: lkey];
|
1999-04-20 16:28:04 +00:00
|
|
|
|
RELEASE(list); /* retained in dictionary. */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
@implementation NotificationQueueList
|
|
|
|
|
|
2006-06-29 18:01:44 +00:00
|
|
|
|
- (void) dealloc
|
|
|
|
|
{
|
|
|
|
|
while (next != nil)
|
|
|
|
|
{
|
|
|
|
|
NotificationQueueList *tmp = next;
|
|
|
|
|
|
|
|
|
|
next = tmp->next;
|
|
|
|
|
RELEASE(tmp);
|
|
|
|
|
}
|
|
|
|
|
[super dealloc];
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-24 19:30:29 +00:00
|
|
|
|
+ (void) registerQueue: (NSNotificationQueue*)q
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-11-21 06:33:45 +00:00
|
|
|
|
NotificationQueueList *list;
|
|
|
|
|
NotificationQueueList *elem;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
list = currentList(); /* List of queues for thread. */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
if (list->queue == nil)
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
|
|
|
|
list->queue = q; /* Make this the default. */
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
while (list->queue != q && list->next != nil)
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
|
|
|
|
list = list->next;
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
if (list->queue == q)
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
|
|
|
|
return; /* Queue already registered. */
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-06-24 19:30:29 +00:00
|
|
|
|
elem = (NotificationQueueList*)NSAllocateObject(self, 0,
|
|
|
|
|
NSDefaultMallocZone());
|
1997-09-01 21:59:51 +00:00
|
|
|
|
elem->queue = q;
|
|
|
|
|
list->next = elem;
|
|
|
|
|
}
|
|
|
|
|
|
1999-07-14 19:31:28 +00:00
|
|
|
|
+ (void) unregisterQueue: (NSNotificationQueue*)q
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-11-21 06:33:45 +00:00
|
|
|
|
NotificationQueueList *list;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
list = currentList();
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
|
|
|
|
if (list->queue == q)
|
|
|
|
|
{
|
2010-04-13 10:44:58 +00:00
|
|
|
|
NSMutableDictionary *d = GSCurrentThreadDictionary();
|
|
|
|
|
NotificationQueueList *tmp = list->next;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2010-04-13 10:44:58 +00:00
|
|
|
|
if (tmp != nil)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2006-06-29 18:01:44 +00:00
|
|
|
|
[d setObject: tmp forKey: lkey];
|
1999-04-20 16:28:04 +00:00
|
|
|
|
RELEASE(tmp); /* retained in dictionary. */
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
2006-06-29 18:01:44 +00:00
|
|
|
|
[d removeObjectForKey: lkey];
|
1999-11-21 06:33:45 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
1999-04-20 16:28:04 +00:00
|
|
|
|
{
|
|
|
|
|
while (list->next != nil)
|
|
|
|
|
{
|
|
|
|
|
if (list->next->queue == q)
|
|
|
|
|
{
|
1999-11-21 06:33:45 +00:00
|
|
|
|
NotificationQueueList *tmp = list->next;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
list->next = tmp->next;
|
|
|
|
|
RELEASE(tmp);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* NSNotificationQueue queue
|
|
|
|
|
*/
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
typedef struct _NSNotificationQueueRegistration
|
|
|
|
|
{
|
1999-11-21 06:33:45 +00:00
|
|
|
|
struct _NSNotificationQueueRegistration *next;
|
|
|
|
|
struct _NSNotificationQueueRegistration *prev;
|
|
|
|
|
NSNotification *notification;
|
|
|
|
|
id name;
|
|
|
|
|
id object;
|
|
|
|
|
NSArray *modes;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
} NSNotificationQueueRegistration;
|
|
|
|
|
|
|
|
|
|
struct _NSNotificationQueueList;
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
typedef struct _NSNotificationQueueList
|
|
|
|
|
{
|
1999-11-21 06:33:45 +00:00
|
|
|
|
struct _NSNotificationQueueRegistration *head;
|
|
|
|
|
struct _NSNotificationQueueRegistration *tail;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
} NSNotificationQueueList;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Queue functions
|
|
|
|
|
*
|
|
|
|
|
* Queue Elem Elem Elem
|
2010-04-13 10:44:58 +00:00
|
|
|
|
* head ---------> next -----------> next -----------> next --> nil
|
|
|
|
|
* nil <-- prev <----------- prev <----------- prev
|
1997-09-01 21:59:51 +00:00
|
|
|
|
* tail --------------------------------------------->
|
|
|
|
|
*/
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
static inline void
|
1999-11-21 06:33:45 +00:00
|
|
|
|
remove_from_queue_no_release(NSNotificationQueueList *queue,
|
|
|
|
|
NSNotificationQueueRegistration *item)
|
1999-04-20 16:28:04 +00:00
|
|
|
|
{
|
2010-04-13 10:44:58 +00:00
|
|
|
|
if (item->next)
|
1999-04-20 16:28:04 +00:00
|
|
|
|
{
|
2010-04-13 10:44:58 +00:00
|
|
|
|
item->next->prev = item->prev;
|
1999-04-20 16:28:04 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-08-17 07:13:05 +00:00
|
|
|
|
NSCAssert(queue->tail == item, @"tail item not at tail of queue!");
|
2010-04-13 10:44:58 +00:00
|
|
|
|
queue->tail = item->prev;
|
1999-04-20 16:28:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-04-13 10:44:58 +00:00
|
|
|
|
if (item->prev)
|
1999-04-20 16:28:04 +00:00
|
|
|
|
{
|
2010-04-13 10:44:58 +00:00
|
|
|
|
item->prev->next = item->next;
|
1999-04-20 16:28:04 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-08-17 07:13:05 +00:00
|
|
|
|
NSCAssert(queue->head == item, @"head item not at head of queue!");
|
2010-04-13 10:44:58 +00:00
|
|
|
|
queue->head = item->next;
|
1999-04-20 16:28:04 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
static void
|
1999-11-21 06:33:45 +00:00
|
|
|
|
remove_from_queue(NSNotificationQueueList *queue,
|
|
|
|
|
NSNotificationQueueRegistration *item, NSZone *_zone)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
remove_from_queue_no_release(queue, item);
|
|
|
|
|
RELEASE(item->notification);
|
|
|
|
|
RELEASE(item->modes);
|
1999-09-16 07:21:34 +00:00
|
|
|
|
NSZoneFree(_zone, item);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
1999-11-21 06:33:45 +00:00
|
|
|
|
add_to_queue(NSNotificationQueueList *queue, NSNotification *notification,
|
|
|
|
|
NSArray *modes, NSZone *_zone)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-11-21 06:33:45 +00:00
|
|
|
|
NSNotificationQueueRegistration *item;
|
|
|
|
|
|
2009-03-10 17:12:47 +00:00
|
|
|
|
#if GS_WITH_GC
|
|
|
|
|
item = NSAllocateCollectable(sizeof(NSNotificationQueueRegistration),
|
|
|
|
|
NSScannedOption);
|
|
|
|
|
#else
|
1999-11-21 06:33:45 +00:00
|
|
|
|
item = NSZoneCalloc(_zone, 1, sizeof(NSNotificationQueueRegistration));
|
2009-03-10 17:12:47 +00:00
|
|
|
|
#endif
|
2002-10-09 06:07:38 +00:00
|
|
|
|
if (item == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSMallocException
|
|
|
|
|
format: @"Unable to add to notification queue"];
|
|
|
|
|
}
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1999-07-14 19:31:28 +00:00
|
|
|
|
item->notification = RETAIN(notification);
|
|
|
|
|
item->name = [notification name];
|
|
|
|
|
item->object = [notification object];
|
|
|
|
|
item->modes = [modes copyWithZone: [modes zone]];
|
|
|
|
|
|
2010-04-13 10:44:58 +00:00
|
|
|
|
item->next = NULL;
|
|
|
|
|
item->prev = queue->tail;
|
1999-07-14 19:31:28 +00:00
|
|
|
|
queue->tail = item;
|
2010-04-13 10:44:58 +00:00
|
|
|
|
if (item->prev)
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
2010-04-13 10:44:58 +00:00
|
|
|
|
item->prev->next = item;
|
1999-11-21 06:33:45 +00:00
|
|
|
|
}
|
1999-07-14 19:31:28 +00:00
|
|
|
|
if (!queue->head)
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
|
|
|
|
queue->head = item;
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
|
|
|
|
|
|
1997-09-01 21:59:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* NSNotificationQueue class implementation
|
|
|
|
|
*/
|
|
|
|
|
|
2002-08-07 15:30:03 +00:00
|
|
|
|
@interface NSNotificationQueue (Private)
|
2009-11-27 10:42:33 +00:00
|
|
|
|
- (NSNotificationCenter*) _center;
|
2002-08-07 15:30:03 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* This class supports asynchronous posting of [NSNotification]s to an
|
|
|
|
|
* [NSNotificationCenter]. The method to add a notification to the queue
|
|
|
|
|
* returns immediately. The queue will periodically post its oldest
|
|
|
|
|
* notification to the notification center. In a multithreaded process,
|
|
|
|
|
* notifications are always sent on the thread that they are posted from.
|
|
|
|
|
*/
|
1997-09-01 21:59:51 +00:00
|
|
|
|
@implementation NSNotificationQueue
|
|
|
|
|
|
2009-11-27 10:42:33 +00:00
|
|
|
|
static NSArray *defaultMode = nil;
|
|
|
|
|
|
|
|
|
|
+ (void) initialize
|
|
|
|
|
{
|
|
|
|
|
if (defaultMode == nil)
|
|
|
|
|
{
|
2010-04-14 12:37:23 +00:00
|
|
|
|
defaultMode = [[NSArray alloc] initWithObjects: (id*)&NSDefaultRunLoopMode
|
2009-11-27 10:42:33 +00:00
|
|
|
|
count: 1];
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-06-22 22:40:40 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the default notification queue for use in this thread. It will
|
|
|
|
|
* always post notifications to the default notification center (for the
|
|
|
|
|
* entire task, which may have multiple threads and therefore multiple
|
|
|
|
|
* notification queues).
|
|
|
|
|
*/
|
1999-07-14 19:31:28 +00:00
|
|
|
|
+ (NSNotificationQueue*) defaultQueue
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
NotificationQueueList *list;
|
|
|
|
|
NSNotificationQueue *item;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
list = currentList();
|
|
|
|
|
item = list->queue;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
if (item == nil)
|
1999-04-20 16:28:04 +00:00
|
|
|
|
{
|
|
|
|
|
item = (NSNotificationQueue*)NSAllocateObject(self,
|
|
|
|
|
0, NSDefaultMallocZone());
|
2005-02-22 11:22:44 +00:00
|
|
|
|
item = [item initWithNotificationCenter:
|
1999-07-14 19:31:28 +00:00
|
|
|
|
[NSNotificationCenter defaultCenter]];
|
2006-06-29 18:01:44 +00:00
|
|
|
|
if (item != nil)
|
|
|
|
|
{
|
|
|
|
|
NSMutableDictionary *d;
|
|
|
|
|
|
|
|
|
|
d = GSCurrentThreadDictionary();
|
|
|
|
|
[d setObject: item forKey: qkey];
|
|
|
|
|
RELEASE(item); /* retained in dictionary. */
|
|
|
|
|
}
|
1999-04-20 16:28:04 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
return item;
|
|
|
|
|
}
|
|
|
|
|
|
1999-07-14 19:31:28 +00:00
|
|
|
|
- (id) init
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
|
return [self initWithNotificationCenter:
|
1999-04-20 16:28:04 +00:00
|
|
|
|
[NSNotificationCenter defaultCenter]];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Initialize a new instance to post notifications to the given
|
|
|
|
|
* notificationCenter (instead of the default).
|
|
|
|
|
*/
|
1999-07-14 19:31:28 +00:00
|
|
|
|
- (id) initWithNotificationCenter: (NSNotificationCenter*)notificationCenter
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_zone = [self zone];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
// init queue
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_center = RETAIN(notificationCenter);
|
2009-03-10 17:12:47 +00:00
|
|
|
|
#if GS_WITH_GC
|
|
|
|
|
_asapQueue = NSAllocateCollectable(sizeof(NSNotificationQueueList),
|
|
|
|
|
NSScannedOption);
|
|
|
|
|
_idleQueue = NSAllocateCollectable(sizeof(NSNotificationQueueList),
|
|
|
|
|
NSScannedOption);
|
|
|
|
|
#else
|
1999-09-16 07:21:34 +00:00
|
|
|
|
_asapQueue = NSZoneCalloc(_zone, 1, sizeof(NSNotificationQueueList));
|
|
|
|
|
_idleQueue = NSZoneCalloc(_zone, 1, sizeof(NSNotificationQueueList));
|
2009-03-10 17:12:47 +00:00
|
|
|
|
#endif
|
2002-10-09 06:07:38 +00:00
|
|
|
|
if (_asapQueue == 0 || _idleQueue == 0)
|
|
|
|
|
{
|
|
|
|
|
DESTROY(self);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* insert in global queue list
|
|
|
|
|
*/
|
|
|
|
|
[NotificationQueueList registerQueue: self];
|
|
|
|
|
}
|
1999-04-20 16:28:04 +00:00
|
|
|
|
return self;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-07-14 19:31:28 +00:00
|
|
|
|
- (void) dealloc
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-07-14 19:31:28 +00:00
|
|
|
|
NSNotificationQueueRegistration *item;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-11-21 06:33:45 +00:00
|
|
|
|
/*
|
|
|
|
|
* remove from class instances list
|
|
|
|
|
*/
|
1999-07-14 19:31:28 +00:00
|
|
|
|
[NotificationQueueList unregisterQueue: self];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-11-21 06:33:45 +00:00
|
|
|
|
/*
|
2009-03-18 15:08:13 +00:00
|
|
|
|
* release items from our queues
|
1999-11-21 06:33:45 +00:00
|
|
|
|
*/
|
2009-03-18 15:08:13 +00:00
|
|
|
|
while ((item = _asapQueue->head) != 0)
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
|
|
|
|
remove_from_queue(_asapQueue, item, _zone);
|
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
NSZoneFree(_zone, _asapQueue);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
2009-03-18 15:08:13 +00:00
|
|
|
|
while ((item = _idleQueue->head) != 0)
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
|
|
|
|
remove_from_queue(_idleQueue, item, _zone);
|
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
NSZoneFree(_zone, _idleQueue);
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-09-16 07:21:34 +00:00
|
|
|
|
RELEASE(_center);
|
1999-07-14 19:31:28 +00:00
|
|
|
|
[super dealloc];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Inserting and Removing Notifications From a Queue */
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Immediately remove all notifications from queue matching notification on
|
|
|
|
|
* name and/or object as specified by coalesce mask, which is an OR
|
|
|
|
|
* ('<code>|</code>') of the options
|
|
|
|
|
* <code>NSNotificationCoalescingOnName</code>,
|
|
|
|
|
* <code>NSNotificationCoalescingOnSender</code> (object), and
|
|
|
|
|
* <code>NSNotificationNoCoalescing</code> (match only the given instance
|
|
|
|
|
* exactly). If both of the first options are specified, notifications must
|
|
|
|
|
* match on both attributes (not just either one). Removed notifications are
|
|
|
|
|
* <em>not</em> posted.
|
|
|
|
|
*/
|
1999-07-14 19:31:28 +00:00
|
|
|
|
- (void) dequeueNotificationsMatching: (NSNotification*)notification
|
2009-02-23 20:42:32 +00:00
|
|
|
|
coalesceMask: (NSUInteger)coalesceMask
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-11-21 06:33:45 +00:00
|
|
|
|
NSNotificationQueueRegistration *item;
|
2010-04-13 10:44:58 +00:00
|
|
|
|
NSNotificationQueueRegistration *prev;
|
1999-11-21 06:33:45 +00:00
|
|
|
|
id name = [notification name];
|
|
|
|
|
id object = [notification object];
|
1999-07-14 19:31:28 +00:00
|
|
|
|
|
1999-11-21 06:33:45 +00:00
|
|
|
|
if ((coalesceMask & NSNotificationCoalescingOnName)
|
|
|
|
|
&& (coalesceMask & NSNotificationCoalescingOnSender))
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* find in ASAP notification in queue matching both
|
|
|
|
|
*/
|
2010-04-13 10:44:58 +00:00
|
|
|
|
for (item = _asapQueue->tail; item; item = prev)
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
2010-04-13 10:44:58 +00:00
|
|
|
|
prev = item->prev;
|
2004-06-22 22:40:40 +00:00
|
|
|
|
//PENDING: should object comparison be '==' instead of isEqual?!
|
1999-11-21 06:33:45 +00:00
|
|
|
|
if ((object == item->object) && [name isEqual: item->name])
|
|
|
|
|
{
|
|
|
|
|
remove_from_queue(_asapQueue, item, _zone);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* find in idle notification in queue matching both
|
|
|
|
|
*/
|
2010-04-13 10:44:58 +00:00
|
|
|
|
for (item = _idleQueue->tail; item; item = prev)
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
2010-04-13 10:44:58 +00:00
|
|
|
|
prev = item->prev;
|
1999-11-21 06:33:45 +00:00
|
|
|
|
if ((object == item->object) && [name isEqual: item->name])
|
|
|
|
|
{
|
|
|
|
|
remove_from_queue(_idleQueue, item, _zone);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if ((coalesceMask & NSNotificationCoalescingOnName))
|
1999-07-14 19:31:28 +00:00
|
|
|
|
{
|
1999-11-21 06:33:45 +00:00
|
|
|
|
/*
|
|
|
|
|
* find in ASAP notification in queue matching name
|
|
|
|
|
*/
|
2010-04-13 10:44:58 +00:00
|
|
|
|
for (item = _asapQueue->tail; item; item = prev)
|
1999-07-14 19:31:28 +00:00
|
|
|
|
{
|
2010-04-13 10:44:58 +00:00
|
|
|
|
prev = item->prev;
|
1999-11-21 06:33:45 +00:00
|
|
|
|
if ([name isEqual: item->name])
|
|
|
|
|
{
|
|
|
|
|
remove_from_queue(_asapQueue, item, _zone);
|
|
|
|
|
}
|
1999-07-14 19:31:28 +00:00
|
|
|
|
}
|
1999-11-21 06:33:45 +00:00
|
|
|
|
/*
|
|
|
|
|
* find in idle notification in queue matching name
|
|
|
|
|
*/
|
2010-04-13 10:44:58 +00:00
|
|
|
|
for (item = _idleQueue->tail; item; item = prev)
|
1999-07-14 19:31:28 +00:00
|
|
|
|
{
|
2010-04-13 10:44:58 +00:00
|
|
|
|
prev = item->prev;
|
1999-11-21 06:33:45 +00:00
|
|
|
|
if ([name isEqual: item->name])
|
|
|
|
|
{
|
|
|
|
|
remove_from_queue(_idleQueue, item, _zone);
|
|
|
|
|
}
|
1999-07-14 19:31:28 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
1999-11-21 06:33:45 +00:00
|
|
|
|
else if ((coalesceMask & NSNotificationCoalescingOnSender))
|
1999-07-14 19:31:28 +00:00
|
|
|
|
{
|
1999-11-21 06:33:45 +00:00
|
|
|
|
/*
|
|
|
|
|
* find in ASAP notification in queue matching sender
|
|
|
|
|
*/
|
2010-04-13 10:44:58 +00:00
|
|
|
|
for (item = _asapQueue->tail; item; item = prev)
|
1999-07-14 19:31:28 +00:00
|
|
|
|
{
|
2010-04-13 10:44:58 +00:00
|
|
|
|
prev = item->prev;
|
1999-11-21 06:33:45 +00:00
|
|
|
|
if (object == item->object)
|
|
|
|
|
{
|
|
|
|
|
remove_from_queue(_asapQueue, item, _zone);
|
|
|
|
|
}
|
1999-07-14 19:31:28 +00:00
|
|
|
|
}
|
1999-11-21 06:33:45 +00:00
|
|
|
|
/*
|
|
|
|
|
* find in idle notification in queue matching sender
|
|
|
|
|
*/
|
2010-04-13 10:44:58 +00:00
|
|
|
|
for (item = _idleQueue->tail; item; item = prev)
|
1999-07-14 19:31:28 +00:00
|
|
|
|
{
|
2010-04-13 10:44:58 +00:00
|
|
|
|
prev = item->prev;
|
1999-11-21 06:33:45 +00:00
|
|
|
|
if (object == item->object)
|
|
|
|
|
{
|
|
|
|
|
remove_from_queue(_idleQueue, item, _zone);
|
|
|
|
|
}
|
1999-07-14 19:31:28 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Sets notification to be posted to notification center at time dependent on
|
|
|
|
|
* postingStyle, which may be either <code>NSPostNow</code> (synchronous post),
|
|
|
|
|
* <code>NSPostASAP</code> (post soon), or <code>NSPostWhenIdle</code> (post
|
|
|
|
|
* when runloop is idle).
|
|
|
|
|
*/
|
1999-07-14 19:31:28 +00:00
|
|
|
|
- (void) enqueueNotification: (NSNotification*)notification
|
2000-02-19 00:40:47 +00:00
|
|
|
|
postingStyle: (NSPostingStyle)postingStyle
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-07-14 19:31:28 +00:00
|
|
|
|
[self enqueueNotification: notification
|
2001-12-17 14:31:42 +00:00
|
|
|
|
postingStyle: postingStyle
|
|
|
|
|
coalesceMask: NSNotificationCoalescingOnName
|
|
|
|
|
+ NSNotificationCoalescingOnSender
|
|
|
|
|
forModes: nil];
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2004-06-22 22:40:40 +00:00
|
|
|
|
/**
|
|
|
|
|
* Sets notification to be posted to notification center at time dependent on
|
|
|
|
|
* postingStyle, which may be either <code>NSPostNow</code> (synchronous
|
|
|
|
|
* post), <code>NSPostASAP</code> (post soon), or <code>NSPostWhenIdle</code>
|
|
|
|
|
* (post when runloop is idle). coalesceMask determines whether this
|
|
|
|
|
* notification should be considered same as other ones already on the queue,
|
|
|
|
|
* in which case they are removed through a call to
|
|
|
|
|
* -dequeueNotificationsMatching:coalesceMask: . The modes argument
|
|
|
|
|
* determines which [NSRunLoop] mode notification may be posted in (nil means
|
2009-11-27 10:42:33 +00:00
|
|
|
|
* NSDefaultRunLoopMode).
|
2004-06-22 22:40:40 +00:00
|
|
|
|
*/
|
1999-07-14 19:31:28 +00:00
|
|
|
|
- (void) enqueueNotification: (NSNotification*)notification
|
2000-02-19 00:40:47 +00:00
|
|
|
|
postingStyle: (NSPostingStyle)postingStyle
|
2009-02-23 20:42:32 +00:00
|
|
|
|
coalesceMask: (NSUInteger)coalesceMask
|
2000-02-19 00:40:47 +00:00
|
|
|
|
forModes: (NSArray*)modes
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2009-11-27 10:42:33 +00:00
|
|
|
|
if (modes == nil)
|
|
|
|
|
{
|
|
|
|
|
modes = defaultMode;
|
|
|
|
|
}
|
1999-07-14 19:31:28 +00:00
|
|
|
|
if (coalesceMask != NSNotificationNoCoalescing)
|
2001-12-17 14:31:42 +00:00
|
|
|
|
{
|
|
|
|
|
[self dequeueNotificationsMatching: notification
|
|
|
|
|
coalesceMask: coalesceMask];
|
|
|
|
|
}
|
1999-07-14 19:31:28 +00:00
|
|
|
|
switch (postingStyle)
|
|
|
|
|
{
|
2005-02-22 11:22:44 +00:00
|
|
|
|
case NSPostNow:
|
2009-11-27 10:42:33 +00:00
|
|
|
|
{
|
|
|
|
|
NSString *mode;
|
|
|
|
|
|
|
|
|
|
mode = [[NSRunLoop currentRunLoop] currentMode];
|
|
|
|
|
if (mode == nil || [modes indexOfObject: mode] != NSNotFound)
|
|
|
|
|
{
|
|
|
|
|
[_center postNotification: notification];
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-07-14 19:31:28 +00:00
|
|
|
|
break;
|
2009-11-27 10:42:33 +00:00
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
case NSPostASAP:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
add_to_queue(_asapQueue, notification, modes, _zone);
|
1999-07-14 19:31:28 +00:00
|
|
|
|
break;
|
2009-11-27 10:42:33 +00:00
|
|
|
|
|
2005-02-22 11:22:44 +00:00
|
|
|
|
case NSPostWhenIdle:
|
1999-09-16 07:21:34 +00:00
|
|
|
|
add_to_queue(_idleQueue, notification, modes, _zone);
|
1999-07-14 19:31:28 +00:00
|
|
|
|
break;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2002-08-07 15:30:03 +00:00
|
|
|
|
@implementation NSNotificationQueue (Private)
|
|
|
|
|
|
2009-11-27 10:42:33 +00:00
|
|
|
|
- (NSNotificationCenter*) _center
|
2002-08-07 15:30:03 +00:00
|
|
|
|
{
|
2009-11-27 10:42:33 +00:00
|
|
|
|
return _center;
|
2002-08-07 15:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
2009-11-27 10:42:33 +00:00
|
|
|
|
static void
|
|
|
|
|
notify(NSNotificationCenter *center, NSNotificationQueueList *list,
|
|
|
|
|
NSString *mode, NSZone *zone)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
2009-11-27 10:42:33 +00:00
|
|
|
|
BOOL allocated = NO;
|
2010-08-17 07:28:44 +00:00
|
|
|
|
void *buf[100];
|
|
|
|
|
void **ptr = buf;
|
2009-11-27 10:42:33 +00:00
|
|
|
|
unsigned len = sizeof(buf) / sizeof(*buf);
|
|
|
|
|
unsigned pos = 0;
|
|
|
|
|
NSNotificationQueueRegistration *item = list->head;
|
|
|
|
|
|
|
|
|
|
/* Gather matching items into a buffer.
|
1999-04-20 16:28:04 +00:00
|
|
|
|
*/
|
2009-11-27 10:42:33 +00:00
|
|
|
|
while (item != 0)
|
1999-04-20 16:28:04 +00:00
|
|
|
|
{
|
2009-11-27 10:42:33 +00:00
|
|
|
|
if (mode == nil || [item->modes indexOfObject: mode] != NSNotFound)
|
|
|
|
|
{
|
|
|
|
|
if (pos == len)
|
|
|
|
|
{
|
|
|
|
|
unsigned want;
|
|
|
|
|
|
|
|
|
|
want = (len == 0) ? 2 : len * 2;
|
|
|
|
|
if (NO == allocated)
|
|
|
|
|
{
|
|
|
|
|
void *tmp;
|
|
|
|
|
|
|
|
|
|
tmp = NSZoneMalloc(NSDefaultMallocZone(),
|
|
|
|
|
want * sizeof(void*));
|
|
|
|
|
memcpy(tmp, (void*)ptr, len * sizeof(void*));
|
|
|
|
|
ptr = tmp;
|
|
|
|
|
allocated = YES;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ptr = NSZoneRealloc(NSDefaultMallocZone(),
|
|
|
|
|
ptr, want * sizeof(void*));
|
|
|
|
|
}
|
|
|
|
|
len = want;
|
|
|
|
|
}
|
|
|
|
|
ptr[pos++] = item;
|
|
|
|
|
}
|
2010-04-13 10:44:58 +00:00
|
|
|
|
item = item->next; // head --> tail uses next link
|
2009-11-27 10:42:33 +00:00
|
|
|
|
}
|
|
|
|
|
len = pos; // Number of items found
|
|
|
|
|
|
2010-08-17 07:28:44 +00:00
|
|
|
|
/* Posting a notification catches exceptions, so it's OK to use
|
|
|
|
|
* retain/release of objects here as we won't get an exception
|
|
|
|
|
* causing a leak.
|
|
|
|
|
*/
|
2009-11-27 10:42:33 +00:00
|
|
|
|
if (len > 0)
|
|
|
|
|
{
|
2010-08-17 07:35:20 +00:00
|
|
|
|
/* First, we make a note of each notification while removing the
|
|
|
|
|
* corresponding list item from the queue ... so that when we get
|
|
|
|
|
* round to posting the notifications we will not get problems
|
|
|
|
|
* with another notif() trying to use the same items.
|
|
|
|
|
*/
|
2009-11-27 10:42:33 +00:00
|
|
|
|
for (pos = 0; pos < len; pos++)
|
|
|
|
|
{
|
|
|
|
|
item = ptr[pos];
|
2010-08-17 07:28:44 +00:00
|
|
|
|
ptr[pos] = RETAIN(item->notification);
|
2009-11-27 10:42:33 +00:00
|
|
|
|
remove_from_queue(list, item, zone);
|
|
|
|
|
}
|
2010-08-17 07:35:20 +00:00
|
|
|
|
|
|
|
|
|
/* Now that we no longer need to worry about r-entrancy,
|
|
|
|
|
* we step through our notifications, posting each one in turn.
|
|
|
|
|
*/
|
2010-08-17 07:28:44 +00:00
|
|
|
|
for (pos = 0; pos < len; pos++)
|
2009-11-27 10:42:33 +00:00
|
|
|
|
{
|
2010-08-17 07:28:44 +00:00
|
|
|
|
NSNotification *n = (NSNotification*)ptr[pos];
|
|
|
|
|
|
|
|
|
|
[center postNotification: n];
|
|
|
|
|
RELEASE(n);
|
2009-11-27 10:42:33 +00:00
|
|
|
|
}
|
2010-08-17 07:35:20 +00:00
|
|
|
|
|
2010-08-17 07:28:44 +00:00
|
|
|
|
if (allocated)
|
2010-08-17 07:13:05 +00:00
|
|
|
|
{
|
2010-08-17 07:28:44 +00:00
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), ptr);
|
2010-08-17 07:13:05 +00:00
|
|
|
|
}
|
1999-04-20 16:28:04 +00:00
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-11-27 10:42:33 +00:00
|
|
|
|
/*
|
|
|
|
|
* The following code handles sending of queued notifications by
|
|
|
|
|
* NSRunLoop.
|
|
|
|
|
*/
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
void
|
2009-11-27 07:53:38 +00:00
|
|
|
|
GSPrivateNotifyASAP(NSString *mode)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
NotificationQueueList *item;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
for (item = currentList(); item; item = item->next)
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
|
|
|
|
if (item->queue)
|
|
|
|
|
{
|
2010-02-24 10:23:47 +00:00
|
|
|
|
notify(item->queue->_center,
|
|
|
|
|
item->queue->_asapQueue,
|
2009-11-27 10:42:33 +00:00
|
|
|
|
mode,
|
2010-02-24 10:23:47 +00:00
|
|
|
|
item->queue->_zone);
|
1999-11-21 06:33:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
void
|
2009-11-27 07:53:38 +00:00
|
|
|
|
GSPrivateNotifyIdle(NSString *mode)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
NotificationQueueList *item;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
for (item = currentList(); item; item = item->next)
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
|
|
|
|
if (item->queue)
|
|
|
|
|
{
|
2010-02-24 10:23:47 +00:00
|
|
|
|
notify(item->queue->_center,
|
|
|
|
|
item->queue->_idleQueue,
|
2009-11-27 10:42:33 +00:00
|
|
|
|
mode,
|
2010-02-24 10:23:47 +00:00
|
|
|
|
item->queue->_zone);
|
1999-11-21 06:33:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
BOOL
|
2009-11-27 07:53:38 +00:00
|
|
|
|
GSPrivateNotifyMore(NSString *mode)
|
1997-09-01 21:59:51 +00:00
|
|
|
|
{
|
1999-04-20 16:28:04 +00:00
|
|
|
|
NotificationQueueList *item;
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|
1999-04-20 16:28:04 +00:00
|
|
|
|
for (item = currentList(); item; item = item->next)
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
2009-11-27 10:42:33 +00:00
|
|
|
|
if (item->queue != nil)
|
1999-11-21 06:33:45 +00:00
|
|
|
|
{
|
2009-11-27 10:42:33 +00:00
|
|
|
|
NSNotificationQueueRegistration *r;
|
|
|
|
|
|
2010-02-24 10:23:47 +00:00
|
|
|
|
r = item->queue->_idleQueue->head;
|
2009-11-27 10:42:33 +00:00
|
|
|
|
while (r != 0)
|
|
|
|
|
{
|
|
|
|
|
if (mode == nil || [r->modes indexOfObject: mode] != NSNotFound)
|
|
|
|
|
{
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
2010-04-13 10:44:58 +00:00
|
|
|
|
r = r->next;
|
2009-11-27 10:42:33 +00:00
|
|
|
|
}
|
1999-11-21 06:33:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-04-20 16:28:04 +00:00
|
|
|
|
return NO;
|
|
|
|
|
}
|
1997-09-01 21:59:51 +00:00
|
|
|
|
|