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);