2 #include "../src/config.h"
9 #include <X11/extensions/shape.h>
23 #define IS_DROPPABLE(view) (view!=NULL && view->droppableTypes!=NULL && \
24 view->dragDestinationProcs!=NULL)
27 static Atom
operationToAction(WMScreen
*scr
, WMDragOperationType operation
);
28 static WMDragOperationType
actionToOperation(WMScreen
*scr
, Atom action
);
30 static Bool _XErrorOccured
= False
;
34 static unsigned defDraggingSourceOperation(WMView
*self
, Bool local
)
36 return WDOperationCopy
;
40 static void defBeganDragImage(WMView
*self
, WMPixmap
*image
, WMPoint point
)
45 static void defEndedDragImage(WMView
*self
, WMPixmap
*image
, WMPoint point
,
50 static WMData
* defFetchDragData(WMView
*self
, char *type
)
57 WMSetViewDragSourceProcs(WMView
*view
, WMDragSourceProcs
*procs
)
59 if (view
->dragSourceProcs
)
60 free(view
->dragSourceProcs
);
61 view
->dragSourceProcs
= wmalloc(sizeof(WMDragSourceProcs
));
63 *view
->dragSourceProcs
= *procs
;
65 if (procs
->draggingSourceOperation
== NULL
) {
66 view
->dragSourceProcs
->draggingSourceOperation
= defDraggingSourceOperation
;
68 if (procs
->beganDragImage
== NULL
) {
69 view
->dragSourceProcs
->beganDragImage
= defBeganDragImage
;
71 if (procs
->endedDragImage
== NULL
) {
72 view
->dragSourceProcs
->endedDragImage
= defEndedDragImage
;
74 if (procs
->fetchDragData
== NULL
) {
75 view
->dragSourceProcs
->fetchDragData
= defFetchDragData
;
80 /***********************************************************************/
84 handleXError(Display
*dpy
, XErrorEvent
*ev
)
86 _XErrorOccured
= True
;
93 protectBlock(Bool begin
)
95 static void *oldHandler
= NULL
;
98 oldHandler
= XSetErrorHandler(handleXError
);
100 XSetErrorHandler(oldHandler
);
108 makeDragIcon(WMScreen
*scr
, WMPixmap
*pixmap
)
113 XSetWindowAttributes attribs
;
117 pixmap
= scr
->defaultObjectIcon
;
119 size
= WMGetPixmapSize(pixmap
);
120 pix
= pixmap
->pixmap
;
123 flags
= CWSaveUnder
|CWBackPixmap
|CWOverrideRedirect
|CWColormap
;
124 attribs
.save_under
= True
;
125 attribs
.background_pixmap
= pix
;
126 attribs
.override_redirect
= True
;
127 attribs
.colormap
= scr
->colormap
;
128 window
= XCreateWindow(scr
->display
, scr
->rootWin
, 0, 0, size
.width
,
129 size
.height
, 0, scr
->depth
, InputOutput
,
130 scr
->visual
, flags
, &attribs
);
134 XShapeCombineMask(scr
->display
, window
, ShapeBounding
, 0, 0, mask
,
144 slideWindow(Display
*dpy
, Window win
, int srcX
, int srcY
, int dstX
, int dstY
)
150 iterations
= WMIN(25, WMAX(abs(dstX
-srcX
), abs(dstY
-srcY
)));
155 dx
= (double)(dstX
-srcX
)/iterations
;
156 dy
= (double)(dstY
-srcY
)/iterations
;
158 for (i
= 0; i
<= iterations
; i
++) {
159 XMoveWindow(dpy
, win
, x
, y
);
171 findChildInWindow(Display
*dpy
, Window toplevel
, int x
, int y
)
178 if (!XQueryTree(dpy
, toplevel
, &foo
, &bar
,
179 &children
, &nchildren
) || children
== NULL
) {
183 /* first window that contains the point is the one */
184 for (i
= nchildren
-1; i
>= 0; i
--) {
185 XWindowAttributes attr
;
187 if (XGetWindowAttributes(dpy
, children
[i
], &attr
)
188 && attr
.map_state
== IsViewable
189 && x
>= attr
.x
&& y
>= attr
.y
190 && x
< attr
.x
+ attr
.width
&& y
< attr
.y
+ attr
.height
) {
195 child
= findChildInWindow(dpy
, tmp
, x
- attr
.x
, y
- attr
.y
);
212 findViewInToplevel(Display
*dpy
, Window toplevel
, int x
, int y
)
216 child
= findChildInWindow(dpy
, toplevel
, x
, y
);
219 return W_GetViewForXWindow(dpy
, child
);
228 lookForToplevel(WMScreen
*scr
, Window window
, Bool
*isAware
)
230 Window toplevel
= None
;
236 atoms
= XListProperties(scr
->display
, window
, &count
);
237 for (j
= 0; j
< count
; j
++) {
238 if (atoms
[j
] == scr
->wmStateAtom
) {
240 } else if (atoms
[j
] == scr
->xdndAwareAtom
) {
247 if (toplevel
== None
) {
252 if (!XQueryTree(scr
->display
, window
, &foo
, &bar
,
253 &children
, &nchildren
) || children
== NULL
) {
257 for (j
= 0; j
< nchildren
; j
++) {
258 toplevel
= lookForToplevel(scr
, children
[j
], isAware
);
259 if (toplevel
!= None
)
272 findToplevelUnderDragPointer(WMScreen
*scr
, int x
, int y
, Window iconWindow
)
277 Bool overSomething
= False
;
280 if (!XQueryTree(scr
->display
, scr
->rootWin
, &foo
, &bar
,
281 &children
, &nchildren
) || children
== NULL
) {
282 SPIT("couldnt query tree!");
286 /* try to find the window below the iconWindow by traversing
287 * the whole window list */
289 /* first find the position of the iconWindow */
290 for (i
= nchildren
-1; i
>= 0; i
--) {
291 if (children
[i
] == iconWindow
) {
301 /* first window that contains the point is the one */
302 for (; i
>= 0; i
--) {
303 XWindowAttributes attr
;
305 if (XGetWindowAttributes(scr
->display
, children
[i
], &attr
)
306 && attr
.map_state
== IsViewable
307 && x
>= attr
.x
&& y
>= attr
.y
308 && x
< attr
.x
+ attr
.width
&& y
< attr
.y
+ attr
.height
) {
312 overSomething
= True
;
314 toplevel
= lookForToplevel(scr
, children
[i
], &isaware
);
338 sendClientMessage(Display
*dpy
, Window win
, Atom message
,
339 unsigned data1
, unsigned data2
, unsigned data3
,
340 unsigned data4
, unsigned data5
)
344 ev
.type
= ClientMessage
;
345 ev
.xclient
.message_type
= message
;
346 ev
.xclient
.format
= 32;
347 ev
.xclient
.window
= win
;
348 ev
.xclient
.data
.l
[0] = data1
;
349 ev
.xclient
.data
.l
[1] = data2
;
350 ev
.xclient
.data
.l
[2] = data3
;
351 ev
.xclient
.data
.l
[3] = data4
;
352 ev
.xclient
.data
.l
[4] = data5
;
354 XSendEvent(dpy
, win
, False
, 0, &ev
);
362 notifyPosition(WMScreen
*scr
, WMDraggingInfo
*info
)
364 Atom action
= operationToAction(scr
, info
->sourceOperation
);
366 sendClientMessage(scr
->display
, info
->destinationWindow
,
367 scr
->xdndPositionAtom
,
370 info
->location
.x
<<16|info
->location
.y
,
372 action
/* operation */);
380 notifyDrop(WMScreen
*scr
, WMDraggingInfo
*info
)
382 sendClientMessage(scr
->display
, info
->destinationWindow
,
393 notifyDragLeave(WMScreen
*scr
, WMDraggingInfo
*info
)
395 sendClientMessage(scr
->display
, info
->destinationWindow
,
397 info
->sourceWindow
, 0, 0, 0, 0);
403 notifyDragEnter(WMScreen
*scr
, WMDraggingInfo
*info
)
407 d
= XDND_VERSION
<< 24;
409 sendClientMessage(scr
->display
, info
->destinationWindow
,
411 info
->sourceWindow
, d
, 0, 0, 0);
418 translateCoordinates(WMScreen
*scr
, Window target
, int fromX
, int fromY
,
423 XTranslateCoordinates(scr
->display
, scr
->rootWin
, target
,
424 fromX
, fromY
, x
, y
, &child
);
429 updateDraggingInfo(WMScreen
*scr
, WMDraggingInfo
*info
, WMSize offset
,
430 XEvent
*event
, Window iconWindow
)
434 if (event
->type
== MotionNotify
) {
435 info
->imageLocation
.x
= event
->xmotion
.x_root
-offset
.width
;
436 info
->imageLocation
.y
= event
->xmotion
.y_root
-offset
.height
;
438 info
->location
.x
= event
->xmotion
.x_root
;
439 info
->location
.y
= event
->xmotion
.y_root
;
440 /* info->timestamp = event->xmotion.time;*/
442 } else if (event
->type
== ButtonRelease
) {
443 info
->imageLocation
.x
= event
->xbutton
.x_root
-offset
.width
;
444 info
->imageLocation
.y
= event
->xbutton
.y_root
-offset
.height
;
446 info
->location
.x
= event
->xbutton
.x_root
;
447 info
->location
.y
= event
->xbutton
.y_root
;
448 /* info->timestamp = event->xbutton.time;*/
451 toplevel
= findToplevelUnderDragPointer(scr
,
455 info
->destinationWindow
= toplevel
;
462 processMotion(WMScreen
*scr
, WMDraggingInfo
*info
, WMDraggingInfo
*oldInfo
,
463 WMRect
*rect
, unsigned currentAction
)
467 if (info
->destinationWindow
== None
) { /* entered an unsupporeted window */
469 if (oldInfo
->destinationWindow
!= None
470 && oldInfo
->destinationWindow
!= scr
->rootWin
) {
473 notifyDragLeave(scr
, oldInfo
);
476 } else if (info
->destinationWindow
== scr
->rootWin
) {
478 if (oldInfo
->destinationWindow
!= None
479 && oldInfo
->destinationWindow
!= scr
->rootWin
) {
480 SPIT("left window to root");
482 notifyDragLeave(scr
, oldInfo
);
487 } else if (oldInfo
->destinationWindow
!= info
->destinationWindow
) {
489 if (oldInfo
->destinationWindow
!= None
490 && oldInfo
->destinationWindow
!= scr
->rootWin
) {
491 notifyDragLeave(scr
, oldInfo
);
494 SPIT("entered window");
497 action
= notifyDragEnter(scr
, info
);
501 #define LEFT_RECT(r, X, Y) (X < r->pos.x || Y < r->pos.y \
502 || X >= r->pos.x + r->size.width \
503 || Y >= r->pos.y + r->size.height)
505 if (rect
->size
.width
== 0 ||
506 (LEFT_RECT(rect
, info
->location
.x
, info
->location
.y
))) {
508 action
= notifyPosition(scr
, info
);
510 rect
->size
.width
= 0;
518 convertSelection(WMView
*view
, Atom selection
, Atom target
,
519 void *cdata
, Atom
*type
)
521 WMScreen
*scr
= W_VIEW_SCREEN(view
);
523 char *typeName
= XGetAtomName(scr
->display
, target
);
527 data
= view
->dragSourceProcs
->fetchDragData(view
, typeName
);
529 if (typeName
!= NULL
)
537 selectionLost(WMView
*view
, Atom selection
, void *cdata
)
539 if (W_VIEW_SCREEN(view
)->dragSourceView
== view
) {
540 wwarning("DND selection lost during drag operation...");
541 W_VIEW_SCREEN(view
)->dragSourceView
= NULL
;
547 selectionDone(WMView
*view
, Atom selection
, Atom target
, void *cdata
)
557 setMouseOffsetHint(WMView
*view
, WMSize mouseOffset
)
559 WMScreen
*scr
= W_VIEW_SCREEN(view
);
563 * Tell the offset from the topleft corner of the icon being
564 * dragged. Not from XDND, but it's backwards compatible.
567 hint
[0] = mouseOffset
.width
;
568 hint
[1] = mouseOffset
.height
;
570 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(view
),
571 scr
->wmIconDragOffsetAtom
, XA_INTEGER
, 32,
572 PropModeReplace
, (unsigned char*)hint
, 2);
577 getMouseOffsetHint(WMScreen
*scr
, Window source
, WMSize
*mouseOffset
)
582 unsigned long nitems_ret
, bytes_after_ret
;
588 XGetWindowProperty(scr
->display
, source
,
589 scr
->wmIconDragOffsetAtom
, 0, 2, False
, XA_INTEGER
,
590 &type_ret
, &fmt_ret
, &nitems_ret
, &bytes_after_ret
,
591 (unsigned char **)&hint
);
593 if (hint
&& nitems_ret
== 2) {
594 mouseOffset
->width
= hint
[0];
595 mouseOffset
->height
= hint
[1];
607 timeoutCallback(void *data
)
609 wwarning("drag & drop timed out while waiting for response from 0x%x\n",
615 * State Machine For Drag Source:
616 * ------------------------------
618 * State Call Mtn Ent Lea Crs BUp StA StR Fin TO
619 * 0) idle 1bu - - - - - - - - -
620 * 1) drag over target - 1au - 2cu 1cbu 5fu 3 4 1w -
621 * 2) drag over nothing - 2 1bu - - 0 - - 2w -
622 * 3) drag targ+accept - 3u - 2cu 1cbu 6f 3 4w 0z -
623 * 4) drag targ+reject - 4u - 2cu 1cbu 0 3w 4 0z -
624 * 5) waiting status - 5X 5X 5X 5X - 6f 0 0z 0w
625 * 6) dropped - - - - - - - - 0 0w
628 * Call - called WMDragImageFromView()
630 * Ent - Enter droppable window
631 * Lea - Leave droppable window (or rectangle)
632 * Crs - Leave droppable window (or rectangle) and enter another
633 * BUp - Button Released
634 * StA - XdndStatus client msg with Accept drop
635 * StR - XdndStatus client msg with Reject drop
636 * Fin - XdndFinish client msg
640 * a - send update message
641 * b - send enter message
642 * c - send leave message
643 * d - release drag section info
644 * e - send drop message
646 * u - update dragInfo
649 * w - warn about unexpected reply
650 * z - abort operation.. unexpected reply
654 WMDragImageFromView(WMView
*view
, WMPixmap
*image
, char *dataTypes
[],
655 WMPoint atLocation
, WMSize mouseOffset
, XEvent
*event
,
658 WMScreen
*scr
= view
->screen
;
659 Display
*dpy
= scr
->display
;
660 WMView
*toplevel
= W_TopLevelOfView(view
);
663 WMRect rect
= {{0,0},{0,0}};
667 XColor black
= {0, 0,0,0, DoRed
|DoGreen
|DoBlue
};
668 XColor green
= {0x0045b045, 0x4500,0xb000,0x4500, DoRed
|DoGreen
|DoBlue
};
669 XColor back
= {0, 0xffff,0xffff,0xffff, DoRed
|DoGreen
|DoBlue
};
670 WMDraggingInfo dragInfo
;
671 WMDraggingInfo oldDragInfo
;
672 WMHandlerID timer
= NULL
;
673 static WMSelectionProcs handler
= {
680 if (scr
->dragSourceView
!= NULL
)
683 wassertr(view
->dragSourceProcs
!= NULL
);
686 /* prepare icon to be dragged */
688 image
= scr
->defaultObjectIcon
;
690 icon
= makeDragIcon(scr
, image
);
692 XMoveWindow(dpy
, icon
, atLocation
.x
, atLocation
.y
);
693 XMapRaised(dpy
, icon
);
696 /* init dragging info */
698 scr
->dragSourceView
= view
;
700 memset(&dragInfo
, 0, sizeof(WMDraggingInfo
));
701 memset(&oldDragInfo
, 0, sizeof(WMDraggingInfo
));
702 dragInfo
.image
= image
;
703 dragInfo
.sourceView
= view
;
704 dragInfo
.sourceWindow
= W_VIEW_DRAWABLE(toplevel
);
706 dragInfo
.destinationWindow
= dragInfo
.sourceWindow
;
708 dragInfo
.location
.x
= atLocation
.x
+ mouseOffset
.width
;
709 dragInfo
.location
.y
= atLocation
.y
+ mouseOffset
.height
;
710 dragInfo
.imageLocation
= atLocation
;
713 /* start pointer grab */
714 XGrabPointer(dpy
, scr
->rootWin
, False
,
715 ButtonPressMask
|ButtonReleaseMask
|ButtonMotionMask
,
716 GrabModeAsync
, GrabModeAsync
, None
, scr
->defaultCursor
,
721 _XErrorOccured
= False
;
723 /* take ownership of XdndSelection */
724 if (!WMCreateSelectionHandler(view
, scr
->xdndSelectionAtom
,
727 wwarning("could not get ownership or DND selection");
731 setMouseOffsetHint(toplevel
, mouseOffset
);
733 if (view
->dragSourceProcs
->beganDragImage
!= NULL
) {
734 view
->dragSourceProcs
->beganDragImage(view
, image
, atLocation
);
737 processMotion(scr
, &dragInfo
, &oldDragInfo
, &rect
, action
);
741 while (state
!= 6 && state
!= 0 && !_XErrorOccured
) {
742 WMNextEvent(dpy
, &ev
);
746 if (state
>= 1 && state
<= 4) {
747 while (XCheckTypedEvent(dpy
, MotionNotify
, &ev
)) ;
751 oldDragInfo
= dragInfo
;
753 updateDraggingInfo(scr
, &dragInfo
, mouseOffset
, &ev
, icon
);
755 XMoveWindow(dpy
, icon
, dragInfo
.imageLocation
.x
,
756 dragInfo
.imageLocation
.y
);
758 processMotion(scr
, &dragInfo
, &oldDragInfo
, &rect
, action
);
762 /* XXXif entered a different destination, check the operation */
766 if (oldDragInfo
.destinationWindow
!= None
767 && oldDragInfo
.destinationWindow
!= scr
->rootWin
768 && (dragInfo
.destinationWindow
== None
769 || dragInfo
.destinationWindow
== scr
->rootWin
)) {
770 /* left the droppable window */
777 if (dragInfo
.destinationWindow
!= None
778 && dragInfo
.destinationWindow
!= scr
->rootWin
) {
787 if (oldDragInfo
.destinationWindow
!= None
788 && oldDragInfo
.destinationWindow
!= scr
->rootWin
789 && (dragInfo
.destinationWindow
== None
790 || dragInfo
.destinationWindow
== scr
->rootWin
)) {
791 /* left the droppable window */
802 /* if (state >= 1 && state <= 4) */ {
806 oldDragInfo
= dragInfo
;
808 updateDraggingInfo(scr
, &dragInfo
, mouseOffset
, &ev
, icon
);
810 XMoveWindow(dpy
, icon
, dragInfo
.imageLocation
.x
,
811 dragInfo
.imageLocation
.y
);
813 if (state
== 4 || state
== 1) {
814 dragInfo
.destinationWindow
= None
;
815 dragInfo
.destView
= NULL
;
817 processMotion(scr
, &dragInfo
, &oldDragInfo
, &rect
, action
);
819 dragInfo
.timestamp
= ev
.xbutton
.time
;
826 timer
= WMAddTimerHandler(3000, timeoutCallback
,
827 (void*)dragInfo
.destinationWindow
);
843 if ((state
== 1 || state
== 3 || state
== 4 || state
== 5)
844 && ev
.xclient
.message_type
== scr
->xdndStatusAtom
845 && ev
.xclient
.data
.l
[0] == dragInfo
.destinationWindow
) {
847 if (ev
.xclient
.data
.l
[1] & 1) {
848 SPIT("got accept msg");
849 /* will accept drop */
858 WMDeleteTimerHandler(timer
);
864 action
= actionToOperation(scr
, ev
.xclient
.data
.l
[4]);
866 SPIT("got reject msg");
876 WMDeleteTimerHandler(timer
);
884 if (ev
.xclient
.data
.l
[1] & (1<<1)) {
885 rect
.pos
.x
= ev
.xclient
.data
.l
[2] >> 16;
886 rect
.pos
.y
= ev
.xclient
.data
.l
[2] & 0xffff;
887 rect
.size
.width
= ev
.xclient
.data
.l
[3] >> 16;
888 rect
.size
.height
= ev
.xclient
.data
.l
[3] & 0xffff;
893 } else if ((state
>= 1 && state
<= 5)
894 && ev
.xclient
.message_type
== scr
->xdndFinishedAtom
895 && ev
.xclient
.window
== dragInfo
.destinationWindow
) {
897 wwarning("drag source received unexpected XdndFinished message from %x",
898 (unsigned)dragInfo
.destinationWindow
);
900 if (state
== 3 || state
== 4 || state
== 5) {
903 WMDeleteTimerHandler(timer
);
914 if (ostate
!= state
) {
916 XRecolorCursor(dpy
, scr
->defaultCursor
, &green
, &back
);
917 } else if (ostate
== 3) {
918 XRecolorCursor(dpy
, scr
->defaultCursor
, &black
, &back
);
925 WMDeleteTimerHandler(timer
);
927 } else if (_XErrorOccured
) {
928 /* got a timeout, send leave */
929 notifyDragLeave(scr
, &dragInfo
);
932 XUngrabPointer(dpy
, CurrentTime
);
934 SPIT("exited main loop");
936 if (_XErrorOccured
|| state
!= 6) {
940 assert(dragInfo
.destinationWindow
!= None
);
943 notifyDrop(scr
, &dragInfo
);
953 XDestroyWindow(dpy
, icon
);
958 scr
->dragSourceView
= NULL
;
960 WMDeleteSelectionHandler(view
, scr
->xdndSelectionAtom
,
961 event
->xmotion
.time
);
964 slideWindow(dpy
, icon
,
965 dragInfo
.imageLocation
.x
, dragInfo
.imageLocation
.y
,
966 atLocation
.x
, atLocation
.y
);
968 XDestroyWindow(dpy
, icon
);
969 if (view
->dragSourceProcs
->endedDragImage
!= NULL
) {
970 view
->dragSourceProcs
->endedDragImage(view
, image
,
971 dragInfo
.imageLocation
,
988 operationToAction(WMScreen
*scr
, WMDragOperationType operation
)
991 case WDOperationNone
:
994 case WDOperationCopy
:
995 return scr
->xdndActionCopy
;
997 case WDOperationMove
:
998 return scr
->xdndActionMove
;
1000 case WDOperationLink
:
1001 return scr
->xdndActionLink
;
1003 case WDOperationAsk
:
1004 return scr
->xdndActionAsk
;
1006 case WDOperationPrivate
:
1007 return scr
->xdndActionPrivate
;
1015 static WMDragOperationType
1016 actionToOperation(WMScreen
*scr
, Atom action
)
1018 if (action
== scr
->xdndActionCopy
) {
1019 return WDOperationCopy
;
1021 } else if (action
== scr
->xdndActionMove
) {
1022 return WDOperationMove
;
1024 } else if (action
== scr
->xdndActionLink
) {
1025 return WDOperationLink
;
1027 } else if (action
== scr
->xdndActionAsk
) {
1028 return WDOperationAsk
;
1030 } else if (action
== scr
->xdndActionPrivate
) {
1031 return WDOperationPrivate
;
1033 } else if (action
== None
) {
1035 return WDOperationCopy
;
1037 char *tmp
= XGetAtomName(scr
->display
, action
);
1039 wwarning("unknown XDND action %s from 0x%x", tmp
,
1040 (unsigned)scr
->dragInfo
.sourceWindow
);
1043 return WDOperationCopy
;
1053 getTypeList(Window window
, XClientMessageEvent
*event
)
1058 if (event
->data
.l
[1] & 1) { /* > 3 types */
1061 types
= wmalloc(4 * sizeof(Atom
));
1062 if (event
->data
.l
[2] != None
)
1063 types
[i
++] = event
->data
.l
[2];
1064 if (event
->data
.l
[3] != None
)
1065 types
[i
++] = event
->data
.l
[3];
1066 if (event
->data
.l
[4] != None
)
1067 types
[i
++] = event
->data
.l
[4];
1071 if (types
[0] == 0) {
1072 wwarning("received invalid drag & drop type list");
1081 #define DISPATCH(view, func, info) (view)->dragDestinationProcs->func(view, info)
1086 receivedData(WMView
*view
, Atom selection
, Atom target
,
1087 Time timestamp
, void *cdata
, WMData
*data
)
1089 WMScreen
*scr
= W_VIEW_SCREEN(view
);
1090 WMDraggingInfo
*info
= (WMDraggingInfo
*)cdata
;
1093 res
= view
->dragDestinationProcs
->performDragOperation(view
, info
);
1096 DISPATCH(view
, concludeDragOperation
, info
);
1099 /* send finished message */
1100 sendClientMessage(scr
->display
, info
->sourceWindow
,
1101 scr
->xdndFinishedAtom
,
1102 info
->destinationWindow
,
1105 memset(&scr
->dragInfo
, 0, sizeof(WMDraggingInfo
));
1111 W_HandleDNDClientMessage(WMView
*toplevel
, XClientMessageEvent
*event
)
1113 WMScreen
*scr
= W_VIEW_SCREEN(toplevel
);
1114 WMView
*oldView
= NULL
;
1115 WMView
*newView
= NULL
;
1116 unsigned operation
= 0;
1122 WCross
, /* leave one and enter another */
1127 int what
= WNothing
;
1128 Bool sendStatus
= False
;
1131 source
= scr
->dragInfo
.sourceWindow
;
1132 oldView
= scr
->dragInfo
.destView
;
1134 if (event
->message_type
== scr
->xdndFinishedAtom
) {
1135 WMView
*view
= scr
->dragSourceView
;
1137 WMDeleteSelectionHandler(view
, scr
->xdndSelectionAtom
,
1138 scr
->dragInfo
.timestamp
);
1140 if (view
->dragSourceProcs
->endedDragImage
!= NULL
) {
1141 view
->dragSourceProcs
->endedDragImage(view
,
1142 scr
->dragInfo
.image
,
1143 scr
->dragInfo
.imageLocation
,
1147 scr
->dragSourceView
= NULL
;
1154 if (event
->message_type
== scr
->xdndEnterAtom
) {
1159 if (scr
->dragInfo
.sourceWindow
!= None
) {
1160 puts("received Enter event in bad order");
1163 memset(&scr
->dragInfo
, 0, sizeof(WMDraggingInfo
));
1166 if ((event
->data
.l
[1] >> 24) > XDND_VERSION
) {
1167 wwarning("received drag & drop request with unsupported version %i",
1168 (event
->data
.l
[1] >> 24));
1172 scr
->dragInfo
.protocolVersion
= event
->data
.l
[1] >> 24;
1173 scr
->dragInfo
.sourceWindow
= source
= event
->data
.l
[0];
1174 scr
->dragInfo
.destinationWindow
= event
->window
;
1176 getMouseOffsetHint(scr
, source
, &scr
->dragInfo
.mouseOffset
);
1179 scr
->dragInfo
.image
= NULL
;
1181 XQueryPointer(scr
->display
, scr
->rootWin
, &foo
, &bar
,
1182 &scr
->dragInfo
.location
.x
, &scr
->dragInfo
.location
.y
,
1185 scr
->dragInfo
.imageLocation
= scr
->dragInfo
.location
;
1186 scr
->dragInfo
.imageLocation
.x
-= scr
->dragInfo
.mouseOffset
.width
;
1187 scr
->dragInfo
.imageLocation
.y
-= scr
->dragInfo
.mouseOffset
.height
;
1189 translateCoordinates(scr
, scr
->dragInfo
.destinationWindow
,
1190 scr
->dragInfo
.location
.x
,
1191 scr
->dragInfo
.location
.y
, &x
, &y
);
1194 newView
= findViewInToplevel(scr
->display
,
1195 scr
->dragInfo
.destinationWindow
,
1198 } else if (event
->message_type
== scr
->xdndPositionAtom
1199 && scr
->dragInfo
.sourceWindow
== event
->data
.l
[0]) {
1201 scr
->dragInfo
.location
.x
= event
->data
.l
[2] >> 16;
1202 scr
->dragInfo
.location
.y
= event
->data
.l
[2] & 0xffff;
1204 scr
->dragInfo
.imageLocation
= scr
->dragInfo
.location
;
1205 scr
->dragInfo
.imageLocation
.x
-= scr
->dragInfo
.mouseOffset
.width
;
1206 scr
->dragInfo
.imageLocation
.y
-= scr
->dragInfo
.mouseOffset
.height
;
1208 if (scr
->dragInfo
.protocolVersion
>= 1) {
1209 scr
->dragInfo
.timestamp
= event
->data
.l
[3];
1210 scr
->dragInfo
.sourceOperation
= actionToOperation(scr
,
1214 scr
->dragInfo
.timestamp
= CurrentTime
;
1215 scr
->dragInfo
.sourceOperation
= WDOperationCopy
;
1218 translateCoordinates(scr
, scr
->dragInfo
.destinationWindow
,
1219 scr
->dragInfo
.location
.x
,
1220 scr
->dragInfo
.location
.y
, &x
, &y
);
1222 newView
= findViewInToplevel(scr
->display
,
1223 scr
->dragInfo
.destinationWindow
,
1226 } else if (event
->message_type
== scr
->xdndLeaveAtom
1227 && scr
->dragInfo
.sourceWindow
== event
->data
.l
[0]) {
1229 memset(&scr
->dragInfo
, 0, sizeof(WMDraggingInfo
));
1231 } else if (event
->message_type
== scr
->xdndDropAtom
1232 && scr
->dragInfo
.sourceWindow
== event
->data
.l
[0]) {
1235 if (oldView
!= NULL
)
1244 * Now map the XDND events to WINGs events.
1247 if (what
== WNothing
) {
1248 if (IS_DROPPABLE(newView
)) {
1249 if (!IS_DROPPABLE(oldView
)) { /* entered */
1251 } else if (oldView
== newView
) { /* updated */
1257 if (IS_DROPPABLE(oldView
)) {
1260 /* just send rejection msg */
1271 scr
->dragInfo
.destView
= newView
;
1272 operation
= DISPATCH(newView
, draggingEntered
, &scr
->dragInfo
);
1277 scr
->dragInfo
.destView
= NULL
;
1278 DISPATCH(oldView
, draggingExited
, &scr
->dragInfo
);
1280 operation
= WDOperationNone
;
1284 DISPATCH(oldView
, draggingExited
, &scr
->dragInfo
);
1285 scr
->dragInfo
.destView
= newView
;
1286 operation
= DISPATCH(newView
, draggingEntered
, &scr
->dragInfo
);
1291 operation
= DISPATCH(oldView
, draggingUpdated
, &scr
->dragInfo
);
1299 res
= DISPATCH(oldView
, prepareForDragOperation
, &scr
->dragInfo
);
1302 res
= DISPATCH(oldView
, performDragOperation
, &scr
->dragInfo
);
1320 action
= operationToAction(scr
, operation
);
1322 sendClientMessage(scr
->display
, source
,
1323 scr
->xdndStatusAtom
,
1324 scr
->dragInfo
.destinationWindow
,
1325 action
!= None
? 1 : 0, 0, 0, action
);