X-Git-Url: https://repo.or.cz/w/wmaker-crm.git/blobdiff_plain/59fc927dc9f183802621138534fa6eaafe5593ba..688a56e8ab67b56550e2874d9d7423f0d435bfd9:/WINGs/notification.c diff --git a/WINGs/notification.c b/WINGs/notification.c dissimilarity index 92% index e221b8c7..e3af3df3 100644 --- a/WINGs/notification.c +++ b/WINGs/notification.c @@ -1,543 +1,471 @@ - -#include -#include -#include -#include - -#include "WUtil.h" - - -typedef struct W_Notification { - const char *name; - void *object; - void *clientData; - int refCount; -} Notification; - - -extern void W_FlushASAPNotificationQueue(); - - -const char* -WMGetNotificationName(WMNotification *notification) -{ - return notification->name; -} - - -void* -WMGetNotificationObject(WMNotification *notification) -{ - return notification->object; -} - - -void* -WMGetNotificationClientData(WMNotification *notification) -{ - return notification->clientData; -} - - -WMNotification* -WMCreateNotification(const char *name, void *object, void *clientData) -{ - Notification *nPtr; - - nPtr = wmalloc(sizeof(Notification)); - - nPtr->name = name; - nPtr->object = object; - nPtr->clientData = clientData; - - nPtr->refCount = 1; - - return nPtr; -} - - -void -WMReleaseNotification(WMNotification *notification) -{ - notification->refCount--; - - if (notification->refCount < 1) { - wfree(notification); - } -} - - -WMNotification* -WMRetainNotification(WMNotification *notification) -{ - notification->refCount++; - - return notification; -} - - -/***************** Notification Center *****************/ - -typedef struct NotificationObserver { - WMNotificationObserverAction *observerAction; - void *observer; - - const char *name; - void *object; - - struct NotificationObserver *prev; /* for tables */ - struct NotificationObserver *next; - struct NotificationObserver *nextAction; /* for observerTable */ -} NotificationObserver; - - -typedef struct W_NotificationCenter { - WMHashTable *nameTable; /* names -> observer lists */ - WMHashTable *objectTable; /* object -> observer lists */ - NotificationObserver *nilList; /* obervers that catch everything */ - - WMHashTable *observerTable; /* observer -> NotificationObserver */ -} NotificationCenter; - - -/* default (and only) center */ -static NotificationCenter *notificationCenter = NULL; - - -void -W_InitNotificationCenter(void) -{ - notificationCenter = wmalloc(sizeof(NotificationCenter)); - - notificationCenter->nameTable = WMCreateHashTable(WMStringPointerHashCallbacks); - notificationCenter->objectTable = WMCreateHashTable(WMIntHashCallbacks); - notificationCenter->nilList = NULL; - - notificationCenter->observerTable = WMCreateHashTable(WMIntHashCallbacks); -} - - -void -WMAddNotificationObserver(WMNotificationObserverAction *observerAction, - void *observer, const char *name, void *object) -{ - NotificationObserver *oRec, *rec; - - oRec = wmalloc(sizeof(NotificationObserver)); - oRec->observerAction = observerAction; - oRec->observer = observer; - oRec->name = name; - oRec->object = object; - oRec->next = NULL; - oRec->prev = NULL; - - - /* put this action in the list of actions for this observer */ - rec = (NotificationObserver*)WMHashInsert(notificationCenter->observerTable, - observer, oRec); - - if (rec) { - /* if this is not the first action for the observer */ - oRec->nextAction = rec; - } else { - oRec->nextAction = NULL; - } - - if (!name && !object) { - /* catch-all */ - oRec->next = notificationCenter->nilList; - if (notificationCenter->nilList) { - notificationCenter->nilList->prev = oRec; - } - notificationCenter->nilList = oRec; - } else if (!name) { - /* any message coming from object */ - rec = (NotificationObserver*)WMHashInsert(notificationCenter->objectTable, - object, oRec); - oRec->next = rec; - if (rec) { - rec->prev = oRec; - } - } else { - /* name && (object || !object) */ - rec = (NotificationObserver*)WMHashInsert(notificationCenter->nameTable, - name, oRec); - oRec->next = rec; - if (rec) { - rec->prev = oRec; - } - } -} - - -void -WMPostNotification(WMNotification *notification) -{ - NotificationObserver *orec, *tmp; - - WMRetainNotification(notification); - - /* tell the observers that want to know about a particular message */ - orec = (NotificationObserver*)WMHashGet(notificationCenter->nameTable, - notification->name); - - while (orec) { - tmp = orec->next; - - if (!orec->object || !notification->object - || orec->object == notification->object) { - /* tell the observer */ - if (orec->observerAction) { - (*orec->observerAction)(orec->observer, notification); - } - } - - orec = tmp; - } - - /* tell the observers that want to know about an object */ - orec = (NotificationObserver*)WMHashGet(notificationCenter->objectTable, - notification->object); - - while (orec) { - tmp = orec->next; - - /* tell the observer */ - if (orec->observerAction) { - (*orec->observerAction)(orec->observer, notification); - } - orec = tmp; - } - - /* tell the catch all observers */ - orec = notificationCenter->nilList; - while (orec) { - tmp = orec->next; - - /* tell the observer */ - if (orec->observerAction) { - (*orec->observerAction)(orec->observer, notification); - } - orec = tmp; - } - - WMReleaseNotification(notification); -} - - -void -WMRemoveNotificationObserver(void *observer) -{ - NotificationObserver *orec, *tmp, *rec; - - /* get the list of actions the observer is doing */ - orec = (NotificationObserver*)WMHashGet(notificationCenter->observerTable, - observer); - - /* - * FOREACH orec IN actionlist for observer - * DO - * remove from respective lists/tables - * free - * END - */ - while (orec) { - tmp = orec->nextAction; - - if (!orec->name && !orec->object) { - /* catch-all */ - if (notificationCenter->nilList==orec) - notificationCenter->nilList = orec->next; - } else if (!orec->name) { - /* any message coming from object */ - rec = (NotificationObserver*)WMHashGet(notificationCenter->objectTable, - orec->object); - if (rec==orec) { - /* replace table entry */ - if (orec->next) { - WMHashInsert(notificationCenter->objectTable, orec->object, - orec->next); - } else { - WMHashRemove(notificationCenter->objectTable, orec->object); - } - } - } else { - /* name && (object || !object) */ - rec = (NotificationObserver*)WMHashGet(notificationCenter->nameTable, - orec->name); - if (rec==orec) { - /* replace table entry */ - if (orec->next) { - WMHashInsert(notificationCenter->nameTable, orec->name, - orec->next); - } else { - WMHashRemove(notificationCenter->nameTable, orec->name); - } - } - } - if (orec->prev) - orec->prev->next = orec->next; - if (orec->next) - orec->next->prev = orec->prev; - - wfree(orec); - - orec = tmp; - } - - WMHashRemove(notificationCenter->observerTable, observer); -} - - -void -WMRemoveNotificationObserverWithName(void *observer, const char *name, void *object) -{ - NotificationObserver *orec, *tmp, *rec; - NotificationObserver *newList = NULL; - - /* get the list of actions the observer is doing */ - orec = (NotificationObserver*)WMHashGet(notificationCenter->observerTable, observer); - - WMHashRemove(notificationCenter->observerTable, observer); - - /* rebuild the list of actions for the observer */ - - while (orec) { - tmp = orec->nextAction; - if (orec->name == name && orec->object == object) { - if (!name && !object) { - if (notificationCenter->nilList == orec) - notificationCenter->nilList = orec->next; - } else if (!name) { - rec = (NotificationObserver*)WMHashGet(notificationCenter->objectTable, orec->object); - if (rec==orec) { - assert(rec->prev==NULL); - /* replace table entry */ - if (orec->next) { - WMHashInsert(notificationCenter->objectTable, - orec->object, orec->next); - } else { - WMHashRemove(notificationCenter->objectTable, - orec->object); - } - } - } else { - rec = (NotificationObserver*)WMHashGet(notificationCenter->nameTable, - orec->name); - if (rec==orec) { - assert(rec->prev==NULL); - /* replace table entry */ - if (orec->next) { - WMHashInsert(notificationCenter->nameTable, - orec->name, orec->next); - } else { - WMHashRemove(notificationCenter->nameTable, - orec->name); - } - } - } - - if (orec->prev) - orec->prev->next = orec->next; - if (orec->next) - orec->next->prev = orec->prev; - wfree(orec); - } else { - /* append this action in the new action list */ - orec->nextAction = NULL; - if (!newList) { - newList = orec; - } else { - NotificationObserver *p; - - p = newList; - while (p->nextAction) { - p = p->nextAction; - } - p->nextAction = orec; - } - } - orec = tmp; - } - - /* reinsert the list to the table */ - if (newList) { - WMHashInsert(notificationCenter->observerTable, observer, newList); - } -} - - -void -WMPostNotificationName(const char *name, void *object, void *clientData) -{ - WMNotification *notification; - - notification = WMCreateNotification(name, object, clientData); - - WMPostNotification(notification); - - WMReleaseNotification(notification); -} - - - -/**************** Notification Queues ****************/ - - -typedef struct W_NotificationQueue { - WMArray *asapQueue; - WMArray *idleQueue; - - struct W_NotificationQueue *next; -} NotificationQueue; - - -static WMNotificationQueue *notificationQueueList = NULL; - -/* default queue */ -static WMNotificationQueue *notificationQueue = NULL; - - -WMNotificationQueue* -WMGetDefaultNotificationQueue(void) -{ - if (!notificationQueue) - notificationQueue = WMCreateNotificationQueue(); - - return notificationQueue; -} - - -WMNotificationQueue* -WMCreateNotificationQueue(void) -{ - NotificationQueue *queue; - - queue = wmalloc(sizeof(NotificationQueue)); - - queue->asapQueue = - WMCreateArrayWithDestructor(8, (WMFreeDataProc*)WMReleaseNotification); - queue->idleQueue = - WMCreateArrayWithDestructor(8, (WMFreeDataProc*)WMReleaseNotification); - queue->next = notificationQueueList; - - notificationQueueList = queue; - - return queue; -} - - - -void -WMEnqueueNotification(WMNotificationQueue *queue, WMNotification *notification, - WMPostingStyle postingStyle) -{ - WMEnqueueCoalesceNotification(queue, notification, postingStyle, - WNCOnName|WNCOnSender); -} - - -#define NOTIF ((WMNotification*)cdata) -#define ITEM ((WMNotification*)item) - -static int -matchSenderAndName(void *item, void *cdata) -{ - return (NOTIF->object==ITEM->object && strcmp(NOTIF->name, ITEM->name)==0); -} - - -static int -matchSender(void *item, void *cdata) -{ - return (NOTIF->object == ITEM->object); -} - - -static int -matchName(void *item, void *cdata) -{ - return (strcmp(NOTIF->name, ITEM->name)==0); -} - -#undef NOTIF -#undef ITEM - - -void -WMDequeueNotificationMatching(WMNotificationQueue *queue, - WMNotification *notification, unsigned mask) -{ - WMMatchDataProc *matchFunc; - - if ((mask & WNCOnName) && (mask & WNCOnSender)) - matchFunc = matchSenderAndName; - else if (mask & WNCOnName) - matchFunc = matchName; - else if (mask & WNCOnSender) - matchFunc = matchSender; - else - return; - - WMRemoveFromArrayMatching(queue->asapQueue, matchFunc, notification); - WMRemoveFromArrayMatching(queue->idleQueue, matchFunc, notification); -} - - -void -WMEnqueueCoalesceNotification(WMNotificationQueue *queue, - WMNotification *notification, - WMPostingStyle postingStyle, - unsigned coalesceMask) -{ - if (coalesceMask != WNCNone) - WMDequeueNotificationMatching(queue, notification, coalesceMask); - - switch (postingStyle) { - case WMPostNow: - WMPostNotification(notification); - WMReleaseNotification(notification); - break; - - case WMPostASAP: - WMAddToArray(queue->asapQueue, notification); - break; - - case WMPostWhenIdle: - WMAddToArray(queue->idleQueue, notification); - break; - } -} - - -void -W_FlushASAPNotificationQueue() -{ - WMNotificationQueue *queue = notificationQueueList; - - while (queue) { - while (WMGetArrayItemCount(queue->asapQueue)) { - WMPostNotification(WMGetFromArray(queue->asapQueue, 0)); - WMDeleteFromArray(queue->asapQueue, 0); - } - - queue = queue->next; - } -} - - -void -W_FlushIdleNotificationQueue() -{ - WMNotificationQueue *queue = notificationQueueList; - - while (queue) { - while (WMGetArrayItemCount(queue->idleQueue)) { - WMPostNotification(WMGetFromArray(queue->idleQueue, 0)); - WMDeleteFromArray(queue->idleQueue, 0); - } - - queue = queue->next; - } -} - + +#include +#include +#include +#include + +#include "WUtil.h" + +typedef struct W_Notification { + const char *name; + void *object; + void *clientData; + int refCount; +} Notification; + +extern void W_FlushASAPNotificationQueue(); + +const char *WMGetNotificationName(WMNotification * notification) +{ + return notification->name; +} + +void *WMGetNotificationObject(WMNotification * notification) +{ + return notification->object; +} + +void *WMGetNotificationClientData(WMNotification * notification) +{ + return notification->clientData; +} + +WMNotification *WMCreateNotification(const char *name, void *object, void *clientData) +{ + Notification *nPtr; + + nPtr = wmalloc(sizeof(Notification)); + + nPtr->name = name; + nPtr->object = object; + nPtr->clientData = clientData; + + nPtr->refCount = 1; + + return nPtr; +} + +void WMReleaseNotification(WMNotification * notification) +{ + notification->refCount--; + + if (notification->refCount < 1) { + wfree(notification); + } +} + +WMNotification *WMRetainNotification(WMNotification * notification) +{ + notification->refCount++; + + return notification; +} + +/***************** Notification Center *****************/ + +typedef struct NotificationObserver { + WMNotificationObserverAction *observerAction; + void *observer; + + const char *name; + void *object; + + struct NotificationObserver *prev; /* for tables */ + struct NotificationObserver *next; + struct NotificationObserver *nextAction; /* for observerTable */ +} NotificationObserver; + +typedef struct W_NotificationCenter { + WMHashTable *nameTable; /* names -> observer lists */ + WMHashTable *objectTable; /* object -> observer lists */ + NotificationObserver *nilList; /* obervers that catch everything */ + + WMHashTable *observerTable; /* observer -> NotificationObserver */ +} NotificationCenter; + +/* default (and only) center */ +static NotificationCenter *notificationCenter = NULL; + +void W_InitNotificationCenter(void) +{ + notificationCenter = wmalloc(sizeof(NotificationCenter)); + + notificationCenter->nameTable = WMCreateHashTable(WMStringPointerHashCallbacks); + notificationCenter->objectTable = WMCreateHashTable(WMIntHashCallbacks); + notificationCenter->nilList = NULL; + + notificationCenter->observerTable = WMCreateHashTable(WMIntHashCallbacks); +} + +void +WMAddNotificationObserver(WMNotificationObserverAction * observerAction, + void *observer, const char *name, void *object) +{ + NotificationObserver *oRec, *rec; + + oRec = wmalloc(sizeof(NotificationObserver)); + oRec->observerAction = observerAction; + oRec->observer = observer; + oRec->name = name; + oRec->object = object; + oRec->next = NULL; + oRec->prev = NULL; + + /* put this action in the list of actions for this observer */ + rec = (NotificationObserver *) WMHashInsert(notificationCenter->observerTable, observer, oRec); + + if (rec) { + /* if this is not the first action for the observer */ + oRec->nextAction = rec; + } else { + oRec->nextAction = NULL; + } + + if (!name && !object) { + /* catch-all */ + oRec->next = notificationCenter->nilList; + if (notificationCenter->nilList) { + notificationCenter->nilList->prev = oRec; + } + notificationCenter->nilList = oRec; + } else if (!name) { + /* any message coming from object */ + rec = (NotificationObserver *) WMHashInsert(notificationCenter->objectTable, object, oRec); + oRec->next = rec; + if (rec) { + rec->prev = oRec; + } + } else { + /* name && (object || !object) */ + rec = (NotificationObserver *) WMHashInsert(notificationCenter->nameTable, name, oRec); + oRec->next = rec; + if (rec) { + rec->prev = oRec; + } + } +} + +void WMPostNotification(WMNotification * notification) +{ + NotificationObserver *orec, *tmp; + + WMRetainNotification(notification); + + /* tell the observers that want to know about a particular message */ + orec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, notification->name); + + while (orec) { + tmp = orec->next; + + if (!orec->object || !notification->object || orec->object == notification->object) { + /* tell the observer */ + if (orec->observerAction) { + (*orec->observerAction) (orec->observer, notification); + } + } + + orec = tmp; + } + + /* tell the observers that want to know about an object */ + orec = (NotificationObserver *) WMHashGet(notificationCenter->objectTable, notification->object); + + while (orec) { + tmp = orec->next; + + /* tell the observer */ + if (orec->observerAction) { + (*orec->observerAction) (orec->observer, notification); + } + orec = tmp; + } + + /* tell the catch all observers */ + orec = notificationCenter->nilList; + while (orec) { + tmp = orec->next; + + /* tell the observer */ + if (orec->observerAction) { + (*orec->observerAction) (orec->observer, notification); + } + orec = tmp; + } + + WMReleaseNotification(notification); +} + +void WMRemoveNotificationObserver(void *observer) +{ + NotificationObserver *orec, *tmp, *rec; + + /* get the list of actions the observer is doing */ + orec = (NotificationObserver *) WMHashGet(notificationCenter->observerTable, observer); + + /* + * FOREACH orec IN actionlist for observer + * DO + * remove from respective lists/tables + * free + * END + */ + while (orec) { + tmp = orec->nextAction; + + if (!orec->name && !orec->object) { + /* catch-all */ + if (notificationCenter->nilList == orec) + notificationCenter->nilList = orec->next; + } else if (!orec->name) { + /* any message coming from object */ + rec = (NotificationObserver *) WMHashGet(notificationCenter->objectTable, orec->object); + if (rec == orec) { + /* replace table entry */ + if (orec->next) { + WMHashInsert(notificationCenter->objectTable, orec->object, orec->next); + } else { + WMHashRemove(notificationCenter->objectTable, orec->object); + } + } + } else { + /* name && (object || !object) */ + rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, orec->name); + if (rec == orec) { + /* replace table entry */ + if (orec->next) { + WMHashInsert(notificationCenter->nameTable, orec->name, orec->next); + } else { + WMHashRemove(notificationCenter->nameTable, orec->name); + } + } + } + if (orec->prev) + orec->prev->next = orec->next; + if (orec->next) + orec->next->prev = orec->prev; + + wfree(orec); + + orec = tmp; + } + + WMHashRemove(notificationCenter->observerTable, observer); +} + +void WMRemoveNotificationObserverWithName(void *observer, const char *name, void *object) +{ + NotificationObserver *orec, *tmp, *rec; + NotificationObserver *newList = NULL; + + /* get the list of actions the observer is doing */ + orec = (NotificationObserver *) WMHashGet(notificationCenter->observerTable, observer); + + WMHashRemove(notificationCenter->observerTable, observer); + + /* rebuild the list of actions for the observer */ + + while (orec) { + tmp = orec->nextAction; + if (orec->name == name && orec->object == object) { + if (!name && !object) { + if (notificationCenter->nilList == orec) + notificationCenter->nilList = orec->next; + } else if (!name) { + rec = + (NotificationObserver *) WMHashGet(notificationCenter->objectTable, + orec->object); + if (rec == orec) { + assert(rec->prev == NULL); + /* replace table entry */ + if (orec->next) { + WMHashInsert(notificationCenter->objectTable, + orec->object, orec->next); + } else { + WMHashRemove(notificationCenter->objectTable, orec->object); + } + } + } else { + rec = (NotificationObserver *) WMHashGet(notificationCenter->nameTable, + orec->name); + if (rec == orec) { + assert(rec->prev == NULL); + /* replace table entry */ + if (orec->next) { + WMHashInsert(notificationCenter->nameTable, + orec->name, orec->next); + } else { + WMHashRemove(notificationCenter->nameTable, orec->name); + } + } + } + + if (orec->prev) + orec->prev->next = orec->next; + if (orec->next) + orec->next->prev = orec->prev; + wfree(orec); + } else { + /* append this action in the new action list */ + orec->nextAction = NULL; + if (!newList) { + newList = orec; + } else { + NotificationObserver *p; + + p = newList; + while (p->nextAction) { + p = p->nextAction; + } + p->nextAction = orec; + } + } + orec = tmp; + } + + /* reinsert the list to the table */ + if (newList) { + WMHashInsert(notificationCenter->observerTable, observer, newList); + } +} + +void WMPostNotificationName(const char *name, void *object, void *clientData) +{ + WMNotification *notification; + + notification = WMCreateNotification(name, object, clientData); + + WMPostNotification(notification); + + WMReleaseNotification(notification); +} + +/**************** Notification Queues ****************/ + +typedef struct W_NotificationQueue { + WMArray *asapQueue; + WMArray *idleQueue; + + struct W_NotificationQueue *next; +} NotificationQueue; + +static WMNotificationQueue *notificationQueueList = NULL; + +/* default queue */ +static WMNotificationQueue *notificationQueue = NULL; + +WMNotificationQueue *WMGetDefaultNotificationQueue(void) +{ + if (!notificationQueue) + notificationQueue = WMCreateNotificationQueue(); + + return notificationQueue; +} + +WMNotificationQueue *WMCreateNotificationQueue(void) +{ + NotificationQueue *queue; + + queue = wmalloc(sizeof(NotificationQueue)); + + queue->asapQueue = WMCreateArrayWithDestructor(8, (WMFreeDataProc *) WMReleaseNotification); + queue->idleQueue = WMCreateArrayWithDestructor(8, (WMFreeDataProc *) WMReleaseNotification); + queue->next = notificationQueueList; + + notificationQueueList = queue; + + return queue; +} + +void WMEnqueueNotification(WMNotificationQueue * queue, WMNotification * notification, WMPostingStyle postingStyle) +{ + WMEnqueueCoalesceNotification(queue, notification, postingStyle, WNCOnName | WNCOnSender); +} + +#define NOTIF ((WMNotification*)cdata) +#define ITEM ((WMNotification*)item) + +static int matchSenderAndName(void *item, void *cdata) +{ + return (NOTIF->object == ITEM->object && strcmp(NOTIF->name, ITEM->name) == 0); +} + +static int matchSender(void *item, void *cdata) +{ + return (NOTIF->object == ITEM->object); +} + +static int matchName(void *item, void *cdata) +{ + return (strcmp(NOTIF->name, ITEM->name) == 0); +} + +#undef NOTIF +#undef ITEM + +void WMDequeueNotificationMatching(WMNotificationQueue * queue, WMNotification * notification, unsigned mask) +{ + WMMatchDataProc *matchFunc; + + if ((mask & WNCOnName) && (mask & WNCOnSender)) + matchFunc = matchSenderAndName; + else if (mask & WNCOnName) + matchFunc = matchName; + else if (mask & WNCOnSender) + matchFunc = matchSender; + else + return; + + WMRemoveFromArrayMatching(queue->asapQueue, matchFunc, notification); + WMRemoveFromArrayMatching(queue->idleQueue, matchFunc, notification); +} + +void +WMEnqueueCoalesceNotification(WMNotificationQueue * queue, + WMNotification * notification, WMPostingStyle postingStyle, unsigned coalesceMask) +{ + if (coalesceMask != WNCNone) + WMDequeueNotificationMatching(queue, notification, coalesceMask); + + switch (postingStyle) { + case WMPostNow: + WMPostNotification(notification); + WMReleaseNotification(notification); + break; + + case WMPostASAP: + WMAddToArray(queue->asapQueue, notification); + break; + + case WMPostWhenIdle: + WMAddToArray(queue->idleQueue, notification); + break; + } +} + +void W_FlushASAPNotificationQueue() +{ + WMNotificationQueue *queue = notificationQueueList; + + while (queue) { + while (WMGetArrayItemCount(queue->asapQueue)) { + WMPostNotification(WMGetFromArray(queue->asapQueue, 0)); + WMDeleteFromArray(queue->asapQueue, 0); + } + + queue = queue->next; + } +} + +void W_FlushIdleNotificationQueue() +{ + WMNotificationQueue *queue = notificationQueueList; + + while (queue) { + while (WMGetArrayItemCount(queue->idleQueue)) { + WMPostNotification(WMGetFromArray(queue->idleQueue, 0)); + WMDeleteFromArray(queue->idleQueue, 0); + } + + queue = queue->next; + } +}