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);