I thought the folks on this list should see this guy's comment regarding XDnD and GNUstep
--- Begin Message --- Hi,
Here's a patch to fix WINGs drag'n drop with GDK based apps.
It is made from the 2005-04-09 snapshot. The patched files are WINGsP.h, dragcommon.c, dragsource.c and dragdestination.c. Along with this patch, i've attached the detailed changelog.
Now drag'n drop in WINGs should work with both KDE and GNOME (unfortunately, XDND versions 3 and up are not compatible with version 2, that's why it doesn't work with GNUstep -at least GWorkspace-).


I haven't included any fix for the possible crash (in the source, due to destination response timeout) i reported some time ago, because i think i made a mistake in the first place, using timers too heavily. The current XDND implementation will timeout each time the source spend a lot of time to provide the dropped data (like an archiver or a browser).
So i'll try now to patch drag'n drop to get rid of the timers.


thanks to the WindowMaker team for their work,
Sylvain.
----------------------
Summary of the problem
----------------------

On the source side:
- the source doesn't send the protocol version (it is not set).

- the source may receive a status message from a GDK target after having closed
the DnD dialog with the leave message.


On the destination side:
- GDK widgets start the dialog as soon as they enter the XDND aware widget,
even if this one was not registered for dnd;

- GDK widgets only deal with messages comming from the XDND aware widget,
not the messages comming from the subwidgets that were registered to handle dnd.

- WINGs doesn't reply to position messages once the drop is allowed or
rejected. This stall dnd dialog on GDK side, because the source send position
messages on every move (until the drop occurs or the source leaves the target),
waiting for target's reply, wich is never sent.


Note: this patch does not change the current dnd interface.


---------------
List of changes
---------------

WINGs/WINGsP.h
- set XDND_VERSION 3 (was 4, WINGs is not XDND v4 compliant yet)

- add xdndAwareView to W_DragDestinationInfo. GDK can only deals with
        the (xdnd aware) toplevel window. Store it, to avoid to retrieve it
        each time we send a message to the source.
        
- add boolean sourceActionChanged to W_DragDestinationInfo struct
        As source may send position message with a different action until drop,
        the destination must check if the drop is allowed each time the action
        changes.
        
- add comment on protocolVersion of W_DraggingInfo struct.



dragcommon.c
- rename VERSION_INFO macro as XDND_SOURCE_VERSION

- remove XDND_DEST_VIEW_STORED macro (not relevant now that we store
        even unregistered views).

- W_SendDnDClientMessage:
        Debug code added.

- handleLeaveMessage:
        Add condition in case of unregistered (XDND unaware) destination.
        
- W_HandleDNDClientMessage:
        Fix version checking (XDND v3 and up are not v1 or v2 compliant,
        whereas v4 and v5 are backward compatible with v3).

        

dragsource.c

- rename VERSION_INFO macro as XDND_DEST_VERSION.

- W_DragSourceStateHandler:
        Check if the message comes from the current target, because the source
        may receive a message from the previous GDK target, even if the dialog
        is over.

- sendEnterMessage:
        Send correct version (from xdndAware definition in XDND doc).

- sendPositionMessage:
        Return always something (thanks for the comment, Dan). Return True if
        no message had to be sent, considering it's always a success.
        Also correct mouse position checking (size.height replace the wrong
        size.width when checking y coordinate)
        
- storeDestinationProtocolVersion (new):
        Used in processMotion, if the source enters a new XDND aware 
destination.

- processMotion:
        To handle status message sent from a GDK target after a closed DnD 
dialog,
        set source state to NULL if it enters a non XDND window.
        See W_DragSourceStateHandler change below for more info.
        
        Set XDND_DEST_VERSION when source enters a new XDND aware destination.
        
- W_DragSourceStateHandler:
        As in processMotion, to handle post-dialog status messages, check if
        source state is not NULL before processing the message.
        note: checking if the message's window is the same as the stored 
destination
        doesn't work with KDE (for example in Konqueror, window id depends on 
the
        position of the cursor inside the xdnd aware widget).
        


