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
|| !notification
->object
185 || orec
->object
== notification
->object
) {
186 /* tell the observer */
187 if (orec
->observerAction
) {
188 (*orec
->observerAction
)(orec
->observer
, notification
);
195 /* tell the observers that want to know about an object */
196 orec
= WMHashGet(notificationCenter
->objectTable
, notification
->object
);
201 /* tell the observer */
202 if (orec
->observerAction
) {
203 (*orec
->observerAction
)(orec
->observer
, notification
);
208 /* tell the catch all observers */
209 orec
= notificationCenter
->nilList
;
213 /* tell the observer */
214 if (orec
->observerAction
) {
215 (*orec
->observerAction
)(orec
->observer
, notification
);
220 WMReleaseNotification(notification
);
222 W_FlushASAPNotificationQueue();
227 WMRemoveNotificationObserver(void *observer
)
229 NotificationObserver
*orec
, *tmp
, *rec
;
231 /* get the list of actions the observer is doing */
232 orec
= WMHashGet(notificationCenter
->observerTable
, observer
);
235 * FOREACH orec IN actionlist for observer
237 * remove from respective lists/tables
242 tmp
= orec
->nextAction
;
244 if (!orec
->name
&& !orec
->object
) {
246 if (notificationCenter
->nilList
==orec
)
247 notificationCenter
->nilList
= orec
->next
;
248 } else if (!orec
->name
) {
249 /* any message coming from object */
250 rec
= WMHashGet(notificationCenter
->objectTable
, orec
->object
);
252 /* replace table entry */
254 WMHashInsert(notificationCenter
->objectTable
, orec
->object
,
257 WMHashRemove(notificationCenter
->objectTable
, orec
->object
);
261 /* name && (object || !object) */
262 rec
= WMHashGet(notificationCenter
->nameTable
, orec
->name
);
264 /* replace table entry */
266 WMHashInsert(notificationCenter
->nameTable
, orec
->name
,
269 WMHashRemove(notificationCenter
->nameTable
, orec
->name
);
274 orec
->prev
->next
= orec
->next
;
276 orec
->next
->prev
= orec
->prev
;
283 WMHashRemove(notificationCenter
->observerTable
, observer
);
288 WMRemoveNotificationObserverWithName(void *observer
, char *name
, void *object
)
290 NotificationObserver
*orec
, *tmp
, *rec
;
291 NotificationObserver
*newList
= NULL
;
293 /* get the list of actions the observer is doing */
294 orec
= WMHashGet(notificationCenter
->observerTable
, observer
);
296 WMHashRemove(notificationCenter
->observerTable
, observer
);
298 /* rebuild the list of actions for the observer */
301 tmp
= orec
->nextAction
;
302 if (orec
->name
== name
&& orec
->object
== object
) {
303 if (!name
&& !object
) {
304 if (notificationCenter
->nilList
== orec
)
305 notificationCenter
->nilList
= orec
->next
;
307 rec
= WMHashGet(notificationCenter
->objectTable
, orec
->object
);
309 assert(rec
->prev
==NULL
);
310 /* replace table entry */
312 WMHashInsert(notificationCenter
->objectTable
,
313 orec
->object
, orec
->next
);
315 WMHashRemove(notificationCenter
->objectTable
,
320 rec
= WMHashGet(notificationCenter
->nameTable
, orec
->name
);
322 assert(rec
->prev
==NULL
);
323 /* replace table entry */
325 WMHashInsert(notificationCenter
->nameTable
,
326 orec
->name
, orec
->next
);
328 WMHashRemove(notificationCenter
->nameTable
,
335 orec
->prev
->next
= orec
->next
;
337 orec
->next
->prev
= orec
->prev
;
340 /* append this action in the new action list */
341 orec
->nextAction
= NULL
;
345 NotificationObserver
*p
;
348 while (p
->nextAction
) {
351 p
->nextAction
= orec
;
357 /* reinsert the list to the table */
359 WMHashInsert(notificationCenter
->observerTable
, observer
, newList
);
365 WMPostNotificationName(char *name
, void *object
, void *clientData
)
367 WMNotification
*notification
;
369 notification
= WMCreateNotification(name
, object
, clientData
);
371 WMPostNotification(notification
);
373 WMReleaseNotification(notification
);
378 /**************** Notification Queues ****************/
381 typedef struct W_NotificationQueue
{
385 struct W_NotificationQueue
*next
;
389 static WMNotificationQueue
*notificationQueueList
= NULL
;
392 static WMNotificationQueue
*notificationQueue
= NULL
;
396 WMGetDefaultNotificationQueue(void)
398 if (!notificationQueue
)
399 notificationQueue
= WMCreateNotificationQueue();
401 return notificationQueue
;
406 WMCreateNotificationQueue(void)
408 NotificationQueue
*queue
;
410 queue
= wmalloc(sizeof(NotificationQueue
));
412 queue
->asapQueue
= NULL
;
413 queue
->idleQueue
= NULL
;
414 queue
->next
= notificationQueueList
;
416 notificationQueueList
= queue
;
424 WMEnqueueNotification(WMNotificationQueue
*queue
, WMNotification
*notification
,
425 WMPostingStyle postingStyle
)
427 WMEnqueueCoalesceNotification(queue
, notification
, postingStyle
,
428 WNCOnName
|WNCOnSender
);
433 matchName(void *a
, void *b
)
435 WMNotification
*n1
= (WMNotification
*)a
;
436 WMNotification
*n2
= (WMNotification
*)b
;
438 return strcmp(n1
->name
, n2
->name
);
443 matchSender(void *a
, void *b
)
445 WMNotification
*n1
= (WMNotification
*)a
;
446 WMNotification
*n2
= (WMNotification
*)b
;
448 return (n1
->object
== n2
->object
);
453 WMDequeueNotificationMatching(WMNotificationQueue
*queue
,
454 WMNotification
*notification
, unsigned mask
)
458 if (mask
& WNCOnName
) {
459 while ((n
= lfind(notification
->name
, queue
->asapQueue
, matchName
))) {
460 queue
->asapQueue
= lremove(queue
->asapQueue
, n
);
461 WMReleaseNotification((WMNotification
*)n
);
463 while ((n
= lfind(notification
->name
, queue
->idleQueue
, matchName
))) {
464 queue
->idleQueue
= lremove(queue
->idleQueue
, n
);
465 WMReleaseNotification((WMNotification
*)n
);
468 if (mask
& WNCOnSender
) {
469 while ((n
= lfind(notification
->name
, queue
->asapQueue
, matchSender
))) {
470 queue
->asapQueue
= lremove(queue
->asapQueue
, n
);
471 WMReleaseNotification((WMNotification
*)n
);
473 while ((n
= lfind(notification
->name
, queue
->idleQueue
, matchSender
))) {
474 queue
->idleQueue
= lremove(queue
->idleQueue
, n
);
475 WMReleaseNotification((WMNotification
*)n
);
482 WMEnqueueCoalesceNotification(WMNotificationQueue
*queue
,
483 WMNotification
*notification
,
484 WMPostingStyle postingStyle
,
485 unsigned coalesceMask
)
487 if (coalesceMask
!= WNCNone
)
488 WMDequeueNotificationMatching(queue
, notification
, coalesceMask
);
490 switch (postingStyle
) {
492 WMPostNotification(notification
);
496 queue
->asapQueue
= lappend(queue
->asapQueue
,
497 lcons(notification
, NULL
));
501 queue
->idleQueue
= lappend(queue
->idleQueue
,
502 lcons(notification
, NULL
));
509 W_FlushASAPNotificationQueue()
511 WMNotificationQueue
*queue
= notificationQueueList
;
514 while (queue
->asapQueue
) {
515 WMPostNotification((WMNotification
*)lhead(queue
->asapQueue
));
516 queue
->asapQueue
= lremovehead(queue
->asapQueue
);
523 W_FlushIdleNotificationQueue()
525 WMNotificationQueue
*queue
= notificationQueueList
;
528 while (queue
->idleQueue
) {
529 WMPostNotification((WMNotification
*)lhead(queue
->idleQueue
));
530 queue
->idleQueue
= lremovehead(queue
->idleQueue
);