11 typedef struct W_Notification
{
19 const char *WMGetNotificationName(WMNotification
* notification
)
21 return notification
->name
;
24 void *WMGetNotificationObject(WMNotification
* notification
)
26 return notification
->object
;
29 void *WMGetNotificationClientData(WMNotification
* notification
)
31 return notification
->clientData
;
34 WMNotification
*WMCreateNotification(const char *name
, void *object
, void *clientData
)
38 nPtr
= wmalloc(sizeof(Notification
));
40 nPtr
->object
= object
;
41 nPtr
->clientData
= clientData
;
47 void WMReleaseNotification(WMNotification
* notification
)
49 notification
->refCount
--;
51 if (notification
->refCount
< 1) {
56 WMNotification
*WMRetainNotification(WMNotification
* notification
)
58 notification
->refCount
++;
63 /***************** Notification Center *****************/
65 typedef struct NotificationObserver
{
66 WMNotificationObserverAction
*observerAction
;
72 struct NotificationObserver
*prev
; /* for tables */
73 struct NotificationObserver
*next
;
74 struct NotificationObserver
*nextAction
; /* for observerTable */
75 } NotificationObserver
;
77 typedef struct W_NotificationCenter
{
78 WMHashTable
*nameTable
; /* names -> observer lists */
79 WMHashTable
*objectTable
; /* object -> observer lists */
80 NotificationObserver
*nilList
; /* obervers that catch everything */
82 WMHashTable
*observerTable
; /* observer -> NotificationObserver */
85 /* default (and only) center */
86 static NotificationCenter
*notificationCenter
= NULL
;
88 void W_InitNotificationCenter(void)
90 notificationCenter
= wmalloc(sizeof(NotificationCenter
));
91 notificationCenter
->nameTable
= WMCreateHashTable(WMStringPointerHashCallbacks
);
92 notificationCenter
->objectTable
= WMCreateHashTable(WMIntHashCallbacks
);
93 notificationCenter
->nilList
= NULL
;
94 notificationCenter
->observerTable
= WMCreateHashTable(WMIntHashCallbacks
);
97 void W_ReleaseNotificationCenter(void)
99 if (notificationCenter
) {
100 if (notificationCenter
->nameTable
)
101 WMFreeHashTable(notificationCenter
->nameTable
);
102 if (notificationCenter
->objectTable
)
103 WMFreeHashTable(notificationCenter
->objectTable
);
104 if (notificationCenter
->observerTable
)
105 WMFreeHashTable(notificationCenter
->observerTable
);
107 wfree(notificationCenter
);
108 notificationCenter
= NULL
;
113 WMAddNotificationObserver(WMNotificationObserverAction
* observerAction
,
114 void *observer
, const char *name
, void *object
)
116 NotificationObserver
*oRec
, *rec
;
118 oRec
= wmalloc(sizeof(NotificationObserver
));
119 oRec
->observerAction
= observerAction
;
120 oRec
->observer
= observer
;
122 oRec
->object
= object
;
126 /* put this action in the list of actions for this observer */
127 rec
= (NotificationObserver
*) WMHashInsert(notificationCenter
->observerTable
, observer
, oRec
);
130 /* if this is not the first action for the observer */
131 oRec
->nextAction
= rec
;
133 oRec
->nextAction
= NULL
;
136 if (!name
&& !object
) {
138 oRec
->next
= notificationCenter
->nilList
;
139 if (notificationCenter
->nilList
) {
140 notificationCenter
->nilList
->prev
= oRec
;
142 notificationCenter
->nilList
= oRec
;
144 /* any message coming from object */
145 rec
= (NotificationObserver
*) WMHashInsert(notificationCenter
->objectTable
, object
, oRec
);
151 /* name && (object || !object) */
152 rec
= (NotificationObserver
*) WMHashInsert(notificationCenter
->nameTable
, name
, oRec
);
160 void WMPostNotification(WMNotification
* notification
)
162 NotificationObserver
*orec
, *tmp
;
164 WMRetainNotification(notification
);
166 /* tell the observers that want to know about a particular message */
167 orec
= (NotificationObserver
*) WMHashGet(notificationCenter
->nameTable
, notification
->name
);
172 if (!orec
->object
|| !notification
->object
|| orec
->object
== notification
->object
) {
173 /* tell the observer */
174 if (orec
->observerAction
) {
175 (*orec
->observerAction
) (orec
->observer
, notification
);
182 /* tell the observers that want to know about an object */
183 orec
= (NotificationObserver
*) WMHashGet(notificationCenter
->objectTable
, notification
->object
);
188 /* tell the observer */
189 if (orec
->observerAction
) {
190 (*orec
->observerAction
) (orec
->observer
, notification
);
195 /* tell the catch all observers */
196 orec
= notificationCenter
->nilList
;
200 /* tell the observer */
201 if (orec
->observerAction
) {
202 (*orec
->observerAction
) (orec
->observer
, notification
);
207 WMReleaseNotification(notification
);
210 void WMRemoveNotificationObserver(void *observer
)
212 NotificationObserver
*orec
, *tmp
, *rec
;
214 /* get the list of actions the observer is doing */
215 orec
= (NotificationObserver
*) WMHashGet(notificationCenter
->observerTable
, observer
);
218 * FOREACH orec IN actionlist for observer
220 * remove from respective lists/tables
225 tmp
= orec
->nextAction
;
227 if (!orec
->name
&& !orec
->object
) {
229 if (notificationCenter
->nilList
== orec
)
230 notificationCenter
->nilList
= orec
->next
;
231 } else if (!orec
->name
) {
232 /* any message coming from object */
233 rec
= (NotificationObserver
*) WMHashGet(notificationCenter
->objectTable
, orec
->object
);
235 /* replace table entry */
237 WMHashInsert(notificationCenter
->objectTable
, orec
->object
, orec
->next
);
239 WMHashRemove(notificationCenter
->objectTable
, orec
->object
);
243 /* name && (object || !object) */
244 rec
= (NotificationObserver
*) WMHashGet(notificationCenter
->nameTable
, orec
->name
);
246 /* replace table entry */
248 WMHashInsert(notificationCenter
->nameTable
, orec
->name
, orec
->next
);
250 WMHashRemove(notificationCenter
->nameTable
, orec
->name
);
255 orec
->prev
->next
= orec
->next
;
257 orec
->next
->prev
= orec
->prev
;
264 WMHashRemove(notificationCenter
->observerTable
, observer
);
267 void WMRemoveNotificationObserverWithName(void *observer
, const char *name
, void *object
)
269 NotificationObserver
*orec
, *tmp
, *rec
;
270 NotificationObserver
*newList
= NULL
;
272 /* get the list of actions the observer is doing */
273 orec
= (NotificationObserver
*) WMHashGet(notificationCenter
->observerTable
, observer
);
275 WMHashRemove(notificationCenter
->observerTable
, observer
);
277 /* rebuild the list of actions for the observer */
280 tmp
= orec
->nextAction
;
281 if (orec
->name
== name
&& orec
->object
== object
) {
282 if (!name
&& !object
) {
283 if (notificationCenter
->nilList
== orec
)
284 notificationCenter
->nilList
= orec
->next
;
287 (NotificationObserver
*) WMHashGet(notificationCenter
->objectTable
,
290 assert(rec
->prev
== NULL
);
291 /* replace table entry */
293 WMHashInsert(notificationCenter
->objectTable
,
294 orec
->object
, orec
->next
);
296 WMHashRemove(notificationCenter
->objectTable
, orec
->object
);
300 rec
= (NotificationObserver
*) WMHashGet(notificationCenter
->nameTable
,
303 assert(rec
->prev
== NULL
);
304 /* replace table entry */
306 WMHashInsert(notificationCenter
->nameTable
,
307 orec
->name
, orec
->next
);
309 WMHashRemove(notificationCenter
->nameTable
, orec
->name
);
315 orec
->prev
->next
= orec
->next
;
317 orec
->next
->prev
= orec
->prev
;
320 /* append this action in the new action list */
321 orec
->nextAction
= NULL
;
325 NotificationObserver
*p
;
328 while (p
->nextAction
) {
331 p
->nextAction
= orec
;
337 /* reinsert the list to the table */
339 WMHashInsert(notificationCenter
->observerTable
, observer
, newList
);
343 void WMPostNotificationName(const char *name
, void *object
, void *clientData
)
345 WMNotification
*notification
;
347 notification
= WMCreateNotification(name
, object
, clientData
);
349 WMPostNotification(notification
);
351 WMReleaseNotification(notification
);
354 /**************** Notification Queues ****************/
356 typedef struct W_NotificationQueue
{
360 struct W_NotificationQueue
*next
;
363 static WMNotificationQueue
*notificationQueueList
= NULL
;
366 static WMNotificationQueue
*notificationQueue
= NULL
;
368 WMNotificationQueue
*WMGetDefaultNotificationQueue(void)
370 if (!notificationQueue
)
371 notificationQueue
= WMCreateNotificationQueue();
373 return notificationQueue
;
376 WMNotificationQueue
*WMCreateNotificationQueue(void)
378 NotificationQueue
*queue
;
380 queue
= wmalloc(sizeof(NotificationQueue
));
381 queue
->asapQueue
= WMCreateArrayWithDestructor(8, (WMFreeDataProc
*) WMReleaseNotification
);
382 queue
->idleQueue
= WMCreateArrayWithDestructor(8, (WMFreeDataProc
*) WMReleaseNotification
);
383 queue
->next
= notificationQueueList
;
385 notificationQueueList
= queue
;
390 void WMEnqueueNotification(WMNotificationQueue
* queue
, WMNotification
* notification
, WMPostingStyle postingStyle
)
392 WMEnqueueCoalesceNotification(queue
, notification
, postingStyle
, WNCOnName
| WNCOnSender
);
395 #define NOTIF ((WMNotification*)cdata)
396 #define ITEM ((WMNotification*)item)
398 static int matchSenderAndName(const void *item
, const void *cdata
)
400 return (NOTIF
->object
== ITEM
->object
&& strcmp(NOTIF
->name
, ITEM
->name
) == 0);
403 static int matchSender(const void *item
, const void *cdata
)
405 return (NOTIF
->object
== ITEM
->object
);
408 static int matchName(const void *item
, const void *cdata
)
410 return (strcmp(NOTIF
->name
, ITEM
->name
) == 0);
416 void WMDequeueNotificationMatching(WMNotificationQueue
* queue
, WMNotification
* notification
, unsigned mask
)
418 WMMatchDataProc
*matchFunc
;
420 if ((mask
& WNCOnName
) && (mask
& WNCOnSender
))
421 matchFunc
= matchSenderAndName
;
422 else if (mask
& WNCOnName
)
423 matchFunc
= matchName
;
424 else if (mask
& WNCOnSender
)
425 matchFunc
= matchSender
;
429 WMRemoveFromArrayMatching(queue
->asapQueue
, matchFunc
, notification
);
430 WMRemoveFromArrayMatching(queue
->idleQueue
, matchFunc
, notification
);
434 WMEnqueueCoalesceNotification(WMNotificationQueue
* queue
,
435 WMNotification
* notification
, WMPostingStyle postingStyle
, unsigned coalesceMask
)
437 if (coalesceMask
!= WNCNone
)
438 WMDequeueNotificationMatching(queue
, notification
, coalesceMask
);
440 switch (postingStyle
) {
442 WMPostNotification(notification
);
443 WMReleaseNotification(notification
);
447 WMAddToArray(queue
->asapQueue
, notification
);
451 WMAddToArray(queue
->idleQueue
, notification
);
456 void W_FlushASAPNotificationQueue(void)
458 WMNotificationQueue
*queue
= notificationQueueList
;
461 while (WMGetArrayItemCount(queue
->asapQueue
)) {
462 WMPostNotification(WMGetFromArray(queue
->asapQueue
, 0));
463 WMDeleteFromArray(queue
->asapQueue
, 0);
470 void W_FlushIdleNotificationQueue(void)
472 WMNotificationQueue
*queue
= notificationQueueList
;
475 while (WMGetArrayItemCount(queue
->idleQueue
)) {
476 WMPostNotification(WMGetFromArray(queue
->idleQueue
, 0));
477 WMDeleteFromArray(queue
->idleQueue
, 0);