dragdestination.c:
- rename VERSION_INFO macro as XDND_SOURCE_VERSION

- add XDND_SOURCE_ACTION_CHANGED macro (refers to sourceActionChanged,
        see WINGsP.h changes)

- add XDND_AWARE_VIEW macro (refers to xdndAwareView, see WINGsP.h changes)

- replace XDND_DEST_VIEW_STORED with XDND_DEST_VIEW_IS_REGISTERED (since
        findXdndViewInToplevel change implies that XDND_DEST_VIEW is never NULL,
        but can be an unregistered (XDND unaware) view.
        
- W_DragDestinationStoreEnterMsgInfo:
        Use initDestinationDragInfo with toplevel as destView parameter (see
        initDestinationDragInfo and findXdndViewInToplevel changes for more 
infos
        on this).
        
        Store the toplevel (xdnd aware) window. This is the only one that can be
        used to send messages to GDK.
        
- W_DragDestinationStorePositionMsgInfo:
        Store the toplevel (xdnd aware) window.
        
        Doesn't need to handle the "new destination is NULL" case anymore.

        Set the newly added sourceActionChanged

- W_DragDestinationCancelDropOnEnter:
        Handle unregistered destination case.

- sendDnDClientMessage:
        When calling W_SendDnDClientMessage, use the toplevel (xdnd aware) view,
        instead of the destination one.
        This allow to change sendDnDClientMessage, replacing the WMView* 
parameter
        with a WMDraggingInfo* one, to conform to the sendDnDClientMessage 
signature
        defined in dragsource, and hide a little more the datas. This implies 
minor
        changes on dragdestination.c static function signatures.

- sendStatusMessage (new):
        This function is used wherever a status message needs to be sent.
        It manage the coordinates part of the message, to reduce XDND dialog.
        if the destination has no subwidget, it send the widget position and 
size,
        otherwise it request a position message on every move.

- sendAllowedAction:
        Removed (it's reduced to one line with use of sendStatusMessage. Call
        directly this one in checkActionAllowed).
        
- findXdndViewInToplevel (renamed as findDestinationViewInToplevel):
        To work with GDK, findXdndViewInToplevel return the view directly under
        the drag icon (not the registered view or NULL if none). This function
        is renamed findDestinationViewInToplevel, and never return NULL.
        Now, the destination view stored in WMDraggingInfo may not be 
registered.
        
- findChildInWindow (renamed as findChildInView)
        Following findXdndViewInToplevel changes (may be it was also possible
        before), use WINGs view's childrenList to find the view under
        the pointer instead of X functions. This speeds the things quite a lot
        (approx. x5 according to a quick profiling). With the increase of
        position/status messages, this is really needed.
        
- initDestinationDragInfo:
        Following findXdndViewInToplevel change, we can set destView to toplevel
        on "enter" message". Now destView is always defined.
        
        Set newly added sourceActionChanged to False.

- W_DragDestinationStartTimer:
        Remove (XDND_DEST_VIEW(info) == NULL) test (always false, see
        initDestinationDragInfo change).

- idleState:
        Handle the case where the destination is not registered.

- dropAllowedState and dropNotAllowedState:
        Reply to xdndPosition messages. Recheck if drop is allowed if the action
        has changed.

- W_DragDestinationStateHandler:
        remove now useless XDND_DEST_VIEW_STORED test (see 
initDestinationDragInfo),
        replaced with assertions.
        
- storeRequiredTypeList:
        Retrieve the type list (if needed) only once and store it.

diff -ur WindowMaker-0.92.0/WINGs/dragcommon.c WindowMaker-0.92.0-patch/WINGs/dragcommon.c
--- WindowMaker-0.92.0/WINGs/dragcommon.c	2004-10-28 11:25:23.000000000 +0200
+++ WindowMaker-0.92.0-patch/WINGs/dragcommon.c	2005-04-18 19:03:07.710964296 +0200
@@ -2,11 +2,9 @@
 
 #include "WINGsP.h"
 
-#define VERSION_INFO(dragInfo) dragInfo->protocolVersion
+#define XDND_SOURCE_VERSION(dragInfo) dragInfo->protocolVersion
 #define XDND_DEST_INFO(dragInfo) dragInfo->destInfo
 #define XDND_DEST_VIEW(dragInfo) dragInfo->destInfo->destView
-#define XDND_DEST_VIEW_STORED(dragInfo) ((dragInfo->destInfo) != NULL)\
-    && ((dragInfo->destInfo->destView) != NULL)
 
 
 static Bool _WindowExists;
@@ -151,6 +149,13 @@
 {
     XEvent ev;
 
+#ifdef XDND_DEBUG
+    char* msgName = XGetAtomName(dpy, message);
+
+    printf("sending message %s ... ", msgName);
+    XFree(msgName);
+#endif
+
     if (! windowExists(dpy, win)) {
         wwarning("xdnd message target %d does no longer exist.", win);
         return False; /* message not sent */
@@ -170,6 +175,9 @@
     XSendEvent(dpy, win, False, 0, &ev);
     XFlush(dpy);
 
+#ifdef XDND_DEBUG
+    printf("sent\n");
+#endif
     return True; /* message sent */
 }
 
@@ -178,7 +186,9 @@
 handleLeaveMessage(WMDraggingInfo *info)
 {
     if (XDND_DEST_INFO(info) != NULL) {
-        if (XDND_DEST_VIEW(info) != NULL) {
+        /* XDND_DEST_VIEW is never NULL (it's the xdnd aware view) */
+        wassertr(XDND_DEST_VIEW(info) != NULL);
+        if (XDND_DEST_VIEW(info)->dragDestinationProcs != NULL) {
             XDND_DEST_VIEW(info)->dragDestinationProcs->concludeDragOperation(
                                                                               XDND_DEST_VIEW(info));
         }
@@ -216,11 +226,15 @@
 
     /* Messages from source to destination */
     if (messageType == scr->xdndEnterAtom) {
+        Bool positionSent = (XDND_DEST_INFO(info) != NULL);
+
         W_DragDestinationStopTimer();
         W_DragDestinationStoreEnterMsgInfo(info, toplevel, event);
 
-        if (VERSION_INFO(info) <= XDND_VERSION) {
-            if (XDND_DEST_VIEW_STORED(info)) {
+        /* Xdnd version 3 and up are not compatible with version 1 or 2 */
+        if (XDND_SOURCE_VERSION(info) > 2) {
+
+            if (positionSent) {
                 /* xdndPosition previously received on xdnd aware view */
                 W_DragDestinationStateHandler(info, event);
                 return;
@@ -230,7 +244,7 @@
             }
         } else {
             wwarning("received dnd enter msg with unsupported version %i",
-                     VERSION_INFO(info));
+                     XDND_SOURCE_VERSION(info));
             W_DragDestinationCancelDropOnEnter(toplevel, info);
             return;
         }
diff -ur WindowMaker-0.92.0/WINGs/dragdestination.c WindowMaker-0.92.0-patch/WINGs/dragdestination.c
--- WindowMaker-0.92.0/WINGs/dragdestination.c	2004-10-28 11:25:36.000000000 +0200
+++ WindowMaker-0.92.0-patch/WINGs/dragdestination.c	2005-04-18 19:03:07.712963992 +0200
@@ -5,15 +5,16 @@
 
 #define XDND_SOURCE_RESPONSE_MAX_DELAY 3000
 
-#define VERSION_INFO(dragInfo) dragInfo->protocolVersion
-
 #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
@@ -22,8 +23,8 @@
 #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_STORED(dragInfo) ((dragInfo->destInfo) != NULL)\
-    && ((dragInfo->destInfo->destView) != NULL)
+#define XDND_DEST_VIEW_IS_REGISTERED(dragInfo) ((dragInfo->destInfo) != NULL)\
+    && ((dragInfo->destInfo->destView->dragDestinationProcs) != NULL)
 
 
 static unsigned char XDNDversion = XDND_VERSION;
@@ -81,7 +82,6 @@
 static WMArray*
 getTypesFromTypeList(WMScreen *scr, Window sourceWin)
 {
-    /* // WMDraggingInfo *info = &scr->dragInfo;*/
     Atom dataType;
     Atom* typeAtomList;
     WMArray* typeList;
@@ -138,22 +138,29 @@
     WMScreen *scr = W_VIEW_SCREEN(destView);
     WMArray *requiredTypes;
 
-    /* First, see if the 3 source types are enough for dest requirements */
+    /* 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 3 source types fits, get the whole type list */
+        /* 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)),
-                                                              getTypesFromTypeList(scr, XDND_SOURCE_WIN(info)));
+                                                              XDND_SOURCE_TYPES(info));
     }
 
-
     XDND_REQUIRED_TYPES(info) = requiredTypes;
 }
 
@@ -249,47 +256,35 @@
 }
 
 
-static Window
-findChildInWindow(Display *dpy, Window toplevel, int x, int y)
+static WMView*
+findChildInView(WMView* parent, int x, int y)
 {
-    Window foo, bar;
-    Window *children;
-    unsigned nchildren;
-    int i;
+    if (parent->childrenList == NULL)
+        return parent;
+    else {
+        WMView* child = parent->childrenList;
 
-    if (!XQueryTree(dpy, toplevel, &foo, &bar,
-                    &children, &nchildren) || children == NULL) {
-        return None;
-    }
-
-    /* first window that contains the point is the one */
-    for (i = nchildren-1; i >= 0; i--) {
-        XWindowAttributes attr;
-
-        if (XGetWindowAttributes(dpy, children[i], &attr)
-            && attr.map_state == IsViewable
-            && x >= attr.x && y >= attr.y
-            && x < attr.x + attr.width && y < attr.y + attr.height) {
-            Window child, tmp;
-
-            tmp = children[i];
-            child = findChildInWindow(dpy, tmp, x - attr.x, y - attr.y);
-            XFree(children);
-
-            if (child == None)
-                return tmp;
-            else
-                return child;
-        }
+        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);
     }
-
-    XFree(children);
-    return None;
 }
 
 
 static WMView*
-findXdndViewInToplevel(WMView* toplevel, int x, int y)
+findDestinationViewInToplevel(WMView* toplevel, int x, int y)
 {
     WMScreen *scr = W_VIEW_SCREEN(toplevel);
     Window toplevelWin = WMViewXID(toplevel);
@@ -300,20 +295,7 @@
     XTranslateCoordinates(scr->display, scr->rootWin, toplevelWin,
                           x, y, &xInToplevel, &yInToplevel,
                           &foo);
-
-    child = findChildInWindow(scr->display, toplevelWin,
-                              xInToplevel, yInToplevel);
-
-    if (child != None) {
-        childView = W_GetViewForXWindow(scr->display, child);
-
-        /* if childView supports Xdnd, return childView */
-        if (childView != NULL
-            && childView->dragDestinationProcs != NULL)
-            return childView;
-    }
-
-    return NULL;
+    return findChildInView(toplevel, xInToplevel, yInToplevel);
 }
 
 
@@ -334,6 +316,7 @@
     XDND_REQUIRED_TYPES(info) = NULL;
 }
 
+
 void
 W_DragDestinationInfoClear(WMDraggingInfo *info)
 {
@@ -347,15 +330,19 @@
     }
 }
 
+
 static void
-initDestinationDragInfo(WMDraggingInfo *info)
+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) = NULL;
+    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;
@@ -369,13 +356,19 @@
     WMScreen *scr = W_VIEW_SCREEN(toplevel);
 
     if (XDND_DEST_INFO(info) == NULL)
-        initDestinationDragInfo(info);
+        initDestinationDragInfo(info, toplevel);
 
+    XDND_SOURCE_VERSION(info) = (event->data.l[1] >> 24);
+    XDND_AWARE_VIEW(info) = toplevel;
     updateSourceWindow(info, event);
 
-    /* store xdnd version for source */
-    info->protocolVersion = (event->data.l[1] >> 24);
-
+/*
+    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 */
@@ -383,45 +376,30 @@
 }
 
 
-static void
-cancelDrop(WMView *destView, WMDraggingInfo *info);
-
-static void
-suspendDropAuthorization(WMView *destView, WMDraggingInfo *info);
-
-
 void
-    W_DragDestinationStorePositionMsgInfo(WMDraggingInfo *info,
-                                          WMView *toplevel, XClientMessageEvent *event)
+W_DragDestinationStorePositionMsgInfo(WMDraggingInfo *info,
+                                      WMView *toplevel, XClientMessageEvent *event)
 {
     int x = event->data.l[2] >> 16;
     int y = event->data.l[2] & 0xffff;
-    WMView *oldDestView;
     WMView *newDestView;
 
-    newDestView = findXdndViewInToplevel(toplevel, x, y);
+    newDestView = findDestinationViewInToplevel(toplevel, x, y);
 
     if (XDND_DEST_INFO(info) == NULL) {
-        initDestinationDragInfo(info);
+        initDestinationDragInfo(info, newDestView);
+        XDND_AWARE_VIEW(info) = toplevel;
         updateSourceWindow(info, event);
-        XDND_DEST_VIEW(info) = newDestView;
-    }
-    else {
-        oldDestView = XDND_DEST_VIEW(info);
-
-        if (newDestView != oldDestView) {
-            if (oldDestView != NULL) {
-                suspendDropAuthorization(oldDestView, info);
-                XDND_DEST_STATE(info) = dropNotAllowedState;
-            }
-
+    } else {
+        if (newDestView != XDND_DEST_VIEW(info)) {
             updateSourceWindow(info, event);
             XDND_DEST_VIEW(info) = newDestView;
+            XDND_SOURCE_ACTION_CHANGED(info) = False;
 
-            if (newDestView != NULL) {
-                if (XDND_DEST_STATE(info) != waitEnterState)
-                    XDND_DEST_STATE(info) = idleState;
-            }
+            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]);
         }
     }
 
@@ -437,27 +415,62 @@
 
 /* send a DnD message to the source window */
 static void
-sendDnDClientMessage(WMView *destView, Atom message,
+sendDnDClientMessage(WMDraggingInfo *info, Atom message,
                      unsigned long data1,
                      unsigned long data2,
                      unsigned long data3,
                      unsigned long data4)
 {
-    WMScreen *scr = W_VIEW_SCREEN(destView);
-    WMDraggingInfo *info = &scr->dragInfo;
+    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);
+    }
+}
 
-    if (XDND_DEST_INFO(info) != NULL) {
-        if (! W_SendDnDClientMessage(scr->display,
-                                     XDND_SOURCE_WIN(info),
-                                     message,
-                                     WMViewXID(destView),
-                                     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);
     }
 }
 
@@ -534,31 +547,26 @@
 static void
 cancelDrop(WMView *destView, WMDraggingInfo *info)
 {
-    /* send XdndStatus with action None */
-    sendDnDClientMessage(destView,
-                         W_VIEW_SCREEN(destView)->xdndStatusAtom,
-                         0, 0, 0, None);
+    sendStatusMessage(destView, info, None);
     concludeDrop(destView);
     freeDestinationViewInfos(info);
 }
 
 
-/* suspend drop, when dragged icon enter an unaware subview of destView */
+/* 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)
 {
-    /* free datas that depend on destination behaviour */
-    /* (in short: only keep source's types) */
+    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;
 
-    /* send XdndStatus with action None */
-    sendDnDClientMessage(destView,
-                         W_VIEW_SCREEN(destView)->xdndStatusAtom,
-                         0, 0, 0, None);
+    XDND_REQUIRED_TYPES(info) = NULL;
 }
 
 
