Fixes missing appicons after restarting Window Maker
[wmaker-crm.git] / WINGs / notification.c
blobb1b3712802bbc9ee2237352d819331d1534692d1
2 #include <stdlib.h>
3 #include <assert.h>
4 #include <stdio.h>
5 #include <string.h>
7 #include "WUtil.h"
8 #include "WINGsP.h"
11 typedef struct W_Notification {
12 const char *name;
13 void *object;
14 void *clientData;
15 int refCount;
16 } Notification;
19 const char *WMGetNotificationName(WMNotification * notification)
21 return notification->name;
24 void *WMGetNotificationObject(WMNotification * notification)
26 return notification->object;
29 void *WMGetNotificationClientData(WMNotification * notification)
31 return notification->clientData;
34 WMNotification *WMCreateNotification(const char *name, void *object, void *clientData)
36 Notification *nPtr;
38 nPtr = wmalloc(sizeof(Notification));
39 nPtr->name = name;
40 nPtr->object = object;
41 nPtr->clientData = clientData;
42 nPtr->refCount = 1;
44 return nPtr;
47 void WMReleaseNotification(WMNotification * notification)
49 notification->refCount--;
51 if (notification->refCount < 1) {
52 wfree(notification);
56 WMNotification *WMRetainNotification(WMNotification * notification)
58 notification->refCount++;
60 return notification;
63 /***************** Notification Center *****************/
65 typedef struct NotificationObserver {
66 WMNotificationObserverAction *observerAction;
67 void *observer;
69 const char *name;
70 void *object;
72 struct NotificationObserver *prev; /* for tables */
73 struct NotificationObserver *next;
74 struct NotificationObserver *nextAction; /* for observerTable */
75 } NotificationObserver;
77 typedef struct W_NotificationCenter {
78 WMHashTable *nameTable; /* names -> observer lists */
79 WMHashTable *objectTable; /* object -> observer lists */
80 NotificationObserver *nilList; /* obervers that catch everything */
82 WMHashTable *observerTable; /* observer -> NotificationObserver */
83 } NotificationCenter;
85 /* default (and only) center */
86 static NotificationCenter *notificationCenter = NULL;
88 void W_InitNotificationCenter(void)
90 notificationCenter = wmalloc(sizeof(NotificationCenter));
91 notificationCenter->nameTable = WMCreateHashTable(WMStringPointerHashCallbacks);
92 notificationCenter->objectTable = WMCreateHashTable(WMIntHashCallbacks);
93 notificationCenter->nilList = NULL;
94 notificationCenter->observerTable = WMCreateHashTable(WMIntHashCallbacks);
97 void W_ReleaseNotificationCenter(void)
99 if (notificationCenter) {
100 if (notificationCenter->nameTable)
101 WMFreeHashTable(notificationCenter->nameTable);
102 if (notificationCenter->objectTable)
103 WMFreeHashTable(notificationCenter->objectTable);
104 if (notificationCenter->observerTable)
105 WMFreeHashTable(notificationCenter->observerTable);
107 wfree(notificationCenter);
108 notificationCenter = NULL;
112 void
113 WMAddNotificationObserver(WMNotificationObserverAction * observerAction,
114 void *observer, const char *name, void *object)
116 NotificationObserver *oRec, *rec;
118 oRec = wmalloc(sizeof(NotificationObserver));
119 oRec->observerAction = observerAction;
120 oRec->observer = observer;
121 oRec->name = name;
122 oRec->object = object;
123 oRec->next = NULL;
124 oRec->prev = NULL;
126 /* put this action in the list of actions for this observer */
127 rec = (NotificationObserver *) WMHashInsert(notificationCenter->observerTable, observer, oRec);
129 if (rec) {
130 /* if this is not the first action for the observer */
131 oRec->nextAction = rec;
132 } else {
133 oRec->nextAction = NULL;
136 if (!name && !object) {
137 /* catch-all */
138 oRec->next = notificationCenter->nilList;
139 if (notificationCenter->nilList) {
140 notificationCenter->nilList->prev = oRec;
142 notificationCenter->nilList = oRec;
143 } else if (!name) {
144 /* any message coming from object */
145 rec = (NotificationObserver *) WMHashInsert(notificationCenter->objectTable, object, oRec);
146 oRec->next = rec;
147 if (rec) {
148 rec->prev = oRec;
150 } else {
151 /* name && (object || !object) */
152 rec = (NotificationObserver *) WMHashInsert(notificationCenter->nameTable, name, oRec);
153 oRec->next = rec;
154 if (rec) {
155 rec->prev = oRec;
160 void WMPostNotification(WMNotification * notification)
162 NotificationObserver *orec, *tmp;
164 WMRetainNotification(notification);
166 /* tell the observers that want to know about a particular message */
167 orec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, notification->name);
169 while (orec) {
170 tmp = orec->next;
172 if (!orec->object || !notification->object || orec->object == notification->object) {
173 /* tell the observer */
174 if (orec->observerAction) {
175 (*orec->observerAction) (orec->observer, notification);
179 orec = tmp;
182 /* tell the observers that want to know about an object */
183 orec = (NotificationObserver *) WMHashGet(notificationCenter->objectTable, notification->object);
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 /* tell the catch all observers */
196 orec = notificationCenter->nilList;
197 while (orec) {
198 tmp = orec->next;
200 /* tell the observer */
201 if (orec->observerAction) {
202 (*orec->observerAction) (orec->observer, notification);
204 orec = tmp;
207 WMReleaseNotification(notification);
210 void WMRemoveNotificationObserver(void *observer)
212 NotificationObserver *orec, *tmp, *rec;
214 /* get the list of actions the observer is doing */
215 orec = (NotificationObserver *) WMHashGet(notificationCenter->observerTable, observer);
218 * FOREACH orec IN actionlist for observer
219 * DO
220 * remove from respective lists/tables
221 * free
222 * END
224 while (orec) {
225 tmp = orec->nextAction;
227 if (!orec->name && !orec->object) {
228 /* catch-all */
229 if (notificationCenter->nilList == orec)
230 notificationCenter->nilList = orec->next;
231 } else if (!orec->name) {
232 /* any message coming from object */
233 rec = (NotificationObserver *) WMHashGet(notificationCenter->objectTable, orec->object);
234 if (rec == orec) {
235 /* replace table entry */
236 if (orec->next) {
237 WMHashInsert(notificationCenter->objectTable, orec->object, orec->next);
238 } else {
239 WMHashRemove(notificationCenter->objectTable, orec->object);
242 } else {
243 /* name && (object || !object) */
244 rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, orec->name);
245 if (rec == orec) {
246 /* replace table entry */
247 if (orec->next) {
248 WMHashInsert(notificationCenter->nameTable, orec->name, orec->next);
249 } else {
250 WMHashRemove(notificationCenter->nameTable, orec->name);
254 if (orec->prev)
255 orec->prev->next = orec->next;
256 if (orec->next)
257 orec->next->prev = orec->prev;
259 wfree(orec);
261 orec = tmp;
264 WMHashRemove(notificationCenter->observerTable, observer);
267 void WMRemoveNotificationObserverWithName(void *observer, const char *name, void *object)
269 NotificationObserver *orec, *tmp, *rec;
270 NotificationObserver *newList = NULL;
272 /* get the list of actions the observer is doing */
273 orec = (NotificationObserver *) WMHashGet(notificationCenter->observerTable, observer);
275 WMHashRemove(notificationCenter->observerTable, observer);
277 /* rebuild the list of actions for the observer */
279 while (orec) {
280 tmp = orec->nextAction;
281 if (orec->name == name && orec->object == object) {
282 if (!name && !object) {
283 if (notificationCenter->nilList == orec)
284 notificationCenter->nilList = orec->next;
285 } else if (!name) {
286 rec =
287 (NotificationObserver *) WMHashGet(notificationCenter->objectTable,
288 orec->object);
289 if (rec == orec) {
290 assert(rec->prev == NULL);
291 /* replace table entry */
292 if (orec->next) {
293 WMHashInsert(notificationCenter->objectTable,
294 orec->object, orec->next);
295 } else {
296 WMHashRemove(notificationCenter->objectTable, orec->object);
299 } else {
300 rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable,
301 orec->name);
302 if (rec == orec) {
303 assert(rec->prev == NULL);
304 /* replace table entry */
305 if (orec->next) {
306 WMHashInsert(notificationCenter->nameTable,
307 orec->name, orec->next);
308 } else {
309 WMHashRemove(notificationCenter->nameTable, orec->name);
314 if (orec->prev)
315 orec->prev->next = orec->next;
316 if (orec->next)
317 orec->next->prev = orec->prev;
318 wfree(orec);
319 } else {
320 /* append this action in the new action list */
321 orec->nextAction = NULL;
322 if (!newList) {
323 newList = orec;
324 } else {
325 NotificationObserver *p;
327 p = newList;
328 while (p->nextAction) {
329 p = p->nextAction;
331 p->nextAction = orec;
334 orec = tmp;
337 /* reinsert the list to the table */
338 if (newList) {
339 WMHashInsert(notificationCenter->observerTable, observer, newList);
343 void WMPostNotificationName(const char *name, void *object, void *clientData)
345 WMNotification *notification;
347 notification = WMCreateNotification(name, object, clientData);
349 WMPostNotification(notification);
351 WMReleaseNotification(notification);
354 /**************** Notification Queues ****************/
356 typedef struct W_NotificationQueue {
357 WMArray *asapQueue;
358 WMArray *idleQueue;
360 struct W_NotificationQueue *next;
361 } NotificationQueue;
363 static WMNotificationQueue *notificationQueueList = NULL;
365 /* default queue */
366 static WMNotificationQueue *notificationQueue = NULL;
368 WMNotificationQueue *WMGetDefaultNotificationQueue(void)
370 if (!notificationQueue)
371 notificationQueue = WMCreateNotificationQueue();
373 return notificationQueue;
376 WMNotificationQueue *WMCreateNotificationQueue(void)
378 NotificationQueue *queue;
380 queue = wmalloc(sizeof(NotificationQueue));
381 queue->asapQueue = WMCreateArrayWithDestructor(8, (WMFreeDataProc *) WMReleaseNotification);
382 queue->idleQueue = WMCreateArrayWithDestructor(8, (WMFreeDataProc *) WMReleaseNotification);
383 queue->next = notificationQueueList;
385 notificationQueueList = queue;
387 return queue;
390 void WMEnqueueNotification(WMNotificationQueue * queue, WMNotification * notification, WMPostingStyle postingStyle)
392 WMEnqueueCoalesceNotification(queue, notification, postingStyle, WNCOnName | WNCOnSender);
395 #define NOTIF ((WMNotification*)cdata)
396 #define ITEM ((WMNotification*)item)
398 static int matchSenderAndName(const void *item, const void *cdata)
400 return (NOTIF->object == ITEM->object && strcmp(NOTIF->name, ITEM->name) == 0);
403 static int matchSender(const void *item, const void *cdata)
405 return (NOTIF->object == ITEM->object);
408 static int matchName(const void *item, const void *cdata)
410 return (strcmp(NOTIF->name, ITEM->name) == 0);
413 #undef NOTIF
414 #undef ITEM
416 void WMDequeueNotificationMatching(WMNotificationQueue * queue, WMNotification * notification, unsigned mask)
418 WMMatchDataProc *matchFunc;
420 if ((mask & WNCOnName) && (mask & WNCOnSender))
421 matchFunc = matchSenderAndName;
422 else if (mask & WNCOnName)
423 matchFunc = matchName;
424 else if (mask & WNCOnSender)
425 matchFunc = matchSender;
426 else
427 return;
429 WMRemoveFromArrayMatching(queue->asapQueue, matchFunc, notification);
430 WMRemoveFromArrayMatching(queue->idleQueue, matchFunc, notification);
433 void
434 WMEnqueueCoalesceNotification(WMNotificationQueue * queue,
435 WMNotification * notification, WMPostingStyle postingStyle, unsigned coalesceMask)
437 if (coalesceMask != WNCNone)
438 WMDequeueNotificationMatching(queue, notification, coalesceMask);
440 switch (postingStyle) {
441 case WMPostNow:
442 WMPostNotification(notification);
443 WMReleaseNotification(notification);
444 break;
446 case WMPostASAP:
447 WMAddToArray(queue->asapQueue, notification);
448 break;
450 case WMPostWhenIdle:
451 WMAddToArray(queue->idleQueue, notification);
452 break;
456 void W_FlushASAPNotificationQueue(void)
458 WMNotificationQueue *queue = notificationQueueList;
460 while (queue) {
461 while (WMGetArrayItemCount(queue->asapQueue)) {
462 WMPostNotification(WMGetFromArray(queue->asapQueue, 0));
463 WMDeleteFromArray(queue->asapQueue, 0);
466 queue = queue->next;
470 void W_FlushIdleNotificationQueue(void)
472 WMNotificationQueue *queue = notificationQueueList;
474 while (queue) {
475 while (WMGetArrayItemCount(queue->idleQueue)) {
476 WMPostNotification(WMGetFromArray(queue->idleQueue, 0));
477 WMDeleteFromArray(queue->idleQueue, 0);
480 queue = queue->next;