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(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
, 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
= WMHashInsert(notificationCenter
->observerTable
, observer
, oRec
);
139 /* if this is not the first action for the observer */
140 oRec
->nextAction
= rec
;
142 oRec
->nextAction
= NULL
;
145 if (!name
&& !object
) {
147 oRec
->next
= notificationCenter
->nilList
;
148 if (notificationCenter
->nilList
) {
149 notificationCenter
->nilList
->prev
= oRec
;
151 notificationCenter
->nilList
= oRec
;
153 /* any message coming from object */
154 rec
= WMHashInsert(notificationCenter
->objectTable
, object
, oRec
);
160 /* name && (object || !object) */
161 rec
= WMHashInsert(notificationCenter
->nameTable
, name
, oRec
);
171 WMPostNotification(WMNotification
*notification
)
173 NotificationObserver
*orec
, *tmp
;
175 WMRetainNotification(notification
);
177 /* tell the observers that want to know about a particular message */
178 orec
= WMHashGet(notificationCenter
->nameTable
, notification
->name
);
183 if (!orec
->object
|| !notification
->object
184 || orec
->object
== notification
->object
) {
185 /* tell the observer */
186 if (orec
->observerAction
) {
187 (*orec
->observerAction
)(orec
->observer
, notification
);
194 /* tell the observers that want to know about an object */
195 orec
= WMHashGet(notificationCenter
->objectTable
, notification
->object
);
200 /* tell the observer */
201 if (orec
->observerAction
) {
202 (*orec
->observerAction
)(orec
->observer
, notification
);
207 /* tell the catch all observers */
208 orec
= notificationCenter
->nilList
;
212 /* tell the observer */
213 if (orec
->observerAction
) {
214 (*orec
->observerAction
)(orec
->observer
, notification
);
219 WMReleaseNotification(notification
);
224 WMRemoveNotificationObserver(void *observer
)
226 NotificationObserver
*orec
, *tmp
, *rec
;
228 /* get the list of actions the observer is doing */
229 orec
= WMHashGet(notificationCenter
->observerTable
, observer
);
232 * FOREACH orec IN actionlist for observer
234 * remove from respective lists/tables
239 tmp
= orec
->nextAction
;
241 if (!orec
->name
&& !orec
->object
) {
243 if (notificationCenter
->nilList
==orec
)
244 notificationCenter
->nilList
= orec
->next
;
245 } else if (!orec
->name
) {
246 /* any message coming from object */
247 rec
= WMHashGet(notificationCenter
->objectTable
, orec
->object
);
249 /* replace table entry */
251 WMHashInsert(notificationCenter
->objectTable
, orec
->object
,
254 WMHashRemove(notificationCenter
->objectTable
, orec
->object
);
258 /* name && (object || !object) */
259 rec
= WMHashGet(notificationCenter
->nameTable
, orec
->name
);
261 /* replace table entry */
263 WMHashInsert(notificationCenter
->nameTable
, orec
->name
,
266 WMHashRemove(notificationCenter
->nameTable
, orec
->name
);
271 orec
->prev
->next
= orec
->next
;
273 orec
->next
->prev
= orec
->prev
;
280 WMHashRemove(notificationCenter
->observerTable
, observer
);
285 WMRemoveNotificationObserverWithName(void *observer
, char *name
, void *object
)
287 NotificationObserver
*orec
, *tmp
, *rec
;
288 NotificationObserver
*newList
= NULL
;
290 /* get the list of actions the observer is doing */
291 orec
= WMHashGet(notificationCenter
->observerTable
, observer
);
293 WMHashRemove(notificationCenter
->observerTable
, observer
);
295 /* rebuild the list of actions for the observer */
298 tmp
= orec
->nextAction
;
299 if (orec
->name
== name
&& orec
->object
== object
) {
300 if (!name
&& !object
) {
301 if (notificationCenter
->nilList
== orec
)
302 notificationCenter
->nilList
= orec
->next
;
304 rec
= WMHashGet(notificationCenter
->objectTable
, orec
->object
);
306 assert(rec
->prev
==NULL
);
307 /* replace table entry */
309 WMHashInsert(notificationCenter
->objectTable
,
310 orec
->object
, orec
->next
);
312 WMHashRemove(notificationCenter
->objectTable
,
317 rec
= WMHashGet(notificationCenter
->nameTable
, orec
->name
);
319 assert(rec
->prev
==NULL
);
320 /* replace table entry */
322 WMHashInsert(notificationCenter
->nameTable
,
323 orec
->name
, orec
->next
);
325 WMHashRemove(notificationCenter
->nameTable
,
332 orec
->prev
->next
= orec
->next
;
334 orec
->next
->prev
= orec
->prev
;
337 /* append this action in the new action list */
338 orec
->nextAction
= NULL
;
342 NotificationObserver
*p
;
345 while (p
->nextAction
) {
348 p
->nextAction
= orec
;
354 /* reinsert the list to the table */
356 WMHashInsert(notificationCenter
->observerTable
, observer
, newList
);
362 WMPostNotificationName(char *name
, void *object
, void *clientData
)
364 WMNotification
*notification
;
366 notification
= WMCreateNotification(name
, object
, clientData
);
368 WMPostNotification(notification
);
370 WMReleaseNotification(notification
);
375 /**************** Notification Queues ****************/
378 typedef struct W_NotificationQueue
{
382 struct W_NotificationQueue
*next
;
386 static WMNotificationQueue
*notificationQueueList
= NULL
;
389 static WMNotificationQueue
*notificationQueue
= NULL
;
393 WMGetDefaultNotificationQueue(void)
395 if (!notificationQueue
)
396 notificationQueue
= WMCreateNotificationQueue();
398 return notificationQueue
;
403 WMCreateNotificationQueue(void)
405 NotificationQueue
*queue
;
407 queue
= wmalloc(sizeof(NotificationQueue
));
409 queue
->asapQueue
= WMCreateBag(8);
410 queue
->idleQueue
= WMCreateBag(8);
411 queue
->next
= notificationQueueList
;
413 notificationQueueList
= queue
;
421 WMEnqueueNotification(WMNotificationQueue
*queue
, WMNotification
*notification
,
422 WMPostingStyle postingStyle
)
424 WMEnqueueCoalesceNotification(queue
, notification
, postingStyle
,
425 WNCOnName
|WNCOnSender
);
431 WMDequeueNotificationMatching(WMNotificationQueue
*queue
,
432 WMNotification
*notification
, unsigned mask
)
437 if ((mask
& WNCOnName
) && (mask
& WNCOnSender
)) {
438 for (i
= 0; i
< WMGetBagItemCount(queue
->asapQueue
); i
++) {
439 tmp
= WMGetFromBag(queue
->asapQueue
, i
);
441 if (notification
->object
== tmp
->object
&&
442 strcmp(notification
->name
, tmp
->name
) == 0) {
443 WMRemoveFromBag(queue
->asapQueue
, tmp
);
444 WMReleaseNotification(tmp
);
448 for (i
= 0; i
< WMGetBagItemCount(queue
->idleQueue
); i
++) {
449 tmp
= WMGetFromBag(queue
->idleQueue
, i
);
451 if (notification
->object
== tmp
->object
&&
452 strcmp(notification
->name
, tmp
->name
) == 0) {
453 WMRemoveFromBag(queue
->idleQueue
, tmp
);
454 WMReleaseNotification(tmp
);
458 } else if (mask
& WNCOnName
) {
459 for (i
= 0; i
< WMGetBagItemCount(queue
->asapQueue
); i
++) {
460 tmp
= WMGetFromBag(queue
->asapQueue
, i
);
462 if (strcmp(notification
->name
, tmp
->name
) == 0) {
463 WMRemoveFromBag(queue
->asapQueue
, tmp
);
464 WMReleaseNotification(tmp
);
468 for (i
= 0; i
< WMGetBagItemCount(queue
->idleQueue
); i
++) {
469 tmp
= WMGetFromBag(queue
->idleQueue
, i
);
471 if (strcmp(notification
->name
, tmp
->name
) == 0) {
472 WMRemoveFromBag(queue
->idleQueue
, tmp
);
473 WMReleaseNotification(tmp
);
477 } else if (mask
& WNCOnSender
) {
478 for (i
= 0; i
< WMGetBagItemCount(queue
->asapQueue
); i
++) {
479 tmp
= WMGetFromBag(queue
->asapQueue
, i
);
481 if (notification
->object
== tmp
->object
) {
482 WMRemoveFromBag(queue
->asapQueue
, tmp
);
483 WMReleaseNotification(tmp
);
487 for (i
= 0; i
< WMGetBagItemCount(queue
->idleQueue
); i
++) {
488 tmp
= WMGetFromBag(queue
->idleQueue
, i
);
490 if (notification
->object
== tmp
->object
) {
491 WMRemoveFromBag(queue
->idleQueue
, tmp
);
492 WMReleaseNotification(tmp
);
501 WMEnqueueCoalesceNotification(WMNotificationQueue
*queue
,
502 WMNotification
*notification
,
503 WMPostingStyle postingStyle
,
504 unsigned coalesceMask
)
506 if (coalesceMask
!= WNCNone
)
507 WMDequeueNotificationMatching(queue
, notification
, coalesceMask
);
509 switch (postingStyle
) {
511 WMPostNotification(notification
);
512 WMReleaseNotification(notification
);
516 WMPutInBag(queue
->asapQueue
, notification
);
520 WMPutInBag(queue
->idleQueue
, notification
);
527 W_FlushASAPNotificationQueue()
529 WMNotificationQueue
*queue
= notificationQueueList
;
532 while (WMGetBagItemCount(queue
->asapQueue
)) {
533 WMNotification
*tmp
= WMGetFromBag(queue
->asapQueue
, 0);
535 WMPostNotification(tmp
);
536 WMReleaseNotification(tmp
);
537 WMDeleteFromBag(queue
->asapQueue
, 0);
546 W_FlushIdleNotificationQueue()
548 WMNotificationQueue
*queue
= notificationQueueList
;
551 while (WMGetBagItemCount(queue
->idleQueue
)) {
552 WMNotification
*tmp
= WMGetFromBag(queue
->idleQueue
, 0);
554 WMPostNotification(tmp
);
555 WMReleaseNotification(tmp
);
556 WMDeleteFromBag(queue
->idleQueue
, 0);