@@ -566,14 +574,10 @@
 void
 W_DragDestinationCancelDropOnEnter(WMView *toplevel, WMDraggingInfo *info)
 {
-    if (XDND_DEST_VIEW_STORED(info))
+    if (XDND_DEST_VIEW_IS_REGISTERED(info))
         cancelDrop(XDND_DEST_VIEW(info), info);
-    else {
-        /* send XdndStatus with action None */
-        sendDnDClientMessage(toplevel,
-                             W_VIEW_SCREEN(toplevel)->xdndStatusAtom,
-                             0, 0, 0, None);
-    }
+    else
+        sendStatusMessage(toplevel, info, None);
 
     W_DragDestinationInfoClear(info);
 }
@@ -582,7 +586,7 @@
 static void
 finishDrop(WMView *destView, WMDraggingInfo *info)
 {
-    sendDnDClientMessage(destView,
+    sendDnDClientMessage(info,
                          W_VIEW_SCREEN(destView)->xdndFinishedAtom,
                          0, 0, 0, 0);
     concludeDrop(destView);
@@ -603,31 +607,6 @@
 }
 
 
-/*  send the action that can be performed,
- and the limits outside wich the source must re-send
- its position and action */
-static void
-sendAllowedAction(WMView *destView, Atom action)
-{
-    WMScreen *scr = W_VIEW_SCREEN(destView);
-    /* // WMPoint destPos = WMGetViewScreenPosition(destView); */
-    WMSize destSize = WMGetViewSize(destView);
-    int destX, destY;
-    Window foo;
-
-    XTranslateCoordinates(scr->display, scr->rootWin, WMViewXID(destView),
-                          0, 0, &destX, &destY,
-                          &foo);
-
-    sendDnDClientMessage(destView,
-                         scr->xdndStatusAtom,
-                         1,
-                         (destX << 16)|destY,
-                         (destSize.width << 16)|destSize.height,
-                         action);
-}
-
-
 static void*
 checkActionAllowed(WMView *destView, WMDraggingInfo* info)
 {
@@ -639,10 +618,11 @@
         return dropNotAllowedState;
     }
 
-    sendAllowedAction(destView, XDND_DEST_ACTION(info));
+    sendStatusMessage(destView, info, XDND_DEST_ACTION(info));
     return dropAllowedState;
 }
 
