11 typedef struct W_Notification
{
19 extern void W_FlushASAPNotificationQueue();
23 WMGetNotificationName(WMNotification
*notification
)
25 return notification
->name
;
30 WMGetNotificationObject(WMNotification
*notification
)
32 return notification
->object
;
37 WMGetNotificationClientData(WMNotification
*notification
)
39 return notification
->clientData
;
44 WMCreateNotification(char *name
, void *object
, void *clientData
)
48 nPtr
= wmalloc(sizeof(Notification
));
51 nPtr
->object
= object
;
52 nPtr
->clientData
= clientData
;
61 WMReleaseNotification(WMNotification
*notification
)
63 notification
->refCount
--;
65 if (notification
->refCount
< 1) {
72 WMRetainNotification(WMNotification
*notification
)
74 notification
->refCount
++;
80 /***************** Notification Center *****************/
82 typedef struct NotificationObserver
{
83 WMNotificationObserverAction
*observerAction
;
89 struct NotificationObserver
*prev
; /* for tables */
90 struct NotificationObserver
*next
;
91 struct NotificationObserver
*nextAction
; /* for observerTable */
92 } NotificationObserver
;
95 typedef struct W_NotificationCenter
{
96 WMHashTable
*nameTable
; /* names -> observer lists */
97 WMHashTable
*objectTable
; /* object -> observer lists */
98 NotificationObserver
*nilList
; /* obervers that catch everything */
100 WMHashTable
*observerTable
; /* observer -> NotificationObserver */
101 } NotificationCenter
;
104 /* default (and only) center */
105 static NotificationCenter
*notificationCenter
= NULL
;
109 W_InitNotificationCenter(void)
111 notificationCenter
= wmalloc(sizeof(NotificationCenter
));
113 notificationCenter
->nameTable
= WMCreateHashTable(WMStringPointerHashCallbacks
);
114 notificationCenter
->objectTable
= WMCreateHashTable(WMIntHashCallbacks
);
115 notificationCenter
->nilList
= NULL
;
117 notificationCenter
->observerTable
= WMCreateHashTable(WMIntHashCallbacks
);
122 WMAddNotificationObserver(WMNotificationObserverAction
*observerAction
,
123 void *observer
, char *name
, void *object
)
125 NotificationObserver
*oRec
, *rec
;
127 oRec
= wmalloc(sizeof(NotificationObserver
));
128 oRec
->observerAction
= observerAction
;
129 oRec
->observer
= observer
;
131 oRec
->object
= object
;
136 /* put this action in the list of actions for this observer */
137 rec
= WMHashInsert(notificationCenter
->observerTable
, observer
, oRec
);
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
= WMHashInsert(notificationCenter
->objectTable
, object
, oRec
);
161 /* name && (object || !object) */
162 rec
= WMHashInsert(notificationCenter
->nameTable
, name
, oRec
);
172 WMPostNotification(WMNotification
*notification
)
174 NotificationObserver
*orec
, *tmp
;
176 WMRetainNotification(notification
);
178 /* tell the observers that want to know about a particular message */
179 orec
= WMHashGet(notificationCenter
->nameTable
, notification
->name
);
184 if (!orec
->object
|| 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
);
221 W_FlushASAPNotificationQueue();
226 WMRemoveNotificationObserver(void *observer
)
228 NotificationObserver
*orec
, *tmp
, *rec
;
230 /* get the list of actions the observer is doing */
231 orec
= WMHashGet(notificationCenter
->observerTable
, observer
);
234 * FOREACH orec IN actionlist for observer
236 * remove from respective lists/tables
241 tmp
= orec
->nextAction
;
243 if (!orec
->name
&& !orec
->object
) {
245 if (notificationCenter
->nilList
==orec
)
246 notificationCenter
->nilList
= orec
->next
;
247 } else if (!orec
->name
) {
248 /* any message coming from object */
249 rec
= WMHashGet(notificationCenter
->objectTable
, orec
->object
);
251 /* replace table entry */
253 WMHashInsert(notificationCenter
->objectTable
, orec
->object
,
256 WMHashRemove(notificationCenter
->objectTable
, orec
->object
);
260 /* name && (object || !object) */
261 rec
= WMHashGet(notificationCenter
->nameTable
, orec
->name
);
263 /* replace table entry */
265 WMHashInsert(notificationCenter
->nameTable
, orec
->name
,
268 WMHashRemove(notificationCenter
->nameTable
, orec
->name
);
273 orec
->prev
->next
= orec
->next
;
275 orec
->next
->prev
= orec
->prev
;
282 WMHashRemove(notificationCenter
->observerTable
, observer
);
287 WMRemoveNotificationObserverWithName(void *observer
, char *name
, void *object
)
289 NotificationObserver
*orec
, *tmp
, *rec
;
290 NotificationObserver
*newList
= NULL
;
292 /* get the list of actions the observer is doing */
293 orec
= WMHashGet(notificationCenter
->observerTable
, observer
);
295 WMHashRemove(notificationCenter
->observerTable
, observer
);
297 /* rebuild the list of actions for the observer */
300 tmp
= orec
->nextAction
;
301 if (orec
->name
== name
&& orec
->object
== object
) {
302 if (!name
&& !object
) {
303 if (notificationCenter
->nilList
== orec
)
304 notificationCenter
->nilList
= orec
->next
;
306 rec
= WMHashGet(notificationCenter
->objectTable
, orec
->object
);
308 assert(rec
->prev
==NULL
);
309 /* replace table entry */
311 WMHashInsert(notificationCenter
->objectTable
,
312 orec
->object
, orec
->next
);
314 WMHashRemove(notificationCenter
->objectTable
,
319 rec
= WMHashGet(notificationCenter
->nameTable
, orec
->name
);
321 assert(rec
->prev
==NULL
);
322 /* replace table entry */
324 WMHashInsert(notificationCenter
->nameTable
,
325 orec
->name
, orec
->next
);
327 WMHashRemove(notificationCenter
->nameTable
,
334 orec
->prev
->next
= orec
->next
;
336 orec
->next
->prev
= orec
->prev
;
339 /* append this action in the new action list */
340 orec
->nextAction
= NULL
;
344 NotificationObserver
*p
;
347 while (p
->nextAction
) {
350 p
->nextAction
= orec
;
356 /* reinsert the list to the table */
358 WMHashInsert(notificationCenter
->observerTable
, observer
, newList
);
364 WMPostNotificationName(char *name
, void *object
, void *clientData
)
366 WMNotification
*notification
;
368 notification
= WMCreateNotification(name
, object
, clientData
);
370 WMPostNotification(notification
);
372 WMReleaseNotification(notification
);
377 /**************** Notification Queues ****************/
380 typedef struct W_NotificationQueue
{
384 struct W_NotificationQueue
*next
;
388 static WMNotificationQueue
*notificationQueueList
= NULL
;
391 static WMNotificationQueue
*notificationQueue
= NULL
;
395 WMGetDefaultNotificationQueue(void)
397 if (!notificationQueue
)
398 notificationQueue
= WMCreateNotificationQueue();
400 return notificationQueue
;
405 WMCreateNotificationQueue(void)
407 NotificationQueue
*queue
;
409 queue
= wmalloc(sizeof(NotificationQueue
));
411 queue
->asapQueue
= NULL
;
412 queue
->idleQueue
= NULL
;
413 queue
->next
= notificationQueueList
;
415 notificationQueueList
= queue
;
423 WMEnqueueNotification(WMNotificationQueue
*queue
, WMNotification
*notification
,
424 WMPostingStyle postingStyle
)
426 WMEnqueueCoalesceNotification(queue
, notification
, postingStyle
,
427 WNCOnName
|WNCOnSender
);
432 matchName(void *a
, void *b
)
434 WMNotification
*n1
= (WMNotification
*)a
;
435 WMNotification
*n2
= (WMNotification
*)b
;
437 return strcmp(n1
->name
, n2
->name
);
442 matchSender(void *a
, void *b
)
444 WMNotification
*n1
= (WMNotification
*)a
;
445 WMNotification
*n2
= (WMNotification
*)b
;
447 return (n1
->object
== n2
->object
);
452 WMDequeueNotificationMatching(WMNotificationQueue
*queue
,
453 WMNotification
*notification
, unsigned mask
)
457 if (mask
& WNCOnName
) {
458 while ((n
= lfind(notification
->name
, queue
->asapQueue
, matchName
))) {
459 queue
->asapQueue
= lremove(queue
->asapQueue
, n
);
460 WMReleaseNotification((WMNotification
*)n
);
462 while ((n
= lfind(notification
->name
, queue
->idleQueue
, matchName
))) {
463 queue
->idleQueue
= lremove(queue
->idleQueue
, n
);
464 WMReleaseNotification((WMNotification
*)n
);
467 if (mask
& WNCOnSender
) {
468 while ((n
= lfind(notification
->name
, queue
->asapQueue
, matchSender
))) {
469 queue
->asapQueue
= lremove(queue
->asapQueue
, n
);
470 WMReleaseNotification((WMNotification
*)n
);
472 while ((n
= lfind(notification
->name
, queue
->idleQueue
, matchSender
))) {
473 queue
->idleQueue
= lremove(queue
->idleQueue
, n
);
474 WMReleaseNotification((WMNotification
*)n
);
481 WMEnqueueCoalesceNotification(WMNotificationQueue
*queue
,
482 WMNotification
*notification
,
483 WMPostingStyle postingStyle
,
484 unsigned coalesceMask
)
486 if (coalesceMask
!= WNCNone
)
487 WMDequeueNotificationMatching(queue
, notification
, coalesceMask
);
489 switch (postingStyle
) {
491 WMPostNotification(notification
);
495 queue
->asapQueue
= lappend(queue
->asapQueue
,
496 lcons(notification
, NULL
));
500 queue
->idleQueue
= lappend(queue
->idleQueue
,
501 lcons(notification
, NULL
));
508 W_FlushASAPNotificationQueue()
510 WMNotificationQueue
*queue
= notificationQueueList
;
513 while (queue
->asapQueue
) {
514 WMPostNotification((WMNotification
*)lhead(queue
->asapQueue
));
515 queue
->asapQueue
= lremovehead(queue
->asapQueue
);
522 W_FlushIdleNotificationQueue()
524 WMNotificationQueue
*queue
= notificationQueueList
;
527 while (queue
->idleQueue
) {
528 WMPostNotification((WMNotification
*)lhead(queue
->idleQueue
));
529 queue
->idleQueue
= lremovehead(queue
->idleQueue
);