Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / dragdestination.c
dissimilarity index 85%
index f538722..0f1849f 100644 (file)
-
-
-#include "WINGsP.h"
-#include <X11/Xatom.h>
-
-#define XDND_SOURCE_RESPONSE_MAX_DELAY 3000
-
-#define XDND_PROPERTY_FORMAT 32
-#define XDND_ACTION_DESCRIPTION_FORMAT 8
-
-#define XDND_SOURCE_VERSION(dragInfo) dragInfo->protocolVersion
-#define XDND_DEST_INFO(dragInfo) dragInfo->destInfo
-#define XDND_AWARE_VIEW(dragInfo) dragInfo->destInfo->xdndAwareView
-#define XDND_SOURCE_WIN(dragInfo) dragInfo->destInfo->sourceWindow
-#define XDND_DEST_VIEW(dragInfo) dragInfo->destInfo->destView
-#define XDND_DEST_STATE(dragInfo) dragInfo->destInfo->state
-#define XDND_SOURCE_ACTION_CHANGED(dragInfo) dragInfo->destInfo->sourceActionChanged
-#define XDND_SOURCE_TYPES(dragInfo) dragInfo->destInfo->sourceTypes
-#define XDND_TYPE_LIST_AVAILABLE(dragInfo) dragInfo->destInfo->typeListAvailable
-#define XDND_REQUIRED_TYPES(dragInfo) dragInfo->destInfo->requiredTypes
-#define XDND_SOURCE_ACTION(dragInfo) dragInfo->sourceAction
-#define XDND_DEST_ACTION(dragInfo) dragInfo->destinationAction
-#define XDND_SOURCE_OPERATIONS(dragInfo) dragInfo->destInfo->sourceOperations
-#define XDND_DROP_DATAS(dragInfo) dragInfo->destInfo->dropDatas
-#define XDND_DROP_DATA_COUNT(dragInfo) dragInfo->destInfo->dropDataCount
-#define XDND_DEST_VIEW_IS_REGISTERED(dragInfo) ((dragInfo->destInfo) != NULL)\
-    && ((dragInfo->destInfo->destView->dragDestinationProcs) != NULL)
-
-
-static unsigned char XDNDversion = XDND_VERSION;
-static WMHandlerID dndDestinationTimer = NULL;
-
-
-static void* idleState(WMView *destView, XClientMessageEvent *event,
-                       WMDraggingInfo *info);
-static void* waitEnterState(WMView *destView, XClientMessageEvent *event,
-                            WMDraggingInfo *info);
-static void* inspectDropDataState(WMView *destView, XClientMessageEvent *event,
-                                  WMDraggingInfo *info);
-static void* dropAllowedState(WMView *destView, XClientMessageEvent *event,
-                              WMDraggingInfo *info);
-static void* dropNotAllowedState(WMView *destView, XClientMessageEvent *event,
-                                 WMDraggingInfo *info);
-static void* waitForDropDataState(WMView *destView, XClientMessageEvent *event,
-                                  WMDraggingInfo *info);
-
-/* ----- Types & datas list ----- */
-static void
-freeSourceTypeArrayItem(void *type)
-{
-    XFree(type);
-}
-
-
-static WMArray*
-createSourceTypeArray(int initialSize)
-{
-    return WMCreateArrayWithDestructor(initialSize, freeSourceTypeArrayItem);
-}
-
-
-static void
-freeDropDataArrayItem(void* data)
-{
-    if (data != NULL)
-        WMReleaseData((WMData*) data);
-}
-
-
-static WMArray*
-createDropDataArray(WMArray *requiredTypes)
-{
-    if (requiredTypes != NULL)
-        return WMCreateArrayWithDestructor(
-                                           WMGetArrayItemCount(requiredTypes),
-                                           freeDropDataArrayItem);
-
-    else
-        return WMCreateArray(0);
-}
-
-static WMArray*
-getTypesFromTypeList(WMScreen *scr, Window sourceWin)
-{
-    Atom dataType;
-    Atom* typeAtomList;
-    WMArray* typeList;
-    int i, format;
-    unsigned long count, remaining;
-    unsigned char *data = NULL;
-
-    XGetWindowProperty(scr->display, sourceWin, scr->xdndTypeListAtom,
-                       0, 0x8000000L, False, XA_ATOM, &dataType, &format,
-                       &count, &remaining, &data);
-
-    if (dataType!=XA_ATOM || format!=XDND_PROPERTY_FORMAT || count==0 || !data) {
-        if (data) {
-            XFree(data);
-        }
-        return createSourceTypeArray(0);
-    }
-
-    typeList = createSourceTypeArray(count);
-    typeAtomList = (Atom*) data;
-    for (i=0; i < count; i++) {
-        WMAddToArray(typeList, XGetAtomName(scr->display, typeAtomList[i]));
-    }
-
-    XFree(data);
-
-    return typeList;
-}
-
-
-static WMArray*
-getTypesFromThreeTypes(WMScreen *scr, XClientMessageEvent *event)
-{
-    WMArray* typeList;
-    Atom atom;
-    int i;
-
-    typeList = createSourceTypeArray(3);
-    for (i = 2; i < 5; i++) {
-        if (event->data.l[i] != None) {
-            atom = (Atom)event->data.l[i];
-            WMAddToArray(typeList, XGetAtomName(scr->display, atom));
-        }
-    }
-
-    return typeList;
-}
-
-
-void
-storeRequiredTypeList(WMDraggingInfo *info)
-{
-    WMView *destView = XDND_DEST_VIEW(info);
-    WMScreen *scr = W_VIEW_SCREEN(destView);
-    WMArray *requiredTypes;
-
-    /* First, see if the stored source types are enough for dest requirements */
-    requiredTypes = destView->dragDestinationProcs->requiredDataTypes(
-                                                                      destView,
-                                                                      W_ActionToOperation(scr, XDND_SOURCE_ACTION(info)),
-                                                                      XDND_SOURCE_TYPES(info));
-
-    if (requiredTypes == NULL && XDND_TYPE_LIST_AVAILABLE(info)) {
-        /* None of the stored source types fits, but the whole type list
-           hasn't been retrieved yet. */
-        WMFreeArray(XDND_SOURCE_TYPES(info));
-        XDND_SOURCE_TYPES(info) = getTypesFromTypeList(
-                                                       scr,
-                                                       XDND_SOURCE_WIN(info));
-        /* Don't retrieve the type list again */
-        XDND_TYPE_LIST_AVAILABLE(info) = False;
-
-        requiredTypes =
-            destView->dragDestinationProcs->requiredDataTypes(
-                                                              destView,
-                                                              W_ActionToOperation(scr, XDND_SOURCE_ACTION(info)),
-                                                              XDND_SOURCE_TYPES(info));
-    }
-
-    XDND_REQUIRED_TYPES(info) = requiredTypes;
-}
-
-
-char*
-getNextRequestedDataType(WMDraggingInfo *info)
-{
-    /* get the type of the first data not yet retrieved from selection */
-    int nextTypeIndex;
-
-    if (XDND_REQUIRED_TYPES(info) != NULL) {
-        nextTypeIndex = WMGetArrayItemCount(XDND_DROP_DATAS(info));
-        return WMGetFromArray(XDND_REQUIRED_TYPES(info), nextTypeIndex);
-        /* NULL if no more type */
-    } else
-        return NULL;
-}
-
-
-/* ----- Action list ----- */
-
-WMArray*
-sourceOperationList(WMScreen *scr, Window sourceWin)
-{
-    Atom dataType, *actionList;
-    int i, size;
-    unsigned long count, remaining;
-    unsigned char* actionDatas = NULL;
-    unsigned char* descriptionList = NULL;
-    WMArray* operationArray;
-    WMDragOperationItem* operationItem;
-    char* description;
-
-    remaining = 0;
-    XGetWindowProperty(scr->display, sourceWin, scr->xdndActionListAtom,
-                       0, 0x8000000L, False, XA_ATOM, &dataType, &size,
-                       &count, &remaining, &actionDatas);
-
-    if (dataType!=XA_ATOM || size!=XDND_PROPERTY_FORMAT || count==0 || !actionDatas) {
-        wwarning("Cannot read action list");
-        if (actionDatas) {
-            XFree(actionDatas);
-        }
-        return NULL;
-    }
-
-    actionList = (Atom*)actionDatas;
-
-    XGetWindowProperty(scr->display, sourceWin, scr->xdndActionDescriptionAtom,
-                       0, 0x8000000L, False, XA_STRING, &dataType, &size,
-                       &count, &remaining, &descriptionList);
-
-    if (dataType!=XA_STRING || size!=XDND_ACTION_DESCRIPTION_FORMAT ||
-        count==0 || !descriptionList) {
-        wwarning("Cannot read action description list");
-        if (actionList) {
-            XFree(actionList);
-        }
-        if (descriptionList) {
-            XFree(descriptionList);
-        }
-        return NULL;
-    }
-
-    operationArray = WMCreateDragOperationArray(count);
-    description = (char*)descriptionList;
-
-    for (i=0; count > 0; i++) {
-        size = strlen(description);
-        operationItem = WMCreateDragOperationItem(
-                                                  W_ActionToOperation(scr, actionList[i]),
-                                                  wstrdup(description));
-
-        WMAddToArray(operationArray, operationItem);
-        count -= (size + 1); /* -1 : -NULL char */
-
-        /* next description */
-        description = &(description[size + 1]);
-    }
-
-    XFree(actionList);
-    XFree(descriptionList);
-
-    return operationArray;
-}
-
-
-/* ----- Dragging Info ----- */
-static void
-updateSourceWindow(WMDraggingInfo *info, XClientMessageEvent *event)
-{
-    XDND_SOURCE_WIN(info) = (Window) event->data.l[0];
-}
-
-
-static WMView*
-findChildInView(WMView* parent, int x, int y)
-{
-    if (parent->childrenList == NULL)
-        return parent;
-    else {
-        WMView* child = parent->childrenList;
-
-        while (child != NULL
-               && (! child->flags.mapped
-                   || x < WMGetViewPosition(child).x
-                   || x > WMGetViewPosition(child).x + WMGetViewSize(child).width
-                   || y < WMGetViewPosition(child).y
-                   || y > WMGetViewPosition(child).y + WMGetViewSize(child).height))
-
-            child = child->nextSister;
-
-        if (child == NULL)
-            return parent;
-        else
-            return findChildInView(child,
-                                      x - WMGetViewPosition(child).x,
-                                      y - WMGetViewPosition(child).y);
-    }
-}
-
-
-static WMView*
-findDestinationViewInToplevel(WMView* toplevel, int x, int y)
-{
-    WMScreen *scr = W_VIEW_SCREEN(toplevel);
-    Window toplevelWin = WMViewXID(toplevel);
-    int xInToplevel, yInToplevel;
-    Window foo;
-
-    XTranslateCoordinates(scr->display, scr->rootWin, toplevelWin,
-                          x, y, &xInToplevel, &yInToplevel,
-                          &foo);
-    return findChildInView(toplevel, xInToplevel, yInToplevel);
-}
-
-
-/* Clear datas only used by current destination view */
-static void
-freeDestinationViewInfos(WMDraggingInfo *info)
-{
-    if (XDND_SOURCE_TYPES(info) != NULL) {
-        WMFreeArray(XDND_SOURCE_TYPES(info));
-        XDND_SOURCE_TYPES(info) = NULL;
-    }
-
-    if (XDND_DROP_DATAS(info) != NULL) {
-        WMFreeArray(XDND_DROP_DATAS(info));
-        XDND_DROP_DATAS(info) = NULL;
-    }
-
-    XDND_REQUIRED_TYPES(info) = NULL;
-}
-
-
-void
-W_DragDestinationInfoClear(WMDraggingInfo *info)
-{
-    W_DragDestinationStopTimer();
-
-    if (XDND_DEST_INFO(info) != NULL) {
-        freeDestinationViewInfos(info);
-
-        wfree(XDND_DEST_INFO(info));
-        XDND_DEST_INFO(info) = NULL;
-    }
-}
-
-
-static void
-initDestinationDragInfo(WMDraggingInfo *info, WMView *destView)
-{
-    wassertr(destView != NULL);
-
-    XDND_DEST_INFO(info) =
-        (W_DragDestinationInfo*) wmalloc(sizeof(W_DragDestinationInfo));
-
-    XDND_DEST_STATE(info) = idleState;
-    XDND_DEST_VIEW(info) = destView;
-
-    XDND_SOURCE_ACTION_CHANGED(info) = False;
-    XDND_SOURCE_TYPES(info) = NULL;
-    XDND_REQUIRED_TYPES(info) = NULL;
-    XDND_DROP_DATAS(info) = NULL;
-}
-
-
-void
-W_DragDestinationStoreEnterMsgInfo(WMDraggingInfo *info,
-                                   WMView *toplevel, XClientMessageEvent *event)
-{
-    WMScreen *scr = W_VIEW_SCREEN(toplevel);
-
-    if (XDND_DEST_INFO(info) == NULL)
-        initDestinationDragInfo(info, toplevel);
-
-    XDND_SOURCE_VERSION(info) = (event->data.l[1] >> 24);
-    XDND_AWARE_VIEW(info) = toplevel;
-    updateSourceWindow(info, event);
-
-/*
-    if (event->data.l[1] & 1)
-        /* XdndTypeList property is available */
-/*        XDND_SOURCE_TYPES(info) = getTypesFromTypeList(scr, XDND_SOURCE_WIN(info));
-    else
-        XDND_SOURCE_TYPES(info) = getTypesFromThreeTypes(scr, event);
-*/
-    XDND_SOURCE_TYPES(info) = getTypesFromThreeTypes(scr, event);
-
-    /* to use if the 3 types are not enough */
-    XDND_TYPE_LIST_AVAILABLE(info) = (event->data.l[1] & 1);
-}
-
-
-void
-W_DragDestinationStorePositionMsgInfo(WMDraggingInfo *info,
-                                      WMView *toplevel, XClientMessageEvent *event)
-{
-    int x = event->data.l[2] >> 16;
-    int y = event->data.l[2] & 0xffff;
-    WMView *newDestView;
-
-    newDestView = findDestinationViewInToplevel(toplevel, x, y);
-
-    if (XDND_DEST_INFO(info) == NULL) {
-        initDestinationDragInfo(info, newDestView);
-        XDND_AWARE_VIEW(info) = toplevel;
-        updateSourceWindow(info, event);
-    } else {
-        if (newDestView != XDND_DEST_VIEW(info)) {
-            updateSourceWindow(info, event);
-            XDND_DEST_VIEW(info) = newDestView;
-            XDND_SOURCE_ACTION_CHANGED(info) = False;
-
-            if (XDND_DEST_STATE(info) != waitEnterState)
-                XDND_DEST_STATE(info) = idleState;
-        } else {
-            XDND_SOURCE_ACTION_CHANGED(info) = (XDND_SOURCE_ACTION(info) != event->data.l[4]);
-        }
-    }
-
-    XDND_SOURCE_ACTION(info) = event->data.l[4];
-
-    /* note: source position is not stored */
-}
-
-/* ----- End of Dragging Info ----- */
-
-
-/* ----- Messages ----- */
-
-/* send a DnD message to the source window */
-static void
-sendDnDClientMessage(WMDraggingInfo *info, Atom message,
-                     unsigned long data1,
-                     unsigned long data2,
-                     unsigned long data3,
-                     unsigned long data4)
-{
-    if (! W_SendDnDClientMessage(W_VIEW_SCREEN(XDND_AWARE_VIEW(info))->display,
-                                 XDND_SOURCE_WIN(info),
-                                 message,
-                                 WMViewXID(XDND_AWARE_VIEW(info)),
-                                 data1,
-                                 data2,
-                                 data3,
-                                 data4)) {
-        /* drop failed */
-        W_DragDestinationInfoClear(info);
-    }
-}
-
-
-/* send a xdndStatus message to the source, with position and size
-   of the destination if it has no subwidget (requesting a position message
-   on every move otherwise) */
-static void
-sendStatusMessage(WMView *destView, WMDraggingInfo *info, Atom action)
-{
-    unsigned long data1;
-
-    data1 = (action == None) ? 0 : 1;
-
-    if (destView->childrenList == NULL) {
-        WMScreen *scr = W_VIEW_SCREEN(destView);
-        int destX, destY;
-        WMSize destSize = WMGetViewSize(destView);
-        Window foo;
-
-        XTranslateCoordinates(scr->display, WMViewXID(destView), scr->rootWin,
-                              0, 0, &destX, &destY,
-                              &foo);
-
-       sendDnDClientMessage(info,
-                             W_VIEW_SCREEN(destView)->xdndStatusAtom,
-                             data1,
-                             (destX << 16)|destY,
-                             (destSize.width << 16)|destSize.height,
-                             action);
-    } else {
-        /* set bit 1 to request explicitly position message on every move */
-        data1 = data1 | 2;
-
-        sendDnDClientMessage(info,
-                             W_VIEW_SCREEN(destView)->xdndStatusAtom,
-                             data1,
-                             0,
-                             0,
-                             action);
-    }
-}
-
-
-static void
-storeDropData(WMView *destView, Atom selection, Atom target,
-              Time timestamp, void *cdata, WMData *data)
-{
-    WMScreen *scr = W_VIEW_SCREEN(destView);
-    WMDraggingInfo *info = &(scr->dragInfo);
-    WMData *dataToStore = NULL;
-
-    if (data != NULL)
-        dataToStore = WMRetainData(data);
-
-    if (XDND_DEST_INFO(info) != NULL && XDND_DROP_DATAS(info) != NULL) {
-        WMAddToArray(XDND_DROP_DATAS(info), dataToStore);
-        W_SendDnDClientMessage(scr->display, WMViewXID(destView),
-                               scr->xdndSelectionAtom,
-                               WMViewXID(destView),
-                               0, 0, 0, 0);
-    }
-}
-
-
-Bool
-requestDropDataInSelection(WMView *destView, char* type)
-{
-    WMScreen *scr = W_VIEW_SCREEN(destView);
-
-    if (type != NULL) {
-        if (!WMRequestSelection(destView,
-                                scr->xdndSelectionAtom,
-                                XInternAtom(scr->display, type, False),
-                                CurrentTime,
-                                storeDropData, NULL)) {
-            wwarning("could not request data for dropped data");
-            return False;
-        }
-
-        return True;
-    }
-
-    return False;
-}
-
-
-Bool
-requestDropData(WMDraggingInfo *info)
-{
-    WMView *destView = XDND_DEST_VIEW(info);
-    char* nextType = getNextRequestedDataType(info);
-
-    while ((nextType != NULL)
-           && (!requestDropDataInSelection(destView, nextType)) ) {
-        /* store NULL if request failed, and try with next type */
-        WMAddToArray(XDND_DROP_DATAS(info), NULL);
-        nextType = getNextRequestedDataType(info);
-    }
-
-    /* remains types to retrieve ? */
-    return (nextType != NULL);
-}
-
-
-static void
-concludeDrop(WMView *destView)
-{
-    destView->dragDestinationProcs->concludeDragOperation(destView);
-}
-
-
-/* send cancel message to the source */
-static void
-cancelDrop(WMView *destView, WMDraggingInfo *info)
-{
-    sendStatusMessage(destView, info, None);
-    concludeDrop(destView);
-    freeDestinationViewInfos(info);
-}
-
-
-/* suspend drop, when dragged icon enter an unregistered view
-   or a register view that doesn't accept the drop */
-static void
-suspendDropAuthorization(WMView *destView, WMDraggingInfo *info)
-{
-    sendStatusMessage(destView, info, None);
-
-    /* Free datas that depend on destination behaviour */
-    if (XDND_DROP_DATAS(info) != NULL) {
-        WMFreeArray(XDND_DROP_DATAS(info));
-        XDND_DROP_DATAS(info) = NULL;
-    }
-
-    XDND_REQUIRED_TYPES(info) = NULL;
-}
-
-
-/* cancel drop on Enter message, if protocol version is nok */
-void
-W_DragDestinationCancelDropOnEnter(WMView *toplevel, WMDraggingInfo *info)
-{
-    if (XDND_DEST_VIEW_IS_REGISTERED(info))
-        cancelDrop(XDND_DEST_VIEW(info), info);
-    else
-        sendStatusMessage(toplevel, info, None);
-
-    W_DragDestinationInfoClear(info);
-}
-
-
-static void
-finishDrop(WMView *destView, WMDraggingInfo *info)
-{
-    sendDnDClientMessage(info,
-                         W_VIEW_SCREEN(destView)->xdndFinishedAtom,
-                         0, 0, 0, 0);
-    concludeDrop(destView);
-    W_DragDestinationInfoClear(info);
-}
-
-
-static Atom
-getAllowedAction(WMView *destView, WMDraggingInfo *info)
-{
-    WMScreen *scr = W_VIEW_SCREEN(destView);
-
-    return W_OperationToAction(scr,
-                               destView->dragDestinationProcs->allowedOperation(
-                                                                                destView,
-                                                                                W_ActionToOperation(scr, XDND_SOURCE_ACTION(info)),
-                                                                                XDND_SOURCE_TYPES(info)));
-}
-
-
-static void*
-checkActionAllowed(WMView *destView, WMDraggingInfo* info)
-{
-    XDND_DEST_ACTION(info) =
-        getAllowedAction(destView, info);
-
-    if (XDND_DEST_ACTION(info) == None) {
-        suspendDropAuthorization(destView, info);
-        return dropNotAllowedState;
-    }
-
-    sendStatusMessage(destView, info, XDND_DEST_ACTION(info));
-    return dropAllowedState;
-}
-
-
-static void*
-checkDropAllowed(WMView *destView, XClientMessageEvent *event,
-                 WMDraggingInfo* info)
-{
-    storeRequiredTypeList(info);
-
-    if (destView->dragDestinationProcs->inspectDropData != NULL) {
-        XDND_DROP_DATAS(info) = createDropDataArray(
-                                                    XDND_REQUIRED_TYPES(info));
-
-        /* store first available data */
-        if (requestDropData(info))
-            return inspectDropDataState;
-
-        /* no data retrieved, but inspect can allow it */
-        if (destView->dragDestinationProcs->inspectDropData(
-                                                            destView,
-                                                            XDND_DROP_DATAS(info)))
-            return checkActionAllowed(destView, info);
-
-        suspendDropAuthorization(destView, info);
-        return dropNotAllowedState;
-    }
-
-    return checkActionAllowed(destView, info);
-}
-
-
-static WMPoint*
-getDropLocationInView(WMView *view)
-{
-    Window rootWin, childWin;
-    int rootX, rootY;
-    unsigned int mask;
-    WMPoint* location;
-
-    location = (WMPoint*) wmalloc(sizeof(WMPoint));
-
-    XQueryPointer(
-                  W_VIEW_SCREEN(view)->display,
-                  WMViewXID(view), &rootWin, &childWin,
-                  &rootX, &rootY,
-                  &(location->x), &(location->y),
-                  &mask);
-
-    return location;
-}
-
-
-static void
-callPerformDragOperation(WMView *destView, WMDraggingInfo *info)
-{
-    WMArray *operationList = NULL;
-    WMScreen *scr = W_VIEW_SCREEN(destView);
-    WMPoint* dropLocation;
-
-    if (XDND_SOURCE_ACTION(info) == scr->xdndActionAsk)
-        operationList = sourceOperationList(scr, XDND_SOURCE_WIN(info));
-
-    dropLocation = getDropLocationInView(destView);
-    destView->dragDestinationProcs->performDragOperation(
-                                                         destView,
-                                                         XDND_DROP_DATAS(info),
-                                                         operationList,
-                                                         dropLocation);
-
-    wfree(dropLocation);
-    if (operationList != NULL)
-        WMFreeArray(operationList);
-}
-
-
-/* ----- Destination timer ----- */
-static void
-dragSourceResponseTimeOut(void *destView)
-{
-    WMView *view = (WMView*) destView;
-    WMDraggingInfo *info;
-
-    wwarning("delay for drag source response expired");
-    info = &(W_VIEW_SCREEN(view)->dragInfo);
-    if (XDND_DEST_VIEW_IS_REGISTERED(info))
-        cancelDrop(view, info);
-    else {
-        sendStatusMessage(view, info, None);
-    }
-
-    W_DragDestinationInfoClear(info);
-}
-
-
-void
-W_DragDestinationStopTimer()
-{
-    if (dndDestinationTimer != NULL) {
-        WMDeleteTimerHandler(dndDestinationTimer);
-        dndDestinationTimer = NULL;
-    }
-}
-
-
-void
-W_DragDestinationStartTimer(WMDraggingInfo *info)
-{
-    W_DragDestinationStopTimer();
-
-    if (XDND_DEST_STATE(info) != idleState)
-        dndDestinationTimer = WMAddTimerHandler(
-                                                XDND_SOURCE_RESPONSE_MAX_DELAY,
-                                                dragSourceResponseTimeOut,
-                                                XDND_DEST_VIEW(info));
-}
-/* ----- End of Destination timer ----- */
-
-
-/* ----- Destination states ----- */
-
-#ifdef XDND_DEBUG
-static const char*
-stateName(W_DndState *state)
-{
-    if (state == NULL)
-        return "no state defined";
-
-    if (state == idleState)
-        return "idleState";
-
-    if (state == waitEnterState)
-        return "waitEnterState";
-
-    if (state == inspectDropDataState)
-        return "inspectDropDataState";
-
-    if (state == dropAllowedState)
-        return "dropAllowedState";
-
-    if (state == dropNotAllowedState)
-        return "dropNotAllowedState";
-
-    if (state == waitForDropDataState)
-        return "waitForDropDataState";
-
-    return "unknown state";
-}
-#endif
-
-
-static void*
-idleState(WMView *destView, XClientMessageEvent *event,
-          WMDraggingInfo *info)
-{
-    WMScreen *scr;
-    Atom sourceMsg;
-
-    if (destView->dragDestinationProcs != NULL) {
-        scr = W_VIEW_SCREEN(destView);
-        sourceMsg = event->message_type;
-
-        if (sourceMsg == scr->xdndPositionAtom) {
-            destView->dragDestinationProcs->prepareForDragOperation(destView);
-
-            if (XDND_SOURCE_TYPES(info) != NULL) {
-                /* enter message infos are available */
-                return checkDropAllowed(destView, event, info);
-            }
-
-            /* waiting for enter message */
-            return waitEnterState;
-        }
-    }
-
-    suspendDropAuthorization(destView, info);
-    return idleState;
-}
-
-
-/*  Source position and action are stored,
- waiting for xdnd protocol version and source type */
-static void*
-waitEnterState(WMView *destView, XClientMessageEvent *event,
-               WMDraggingInfo *info)
-{
-    WMScreen *scr = W_VIEW_SCREEN(destView);
-    Atom sourceMsg = event->message_type;
-
-    if (sourceMsg == scr->xdndEnterAtom) {
-        W_DragDestinationStoreEnterMsgInfo(info, destView, event);
-        return checkDropAllowed(destView, event, info);
-    }
-
-    return waitEnterState;
-}
-
-
-/* We have requested a data, and have received it */
-static void*
-inspectDropDataState(WMView *destView, XClientMessageEvent *event,
-                     WMDraggingInfo *info)
-{
-    WMScreen *scr;
-    Atom sourceMsg;
-
-    scr = W_VIEW_SCREEN(destView);
-    sourceMsg = event->message_type;
-
-    if (sourceMsg == scr->xdndSelectionAtom) {
-        /* a data has been retrieved, store next available */
-        if (requestDropData(info))
-            return inspectDropDataState;
-
-        /* all required (and available) datas are stored */
-        if (destView->dragDestinationProcs->inspectDropData(
-                                                            destView,
-                                                            XDND_DROP_DATAS(info)))
-            return checkActionAllowed(destView, info);
-
-        suspendDropAuthorization(destView, info);
-        return dropNotAllowedState;
-    }
-
-    return inspectDropDataState;
-}
-
-
-static void*
-dropNotAllowedState(WMView *destView, XClientMessageEvent *event,
-                    WMDraggingInfo *info)
-{
-    WMScreen *scr = W_VIEW_SCREEN(destView);
-    Atom sourceMsg = event->message_type;
-
-    if (sourceMsg == scr->xdndDropAtom) {
-        finishDrop(destView, info);
-        return idleState;
-    }
-
-    if (sourceMsg == scr->xdndPositionAtom) {
-        if (XDND_SOURCE_ACTION_CHANGED(info)) {
-            return checkDropAllowed(destView, event, info);
-        } else {
-            sendStatusMessage(destView, info, None);
-            return dropNotAllowedState;
-        }
-    }
-
-    return dropNotAllowedState;
-}
-
-
-static void*
-dropAllowedState(WMView *destView, XClientMessageEvent *event,
-                 WMDraggingInfo *info)
-{
-    WMScreen *scr = W_VIEW_SCREEN(destView);
-    Atom sourceMsg = event->message_type;
-
-    if (sourceMsg == scr->xdndDropAtom) {
-        if (XDND_DROP_DATAS(info) != NULL) {
-            /* drop datas were cached with inspectDropData call */
-            callPerformDragOperation(destView, info);
-        } else {
-            XDND_DROP_DATAS(info) = createDropDataArray(
-                                                        XDND_REQUIRED_TYPES(info));
-
-            /* store first available data */
-            if (requestDropData(info))
-                return waitForDropDataState;
-
-            /* no data retrieved */
-            callPerformDragOperation(destView, info);
-        }
-
-        finishDrop(destView, info);
-        return idleState;
-    }
-
-    if (sourceMsg == scr->xdndPositionAtom) {
-        if (XDND_SOURCE_ACTION_CHANGED(info)) {
-            return checkDropAllowed(destView, event, info);
-        } else {
-            sendStatusMessage(destView, info, XDND_DEST_ACTION(info));
-            return dropAllowedState;
-        }
-    }
-
-    return dropAllowedState;
-}
-
-
-static void*
-waitForDropDataState(WMView *destView, XClientMessageEvent *event,
-                     WMDraggingInfo *info)
-{
-    WMScreen *scr = W_VIEW_SCREEN(destView);
-    Atom sourceMsg = event->message_type;
-
-    if (sourceMsg == scr->xdndSelectionAtom) {
-        /* store next data */
-        if (requestDropData(info))
-            return waitForDropDataState;
-
-        /* all required (and available) datas are stored */
-        callPerformDragOperation(destView, info);
-
-        finishDrop(destView, info);
-        return idleState;
-    }
-
-    return waitForDropDataState;
-}
-
-/* ----- End of Destination states ----- */
-
-
-void
-W_DragDestinationStateHandler(WMDraggingInfo *info, XClientMessageEvent *event)
-{
-    WMView *destView;
-    W_DndState* newState;
-
-    wassertr(XDND_DEST_INFO(info) != NULL);
-    wassertr(XDND_DEST_VIEW(info) != NULL);
-
-    destView = XDND_DEST_VIEW(info);
-    if (XDND_DEST_STATE(info) == NULL)
-        XDND_DEST_STATE(info) = idleState;
-
-#ifdef XDND_DEBUG
-
-    printf("current dest state: %s\n",
-           stateName(XDND_DEST_STATE(info)));
-#endif
-
-    newState = (W_DndState*) XDND_DEST_STATE(info)(destView, event, info);
-
-#ifdef XDND_DEBUG
-
-    printf("new dest state: %s\n", stateName(newState));
-#endif
-
-    if (XDND_DEST_INFO(info) != NULL) {
-        XDND_DEST_STATE(info) = newState;
-        if (XDND_DEST_STATE(info) != idleState)
-            W_DragDestinationStartTimer(info);
-    }
-}
-
-
-static void
-realizedObserver(void *self, WMNotification *notif)
-{
-    WMView *view = (WMView*)WMGetNotificationObject(notif);
-    WMScreen *scr = W_VIEW_SCREEN(view);
-
-    XChangeProperty(scr->display, W_VIEW_DRAWABLE(view),
-                    scr->xdndAwareAtom,
-                    XA_ATOM, XDND_PROPERTY_FORMAT, PropModeReplace,
-                    &XDNDversion, 1);
-
-    WMRemoveNotificationObserver(self);
-}
-
-
-void
-W_SetXdndAwareProperty(WMScreen *scr, WMView *view, Atom *types,
-                       int typeCount)
-{
-    WMView *toplevel = W_TopLevelOfView(view);
-
-    if (!toplevel->flags.xdndHintSet) {
-        toplevel->flags.xdndHintSet = 1;
-
-        if (toplevel->flags.realized) {
-            XChangeProperty(scr->display, W_VIEW_DRAWABLE(toplevel),
-                            scr->xdndAwareAtom, XA_ATOM, XDND_PROPERTY_FORMAT,
-                            PropModeReplace, &XDNDversion, 1);
-        } else {
-            WMAddNotificationObserver(realizedObserver,
-                                      /* just use as an id */
-                                      &view->dragDestinationProcs,
-                                      WMViewRealizedNotification,
-                                      toplevel);
-        }
-    }
-}
-
-
-void
-WMRegisterViewForDraggedTypes(WMView *view, WMArray *acceptedTypes)
-{
-    Atom *types;
-    int typeCount;
-    int i;
-
-    typeCount = WMGetArrayItemCount(acceptedTypes);
-    types = wmalloc(sizeof(Atom)*(typeCount+1));
-
-    for (i = 0; i < typeCount; i++) {
-        types[i] = XInternAtom(W_VIEW_SCREEN(view)->display,
-                               WMGetFromArray(acceptedTypes, i),
-                               False);
-    }
-    types[i] = 0;
-
-    view->droppableTypes = types;
-    /* WMFreeArray(acceptedTypes); */
-
-    W_SetXdndAwareProperty(W_VIEW_SCREEN(view), view, types, typeCount);
-}
-
-
-void
-WMUnregisterViewDraggedTypes(WMView *view)
-{
-    if (view->droppableTypes != NULL)
-        wfree(view->droppableTypes);
-    view->droppableTypes = NULL;
-}
-
-
-/*
- requestedOperation: operation requested by the source
- sourceDataTypes:  data types (mime-types strings) supported by the source
- (never NULL, destroyed when drop ends)
- return operation allowed by destination (self)
- */
-static WMDragOperationType
-defAllowedOperation(WMView *self,
-                    WMDragOperationType requestedOperation,
-                    WMArray* sourceDataTypes)
-{
-    /* no operation allowed */
-    return WDOperationNone;
-}
-
-
-/*
- requestedOperation: operation requested by the source
- sourceDataTypes:  data types (mime-types strings) supported by the source
- (never NULL, destroyed when drop ends)
- return data types (mime-types strings) required by destination (self)
- or NULL if no suitable data type is available (force
- to 2nd pass with full source type list).
- */
-static WMArray*
-defRequiredDataTypes (WMView *self,
-                      WMDragOperationType requestedOperation,
-                      WMArray* sourceDataTypes)
-{
-    /* no data type allowed (NULL even at 2nd pass) */
-    return NULL;
-}
-
-
-/*
- Executed when the drag enters destination (self)
- */
-static void
-defPrepareForDragOperation(WMView *self)
-{
-}
-
-
-/*
- Checks datas to be dropped (optional).
- dropDatas: datas (WMData*) required by destination (self)
- (given in same order as returned by requiredDataTypes).
- A NULL data means it couldn't be retreived.
- Destroyed when drop ends.
- return true if data array is ok
- */
-/* Bool (*inspectDropData)(WMView *self, WMArray *dropDatas); */
-
-
-/*
- Process drop
- dropDatas: datas (WMData*) required by destination (self)
- (given in same order as returned by requiredDataTypes).
- A NULL data means it couldn't be retrieved.
- Destroyed when drop ends.
- operationList: if source operation is WDOperationAsk, contains
- operations (and associated texts) that can be asked
- to source. (destroyed after performDragOperation call)
- Otherwise this parameter is NULL.
- */
-static void
-defPerformDragOperation(WMView *self, WMArray *dropDatas,
-                        WMArray *operationList, WMPoint *dropLocation)
-{
-}
-
-
-/* Executed after drop */
-static void
-defConcludeDragOperation(WMView *self)
-{
-}
-
-
-void
-WMSetViewDragDestinationProcs(WMView *view, WMDragDestinationProcs *procs)
-{
-    if (view->dragDestinationProcs == NULL) {
-        view->dragDestinationProcs = wmalloc(sizeof(WMDragDestinationProcs));
-    } else {
-        free(view->dragDestinationProcs);
-    }
-
-    *view->dragDestinationProcs = *procs;
-
-    /*XXX fill in non-implemented stuffs */
-    if (procs->allowedOperation == NULL) {
-        view->dragDestinationProcs->allowedOperation = defAllowedOperation;
-    }
-    if (procs->allowedOperation == NULL) {
-        view->dragDestinationProcs->requiredDataTypes = defRequiredDataTypes;
-    }
-
-    /* note: inspectDropData can be NULL, if data consultation is not needed
-     to give drop permission */
-
-    if (procs->prepareForDragOperation == NULL) {
-        view->dragDestinationProcs->prepareForDragOperation = defPrepareForDragOperation;
-    }
-    if (procs->performDragOperation == NULL) {
-        view->dragDestinationProcs->performDragOperation = defPerformDragOperation;
-    }
-    if (procs->concludeDragOperation == NULL) {
-        view->dragDestinationProcs->concludeDragOperation = defConcludeDragOperation;
-    }
-}
-
-
+
+#include "WINGsP.h"
+#include <X11/Xatom.h>
+
+#define XDND_SOURCE_RESPONSE_MAX_DELAY 3000
+
+#define XDND_PROPERTY_FORMAT 32
+#define XDND_ACTION_DESCRIPTION_FORMAT 8
+
+#define XDND_SOURCE_VERSION(dragInfo) dragInfo->protocolVersion
+#define XDND_DEST_INFO(dragInfo) dragInfo->destInfo
+#define XDND_AWARE_VIEW(dragInfo) dragInfo->destInfo->xdndAwareView
+#define XDND_SOURCE_WIN(dragInfo) dragInfo->destInfo->sourceWindow
+#define XDND_DEST_VIEW(dragInfo) dragInfo->destInfo->destView
+#define XDND_DEST_STATE(dragInfo) dragInfo->destInfo->state
+#define XDND_SOURCE_ACTION_CHANGED(dragInfo) dragInfo->destInfo->sourceActionChanged
+#define XDND_SOURCE_TYPES(dragInfo) dragInfo->destInfo->sourceTypes
+#define XDND_TYPE_LIST_AVAILABLE(dragInfo) dragInfo->destInfo->typeListAvailable
+#define XDND_REQUIRED_TYPES(dragInfo) dragInfo->destInfo->requiredTypes
+#define XDND_SOURCE_ACTION(dragInfo) dragInfo->sourceAction
+#define XDND_DEST_ACTION(dragInfo) dragInfo->destinationAction
+#define XDND_SOURCE_OPERATIONS(dragInfo) dragInfo->destInfo->sourceOperations
+#define XDND_DROP_DATAS(dragInfo) dragInfo->destInfo->dropDatas
+#define XDND_DROP_DATA_COUNT(dragInfo) dragInfo->destInfo->dropDataCount
+#define XDND_DEST_VIEW_IS_REGISTERED(dragInfo) ((dragInfo->destInfo) != NULL)\
+    && ((dragInfo->destInfo->destView->dragDestinationProcs) != NULL)
+
+static unsigned char XDNDversion = XDND_VERSION;
+static WMHandlerID dndDestinationTimer = NULL;
+
+static void *idleState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info);
+static void *waitEnterState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info);
+static void *inspectDropDataState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info);
+static void *dropAllowedState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info);
+static void *dropNotAllowedState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info);
+static void *waitForDropDataState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info);
+
+/* ----- Types & datas list ----- */
+static void freeSourceTypeArrayItem(void *type)
+{
+       XFree(type);
+}
+
+static WMArray *createSourceTypeArray(int initialSize)
+{
+       return WMCreateArrayWithDestructor(initialSize, freeSourceTypeArrayItem);
+}
+
+static void freeDropDataArrayItem(void *data)
+{
+       if (data != NULL)
+               WMReleaseData((WMData *) data);
+}
+
+static WMArray *createDropDataArray(WMArray * requiredTypes)
+{
+       if (requiredTypes != NULL)
+               return WMCreateArrayWithDestructor(WMGetArrayItemCount(requiredTypes), freeDropDataArrayItem);
+
+       else
+               return WMCreateArray(0);
+}
+
+static WMArray *getTypesFromTypeList(WMScreen * scr, Window sourceWin)
+{
+       Atom dataType;
+       Atom *typeAtomList;
+       WMArray *typeList;
+       int i, format;
+       unsigned long count, remaining;
+       unsigned char *data = NULL;
+
+       XGetWindowProperty(scr->display, sourceWin, scr->xdndTypeListAtom,
+                          0, 0x8000000L, False, XA_ATOM, &dataType, &format, &count, &remaining, &data);
+
+       if (dataType != XA_ATOM || format != XDND_PROPERTY_FORMAT || count == 0 || !data) {
+               if (data) {
+                       XFree(data);
+               }
+               return createSourceTypeArray(0);
+       }
+
+       typeList = createSourceTypeArray(count);
+       typeAtomList = (Atom *) data;
+       for (i = 0; i < count; i++) {
+               WMAddToArray(typeList, XGetAtomName(scr->display, typeAtomList[i]));
+       }
+
+       XFree(data);
+
+       return typeList;
+}
+
+static WMArray *getTypesFromThreeTypes(WMScreen * scr, XClientMessageEvent * event)
+{
+       WMArray *typeList;
+       Atom atom;
+       int i;
+
+       typeList = createSourceTypeArray(3);
+       for (i = 2; i < 5; i++) {
+               if (event->data.l[i] != None) {
+                       atom = (Atom) event->data.l[i];
+                       WMAddToArray(typeList, XGetAtomName(scr->display, atom));
+               }
+       }
+
+       return typeList;
+}
+
+void storeRequiredTypeList(WMDraggingInfo * info)
+{
+       WMView *destView = XDND_DEST_VIEW(info);
+       WMScreen *scr = W_VIEW_SCREEN(destView);
+       WMArray *requiredTypes;
+
+       /* First, see if the stored source types are enough for dest requirements */
+       requiredTypes = destView->dragDestinationProcs->requiredDataTypes(destView,
+                                                                         W_ActionToOperation(scr,
+                                                                                             XDND_SOURCE_ACTION
+                                                                                             (info)),
+                                                                         XDND_SOURCE_TYPES(info));
+
+       if (requiredTypes == NULL && XDND_TYPE_LIST_AVAILABLE(info)) {
+               /* None of the stored source types fits, but the whole type list
+                  hasn't been retrieved yet. */
+               WMFreeArray(XDND_SOURCE_TYPES(info));
+               XDND_SOURCE_TYPES(info) = getTypesFromTypeList(scr, XDND_SOURCE_WIN(info));
+               /* Don't retrieve the type list again */
+               XDND_TYPE_LIST_AVAILABLE(info) = False;
+
+               requiredTypes =
+                   destView->dragDestinationProcs->requiredDataTypes(destView,
+                                                                     W_ActionToOperation(scr,
+                                                                                         XDND_SOURCE_ACTION
+                                                                                         (info)),
+                                                                     XDND_SOURCE_TYPES(info));
+       }
+
+       XDND_REQUIRED_TYPES(info) = requiredTypes;
+}
+
+char *getNextRequestedDataType(WMDraggingInfo * info)
+{
+       /* get the type of the first data not yet retrieved from selection */
+       int nextTypeIndex;
+
+       if (XDND_REQUIRED_TYPES(info) != NULL) {
+               nextTypeIndex = WMGetArrayItemCount(XDND_DROP_DATAS(info));
+               return WMGetFromArray(XDND_REQUIRED_TYPES(info), nextTypeIndex);
+               /* NULL if no more type */
+       } else
+               return NULL;
+}
+
+/* ----- Action list ----- */
+
+WMArray *sourceOperationList(WMScreen * scr, Window sourceWin)
+{
+       Atom dataType, *actionList;
+       int i, size;
+       unsigned long count, remaining;
+       unsigned char *actionDatas = NULL;
+       unsigned char *descriptionList = NULL;
+       WMArray *operationArray;
+       WMDragOperationItem *operationItem;
+       char *description;
+
+       remaining = 0;
+       XGetWindowProperty(scr->display, sourceWin, scr->xdndActionListAtom,
+                          0, 0x8000000L, False, XA_ATOM, &dataType, &size, &count, &remaining, &actionDatas);
+
+       if (dataType != XA_ATOM || size != XDND_PROPERTY_FORMAT || count == 0 || !actionDatas) {
+               wwarning("Cannot read action list");
+               if (actionDatas) {
+                       XFree(actionDatas);
+               }
+               return NULL;
+       }
+
+       actionList = (Atom *) actionDatas;
+
+       XGetWindowProperty(scr->display, sourceWin, scr->xdndActionDescriptionAtom,
+                          0, 0x8000000L, False, XA_STRING, &dataType, &size,
+                          &count, &remaining, &descriptionList);
+
+       if (dataType != XA_STRING || size != XDND_ACTION_DESCRIPTION_FORMAT || count == 0 || !descriptionList) {
+               wwarning("Cannot read action description list");
+               if (actionList) {
+                       XFree(actionList);
+               }
+               if (descriptionList) {
+                       XFree(descriptionList);
+               }
+               return NULL;
+       }
+
+       operationArray = WMCreateDragOperationArray(count);
+       description = (char *)descriptionList;
+
+       for (i = 0; count > 0; i++) {
+               size = strlen(description);
+               operationItem = WMCreateDragOperationItem(W_ActionToOperation(scr, actionList[i]),
+                                                         wstrdup(description));
+
+               WMAddToArray(operationArray, operationItem);
+               count -= (size + 1);    /* -1 : -NULL char */
+
+               /* next description */
+               description = &(description[size + 1]);
+       }
+
+       XFree(actionList);
+       XFree(descriptionList);
+
+       return operationArray;
+}
+
+/* ----- Dragging Info ----- */
+static void updateSourceWindow(WMDraggingInfo * info, XClientMessageEvent * event)
+{
+       XDND_SOURCE_WIN(info) = (Window) event->data.l[0];
+}
+
+static WMView *findChildInView(WMView * parent, int x, int y)
+{
+       if (parent->childrenList == NULL)
+               return parent;
+       else {
+               WMView *child = parent->childrenList;
+
+               while (child != NULL
+                      && (!child->flags.mapped
+                          || x < WMGetViewPosition(child).x
+                          || x > WMGetViewPosition(child).x + WMGetViewSize(child).width
+                          || y < WMGetViewPosition(child).y
+                          || y > WMGetViewPosition(child).y + WMGetViewSize(child).height))
+
+                       child = child->nextSister;
+
+               if (child == NULL)
+                       return parent;
+               else
+                       return findChildInView(child,
+                                              x - WMGetViewPosition(child).x, y - WMGetViewPosition(child).y);
+       }
+}
+
+static WMView *findDestinationViewInToplevel(WMView * toplevel, int x, int y)
+{
+       WMScreen *scr = W_VIEW_SCREEN(toplevel);
+       Window toplevelWin = WMViewXID(toplevel);
+       int xInToplevel, yInToplevel;
+       Window foo;
+
+       XTranslateCoordinates(scr->display, scr->rootWin, toplevelWin, x, y, &xInToplevel, &yInToplevel, &foo);
+       return findChildInView(toplevel, xInToplevel, yInToplevel);
+}
+
+/* Clear datas only used by current destination view */
+static void freeDestinationViewInfos(WMDraggingInfo * info)
+{
+       if (XDND_SOURCE_TYPES(info) != NULL) {
+               WMFreeArray(XDND_SOURCE_TYPES(info));
+               XDND_SOURCE_TYPES(info) = NULL;
+       }
+
+       if (XDND_DROP_DATAS(info) != NULL) {
+               WMFreeArray(XDND_DROP_DATAS(info));
+               XDND_DROP_DATAS(info) = NULL;
+       }
+
+       XDND_REQUIRED_TYPES(info) = NULL;
+}
+
+void W_DragDestinationInfoClear(WMDraggingInfo * info)
+{
+       W_DragDestinationStopTimer();
+
+       if (XDND_DEST_INFO(info) != NULL) {
+               freeDestinationViewInfos(info);
+
+               wfree(XDND_DEST_INFO(info));
+               XDND_DEST_INFO(info) = NULL;
+       }
+}
+
+static void initDestinationDragInfo(WMDraggingInfo * info, WMView * destView)
+{
+       wassertr(destView != NULL);
+
+       XDND_DEST_INFO(info) = (W_DragDestinationInfo *) wmalloc(sizeof(W_DragDestinationInfo));
+
+       XDND_DEST_STATE(info) = idleState;
+       XDND_DEST_VIEW(info) = destView;
+
+       XDND_SOURCE_ACTION_CHANGED(info) = False;
+       XDND_SOURCE_TYPES(info) = NULL;
+       XDND_REQUIRED_TYPES(info) = NULL;
+       XDND_DROP_DATAS(info) = NULL;
+}
+
+void W_DragDestinationStoreEnterMsgInfo(WMDraggingInfo * info, WMView * toplevel, XClientMessageEvent * event)
+{
+       WMScreen *scr = W_VIEW_SCREEN(toplevel);
+
+       if (XDND_DEST_INFO(info) == NULL)
+               initDestinationDragInfo(info, toplevel);
+
+       XDND_SOURCE_VERSION(info) = (event->data.l[1] >> 24);
+       XDND_AWARE_VIEW(info) = toplevel;
+       updateSourceWindow(info, event);
+
+/*
+    if (event->data.l[1] & 1)
+        /* XdndTypeList property is available */
+/*        XDND_SOURCE_TYPES(info) = getTypesFromTypeList(scr, XDND_SOURCE_WIN(info));
+    else
+        XDND_SOURCE_TYPES(info) = getTypesFromThreeTypes(scr, event);
+*/
+       XDND_SOURCE_TYPES(info) = getTypesFromThreeTypes(scr, event);
+
+       /* to use if the 3 types are not enough */
+       XDND_TYPE_LIST_AVAILABLE(info) = (event->data.l[1] & 1);
+}
+
+void W_DragDestinationStorePositionMsgInfo(WMDraggingInfo * info, WMView * toplevel, XClientMessageEvent * event)
+{
+       int x = event->data.l[2] >> 16;
+       int y = event->data.l[2] & 0xffff;
+       WMView *newDestView;
+
+       newDestView = findDestinationViewInToplevel(toplevel, x, y);
+
+       if (XDND_DEST_INFO(info) == NULL) {
+               initDestinationDragInfo(info, newDestView);
+               XDND_AWARE_VIEW(info) = toplevel;
+               updateSourceWindow(info, event);
+       } else {
+               if (newDestView != XDND_DEST_VIEW(info)) {
+                       updateSourceWindow(info, event);
+                       XDND_DEST_VIEW(info) = newDestView;
+                       XDND_SOURCE_ACTION_CHANGED(info) = False;
+
+                       if (XDND_DEST_STATE(info) != waitEnterState)
+                               XDND_DEST_STATE(info) = idleState;
+               } else {
+                       XDND_SOURCE_ACTION_CHANGED(info) = (XDND_SOURCE_ACTION(info) != event->data.l[4]);
+               }
+       }
+
+       XDND_SOURCE_ACTION(info) = event->data.l[4];
+
+       /* note: source position is not stored */
+}
+
+/* ----- End of Dragging Info ----- */
+
+/* ----- Messages ----- */
+
+/* send a DnD message to the source window */
+static void
+sendDnDClientMessage(WMDraggingInfo * info, Atom message,
+                    unsigned long data1, unsigned long data2, unsigned long data3, unsigned long data4)
+{
+       if (!W_SendDnDClientMessage(W_VIEW_SCREEN(XDND_AWARE_VIEW(info))->display,
+                                   XDND_SOURCE_WIN(info),
+                                   message, WMViewXID(XDND_AWARE_VIEW(info)), data1, data2, data3, data4)) {
+               /* drop failed */
+               W_DragDestinationInfoClear(info);
+       }
+}
+
+/* send a xdndStatus message to the source, with position and size
+   of the destination if it has no subwidget (requesting a position message
+   on every move otherwise) */
+static void sendStatusMessage(WMView * destView, WMDraggingInfo * info, Atom action)
+{
+       unsigned long data1;
+
+       data1 = (action == None) ? 0 : 1;
+
+       if (destView->childrenList == NULL) {
+               WMScreen *scr = W_VIEW_SCREEN(destView);
+               int destX, destY;
+               WMSize destSize = WMGetViewSize(destView);
+               Window foo;
+
+               XTranslateCoordinates(scr->display, WMViewXID(destView), scr->rootWin, 0, 0, &destX, &destY, &foo);
+
+               sendDnDClientMessage(info,
+                                    W_VIEW_SCREEN(destView)->xdndStatusAtom,
+                                    data1,
+                                    (destX << 16) | destY, (destSize.width << 16) | destSize.height, action);
+       } else {
+               /* set bit 1 to request explicitly position message on every move */
+               data1 = data1 | 2;
+
+               sendDnDClientMessage(info, W_VIEW_SCREEN(destView)->xdndStatusAtom, data1, 0, 0, action);
+       }
+}
+
+static void
+storeDropData(WMView * destView, Atom selection, Atom target, Time timestamp, void *cdata, WMData * data)
+{
+       WMScreen *scr = W_VIEW_SCREEN(destView);
+       WMDraggingInfo *info = &(scr->dragInfo);
+       WMData *dataToStore = NULL;
+
+       if (data != NULL)
+               dataToStore = WMRetainData(data);
+
+       if (XDND_DEST_INFO(info) != NULL && XDND_DROP_DATAS(info) != NULL) {
+               WMAddToArray(XDND_DROP_DATAS(info), dataToStore);
+               W_SendDnDClientMessage(scr->display, WMViewXID(destView),
+                                      scr->xdndSelectionAtom, WMViewXID(destView), 0, 0, 0, 0);
+       }
+}
+
+Bool requestDropDataInSelection(WMView * destView, char *type)
+{
+       WMScreen *scr = W_VIEW_SCREEN(destView);
+
+       if (type != NULL) {
+               if (!WMRequestSelection(destView,
+                                       scr->xdndSelectionAtom,
+                                       XInternAtom(scr->display, type, False),
+                                       CurrentTime, storeDropData, NULL)) {
+                       wwarning("could not request data for dropped data");
+                       return False;
+               }
+
+               return True;
+       }
+
+       return False;
+}
+
+Bool requestDropData(WMDraggingInfo * info)
+{
+       WMView *destView = XDND_DEST_VIEW(info);
+       char *nextType = getNextRequestedDataType(info);
+
+       while ((nextType != NULL)
+              && (!requestDropDataInSelection(destView, nextType))) {
+               /* store NULL if request failed, and try with next type */
+               WMAddToArray(XDND_DROP_DATAS(info), NULL);
+               nextType = getNextRequestedDataType(info);
+       }
+
+       /* remains types to retrieve ? */
+       return (nextType != NULL);
+}
+
+static void concludeDrop(WMView * destView)
+{
+       destView->dragDestinationProcs->concludeDragOperation(destView);
+}
+
+/* send cancel message to the source */
+static void cancelDrop(WMView * destView, WMDraggingInfo * info)
+{
+       sendStatusMessage(destView, info, None);
+       concludeDrop(destView);
+       freeDestinationViewInfos(info);
+}
+
+/* suspend drop, when dragged icon enter an unregistered view
+   or a register view that doesn't accept the drop */
+static void suspendDropAuthorization(WMView * destView, WMDraggingInfo * info)
+{
+       sendStatusMessage(destView, info, None);
+
+       /* Free datas that depend on destination behaviour */
+       if (XDND_DROP_DATAS(info) != NULL) {
+               WMFreeArray(XDND_DROP_DATAS(info));
+               XDND_DROP_DATAS(info) = NULL;
+       }
+
+       XDND_REQUIRED_TYPES(info) = NULL;
+}
+
+/* cancel drop on Enter message, if protocol version is nok */
+void W_DragDestinationCancelDropOnEnter(WMView * toplevel, WMDraggingInfo * info)
+{
+       if (XDND_DEST_VIEW_IS_REGISTERED(info))
+               cancelDrop(XDND_DEST_VIEW(info), info);
+       else
+               sendStatusMessage(toplevel, info, None);
+
+       W_DragDestinationInfoClear(info);
+}
+
+static void finishDrop(WMView * destView, WMDraggingInfo * info)
+{
+       sendDnDClientMessage(info, W_VIEW_SCREEN(destView)->xdndFinishedAtom, 0, 0, 0, 0);
+       concludeDrop(destView);
+       W_DragDestinationInfoClear(info);
+}
+
+static Atom getAllowedAction(WMView * destView, WMDraggingInfo * info)
+{
+       WMScreen *scr = W_VIEW_SCREEN(destView);
+
+       return W_OperationToAction(scr,
+                                  destView->dragDestinationProcs->allowedOperation(destView,
+                                                                                   W_ActionToOperation(scr,
+                                                                                                       XDND_SOURCE_ACTION
+                                                                                                       (info)),
+                                                                                   XDND_SOURCE_TYPES(info)));
+}
+
+static void *checkActionAllowed(WMView * destView, WMDraggingInfo * info)
+{
+       XDND_DEST_ACTION(info) = getAllowedAction(destView, info);
+
+       if (XDND_DEST_ACTION(info) == None) {
+               suspendDropAuthorization(destView, info);
+               return dropNotAllowedState;
+       }
+
+       sendStatusMessage(destView, info, XDND_DEST_ACTION(info));
+       return dropAllowedState;
+}
+
+static void *checkDropAllowed(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info)
+{
+       storeRequiredTypeList(info);
+
+       if (destView->dragDestinationProcs->inspectDropData != NULL) {
+               XDND_DROP_DATAS(info) = createDropDataArray(XDND_REQUIRED_TYPES(info));
+
+               /* store first available data */
+               if (requestDropData(info))
+                       return inspectDropDataState;
+
+               /* no data retrieved, but inspect can allow it */
+               if (destView->dragDestinationProcs->inspectDropData(destView, XDND_DROP_DATAS(info)))
+                       return checkActionAllowed(destView, info);
+
+               suspendDropAuthorization(destView, info);
+               return dropNotAllowedState;
+       }
+
+       return checkActionAllowed(destView, info);
+}
+
+static WMPoint *getDropLocationInView(WMView * view)
+{
+       Window rootWin, childWin;
+       int rootX, rootY;
+       unsigned int mask;
+       WMPoint *location;
+
+       location = (WMPoint *) wmalloc(sizeof(WMPoint));
+
+       XQueryPointer(W_VIEW_SCREEN(view)->display,
+                     WMViewXID(view), &rootWin, &childWin, &rootX, &rootY, &(location->x), &(location->y), &mask);
+
+       return location;
+}
+
+static void callPerformDragOperation(WMView * destView, WMDraggingInfo * info)
+{
+       WMArray *operationList = NULL;
+       WMScreen *scr = W_VIEW_SCREEN(destView);
+       WMPoint *dropLocation;
+
+       if (XDND_SOURCE_ACTION(info) == scr->xdndActionAsk)
+               operationList = sourceOperationList(scr, XDND_SOURCE_WIN(info));
+
+       dropLocation = getDropLocationInView(destView);
+       destView->dragDestinationProcs->performDragOperation(destView,
+                                                            XDND_DROP_DATAS(info), operationList, dropLocation);
+
+       wfree(dropLocation);
+       if (operationList != NULL)
+               WMFreeArray(operationList);
+}
+
+/* ----- Destination timer ----- */
+static void dragSourceResponseTimeOut(void *destView)
+{
+       WMView *view = (WMView *) destView;
+       WMDraggingInfo *info;
+
+       wwarning("delay for drag source response expired");
+       info = &(W_VIEW_SCREEN(view)->dragInfo);
+       if (XDND_DEST_VIEW_IS_REGISTERED(info))
+               cancelDrop(view, info);
+       else {
+               sendStatusMessage(view, info, None);
+       }
+
+       W_DragDestinationInfoClear(info);
+}
+
+void W_DragDestinationStopTimer()
+{
+       if (dndDestinationTimer != NULL) {
+               WMDeleteTimerHandler(dndDestinationTimer);
+               dndDestinationTimer = NULL;
+       }
+}
+
+void W_DragDestinationStartTimer(WMDraggingInfo * info)
+{
+       W_DragDestinationStopTimer();
+
+       if (XDND_DEST_STATE(info) != idleState)
+               dndDestinationTimer = WMAddTimerHandler(XDND_SOURCE_RESPONSE_MAX_DELAY,
+                                                       dragSourceResponseTimeOut, XDND_DEST_VIEW(info));
+}
+
+/* ----- End of Destination timer ----- */
+
+/* ----- Destination states ----- */
+
+#ifdef XDND_DEBUG
+static const char *stateName(W_DndState * state)
+{
+       if (state == NULL)
+               return "no state defined";
+
+       if (state == idleState)
+               return "idleState";
+
+       if (state == waitEnterState)
+               return "waitEnterState";
+
+       if (state == inspectDropDataState)
+               return "inspectDropDataState";
+
+       if (state == dropAllowedState)
+               return "dropAllowedState";
+
+       if (state == dropNotAllowedState)
+               return "dropNotAllowedState";
+
+       if (state == waitForDropDataState)
+               return "waitForDropDataState";
+
+       return "unknown state";
+}
+#endif
+
+static void *idleState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info)
+{
+       WMScreen *scr;
+       Atom sourceMsg;
+
+       if (destView->dragDestinationProcs != NULL) {
+               scr = W_VIEW_SCREEN(destView);
+               sourceMsg = event->message_type;
+
+               if (sourceMsg == scr->xdndPositionAtom) {
+                       destView->dragDestinationProcs->prepareForDragOperation(destView);
+
+                       if (XDND_SOURCE_TYPES(info) != NULL) {
+                               /* enter message infos are available */
+                               return checkDropAllowed(destView, event, info);
+                       }
+
+                       /* waiting for enter message */
+                       return waitEnterState;
+               }
+       }
+
+       suspendDropAuthorization(destView, info);
+       return idleState;
+}
+
+/*  Source position and action are stored,
+ waiting for xdnd protocol version and source type */
+static void *waitEnterState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info)
+{
+       WMScreen *scr = W_VIEW_SCREEN(destView);
+       Atom sourceMsg = event->message_type;
+
+       if (sourceMsg == scr->xdndEnterAtom) {
+               W_DragDestinationStoreEnterMsgInfo(info, destView, event);
+               return checkDropAllowed(destView, event, info);
+       }
+
+       return waitEnterState;
+}
+
+/* We have requested a data, and have received it */
+static void *inspectDropDataState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info)
+{
+       WMScreen *scr;
+       Atom sourceMsg;
+
+       scr = W_VIEW_SCREEN(destView);
+       sourceMsg = event->message_type;
+
+       if (sourceMsg == scr->xdndSelectionAtom) {
+               /* a data has been retrieved, store next available */
+               if (requestDropData(info))
+                       return inspectDropDataState;
+
+               /* all required (and available) datas are stored */
+               if (destView->dragDestinationProcs->inspectDropData(destView, XDND_DROP_DATAS(info)))
+                       return checkActionAllowed(destView, info);
+
+               suspendDropAuthorization(destView, info);
+               return dropNotAllowedState;
+       }
+
+       return inspectDropDataState;
+}
+
+static void *dropNotAllowedState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info)
+{
+       WMScreen *scr = W_VIEW_SCREEN(destView);
+       Atom sourceMsg = event->message_type;
+
+       if (sourceMsg == scr->xdndDropAtom) {
+               finishDrop(destView, info);
+               return idleState;
+       }
+
+       if (sourceMsg == scr->xdndPositionAtom) {
+               if (XDND_SOURCE_ACTION_CHANGED(info)) {
+                       return checkDropAllowed(destView, event, info);
+               } else {
+                       sendStatusMessage(destView, info, None);
+                       return dropNotAllowedState;
+               }
+       }
+
+       return dropNotAllowedState;
+}
+
+static void *dropAllowedState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info)
+{
+       WMScreen *scr = W_VIEW_SCREEN(destView);
+       Atom sourceMsg = event->message_type;
+
+       if (sourceMsg == scr->xdndDropAtom) {
+               if (XDND_DROP_DATAS(info) != NULL) {
+                       /* drop datas were cached with inspectDropData call */
+                       callPerformDragOperation(destView, info);
+               } else {
+                       XDND_DROP_DATAS(info) = createDropDataArray(XDND_REQUIRED_TYPES(info));
+
+                       /* store first available data */
+                       if (requestDropData(info))
+                               return waitForDropDataState;
+
+                       /* no data retrieved */
+                       callPerformDragOperation(destView, info);
+               }
+
+               finishDrop(destView, info);
+               return idleState;
+       }
+
+       if (sourceMsg == scr->xdndPositionAtom) {
+               if (XDND_SOURCE_ACTION_CHANGED(info)) {
+                       return checkDropAllowed(destView, event, info);
+               } else {
+                       sendStatusMessage(destView, info, XDND_DEST_ACTION(info));
+                       return dropAllowedState;
+               }
+       }
+
+       return dropAllowedState;
+}
+
+static void *waitForDropDataState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info)
+{
+       WMScreen *scr = W_VIEW_SCREEN(destView);
+       Atom sourceMsg = event->message_type;
+
+       if (sourceMsg == scr->xdndSelectionAtom) {
+               /* store next data */
+               if (requestDropData(info))
+                       return waitForDropDataState;
+
+               /* all required (and available) datas are stored */
+               callPerformDragOperation(destView, info);
+
+               finishDrop(destView, info);
+               return idleState;
+       }
+
+       return waitForDropDataState;
+}
+
+/* ----- End of Destination states ----- */
+
+void W_DragDestinationStateHandler(WMDraggingInfo * info, XClientMessageEvent * event)
+{
+       WMView *destView;
+       W_DndState *newState;
+
+       wassertr(XDND_DEST_INFO(info) != NULL);
+       wassertr(XDND_DEST_VIEW(info) != NULL);
+
+       destView = XDND_DEST_VIEW(info);
+       if (XDND_DEST_STATE(info) == NULL)
+               XDND_DEST_STATE(info) = idleState;
+
+#ifdef XDND_DEBUG
+
+       printf("current dest state: %s\n", stateName(XDND_DEST_STATE(info)));
+#endif
+
+       newState = (W_DndState *) XDND_DEST_STATE(info) (destView, event, info);
+
+#ifdef XDND_DEBUG
+
+       printf("new dest state: %s\n", stateName(newState));
+#endif
+
+       if (XDND_DEST_INFO(info) != NULL) {
+               XDND_DEST_STATE(info) = newState;
+               if (XDND_DEST_STATE(info) != idleState)
+                       W_DragDestinationStartTimer(info);
+       }
+}
+
+static void realizedObserver(void *self, WMNotification * notif)
+{
+       WMView *view = (WMView *) WMGetNotificationObject(notif);
+       WMScreen *scr = W_VIEW_SCREEN(view);
+
+       XChangeProperty(scr->display, W_VIEW_DRAWABLE(view),
+                       scr->xdndAwareAtom, XA_ATOM, XDND_PROPERTY_FORMAT, PropModeReplace, &XDNDversion, 1);
+
+       WMRemoveNotificationObserver(self);
+}
+
+void W_SetXdndAwareProperty(WMScreen * scr, WMView * view, Atom * types, int typeCount)
+{
+       WMView *toplevel = W_TopLevelOfView(view);
+
+       if (!toplevel->flags.xdndHintSet) {
+               toplevel->flags.xdndHintSet = 1;
+
+               if (toplevel->flags.realized) {
+                       XChangeProperty(scr->display, W_VIEW_DRAWABLE(toplevel),
+                                       scr->xdndAwareAtom, XA_ATOM, XDND_PROPERTY_FORMAT,
+                                       PropModeReplace, &XDNDversion, 1);
+               } else {
+                       WMAddNotificationObserver(realizedObserver,
+                                                 /* just use as an id */
+                                                 &view->dragDestinationProcs,
+                                                 WMViewRealizedNotification, toplevel);
+               }
+       }
+}
+
+void WMRegisterViewForDraggedTypes(WMView * view, WMArray * acceptedTypes)
+{
+       Atom *types;
+       int typeCount;
+       int i;
+
+       typeCount = WMGetArrayItemCount(acceptedTypes);
+       types = wmalloc(sizeof(Atom) * (typeCount + 1));
+
+       for (i = 0; i < typeCount; i++) {
+               types[i] = XInternAtom(W_VIEW_SCREEN(view)->display, WMGetFromArray(acceptedTypes, i), False);
+       }
+       types[i] = 0;
+
+       view->droppableTypes = types;
+       /* WMFreeArray(acceptedTypes); */
+
+       W_SetXdndAwareProperty(W_VIEW_SCREEN(view), view, types, typeCount);
+}
+
+void WMUnregisterViewDraggedTypes(WMView * view)
+{
+       if (view->droppableTypes != NULL)
+               wfree(view->droppableTypes);
+       view->droppableTypes = NULL;
+}
+
+/*
+ requestedOperation: operation requested by the source
+ sourceDataTypes:  data types (mime-types strings) supported by the source
+ (never NULL, destroyed when drop ends)
+ return operation allowed by destination (self)
+ */
+static WMDragOperationType
+defAllowedOperation(WMView * self, WMDragOperationType requestedOperation, WMArray * sourceDataTypes)
+{
+       /* no operation allowed */
+       return WDOperationNone;
+}
+
+/*
+ requestedOperation: operation requested by the source
+ sourceDataTypes:  data types (mime-types strings) supported by the source
+ (never NULL, destroyed when drop ends)
+ return data types (mime-types strings) required by destination (self)
+ or NULL if no suitable data type is available (force
+ to 2nd pass with full source type list).
+ */
+static WMArray *defRequiredDataTypes(WMView * self,
+                                    WMDragOperationType requestedOperation, WMArray * sourceDataTypes)
+{
+       /* no data type allowed (NULL even at 2nd pass) */
+       return NULL;
+}
+
+/*
+ Executed when the drag enters destination (self)
+ */
+static void defPrepareForDragOperation(WMView * self)
+{
+}
+
+/*
+ Checks datas to be dropped (optional).
+ dropDatas: datas (WMData*) required by destination (self)
+ (given in same order as returned by requiredDataTypes).
+ A NULL data means it couldn't be retreived.
+ Destroyed when drop ends.
+ return true if data array is ok
+ */
+/* Bool (*inspectDropData)(WMView *self, WMArray *dropDatas); */
+
+/*
+ Process drop
+ dropDatas: datas (WMData*) required by destination (self)
+ (given in same order as returned by requiredDataTypes).
+ A NULL data means it couldn't be retrieved.
+ Destroyed when drop ends.
+ operationList: if source operation is WDOperationAsk, contains
+ operations (and associated texts) that can be asked
+ to source. (destroyed after performDragOperation call)
+ Otherwise this parameter is NULL.
+ */
+static void
+defPerformDragOperation(WMView * self, WMArray * dropDatas, WMArray * operationList, WMPoint * dropLocation)
+{
+}
+
+/* Executed after drop */
+static void defConcludeDragOperation(WMView * self)
+{
+}
+
+void WMSetViewDragDestinationProcs(WMView * view, WMDragDestinationProcs * procs)
+{
+       if (view->dragDestinationProcs == NULL) {
+               view->dragDestinationProcs = wmalloc(sizeof(WMDragDestinationProcs));
+       } else {
+               free(view->dragDestinationProcs);
+       }
+
+       *view->dragDestinationProcs = *procs;
+
+       /*XXX fill in non-implemented stuffs */
+       if (procs->allowedOperation == NULL) {
+               view->dragDestinationProcs->allowedOperation = defAllowedOperation;
+       }
+       if (procs->allowedOperation == NULL) {
+               view->dragDestinationProcs->requiredDataTypes = defRequiredDataTypes;
+       }
+
+       /* note: inspectDropData can be NULL, if data consultation is not needed
+          to give drop permission */
+
+       if (procs->prepareForDragOperation == NULL) {
+               view->dragDestinationProcs->prepareForDragOperation = defPrepareForDragOperation;
+       }
+       if (procs->performDragOperation == NULL) {
+               view->dragDestinationProcs->performDragOperation = defPerformDragOperation;
+       }
+       if (procs->concludeDragOperation == NULL) {
+               view->dragDestinationProcs->concludeDragOperation = defConcludeDragOperation;
+       }
+}