diff --git a/ChangeLog b/ChangeLog index ace05c27..d6a596ab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -21,6 +21,15 @@ Changes since version 0.92.0: - fixed a small memory leak in WINGs/wview.c caused by not releasing the background color of a view (Martin Frydl ) - updated estonian translation (Ivar Smolin ) +- updated the XDND code in WINGs to work with GDK based applications. + WINGs based applications should now work with both KDE and GNOME + applications (Sylvain Reynal ) +- better check for the XDND protocol version when interoperating with other + applications. As it seems xdnd version 3 (which WINGs supports) and newer + are not backward compatible with xdnd version 1 and 2. This is why WINGs + applications cannot interoperate with GNUstep applications (which uses + xdnd version 2). Xdnd version 4 and 5 are backwards compatible with + version 3 though. (Sylvain Reynal ) Changes since version 0.91.0: diff --git a/WINGs/ChangeLog b/WINGs/ChangeLog index 793f838b..4bb77567 100644 --- a/WINGs/ChangeLog +++ b/WINGs/ChangeLog @@ -1,3 +1,17 @@ +Changes since wmaker 0.92.0: +............................ + +- updated the XDND code in to work with GDK based applications. + WINGs based applications should now work with both KDE and GNOME + applications (Sylvain Reynal ) +- better check for the XDND protocol version when interoperating with other + applications. As it seems xdnd version 3 (which WINGs supports) and newer + are not backward compatible with xdnd version 1 and 2. This is why WINGs + applications cannot interoperate with GNUstep applications (which uses + xdnd version 2). Xdnd version 4 and 5 are backwards compatible with + version 3 though. (Sylvain Reynal ) + + Changes since wmaker 0.80.1: ............................ diff --git a/WINGs/WINGs/WINGsP.h b/WINGs/WINGs/WINGsP.h index 01faf088..b72de53b 100644 --- a/WINGs/WINGs/WINGsP.h +++ b/WINGs/WINGs/WINGsP.h @@ -29,7 +29,7 @@ extern "C" { #define SCROLLER_WIDTH 20 -#define XDND_VERSION 4 +#define XDND_VERSION 3 typedef struct W_Application { @@ -78,7 +78,7 @@ typedef struct W_Color { typedef struct W_FocusInfo { struct W_View *toplevel; - struct W_View *focused; /* view that has the focus in this toplevel */ + struct W_View *focused; /* view that has the focus in this toplevel */ struct W_FocusInfo *next; } W_FocusInfo; @@ -110,8 +110,10 @@ typedef struct W_DragSourceInfo { 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 @@ typedef struct W_DragDestinationInfo { struct W_DraggingInfo { - unsigned char protocolVersion; + unsigned char protocolVersion; /* version supported on the other side */ Time timestamp; Atom sourceAction; @@ -162,7 +164,7 @@ typedef struct W_Screen { struct W_Window *windowList; /* list of windows in the app */ - Window groupLeader; /* the leader of the application */ + Window groupLeader; /* the leader of the application */ /* also used for other things */ struct W_SelectionHandlers *selectionHandlerList; @@ -195,11 +197,11 @@ typedef struct W_Screen { GC copyGC; GC clipGC; - GC monoGC; /* GC for 1bpp visuals */ + GC monoGC; /* GC for 1bpp visuals */ GC xorGC; - GC ixorGC; /* IncludeInferiors XOR */ + GC ixorGC; /* IncludeInferiors XOR */ GC drawStringGC; /* for WMDrawString() */ @@ -276,15 +278,15 @@ typedef struct W_Screen { Cursor invisibleCursor; - Atom attribsAtom; /* GNUstepWindowAttributes */ + Atom attribsAtom; /* GNUstepWindowAttributes */ - Atom deleteWindowAtom; /* WM_DELETE_WINDOW */ + Atom deleteWindowAtom; /* WM_DELETE_WINDOW */ - Atom protocolsAtom; /* _XA_WM_PROTOCOLS */ + Atom protocolsAtom; /* _XA_WM_PROTOCOLS */ - Atom clipboardAtom; /* CLIPBOARD */ + Atom clipboardAtom; /* CLIPBOARD */ - Atom xdndAwareAtom; /* XdndAware */ + Atom xdndAwareAtom; /* XdndAware */ Atom xdndSelectionAtom; Atom xdndEnterAtom; Atom xdndLeaveAtom; @@ -304,7 +306,7 @@ typedef struct W_Screen { Atom wmIconDragOffsetAtom; - Atom wmStateAtom; /* WM_STATE */ + Atom wmStateAtom; /* WM_STATE */ Atom utf8String; @@ -313,8 +315,8 @@ typedef struct W_Screen { Atom netwmIcon; /* stuff for detecting double-clicks */ - Time lastClickTime; /* time of last mousedown event */ - Window lastClickWindow; /* window of the last mousedown */ + Time lastClickTime; /* time of last mousedown event */ + Window lastClickWindow; /* window of the last mousedown */ struct W_View *modalView; unsigned modalLoop:1; @@ -341,8 +343,7 @@ typedef struct W_ViewDelegate { typedef struct W_View { struct W_Screen *screen; - WMWidget *self; /* must point to the widget the - * view belongs to */ + WMWidget *self; /* must point to the widget the view belongs to */ W_ViewDelegate *delegate; @@ -362,18 +363,18 @@ typedef struct W_View { struct W_View *nextResponder; /* next to receive keyboard events */ - struct W_View *parent; /* parent WMView */ + struct W_View *parent; /* parent WMView */ struct W_View *childrenList; /* first in list of child windows */ - struct W_View *nextSister; /* next on parent's children list */ + struct W_View *nextSister; /* next on parent's children list */ - WMArray *eventHandlers; /* event handlers for this window */ + WMArray *eventHandlers; /* event handlers for this window */ unsigned long attribFlags; XSetWindowAttributes attribs; - void *hangedData; /* data holder for user program */ + void *hangedData; /* data holder for user program */ WMColor *backColor; @@ -391,9 +392,9 @@ typedef struct W_View { unsigned int realized:1; unsigned int mapped:1; unsigned int parentDying:1; - unsigned int dying:1; /* the view is being destroyed */ + unsigned int dying:1; /* the view is being destroyed */ unsigned int topLevel:1; /* is a top level window */ - unsigned int root:1; /* is the root window */ + unsigned int root:1; /* is the root window */ unsigned int mapWhenRealized:1; /* map the view when it's realized */ unsigned int alreadyDead:1; /* view was freed */ diff --git a/WINGs/dragcommon.c b/WINGs/dragcommon.c index 61482bc9..be468e54 100644 --- a/WINGs/dragcommon.c +++ b/WINGs/dragcommon.c @@ -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 @@ W_SendDnDClientMessage(Display *dpy, Window win, Atom message, { 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 @@ W_SendDnDClientMessage(Display *dpy, Window win, Atom message, XSendEvent(dpy, win, False, 0, &ev); XFlush(dpy); +#ifdef XDND_DEBUG + printf("sent\n"); +#endif return True; /* message sent */ } @@ -178,7 +186,9 @@ static void 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 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) /* 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 @@ W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) } } else { wwarning("received dnd enter msg with unsupported version %i", - VERSION_INFO(info)); + XDND_SOURCE_VERSION(info)); W_DragDestinationCancelDropOnEnter(toplevel, info); return; } diff --git a/WINGs/dragdestination.c b/WINGs/dragdestination.c index a1944a79..9206cb82 100644 --- a/WINGs/dragdestination.c +++ b/WINGs/dragdestination.c @@ -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 @@ createDropDataArray(WMArray *requiredTypes) static WMArray* getTypesFromTypeList(WMScreen *scr, Window sourceWin) { - /* // WMDraggingInfo *info = &scr->dragInfo;*/ Atom dataType; Atom* typeAtomList; WMArray* typeList; @@ -138,22 +138,29 @@ storeRequiredTypeList(WMDraggingInfo *info) 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 @@ updateSourceWindow(WMDraggingInfo *info, XClientMessageEvent *event) } -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; + 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); } - - /* 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; - } - } - - 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 @@ findXdndViewInToplevel(WMView* toplevel, int x, int y) 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 @@ freeDestinationViewInfos(WMDraggingInfo *info) XDND_REQUIRED_TYPES(info) = NULL; } + void W_DragDestinationInfoClear(WMDraggingInfo *info) { @@ -347,15 +330,19 @@ W_DragDestinationInfoClear(WMDraggingInfo *info) } } + 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 @@ W_DragDestinationStoreEnterMsgInfo(WMDraggingInfo *info, 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 @@ W_DragDestinationStoreEnterMsgInfo(WMDraggingInfo *info, } -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 @@ void /* 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 @@ concludeDrop(WMView *destView) 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 @@ suspendDropAuthorization(WMView *destView, WMDraggingInfo *info) 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 @@ W_DragDestinationCancelDropOnEnter(WMView *toplevel, WMDraggingInfo *info) 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 @@ getAllowedAction(WMView *destView, WMDraggingInfo *info) } -/* 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 @@ checkActionAllowed(WMView *destView, WMDraggingInfo* info) 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 @@ checkDropAllowed(WMView *destView, XClientMessageEvent *event, return checkActionAllowed(destView, info); } + static WMPoint* getDropLocationInView(WMView *view) { @@ -690,6 +671,7 @@ getDropLocationInView(WMView *view) return location; } + static void callPerformDragOperation(WMView *destView, WMDraggingInfo *info) { @@ -721,21 +703,17 @@ dragSourceResponseTimeOut(void *destView) 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 @@ W_DragDestinationStopTimer() } } + 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 @@ stateName(W_DndState *state) } #endif + static void* idleState(WMView *destView, XClientMessageEvent *event, WMDraggingInfo *info) @@ -802,21 +777,24 @@ idleState(WMView *destView, XClientMessageEvent *event, WMScreen *scr; Atom sourceMsg; - scr = W_VIEW_SCREEN(destView); - sourceMsg = event->message_type; + if (destView->dragDestinationProcs != NULL) { + scr = W_VIEW_SCREEN(destView); + sourceMsg = event->message_type; - if (sourceMsg == scr->xdndPositionAtom) { - destView->dragDestinationProcs->prepareForDragOperation(destView); + 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 @@ dropNotAllowedState(WMView *destView, XClientMessageEvent *event, 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 @@ dropAllowedState(WMView *destView, XClientMessageEvent *event, 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 @@ W_DragDestinationStateHandler(WMDraggingInfo *info, XClientMessageEvent *event) 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 @@ defPrepareForDragOperation(WMView *self) 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 --git a/WINGs/dragsource.c b/WINGs/dragsource.c index 50ecdf06..04baa23b 100644 --- a/WINGs/dragsource.c +++ b/WINGs/dragsource.c @@ -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 @@ static Bool 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 @@ sendPositionMessage(WMDraggingInfo *info, WMPoint *mousePos) 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 @@ sendPositionMessage(WMDraggingInfo *info, WMPoint *mousePos) 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)); } @@ -845,6 +853,30 @@ findDestination(WMDraggingInfo *info, WMPoint *mousePos) } +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 @@ initMotionProcess(WMView *view, WMDraggingInfo *info, 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 @@ processMotion(WMDraggingInfo *info, Window windowUnderDrag, WMPoint *mousePos) } 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 @@ WMDragImageFromView(WMView *view, XEvent *event) mouseLocation.y - XDND_MOUSE_OFFSET(info).y; refreshDragImage(view, info); - processMotion(info, - event->xmotion.window, - &mouseLocation); + processMotion(info, &mouseLocation); } } } @@ -1041,7 +1074,7 @@ traceStatusMsg(Display *dpy, XClientMessageEvent *statusEvent) 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 @@ traceStatusMsg(Display *dpy, XClientMessageEvent *statusEvent) 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_DragSourceStateHandler(WMDraggingInfo *info, XClientMessageEvent *event) 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"); } }