wmaker: Moved variables for the XShape extension into the global namespace
[wmaker-crm.git] / WINGs / notification.c
blobada942fe3336e7fe2665c869c2a3fdb26402e81e
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
98 WMAddNotificationObserver(WMNotificationObserverAction * observerAction,
99 void *observer, const char *name, void *object)
101 NotificationObserver *oRec, *rec;
103 oRec = wmalloc(sizeof(NotificationObserver));
104 oRec->observerAction = observerAction;
105 oRec->observer = observer;
106 oRec->name = name;
107 oRec->object = object;
108 oRec->next = NULL;
109 oRec->prev = NULL;
111 /* put this action in the list of actions for this observer */
112 rec = (NotificationObserver *) WMHashInsert(notificationCenter->observerTable, observer, oRec);
114 if (rec) {
115 /* if this is not the first action for the observer */
116 oRec->nextAction = rec;
117 } else {
118 oRec->nextAction = NULL;
121 if (!name && !object) {
122 /* catch-all */
123 oRec->next = notificationCenter->nilList;
124 if (notificationCenter->nilList) {
125 notificationCenter->nilList->prev = oRec;
127 notificationCenter->nilList = oRec;
128 } else if (!name) {
129 /* any message coming from object */
130 rec = (NotificationObserver *) WMHashInsert(notificationCenter->objectTable, object, oRec);
131 oRec->next = rec;
132 if (rec) {
133 rec->prev = oRec;
135 } else {
136 /* name && (object || !object) */
137 rec = (NotificationObserver *) WMHashInsert(notificationCenter->nameTable, name, oRec);
138 oRec->next = rec;
139 if (rec) {
140 rec->prev = oRec;
145 void WMPostNotification(WMNotification * notification)
147 NotificationObserver *orec, *tmp;
149 WMRetainNotification(notification);
151 /* tell the observers that want to know about a particular message */
152 orec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, notification->name);
154 while (orec) {
155 tmp = orec->next;
157 if (!orec->object || !notification->object || orec->object == notification->object) {
158 /* tell the observer */
159 if (orec->observerAction) {
160 (*orec->observerAction) (orec->observer, notification);
164 orec = tmp;
167 /* tell the observers that want to know about an object */
168 orec = (NotificationObserver *) WMHashGet(notificationCenter->objectTable, notification->object);
170 while (orec) {
171 tmp = orec->next;
173 /* tell the observer */
174 if (orec->observerAction) {
175 (*orec->observerAction) (orec->observer, notification);
177 orec = tmp;
180 /* tell the catch all observers */
181 orec = notificationCenter->nilList;
182 while (orec) {
183 tmp = orec->next;
185 /* tell the observer */
186 if (orec->observerAction) {
187 (*orec->observerAction) (orec->observer, notification);
189 orec = tmp;
192 WMReleaseNotification(notification);
195 void WMRemoveNotificationObserver(void *observer)
197 NotificationObserver *orec, *tmp, *rec;
199 /* get the list of actions the observer is doing */
200 orec = (NotificationObserver *) WMHashGet(notificationCenter->observerTable, observer);
203 * FOREACH orec IN actionlist for observer
204 * DO
205 * remove from respective lists/tables
206 * free
207 * END
209 while (orec) {
210 tmp = orec->nextAction;
212 if (!orec->name && !orec->object) {
213 /* catch-all */
214 if (notificationCenter->nilList == orec)
215 notificationCenter->nilList = orec->next;
216 } else if (!orec->name) {
217 /* any message coming from object */
218 rec = (NotificationObserver *) WMHashGet(notificationCenter->objectTable, orec->object);
219 if (rec == orec) {
220 /* replace table entry */
221 if (orec->next) {
222 WMHashInsert(notificationCenter->objectTable, orec->object, orec->next);
223 } else {
224 WMHashRemove(notificationCenter->objectTable, orec->object);
227 } else {
228 /* name && (object || !object) */
229 rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, orec->name);
230 if (rec == orec) {
231 /* replace table entry */
232 if (orec->next) {
233 WMHashInsert(notificationCenter->nameTable, orec->name, orec->next);
234 } else {
235 WMHashRemove(notificationCenter->nameTable, orec->name);
239 if (orec->prev)
240 orec->prev->next = orec->next;
241 if (orec->next)
242 orec->next->prev = orec->prev;
244 wfree(orec);
246 orec = tmp;
249 WMHashRemove(notificationCenter->observerTable, observer);
252 void WMRemoveNotificationObserverWithName(void *observer, const char *name, void *object)
254 NotificationObserver *orec, *tmp, *rec;
255 NotificationObserver *newList = NULL;
257 /* get the list of actions the observer is doing */
258 orec = (NotificationObserver *) WMHashGet(notificationCenter->observerTable, observer);
260 WMHashRemove(notificationCenter->observerTable, observer);
262 /* rebuild the list of actions for the observer */
264 while (orec) {
265 tmp = orec->nextAction;
266 if (orec->name == name && orec->object == object) {
267 if (!name && !object) {
268 if (notificationCenter->nilList == orec)
269 notificationCenter->nilList = orec->next;
270 } else if (!name) {
271 rec =
272 (NotificationObserver *) WMHashGet(notificationCenter->objectTable,
273 orec->object);
274 if (rec == orec) {
275 assert(rec->prev == NULL);
276 /* replace table entry */
277 if (orec->next) {
278 WMHashInsert(notificationCenter->objectTable,
279 orec->object, orec->next);
280 } else {
281 WMHashRemove(notificationCenter->objectTable, orec->object);
284 } else {
285 rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable,
286 orec->name);
287 if (rec == orec) {
288 assert(rec->prev == NULL);
289 /* replace table entry */
290 if (orec->next) {
291 WMHashInsert(notificationCenter->nameTable,
292 orec->name, orec->next);
293 } else {
294 WMHashRemove(notificationCenter->nameTable, orec->name);
299 if (orec->prev)
300 orec->prev->next = orec->next;
301 if (orec->next)
302 orec->next->prev = orec->prev;
303 wfree(orec);
304 } else {
305 /* append this action in the new action list */
306 orec->nextAction = NULL;
307 if (!newList) {
308 newList = orec;
309 } else {
310 NotificationObserver *p;
312 p = newList;
313 while (p->nextAction) {
314 p = p->nextAction;
316 p->nextAction = orec;
319 orec = tmp;
322 /* reinsert the list to the table */
323 if (newList) {
324 WMHashInsert(notificationCenter->observerTable, observer, newList);
328 void WMPostNotificationName(const char *name, void *object, void *clientData)
330 WMNotification *notification;
332 notification = WMCreateNotification(name, object, clientData);
334 WMPostNotification(notification);
336 WMReleaseNotification(notification);
339 /**************** Notification Queues ****************/
341 typedef struct W_NotificationQueue {
342 WMArray *asapQueue;
343 WMArray *idleQueue;
345 struct W_NotificationQueue *next;
346 } NotificationQueue;
348 static WMNotificationQueue *notificationQueueList = NULL;
350 /* default queue */
351 static WMNotificationQueue *notificationQueue = NULL;
353 WMNotificationQueue *WMGetDefaultNotificationQueue(void)
355 if (!notificationQueue)
356 notificationQueue = WMCreateNotificationQueue();
358 return notificationQueue;
361 WMNotificationQueue *WMCreateNotificationQueue(void)
363 NotificationQueue *queue;
365 queue = wmalloc(sizeof(NotificationQueue));
366 queue->asapQueue = WMCreateArrayWithDestructor(8, (WMFreeDataProc *) WMReleaseNotification);
367 queue->idleQueue = WMCreateArrayWithDestructor(8, (WMFreeDataProc *) WMReleaseNotification);
368 queue->next = notificationQueueList;
370 notificationQueueList = queue;
372 return queue;
375 void WMEnqueueNotification(WMNotificationQueue * queue, WMNotification * notification, WMPostingStyle postingStyle)
377 WMEnqueueCoalesceNotification(queue, notification, postingStyle, WNCOnName | WNCOnSender);
380 #define NOTIF ((WMNotification*)cdata)
381 #define ITEM ((WMNotification*)item)
383 static int matchSenderAndName(const void *item, const void *cdata)
385 return (NOTIF->object == ITEM->object && strcmp(NOTIF->name, ITEM->name) == 0);
388 static int matchSender(const void *item, const void *cdata)
390 return (NOTIF->object == ITEM->object);
393 static int matchName(const void *item, const void *cdata)
395 return (strcmp(NOTIF->name, ITEM->name) == 0);
398 #undef NOTIF
399 #undef ITEM
401 void WMDequeueNotificationMatching(WMNotificationQueue * queue, WMNotification * notification, unsigned mask)
403 WMMatchDataProc *matchFunc;
405 if ((mask & WNCOnName) && (mask & WNCOnSender))
406 matchFunc = matchSenderAndName;
407 else if (mask & WNCOnName)
408 matchFunc = matchName;
409 else if (mask & WNCOnSender)
410 matchFunc = matchSender;
411 else
412 return;
414 WMRemoveFromArrayMatching(queue->asapQueue, matchFunc, notification);
415 WMRemoveFromArrayMatching(queue->idleQueue, matchFunc, notification);
418 void
419 WMEnqueueCoalesceNotification(WMNotificationQueue * queue,
420 WMNotification * notification, WMPostingStyle postingStyle, unsigned coalesceMask)
422 if (coalesceMask != WNCNone)
423 WMDequeueNotificationMatching(queue, notification, coalesceMask);
425 switch (postingStyle) {
426 case WMPostNow:
427 WMPostNotification(notification);
428 WMReleaseNotification(notification);
429 break;
431 case WMPostASAP:
432 WMAddToArray(queue->asapQueue, notification);
433 break;
435 case WMPostWhenIdle:
436 WMAddToArray(queue->idleQueue, notification);
437 break;
441 void W_FlushASAPNotificationQueue(void)
443 WMNotificationQueue *queue = notificationQueueList;
445 while (queue) {
446 while (WMGetArrayItemCount(queue->asapQueue)) {
447 WMPostNotification(WMGetFromArray(queue->asapQueue, 0));
448 WMDeleteFromArray(queue->asapQueue, 0);
451 queue = queue->next;
455 void W_FlushIdleNotificationQueue(void)
457 WMNotificationQueue *queue = notificationQueueList;
459 while (queue) {
460 while (WMGetArrayItemCount(queue->idleQueue)) {
461 WMPostNotification(WMGetFromArray(queue->idleQueue, 0));
462 WMDeleteFromArray(queue->idleQueue, 0);
465 queue = queue->next;