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
)
274 findToplevelUnderDragPointer(WMScreen
*scr
, int x
, int y
, Window iconWindow
)
279 Bool overSomething
= False
;
282 if (!XQueryTree(scr
->display
, scr
->rootWin
, &foo
, &bar
,
283 &children
, &nchildren
) || children
== NULL
) {
284 SPIT("couldnt query tree!");
288 /* try to find the window below the iconWindow by traversing
289 * the whole window list */
291 /* first find the position of the iconWindow */
292 for (i
= nchildren
-1; i
>= 0; i
--) {
293 if (children
[i
] == iconWindow
) {
303 /* first window that contains the point is the one */
304 for (; i
>= 0; i
--) {
305 XWindowAttributes attr
;
307 if (XGetWindowAttributes(scr
->display
, children
[i
], &attr
)
308 && attr
.map_state
== IsViewable
309 && x
>= attr
.x
&& y
>= attr
.y
310 && x
< attr
.x
+ attr
.width
&& y
< attr
.y
+ attr
.height
) {
314 overSomething
= True
;
316 toplevel
= lookForToplevel(scr
, children
[i
], &isaware
);
340 sendClientMessage(Display
*dpy
, Window win
, Atom message
,
341 unsigned data1
, unsigned data2
, unsigned data3
,
342 unsigned data4
, unsigned data5
)
346 ev
.type
= ClientMessage
;
347 ev
.xclient
.message_type
= message
;
348 ev
.xclient
.format
= 32;
349 ev
.xclient
.window
= win
;
350 ev
.xclient
.data
.l
[0] = data1
;
351 ev
.xclient
.data
.l
[1] = data2
;
352 ev
.xclient
.data
.l
[2] = data3
;
353 ev
.xclient
.data
.l
[3] = data4
;
354 ev
.xclient
.data
.l
[4] = data5
;
356 XSendEvent(dpy
, win
, False
, 0, &ev
);
364 notifyPosition(WMScreen
*scr
, WMDraggingInfo
*info
)
366 Atom action
= operationToAction(scr
, info
->sourceOperation
);
368 sendClientMessage(scr
->display
, info
->destinationWindow
,
369 scr
->xdndPositionAtom
,
372 info
->location
.x
<<16|info
->location
.y
,
374 action
/* operation */);
382 notifyDrop(WMScreen
*scr
, WMDraggingInfo
*info
)
384 sendClientMessage(scr
->display
, info
->destinationWindow
,
395 notifyDragLeave(WMScreen
*scr
, WMDraggingInfo
*info
)
397 sendClientMessage(scr
->display
, info
->destinationWindow
,
399 info
->sourceWindow
, 0, 0, 0, 0);
405 notifyDragEnter(WMScreen
*scr
, WMDraggingInfo
*info
)
409 d
= XDND_VERSION
<< 24;
411 sendClientMessage(scr
->display
, info
->destinationWindow
,
413 info
->sourceWindow
, d
, 0, 0, 0);
420 translateCoordinates(WMScreen
*scr
, Window target
, int fromX
, int fromY
,
425 XTranslateCoordinates(scr
->display
, scr
->rootWin
, target
,
426 fromX
, fromY
, x
, y
, &child
);
431 updateDraggingInfo(WMScreen
*scr
, WMDraggingInfo
*info
, WMSize offset
,
432 XEvent
*event
, Window iconWindow
)
436 if (event
->type
== MotionNotify
) {
437 info
->imageLocation
.x
= event
->xmotion
.x_root
-offset
.width
;
438 info
->imageLocation
.y
= event
->xmotion
.y_root
-offset
.height
;
440 info
->location
.x
= event
->xmotion
.x_root
;
441 info
->location
.y
= event
->xmotion
.y_root
;
442 /* info->timestamp = event->xmotion.time;*/
444 } else if (event
->type
== ButtonRelease
) {
445 info
->imageLocation
.x
= event
->xbutton
.x_root
-offset
.width
;
446 info
->imageLocation
.y
= event
->xbutton
.y_root
-offset
.height
;
448 info
->location
.x
= event
->xbutton
.x_root
;
449 info
->location
.y
= event
->xbutton
.y_root
;
450 /* info->timestamp = event->xbutton.time;*/
453 toplevel
= findToplevelUnderDragPointer(scr
,
457 info
->destinationWindow
= toplevel
;
464 processMotion(WMScreen
*scr
, WMDraggingInfo
*info
, WMDraggingInfo
*oldInfo
,
465 WMRect
*rect
, unsigned currentAction
)
469 if (info
->destinationWindow
== None
) { /* entered an unsupporeted window */
471 if (oldInfo
->destinationWindow
!= None
472 && oldInfo
->destinationWindow
!= scr
->rootWin
) {
475 notifyDragLeave(scr
, oldInfo
);
478 } else if (info
->destinationWindow
== scr
->rootWin
) {
480 if (oldInfo
->destinationWindow
!= None
481 && oldInfo
->destinationWindow
!= scr
->rootWin
) {
482 SPIT("left window to root");
484 notifyDragLeave(scr
, oldInfo
);
489 } else if (oldInfo
->destinationWindow
!= info
->destinationWindow
) {
491 if (oldInfo
->destinationWindow
!= None
492 && oldInfo
->destinationWindow
!= scr
->rootWin
) {
493 notifyDragLeave(scr
, oldInfo
);
496 SPIT("entered window");
499 action
= notifyDragEnter(scr
, info
);
503 #define LEFT_RECT(r, X, Y) (X < r->pos.x || Y < r->pos.y \
504 || X >= r->pos.x + r->size.width \
505 || Y >= r->pos.y + r->size.height)
507 if (rect
->size
.width
== 0 ||
508 (LEFT_RECT(rect
, info
->location
.x
, info
->location
.y
))) {
510 action
= notifyPosition(scr
, info
);
512 rect
->size
.width
= 0;
520 convertSelection(WMView
*view
, Atom selection
, Atom target
,
521 void *cdata
, Atom
*type
)
523 WMScreen
*scr
= W_VIEW_SCREEN(view
);
525 char *typeName
= XGetAtomName(scr
->display
, target
);
529 data
= view
->dragSourceProcs
->fetchDragData(view
, typeName
);
531 if (typeName
!= NULL
)
539 selectionLost(WMView
*view
, Atom selection
, void *cdata
)
541 if (W_VIEW_SCREEN(view
)->dragSourceView
== view
) {
542 wwarning("DND selection lost during drag operation...");
543 W_VIEW_SCREEN(view
)->dragSourceView
= NULL
;
549 selectionDone(WMView
*view
, Atom selection
, Atom target
, void *cdata
)
559 setMouseOffsetHint(WMView
*view
, WMSize mouseOffset
)
561 WMScreen
*scr
= W_VIEW_SCREEN(view
);
565 * Tell the offset from the topleft corner of the icon being
566 * dragged. Not from XDND, but it's backwards compatible.
569 hint
[0] = mouseOffset
.width
;
570 hint
[1] = mouseOffset
.height
;
572 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(view
),
573 scr
->wmIconDragOffsetAtom
, XA_INTEGER
, 32,
574 PropModeReplace
, (unsigned char*)hint
, 2);
579 getMouseOffsetHint(WMScreen
*scr
, Window source
, WMSize
*mouseOffset
)
584 unsigned long nitems_ret
, bytes_after_ret
;
590 XGetWindowProperty(scr
->display
, source
,
591 scr
->wmIconDragOffsetAtom
, 0, 2, False
, XA_INTEGER
,
592 &type_ret
, &fmt_ret
, &nitems_ret
, &bytes_after_ret
,
593 (unsigned char **)&hint
);
595 if (hint
&& nitems_ret
== 2) {
596 mouseOffset
->width
= hint
[0];
597 mouseOffset
->height
= hint
[1];
609 timeoutCallback(void *data
)
611 wwarning("drag & drop timed out while waiting for response from 0x%x\n",
617 * State Machine For Drag Source:
618 * ------------------------------
620 * State Call Mtn Ent Lea Crs BUp StA StR Fin TO
621 * 0) idle 1bu - - - - - - - - -
622 * 1) drag over target - 1au - 2cu 1cbu 5fu 3 4 1w -
623 * 2) drag over nothing - 2 1bu - - 0 - - 2w -
624 * 3) drag targ+accept - 3u - 2cu 1cbu 6f 3 4w 0z -
625 * 4) drag targ+reject - 4u - 2cu 1cbu 0 3w 4 0z -
626 * 5) waiting status - 5X 5X 5X 5X - 6f 0 0z 0w
627 * 6) dropped - - - - - - - - 0 0w
630 * Call - called WMDragImageFromView()
632 * Ent - Enter droppable window
633 * Lea - Leave droppable window (or rectangle)
634 * Crs - Leave droppable window (or rectangle) and enter another
635 * BUp - Button Released
636 * StA - XdndStatus client msg with Accept drop
637 * StR - XdndStatus client msg with Reject drop
638 * Fin - XdndFinish client msg
642 * a - send update message
643 * b - send enter message
644 * c - send leave message
645 * d - release drag section info
646 * e - send drop message
648 * u - update dragInfo
651 * w - warn about unexpected reply
652 * z - abort operation.. unexpected reply
656 WMDragImageFromView(WMView
*view
, WMPixmap
*image
, char *dataTypes
[],
657 WMPoint atLocation
, WMSize mouseOffset
, XEvent
*event
,
660 WMScreen
*scr
= view
->screen
;
661 Display
*dpy
= scr
->display
;
662 WMView
*toplevel
= W_TopLevelOfView(view
);
665 WMRect rect
= {{0,0},{0,0}};
669 XColor black
= {0, 0,0,0, DoRed
|DoGreen
|DoBlue
};
670 XColor green
= {0x0045b045, 0x4500,0xb000,0x4500, DoRed
|DoGreen
|DoBlue
};
671 XColor back
= {0, 0xffff,0xffff,0xffff, DoRed
|DoGreen
|DoBlue
};
672 WMDraggingInfo dragInfo
;
673 WMDraggingInfo oldDragInfo
;
674 WMHandlerID timer
= NULL
;
675 static WMSelectionProcs handler
= {
682 if (scr
->dragSourceView
!= NULL
)
685 wassertr(view
->dragSourceProcs
!= NULL
);
688 /* prepare icon to be dragged */
690 image
= scr
->defaultObjectIcon
;
692 icon
= makeDragIcon(scr
, image
);
694 XMoveWindow(dpy
, icon
, atLocation
.x
, atLocation
.y
);
695 XMapRaised(dpy
, icon
);
698 /* init dragging info */
700 scr
->dragSourceView
= view
;
702 memset(&dragInfo
, 0, sizeof(WMDraggingInfo
));
703 memset(&oldDragInfo
, 0, sizeof(WMDraggingInfo
));
704 dragInfo
.image
= image
;
705 dragInfo
.sourceView
= view
;
706 dragInfo
.sourceWindow
= W_VIEW_DRAWABLE(toplevel
);
708 dragInfo
.destinationWindow
= dragInfo
.sourceWindow
;
710 dragInfo
.location
.x
= atLocation
.x
+ mouseOffset
.width
;
711 dragInfo
.location
.y
= atLocation
.y
+ mouseOffset
.height
;
712 dragInfo
.imageLocation
= atLocation
;
715 /* start pointer grab */
716 XGrabPointer(dpy
, scr
->rootWin
, False
,
717 ButtonPressMask
|ButtonReleaseMask
|ButtonMotionMask
,
718 GrabModeSync
, GrabModeAsync
, None
, scr
->defaultCursor
,
723 _XErrorOccured
= False
;
725 /* take ownership of XdndSelection */
726 if (!WMCreateSelectionHandler(view
, scr
->xdndSelectionAtom
,
729 wwarning("could not get ownership or DND selection");
733 setMouseOffsetHint(toplevel
, mouseOffset
);
735 if (view
->dragSourceProcs
->beganDragImage
!= NULL
) {
736 view
->dragSourceProcs
->beganDragImage(view
, image
, atLocation
);
739 processMotion(scr
, &dragInfo
, &oldDragInfo
, &rect
, action
);
743 while (state
!= 6 && state
!= 0 && !_XErrorOccured
) {
744 XAllowEvents(dpy
, SyncPointer
, CurrentTime
);
745 WMNextEvent(dpy
, &ev
);
749 if (state
>= 1 && state
<= 4) {
750 while (XCheckTypedEvent(dpy
, MotionNotify
, &ev
)) ;
754 oldDragInfo
= dragInfo
;
756 updateDraggingInfo(scr
, &dragInfo
, mouseOffset
, &ev
, icon
);
758 XMoveWindow(dpy
, icon
, dragInfo
.imageLocation
.x
,
759 dragInfo
.imageLocation
.y
);
761 processMotion(scr
, &dragInfo
, &oldDragInfo
, &rect
, action
);
765 /* XXXif entered a different destination, check the operation */
769 if (oldDragInfo
.destinationWindow
!= None
770 && oldDragInfo
.destinationWindow
!= scr
->rootWin
771 && (dragInfo
.destinationWindow
== None
772 || dragInfo
.destinationWindow
== scr
->rootWin
)) {
773 /* left the droppable window */
780 if (dragInfo
.destinationWindow
!= None
781 && dragInfo
.destinationWindow
!= scr
->rootWin
) {
790 if (oldDragInfo
.destinationWindow
!= None
791 && oldDragInfo
.destinationWindow
!= scr
->rootWin
792 && (dragInfo
.destinationWindow
== None
793 || dragInfo
.destinationWindow
== scr
->rootWin
)) {
794 /* left the droppable window */
805 /* if (state >= 1 && state <= 4) */ {
809 oldDragInfo
= dragInfo
;
811 updateDraggingInfo(scr
, &dragInfo
, mouseOffset
, &ev
, icon
);
813 XMoveWindow(dpy
, icon
, dragInfo
.imageLocation
.x
,
814 dragInfo
.imageLocation
.y
);
816 if (state
== 4 || state
== 1) {
817 dragInfo
.destinationWindow
= None
;
818 dragInfo
.destView
= NULL
;
820 processMotion(scr
, &dragInfo
, &oldDragInfo
, &rect
, action
);
822 dragInfo
.timestamp
= ev
.xbutton
.time
;
829 timer
= WMAddTimerHandler(3000, timeoutCallback
,
830 (void*)dragInfo
.destinationWindow
);
846 if ((state
== 1 || state
== 3 || state
== 4 || state
== 5)
847 && ev
.xclient
.message_type
== scr
->xdndStatusAtom
848 && ev
.xclient
.data
.l
[0] == dragInfo
.destinationWindow
) {
850 if (ev
.xclient
.data
.l
[1] & 1) {
851 SPIT("got accept msg");
852 /* will accept drop */
861 WMDeleteTimerHandler(timer
);
867 action
= actionToOperation(scr
, ev
.xclient
.data
.l
[4]);
869 SPIT("got reject msg");
879 WMDeleteTimerHandler(timer
);
887 if (ev
.xclient
.data
.l
[1] & (1<<1)) {
888 rect
.pos
.x
= ev
.xclient
.data
.l
[2] >> 16;
889 rect
.pos
.y
= ev
.xclient
.data
.l
[2] & 0xffff;
890 rect
.size
.width
= ev
.xclient
.data
.l
[3] >> 16;
891 rect
.size
.height
= ev
.xclient
.data
.l
[3] & 0xffff;
896 } else if ((state
>= 1 && state
<= 5)
897 && ev
.xclient
.message_type
== scr
->xdndFinishedAtom
898 && ev
.xclient
.window
== dragInfo
.destinationWindow
) {
900 wwarning("drag source received unexpected XdndFinished message from %x",
901 (unsigned)dragInfo
.destinationWindow
);
903 if (state
== 3 || state
== 4 || state
== 5) {
906 WMDeleteTimerHandler(timer
);
917 if (ostate
!= state
) {
919 XRecolorCursor(dpy
, scr
->defaultCursor
, &green
, &back
);
920 } else if (ostate
== 3) {
921 XRecolorCursor(dpy
, scr
->defaultCursor
, &black
, &back
);
928 WMDeleteTimerHandler(timer
);
930 } else if (_XErrorOccured
) {
931 /* got a timeout, send leave */
932 notifyDragLeave(scr
, &dragInfo
);
935 XUngrabPointer(dpy
, CurrentTime
);
937 SPIT("exited main loop");
939 if (_XErrorOccured
|| state
!= 6) {
943 assert(dragInfo
.destinationWindow
!= None
);
946 notifyDrop(scr
, &dragInfo
);
956 XDestroyWindow(dpy
, icon
);
961 scr
->dragSourceView
= NULL
;
963 WMDeleteSelectionHandler(view
, scr
->xdndSelectionAtom
,
964 event
->xmotion
.time
);
967 slideWindow(dpy
, icon
,
968 dragInfo
.imageLocation
.x
, dragInfo
.imageLocation
.y
,
969 atLocation
.x
, atLocation
.y
);
971 XDestroyWindow(dpy
, icon
);
972 if (view
->dragSourceProcs
->endedDragImage
!= NULL
) {
973 view
->dragSourceProcs
->endedDragImage(view
, image
,
974 dragInfo
.imageLocation
,
991 operationToAction(WMScreen
*scr
, WMDragOperationType operation
)
994 case WDOperationNone
:
997 case WDOperationCopy
:
998 return scr
->xdndActionCopy
;
1000 case WDOperationMove
:
1001 return scr
->xdndActionMove
;
1003 case WDOperationLink
:
1004 return scr
->xdndActionLink
;
1006 case WDOperationAsk
:
1007 return scr
->xdndActionAsk
;
1009 case WDOperationPrivate
:
1010 return scr
->xdndActionPrivate
;
1018 static WMDragOperationType
1019 actionToOperation(WMScreen
*scr
, Atom action
)
1021 if (action
== scr
->xdndActionCopy
) {
1022 return WDOperationCopy
;
1024 } else if (action
== scr
->xdndActionMove
) {
1025 return WDOperationMove
;
1027 } else if (action
== scr
->xdndActionLink
) {
1028 return WDOperationLink
;
1030 } else if (action
== scr
->xdndActionAsk
) {
1031 return WDOperationAsk
;
1033 } else if (action
== scr
->xdndActionPrivate
) {
1034 return WDOperationPrivate
;
1036 } else if (action
== None
) {
1038 return WDOperationCopy
;
1040 char *tmp
= XGetAtomName(scr
->display
, action
);
1042 wwarning("unknown XDND action %s from 0x%x", tmp
,
1043 (unsigned)scr
->dragInfo
.sourceWindow
);
1046 return WDOperationCopy
;
1056 getTypeList(Window window
, XClientMessageEvent
*event
)
1061 if (event
->data
.l
[1] & 1) { /* > 3 types */
1064 types
= wmalloc(4 * sizeof(Atom
));
1065 if (event
->data
.l
[2] != None
)
1066 types
[i
++] = event
->data
.l
[2];
1067 if (event
->data
.l
[3] != None
)
1068 types
[i
++] = event
->data
.l
[3];
1069 if (event
->data
.l
[4] != None
)
1070 types
[i
++] = event
->data
.l
[4];
1074 if (types
[0] == 0) {
1075 wwarning("received invalid drag & drop type list");
1084 #define DISPATCH(view, func, info) (view)->dragDestinationProcs->func(view, info)
1089 receivedData(WMView
*view
, Atom selection
, Atom target
,
1090 Time timestamp
, void *cdata
, WMData
*data
)
1092 WMScreen
*scr
= W_VIEW_SCREEN(view
);
1093 WMDraggingInfo
*info
= (WMDraggingInfo
*)cdata
;
1096 res
= view
->dragDestinationProcs
->performDragOperation(view
, info
, data
);
1099 DISPATCH(view
, concludeDragOperation
, info
);
1102 /* send finished message */
1103 sendClientMessage(scr
->display
, info
->sourceWindow
,
1104 scr
->xdndFinishedAtom
,
1105 info
->destinationWindow
,
1108 memset(&scr
->dragInfo
, 0, sizeof(WMDraggingInfo
));
1114 W_HandleDNDClientMessage(WMView
*toplevel
, XClientMessageEvent
*event
)
1116 WMScreen
*scr
= W_VIEW_SCREEN(toplevel
);
1117 WMView
*oldView
= NULL
;
1118 WMView
*newView
= NULL
;
1119 unsigned operation
= 0;
1125 WCross
, /* leave one and enter another */
1130 int what
= WNothing
;
1131 Bool sendStatus
= False
;
1134 source
= scr
->dragInfo
.sourceWindow
;
1135 oldView
= scr
->dragInfo
.destView
;
1137 if (event
->message_type
== scr
->xdndFinishedAtom
) {
1138 WMView
*view
= scr
->dragSourceView
;
1140 WMDeleteSelectionHandler(view
, scr
->xdndSelectionAtom
,
1141 scr
->dragInfo
.timestamp
);
1143 if (view
->dragSourceProcs
->endedDragImage
!= NULL
) {
1144 view
->dragSourceProcs
->endedDragImage(view
,
1145 scr
->dragInfo
.image
,
1146 scr
->dragInfo
.imageLocation
,
1150 scr
->dragSourceView
= NULL
;
1157 if (event
->message_type
== scr
->xdndEnterAtom
) {
1162 if (scr
->dragInfo
.sourceWindow
!= None
) {
1163 puts("received Enter event in bad order");
1166 memset(&scr
->dragInfo
, 0, sizeof(WMDraggingInfo
));
1169 if ((event
->data
.l
[1] >> 24) > XDND_VERSION
) {
1170 wwarning("received drag & drop request with unsupported version %i",
1171 (event
->data
.l
[1] >> 24));
1175 scr
->dragInfo
.protocolVersion
= event
->data
.l
[1] >> 24;
1176 scr
->dragInfo
.sourceWindow
= source
= event
->data
.l
[0];
1177 scr
->dragInfo
.destinationWindow
= event
->window
;
1179 getMouseOffsetHint(scr
, source
, &scr
->dragInfo
.mouseOffset
);
1182 scr
->dragInfo
.image
= NULL
;
1184 XQueryPointer(scr
->display
, scr
->rootWin
, &foo
, &bar
,
1185 &scr
->dragInfo
.location
.x
, &scr
->dragInfo
.location
.y
,
1188 scr
->dragInfo
.imageLocation
= scr
->dragInfo
.location
;
1189 scr
->dragInfo
.imageLocation
.x
-= scr
->dragInfo
.mouseOffset
.width
;
1190 scr
->dragInfo
.imageLocation
.y
-= scr
->dragInfo
.mouseOffset
.height
;
1192 translateCoordinates(scr
, scr
->dragInfo
.destinationWindow
,
1193 scr
->dragInfo
.location
.x
,
1194 scr
->dragInfo
.location
.y
, &x
, &y
);
1197 newView
= findViewInToplevel(scr
->display
,
1198 scr
->dragInfo
.destinationWindow
,
1201 } else if (event
->message_type
== scr
->xdndPositionAtom
1202 && scr
->dragInfo
.sourceWindow
== event
->data
.l
[0]) {
1204 scr
->dragInfo
.location
.x
= event
->data
.l
[2] >> 16;
1205 scr
->dragInfo
.location
.y
= event
->data
.l
[2] & 0xffff;
1207 scr
->dragInfo
.imageLocation
= scr
->dragInfo
.location
;
1208 scr
->dragInfo
.imageLocation
.x
-= scr
->dragInfo
.mouseOffset
.width
;
1209 scr
->dragInfo
.imageLocation
.y
-= scr
->dragInfo
.mouseOffset
.height
;
1211 if (scr
->dragInfo
.protocolVersion
>= 1) {
1212 scr
->dragInfo
.timestamp
= event
->data
.l
[3];
1213 scr
->dragInfo
.sourceOperation
= actionToOperation(scr
,
1217 scr
->dragInfo
.timestamp
= CurrentTime
;
1218 scr
->dragInfo
.sourceOperation
= WDOperationCopy
;
1221 translateCoordinates(scr
, scr
->dragInfo
.destinationWindow
,
1222 scr
->dragInfo
.location
.x
,
1223 scr
->dragInfo
.location
.y
, &x
, &y
);
1225 newView
= findViewInToplevel(scr
->display
,
1226 scr
->dragInfo
.destinationWindow
,
1229 } else if (event
->message_type
== scr
->xdndLeaveAtom
1230 && scr
->dragInfo
.sourceWindow
== event
->data
.l
[0]) {
1232 memset(&scr
->dragInfo
, 0, sizeof(WMDraggingInfo
));
1234 } else if (event
->message_type
== scr
->xdndDropAtom
1235 && scr
->dragInfo
.sourceWindow
== event
->data
.l
[0]) {
1238 if (oldView
!= NULL
)
1247 * Now map the XDND events to WINGs events.
1250 if (what
== WNothing
) {
1251 if (IS_DROPPABLE(newView
)) {
1252 if (!IS_DROPPABLE(oldView
)) { /* entered */
1254 } else if (oldView
== newView
) { /* updated */
1260 if (IS_DROPPABLE(oldView
)) {
1263 /* just send rejection msg */
1274 scr
->dragInfo
.destView
= newView
;
1275 operation
= DISPATCH(newView
, draggingEntered
, &scr
->dragInfo
);
1280 scr
->dragInfo
.destView
= NULL
;
1281 DISPATCH(oldView
, draggingExited
, &scr
->dragInfo
);
1283 operation
= WDOperationNone
;
1287 DISPATCH(oldView
, draggingExited
, &scr
->dragInfo
);
1288 scr
->dragInfo
.destView
= newView
;
1289 operation
= DISPATCH(newView
, draggingEntered
, &scr
->dragInfo
);
1294 operation
= DISPATCH(oldView
, draggingUpdated
, &scr
->dragInfo
);
1302 type
= DISPATCH(oldView
, prepareForDragOperation
, &scr
->dragInfo
);
1305 if (!WMRequestSelection(scr
->dragInfo
.destView
,
1306 scr
->xdndSelectionAtom
,
1307 XInternAtom(scr
->display
, type
, False
),
1308 scr
->dragInfo
.timestamp
,
1309 receivedData
, &scr
->dragInfo
)) {
1310 wwarning("could not request data for dropped data");
1312 /* send finished message */
1313 sendClientMessage(scr
->display
, source
,
1314 scr
->xdndFinishedAtom
,
1315 scr
->dragInfo
.destinationWindow
,
1319 /* send finished message */
1320 sendClientMessage(scr
->display
, source
,
1321 scr
->xdndFinishedAtom
,
1322 scr
->dragInfo
.destinationWindow
,
1337 action
= operationToAction(scr
, operation
);
1339 sendClientMessage(scr
->display
, source
,
1340 scr
->xdndStatusAtom
,
1341 scr
->dragInfo
.destinationWindow
,
1342 action
!= None
? 1 : 0, 0, 0, action
);