+
 static void*
 checkDropAllowed(WMView *destView, XClientMessageEvent *event,
                  WMDraggingInfo* info)
@@ -670,6 +650,7 @@
     return checkActionAllowed(destView, info);
 }
 
+
 static WMPoint*
 getDropLocationInView(WMView *view)
 {
@@ -690,6 +671,7 @@
     return location;
 }
 
+
 static void
 callPerformDragOperation(WMView *destView, WMDraggingInfo *info)
 {
@@ -721,21 +703,17 @@
     WMDraggingInfo *info;
 
     wwarning("delay for drag source response expired");
-    if (view != NULL) {
-        info = &(W_VIEW_SCREEN(view)->dragInfo);
-        if (XDND_DEST_VIEW_STORED(info))
-            cancelDrop(view, info);
-        else {
-            /* send XdndStatus with action None */
-            sendDnDClientMessage(view,
-                                 W_VIEW_SCREEN(view)->xdndStatusAtom,
-                                 0, 0, 0, None);
-        }
-
-        W_DragDestinationInfoClear(info);
+    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()
 {
@@ -745,21 +723,17 @@
     }
 }
 
+
 void
 W_DragDestinationStartTimer(WMDraggingInfo *info)
 {
     W_DragDestinationStopTimer();
 
-    if (XDND_DEST_STATE(info) != idleState
-        || XDND_DEST_VIEW(info) == NULL) {
-        /* note: info->destView == NULL means :
-         Enter message has been received, waiting for Position message */
-
+    if (XDND_DEST_STATE(info) != idleState)
         dndDestinationTimer = WMAddTimerHandler(
                                                 XDND_SOURCE_RESPONSE_MAX_DELAY,
                                                 dragSourceResponseTimeOut,
                                                 XDND_DEST_VIEW(info));
-    }
 }
 /* ----- End of Destination timer ----- */
 
@@ -795,6 +769,7 @@
 }
 #endif
 
