Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / notification.c
blobe3af3df32a8cc57415f541b858fb2a0f71028a15
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <stdio.h>
5 #include <string.h>
7 #include "WUtil.h"
9 typedef struct W_Notification {
10 const char *name;
11 void *object;
12 void *clientData;
13 int refCount;
14 } Notification;
16 extern void W_FlushASAPNotificationQueue();
18 const char *WMGetNotificationName(WMNotification * notification)
19 {
20 return notification->name;
21 }
23 void *WMGetNotificationObject(WMNotification * notification)
24 {
25 return notification->object;
26 }
28 void *WMGetNotificationClientData(WMNotification * notification)
29 {
30 return notification->clientData;
31 }
33 WMNotification *WMCreateNotification(const char *name, void *object, void *clientData)
34 {
35 Notification *nPtr;
37 nPtr = wmalloc(sizeof(Notification));
39 nPtr->name = name;
40 nPtr->object = object;
41 nPtr->clientData = clientData;
43 nPtr->refCount = 1;
45 return nPtr;
46 }
48 void WMReleaseNotification(WMNotification * notification)
49 {
50 notification->refCount--;
52 if (notification->refCount < 1) {
53 wfree(notification);
54 }
55 }
57 WMNotification *WMRetainNotification(WMNotification * notification)
58 {
59 notification->refCount++;
61 return notification;
62 }
64 /***************** Notification Center *****************/
66 typedef struct NotificationObserver {
67 WMNotificationObserverAction *observerAction;
68 void *observer;
70 const char *name;
71 void *object;
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 */
84 } NotificationCenter;
86 /* default (and only) center */
87 static NotificationCenter *notificationCenter = NULL;
89 void W_InitNotificationCenter(void)
90 {
91 notificationCenter = wmalloc(sizeof(NotificationCenter));
93 notificationCenter->nameTable = WMCreateHashTable(WMStringPointerHashCallbacks);
94 notificationCenter->objectTable = WMCreateHashTable(WMIntHashCallbacks);
95 notificationCenter->nilList = NULL;
97 notificationCenter->observerTable = WMCreateHashTable(WMIntHashCallbacks);
98 }
100 void
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;
109 oRec->name = name;
110 oRec->object = object;
111 oRec->next = NULL;
112 oRec->prev = NULL;
114 /* put this action in the list of actions for this observer */
115 rec = (NotificationObserver *) WMHashInsert(notificationCenter->observerTable, observer, oRec);
117 if (rec) {
118 /* if this is not the first action for the observer */
119 oRec->nextAction = rec;
120 } else {
121 oRec->nextAction = NULL;
124 if (!name && !object) {
125 /* catch-all */
126 oRec->next = notificationCenter->nilList;
127 if (notificationCenter->nilList) {
128 notificationCenter->nilList->prev = oRec;
130 notificationCenter->nilList = oRec;
131 } else if (!name) {
132 /* any message coming from object */
133 rec = (NotificationObserver *) WMHashInsert(notificationCenter->objectTable, object, oRec);
134 oRec->next = rec;
135 if (rec) {
136 rec->prev = oRec;
138 } else {
139 /* name && (object || !object) */
140 rec = (NotificationObserver *) WMHashInsert(notificationCenter->nameTable, name, oRec);
141 oRec->next = rec;
142 if (rec) {
143 rec->prev = 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);
157 while (orec) {
158 tmp = orec->next;
160 if (!orec->object || !notification->object || orec->object == notification->object) {
161 /* tell the observer */
162 if (orec->observerAction) {
163 (*orec->observerAction) (orec->observer, notification);
167 orec = tmp;
170 /* tell the observers that want to know about an object */
171 orec = (NotificationObserver *) WMHashGet(notificationCenter->objectTable, notification->object);
173 while (orec) {
174 tmp = orec->next;
176 /* tell the observer */
177 if (orec->observerAction) {
178 (*orec->observerAction) (orec->observer, notification);
180 orec = tmp;
183 /* tell the catch all observers */
184 orec = notificationCenter->nilList;
185 while (orec) {
186 tmp = orec->next;
188 /* tell the observer */
189 if (orec->observerAction) {
190 (*orec->observerAction) (orec->observer, notification);
192 orec = tmp;
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);
205 /*
206 * FOREACH orec IN actionlist for observer
207 * DO
208 * remove from respective lists/tables
209 * free
210 * END
211 */
212 while (orec) {
213 tmp = orec->nextAction;
215 if (!orec->name && !orec->object) {
216 /* catch-all */
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);
222 if (rec == orec) {
223 /* replace table entry */
224 if (orec->next) {
225 WMHashInsert(notificationCenter->objectTable, orec->object, orec->next);
226 } else {
227 WMHashRemove(notificationCenter->objectTable, orec->object);
230 } else {
231 /* name && (object || !object) */
232 rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, orec->name);
233 if (rec == orec) {
234 /* replace table entry */
235 if (orec->next) {
236 WMHashInsert(notificationCenter->nameTable, orec->name, orec->next);
237 } else {
238 WMHashRemove(notificationCenter->nameTable, orec->name);
242 if (orec->prev)
243 orec->prev->next = orec->next;
244 if (orec->next)
245 orec->next->prev = orec->prev;
247 wfree(orec);
249 orec = tmp;
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 */
267 while (orec) {
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;
273 } else if (!name) {
274 rec =
275 (NotificationObserver *) WMHashGet(notificationCenter->objectTable,
276 orec->object);
277 if (rec == orec) {
278 assert(rec->prev == NULL);
279 /* replace table entry */
280 if (orec->next) {
281 WMHashInsert(notificationCenter->objectTable,
282 orec->object, orec->next);
283 } else {
284 WMHashRemove(notificationCenter->objectTable, orec->object);
287 } else {
288 rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable,
289 orec->name);
290 if (rec == orec) {
291 assert(rec->prev == NULL);
292 /* replace table entry */
293 if (orec->next) {
294 WMHashInsert(notificationCenter->nameTable,
295 orec->name, orec->next);
296 } else {
297 WMHashRemove(notificationCenter->nameTable, orec->name);
302 if (orec->prev)
303 orec->prev->next = orec->next;
304 if (orec->next)
305 orec->next->prev = orec->prev;
306 wfree(orec);
307 } else {
308 /* append this action in the new action list */
309 orec->nextAction = NULL;
310 if (!newList) {
311 newList = orec;
312 } else {
313 NotificationObserver *p;
315 p = newList;
316 while (p->nextAction) {
317 p = p->nextAction;
319 p->nextAction = orec;
322 orec = tmp;
325 /* reinsert the list to the table */
326 if (newList) {
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 {
345 WMArray *asapQueue;
346 WMArray *idleQueue;
348 struct W_NotificationQueue *next;
349 } NotificationQueue;
351 static WMNotificationQueue *notificationQueueList = NULL;
353 /* default queue */
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;
376 return 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);
402 #undef NOTIF
403 #undef ITEM
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;
415 else
416 return;
418 WMRemoveFromArrayMatching(queue->asapQueue, matchFunc, notification);
419 WMRemoveFromArrayMatching(queue->idleQueue, matchFunc, notification);
422 void
423 WMEnqueueCoalesceNotification(WMNotificationQueue * queue,
424 WMNotification * notification, WMPostingStyle postingStyle, unsigned coalesceMask)
426 if (coalesceMask != WNCNone)
427 WMDequeueNotificationMatching(queue, notification, coalesceMask);
429 switch (postingStyle) {
430 case WMPostNow:
431 WMPostNotification(notification);
432 WMReleaseNotification(notification);
433 break;
435 case WMPostASAP:
436 WMAddToArray(queue->asapQueue, notification);
437 break;
439 case WMPostWhenIdle:
440 WMAddToArray(queue->idleQueue, notification);
441 break;
445 void W_FlushASAPNotificationQueue()
447 WMNotificationQueue *queue = notificationQueueList;
449 while (queue) {
450 while (WMGetArrayItemCount(queue->asapQueue)) {
451 WMPostNotification(WMGetFromArray(queue->asapQueue, 0));
452 WMDeleteFromArray(queue->asapQueue, 0);
455 queue = queue->next;
459 void W_FlushIdleNotificationQueue()
461 WMNotificationQueue *queue = notificationQueueList;
463 while (queue) {
464 while (WMGetArrayItemCount(queue->idleQueue)) {
465 WMPostNotification(WMGetFromArray(queue->idleQueue, 0));
466 WMDeleteFromArray(queue->idleQueue, 0);
469 queue = queue->next;