Revert "Prevent border drifting."
[wmaker-crm.git] / WINGs / notification.c
blob5d0c80283ad648440d2a69e6022e3ebacbf6f0fa
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)
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)
35 Notification *nPtr;
37 nPtr = wmalloc(sizeof(Notification));
38 nPtr->name = name;
39 nPtr->object = object;
40 nPtr->clientData = clientData;
41 nPtr->refCount = 1;
43 return nPtr;
46 void WMReleaseNotification(WMNotification * notification)
48 notification->refCount--;
50 if (notification->refCount < 1) {
51 wfree(notification);
55 WMNotification *WMRetainNotification(WMNotification * notification)
57 notification->refCount++;
59 return notification;
62 /***************** Notification Center *****************/
64 typedef struct NotificationObserver {
65 WMNotificationObserverAction *observerAction;
66 void *observer;
68 const char *name;
69 void *object;
71 struct NotificationObserver *prev; /* for tables */
72 struct NotificationObserver *next;
73 struct NotificationObserver *nextAction; /* for observerTable */
74 } NotificationObserver;
76 typedef struct W_NotificationCenter {
77 WMHashTable *nameTable; /* names -> observer lists */
78 WMHashTable *objectTable; /* object -> observer lists */
79 NotificationObserver *nilList; /* obervers that catch everything */
81 WMHashTable *observerTable; /* observer -> NotificationObserver */
82 } NotificationCenter;
84 /* default (and only) center */
85 static NotificationCenter *notificationCenter = NULL;
87 void W_InitNotificationCenter(void)
89 notificationCenter = wmalloc(sizeof(NotificationCenter));
90 notificationCenter->nameTable = WMCreateHashTable(WMStringPointerHashCallbacks);
91 notificationCenter->objectTable = WMCreateHashTable(WMIntHashCallbacks);
92 notificationCenter->nilList = NULL;
93 notificationCenter->observerTable = WMCreateHashTable(WMIntHashCallbacks);
96 void
97 WMAddNotificationObserver(WMNotificationObserverAction * observerAction,
98 void *observer, const char *name, void *object)
100 NotificationObserver *oRec, *rec;
102 oRec = wmalloc(sizeof(NotificationObserver));
103 oRec->observerAction = observerAction;
104 oRec->observer = observer;
105 oRec->name = name;
106 oRec->object = object;
107 oRec->next = NULL;
108 oRec->prev = NULL;
110 /* put this action in the list of actions for this observer */
111 rec = (NotificationObserver *) WMHashInsert(notificationCenter->observerTable, observer, oRec);
113 if (rec) {
114 /* if this is not the first action for the observer */
115 oRec->nextAction = rec;
116 } else {
117 oRec->nextAction = NULL;
120 if (!name && !object) {
121 /* catch-all */
122 oRec->next = notificationCenter->nilList;
123 if (notificationCenter->nilList) {
124 notificationCenter->nilList->prev = oRec;
126 notificationCenter->nilList = oRec;
127 } else if (!name) {
128 /* any message coming from object */
129 rec = (NotificationObserver *) WMHashInsert(notificationCenter->objectTable, object, oRec);
130 oRec->next = rec;
131 if (rec) {
132 rec->prev = oRec;
134 } else {
135 /* name && (object || !object) */
136 rec = (NotificationObserver *) WMHashInsert(notificationCenter->nameTable, name, oRec);
137 oRec->next = rec;
138 if (rec) {
139 rec->prev = oRec;
144 void WMPostNotification(WMNotification * notification)
146 NotificationObserver *orec, *tmp;
148 WMRetainNotification(notification);
150 /* tell the observers that want to know about a particular message */
151 orec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, notification->name);
153 while (orec) {
154 tmp = orec->next;
156 if (!orec->object || !notification->object || orec->object == notification->object) {
157 /* tell the observer */
158 if (orec->observerAction) {
159 (*orec->observerAction) (orec->observer, notification);
163 orec = tmp;
166 /* tell the observers that want to know about an object */
167 orec = (NotificationObserver *) WMHashGet(notificationCenter->objectTable, notification->object);
169 while (orec) {
170 tmp = orec->next;
172 /* tell the observer */
173 if (orec->observerAction) {
174 (*orec->observerAction) (orec->observer, notification);
176 orec = tmp;
179 /* tell the catch all observers */
180 orec = notificationCenter->nilList;
181 while (orec) {
182 tmp = orec->next;
184 /* tell the observer */
185 if (orec->observerAction) {
186 (*orec->observerAction) (orec->observer, notification);
188 orec = tmp;
191 WMReleaseNotification(notification);
194 void WMRemoveNotificationObserver(void *observer)
196 NotificationObserver *orec, *tmp, *rec;
198 /* get the list of actions the observer is doing */
199 orec = (NotificationObserver *) WMHashGet(notificationCenter->observerTable, observer);
202 * FOREACH orec IN actionlist for observer
203 * DO
204 * remove from respective lists/tables
205 * free
206 * END
208 while (orec) {
209 tmp = orec->nextAction;
211 if (!orec->name && !orec->object) {
212 /* catch-all */
213 if (notificationCenter->nilList == orec)
214 notificationCenter->nilList = orec->next;
215 } else if (!orec->name) {
216 /* any message coming from object */
217 rec = (NotificationObserver *) WMHashGet(notificationCenter->objectTable, orec->object);
218 if (rec == orec) {
219 /* replace table entry */
220 if (orec->next) {
221 WMHashInsert(notificationCenter->objectTable, orec->object, orec->next);
222 } else {
223 WMHashRemove(notificationCenter->objectTable, orec->object);
226 } else {
227 /* name && (object || !object) */
228 rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, orec->name);
229 if (rec == orec) {
230 /* replace table entry */
231 if (orec->next) {
232 WMHashInsert(notificationCenter->nameTable, orec->name, orec->next);
233 } else {
234 WMHashRemove(notificationCenter->nameTable, orec->name);
238 if (orec->prev)
239 orec->prev->next = orec->next;
240 if (orec->next)
241 orec->next->prev = orec->prev;
243 wfree(orec);
245 orec = tmp;
248 WMHashRemove(notificationCenter->observerTable, observer);
251 void WMRemoveNotificationObserverWithName(void *observer, const char *name, void *object)
253 NotificationObserver *orec, *tmp, *rec;
254 NotificationObserver *newList = NULL;
256 /* get the list of actions the observer is doing */
257 orec = (NotificationObserver *) WMHashGet(notificationCenter->observerTable, observer);
259 WMHashRemove(notificationCenter->observerTable, observer);
261 /* rebuild the list of actions for the observer */
263 while (orec) {
264 tmp = orec->nextAction;
265 if (orec->name == name && orec->object == object) {
266 if (!name && !object) {
267 if (notificationCenter->nilList == orec)
268 notificationCenter->nilList = orec->next;
269 } else if (!name) {
270 rec =
271 (NotificationObserver *) WMHashGet(notificationCenter->objectTable,
272 orec->object);
273 if (rec == orec) {
274 assert(rec->prev == NULL);
275 /* replace table entry */
276 if (orec->next) {
277 WMHashInsert(notificationCenter->objectTable,
278 orec->object, orec->next);
279 } else {
280 WMHashRemove(notificationCenter->objectTable, orec->object);
283 } else {
284 rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable,
285 orec->name);
286 if (rec == orec) {
287 assert(rec->prev == NULL);
288 /* replace table entry */
289 if (orec->next) {
290 WMHashInsert(notificationCenter->nameTable,
291 orec->name, orec->next);
292 } else {
293 WMHashRemove(notificationCenter->nameTable, orec->name);
298 if (orec->prev)
299 orec->prev->next = orec->next;
300 if (orec->next)
301 orec->next->prev = orec->prev;
302 wfree(orec);
303 } else {
304 /* append this action in the new action list */
305 orec->nextAction = NULL;
306 if (!newList) {
307 newList = orec;
308 } else {
309 NotificationObserver *p;
311 p = newList;
312 while (p->nextAction) {
313 p = p->nextAction;
315 p->nextAction = orec;
318 orec = tmp;
321 /* reinsert the list to the table */
322 if (newList) {
323 WMHashInsert(notificationCenter->observerTable, observer, newList);
327 void WMPostNotificationName(const char *name, void *object, void *clientData)
329 WMNotification *notification;
331 notification = WMCreateNotification(name, object, clientData);
333 WMPostNotification(notification);
335 WMReleaseNotification(notification);
338 /**************** Notification Queues ****************/
340 typedef struct W_NotificationQueue {
341 WMArray *asapQueue;
342 WMArray *idleQueue;
344 struct W_NotificationQueue *next;
345 } NotificationQueue;
347 static WMNotificationQueue *notificationQueueList = NULL;
349 /* default queue */
350 static WMNotificationQueue *notificationQueue = NULL;
352 WMNotificationQueue *WMGetDefaultNotificationQueue(void)
354 if (!notificationQueue)
355 notificationQueue = WMCreateNotificationQueue();
357 return notificationQueue;
360 WMNotificationQueue *WMCreateNotificationQueue(void)
362 NotificationQueue *queue;
364 queue = wmalloc(sizeof(NotificationQueue));
365 queue->asapQueue = WMCreateArrayWithDestructor(8, (WMFreeDataProc *) WMReleaseNotification);
366 queue->idleQueue = WMCreateArrayWithDestructor(8, (WMFreeDataProc *) WMReleaseNotification);
367 queue->next = notificationQueueList;
369 notificationQueueList = queue;
371 return queue;
374 void WMEnqueueNotification(WMNotificationQueue * queue, WMNotification * notification, WMPostingStyle postingStyle)
376 WMEnqueueCoalesceNotification(queue, notification, postingStyle, WNCOnName | WNCOnSender);
379 #define NOTIF ((WMNotification*)cdata)
380 #define ITEM ((WMNotification*)item)
382 static int matchSenderAndName(const void *item, const void *cdata)
384 return (NOTIF->object == ITEM->object && strcmp(NOTIF->name, ITEM->name) == 0);
387 static int matchSender(const void *item, const void *cdata)
389 return (NOTIF->object == ITEM->object);
392 static int matchName(const void *item, const void *cdata)
394 return (strcmp(NOTIF->name, ITEM->name) == 0);
397 #undef NOTIF
398 #undef ITEM
400 void WMDequeueNotificationMatching(WMNotificationQueue * queue, WMNotification * notification, unsigned mask)
402 WMMatchDataProc *matchFunc;
404 if ((mask & WNCOnName) && (mask & WNCOnSender))
405 matchFunc = matchSenderAndName;
406 else if (mask & WNCOnName)
407 matchFunc = matchName;
408 else if (mask & WNCOnSender)
409 matchFunc = matchSender;
410 else
411 return;
413 WMRemoveFromArrayMatching(queue->asapQueue, matchFunc, notification);
414 WMRemoveFromArrayMatching(queue->idleQueue, matchFunc, notification);
417 void
418 WMEnqueueCoalesceNotification(WMNotificationQueue * queue,
419 WMNotification * notification, WMPostingStyle postingStyle, unsigned coalesceMask)
421 if (coalesceMask != WNCNone)
422 WMDequeueNotificationMatching(queue, notification, coalesceMask);
424 switch (postingStyle) {
425 case WMPostNow:
426 WMPostNotification(notification);
427 WMReleaseNotification(notification);
428 break;
430 case WMPostASAP:
431 WMAddToArray(queue->asapQueue, notification);
432 break;
434 case WMPostWhenIdle:
435 WMAddToArray(queue->idleQueue, notification);
436 break;
440 void W_FlushASAPNotificationQueue()
442 WMNotificationQueue *queue = notificationQueueList;
444 while (queue) {
445 while (WMGetArrayItemCount(queue->asapQueue)) {
446 WMPostNotification(WMGetFromArray(queue->asapQueue, 0));
447 WMDeleteFromArray(queue->asapQueue, 0);
450 queue = queue->next;
454 void W_FlushIdleNotificationQueue()
456 WMNotificationQueue *queue = notificationQueueList;
458 while (queue) {
459 while (WMGetArrayItemCount(queue->idleQueue)) {
460 WMPostNotification(WMGetFromArray(queue->idleQueue, 0));
461 WMDeleteFromArray(queue->idleQueue, 0);
464 queue = queue->next;