+
 static void*
 idleState(WMView *destView, XClientMessageEvent *event,
           WMDraggingInfo *info)
@@ -802,21 +777,24 @@
     WMScreen *scr;
     Atom sourceMsg;
 
-    scr = W_VIEW_SCREEN(destView);
-    sourceMsg = event->message_type;
-
-    if (sourceMsg == scr->xdndPositionAtom) {
-        destView->dragDestinationProcs->prepareForDragOperation(destView);
+    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);
+            }
 
-        if (XDND_SOURCE_TYPES(info) != NULL) {
-            /* enter message infos are available */
-            return checkDropAllowed(destView, event, info);
+            /* waiting for enter message */
+            return waitEnterState;
         }
-
-        /* waiting for enter message */
-        return waitEnterState;
     }
-
+	
+    suspendDropAuthorization(destView, info);
     return idleState;
 }
 
@@ -881,6 +859,15 @@
         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;
 }
 
@@ -912,6 +899,15 @@
         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;
 }
 
@@ -947,29 +943,30 @@
     WMView *destView;
     W_DndState* newState;
 
-    if (XDND_DEST_VIEW_STORED(info)) {
-        destView = XDND_DEST_VIEW(info);
-        if (XDND_DEST_STATE(info) == NULL)
-            XDND_DEST_STATE(info) = idleState;
+    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)));
+    printf("current dest state: %s\n",
+           stateName(XDND_DEST_STATE(info)));
 #endif
 
