9 typedef struct W_Notification
{
16 extern void W_FlushASAPNotificationQueue();
18 const char *WMGetNotificationName(WMNotification
* notification
)
20 return notification
->name
;
23 void *WMGetNotificationObject(WMNotification
* notification
)
25 return notification
->object
;
28 void *WMGetNotificationClientData(WMNotification
* notification
)
30 return notification
->clientData
;
33 WMNotification
*WMCreateNotification(const char *name
, void *object
, void *clientData
)
37 nPtr
= wmalloc(sizeof(Notification
));
39 nPtr
->object
= object
;
40 nPtr
->clientData
= clientData
;
46 void WMReleaseNotification(WMNotification
* notification
)
48 notification
->refCount
--;
50 if (notification
->refCount
< 1) {
55 WMNotification
*WMRetainNotification(WMNotification
* notification
)
57 notification
->refCount
++;
62 /***************** Notification Center *****************/
64 typedef struct NotificationObserver
{
65 WMNotificationObserverAction
*observerAction
;
71 struct NotificationObserver
*prev
; /* for tables */
72 struct NotificationObserver
*next
;
73 struct NotificationObserver
*nextAction
; /* for observerTable */
74 } NotificationObserver
;
76 typedef struct W_NotificationCenter
{
77 WMHashTable
*nameTable
; /* names -> observer lists */
78 WMHashTable
*objectTable
; /* object -> observer lists */
79 NotificationObserver
*nilList
; /* obervers that catch everything */
81 WMHashTable
*observerTable
; /* observer -> NotificationObserver */
84 /* default (and only) center */
85 static NotificationCenter
*notificationCenter
= NULL
;
87 void W_InitNotificationCenter(void)
89 notificationCenter
= wmalloc(sizeof(NotificationCenter
));
90 notificationCenter
->nameTable
= WMCreateHashTable(WMStringPointerHashCallbacks
);
91 notificationCenter
->objectTable
= WMCreateHashTable(WMIntHashCallbacks
);
92 notificationCenter
->nilList
= NULL
;
93 notificationCenter
->observerTable
= WMCreateHashTable(WMIntHashCallbacks
);
97 WMAddNotificationObserver(WMNotificationObserverAction
* observerAction
,
98 void *observer
, const char *name
, void *object
)
100 NotificationObserver
*oRec
, *rec
;
102 oRec
= wmalloc(sizeof(NotificationObserver
));
103 oRec
->observerAction
= observerAction
;
104 oRec
->observer
= observer
;
106 oRec
->object
= object
;
110 /* put this action in the list of actions for this observer */
111 rec
= (NotificationObserver
*) WMHashInsert(notificationCenter
->observerTable
, observer
, oRec
);
114 /* if this is not the first action for the observer */
115 oRec
->nextAction
= rec
;
117 oRec
->nextAction
= NULL
;
120 if (!name
&& !object
) {
122 oRec
->next
= notificationCenter
->nilList
;
123 if (notificationCenter
->nilList
) {
124 notificationCenter
->nilList
->prev
= oRec
;
126 notificationCenter
->nilList
= oRec
;
128 /* any message coming from object */
129 rec
= (NotificationObserver
*) WMHashInsert(notificationCenter
->objectTable
, object
, oRec
);
135 /* name && (object || !object) */
136 rec
= (NotificationObserver
*) WMHashInsert(notificationCenter
->nameTable
, name
, oRec
);
144 void WMPostNotification(WMNotification
* notification
)
146 NotificationObserver
*orec
, *tmp
;
148 WMRetainNotification(notification
);
150 /* tell the observers that want to know about a particular message */
151 orec
= (NotificationObserver
*) WMHashGet(notificationCenter
->nameTable
, notification
->name
);
156 if (!orec
->object
|| !notification
->object
|| orec
->object
== notification
->object
) {
157 /* tell the observer */
158 if (orec
->observerAction
) {
159 (*orec
->observerAction
) (orec
->observer
, notification
);
166 /* tell the observers that want to know about an object */
167 orec
= (NotificationObserver
*) WMHashGet(notificationCenter
->objectTable
, notification
->object
);
172 /* tell the observer */
173 if (orec
->observerAction
) {
174 (*orec
->observerAction
) (orec
->observer
, notification
);
179 /* tell the catch all observers */
180 orec
= notificationCenter
->nilList
;
184 /* tell the observer */
185 if (orec
->observerAction
) {
186 (*orec
->observerAction
) (orec
->observer
, notification
);
191 WMReleaseNotification(notification
);
194 void WMRemoveNotificationObserver(void *observer
)
196 NotificationObserver
*orec
, *tmp
, *rec
;
198 /* get the list of actions the observer is doing */
199 orec
= (NotificationObserver
*) WMHashGet(notificationCenter
->observerTable
, observer
);
202 * FOREACH orec IN actionlist for observer
204 * remove from respective lists/tables
209 tmp
= orec
->nextAction
;
211 if (!orec
->name
&& !orec
->object
) {
213 if (notificationCenter
->nilList
== orec
)
214 notificationCenter
->nilList
= orec
->next
;
215 } else if (!orec
->name
) {
216 /* any message coming from object */
217 rec
= (NotificationObserver
*) WMHashGet(notificationCenter
->objectTable
, orec
->object
);
219 /* replace table entry */
221 WMHashInsert(notificationCenter
->objectTable
, orec
->object
, orec
->next
);
223 WMHashRemove(notificationCenter
->objectTable
, orec
->object
);
227 /* name && (object || !object) */
228 rec
= (NotificationObserver
*) WMHashGet(notificationCenter
->nameTable
, orec
->name
);
230 /* replace table entry */
232 WMHashInsert(notificationCenter
->nameTable
, orec
->name
, orec
->next
);
234 WMHashRemove(notificationCenter
->nameTable
, orec
->name
);
239 orec
->prev
->next
= orec
->next
;
241 orec
->next
->prev
= orec
->prev
;
248 WMHashRemove(notificationCenter
->observerTable
, observer
);
251 void WMRemoveNotificationObserverWithName(void *observer
, const char *name
, void *object
)
253 NotificationObserver
*orec
, *tmp
, *rec
;
254 NotificationObserver
*newList
= NULL
;
256 /* get the list of actions the observer is doing */
257 orec
= (NotificationObserver
*) WMHashGet(notificationCenter
->observerTable
, observer
);
259 WMHashRemove(notificationCenter
->observerTable
, observer
);
261 /* rebuild the list of actions for the observer */
264 tmp
= orec
->nextAction
;
265 if (orec
->name
== name
&& orec
->object
== object
) {
266 if (!name
&& !object
) {
267 if (notificationCenter
->nilList
== orec
)
268 notificationCenter
->nilList
= orec
->next
;
271 (NotificationObserver
*) WMHashGet(notificationCenter
->objectTable
,
274 assert(rec
->prev
== NULL
);
275 /* replace table entry */
277 WMHashInsert(notificationCenter
->objectTable
,
278 orec
->object
, orec
->next
);
280 WMHashRemove(notificationCenter
->objectTable
, orec
->object
);
284 rec
= (NotificationObserver
*) WMHashGet(notificationCenter
->nameTable
,
287 assert(rec
->prev
== NULL
);
288 /* replace table entry */
290 WMHashInsert(notificationCenter
->nameTable
,
291 orec
->name
, orec
->next
);
293 WMHashRemove(notificationCenter
->nameTable
, orec
->name
);
299 orec
->prev
->next
= orec
->next
;
301 orec
->next
->prev
= orec
->prev
;
304 /* append this action in the new action list */
305 orec
->nextAction
= NULL
;
309 NotificationObserver
*p
;
312 while (p
->nextAction
) {
315 p
->nextAction
= orec
;
321 /* reinsert the list to the table */
323 WMHashInsert(notificationCenter
->observerTable
, observer
, newList
);
327 void WMPostNotificationName(const char *name
, void *object
, void *clientData
)
329 WMNotification
*notification
;
331 notification
= WMCreateNotification(name
, object
, clientData
);
333 WMPostNotification(notification
);
335 WMReleaseNotification(notification
);
338 /**************** Notification Queues ****************/
340 typedef struct W_NotificationQueue
{
344 struct W_NotificationQueue
*next
;
347 static WMNotificationQueue
*notificationQueueList
= NULL
;
350 static WMNotificationQueue
*notificationQueue
= NULL
;
352 WMNotificationQueue
*WMGetDefaultNotificationQueue(void)
354 if (!notificationQueue
)
355 notificationQueue
= WMCreateNotificationQueue();
357 return notificationQueue
;
360 WMNotificationQueue
*WMCreateNotificationQueue(void)
362 NotificationQueue
*queue
;
364 queue
= wmalloc(sizeof(NotificationQueue
));
365 queue
->asapQueue
= WMCreateArrayWithDestructor(8, (WMFreeDataProc
*) WMReleaseNotification
);
366 queue
->idleQueue
= WMCreateArrayWithDestructor(8, (WMFreeDataProc
*) WMReleaseNotification
);
367 queue
->next
= notificationQueueList
;
369 notificationQueueList
= queue
;
374 void WMEnqueueNotification(WMNotificationQueue
* queue
, WMNotification
* notification
, WMPostingStyle postingStyle
)
376 WMEnqueueCoalesceNotification(queue
, notification
, postingStyle
, WNCOnName
| WNCOnSender
);
379 #define NOTIF ((WMNotification*)cdata)
380 #define ITEM ((WMNotification*)item)
382 static int matchSenderAndName(const void *item
, const void *cdata
)
384 return (NOTIF
->object
== ITEM
->object
&& strcmp(NOTIF
->name
, ITEM
->name
) == 0);
387 static int matchSender(const void *item
, const void *cdata
)
389 return (NOTIF
->object
== ITEM
->object
);
392 static int matchName(const void *item
, const void *cdata
)
394 return (strcmp(NOTIF
->name
, ITEM
->name
) == 0);
400 void WMDequeueNotificationMatching(WMNotificationQueue
* queue
, WMNotification
* notification
, unsigned mask
)
402 WMMatchDataProc
*matchFunc
;
404 if ((mask
& WNCOnName
) && (mask
& WNCOnSender
))
405 matchFunc
= matchSenderAndName
;
406 else if (mask
& WNCOnName
)
407 matchFunc
= matchName
;
408 else if (mask
& WNCOnSender
)
409 matchFunc
= matchSender
;
413 WMRemoveFromArrayMatching(queue
->asapQueue
, matchFunc
, notification
);
414 WMRemoveFromArrayMatching(queue
->idleQueue
, matchFunc
, notification
);
418 WMEnqueueCoalesceNotification(WMNotificationQueue
* queue
,
419 WMNotification
* notification
, WMPostingStyle postingStyle
, unsigned coalesceMask
)
421 if (coalesceMask
!= WNCNone
)
422 WMDequeueNotificationMatching(queue
, notification
, coalesceMask
);
424 switch (postingStyle
) {
426 WMPostNotification(notification
);
427 WMReleaseNotification(notification
);
431 WMAddToArray(queue
->asapQueue
, notification
);
435 WMAddToArray(queue
->idleQueue
, notification
);
440 void W_FlushASAPNotificationQueue()
442 WMNotificationQueue
*queue
= notificationQueueList
;
445 while (WMGetArrayItemCount(queue
->asapQueue
)) {
446 WMPostNotification(WMGetFromArray(queue
->asapQueue
, 0));
447 WMDeleteFromArray(queue
->asapQueue
, 0);
454 void W_FlushIdleNotificationQueue()
456 WMNotificationQueue
*queue
= notificationQueueList
;
459 while (WMGetArrayItemCount(queue
->idleQueue
)) {
460 WMPostNotification(WMGetFromArray(queue
->idleQueue
, 0));
461 WMDeleteFromArray(queue
->idleQueue
, 0);