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
;
35 defDraggingSourceOperation(WMView
*self
, Bool local
)
37 return WDOperationCopy
;
42 defBeganDragImage(WMView
*self
, WMPixmap
*image
, WMPoint point
)
48 defEndedDragImage(WMView
*self
, WMPixmap
*image
, WMPoint point
, Bool deposited
)
54 defFetchDragData(WMView
*self
, char *type
)
61 WMSetViewDragSourceProcs(WMView
*view
, WMDragSourceProcs
*procs
)
63 if (view
->dragSourceProcs
)
64 wfree(view
->dragSourceProcs
);
65 view
->dragSourceProcs
= wmalloc(sizeof(WMDragSourceProcs
));
67 *view
->dragSourceProcs
= *procs
;
69 if (procs
->draggingSourceOperation
== NULL
) {
70 view
->dragSourceProcs
->draggingSourceOperation
= defDraggingSourceOperation
;
72 if (procs
->beganDragImage
== NULL
) {
73 view
->dragSourceProcs
->beganDragImage
= defBeganDragImage
;
75 if (procs
->endedDragImage
== NULL
) {
76 view
->dragSourceProcs
->endedDragImage
= defEndedDragImage
;
78 if (procs
->fetchDragData
== NULL
) {
79 view
->dragSourceProcs
->fetchDragData
= defFetchDragData
;
84 /***********************************************************************/
88 handleXError(Display
*dpy
, XErrorEvent
*ev
)
90 _XErrorOccured
= True
;
97 protectBlock(Bool begin
)
99 static void *oldHandler
= NULL
;
102 oldHandler
= XSetErrorHandler(handleXError
);
104 XSetErrorHandler(oldHandler
);
112 makeDragIcon(WMScreen
*scr
, WMPixmap
*pixmap
)
117 XSetWindowAttributes attribs
;
121 pixmap
= scr
->defaultObjectIcon
;
123 size
= WMGetPixmapSize(pixmap
);
124 pix
= pixmap
->pixmap
;
127 flags
= CWSaveUnder
|CWBackPixmap
|CWOverrideRedirect
|CWColormap
;
128 attribs
.save_under
= True
;
129 attribs
.background_pixmap
= pix
;
130 attribs
.override_redirect
= True
;
131 attribs
.colormap
= scr
->colormap
;
132 window
= XCreateWindow(scr
->display
, scr
->rootWin
, 0, 0, size
.width
,
133 size
.height
, 0, scr
->depth
, InputOutput
,
134 scr
->visual
, flags
, &attribs
);
138 XShapeCombineMask(scr
->display
, window
, ShapeBounding
, 0, 0, mask
,
148 slideWindow(Display
*dpy
, Window win
, int srcX
, int srcY
, int dstX
, int dstY
)
154 iterations
= WMIN(25, WMAX(abs(dstX
-srcX
), abs(dstY
-srcY
)));
159 dx
= (double)(dstX
-srcX
)/iterations
;
160 dy
= (double)(dstY
-srcY
)/iterations
;
162 for (i
= 0; i
<= iterations
; i
++) {
163 XMoveWindow(dpy
, win
, x
, y
);
175 findChildInWindow(Display
*dpy
, Window toplevel
, int x
, int y
)
182 if (!XQueryTree(dpy
, toplevel
, &foo
, &bar
,
183 &children
, &nchildren
) || children
== NULL
) {
187 /* first window that contains the point is the one */
188 for (i
= nchildren
-1; i
>= 0; i
--) {
189 XWindowAttributes attr
;
191 if (XGetWindowAttributes(dpy
, children
[i
], &attr
)
192 && attr
.map_state
== IsViewable
193 && x
>= attr
.x
&& y
>= attr
.y
194 && x
< attr
.x
+ attr
.width
&& y
< attr
.y
+ attr
.height
) {
199 child
= findChildInWindow(dpy
, tmp
, x
- attr
.x
, y
- attr
.y
);
216 findViewInToplevel(Display
*dpy
, Window toplevel
, int x
, int y
)
220 child
= findChildInWindow(dpy
, toplevel
, x
, y
);
223 return W_GetViewForXWindow(dpy
, child
);
232 lookForToplevel(WMScreen
*scr
, Window window
, Bool
*isAware
)
234 Window toplevel
= None
;
240 atoms
= XListProperties(scr
->display
, window
, &count
);
241 for (j
= 0; j
< count
; j
++) {
242 if (atoms
[j
] == scr
->wmStateAtom
) {
244 } else if (atoms
[j
] == scr
->xdndAwareAtom
) {
251 if (toplevel
== None
) {
256 if (!XQueryTree(scr
->display
, window
, &foo
, &bar
,
257 &children
, &nchildren
) || children
== NULL
) {
261 for (j
= 0; j
< nchildren
; j
++) {
262 toplevel
= lookForToplevel(scr
, children
[j
], isAware
);
263 if (toplevel
!= None
)
276 findToplevelUnderDragPointer(WMScreen
*scr
, int x
, int y
, Window iconWindow
)
281 Bool overSomething
= False
;
284 if (!XQueryTree(scr
->display
, scr
->rootWin
, &foo
, &bar
,
285 &children
, &nchildren
) || children
== NULL
) {
286 SPIT("couldnt query tree!");
290 /* try to find the window below the iconWindow by traversing
291 * the whole window list */
293 /* first find the position of the iconWindow */
294 for (i
= nchildren
-1; i
>= 0; i
--) {
295 if (children
[i
] == iconWindow
) {
305 /* first window that contains the point is the one */
306 for (; i
>= 0; i
--) {
307 XWindowAttributes attr
;
309 if (XGetWindowAttributes(scr
->display
, children
[i
], &attr
)
310 && attr
.map_state
== IsViewable
311 && x
>= attr
.x
&& y
>= attr
.y
312 && x
< attr
.x
+ attr
.width
&& y
< attr
.y
+ attr
.height
) {
316 overSomething
= True
;
318 toplevel
= lookForToplevel(scr
, children
[i
], &isaware
);
342 sendClientMessage(Display
*dpy
, Window win
, Atom message
,
343 unsigned data1
, unsigned data2
, unsigned data3
,
344 unsigned data4
, unsigned data5
)
348 ev
.type
= ClientMessage
;
349 ev
.xclient
.message_type
= message
;
350 ev
.xclient
.format
= 32;
351 ev
.xclient
.window
= win
;
352 ev
.xclient
.data
.l
[0] = data1
;
353 ev
.xclient
.data
.l
[1] = data2
;
354 ev
.xclient
.data
.l
[2] = data3
;
355 ev
.xclient
.data
.l
[3] = data4
;
356 ev
.xclient
.data
.l
[4] = data5
;
358 XSendEvent(dpy
, win
, False
, 0, &ev
);
366 notifyPosition(WMScreen
*scr
, WMDraggingInfo
*info
)
368 Atom action
= operationToAction(scr
, info
->sourceOperation
);
370 sendClientMessage(scr
->display
, info
->destinationWindow
,
371 scr
->xdndPositionAtom
,
374 info
->location
.x
<<16|info
->location
.y
,
376 action
/* operation */);
384 notifyDrop(WMScreen
*scr
, WMDraggingInfo
*info
)
386 sendClientMessage(scr
->display
, info
->destinationWindow
,
397 notifyDragLeave(WMScreen
*scr
, WMDraggingInfo
*info
)
399 sendClientMessage(scr
->display
, info
->destinationWindow
,
401 info
->sourceWindow
, 0, 0, 0, 0);
407 notifyDragEnter(WMScreen
*scr
, WMDraggingInfo
*info
)
411 d
= XDND_VERSION
<< 24;
413 sendClientMessage(scr
->display
, info
->destinationWindow
,
415 info
->sourceWindow
, d
, 0, 0, 0);
422 translateCoordinates(WMScreen
*scr
, Window target
, int fromX
, int fromY
,
427 XTranslateCoordinates(scr
->display
, scr
->rootWin
, target
,
428 fromX
, fromY
, x
, y
, &child
);
433 updateDraggingInfo(WMScreen
*scr
, WMDraggingInfo
*info
, WMSize offset
,
434 XEvent
*event
, Window iconWindow
)
438 if (event
->type
== MotionNotify
) {
439 info
->imageLocation
.x
= event
->xmotion
.x_root
-offset
.width
;
440 info
->imageLocation
.y
= event
->xmotion
.y_root
-offset
.height
;
442 info
->location
.x
= event
->xmotion
.x_root
;
443 info
->location
.y
= event
->xmotion
.y_root
;
444 /* info->timestamp = event->xmotion.time;*/
446 } else if (event
->type
== ButtonRelease
) {
447 info
->imageLocation
.x
= event
->xbutton
.x_root
-offset
.width
;
448 info
->imageLocation
.y
= event
->xbutton
.y_root
-offset
.height
;
450 info
->location
.x
= event
->xbutton
.x_root
;
451 info
->location
.y
= event
->xbutton
.y_root
;
452 /* info->timestamp = event->xbutton.time;*/
455 toplevel
= findToplevelUnderDragPointer(scr
,
459 info
->destinationWindow
= toplevel
;
466 processMotion(WMScreen
*scr
, WMDraggingInfo
*info
, WMDraggingInfo
*oldInfo
,
467 WMRect
*rect
, unsigned currentAction
)
471 if (info
->destinationWindow
== None
) { /* entered an unsupporeted window */
473 if (oldInfo
->destinationWindow
!= None
474 && oldInfo
->destinationWindow
!= scr
->rootWin
) {
477 notifyDragLeave(scr
, oldInfo
);
480 } else if (info
->destinationWindow
== scr
->rootWin
) {
482 if (oldInfo
->destinationWindow
!= None
483 && oldInfo
->destinationWindow
!= scr
->rootWin
) {
484 SPIT("left window to root");
486 notifyDragLeave(scr
, oldInfo
);
491 } else if (oldInfo
->destinationWindow
!= info
->destinationWindow
) {
493 if (oldInfo
->destinationWindow
!= None
494 && oldInfo
->destinationWindow
!= scr
->rootWin
) {
495 notifyDragLeave(scr
, oldInfo
);
498 SPIT("entered window");
501 action
= notifyDragEnter(scr
, info
);
505 #define LEFT_RECT(r, X, Y) (X < r->pos.x || Y < r->pos.y \
506 || X >= r->pos.x + r->size.width \
507 || Y >= r->pos.y + r->size.height)
509 if (rect
->size
.width
== 0 ||
510 (LEFT_RECT(rect
, info
->location
.x
, info
->location
.y
))) {
512 action
= notifyPosition(scr
, info
);
514 rect
->size
.width
= 0;
522 convertSelection(WMView
*view
, Atom selection
, Atom target
,
523 void *cdata
, Atom
*type
)
525 WMScreen
*scr
= W_VIEW_SCREEN(view
);
527 char *typeName
= XGetAtomName(scr
->display
, target
);
531 data
= view
->dragSourceProcs
->fetchDragData(view
, typeName
);
533 if (typeName
!= NULL
)
541 selectionLost(WMView
*view
, Atom selection
, void *cdata
)
543 if (W_VIEW_SCREEN(view
)->dragSourceView
== view
) {
544 wwarning("DND selection lost during drag operation...");
545 W_VIEW_SCREEN(view
)->dragSourceView
= NULL
;
551 selectionDone(WMView
*view
, Atom selection
, Atom target
, void *cdata
)
561 setMouseOffsetHint(WMView
*view
, WMSize mouseOffset
)
563 WMScreen
*scr
= W_VIEW_SCREEN(view
);
567 * Tell the offset from the topleft corner of the icon being
568 * dragged. Not from XDND, but it's backwards compatible.
571 hint
[0] = mouseOffset
.width
;
572 hint
[1] = mouseOffset
.height
;
574 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(view
),
575 scr
->wmIconDragOffsetAtom
, XA_INTEGER
, 32,
576 PropModeReplace
, (unsigned char*)hint
, 2);
581 getMouseOffsetHint(WMScreen
*scr
, Window source
, WMSize
*mouseOffset
)
586 unsigned long nitems_ret
, bytes_after_ret
;
592 XGetWindowProperty(scr
->display
, source
,
593 scr
->wmIconDragOffsetAtom
, 0, 2, False
, XA_INTEGER
,
594 &type_ret
, &fmt_ret
, &nitems_ret
, &bytes_after_ret
,
595 (unsigned char **)&hint
);
597 if (hint
&& nitems_ret
== 2) {
598 mouseOffset
->width
= hint
[0];
599 mouseOffset
->height
= hint
[1];
611 timeoutCallback(void *data
)
613 wwarning("drag & drop timed out while waiting for response from 0x%x\n",
619 * State Machine For Drag Source:
620 * ------------------------------
622 * State Call Mtn Ent Lea Crs BUp StA StR Fin TO
623 * 0) idle 1bu - - - - - - - - -
624 * 1) drag over target - 1au - 2cu 1cbu 5fu 3 4 1w -
625 * 2) drag over nothing - 2 1bu - - 0 - - 2w -
626 * 3) drag targ+accept - 3u - 2cu 1cbu 6f 3 4w 0z -
627 * 4) drag targ+reject - 4u - 2cu 1cbu 0 3w 4 0z -
628 * 5) waiting status - 5X 5X 5X 5X - 6f 0 0z 0w
629 * 6) dropped - - - - - - - - 0 0w
632 * Call - called WMDragImageFromView()
634 * Ent - Enter droppable window
635 * Lea - Leave droppable window (or rectangle)
636 * Crs - Leave droppable window (or rectangle) and enter another
637 * BUp - Button Released
638 * StA - XdndStatus client msg with Accept drop
639 * StR - XdndStatus client msg with Reject drop
640 * Fin - XdndFinish client msg
644 * a - send update message
645 * b - send enter message
646 * c - send leave message
647 * d - release drag section info
648 * e - send drop message
650 * u - update dragInfo
653 * w - warn about unexpected reply
654 * z - abort operation.. unexpected reply
658 WMDragImageFromView(WMView
*view
, WMPixmap
*image
, char *dataTypes
[],
659 WMPoint atLocation
, WMSize mouseOffset
, XEvent
*event
,
662 WMScreen
*scr
= view
->screen
;
663 Display
*dpy
= scr
->display
;
664 WMView
*toplevel
= W_TopLevelOfView(view
);
667 WMRect rect
= {{0,0},{0,0}};
671 XColor black
= {0, 0,0,0, DoRed
|DoGreen
|DoBlue
};
672 XColor green
= {0x0045b045, 0x4500,0xb000,0x4500, DoRed
|DoGreen
|DoBlue
};
673 XColor back
= {0, 0xffff,0xffff,0xffff, DoRed
|DoGreen
|DoBlue
};
674 WMDraggingInfo dragInfo
;
675 WMDraggingInfo oldDragInfo
;
676 WMHandlerID timer
= NULL
;
677 static WMSelectionProcs handler
= {
684 if (scr
->dragSourceView
!= NULL
)
687 wassertr(view
->dragSourceProcs
!= NULL
);
690 /* prepare icon to be dragged */
692 image
= scr
->defaultObjectIcon
;
694 icon
= makeDragIcon(scr
, image
);
696 XMoveWindow(dpy
, icon
, atLocation
.x
, atLocation
.y
);
697 XMapRaised(dpy
, icon
);
700 /* init dragging info */
702 scr
->dragSourceView
= view
;
704 memset(&dragInfo
, 0, sizeof(WMDraggingInfo
));
705 memset(&oldDragInfo
, 0, sizeof(WMDraggingInfo
));
706 dragInfo
.image
= image
;
707 dragInfo
.sourceView
= view
;
708 dragInfo
.sourceWindow
= W_VIEW_DRAWABLE(toplevel
);
710 dragInfo
.destinationWindow
= dragInfo
.sourceWindow
;
712 dragInfo
.location
.x
= atLocation
.x
+ mouseOffset
.width
;
713 dragInfo
.location
.y
= atLocation
.y
+ mouseOffset
.height
;
714 dragInfo
.imageLocation
= atLocation
;
717 /* start pointer grab */
718 XGrabPointer(dpy
, scr
->rootWin
, False
,
719 ButtonPressMask
|ButtonReleaseMask
|ButtonMotionMask
,
720 GrabModeAsync
, GrabModeAsync
, None
, scr
->defaultCursor
,
725 _XErrorOccured
= False
;
727 /* take ownership of XdndSelection */
728 if (!WMCreateSelectionHandler(view
, scr
->xdndSelectionAtom
,
731 wwarning("could not get ownership or DND selection");
735 setMouseOffsetHint(toplevel
, mouseOffset
);
737 if (view
->dragSourceProcs
->beganDragImage
!= NULL
) {
738 view
->dragSourceProcs
->beganDragImage(view
, image
, atLocation
);
741 processMotion(scr
, &dragInfo
, &oldDragInfo
, &rect
, action
);
745 while (state
!= 6 && state
!= 0 && !_XErrorOccured
) {
746 WMNextEvent(dpy
, &ev
);
750 if (state
>= 1 && state
<= 4) {
751 while (XCheckTypedEvent(dpy
, MotionNotify
, &ev
)) ;
755 oldDragInfo
= dragInfo
;
757 updateDraggingInfo(scr
, &dragInfo
, mouseOffset
, &ev
, icon
);
759 XMoveWindow(dpy
, icon
, dragInfo
.imageLocation
.x
,
760 dragInfo
.imageLocation
.y
);
762 processMotion(scr
, &dragInfo
, &oldDragInfo
, &rect
, action
);
766 /* XXXif entered a different destination, check the operation */
770 if (oldDragInfo
.destinationWindow
!= None
771 && oldDragInfo
.destinationWindow
!= scr
->rootWin
772 && (dragInfo
.destinationWindow
== None
773 || dragInfo
.destinationWindow
== scr
->rootWin
)) {
774 /* left the droppable window */
781 if (dragInfo
.destinationWindow
!= None
782 && dragInfo
.destinationWindow
!= scr
->rootWin
) {
791 if (oldDragInfo
.destinationWindow
!= None
792 && oldDragInfo
.destinationWindow
!= scr
->rootWin
793 && (dragInfo
.destinationWindow
== None
794 || dragInfo
.destinationWindow
== scr
->rootWin
)) {
795 /* left the droppable window */
806 /* if (state >= 1 && state <= 4) */ {
810 oldDragInfo
= dragInfo
;
812 updateDraggingInfo(scr
, &dragInfo
, mouseOffset
, &ev
, icon
);
814 XMoveWindow(dpy
, icon
, dragInfo
.imageLocation
.x
,
815 dragInfo
.imageLocation
.y
);
817 if (state
== 4 || state
== 1) {
818 dragInfo
.destinationWindow
= None
;
819 dragInfo
.destView
= NULL
;
821 processMotion(scr
, &dragInfo
, &oldDragInfo
, &rect
, action
);
823 dragInfo
.timestamp
= ev
.xbutton
.time
;
830 timer
= WMAddTimerHandler(3000, timeoutCallback
,
831 (void*)dragInfo
.destinationWindow
);
847 if ((state
== 1 || state
== 3 || state
== 4 || state
== 5)
848 && ev
.xclient
.message_type
== scr
->xdndStatusAtom
849 && ev
.xclient
.data
.l
[0] == dragInfo
.destinationWindow
) {
851 if (ev
.xclient
.data
.l
[1] & 1) {
852 SPIT("got accept msg");
853 /* will accept drop */
862 WMDeleteTimerHandler(timer
);
868 action
= actionToOperation(scr
, ev
.xclient
.data
.l
[4]);
870 SPIT("got reject msg");
880 WMDeleteTimerHandler(timer
);
888 if (ev
.xclient
.data
.l
[1] & (1<<1)) {
889 rect
.pos
.x
= ev
.xclient
.data
.l
[2] >> 16;
890 rect
.pos
.y
= ev
.xclient
.data
.l
[2] & 0xffff;
891 rect
.size
.width
= ev
.xclient
.data
.l
[3] >> 16;
892 rect
.size
.height
= ev
.xclient
.data
.l
[3] & 0xffff;
897 } else if ((state
>= 1 && state
<= 5)
898 && ev
.xclient
.message_type
== scr
->xdndFinishedAtom
899 && ev
.xclient
.window
== dragInfo
.destinationWindow
) {
901 wwarning("drag source received unexpected XdndFinished message from %x",
902 (unsigned)dragInfo
.destinationWindow
);
904 if (state
== 3 || state
== 4 || state
== 5) {
907 WMDeleteTimerHandler(timer
);
918 if (ostate
!= state
) {
920 XRecolorCursor(dpy
, scr
->defaultCursor
, &green
, &back
);
921 } else if (ostate
== 3) {
922 XRecolorCursor(dpy
, scr
->defaultCursor
, &black
, &back
);
929 WMDeleteTimerHandler(timer
);
931 } else if (_XErrorOccured
) {
932 /* got a timeout, send leave */
933 notifyDragLeave(scr
, &dragInfo
);
936 XUngrabPointer(dpy
, CurrentTime
);
938 SPIT("exited main loop");
940 if (_XErrorOccured
|| state
!= 6) {
944 assert(dragInfo
.destinationWindow
!= None
);
947 notifyDrop(scr
, &dragInfo
);
957 XDestroyWindow(dpy
, icon
);
962 scr
->dragSourceView
= NULL
;
964 WMDeleteSelectionHandler(view
, scr
->xdndSelectionAtom
,
965 event
->xmotion
.time
);
968 slideWindow(dpy
, icon
,
969 dragInfo
.imageLocation
.x
, dragInfo
.imageLocation
.y
,
970 atLocation
.x
, atLocation
.y
);
972 XDestroyWindow(dpy
, icon
);
973 if (view
->dragSourceProcs
->endedDragImage
!= NULL
) {
974 view
->dragSourceProcs
->endedDragImage(view
, image
,
975 dragInfo
.imageLocation
,
992 operationToAction(WMScreen
*scr
, WMDragOperationType operation
)
995 case WDOperationNone
:
998 case WDOperationCopy
:
999 return scr
->xdndActionCopy
;
1001 case WDOperationMove
:
1002 return scr
->xdndActionMove
;
1004 case WDOperationLink
:
1005 return scr
->xdndActionLink
;
1007 case WDOperationAsk
:
1008 return scr
->xdndActionAsk
;
1010 case WDOperationPrivate
:
1011 return scr
->xdndActionPrivate
;
1019 static WMDragOperationType
1020 actionToOperation(WMScreen
*scr
, Atom action
)
1022 if (action
== scr
->xdndActionCopy
) {
1023 return WDOperationCopy
;
1025 } else if (action
== scr
->xdndActionMove
) {
1026 return WDOperationMove
;
1028 } else if (action
== scr
->xdndActionLink
) {
1029 return WDOperationLink
;
1031 } else if (action
== scr
->xdndActionAsk
) {
1032 return WDOperationAsk
;
1034 } else if (action
== scr
->xdndActionPrivate
) {
1035 return WDOperationPrivate
;
1037 } else if (action
== None
) {
1039 return WDOperationCopy
;
1041 char *tmp
= XGetAtomName(scr
->display
, action
);
1043 wwarning("unknown XDND action %s from 0x%x", tmp
,
1044 (unsigned)scr
->dragInfo
.sourceWindow
);
1047 return WDOperationCopy
;
1057 getTypeList(Window window
, XClientMessageEvent
*event
)
1062 if (event
->data
.l
[1] & 1) { /* > 3 types */
1065 types
= wmalloc(4 * sizeof(Atom
));
1066 if (event
->data
.l
[2] != None
)
1067 types
[i
++] = event
->data
.l
[2];
1068 if (event
->data
.l
[3] != None
)
1069 types
[i
++] = event
->data
.l
[3];
1070 if (event
->data
.l
[4] != None
)
1071 types
[i
++] = event
->data
.l
[4];
1075 if (types
[0] == 0) {
1076 wwarning("received invalid drag & drop type list");
1085 #define DISPATCH(view, func, info) (view)->dragDestinationProcs->func(view, info)
1090 receivedData(WMView
*view
, Atom selection
, Atom target
,
1091 Time timestamp
, void *cdata
, WMData
*data
)
1093 WMScreen
*scr
= W_VIEW_SCREEN(view
);
1094 WMDraggingInfo
*info
= (WMDraggingInfo
*)cdata
;
1097 res
= view
->dragDestinationProcs
->performDragOperation(view
, info
);
1100 DISPATCH(view
, concludeDragOperation
, info
);
1103 /* send finished message */
1104 sendClientMessage(scr
->display
, info
->sourceWindow
,
1105 scr
->xdndFinishedAtom
,
1106 info
->destinationWindow
,
1109 memset(&scr
->dragInfo
, 0, sizeof(WMDraggingInfo
));
1115 W_HandleDNDClientMessage(WMView
*toplevel
, XClientMessageEvent
*event
)
1117 WMScreen
*scr
= W_VIEW_SCREEN(toplevel
);
1118 WMView
*oldView
= NULL
;
1119 WMView
*newView
= NULL
;
1120 unsigned operation
= 0;
1126 WCross
, /* leave one and enter another */
1131 int what
= WNothing
;
1132 Bool sendStatus
= False
;
1135 source
= scr
->dragInfo
.sourceWindow
;
1136 oldView
= scr
->dragInfo
.destView
;
1138 if (event
->message_type
== scr
->xdndFinishedAtom
) {
1139 WMView
*view
= scr
->dragSourceView
;
1141 WMDeleteSelectionHandler(view
, scr
->xdndSelectionAtom
,
1142 scr
->dragInfo
.timestamp
);
1144 if (view
->dragSourceProcs
->endedDragImage
!= NULL
) {
1145 view
->dragSourceProcs
->endedDragImage(view
,
1146 scr
->dragInfo
.image
,
1147 scr
->dragInfo
.imageLocation
,
1151 scr
->dragSourceView
= NULL
;
1158 if (event
->message_type
== scr
->xdndEnterAtom
) {
1163 if (scr
->dragInfo
.sourceWindow
!= None
) {
1164 puts("received Enter event in bad order");
1167 memset(&scr
->dragInfo
, 0, sizeof(WMDraggingInfo
));
1170 if ((event
->data
.l
[1] >> 24) > XDND_VERSION
) {
1171 wwarning("received drag & drop request with unsupported version %i",
1172 (event
->data
.l
[1] >> 24));
1176 scr
->dragInfo
.protocolVersion
= event
->data
.l
[1] >> 24;
1177 scr
->dragInfo
.sourceWindow
= source
= event
->data
.l
[0];
1178 scr
->dragInfo
.destinationWindow
= event
->window
;
1180 getMouseOffsetHint(scr
, source
, &scr
->dragInfo
.mouseOffset
);
1183 scr
->dragInfo
.image
= NULL
;
1185 XQueryPointer(scr
->display
, scr
->rootWin
, &foo
, &bar
,
1186 &scr
->dragInfo
.location
.x
, &scr
->dragInfo
.location
.y
,
1189 scr
->dragInfo
.imageLocation
= scr
->dragInfo
.location
;
1190 scr
->dragInfo
.imageLocation
.x
-= scr
->dragInfo
.mouseOffset
.width
;
1191 scr
->dragInfo
.imageLocation
.y
-= scr
->dragInfo
.mouseOffset
.height
;
1193 translateCoordinates(scr
, scr
->dragInfo
.destinationWindow
,
1194 scr
->dragInfo
.location
.x
,
1195 scr
->dragInfo
.location
.y
, &x
, &y
);
1198 newView
= findViewInToplevel(scr
->display
,
1199 scr
->dragInfo
.destinationWindow
,
1202 } else if (event
->message_type
== scr
->xdndPositionAtom
1203 && scr
->dragInfo
.sourceWindow
== event
->data
.l
[0]) {
1205 scr
->dragInfo
.location
.x
= event
->data
.l
[2] >> 16;
1206 scr
->dragInfo
.location
.y
= event
->data
.l
[2] & 0xffff;
1208 scr
->dragInfo
.imageLocation
= scr
->dragInfo
.location
;
1209 scr
->dragInfo
.imageLocation
.x
-= scr
->dragInfo
.mouseOffset
.width
;
1210 scr
->dragInfo
.imageLocation
.y
-= scr
->dragInfo
.mouseOffset
.height
;
1212 if (scr
->dragInfo
.protocolVersion
>= 1) {
1213 scr
->dragInfo
.timestamp
= event
->data
.l
[3];
1214 scr
->dragInfo
.sourceOperation
= actionToOperation(scr
,
1218 scr
->dragInfo
.timestamp
= CurrentTime
;
1219 scr
->dragInfo
.sourceOperation
= WDOperationCopy
;
1222 translateCoordinates(scr
, scr
->dragInfo
.destinationWindow
,
1223 scr
->dragInfo
.location
.x
,
1224 scr
->dragInfo
.location
.y
, &x
, &y
);
1226 newView
= findViewInToplevel(scr
->display
,
1227 scr
->dragInfo
.destinationWindow
,
1230 } else if (event
->message_type
== scr
->xdndLeaveAtom
1231 && scr
->dragInfo
.sourceWindow
== event
->data
.l
[0]) {
1233 memset(&scr
->dragInfo
, 0, sizeof(WMDraggingInfo
));
1235 } else if (event
->message_type
== scr
->xdndDropAtom
1236 && scr
->dragInfo
.sourceWindow
== event
->data
.l
[0]) {
1239 if (oldView
!= NULL
)
1248 * Now map the XDND events to WINGs events.
1251 if (what
== WNothing
) {
1252 if (IS_DROPPABLE(newView
)) {
1253 if (!IS_DROPPABLE(oldView
)) { /* entered */
1255 } else if (oldView
== newView
) { /* updated */
1261 if (IS_DROPPABLE(oldView
)) {
1264 /* just send rejection msg */
1275 scr
->dragInfo
.destView
= newView
;
1276 operation
= DISPATCH(newView
, draggingEntered
, &scr
->dragInfo
);
1281 scr
->dragInfo
.destView
= NULL
;
1282 DISPATCH(oldView
, draggingExited
, &scr
->dragInfo
);
1284 operation
= WDOperationNone
;
1288 DISPATCH(oldView
, draggingExited
, &scr
->dragInfo
);
1289 scr
->dragInfo
.destView
= newView
;
1290 operation
= DISPATCH(newView
, draggingEntered
, &scr
->dragInfo
);
1295 operation
= DISPATCH(oldView
, draggingUpdated
, &scr
->dragInfo
);
1303 res
= DISPATCH(oldView
, prepareForDragOperation
, &scr
->dragInfo
);
1306 res
= DISPATCH(oldView
, performDragOperation
, &scr
->dragInfo
);
1324 action
= operationToAction(scr
, operation
);
1326 sendClientMessage(scr
->display
, source
,
1327 scr
->xdndStatusAtom
,
1328 scr
->dragInfo
.destinationWindow
,
1329 action
!= None
? 1 : 0, 0, 0, action
);