10
typedef struct W_Notification {
18
extern void W_FlushASAPNotificationQueue();
22
WMGetNotificationName(WMNotification *notification)
24
return notification->name;
29
WMGetNotificationObject(WMNotification *notification)
31
return notification->object;
36
WMGetNotificationClientData(WMNotification *notification)
38
return notification->clientData;
43
WMCreateNotification(const char *name, void *object, void *clientData)
47
nPtr = wmalloc(sizeof(Notification));
50
nPtr->object = object;
51
nPtr->clientData = clientData;
60
WMReleaseNotification(WMNotification *notification)
62
notification->refCount--;
64
if (notification->refCount < 1) {
71
WMRetainNotification(WMNotification *notification)
73
notification->refCount++;
79
/***************** Notification Center *****************/
81
typedef struct NotificationObserver {
82
WMNotificationObserverAction *observerAction;
88
struct NotificationObserver *prev; /* for tables */
89
struct NotificationObserver *next;
90
struct NotificationObserver *nextAction; /* for observerTable */
91
} NotificationObserver;
94
typedef struct W_NotificationCenter {
95
WMHashTable *nameTable; /* names -> observer lists */
96
WMHashTable *objectTable; /* object -> observer lists */
97
NotificationObserver *nilList; /* obervers that catch everything */
99
WMHashTable *observerTable; /* observer -> NotificationObserver */
100
} NotificationCenter;
103
/* default (and only) center */
104
static NotificationCenter *notificationCenter = NULL;
108
W_InitNotificationCenter(void)
110
notificationCenter = wmalloc(sizeof(NotificationCenter));
112
notificationCenter->nameTable = WMCreateHashTable(WMStringPointerHashCallbacks);
113
notificationCenter->objectTable = WMCreateHashTable(WMIntHashCallbacks);
114
notificationCenter->nilList = NULL;
116
notificationCenter->observerTable = WMCreateHashTable(WMIntHashCallbacks);
121
WMAddNotificationObserver(WMNotificationObserverAction *observerAction,
122
void *observer, const char *name, void *object)
124
NotificationObserver *oRec, *rec;
126
oRec = wmalloc(sizeof(NotificationObserver));
127
oRec->observerAction = observerAction;
128
oRec->observer = observer;
130
oRec->object = object;
135
/* put this action in the list of actions for this observer */
136
rec = (NotificationObserver*)WMHashInsert(notificationCenter->observerTable,
140
/* if this is not the first action for the observer */
141
oRec->nextAction = rec;
143
oRec->nextAction = NULL;
146
if (!name && !object) {
148
oRec->next = notificationCenter->nilList;
149
if (notificationCenter->nilList) {
150
notificationCenter->nilList->prev = oRec;
152
notificationCenter->nilList = oRec;
154
/* any message coming from object */
155
rec = (NotificationObserver*)WMHashInsert(notificationCenter->objectTable,
162
/* name && (object || !object) */
163
rec = (NotificationObserver*)WMHashInsert(notificationCenter->nameTable,
174
WMPostNotification(WMNotification *notification)
176
NotificationObserver *orec, *tmp;
178
WMRetainNotification(notification);
180
/* tell the observers that want to know about a particular message */
181
orec = (NotificationObserver*)WMHashGet(notificationCenter->nameTable,
187
if (!orec->object || !notification->object
188
|| orec->object == notification->object) {
189
/* tell the observer */
190
if (orec->observerAction) {
191
(*orec->observerAction)(orec->observer, notification);
198
/* tell the observers that want to know about an object */
199
orec = (NotificationObserver*)WMHashGet(notificationCenter->objectTable,
200
notification->object);
205
/* tell the observer */
206
if (orec->observerAction) {
207
(*orec->observerAction)(orec->observer, notification);
212
/* tell the catch all observers */
213
orec = notificationCenter->nilList;
217
/* tell the observer */
218
if (orec->observerAction) {
219
(*orec->observerAction)(orec->observer, notification);
224
WMReleaseNotification(notification);
229
WMRemoveNotificationObserver(void *observer)
231
NotificationObserver *orec, *tmp, *rec;
233
/* get the list of actions the observer is doing */
234
orec = (NotificationObserver*)WMHashGet(notificationCenter->observerTable,
238
* FOREACH orec IN actionlist for observer
240
* remove from respective lists/tables
245
tmp = orec->nextAction;
247
if (!orec->name && !orec->object) {
249
if (notificationCenter->nilList==orec)
250
notificationCenter->nilList = orec->next;
251
} else if (!orec->name) {
252
/* any message coming from object */
253
rec = (NotificationObserver*)WMHashGet(notificationCenter->objectTable,
256
/* replace table entry */
258
WMHashInsert(notificationCenter->objectTable, orec->object,
261
WMHashRemove(notificationCenter->objectTable, orec->object);
265
/* name && (object || !object) */
266
rec = (NotificationObserver*)WMHashGet(notificationCenter->nameTable,
269
/* replace table entry */
271
WMHashInsert(notificationCenter->nameTable, orec->name,
274
WMHashRemove(notificationCenter->nameTable, orec->name);
279
orec->prev->next = orec->next;
281
orec->next->prev = orec->prev;
288
WMHashRemove(notificationCenter->observerTable, observer);
293
WMRemoveNotificationObserverWithName(void *observer, const char *name, void *object)
295
NotificationObserver *orec, *tmp, *rec;
296
NotificationObserver *newList = NULL;
298
/* get the list of actions the observer is doing */
299
orec = (NotificationObserver*)WMHashGet(notificationCenter->observerTable, observer);
301
WMHashRemove(notificationCenter->observerTable, observer);
303
/* rebuild the list of actions for the observer */
306
tmp = orec->nextAction;
307
if (orec->name == name && orec->object == object) {
308
if (!name && !object) {
309
if (notificationCenter->nilList == orec)
310
notificationCenter->nilList = orec->next;
312
rec = (NotificationObserver*)WMHashGet(notificationCenter->objectTable, orec->object);
314
assert(rec->prev==NULL);
315
/* replace table entry */
317
WMHashInsert(notificationCenter->objectTable,
318
orec->object, orec->next);
320
WMHashRemove(notificationCenter->objectTable,
325
rec = (NotificationObserver*)WMHashGet(notificationCenter->nameTable,
328
assert(rec->prev==NULL);
329
/* replace table entry */
331
WMHashInsert(notificationCenter->nameTable,
332
orec->name, orec->next);
334
WMHashRemove(notificationCenter->nameTable,
341
orec->prev->next = orec->next;
343
orec->next->prev = orec->prev;
346
/* append this action in the new action list */
347
orec->nextAction = NULL;
351
NotificationObserver *p;
354
while (p->nextAction) {
357
p->nextAction = orec;
363
/* reinsert the list to the table */
365
WMHashInsert(notificationCenter->observerTable, observer, newList);
371
WMPostNotificationName(const char *name, void *object, void *clientData)
373
WMNotification *notification;
375
notification = WMCreateNotification(name, object, clientData);
377
WMPostNotification(notification);
379
WMReleaseNotification(notification);
384
/**************** Notification Queues ****************/
387
typedef struct W_NotificationQueue {
391
struct W_NotificationQueue *next;
395
static WMNotificationQueue *notificationQueueList = NULL;
398
static WMNotificationQueue *notificationQueue = NULL;
402
WMGetDefaultNotificationQueue(void)
404
if (!notificationQueue)
405
notificationQueue = WMCreateNotificationQueue();
407
return notificationQueue;
412
WMCreateNotificationQueue(void)
414
NotificationQueue *queue;
416
queue = wmalloc(sizeof(NotificationQueue));
419
WMCreateArrayWithDestructor(8, (WMFreeDataProc*)WMReleaseNotification);
421
WMCreateArrayWithDestructor(8, (WMFreeDataProc*)WMReleaseNotification);
422
queue->next = notificationQueueList;
424
notificationQueueList = queue;
432
WMEnqueueNotification(WMNotificationQueue *queue, WMNotification *notification,
433
WMPostingStyle postingStyle)
435
WMEnqueueCoalesceNotification(queue, notification, postingStyle,
436
WNCOnName|WNCOnSender);
440
#define NOTIF ((WMNotification*)cdata)
441
#define ITEM ((WMNotification*)item)
444
matchSenderAndName(void *item, void *cdata)
446
return (NOTIF->object==ITEM->object && strcmp(NOTIF->name, ITEM->name)==0);
451
matchSender(void *item, void *cdata)
453
return (NOTIF->object == ITEM->object);
458
matchName(void *item, void *cdata)
460
return (strcmp(NOTIF->name, ITEM->name)==0);
468
WMDequeueNotificationMatching(WMNotificationQueue *queue,
469
WMNotification *notification, unsigned mask)
471
WMMatchDataProc *matchFunc;
473
if ((mask & WNCOnName) && (mask & WNCOnSender))
474
matchFunc = matchSenderAndName;
475
else if (mask & WNCOnName)
476
matchFunc = matchName;
477
else if (mask & WNCOnSender)
478
matchFunc = matchSender;
482
WMRemoveFromArrayMatching(queue->asapQueue, matchFunc, notification);
483
WMRemoveFromArrayMatching(queue->idleQueue, matchFunc, notification);
488
WMEnqueueCoalesceNotification(WMNotificationQueue *queue,
489
WMNotification *notification,
490
WMPostingStyle postingStyle,
491
unsigned coalesceMask)
493
if (coalesceMask != WNCNone)
494
WMDequeueNotificationMatching(queue, notification, coalesceMask);
496
switch (postingStyle) {
498
WMPostNotification(notification);
499
WMReleaseNotification(notification);
503
WMAddToArray(queue->asapQueue, notification);
507
WMAddToArray(queue->idleQueue, notification);
514
W_FlushASAPNotificationQueue()
516
WMNotificationQueue *queue = notificationQueueList;
519
while (WMGetArrayItemCount(queue->asapQueue)) {
520
WMPostNotification(WMGetFromArray(queue->asapQueue, 0));
521
WMDeleteFromArray(queue->asapQueue, 0);
530
W_FlushIdleNotificationQueue()
532
WMNotificationQueue *queue = notificationQueueList;
535
while (WMGetArrayItemCount(queue->idleQueue)) {
536
WMPostNotification(WMGetFromArray(queue->idleQueue, 0));
537
WMDeleteFromArray(queue->idleQueue, 0);