-        newState = (W_DndState*) XDND_DEST_STATE(info)(destView, event, info);
+    newState = (W_DndState*) XDND_DEST_STATE(info)(destView, event, info);
 
 #ifdef XDND_DEBUG
 
-        printf("new dest state: %s\n", stateName(newState));
+    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);
-        }
+    if (XDND_DEST_INFO(info) != NULL) {
+        XDND_DEST_STATE(info) = newState;
+        if (XDND_DEST_STATE(info) != idleState)
+            W_DragDestinationStartTimer(info);
     }
 }
 
@@ -1104,7 +1101,7 @@
  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 retrivied.
+ 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
diff -ur WindowMaker-0.92.0/WINGs/dragsource.c WindowMaker-0.92.0-patch/WINGs/dragsource.c
--- WindowMaker-0.92.0/WINGs/dragsource.c	2004-10-28 11:29:59.000000000 +0200
+++ WindowMaker-0.92.0-patch/WINGs/dragsource.c	2005-04-18 19:03:07.713963840 +0200
@@ -16,10 +16,10 @@
 #define MIN_Y_MOVE_OFFSET 5
 #define MAX_SLIDEBACK_ITER 15
 
-#define VERSION_INFO(dragInfo) dragInfo->protocolVersion
 #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
@@ -415,21 +415,25 @@
 sendEnterMessage(WMDraggingInfo *info)
 {
     WMScreen *scr = sourceScreen(info);
-    unsigned long data1;
+    unsigned long version;
 
-    data1 = (VERSION_INFO(info) << 24)|1; /* 1: support of type list */
+    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,
-                                data1,
+                                (version << 24) | 1, /* 1: support of type list */
                                 XDND_3_TYPES(info)[0],
                                 XDND_3_TYPES(info)[1],
                                 XDND_3_TYPES(info)[2]);
 }
 
 
