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
));
40 nPtr
->object
= object
;
41 nPtr
->clientData
= clientData
;
48 void WMReleaseNotification(WMNotification
* notification
)
50 notification
->refCount
--;
52 if (notification
->refCount
< 1) {
57 WMNotification
*WMRetainNotification(WMNotification
* notification
)
59 notification
->refCount
++;
64 /***************** Notification Center *****************/
66 typedef struct NotificationObserver
{
67 WMNotificationObserverAction
*observerAction
;
73 struct NotificationObserver
*prev
; /* for tables */
74 struct NotificationObserver
*next
;
75 struct NotificationObserver
*nextAction
; /* for observerTable */
76 } NotificationObserver
;
78 typedef struct W_NotificationCenter
{
79 WMHashTable
*nameTable
; /* names -> observer lists */
80 WMHashTable
*objectTable
; /* object -> observer lists */
81 NotificationObserver
*nilList
; /* obervers that catch everything */
83 WMHashTable
*observerTable
; /* observer -> NotificationObserver */
86 /* default (and only) center */
87 static NotificationCenter
*notificationCenter
= NULL
;
89 void W_InitNotificationCenter(void)
91 notificationCenter
= wmalloc(sizeof(NotificationCenter
));
93 notificationCenter
->nameTable
= WMCreateHashTable(WMStringPointerHashCallbacks
);
94 notificationCenter
->objectTable
= WMCreateHashTable(WMIntHashCallbacks
);
95 notificationCenter
->nilList
= NULL
;
97 notificationCenter
->observerTable
= WMCreateHashTable(WMIntHashCallbacks
);
101 WMAddNotificationObserver(WMNotificationObserverAction
* observerAction
,
102 void *observer
, const char *name
, void *object
)
104 NotificationObserver
*oRec
, *rec
;
106 oRec
= wmalloc(sizeof(NotificationObserver
));
107 oRec
->observerAction
= observerAction
;
108 oRec
->observer
= observer
;
110 oRec
->object
= object
;
114 /* put this action in the list of actions for this observer */
115 rec
= (NotificationObserver
*) WMHashInsert(notificationCenter
->observerTable
, observer
, oRec
);
118 /* if this is not the first action for the observer */
119 oRec
->nextAction
= rec
;
121 oRec
->nextAction
= NULL
;
124 if (!name
&& !object
) {
126 oRec
->next
= notificationCenter
->nilList
;
127 if (notificationCenter
->nilList
) {
128 notificationCenter
->nilList
->prev
= oRec
;
130 notificationCenter
->nilList
= oRec
;
132 /* any message coming from object */
133 rec
= (NotificationObserver
*) WMHashInsert(notificationCenter
->objectTable
, object
, oRec
);
139 /* name && (object || !object) */
140 rec
= (NotificationObserver
*) WMHashInsert(notificationCenter
->nameTable
, name
, oRec
);
148 void WMPostNotification(WMNotification
* notification
)
150 NotificationObserver
*orec
, *tmp
;
152 WMRetainNotification(notification
);
154 /* tell the observers that want to know about a particular message */
155 orec
= (NotificationObserver
*) WMHashGet(notificationCenter
->nameTable
, notification
->name
);
160 if (!orec
->object
|| !notification
->object
|| orec
->object
== notification
->object
) {
161 /* tell the observer */
162 if (orec
->observerAction
) {
163 (*orec
->observerAction
) (orec
->observer
, notification
);
170 /* tell the observers that want to know about an object */
171 orec
= (NotificationObserver
*) WMHashGet(notificationCenter
->objectTable
, notification
->object
);
176 /* tell the observer */
177 if (orec
->observerAction
) {
178 (*orec
->observerAction
) (orec
->observer
, notification
);
183 /* tell the catch all observers */
184 orec
= notificationCenter
->nilList
;
188 /* tell the observer */
189 if (orec
->observerAction
) {
190 (*orec
->observerAction
) (orec
->observer
, notification
);
195 WMReleaseNotification(notification
);
198 void WMRemoveNotificationObserver(void *observer
)
200 NotificationObserver
*orec
, *tmp
, *rec
;
202 /* get the list of actions the observer is doing */
203 orec
= (NotificationObserver
*) WMHashGet(notificationCenter
->observerTable
, observer
);
206 * FOREACH orec IN actionlist for observer
208 * remove from respective lists/tables
213 tmp
= orec
->nextAction
;
215 if (!orec
->name
&& !orec
->object
) {
217 if (notificationCenter
->nilList
== orec
)
218 notificationCenter
->nilList
= orec
->next
;
219 } else if (!orec
->name
) {
220 /* any message coming from object */
221 rec
= (NotificationObserver
*) WMHashGet(notificationCenter
->objectTable
, orec
->object
);
223 /* replace table entry */
225 WMHashInsert(notificationCenter
->objectTable
, orec
->object
, orec
->next
);
227 WMHashRemove(notificationCenter
->objectTable
, orec
->object
);
231 /* name && (object || !object) */
232 rec
= (NotificationObserver
*) WMHashGet(notificationCenter
->nameTable
, orec
->name
);
234 /* replace table entry */
236 WMHashInsert(notificationCenter
->nameTable
, orec
->name
, orec
->next
);
238 WMHashRemove(notificationCenter
->nameTable
, orec
->name
);
243 orec
->prev
->next
= orec
->next
;
245 orec
->next
->prev
= orec
->prev
;
252 WMHashRemove(notificationCenter
->observerTable
, observer
);
255 void WMRemoveNotificationObserverWithName(void *observer
, const char *name
, void *object
)
257 NotificationObserver
*orec
, *tmp
, *rec
;
258 NotificationObserver
*newList
= NULL
;
260 /* get the list of actions the observer is doing */
261 orec
= (NotificationObserver
*) WMHashGet(notificationCenter
->observerTable
, observer
);
263 WMHashRemove(notificationCenter
->observerTable
, observer
);
265 /* rebuild the list of actions for the observer */
268 tmp
= orec
->nextAction
;
269 if (orec
->name
== name
&& orec
->object
== object
) {
270 if (!name
&& !object
) {
271 if (notificationCenter
->nilList
== orec
)
272 notificationCenter
->nilList
= orec
->next
;
275 (NotificationObserver
*) WMHashGet(notificationCenter
->objectTable
,
278 assert(rec
->prev
== NULL
);
279 /* replace table entry */
281 WMHashInsert(notificationCenter
->objectTable
,
282 orec
->object
, orec
->next
);
284 WMHashRemove(notificationCenter
->objectTable
, orec
->object
);
288 rec
= (NotificationObserver
*) WMHashGet(notificationCenter
->nameTable
,
291 assert(rec
->prev
== NULL
);
292 /* replace table entry */
294 WMHashInsert(notificationCenter
->nameTable
,
295 orec
->name
, orec
->next
);
297 WMHashRemove(notificationCenter
->nameTable
, orec
->name
);
303 orec
->prev
->next
= orec
->next
;
305 orec
->next
->prev
= orec
->prev
;
308 /* append this action in the new action list */
309 orec
->nextAction
= NULL
;
313 NotificationObserver
*p
;
316 while (p
->nextAction
) {
319 p
->nextAction
= orec
;
325 /* reinsert the list to the table */
327 WMHashInsert(notificationCenter
->observerTable
, observer
, newList
);
331 void WMPostNotificationName(const char *name
, void *object
, void *clientData
)
333 WMNotification
*notification
;
335 notification
= WMCreateNotification(name
, object
, clientData
);
337 WMPostNotification(notification
);
339 WMReleaseNotification(notification
);
342 /**************** Notification Queues ****************/
344 typedef struct W_NotificationQueue
{
348 struct W_NotificationQueue
*next
;
351 static WMNotificationQueue
*notificationQueueList
= NULL
;
354 static WMNotificationQueue
*notificationQueue
= NULL
;
356 WMNotificationQueue
*WMGetDefaultNotificationQueue(void)
358 if (!notificationQueue
)
359 notificationQueue
= WMCreateNotificationQueue();
361 return notificationQueue
;
364 WMNotificationQueue
*WMCreateNotificationQueue(void)
366 NotificationQueue
*queue
;
368 queue
= wmalloc(sizeof(NotificationQueue
));
370 queue
->asapQueue
= WMCreateArrayWithDestructor(8, (WMFreeDataProc
*) WMReleaseNotification
);
371 queue
->idleQueue
= WMCreateArrayWithDestructor(8, (WMFreeDataProc
*) WMReleaseNotification
);
372 queue
->next
= notificationQueueList
;
374 notificationQueueList
= queue
;
379 void WMEnqueueNotification(WMNotificationQueue
* queue
, WMNotification
* notification
, WMPostingStyle postingStyle
)
381 WMEnqueueCoalesceNotification(queue
, notification
, postingStyle
, WNCOnName
| WNCOnSender
);
384 #define NOTIF ((WMNotification*)cdata)
385 #define ITEM ((WMNotification*)item)
387 static int matchSenderAndName(void *item
, void *cdata
)
389 return (NOTIF
->object
== ITEM
->object
&& strcmp(NOTIF
->name
, ITEM
->name
) == 0);
392 static int matchSender(void *item
, void *cdata
)
394 return (NOTIF
->object
== ITEM
->object
);
397 static int matchName(void *item
, void *cdata
)
399 return (strcmp(NOTIF
->name
, ITEM
->name
) == 0);
405 void WMDequeueNotificationMatching(WMNotificationQueue
* queue
, WMNotification
* notification
, unsigned mask
)
407 WMMatchDataProc
*matchFunc
;
409 if ((mask
& WNCOnName
) && (mask
& WNCOnSender
))
410 matchFunc
= matchSenderAndName
;
411 else if (mask
& WNCOnName
)
412 matchFunc
= matchName
;
413 else if (mask
& WNCOnSender
)
414 matchFunc
= matchSender
;
418 WMRemoveFromArrayMatching(queue
->asapQueue
, matchFunc
, notification
);
419 WMRemoveFromArrayMatching(queue
->idleQueue
, matchFunc
, notification
);
423 WMEnqueueCoalesceNotification(WMNotificationQueue
* queue
,
424 WMNotification
* notification
, WMPostingStyle postingStyle
, unsigned coalesceMask
)
426 if (coalesceMask
!= WNCNone
)
427 WMDequeueNotificationMatching(queue
, notification
, coalesceMask
);
429 switch (postingStyle
) {
431 WMPostNotification(notification
);
432 WMReleaseNotification(notification
);
436 WMAddToArray(queue
->asapQueue
, notification
);
440 WMAddToArray(queue
->idleQueue
, notification
);
445 void W_FlushASAPNotificationQueue()
447 WMNotificationQueue
*queue
= notificationQueueList
;
450 while (WMGetArrayItemCount(queue
->asapQueue
)) {
451 WMPostNotification(WMGetFromArray(queue
->asapQueue
, 0));
452 WMDeleteFromArray(queue
->asapQueue
, 0);
459 void W_FlushIdleNotificationQueue()
461 WMNotificationQueue
*queue
= notificationQueueList
;
464 while (WMGetArrayItemCount(queue
->idleQueue
)) {
465 WMPostNotification(WMGetFromArray(queue
->idleQueue
, 0));
466 WMDeleteFromArray(queue
->idleQueue
, 0);