Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / dragsource.c
dissimilarity index 90%
index 04baa23..eea0ef5 100644 (file)
-
-
-#include "wconfig.h"
-#include "WINGsP.h"
-
-#include <X11/Xatom.h>
-#include <X11/cursorfont.h>
-#ifdef SHAPE
-#include <X11/extensions/shape.h>
-#endif
-
-
-
-#define XDND_DESTINATION_RESPONSE_MAX_DELAY 10000
-#define MIN_X_MOVE_OFFSET 5
-#define MIN_Y_MOVE_OFFSET 5
-#define MAX_SLIDEBACK_ITER 15
-
-#define XDND_PROPERTY_FORMAT 32
-#define XDND_ACTION_DESCRIPTION_FORMAT 8
-
-#define XDND_DEST_VERSION(dragInfo) dragInfo->protocolVersion
-#define XDND_SOURCE_INFO(dragInfo) dragInfo->sourceInfo
-#define XDND_DEST_WIN(dragInfo) dragInfo->sourceInfo->destinationWindow
-#define XDND_SOURCE_ACTION(dragInfo) dragInfo->sourceAction
-#define XDND_DEST_ACTION(dragInfo) dragInfo->destinationAction
-#define XDND_SOURCE_VIEW(dragInfo) dragInfo->sourceInfo->sourceView
-#define XDND_SOURCE_STATE(dragInfo) dragInfo->sourceInfo->state
-#define XDND_SELECTION_PROCS(dragInfo) dragInfo->sourceInfo->selectionProcs
-#define XDND_DRAG_ICON(dragInfo) dragInfo->sourceInfo->icon
-#define XDND_MOUSE_OFFSET(dragInfo) dragInfo->sourceInfo->mouseOffset
-#define XDND_DRAG_CURSOR(dragInfo) dragInfo->sourceInfo->dragCursor
-#define XDND_DRAG_ICON_POS(dragInfo) dragInfo->sourceInfo->imageLocation
-#define XDND_NO_POS_ZONE(dragInfo) dragInfo->sourceInfo->noPositionMessageZone
-#define XDND_TIMESTAMP(dragInfo) dragInfo->timestamp
-#define XDND_3_TYPES(dragInfo) dragInfo->sourceInfo->firstThreeTypes
-#define XDND_SOURCE_VIEW_STORED(dragInfo) dragInfo->sourceInfo != NULL \
-    && dragInfo->sourceInfo->sourceView != NULL
-
-
-static WMHandlerID dndSourceTimer = NULL;
-
-
-static void* idleState(WMView *srcView, XClientMessageEvent *event,
-                       WMDraggingInfo *info);
-static void* dropAllowedState(WMView *srcView, XClientMessageEvent *event,
-                              WMDraggingInfo *info);
-static void* finishDropState(WMView *srcView, XClientMessageEvent *event,
-                             WMDraggingInfo *info);
-
-#ifdef XDND_DEBUG
-static const char*
-stateName(W_DndState *state)
-{
-    if (state == NULL)
-        return "no state defined";
-
-    if (state == idleState)
-        return "idleState";
-
-    if (state == dropAllowedState)
-        return "dropAllowedState";
-
-    if (state == finishDropState)
-        return "finishDropState";
-
-    return "unknown state";
-}
-#endif
-
-
-static WMScreen*
-sourceScreen(WMDraggingInfo *info)
-{
-    return W_VIEW_SCREEN(XDND_SOURCE_VIEW(info));
-}
-
-
-static void
-endDragProcess(WMDraggingInfo *info, Bool deposited)
-{
-    WMView *view = XDND_SOURCE_VIEW(info);
-    WMScreen *scr = W_VIEW_SCREEN(XDND_SOURCE_VIEW(info));
-
-    /* free selection handler while view exists */
-    WMDeleteSelectionHandler(view,
-                             scr->xdndSelectionAtom,
-                             CurrentTime);
-    wfree(XDND_SELECTION_PROCS(info));
-
-    if (XDND_DRAG_CURSOR(info) != None) {
-        XFreeCursor(scr->display,
-                    XDND_DRAG_CURSOR(info));
-        XDND_DRAG_CURSOR(info) = None;
-    }
-
-    if (view->dragSourceProcs->endedDrag != NULL) {
-        /* this can destroy source view (with a "move" action for example) */
-        view->dragSourceProcs->endedDrag(view, &XDND_DRAG_ICON_POS(info),
-                                         deposited);
-    }
-
-    /* clear remaining draggging infos */
-    wfree(XDND_SOURCE_INFO(info));
-    XDND_SOURCE_INFO(info) = NULL;
-}
-
-
-/* ----- drag cursor ----- */
-static void
-initDragCursor(WMDraggingInfo *info)
-{
-    WMScreen *scr = sourceScreen(info);
-    XColor cursorFgColor, cursorBgColor;
-
-    /* green */
-    cursorFgColor.red = 0x4500;
-    cursorFgColor.green = 0xb000;
-    cursorFgColor.blue = 0x4500;
-
-    /* white */
-    cursorBgColor.red = 0xffff;
-    cursorBgColor.green = 0xffff;
-    cursorBgColor.blue = 0xffff;
-
-    XDND_DRAG_CURSOR(info) = XCreateFontCursor(scr->display, XC_left_ptr);
-    XRecolorCursor(scr->display,
-                   XDND_DRAG_CURSOR(info),
-                   &cursorFgColor,
-                   &cursorBgColor);
-
-    XFlush(scr->display);
-}
-
-static void
-recolorCursor(WMDraggingInfo *info, Bool dropIsAllowed)
-{
-    WMScreen *scr = sourceScreen(info);
-
-    if (dropIsAllowed) {
-        XDefineCursor(scr->display,
-                      scr->rootWin,
-                      XDND_DRAG_CURSOR(info));
-    } else {
-        XDefineCursor(scr->display,
-                      scr->rootWin,
-                      scr->defaultCursor);
-    }
-
-    XFlush(scr->display);
-}
-/* ----- end of drag cursor ----- */
-
-
-/* ----- selection procs ----- */
-static WMData*
-convertSelection(WMView *view, Atom selection, Atom target,
-                 void *cdata, Atom *type)
-{
-    WMScreen *scr;
-    WMData *data;
-    char *typeName;
-
-    scr = W_VIEW_SCREEN(view);
-    typeName = XGetAtomName(scr->display, target);
-
-    *type = target;
-
-    if (view->dragSourceProcs->fetchDragData != NULL) {
-        data = view->dragSourceProcs->fetchDragData(
-                                                    view,
-                                                    typeName);
-    } else {
-        data = NULL;
-    }
-
-    if (typeName != NULL)
-        XFree(typeName);
-
-    return data;
-}
-
-
-static void
-selectionLost(WMView *view, Atom selection, void *cdata)
-{
-    wwarning("DND selection lost during drag operation...");
-}
-
-
-static void
-selectionDone(WMView *view, Atom selection, Atom target, void *cdata)
-{
-#ifdef XDND_DEBUG
-    printf("selection done\n");
-#endif
-}
-/* ----- end of selection procs ----- */
-
-
-/* ----- visual part ----- */
-
-static Window
-makeDragIcon(WMScreen *scr, WMPixmap *pixmap)
-{
-    Window window;
-    WMSize size;
-    unsigned long flags;
-    XSetWindowAttributes attribs;
-    Pixmap pix, mask;
-
-    if (!pixmap) {
-        pixmap = scr->defaultObjectIcon;
-    }
-
-    size = WMGetPixmapSize(pixmap);
-    pix = pixmap->pixmap;
-    mask = pixmap->mask;
-
-    flags = CWSaveUnder|CWBackPixmap|CWOverrideRedirect|CWColormap;
-    attribs.save_under = True;
-    attribs.background_pixmap = pix;
-    attribs.override_redirect = True;
-    attribs.colormap = scr->colormap;
-
-    window = XCreateWindow(scr->display, scr->rootWin, 0, 0, size.width,
-                           size.height, 0, scr->depth, InputOutput,
-                           scr->visual, flags, &attribs);
-
-#ifdef SHAPE
-
-    if (mask) {
-        XShapeCombineMask(scr->display, window, ShapeBounding, 0, 0, mask,
-                          ShapeSet);
-    }
-#endif
-
-    return window;
-}
-
-
-static void
-slideWindow(Display *dpy, Window win, int srcX, int srcY, int dstX, int dstY)
-{
-    double x, y, dx, dy;
-    int i;
-    int iterations;
-
-    iterations = WMIN(MAX_SLIDEBACK_ITER,
-                      WMAX(abs(dstX-srcX), abs(dstY-srcY)));
-
-    x = srcX;
-    y = srcY;
-
-    dx = (double)(dstX-srcX)/iterations;
-    dy = (double)(dstY-srcY)/iterations;
-
-    for (i = 0; i <= iterations; i++) {
-        XMoveWindow(dpy, win, x, y);
-        XFlush(dpy);
-
-        wusleep(800);
-
-        x += dx;
-        y += dy;
-    }
-}
-
-
-static int
-getInitialDragImageCoord(int viewCoord, int mouseCoord,
-                         int viewSize, int iconSize)
-{
-    if (iconSize >= viewSize) {
-        /* center icon coord on view */
-        return viewCoord - iconSize/2;
-    } else {
-        /* try to center icon on mouse pos */
-
-        if (mouseCoord - iconSize/2 <= viewCoord)
-            /* if icon was centered on mouse, it would be off view
-             thus, put icon left (resp. top) side
-             at view (resp. top) side */
-            return viewCoord;
-
-        else if (mouseCoord + iconSize/2 >= viewCoord + viewSize)
-            /* if icon was centered on mouse, it would be off view
-             thus, put icon right (resp. bottom) side
-             at view right (resp. bottom) side */
-            return viewCoord + viewSize - iconSize;
-
-        else
-            return mouseCoord - iconSize/2;
-    }
-
-}
-
-static void
-initDragImagePos(WMView *view, WMDraggingInfo *info, XEvent *event)
-{
-    WMSize iconSize = WMGetPixmapSize(view->dragImage);
-    WMSize viewSize = WMGetViewSize(view);
-    WMPoint viewPos;
-    Window foo;
-
-    XTranslateCoordinates(W_VIEW_SCREEN(view)->display,
-                          WMViewXID(view), W_VIEW_SCREEN(view)->rootWin,
-                          0, 0, &(viewPos.x), &(viewPos.y),
-                          &foo);
-
-    /* set icon pos */
-    XDND_DRAG_ICON_POS(info).x =
-        getInitialDragImageCoord(viewPos.x, event->xmotion.x_root,
-                                 viewSize.width, iconSize.width);
-
-    XDND_DRAG_ICON_POS(info).y =
-        getInitialDragImageCoord(viewPos.y, event->xmotion.y_root,
-                                 viewSize.height, iconSize.height);
-
-    /* set mouse offset relative to icon */
-    XDND_MOUSE_OFFSET(info).x =
-        event->xmotion.x_root - XDND_DRAG_ICON_POS(info).x;
-    XDND_MOUSE_OFFSET(info).y =
-        event->xmotion.y_root - XDND_DRAG_ICON_POS(info).y;
-}
-
-
-static void
-refreshDragImage(WMView *view, WMDraggingInfo *info)
-{
-    WMScreen *scr = W_VIEW_SCREEN(view);
-
-    XMoveWindow(scr->display, XDND_DRAG_ICON(info),
-                XDND_DRAG_ICON_POS(info).x,
-                XDND_DRAG_ICON_POS(info).y);
-}
-
-
-static void
-startDragImage(WMView *view, WMDraggingInfo *info, XEvent* event)
-{
-    WMScreen *scr = W_VIEW_SCREEN(view);
-
-    XDND_DRAG_ICON(info) = makeDragIcon(scr, view->dragImage);
-    initDragImagePos(view, info, event);
-    refreshDragImage(view, info);
-    XMapRaised(scr->display, XDND_DRAG_ICON(info));
-
-    initDragCursor(info);
-}
-
-
-static void
-endDragImage(WMDraggingInfo *info, Bool slideBack)
-{
-    WMView *view = XDND_SOURCE_VIEW(info);
-    Display *dpy = W_VIEW_SCREEN(view)->display;
-
-    if (slideBack) {
-        WMPoint toLocation;
-        Window foo;
-
-        XTranslateCoordinates(W_VIEW_SCREEN(view)->display,
-                              WMViewXID(view), W_VIEW_SCREEN(view)->rootWin,
-                              0, 0, &(toLocation.x), &(toLocation.y),
-                              &foo);
-
-        slideWindow(dpy, XDND_DRAG_ICON(info),
-                    XDND_DRAG_ICON_POS(info).x,
-                    XDND_DRAG_ICON_POS(info).y,
-                    toLocation.x,
-                    toLocation.y);
-    }
-
-    XDestroyWindow(dpy, XDND_DRAG_ICON(info));
-}
-
-/* ----- end of visual part ----- */
-
-
-/* ----- messages ----- */
-
-/* send a DnD message to the destination window */
-static Bool
-sendDnDClientMessage(WMDraggingInfo *info, Atom message,
-                     unsigned long data1,
-                     unsigned long data2,
-                     unsigned long data3,
-                     unsigned long data4)
-{
-    Display *dpy = sourceScreen(info)->display;
-    Window srcWin = WMViewXID(XDND_SOURCE_VIEW(info));
-    Window destWin = XDND_DEST_WIN(info);
-
-    if (! W_SendDnDClientMessage(dpy,
-                                 destWin,
-                                 message,
-                                 srcWin,
-                                 data1,
-                                 data2,
-                                 data3,
-                                 data4)) {
-        /* drop failed */
-        recolorCursor(info, False);
-        endDragImage(info, True);
-        endDragProcess(info, False);
-        return False;
-    }
-
-    return True;
-}
-
-
-static Bool
-sendEnterMessage(WMDraggingInfo *info)
-{
-    WMScreen *scr = sourceScreen(info);
-    unsigned long version;
-
-    if (XDND_DEST_VERSION(info) > 2) {
-        if (XDND_DEST_VERSION(info) < XDND_VERSION)
-            version = XDND_DEST_VERSION(info);
-        else
-            version = XDND_VERSION;
-    } else {
-        version = 3;
-    }
-
-    return sendDnDClientMessage(info, scr->xdndEnterAtom,
-                                (version << 24) | 1, /* 1: support of type list */
-                                XDND_3_TYPES(info)[0],
-                                XDND_3_TYPES(info)[1],
-                                XDND_3_TYPES(info)[2]);
-}
-
-
-static Bool
-sendPositionMessage(WMDraggingInfo *info, WMPoint *mousePos)
-{
-    WMScreen *scr = sourceScreen(info);
-    WMRect *noPosZone = &(XDND_NO_POS_ZONE(info));
-
-    if (noPosZone->size.width != 0 || noPosZone->size.height != 0) {
-        if (mousePos->x < noPosZone->pos.x
-            || mousePos->x > (noPosZone->pos.x + noPosZone->size.width)
-            || mousePos->y < noPosZone->pos.y
-            || mousePos->y > (noPosZone->pos.y + noPosZone->size.height)) {
-            /* send position if out of zone defined by destination */
-            return sendDnDClientMessage(info, scr->xdndPositionAtom,
-                                        0,
-                                        mousePos->x<<16|mousePos->y,
-                                        XDND_TIMESTAMP(info),
-                                        XDND_SOURCE_ACTION(info));
-        }
-
-        /* Nothing to send, always succeed */
-        return True;
-
-    }
-
-    /* send position on each move */
-    return sendDnDClientMessage(info, scr->xdndPositionAtom,
-                                0,
-                                mousePos->x<<16|mousePos->y,
-                                XDND_TIMESTAMP(info),
-                                XDND_SOURCE_ACTION(info));
-}
-
-
-static Bool
-sendLeaveMessage(WMDraggingInfo *info)
-{
-    WMScreen *scr = sourceScreen(info);
-
-    return sendDnDClientMessage(info, scr->xdndLeaveAtom,
-                                0, 0, 0, 0);
-}
-
-
-static Bool
-sendDropMessage(WMDraggingInfo *info)
-{
-    WMScreen *scr = sourceScreen(info);
-
-    return sendDnDClientMessage(info,
-                                scr->xdndDropAtom,
-                                0,
-                                XDND_TIMESTAMP(info),
-                                0, 0);
-}
-
-/* ----- end of messages ----- */
-
-
-static Atom*
-getTypeAtomList(WMScreen *scr, WMView *view, int* count)
-{
-    WMArray* types;
-    Atom* typeAtoms;
-    int i;
-
-    types = view->dragSourceProcs->dropDataTypes(view);
-
-    if (types != NULL) {
-        *count = WMGetArrayItemCount(types);
-        if (*count > 0) {
-            typeAtoms = wmalloc((*count)*sizeof(Atom));
-            for (i=0; i < *count; i++) {
-                typeAtoms[i] = XInternAtom(scr->display,
-                                           WMGetFromArray(types, i),
-                                           False);
-            }
-
-            /* WMFreeArray(types); */
-            return typeAtoms;
-        }
-
-        /* WMFreeArray(types); */
-    }
-
-    *count = 1;
-    typeAtoms = wmalloc(sizeof(Atom));
-    *typeAtoms = None;
-
-    return typeAtoms;
-}
-
-
-static void
-registerDropTypes(WMScreen *scr, WMView *view, WMDraggingInfo *info)
-{
-    Atom* typeList;
-    int i, count;
-
-    typeList = getTypeAtomList(scr, view, &count);
-
-    /* store the first 3 types */
-    for(i=0; i < 3 && i < count; i++)
-        XDND_3_TYPES(info)[i] = typeList[i];
-
-    for(; i < 3; i++)
-        XDND_3_TYPES(info)[i] = None;
-
-
-    /* store the entire type list */
-    XChangeProperty(scr->display,
-                    WMViewXID(view),
-                    scr->xdndTypeListAtom,
-                    XA_ATOM,
-                    XDND_PROPERTY_FORMAT,
-                    PropModeReplace,
-                    (unsigned char*) typeList,
-                    count);
-}
-
-
-static void
-registerOperationList(WMScreen *scr, WMView *view, WMArray* operationArray)
-{
-    Atom* actionList;
-    WMDragOperationType operation;
-    int count = WMGetArrayItemCount(operationArray);
-    int i;
-
-    actionList = wmalloc(sizeof(Atom)*count);
-
-    for(i=0; i < count; i++) {
-        operation = WMGetDragOperationItemType(
-                                               WMGetFromArray(operationArray, i));
-        actionList[i] = W_OperationToAction(scr, operation);
-    }
-
-    XChangeProperty(scr->display,
-                    WMViewXID(view),
-                    scr->xdndActionListAtom,
-                    XA_ATOM,
-                    XDND_PROPERTY_FORMAT,
-                    PropModeReplace,
-                    (unsigned char*) actionList,
-                    count);
-}
-
-static void
-registerDescriptionList(WMScreen *scr, WMView *view, WMArray* operationArray)
-{
-    char *text, *textListItem, *textList;
-    int count = WMGetArrayItemCount(operationArray);
-    int i;
-    int size = 0;
-
-    /* size of XA_STRING info */
-    for(i=0; i < count; i++) {
-        size += strlen(WMGetDragOperationItemText(
-                                                  WMGetFromArray(operationArray, i))) + 1; /* +1 = +NULL */
-    }
-
-    /* create text list */
-    textList = wmalloc(size);
-    textListItem = textList;
-
-    for(i=0; i < count; i++) {
-        text = WMGetDragOperationItemText(WMGetFromArray(operationArray, i));
-        strcpy(textListItem, text);
-
-        /* to next text offset */
-        textListItem  = &(textListItem[strlen(textListItem) + 1]);
-    }
-
-    XChangeProperty(scr->display,
-                    WMViewXID(view),
-                    scr->xdndActionDescriptionAtom,
-                    XA_STRING,
-                    XDND_ACTION_DESCRIPTION_FORMAT,
-                    PropModeReplace,
-                    (unsigned char*) textList,
-                    size);
-}
-
-/* called if wanted operation is WDOperationAsk */
-static void
-registerSupportedOperations(WMView *view)
-{
-    WMScreen *scr = W_VIEW_SCREEN(view);
-    WMArray* operationArray;
-
-    operationArray = view->dragSourceProcs->askedOperations(view);
-
-    registerOperationList(scr, view, operationArray);
-    registerDescriptionList(scr, view, operationArray);
-
-    /* WMFreeArray(operationArray); */
-}
-
-
-static void
-initSourceDragInfo(WMView *sourceView, WMDraggingInfo *info)
-{
-    WMRect emptyZone;
-
-    XDND_SOURCE_INFO(info) = (W_DragSourceInfo*) wmalloc(sizeof(W_DragSourceInfo));
-
-    XDND_SOURCE_VIEW(info) = sourceView;
-    XDND_DEST_WIN(info) = None;
-    XDND_DRAG_ICON(info) = None;
-
-    XDND_SOURCE_ACTION(info) = W_OperationToAction(
-                                                   W_VIEW_SCREEN(sourceView),
-                                                   sourceView->dragSourceProcs->wantedDropOperation(sourceView));
-
-    XDND_DEST_ACTION(info) = None;
-
-    XDND_SOURCE_STATE(info) = idleState;
-
-    emptyZone.pos = wmkpoint(0, 0);
-    emptyZone.size = wmksize(0, 0);
-    XDND_NO_POS_ZONE(info) = emptyZone;
-}
-
-
-/*
- Returned array is destroyed after dropDataTypes call
- */
-static WMArray*
-defDropDataTypes(WMView *self)
-{
-    return NULL;
-}
-
-
-static WMDragOperationType
-defWantedDropOperation(WMView *self)
-{
-    return WDOperationNone;
-}
-
-
-/*
- Must be defined if wantedDropOperation return WDOperationAsk
- (useless otherwise).
- Return a WMDragOperationItem array (destroyed after call).
- A WMDragOperationItem links a label to an operation.
- static WMArray*
- defAskedOperations(WMView *self); */
-
-
-static Bool
-defAcceptDropOperation(WMView *self, WMDragOperationType allowedOperation)
-{
-    return False;
-}
-
-
-static void
-defBeganDrag(WMView *self, WMPoint *point)
-{
-}
-
-
-static void
-defEndedDrag(WMView *self, WMPoint *point, Bool deposited)
-{
-}
-
-
-/*
- Returned data is not destroyed
- */
-static WMData*
-defFetchDragData(WMView *self, char *type)
-{
-    return NULL;
-}
-
-
-void
-WMSetViewDragSourceProcs(WMView *view, WMDragSourceProcs *procs)
-{
-    if (view->dragSourceProcs)
-        wfree(view->dragSourceProcs);
-    view->dragSourceProcs = wmalloc(sizeof(WMDragSourceProcs));
-
-    *view->dragSourceProcs = *procs;
-
-    if (procs->dropDataTypes == NULL)
-        view->dragSourceProcs->dropDataTypes = defDropDataTypes;
-
-    if (procs->wantedDropOperation == NULL)
-        view->dragSourceProcs->wantedDropOperation = defWantedDropOperation;
-
-    /*
-     Note: askedOperations can be NULL, if wantedDropOperation never returns
-     WDOperationAsk.
-     */
-
-    if (procs->acceptDropOperation == NULL)
-        view->dragSourceProcs->acceptDropOperation = defAcceptDropOperation;
-
-    if (procs->beganDrag == NULL)
-        view->dragSourceProcs->beganDrag = defBeganDrag;
-
-    if (procs->endedDrag == NULL)
-        view->dragSourceProcs->endedDrag = defEndedDrag;
-
-    if (procs->fetchDragData == NULL)
-        view->dragSourceProcs->fetchDragData = defFetchDragData;
-}
-
-
-static Bool
-isXdndAware(WMScreen *scr, Window win)
-{
-    Atom type;
-    int format;
-    unsigned long count, remain;
-    unsigned char *winXdndVersion;
-
-    if (win == None)
-        return False;
-
-    XGetWindowProperty(scr->display, win, scr->xdndAwareAtom,
-                       0, 1, False, XA_ATOM, &type, &format,
-                       &count, &remain, &winXdndVersion);
-
-    if (type != XA_ATOM
-        || format != XDND_PROPERTY_FORMAT
-        || count == 0 || !winXdndVersion) {
-        if (winXdndVersion)
-            XFree(winXdndVersion);
-        return False;
-    }
-
-    XFree(winXdndVersion);
-    return (count == 1); /* xdnd version is set */
-}
-
-
-static Window*
-windowChildren(Display *dpy, Window win, unsigned *nchildren)
-{
-    Window *children;
-    Window foo, bar;
-
-    if (!XQueryTree(dpy, win, &foo, &bar, &children, nchildren)) {
-        *nchildren = 0;
-        return NULL;
-    } else
-        return children;
-}
-
-static Window
-lookForAwareWindow(WMScreen *scr, WMPoint *mousePos, Window win)
-{
-    int tmpx, tmpy;
-    Window child;
-
-    /* Since xdnd v3, only the toplevel window should be aware */
-    if (isXdndAware(scr, win))
-        return win;
-
-    /* inspect child under pointer */
-    if (XTranslateCoordinates(scr->display, scr->rootWin, win,
-                              mousePos->x, mousePos->y, &tmpx, &tmpy,
-                              &child)) {
-        if (child == None)
-            return None;
-        else
-            return lookForAwareWindow(scr, mousePos, child);
-    }
-
-    return None;
-}
-
-
-static Window
-findDestination(WMDraggingInfo *info, WMPoint *mousePos)
-{
-    WMScreen *scr = sourceScreen(info);
-    unsigned nchildren;
-    Window *children = windowChildren(scr->display, scr->rootWin, &nchildren);
-    int i;
-    XWindowAttributes attr;
-
-    if (isXdndAware(scr, scr->rootWin))
-        return scr->rootWin;
-
-    /* exclude drag icon (and upper) from search */
-    for (i = nchildren-1; i >= 0; i--) {
-        if (children[i] == XDND_DRAG_ICON(info)) {
-            i--;
-            break;
-        }
-    }
-
-    if (i < 0) {
-        /* root window has no child under drag icon, and is not xdnd aware. */
-        return None;
-    }
-
-    /* inspecting children, from upper to lower */
-    for (; i >= 0; i--) {
-        if (XGetWindowAttributes(scr->display, children[i], &attr)
-            && attr.map_state == IsViewable
-            && mousePos->x >= attr.x
-            && mousePos->y >= attr.y
-            && mousePos->x < attr.x + attr.width
-            && mousePos->y < attr.y + attr.height) {
-            return lookForAwareWindow(scr, mousePos, children[i]);
-        }
-    }
-
-    /* No child window under drag pointer */
-    return None;
-}
-
-
-static void
-storeDestinationProtocolVersion(WMDraggingInfo *info)
-{
-    Atom type;
-    int format;
-    unsigned long count, remain;
-    unsigned char *winXdndVersion;
-    WMScreen *scr = W_VIEW_SCREEN(XDND_SOURCE_VIEW(info));
-
-    wassertr(XDND_DEST_WIN(info) != None);
-
-    if (XGetWindowProperty(scr->display, XDND_DEST_WIN(info),
-                           scr->xdndAwareAtom,
-                           0, 1, False, XA_ATOM, &type, &format,
-                           &count, &remain, &winXdndVersion) == Success) {
-        XDND_DEST_VERSION(info) = *winXdndVersion;
-        XFree(winXdndVersion);
-    } else {
-        XDND_DEST_VERSION(info) = 0;
-        wwarning("failed to read XDND version of drop target");
-    }
-}
-
-
-static void
-initMotionProcess(WMView *view, WMDraggingInfo *info,
-                  XEvent *event, WMPoint *startLocation)
-{
-    WMScreen *scr = W_VIEW_SCREEN(view);
-
-    /* take ownership of XdndSelection */
-    XDND_SELECTION_PROCS(info) =
-        (WMSelectionProcs*) wmalloc(sizeof(WMSelectionProcs));
-    XDND_SELECTION_PROCS(info)->convertSelection = convertSelection;
-    XDND_SELECTION_PROCS(info)->selectionLost = selectionLost;
-    XDND_SELECTION_PROCS(info)->selectionDone = selectionDone;
-    XDND_TIMESTAMP(info) = event->xmotion.time;
-
-    if (!WMCreateSelectionHandler(view, scr->xdndSelectionAtom,
-                                  CurrentTime,
-                                  XDND_SELECTION_PROCS(info), NULL)) {
-        wwarning("could not get ownership or DND selection");
-        return;
-    }
-
-    registerDropTypes(scr, view, info);
-
-    if (XDND_SOURCE_ACTION(info) == W_VIEW_SCREEN(view)->xdndActionAsk)
-        registerSupportedOperations(view);
-
-    if (view->dragSourceProcs->beganDrag != NULL) {
-        view->dragSourceProcs->beganDrag(view, startLocation);
-    }
-}
-
-
-static void
-processMotion(WMDraggingInfo *info, WMPoint *mousePos)
-{
-    Window newDestination = findDestination(info, mousePos);
-
-    W_DragSourceStopTimer();
-
-    if (newDestination != XDND_DEST_WIN(info)) {
-        recolorCursor(info, False);
-
-        if (XDND_DEST_WIN(info) != None) {
-            /* leaving a xdnd window */
-            sendLeaveMessage(info);
-        }
-
-        XDND_DEST_WIN(info) = newDestination;
-        XDND_DEST_ACTION(info) = None;
-        XDND_NO_POS_ZONE(info).size.width = 0;
-        XDND_NO_POS_ZONE(info).size.height = 0;
-
-        if (newDestination != None) {
-            /* entering a xdnd window */
-            XDND_SOURCE_STATE(info) = idleState;
-            storeDestinationProtocolVersion(info);
-
-            if (! sendEnterMessage(info)) {
-                XDND_DEST_WIN(info) = None;
-                return;
-            }
-
-            W_DragSourceStartTimer(info);
-        } else {
-            XDND_SOURCE_STATE(info) = NULL;
-        } 
-    } else {
-        if (XDND_DEST_WIN(info) != None) {
-            if (! sendPositionMessage(info, mousePos)) {
-                XDND_DEST_WIN(info) = None;
-                return;
-            }
-
-            W_DragSourceStartTimer(info);
-        }
-    }
-}
-
-
-static Bool
-processButtonRelease(WMDraggingInfo *info)
-{
-    if (XDND_SOURCE_STATE(info) == dropAllowedState) {
-        /* begin drop */
-        W_DragSourceStopTimer();
-
-        if (! sendDropMessage(info))
-            return False;
-
-        W_DragSourceStartTimer(info);
-        return True;
-    } else {
-        if (XDND_DEST_WIN(info) != None)
-            sendLeaveMessage(info);
-
-        W_DragSourceStopTimer();
-        return False;
-    }
-}
-
-
-Bool
-WMIsDraggingFromView(WMView *view)
-{
-    WMDraggingInfo *info = &W_VIEW_SCREEN(view)->dragInfo;
-
-    return ( XDND_SOURCE_INFO(info) != NULL
-            &&  XDND_SOURCE_STATE(info) != finishDropState);
-    /* return W_VIEW_SCREEN(view)->dragInfo.sourceInfo != NULL; */
-}
-
-
-void
-WMDragImageFromView(WMView *view, XEvent *event)
-{
-    WMDraggingInfo *info = &W_VIEW_SCREEN(view)->dragInfo;
-    WMPoint mouseLocation;
-
-    switch(event->type) {
-    case ButtonPress:
-        if (event->xbutton.button == Button1) {
-            XEvent nextEvent;
-
-            XPeekEvent(event->xbutton.display, &nextEvent);
-
-            /* Initialize only if a drag really begins (avoid clicks) */
-            if (nextEvent.type == MotionNotify) {
-                initSourceDragInfo(view, info);
-            }
-        }
-
-        break;
-
-    case ButtonRelease:
-        if (WMIsDraggingFromView(view)) {
-            Bool dropBegan = processButtonRelease(info);
-
-            recolorCursor(info, False);
-            if (dropBegan) {
-                endDragImage(info, False);
-                XDND_SOURCE_STATE(info) = finishDropState;
-            } else {
-                /* drop failed */
-                endDragImage(info, True);
-                endDragProcess(info,False);
-            }
-        }
-        break;
-
-    case MotionNotify:
-        if (WMIsDraggingFromView(view)) {
-            mouseLocation = wmkpoint(event->xmotion.x_root,
-                                     event->xmotion.y_root);
-
-            if (abs(XDND_DRAG_ICON_POS(info).x - mouseLocation.x) >=
-                MIN_X_MOVE_OFFSET
-                || abs(XDND_DRAG_ICON_POS(info).y - mouseLocation.y) >=
-                MIN_Y_MOVE_OFFSET) {
-                if (XDND_DRAG_ICON(info) == None) {
-                    initMotionProcess(view, info, event, &mouseLocation);
-                    startDragImage(view, info, event);
-                } else {
-                    XDND_DRAG_ICON_POS(info).x =
-                        mouseLocation.x - XDND_MOUSE_OFFSET(info).x;
-                    XDND_DRAG_ICON_POS(info).y =
-                        mouseLocation.y - XDND_MOUSE_OFFSET(info).y;
-
-                    refreshDragImage(view, info);
-                    processMotion(info, &mouseLocation);
-                }
-            }
-        }
-        break;
-    }
-}
-
-
-/* Minimal mouse events handler: no right or double-click detection,
- only drag is supported */
-static void
-dragImageHandler(XEvent *event, void *cdata)
-{
-    WMView *view = (WMView*)cdata;
-
-    WMDragImageFromView(view, event);
-}
-
-
-/* ----- source states ----- */
-
-#ifdef XDND_DEBUG
-static void
-traceStatusMsg(Display *dpy, XClientMessageEvent *statusEvent)
-{
-    printf("Xdnd status message:\n");
-
-    if (statusEvent->data.l[1] & 0x2UL)
-        printf("\tsend position on every move\n");
-    else {
-        int x, y, w, h;
-        x = statusEvent->data.l[2] >> 16;
-        y = statusEvent->data.l[2] & 0xFFFFL;
-        w = statusEvent->data.l[3] >> 16;
-        h = statusEvent->data.l[3] & 0xFFFFL;
-
-        printf("\tsend position out of ((%d,%d) , (%d,%d))\n",
-               x, y, x+w, y+h);
-    }
-
-    if (statusEvent->data.l[1] & 0x1L)
-        printf("\tallowed action: %s\n",
-               XGetAtomName(dpy, statusEvent->data.l[4]));
-    else
-        printf("\tno action allowed\n");
-}
-#endif
-
-
-static void
-storeDropAction(WMDraggingInfo *info, Atom destAction)
-{
-    WMView* sourceView = XDND_SOURCE_VIEW(info);
-    WMScreen *scr = W_VIEW_SCREEN(sourceView);
-
-    if (sourceView->dragSourceProcs->acceptDropOperation != NULL) {
-        if (sourceView->dragSourceProcs->acceptDropOperation(
-                                                             sourceView,
-                                                             W_ActionToOperation(scr, destAction)))
-            XDND_DEST_ACTION(info) = destAction;
-        else
-            XDND_DEST_ACTION(info) = None;
-    } else {
-        XDND_DEST_ACTION(info) = destAction;
-    }
-}
-
-
-static void
-storeStatusMessageInfos(WMDraggingInfo *info, XClientMessageEvent *statusEvent)
-{
-    WMRect* noPosZone = &(XDND_NO_POS_ZONE(info));
-
-#ifdef XDND_DEBUG
-
-    traceStatusMsg(sourceScreen(info)->display, statusEvent);
-#endif
-
-    if (statusEvent->data.l[1] & 0x2UL) {
-        /* bit 1 set: destination wants position messages on every move */
-        noPosZone->size.width = 0;
-        noPosZone->size.height = 0;
-    } else {
-        /* don't send another position message while in given rectangle */
-        noPosZone->pos.x = statusEvent->data.l[2] >> 16;
-        noPosZone->pos.y = statusEvent->data.l[2] & 0xFFFFL;
-        noPosZone->size.width = statusEvent->data.l[3] >> 16;
-        noPosZone->size.height = statusEvent->data.l[3] & 0xFFFFL;
-    }
-
-    if ((statusEvent->data.l[1] & 0x1L) || statusEvent->data.l[4] != None) {
-        /* destination accept drop */
-        storeDropAction(info, statusEvent->data.l[4]);
-    } else {
-        XDND_DEST_ACTION(info) = None;
-    }
-}
-
-
-static void*
-idleState(WMView *view, XClientMessageEvent *event, WMDraggingInfo *info)
-{
-    WMScreen *scr;
-    Atom destMsg = event->message_type;
-
-    scr = W_VIEW_SCREEN(view);
-
-    if (destMsg == scr->xdndStatusAtom) {
-        storeStatusMessageInfos(info, event);
-
-        if (XDND_DEST_ACTION(info) != None) {
-            recolorCursor(info, True);
-            W_DragSourceStartTimer(info);
-            return dropAllowedState;
-        } else {
-            /* drop denied */
-            recolorCursor(info, False);
-            return idleState;
-        }
-    }
-
-    if (destMsg == scr->xdndFinishedAtom) {
-        wwarning("received xdndFinishedAtom before drop began");
-    }
-
-    W_DragSourceStartTimer(info);
-    return idleState;
-}
-
-
-static void*
-dropAllowedState(WMView *view, XClientMessageEvent *event, WMDraggingInfo *info)
-{
-    WMScreen *scr = W_VIEW_SCREEN(view);
-    Atom destMsg = event->message_type;
-
-    if (destMsg == scr->xdndStatusAtom) {
-        storeStatusMessageInfos(info, event);
-
-        if (XDND_DEST_ACTION(info) == None) {
-            /* drop denied */
-            recolorCursor(info, False);
-            return idleState;
-        }
-    }
-
-    W_DragSourceStartTimer(info);
-    return dropAllowedState;
-}
-
-
-static void*
-finishDropState(WMView *view, XClientMessageEvent *event, WMDraggingInfo *info)
-{
-    WMScreen *scr = W_VIEW_SCREEN(view);
-    Atom destMsg = event->message_type;
-
-    if (destMsg == scr->xdndFinishedAtom) {
-        endDragProcess(info, True);
-        return NULL;
-    }
-
-    W_DragSourceStartTimer(info);
-    return finishDropState;
-}
-/* ----- end of source states ----- */
-
-
-/* ----- source timer ----- */
-static void
-dragSourceResponseTimeOut(void *source)
-{
-    WMView *view = (WMView*)source;
-    WMDraggingInfo *info = &(W_VIEW_SCREEN(view)->dragInfo);
-
-    wwarning("delay for drag destination response expired");
-    sendLeaveMessage(info);
-
-    recolorCursor(info, False);
-    if (XDND_SOURCE_STATE(info) == finishDropState) {
-        /* drop failed */
-        endDragImage(info, True);
-        endDragProcess(info, False);
-    } else {
-        XDND_SOURCE_STATE(info) = idleState;
-    }
-}
-
-void
-W_DragSourceStopTimer()
-{
-    if (dndSourceTimer != NULL) {
-        WMDeleteTimerHandler(dndSourceTimer);
-        dndSourceTimer = NULL;
-    }
-}
-
-void
-W_DragSourceStartTimer(WMDraggingInfo *info)
-{
-    W_DragSourceStopTimer();
-
-    dndSourceTimer = WMAddTimerHandler(
-                                       XDND_DESTINATION_RESPONSE_MAX_DELAY,
-                                       dragSourceResponseTimeOut,
-                                       XDND_SOURCE_VIEW(info));
-}
-
-/* ----- End of Destination timer ----- */
-
-
-void
-W_DragSourceStateHandler(WMDraggingInfo *info, XClientMessageEvent *event)
-{
-    WMView *view;
-    W_DndState* newState;
-
-    if (XDND_SOURCE_VIEW_STORED(info)) {
-        if (XDND_SOURCE_STATE(info) != NULL) {
-            view = XDND_SOURCE_VIEW(info);
-#ifdef XDND_DEBUG
-
-            printf("current source state: %s\n",
-                   stateName(XDND_SOURCE_STATE(info)));
-#endif
-
-            newState = (W_DndState*) XDND_SOURCE_STATE(info)(view, event, info);
-
-#ifdef XDND_DEBUG
-
-            printf("new source state: %s\n", stateName(newState));
-#endif
-
-            if (newState != NULL)
-                XDND_SOURCE_STATE(info) = newState;
-            /* else drop finished, and info has been flushed */
-        }
-
-    } else {
-        wwarning("received DnD message without having a target");
-    }
-}
-
-
-void WMSetViewDragImage(WMView* view, WMPixmap *dragImage)
-{
-    if (view->dragImage != NULL)
-        WMReleasePixmap(view->dragImage);
-
-    view->dragImage = WMRetainPixmap(dragImage);
-}
-
-
-void WMReleaseViewDragImage(WMView* view)
-{
-    if (view->dragImage != NULL)
-        WMReleasePixmap(view->dragImage);
-}
-
-
-/* Create a drag handler, associating drag event masks with dragEventProc */
-void
-WMCreateDragHandler(WMView *view, WMEventProc *dragEventProc, void *clientData)
-{
-    WMCreateEventHandler(view,
-                         ButtonPressMask|ButtonReleaseMask|Button1MotionMask,
-                         dragEventProc, clientData);
-}
-
-
-void
-WMDeleteDragHandler(WMView *view, WMEventProc *dragEventProc, void *clientData)
-{
-    WMDeleteEventHandler(view,
-                         ButtonPressMask|ButtonReleaseMask|Button1MotionMask,
-                         dragEventProc, clientData);
-}
-
-
-/* set default drag handler for view */
-void
-WMSetViewDraggable(WMView *view, WMDragSourceProcs *dragSourceProcs,
-                   WMPixmap *dragImage)
-{
-    wassertr(dragImage != NULL);
-    view->dragImage = WMRetainPixmap(dragImage);
-
-    WMSetViewDragSourceProcs(view, dragSourceProcs);
-
-    WMCreateDragHandler(view, dragImageHandler, view);
-}
-
-
-void
-WMUnsetViewDraggable(WMView *view)
-{
-    if (view->dragSourceProcs) {
-        wfree(view->dragSourceProcs);
-        view->dragSourceProcs = NULL;
-    }
-
-    WMReleaseViewDragImage(view);
-
-    WMDeleteDragHandler(view, dragImageHandler, view);
-}
-
-
+
+#include "wconfig.h"
+#include "WINGsP.h"
+
+#include <X11/Xatom.h>
+#include <X11/cursorfont.h>
+#ifdef SHAPE
+#include <X11/extensions/shape.h>
+#endif
+
+#define XDND_DESTINATION_RESPONSE_MAX_DELAY 10000
+#define MIN_X_MOVE_OFFSET 5
+#define MIN_Y_MOVE_OFFSET 5
+#define MAX_SLIDEBACK_ITER 15
+
+#define XDND_PROPERTY_FORMAT 32
+#define XDND_ACTION_DESCRIPTION_FORMAT 8
+
+#define XDND_DEST_VERSION(dragInfo) dragInfo->protocolVersion
+#define XDND_SOURCE_INFO(dragInfo) dragInfo->sourceInfo
+#define XDND_DEST_WIN(dragInfo) dragInfo->sourceInfo->destinationWindow
+#define XDND_SOURCE_ACTION(dragInfo) dragInfo->sourceAction
+#define XDND_DEST_ACTION(dragInfo) dragInfo->destinationAction
+#define XDND_SOURCE_VIEW(dragInfo) dragInfo->sourceInfo->sourceView
+#define XDND_SOURCE_STATE(dragInfo) dragInfo->sourceInfo->state
+#define XDND_SELECTION_PROCS(dragInfo) dragInfo->sourceInfo->selectionProcs
+#define XDND_DRAG_ICON(dragInfo) dragInfo->sourceInfo->icon
+#define XDND_MOUSE_OFFSET(dragInfo) dragInfo->sourceInfo->mouseOffset
+#define XDND_DRAG_CURSOR(dragInfo) dragInfo->sourceInfo->dragCursor
+#define XDND_DRAG_ICON_POS(dragInfo) dragInfo->sourceInfo->imageLocation
+#define XDND_NO_POS_ZONE(dragInfo) dragInfo->sourceInfo->noPositionMessageZone
+#define XDND_TIMESTAMP(dragInfo) dragInfo->timestamp
+#define XDND_3_TYPES(dragInfo) dragInfo->sourceInfo->firstThreeTypes
+#define XDND_SOURCE_VIEW_STORED(dragInfo) dragInfo->sourceInfo != NULL \
+    && dragInfo->sourceInfo->sourceView != NULL
+
+static WMHandlerID dndSourceTimer = NULL;
+
+static void *idleState(WMView * srcView, XClientMessageEvent * event, WMDraggingInfo * info);
+static void *dropAllowedState(WMView * srcView, XClientMessageEvent * event, WMDraggingInfo * info);
+static void *finishDropState(WMView * srcView, XClientMessageEvent * event, WMDraggingInfo * info);
+
+#ifdef XDND_DEBUG
+static const char *stateName(W_DndState * state)
+{
+       if (state == NULL)
+               return "no state defined";
+
+       if (state == idleState)
+               return "idleState";
+
+       if (state == dropAllowedState)
+               return "dropAllowedState";
+
+       if (state == finishDropState)
+               return "finishDropState";
+
+       return "unknown state";
+}
+#endif
+
+static WMScreen *sourceScreen(WMDraggingInfo * info)
+{
+       return W_VIEW_SCREEN(XDND_SOURCE_VIEW(info));
+}
+
+static void endDragProcess(WMDraggingInfo * info, Bool deposited)
+{
+       WMView *view = XDND_SOURCE_VIEW(info);
+       WMScreen *scr = W_VIEW_SCREEN(XDND_SOURCE_VIEW(info));
+
+       /* free selection handler while view exists */
+       WMDeleteSelectionHandler(view, scr->xdndSelectionAtom, CurrentTime);
+       wfree(XDND_SELECTION_PROCS(info));
+
+       if (XDND_DRAG_CURSOR(info) != None) {
+               XFreeCursor(scr->display, XDND_DRAG_CURSOR(info));
+               XDND_DRAG_CURSOR(info) = None;
+       }
+
+       if (view->dragSourceProcs->endedDrag != NULL) {
+               /* this can destroy source view (with a "move" action for example) */
+               view->dragSourceProcs->endedDrag(view, &XDND_DRAG_ICON_POS(info), deposited);
+       }
+
+       /* clear remaining draggging infos */
+       wfree(XDND_SOURCE_INFO(info));
+       XDND_SOURCE_INFO(info) = NULL;
+}
+
+/* ----- drag cursor ----- */
+static void initDragCursor(WMDraggingInfo * info)
+{
+       WMScreen *scr = sourceScreen(info);
+       XColor cursorFgColor, cursorBgColor;
+
+       /* green */
+       cursorFgColor.red = 0x4500;
+       cursorFgColor.green = 0xb000;
+       cursorFgColor.blue = 0x4500;
+
+       /* white */
+       cursorBgColor.red = 0xffff;
+       cursorBgColor.green = 0xffff;
+       cursorBgColor.blue = 0xffff;
+
+       XDND_DRAG_CURSOR(info) = XCreateFontCursor(scr->display, XC_left_ptr);
+       XRecolorCursor(scr->display, XDND_DRAG_CURSOR(info), &cursorFgColor, &cursorBgColor);
+
+       XFlush(scr->display);
+}
+
+static void recolorCursor(WMDraggingInfo * info, Bool dropIsAllowed)
+{
+       WMScreen *scr = sourceScreen(info);
+
+       if (dropIsAllowed) {
+               XDefineCursor(scr->display, scr->rootWin, XDND_DRAG_CURSOR(info));
+       } else {
+               XDefineCursor(scr->display, scr->rootWin, scr->defaultCursor);
+       }
+
+       XFlush(scr->display);
+}
+
+/* ----- end of drag cursor ----- */
+
+/* ----- selection procs ----- */
+static WMData *convertSelection(WMView * view, Atom selection, Atom target, void *cdata, Atom * type)
+{
+       WMScreen *scr;
+       WMData *data;
+       char *typeName;
+
+       scr = W_VIEW_SCREEN(view);
+       typeName = XGetAtomName(scr->display, target);
+
+       *type = target;
+
+       if (view->dragSourceProcs->fetchDragData != NULL) {
+               data = view->dragSourceProcs->fetchDragData(view, typeName);
+       } else {
+               data = NULL;
+       }
+
+       if (typeName != NULL)
+               XFree(typeName);
+
+       return data;
+}
+
+static void selectionLost(WMView * view, Atom selection, void *cdata)
+{
+       wwarning("DND selection lost during drag operation...");
+}
+
+static void selectionDone(WMView * view, Atom selection, Atom target, void *cdata)
+{
+#ifdef XDND_DEBUG
+       printf("selection done\n");
+#endif
+}
+
+/* ----- end of selection procs ----- */
+
+/* ----- visual part ----- */
+
+static Window makeDragIcon(WMScreen * scr, WMPixmap * pixmap)
+{
+       Window window;
+       WMSize size;
+       unsigned long flags;
+       XSetWindowAttributes attribs;
+       Pixmap pix, mask;
+
+       if (!pixmap) {
+               pixmap = scr->defaultObjectIcon;
+       }
+
+       size = WMGetPixmapSize(pixmap);
+       pix = pixmap->pixmap;
+       mask = pixmap->mask;
+
+       flags = CWSaveUnder | CWBackPixmap | CWOverrideRedirect | CWColormap;
+       attribs.save_under = True;
+       attribs.background_pixmap = pix;
+       attribs.override_redirect = True;
+       attribs.colormap = scr->colormap;
+
+       window = XCreateWindow(scr->display, scr->rootWin, 0, 0, size.width,
+                              size.height, 0, scr->depth, InputOutput, scr->visual, flags, &attribs);
+
+#ifdef SHAPE
+
+       if (mask) {
+               XShapeCombineMask(scr->display, window, ShapeBounding, 0, 0, mask, ShapeSet);
+       }
+#endif
+
+       return window;
+}
+
+static void slideWindow(Display * dpy, Window win, int srcX, int srcY, int dstX, int dstY)
+{
+       double x, y, dx, dy;
+       int i;
+       int iterations;
+
+       iterations = WMIN(MAX_SLIDEBACK_ITER, WMAX(abs(dstX - srcX), abs(dstY - srcY)));
+
+       x = srcX;
+       y = srcY;
+
+       dx = (double)(dstX - srcX) / iterations;
+       dy = (double)(dstY - srcY) / iterations;
+
+       for (i = 0; i <= iterations; i++) {
+               XMoveWindow(dpy, win, x, y);
+               XFlush(dpy);
+
+               wusleep(800);
+
+               x += dx;
+               y += dy;
+       }
+}
+
+static int getInitialDragImageCoord(int viewCoord, int mouseCoord, int viewSize, int iconSize)
+{
+       if (iconSize >= viewSize) {
+               /* center icon coord on view */
+               return viewCoord - iconSize / 2;
+       } else {
+               /* try to center icon on mouse pos */
+
+               if (mouseCoord - iconSize / 2 <= viewCoord)
+                       /* if icon was centered on mouse, it would be off view
+                          thus, put icon left (resp. top) side
+                          at view (resp. top) side */
+                       return viewCoord;
+
+               else if (mouseCoord + iconSize / 2 >= viewCoord + viewSize)
+                       /* if icon was centered on mouse, it would be off view
+                          thus, put icon right (resp. bottom) side
+                          at view right (resp. bottom) side */
+                       return viewCoord + viewSize - iconSize;
+
+               else
+                       return mouseCoord - iconSize / 2;
+       }
+
+}
+
+static void initDragImagePos(WMView * view, WMDraggingInfo * info, XEvent * event)
+{
+       WMSize iconSize = WMGetPixmapSize(view->dragImage);
+       WMSize viewSize = WMGetViewSize(view);
+       WMPoint viewPos;
+       Window foo;
+
+       XTranslateCoordinates(W_VIEW_SCREEN(view)->display,
+                             WMViewXID(view), W_VIEW_SCREEN(view)->rootWin,
+                             0, 0, &(viewPos.x), &(viewPos.y), &foo);
+
+       /* set icon pos */
+       XDND_DRAG_ICON_POS(info).x =
+           getInitialDragImageCoord(viewPos.x, event->xmotion.x_root, viewSize.width, iconSize.width);
+
+       XDND_DRAG_ICON_POS(info).y =
+           getInitialDragImageCoord(viewPos.y, event->xmotion.y_root, viewSize.height, iconSize.height);
+
+       /* set mouse offset relative to icon */
+       XDND_MOUSE_OFFSET(info).x = event->xmotion.x_root - XDND_DRAG_ICON_POS(info).x;
+       XDND_MOUSE_OFFSET(info).y = event->xmotion.y_root - XDND_DRAG_ICON_POS(info).y;
+}
+
+static void refreshDragImage(WMView * view, WMDraggingInfo * info)
+{
+       WMScreen *scr = W_VIEW_SCREEN(view);
+
+       XMoveWindow(scr->display, XDND_DRAG_ICON(info), XDND_DRAG_ICON_POS(info).x, XDND_DRAG_ICON_POS(info).y);
+}
+
+static void startDragImage(WMView * view, WMDraggingInfo * info, XEvent * event)
+{
+       WMScreen *scr = W_VIEW_SCREEN(view);
+
+       XDND_DRAG_ICON(info) = makeDragIcon(scr, view->dragImage);
+       initDragImagePos(view, info, event);
+       refreshDragImage(view, info);
+       XMapRaised(scr->display, XDND_DRAG_ICON(info));
+
+       initDragCursor(info);
+}
+
+static void endDragImage(WMDraggingInfo * info, Bool slideBack)
+{
+       WMView *view = XDND_SOURCE_VIEW(info);
+       Display *dpy = W_VIEW_SCREEN(view)->display;
+
+       if (slideBack) {
+               WMPoint toLocation;
+               Window foo;
+
+               XTranslateCoordinates(W_VIEW_SCREEN(view)->display,
+                                     WMViewXID(view), W_VIEW_SCREEN(view)->rootWin,
+                                     0, 0, &(toLocation.x), &(toLocation.y), &foo);
+
+               slideWindow(dpy, XDND_DRAG_ICON(info),
+                           XDND_DRAG_ICON_POS(info).x, XDND_DRAG_ICON_POS(info).y, toLocation.x, toLocation.y);
+       }
+
+       XDestroyWindow(dpy, XDND_DRAG_ICON(info));
+}
+
+/* ----- end of visual part ----- */
+
+/* ----- messages ----- */
+
+/* send a DnD message to the destination window */
+static Bool
+sendDnDClientMessage(WMDraggingInfo * info, Atom message,
+                    unsigned long data1, unsigned long data2, unsigned long data3, unsigned long data4)
+{
+       Display *dpy = sourceScreen(info)->display;
+       Window srcWin = WMViewXID(XDND_SOURCE_VIEW(info));
+       Window destWin = XDND_DEST_WIN(info);
+
+       if (!W_SendDnDClientMessage(dpy, destWin, message, srcWin, data1, data2, data3, data4)) {
+               /* drop failed */
+               recolorCursor(info, False);
+               endDragImage(info, True);
+               endDragProcess(info, False);
+               return False;
+       }
+
+       return True;
+}
+
+static Bool sendEnterMessage(WMDraggingInfo * info)
+{
+       WMScreen *scr = sourceScreen(info);
+       unsigned long version;
+
+       if (XDND_DEST_VERSION(info) > 2) {
+               if (XDND_DEST_VERSION(info) < XDND_VERSION)
+                       version = XDND_DEST_VERSION(info);
+               else
+                       version = XDND_VERSION;
+       } else {
+               version = 3;
+       }
+
+       return sendDnDClientMessage(info, scr->xdndEnterAtom, (version << 24) | 1,      /* 1: support of type list */
+                                   XDND_3_TYPES(info)[0], XDND_3_TYPES(info)[1], XDND_3_TYPES(info)[2]);
+}
+
+static Bool sendPositionMessage(WMDraggingInfo * info, WMPoint * mousePos)
+{
+       WMScreen *scr = sourceScreen(info);
+       WMRect *noPosZone = &(XDND_NO_POS_ZONE(info));
+
+       if (noPosZone->size.width != 0 || noPosZone->size.height != 0) {
+               if (mousePos->x < noPosZone->pos.x || mousePos->x > (noPosZone->pos.x + noPosZone->size.width)
+                   || mousePos->y < noPosZone->pos.y || mousePos->y > (noPosZone->pos.y + noPosZone->size.height)) {
+                       /* send position if out of zone defined by destination */
+                       return sendDnDClientMessage(info, scr->xdndPositionAtom,
+                                                   0,
+                                                   mousePos->x << 16 | mousePos->y,
+                                                   XDND_TIMESTAMP(info), XDND_SOURCE_ACTION(info));
+               }
+
+               /* Nothing to send, always succeed */
+               return True;
+
+       }
+
+       /* send position on each move */
+       return sendDnDClientMessage(info, scr->xdndPositionAtom,
+                                   0,
+                                   mousePos->x << 16 | mousePos->y,
+                                   XDND_TIMESTAMP(info), XDND_SOURCE_ACTION(info));
+}
+
+static Bool sendLeaveMessage(WMDraggingInfo * info)
+{
+       WMScreen *scr = sourceScreen(info);
+
+       return sendDnDClientMessage(info, scr->xdndLeaveAtom, 0, 0, 0, 0);
+}
+
+static Bool sendDropMessage(WMDraggingInfo * info)
+{
+       WMScreen *scr = sourceScreen(info);
+
+       return sendDnDClientMessage(info, scr->xdndDropAtom, 0, XDND_TIMESTAMP(info), 0, 0);
+}
+
+/* ----- end of messages ----- */
+
+static Atom *getTypeAtomList(WMScreen * scr, WMView * view, int *count)
+{
+       WMArray *types;
+       Atom *typeAtoms;
+       int i;
+
+       types = view->dragSourceProcs->dropDataTypes(view);
+
+       if (types != NULL) {
+               *count = WMGetArrayItemCount(types);
+               if (*count > 0) {
+                       typeAtoms = wmalloc((*count) * sizeof(Atom));
+                       for (i = 0; i < *count; i++) {
+                               typeAtoms[i] = XInternAtom(scr->display, WMGetFromArray(types, i), False);
+                       }
+
+                       /* WMFreeArray(types); */
+                       return typeAtoms;
+               }
+
+               /* WMFreeArray(types); */
+       }
+
+       *count = 1;
+       typeAtoms = wmalloc(sizeof(Atom));
+       *typeAtoms = None;
+
+       return typeAtoms;
+}
+
+static void registerDropTypes(WMScreen * scr, WMView * view, WMDraggingInfo * info)
+{
+       Atom *typeList;
+       int i, count;
+
+       typeList = getTypeAtomList(scr, view, &count);
+
+       /* store the first 3 types */
+       for (i = 0; i < 3 && i < count; i++)
+               XDND_3_TYPES(info)[i] = typeList[i];
+
+       for (; i < 3; i++)
+               XDND_3_TYPES(info)[i] = None;
+
+       /* store the entire type list */
+       XChangeProperty(scr->display,
+                       WMViewXID(view),
+                       scr->xdndTypeListAtom,
+                       XA_ATOM, XDND_PROPERTY_FORMAT, PropModeReplace, (unsigned char *)typeList, count);
+}
+
+static void registerOperationList(WMScreen * scr, WMView * view, WMArray * operationArray)
+{
+       Atom *actionList;
+       WMDragOperationType operation;
+       int count = WMGetArrayItemCount(operationArray);
+       int i;
+
+       actionList = wmalloc(sizeof(Atom) * count);
+
+       for (i = 0; i < count; i++) {
+               operation = WMGetDragOperationItemType(WMGetFromArray(operationArray, i));
+               actionList[i] = W_OperationToAction(scr, operation);
+       }
+
+       XChangeProperty(scr->display,
+                       WMViewXID(view),
+                       scr->xdndActionListAtom,
+                       XA_ATOM, XDND_PROPERTY_FORMAT, PropModeReplace, (unsigned char *)actionList, count);
+}
+
+static void registerDescriptionList(WMScreen * scr, WMView * view, WMArray * operationArray)
+{
+       char *text, *textListItem, *textList;
+       int count = WMGetArrayItemCount(operationArray);
+       int i;
+       int size = 0;
+
+       /* size of XA_STRING info */
+       for (i = 0; i < count; i++) {
+               size += strlen(WMGetDragOperationItemText(WMGetFromArray(operationArray, i))) + 1;      /* +1 = +NULL */
+       }
+
+       /* create text list */
+       textList = wmalloc(size);
+       textListItem = textList;
+
+       for (i = 0; i < count; i++) {
+               text = WMGetDragOperationItemText(WMGetFromArray(operationArray, i));
+               strcpy(textListItem, text);
+
+               /* to next text offset */
+               textListItem = &(textListItem[strlen(textListItem) + 1]);
+       }
+
+       XChangeProperty(scr->display,
+                       WMViewXID(view),
+                       scr->xdndActionDescriptionAtom,
+                       XA_STRING,
+                       XDND_ACTION_DESCRIPTION_FORMAT, PropModeReplace, (unsigned char *)textList, size);
+}
+
+/* called if wanted operation is WDOperationAsk */
+static void registerSupportedOperations(WMView * view)
+{
+       WMScreen *scr = W_VIEW_SCREEN(view);
+       WMArray *operationArray;
+
+       operationArray = view->dragSourceProcs->askedOperations(view);
+
+       registerOperationList(scr, view, operationArray);
+       registerDescriptionList(scr, view, operationArray);
+
+       /* WMFreeArray(operationArray); */
+}
+
+static void initSourceDragInfo(WMView * sourceView, WMDraggingInfo * info)
+{
+       WMRect emptyZone;
+
+       XDND_SOURCE_INFO(info) = (W_DragSourceInfo *) wmalloc(sizeof(W_DragSourceInfo));
+
+       XDND_SOURCE_VIEW(info) = sourceView;
+       XDND_DEST_WIN(info) = None;
+       XDND_DRAG_ICON(info) = None;
+
+       XDND_SOURCE_ACTION(info) = W_OperationToAction(W_VIEW_SCREEN(sourceView),
+                                                      sourceView->dragSourceProcs->
+                                                      wantedDropOperation(sourceView));
+
+       XDND_DEST_ACTION(info) = None;
+
+       XDND_SOURCE_STATE(info) = idleState;
+
+       emptyZone.pos = wmkpoint(0, 0);
+       emptyZone.size = wmksize(0, 0);
+       XDND_NO_POS_ZONE(info) = emptyZone;
+}
+
+/*
+ Returned array is destroyed after dropDataTypes call
+ */
+static WMArray *defDropDataTypes(WMView * self)
+{
+       return NULL;
+}
+
+static WMDragOperationType defWantedDropOperation(WMView * self)
+{
+       return WDOperationNone;
+}
+
+/*
+ Must be defined if wantedDropOperation return WDOperationAsk
+ (useless otherwise).
+ Return a WMDragOperationItem array (destroyed after call).
+ A WMDragOperationItem links a label to an operation.
+ static WMArray*
+ defAskedOperations(WMView *self); */
+
+static Bool defAcceptDropOperation(WMView * self, WMDragOperationType allowedOperation)
+{
+       return False;
+}
+
+static void defBeganDrag(WMView * self, WMPoint * point)
+{
+}
+
+static void defEndedDrag(WMView * self, WMPoint * point, Bool deposited)
+{
+}
+
+/*
+ Returned data is not destroyed
+ */
+static WMData *defFetchDragData(WMView * self, char *type)
+{
+       return NULL;
+}
+
+void WMSetViewDragSourceProcs(WMView * view, WMDragSourceProcs * procs)
+{
+       if (view->dragSourceProcs)
+               wfree(view->dragSourceProcs);
+       view->dragSourceProcs = wmalloc(sizeof(WMDragSourceProcs));
+
+       *view->dragSourceProcs = *procs;
+
+       if (procs->dropDataTypes == NULL)
+               view->dragSourceProcs->dropDataTypes = defDropDataTypes;
+
+       if (procs->wantedDropOperation == NULL)
+               view->dragSourceProcs->wantedDropOperation = defWantedDropOperation;
+
+       /*
+          Note: askedOperations can be NULL, if wantedDropOperation never returns
+          WDOperationAsk.
+        */
+
+       if (procs->acceptDropOperation == NULL)
+               view->dragSourceProcs->acceptDropOperation = defAcceptDropOperation;
+
+       if (procs->beganDrag == NULL)
+               view->dragSourceProcs->beganDrag = defBeganDrag;
+
+       if (procs->endedDrag == NULL)
+               view->dragSourceProcs->endedDrag = defEndedDrag;
+
+       if (procs->fetchDragData == NULL)
+               view->dragSourceProcs->fetchDragData = defFetchDragData;
+}
+
+static Bool isXdndAware(WMScreen * scr, Window win)
+{
+       Atom type;
+       int format;
+       unsigned long count, remain;
+       unsigned char *winXdndVersion;
+
+       if (win == None)
+               return False;
+
+       XGetWindowProperty(scr->display, win, scr->xdndAwareAtom,
+                          0, 1, False, XA_ATOM, &type, &format, &count, &remain, &winXdndVersion);
+
+       if (type != XA_ATOM || format != XDND_PROPERTY_FORMAT || count == 0 || !winXdndVersion) {
+               if (winXdndVersion)
+                       XFree(winXdndVersion);
+               return False;
+       }
+
+       XFree(winXdndVersion);
+       return (count == 1);    /* xdnd version is set */
+}
+
+static Window *windowChildren(Display * dpy, Window win, unsigned *nchildren)
+{
+       Window *children;
+       Window foo, bar;
+
+       if (!XQueryTree(dpy, win, &foo, &bar, &children, nchildren)) {
+               *nchildren = 0;
+               return NULL;
+       } else
+               return children;
+}
+
+static Window lookForAwareWindow(WMScreen * scr, WMPoint * mousePos, Window win)
+{
+       int tmpx, tmpy;
+       Window child;
+
+       /* Since xdnd v3, only the toplevel window should be aware */
+       if (isXdndAware(scr, win))
+               return win;
+
+       /* inspect child under pointer */
+       if (XTranslateCoordinates(scr->display, scr->rootWin, win, mousePos->x, mousePos->y, &tmpx, &tmpy, &child)) {
+               if (child == None)
+                       return None;
+               else
+                       return lookForAwareWindow(scr, mousePos, child);
+       }
+
+       return None;
+}
+
+static Window findDestination(WMDraggingInfo * info, WMPoint * mousePos)
+{
+       WMScreen *scr = sourceScreen(info);
+       unsigned nchildren;
+       Window *children = windowChildren(scr->display, scr->rootWin, &nchildren);
+       int i;
+       XWindowAttributes attr;
+
+       if (isXdndAware(scr, scr->rootWin))
+               return scr->rootWin;
+
+       /* exclude drag icon (and upper) from search */
+       for (i = nchildren - 1; i >= 0; i--) {
+               if (children[i] == XDND_DRAG_ICON(info)) {
+                       i--;
+                       break;
+               }
+       }
+
+       if (i < 0) {
+               /* root window has no child under drag icon, and is not xdnd aware. */
+               return None;
+       }
+
+       /* inspecting children, from upper to lower */
+       for (; i >= 0; i--) {
+               if (XGetWindowAttributes(scr->display, children[i], &attr)
+                   && attr.map_state == IsViewable
+                   && mousePos->x >= attr.x
+                   && mousePos->y >= attr.y
+                   && mousePos->x < attr.x + attr.width && mousePos->y < attr.y + attr.height) {
+                       return lookForAwareWindow(scr, mousePos, children[i]);
+               }
+       }
+
+       /* No child window under drag pointer */
+       return None;
+}
+
+static void storeDestinationProtocolVersion(WMDraggingInfo * info)
+{
+       Atom type;
+       int format;
+       unsigned long count, remain;
+       unsigned char *winXdndVersion;
+       WMScreen *scr = W_VIEW_SCREEN(XDND_SOURCE_VIEW(info));
+
+       wassertr(XDND_DEST_WIN(info) != None);
+
+       if (XGetWindowProperty(scr->display, XDND_DEST_WIN(info),
+                              scr->xdndAwareAtom,
+                              0, 1, False, XA_ATOM, &type, &format,
+                              &count, &remain, &winXdndVersion) == Success) {
+               XDND_DEST_VERSION(info) = *winXdndVersion;
+               XFree(winXdndVersion);
+       } else {
+               XDND_DEST_VERSION(info) = 0;
+               wwarning("failed to read XDND version of drop target");
+       }
+}
+
+static void initMotionProcess(WMView * view, WMDraggingInfo * info, XEvent * event, WMPoint * startLocation)
+{
+       WMScreen *scr = W_VIEW_SCREEN(view);
+
+       /* take ownership of XdndSelection */
+       XDND_SELECTION_PROCS(info) = (WMSelectionProcs *) wmalloc(sizeof(WMSelectionProcs));
+       XDND_SELECTION_PROCS(info)->convertSelection = convertSelection;
+       XDND_SELECTION_PROCS(info)->selectionLost = selectionLost;
+       XDND_SELECTION_PROCS(info)->selectionDone = selectionDone;
+       XDND_TIMESTAMP(info) = event->xmotion.time;
+
+       if (!WMCreateSelectionHandler(view, scr->xdndSelectionAtom, CurrentTime, XDND_SELECTION_PROCS(info), NULL)) {
+               wwarning("could not get ownership or DND selection");
+               return;
+       }
+
+       registerDropTypes(scr, view, info);
+
+       if (XDND_SOURCE_ACTION(info) == W_VIEW_SCREEN(view)->xdndActionAsk)
+               registerSupportedOperations(view);
+
+       if (view->dragSourceProcs->beganDrag != NULL) {
+               view->dragSourceProcs->beganDrag(view, startLocation);
+       }
+}
+
+static void processMotion(WMDraggingInfo * info, WMPoint * mousePos)
+{
+       Window newDestination = findDestination(info, mousePos);
+
+       W_DragSourceStopTimer();
+
+       if (newDestination != XDND_DEST_WIN(info)) {
+               recolorCursor(info, False);
+
+               if (XDND_DEST_WIN(info) != None) {
+                       /* leaving a xdnd window */
+                       sendLeaveMessage(info);
+               }
+
+               XDND_DEST_WIN(info) = newDestination;
+               XDND_DEST_ACTION(info) = None;
+               XDND_NO_POS_ZONE(info).size.width = 0;
+               XDND_NO_POS_ZONE(info).size.height = 0;
+
+               if (newDestination != None) {
+                       /* entering a xdnd window */
+                       XDND_SOURCE_STATE(info) = idleState;
+                       storeDestinationProtocolVersion(info);
+
+                       if (!sendEnterMessage(info)) {
+                               XDND_DEST_WIN(info) = None;
+                               return;
+                       }
+
+                       W_DragSourceStartTimer(info);
+               } else {
+                       XDND_SOURCE_STATE(info) = NULL;
+               }
+       } else {
+               if (XDND_DEST_WIN(info) != None) {
+                       if (!sendPositionMessage(info, mousePos)) {
+                               XDND_DEST_WIN(info) = None;
+                               return;
+                       }
+
+                       W_DragSourceStartTimer(info);
+               }
+       }
+}
+
+static Bool processButtonRelease(WMDraggingInfo * info)
+{
+       if (XDND_SOURCE_STATE(info) == dropAllowedState) {
+               /* begin drop */
+               W_DragSourceStopTimer();
+
+               if (!sendDropMessage(info))
+                       return False;
+
+               W_DragSourceStartTimer(info);
+               return True;
+       } else {
+               if (XDND_DEST_WIN(info) != None)
+                       sendLeaveMessage(info);
+
+               W_DragSourceStopTimer();
+               return False;
+       }
+}
+
+Bool WMIsDraggingFromView(WMView * view)
+{
+       WMDraggingInfo *info = &W_VIEW_SCREEN(view)->dragInfo;
+
+       return (XDND_SOURCE_INFO(info) != NULL && XDND_SOURCE_STATE(info) != finishDropState);
+       /* return W_VIEW_SCREEN(view)->dragInfo.sourceInfo != NULL; */
+}
+
+void WMDragImageFromView(WMView * view, XEvent * event)
+{
+       WMDraggingInfo *info = &W_VIEW_SCREEN(view)->dragInfo;
+       WMPoint mouseLocation;
+
+       switch (event->type) {
+       case ButtonPress:
+               if (event->xbutton.button == Button1) {
+                       XEvent nextEvent;
+
+                       XPeekEvent(event->xbutton.display, &nextEvent);
+
+                       /* Initialize only if a drag really begins (avoid clicks) */
+                       if (nextEvent.type == MotionNotify) {
+                               initSourceDragInfo(view, info);
+                       }
+               }
+
+               break;
+
+       case ButtonRelease:
+               if (WMIsDraggingFromView(view)) {
+                       Bool dropBegan = processButtonRelease(info);
+
+                       recolorCursor(info, False);
+                       if (dropBegan) {
+                               endDragImage(info, False);
+                               XDND_SOURCE_STATE(info) = finishDropState;
+                       } else {
+                               /* drop failed */
+                               endDragImage(info, True);
+                               endDragProcess(info, False);
+                       }
+               }
+               break;
+
+       case MotionNotify:
+               if (WMIsDraggingFromView(view)) {
+                       mouseLocation = wmkpoint(event->xmotion.x_root, event->xmotion.y_root);
+
+                       if (abs(XDND_DRAG_ICON_POS(info).x - mouseLocation.x) >=
+                           MIN_X_MOVE_OFFSET
+                           || abs(XDND_DRAG_ICON_POS(info).y - mouseLocation.y) >= MIN_Y_MOVE_OFFSET) {
+                               if (XDND_DRAG_ICON(info) == None) {
+                                       initMotionProcess(view, info, event, &mouseLocation);
+                                       startDragImage(view, info, event);
+                               } else {
+                                       XDND_DRAG_ICON_POS(info).x = mouseLocation.x - XDND_MOUSE_OFFSET(info).x;
+                                       XDND_DRAG_ICON_POS(info).y = mouseLocation.y - XDND_MOUSE_OFFSET(info).y;
+
+                                       refreshDragImage(view, info);
+                                       processMotion(info, &mouseLocation);
+                               }
+                       }
+               }
+               break;
+       }
+}
+
+/* Minimal mouse events handler: no right or double-click detection,
+ only drag is supported */
+static void dragImageHandler(XEvent * event, void *cdata)
+{
+       WMView *view = (WMView *) cdata;
+
+       WMDragImageFromView(view, event);
+}
+
+/* ----- source states ----- */
+
+#ifdef XDND_DEBUG
+static void traceStatusMsg(Display * dpy, XClientMessageEvent * statusEvent)
+{
+       printf("Xdnd status message:\n");
+
+       if (statusEvent->data.l[1] & 0x2UL)
+               printf("\tsend position on every move\n");
+       else {
+               int x, y, w, h;
+               x = statusEvent->data.l[2] >> 16;
+               y = statusEvent->data.l[2] & 0xFFFFL;
+               w = statusEvent->data.l[3] >> 16;
+               h = statusEvent->data.l[3] & 0xFFFFL;
+
+               printf("\tsend position out of ((%d,%d) , (%d,%d))\n", x, y, x + w, y + h);
+       }
+
+       if (statusEvent->data.l[1] & 0x1L)
+               printf("\tallowed action: %s\n", XGetAtomName(dpy, statusEvent->data.l[4]));
+       else
+               printf("\tno action allowed\n");
+}
+#endif
+
+static void storeDropAction(WMDraggingInfo * info, Atom destAction)
+{
+       WMView *sourceView = XDND_SOURCE_VIEW(info);
+       WMScreen *scr = W_VIEW_SCREEN(sourceView);
+
+       if (sourceView->dragSourceProcs->acceptDropOperation != NULL) {
+               if (sourceView->dragSourceProcs->acceptDropOperation(sourceView,
+                                                                    W_ActionToOperation(scr, destAction)))
+                       XDND_DEST_ACTION(info) = destAction;
+               else
+                       XDND_DEST_ACTION(info) = None;
+       } else {
+               XDND_DEST_ACTION(info) = destAction;
+       }
+}
+
+static void storeStatusMessageInfos(WMDraggingInfo * info, XClientMessageEvent * statusEvent)
+{
+       WMRect *noPosZone = &(XDND_NO_POS_ZONE(info));
+
+#ifdef XDND_DEBUG
+
+       traceStatusMsg(sourceScreen(info)->display, statusEvent);
+#endif
+
+       if (statusEvent->data.l[1] & 0x2UL) {
+               /* bit 1 set: destination wants position messages on every move */
+               noPosZone->size.width = 0;
+               noPosZone->size.height = 0;
+       } else {
+               /* don't send another position message while in given rectangle */
+               noPosZone->pos.x = statusEvent->data.l[2] >> 16;
+               noPosZone->pos.y = statusEvent->data.l[2] & 0xFFFFL;
+               noPosZone->size.width = statusEvent->data.l[3] >> 16;
+               noPosZone->size.height = statusEvent->data.l[3] & 0xFFFFL;
+       }
+
+       if ((statusEvent->data.l[1] & 0x1L) || statusEvent->data.l[4] != None) {
+               /* destination accept drop */
+               storeDropAction(info, statusEvent->data.l[4]);
+       } else {
+               XDND_DEST_ACTION(info) = None;
+       }
+}
+
+static void *idleState(WMView * view, XClientMessageEvent * event, WMDraggingInfo * info)
+{
+       WMScreen *scr;
+       Atom destMsg = event->message_type;
+
+       scr = W_VIEW_SCREEN(view);
+
+       if (destMsg == scr->xdndStatusAtom) {
+               storeStatusMessageInfos(info, event);
+
+               if (XDND_DEST_ACTION(info) != None) {
+                       recolorCursor(info, True);
+                       W_DragSourceStartTimer(info);
+                       return dropAllowedState;
+               } else {
+                       /* drop denied */
+                       recolorCursor(info, False);
+                       return idleState;
+               }
+       }
+
+       if (destMsg == scr->xdndFinishedAtom) {
+               wwarning("received xdndFinishedAtom before drop began");
+       }
+
+       W_DragSourceStartTimer(info);
+       return idleState;
+}
+
+static void *dropAllowedState(WMView * view, XClientMessageEvent * event, WMDraggingInfo * info)
+{
+       WMScreen *scr = W_VIEW_SCREEN(view);
+       Atom destMsg = event->message_type;
+
+       if (destMsg == scr->xdndStatusAtom) {
+               storeStatusMessageInfos(info, event);
+
+               if (XDND_DEST_ACTION(info) == None) {
+                       /* drop denied */
+                       recolorCursor(info, False);
+                       return idleState;
+               }
+       }
+
+       W_DragSourceStartTimer(info);
+       return dropAllowedState;
+}
+
+static void *finishDropState(WMView * view, XClientMessageEvent * event, WMDraggingInfo * info)
+{
+       WMScreen *scr = W_VIEW_SCREEN(view);
+       Atom destMsg = event->message_type;
+
+       if (destMsg == scr->xdndFinishedAtom) {
+               endDragProcess(info, True);
+               return NULL;
+       }
+
+       W_DragSourceStartTimer(info);
+       return finishDropState;
+}
+
+/* ----- end of source states ----- */
+
+/* ----- source timer ----- */
+static void dragSourceResponseTimeOut(void *source)
+{
+       WMView *view = (WMView *) source;
+       WMDraggingInfo *info = &(W_VIEW_SCREEN(view)->dragInfo);
+
+       wwarning("delay for drag destination response expired");
+       sendLeaveMessage(info);
+
+       recolorCursor(info, False);
+       if (XDND_SOURCE_STATE(info) == finishDropState) {
+               /* drop failed */
+               endDragImage(info, True);
+               endDragProcess(info, False);
+       } else {
+               XDND_SOURCE_STATE(info) = idleState;
+       }
+}
+
+void W_DragSourceStopTimer()
+{
+       if (dndSourceTimer != NULL) {
+               WMDeleteTimerHandler(dndSourceTimer);
+               dndSourceTimer = NULL;
+       }
+}
+
+void W_DragSourceStartTimer(WMDraggingInfo * info)
+{
+       W_DragSourceStopTimer();
+
+       dndSourceTimer = WMAddTimerHandler(XDND_DESTINATION_RESPONSE_MAX_DELAY,
+                                          dragSourceResponseTimeOut, XDND_SOURCE_VIEW(info));
+}
+
+/* ----- End of Destination timer ----- */
+
+void W_DragSourceStateHandler(WMDraggingInfo * info, XClientMessageEvent * event)
+{
+       WMView *view;
+       W_DndState *newState;
+
+       if (XDND_SOURCE_VIEW_STORED(info)) {
+               if (XDND_SOURCE_STATE(info) != NULL) {
+                       view = XDND_SOURCE_VIEW(info);
+#ifdef XDND_DEBUG
+
+                       printf("current source state: %s\n", stateName(XDND_SOURCE_STATE(info)));
+#endif
+
+                       newState = (W_DndState *) XDND_SOURCE_STATE(info) (view, event, info);
+
+#ifdef XDND_DEBUG
+
+                       printf("new source state: %s\n", stateName(newState));
+#endif
+
+                       if (newState != NULL)
+                               XDND_SOURCE_STATE(info) = newState;
+                       /* else drop finished, and info has been flushed */
+               }
+
+       } else {
+               wwarning("received DnD message without having a target");
+       }
+}
+
+void WMSetViewDragImage(WMView * view, WMPixmap * dragImage)
+{
+       if (view->dragImage != NULL)
+               WMReleasePixmap(view->dragImage);
+
+       view->dragImage = WMRetainPixmap(dragImage);
+}
+
+void WMReleaseViewDragImage(WMView * view)
+{
+       if (view->dragImage != NULL)
+               WMReleasePixmap(view->dragImage);
+}
+
+/* Create a drag handler, associating drag event masks with dragEventProc */
+void WMCreateDragHandler(WMView * view, WMEventProc * dragEventProc, void *clientData)
+{
+       WMCreateEventHandler(view,
+                            ButtonPressMask | ButtonReleaseMask | Button1MotionMask, dragEventProc, clientData);
+}
+
+void WMDeleteDragHandler(WMView * view, WMEventProc * dragEventProc, void *clientData)
+{
+       WMDeleteEventHandler(view,
+                            ButtonPressMask | ButtonReleaseMask | Button1MotionMask, dragEventProc, clientData);
+}
+
+/* set default drag handler for view */
+void WMSetViewDraggable(WMView * view, WMDragSourceProcs * dragSourceProcs, WMPixmap * dragImage)
+{
+       wassertr(dragImage != NULL);
+       view->dragImage = WMRetainPixmap(dragImage);
+
+       WMSetViewDragSourceProcs(view, dragSourceProcs);
+
+       WMCreateDragHandler(view, dragImageHandler, view);
+}
+
+void WMUnsetViewDraggable(WMView * view)
+{
+       if (view->dragSourceProcs) {
+               wfree(view->dragSourceProcs);
+               view->dragSourceProcs = NULL;
+       }
+
+       WMReleaseViewDragImage(view);
+
+       WMDeleteDragHandler(view, dragImageHandler, view);
+}