-/*
-// this functon doesn't return something in all cases.
-// control reaches end of non-void function. fix this -Dan */
 static Bool
 sendPositionMessage(WMDraggingInfo *info, WMPoint *mousePos)
 {
@@ -440,7 +444,7 @@
         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.width)) {
+            || mousePos->y > (noPosZone->pos.y + noPosZone->size.height)) {
             /* send position if out of zone defined by destination */
             return sendDnDClientMessage(info, scr->xdndPositionAtom,
                                         0,
@@ -448,14 +452,18 @@
                                         XDND_TIMESTAMP(info),
                                         XDND_SOURCE_ACTION(info));
         }
-    } else {
-        /* send position on each move */
-        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));
 }
 
 
@@ -846,6 +854,30 @@
 
 
 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)
 {
@@ -878,9 +910,8 @@
 
 
 static void
-processMotion(WMDraggingInfo *info, Window windowUnderDrag, WMPoint *mousePos)
+processMotion(WMDraggingInfo *info, WMPoint *mousePos)
 {
-    /* // WMScreen *scr = sourceScreen(info); */
     Window newDestination = findDestination(info, mousePos);
 
     W_DragSourceStopTimer();
@@ -894,20 +925,24 @@
         }
 
         XDND_DEST_WIN(info) = newDestination;
-        XDND_SOURCE_STATE(info) = idleState;
         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)) {
@@ -1010,9 +1045,7 @@
                         mouseLocation.y - XDND_MOUSE_OFFSET(info).y;
 
                     refreshDragImage(view, info);
-                    processMotion(info,
-                                  event->xmotion.window,
-                                  &mouseLocation);
+                    processMotion(info, &mouseLocation);
                 }
             }
         }
@@ -1041,7 +1074,7 @@
     printf("Xdnd status message:\n");
 
     if (statusEvent->data.l[1] & 0x2UL)
-        printf("send position on every move\n");
+        printf("\tsend position on every move\n");
     else {
         int x, y, w, h;
         x = statusEvent->data.l[2] >> 16;
@@ -1049,15 +1082,15 @@
         w = statusEvent->data.l[3] >> 16;
         h = statusEvent->data.l[3] & 0xFFFFL;
 
-        printf("send position out of ((%d,%d) , (%d,%d))\n",
+        printf("\tsend position out of ((%d,%d) , (%d,%d))\n",
                x, y, x+w, y+h);
     }
 
     if (statusEvent->data.l[1] & 0x1L)
-        printf("allowed action: %s\n",
+        printf("\tallowed action: %s\n",
                XGetAtomName(dpy, statusEvent->data.l[4]));
     else
-        printf("no action allowed\n");
+        printf("\tno action allowed\n");
 }
 #endif
 
@@ -1231,23 +1264,28 @@
     W_DndState* newState;
 
     if (XDND_SOURCE_VIEW_STORED(info)) {
-        view = XDND_SOURCE_VIEW(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)));
+            printf("current source state: %s\n",
+                   stateName(XDND_SOURCE_STATE(info)));
 #endif
 
-        newState = (W_DndState*) XDND_SOURCE_STATE(info)(view, event, info);
+            newState = (W_DndState*) XDND_SOURCE_STATE(info)(view, event, info);
 
 #ifdef XDND_DEBUG
 
-        printf("new source state: %s\n", stateName(newState));
+            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 */
+            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");
     }
 }
 
diff -ur WindowMaker-0.92.0/WINGs/WINGs/WINGsP.h WindowMaker-0.92.0-patch/WINGs/WINGs/WINGsP.h
--- WindowMaker-0.92.0/WINGs/WINGs/WINGsP.h	2004-10-30 08:32:50.000000000 +0200
+++ WindowMaker-0.92.0-patch/WINGs/WINGs/WINGsP.h	2005-04-18 19:03:21.299898464 +0200
@@ -29,7 +29,7 @@
 
 #define SCROLLER_WIDTH	20
 
-#define XDND_VERSION    4
+#define XDND_VERSION    3
 
 
 typedef struct W_Application {
@@ -110,8 +110,10 @@
 
 typedef struct W_DragDestinationInfo {
     WMView *destView;
+    WMView *xdndAwareView;
     Window sourceWindow;
     W_DndState *state;
+    Bool sourceActionChanged;
     WMArray *sourceTypes;
     WMArray *requiredTypes;
     Bool typeListAvailable;
@@ -120,7 +122,7 @@
 
 
 struct W_DraggingInfo {
-    unsigned char protocolVersion;
+    unsigned char protocolVersion; /* version supported on the other side */
     Time timestamp;
 
     Atom sourceAction;

_______________________________________________
INFO: https://windowmaker.org/lists/listinfo/wm-dev
ARCHIVE: https://windowmaker.org/lists/archive/wm-dev/
CVS: http://windowmaker.org/development-cvs.html

--- End Message ---
_______________________________________________
Gnustep-dev mailing list
Gnustep-dev@gnu.org
http://lists.gnu.org/mailman/listinfo/gnustep-dev

Reply via email to