removed listbag added tree bag
[wmaker-crm.git] / WINGs / dragsource.c
blob6b12bba6ec5d0823b916eac689ae53c76ba2817e
3 #include <X11/Xatom.h>
4 #include <math.h>
6 #include "WINGsP.h"
11 #define SPIT(a) puts(a)
14 #define IS_DROPPABLE(view) (view!=NULL && view->droppableTypes!=NULL && \
15 view->dragDestinationProcs!=NULL)
18 static Bool _XErrorOccured = False;
23 void
24 WMSetViewDragSourceProcs(WMView *view, WMDragSourceProcs *procs)
26 if (view->dragSourceProcs)
27 free(view->dragSourceProcs);
28 view->dragSourceProcs = wmalloc(sizeof(WMDragSourceProcs));
30 *view->dragSourceProcs = *procs;
32 /* XXX fill in non-implemented stuffs */
36 /***********************************************************************/
39 static int
40 handleXError(Display *dpy, XErrorEvent *ev)
42 _XErrorOccured = True;
44 return 1;
48 static void
49 protectBlock(Bool begin)
51 static void *oldHandler = NULL;
53 if (begin) {
54 oldHandler = XSetErrorHandler(handleXError);
55 } else {
56 XSetErrorHandler(oldHandler);
63 static Window
64 makeDragIcon(WMScreen *scr, WMPixmap *pixmap)
66 Window window;
67 WMSize size;
68 unsigned long flags;
69 XSetWindowAttributes attribs;
70 Pixmap pix, mask;
72 if (!pixmap) {
73 pixmap = scr->defaultObjectIcon;
75 size = WMGetPixmapSize(pixmap);
76 pix = pixmap->pixmap;
77 mask = pixmap->mask;
79 flags = CWSaveUnder|CWBackPixmap|CWOverrideRedirect|CWColormap;
80 attribs.save_under = True;
81 attribs.background_pixmap = pix;
82 attribs.override_redirect = True;
83 attribs.colormap = scr->colormap;
84 window = XCreateWindow(scr->display, scr->rootWin, 0, 0, size.width,
85 size.height, 0, scr->depth, InputOutput,
86 scr->visual, flags, &attribs);
88 #ifdef SHAPE
89 if (mask) {
90 XShapeCombineMask(dpy, scr->balloon->window, ShapeBounding, 0, 0, mask,
91 ShapeSet);
93 #endif
95 return window;
99 static void
100 slideWindow(Display *dpy, Window win, int srcX, int srcY, int dstX, int dstY)
102 double x, y, dx, dy;
103 int i;
104 int iterations;
106 iterations = WMIN(25, WMAX(abs(dstX-srcX), abs(dstY-srcY)));
108 x = srcX;
109 y = srcY;
111 dx = (double)(dstX-srcX)/iterations;
112 dy = (double)(dstY-srcY)/iterations;
114 for (i = 0; i <= iterations; i++) {
115 XMoveWindow(dpy, win, x, y);
116 XFlush(dpy);
118 wusleep(800);
120 x += dx;
121 y += dy;
126 static Window
127 findChildInWindow(Display *dpy, Window toplevel, int x, int y)
129 Window foo, bar;
130 Window *children;
131 unsigned nchildren;
132 int i;
134 if (!XQueryTree(dpy, toplevel, &foo, &bar,
135 &children, &nchildren) || children == NULL) {
136 return None;
139 /* first window that contains the point is the one */
140 for (i = nchildren-1; i >= 0; i--) {
141 XWindowAttributes attr;
143 if (XGetWindowAttributes(dpy, children[i], &attr)
144 && attr.map_state == IsViewable
145 && x >= attr.x && y >= attr.y
146 && x < attr.x + attr.width && y < attr.y + attr.height) {
147 Window child;
149 child = findChildInWindow(dpy, children[i],
150 x - attr.x, y - attr.y);
152 XFree(children);
154 if (!child)
155 return toplevel;
156 else
157 return child;
161 XFree(children);
162 return None;
166 static WMView*
167 findViewInToplevel(Display *dpy, Window toplevel, int x, int y)
169 Window child;
171 child = findChildInWindow(dpy, toplevel, x, y);
173 if (child != None)
174 return W_GetViewForXWindow(dpy, child);
175 else
176 return NULL;
181 static Window
182 lookForToplevel(WMScreen *scr, Window window, Bool *isAware)
184 Window toplevel = None;
185 Atom *atoms;
186 int j, count;
188 *isAware = False;
190 atoms = XListProperties(scr->display, window, &count);
191 for (j = 0; j < count; j++) {
192 if (atoms[j] == scr->wmStateAtom) {
193 toplevel = window;
194 } else if (atoms[j] == scr->xdndAwareAtom) {
195 *isAware = True;
198 if (atoms)
199 XFree(atoms);
201 if (toplevel == None) {
202 Window *children;
203 Window foo, bar;
204 unsigned nchildren;
206 if (!XQueryTree(scr->display, window, &foo, &bar,
207 &children, &nchildren) || children == NULL) {
208 return None;
211 for (j = 0; j < nchildren; j++) {
212 toplevel = lookForToplevel(scr, children[j], isAware);
213 if (toplevel != None)
214 break;
217 XFree(children);
222 return toplevel;
227 static Window
228 findToplevelUnderDragPointer(WMScreen *scr, int x, int y, Window iconWindow)
230 Window foo, bar;
231 Window *children;
232 unsigned nchildren;
233 Bool overSomething = False;
234 int i;
236 if (!XQueryTree(scr->display, scr->rootWin, &foo, &bar,
237 &children, &nchildren) || children == NULL) {
238 SPIT("couldnt query tree!");
239 return None;
242 /* try to find the window below the iconWindow by traversing
243 * the whole window list */
245 /* first find the position of the iconWindow */
246 for (i = nchildren-1; i >= 0; i--) {
247 if (children[i] == iconWindow) {
248 i--;
249 break;
252 if (i <= 0) {
253 XFree(children);
254 return scr->rootWin;
257 /* first window that contains the point is the one */
258 for (; i >= 0; i--) {
259 XWindowAttributes attr;
261 if (XGetWindowAttributes(scr->display, children[i], &attr)
262 && attr.map_state == IsViewable
263 && x >= attr.x && y >= attr.y
264 && x < attr.x + attr.width && y < attr.y + attr.height) {
265 Window toplevel;
266 Bool isaware;
268 overSomething = True;
270 toplevel = lookForToplevel(scr, children[i], &isaware);
272 XFree(children);
274 if (isaware)
275 return toplevel;
276 else
277 return None;
281 XFree(children);
282 if (!overSomething)
283 return scr->rootWin;
284 else
285 return None;
293 static void
294 sendClientMessage(Display *dpy, Window win, Atom message,
295 unsigned data1, unsigned data2, unsigned data3,
296 unsigned data4, unsigned data5)
298 XEvent ev;
300 ev.type = ClientMessage;
301 ev.xclient.message_type = message;
302 ev.xclient.format = 32;
303 ev.xclient.window = win;
304 ev.xclient.data.l[0] = data1;
305 ev.xclient.data.l[1] = data2;
306 ev.xclient.data.l[2] = data3;
307 ev.xclient.data.l[3] = data4;
308 ev.xclient.data.l[4] = data5;
310 XSendEvent(dpy, win, False, 0, &ev);
311 XFlush(dpy);
317 static unsigned
318 notifyPosition(WMScreen *scr, WMDraggingInfo *info)
320 unsigned operation;
322 switch (info->sourceOperation) {
323 default:
324 operation = None;
325 break;
328 sendClientMessage(scr->display, info->destinationWindow,
329 scr->xdndPositionAtom,
330 info->sourceWindow,
331 0, /* reserved */
332 info->location.x<<16|info->location.y,
333 info->timestamp,
334 operation/* operation */);
336 return 0;
341 static void
342 notifyDrop(WMScreen *scr, WMDraggingInfo *info)
344 sendClientMessage(scr->display, info->destinationWindow,
345 scr->xdndDropAtom,
346 info->sourceWindow,
347 0, /* reserved */
348 info->timestamp,
349 0, 0);
354 static void
355 notifyDragLeave(WMScreen *scr, WMDraggingInfo *info)
357 sendClientMessage(scr->display, info->destinationWindow,
358 scr->xdndLeaveAtom,
359 info->sourceWindow, 0, 0, 0, 0);
364 static unsigned
365 notifyDragEnter(WMScreen *scr, WMDraggingInfo *info)
367 unsigned d;
369 d = XDND_VERSION << 24;
371 sendClientMessage(scr->display, info->destinationWindow,
372 scr->xdndEnterAtom,
373 info->sourceWindow, d, 0, 0, 0);
375 return 0;
380 static void
381 updateDraggingInfo(WMScreen *scr, WMDraggingInfo *info,
382 XEvent *event, Window iconWindow)
384 Window toplevel;
385 WMSize size;
387 size = WMGetPixmapSize(info->image);
389 if (event->type == MotionNotify) {
390 info->imageLocation.x = event->xmotion.x_root-(int)size.width/2;
391 info->imageLocation.y = event->xmotion.y_root-(int)size.height/2;
393 info->location.x = event->xmotion.x_root;
394 info->location.y = event->xmotion.y_root;
395 info->timestamp = event->xmotion.time;
397 } else if (event->type == ButtonRelease) {
398 info->imageLocation.x = event->xbutton.x_root-(int)size.width/2;
399 info->imageLocation.y = event->xbutton.y_root-(int)size.height/2;
401 info->location.x = event->xbutton.x_root;
402 info->location.y = event->xbutton.y_root;
403 info->timestamp = event->xbutton.time;
406 toplevel = findToplevelUnderDragPointer(scr,
407 info->location.x,
408 info->location.y,
409 iconWindow);
410 info->destinationWindow = toplevel;
412 if (toplevel == None) {
413 info->destinationWindow = None;
414 } else if (toplevel == scr->rootWin) {
415 info->destinationWindow = scr->rootWin;
416 } else {
417 Window child;
418 int x, y;
420 XTranslateCoordinates(scr->display, scr->rootWin, toplevel,
421 info->location.x, info->location.y,
422 &x, &y, &child);
424 child = findChildInWindow(scr->display, toplevel, x, y);
426 if (child != None) {
427 info->destination = W_GetViewForXWindow(scr->display, child);
428 if (info->destination->droppableTypes == NULL) {
429 info->destination = NULL;
430 } else if (info->destination->dragDestinationProcs == NULL) {
431 info->destination = NULL;
433 } else {
434 info->destination = NULL;
436 info->destinationWindow = toplevel;
444 static void
445 processMotion(WMScreen *scr, WMDraggingInfo *info, WMDraggingInfo *oldInfo,
446 WMRect *rect, unsigned currentAction)
448 unsigned action;
450 if (info->destinationWindow == None) { /* entered an unsupporeted window */
452 if (oldInfo->destinationWindow != None
453 && oldInfo->destinationWindow != scr->rootWin) {
454 SPIT("left window");
456 notifyDragLeave(scr, oldInfo);
459 } else if (info->destinationWindow == scr->rootWin) {
461 if (oldInfo->destinationWindow != None
462 && oldInfo->destinationWindow != scr->rootWin) {
463 SPIT("left window to root");
465 notifyDragLeave(scr, oldInfo);
466 } else {
467 /* nothing */
470 } else if (oldInfo->destinationWindow != info->destinationWindow) {
472 if (oldInfo->destinationWindow != None
473 && oldInfo->destinationWindow != scr->rootWin) {
474 notifyDragLeave(scr, oldInfo);
475 SPIT("crossed");
476 } else {
477 SPIT("entered window");
480 action = notifyDragEnter(scr, info);
482 } else {
484 #define LEFT_RECT(r, X, Y) (X < r->pos.x || Y < r->pos.y \
485 || X >= r->pos.x + r->size.width \
486 || Y >= r->pos.y + r->size.height)
488 if (rect->size.width == 0 ||
489 (LEFT_RECT(rect, info->location.x, info->location.y))) {
491 action = notifyPosition(scr, info);
493 rect->size.width = 0;
497 /* little trick to simulate XdndStatus for local dnd */
499 if (bla && action != currentAction) {
500 XEvent ev;
502 ev.type = ClientMessage;
503 ev.xclient.display = scr->display;
504 ev.xclient.message_type = scr->xdndStatusAtom;
505 ev.xclient.format = 32;
506 ev.xclient.window = info->destinationWindow;
507 ev.xclient.data.l[0] = info->sourceWindow;
508 ev.xclient.data.l[1] = (action ? 1 : 0);
509 ev.xclient.data.l[2] = 0;
510 ev.xclient.data.l[3] = 0;
511 ev.xclient.data.l[4] = action;
513 XPutBackEvent(scr->display, &ev);
520 static void
521 timeoutCallback(void *data)
523 wwarning("drag & drop timed out while waiting for response from 0x%x\n",
524 (unsigned)data);
525 _XErrorOccured = 1;
529 * State Machine For Drag Source:
530 * ------------------------------
531 * Events
532 * State Call Mtn Ent Lea Crs BUp StA StR Fin TO
533 * 0) idle 1bu - - - - - - - - -
534 * 1) drag over target - 1au - 2cu 1cbu 5fu 3 4 1w -
535 * 2) drag over nothing - 2 1bu - - 0 - - 2w -
536 * 3) drag targ+accept - 3u - 2cu 1cbu 6f 3 4w 0z -
537 * 4) drag targ+reject - 4u - 2cu 1cbu 0 3w 4 0z -
538 * 5) waiting status - 5X 5X 5X 5X - 6f 0 0z 0w
539 * 6) dropped - - - - - - - - 0 0w
541 * Events:
542 * Call - called WMDragImageFromView()
543 * Mtn - Motion
544 * Ent - Enter droppable window
545 * Lea - Leave droppable window (or rectangle)
546 * Crs - Leave droppable window (or rectangle) and enter another
547 * BUp - Button Released
548 * StA - XdndStatus client msg with Accept drop
549 * StR - XdndStatus client msg with Reject drop
550 * Fin - XdndFinish client msg
551 * TO - timeout
553 * Actions:
554 * a - send update message
555 * b - send enter message
556 * c - send leave message
557 * d - release drag section info
558 * e - send drop message
559 * f - setup timeout
560 * u - update dragInfo
562 * X - ignore
563 * w - warn about unexpected reply
564 * z - abort operation.. unexpected reply
565 * - shouldnt happen
567 void
568 WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
569 WMPoint atLocation, WMSize mouseOffset, XEvent *event,
570 Bool slideBack)
572 WMScreen *scr = view->screen;
573 Display *dpy = scr->display;
574 Window icon;
575 XEvent ev;
576 WMSize size;
577 WMRect rect = {{0,0},{0,0}};
578 int ostate = -1;
579 int state;
580 int action = -1;
581 XColor black = {0, 0,0,0, DoRed|DoGreen|DoBlue};
582 XColor green = {0x0045b045, 0x4500,0xb000,0x4500, DoRed|DoGreen|DoBlue};
583 XColor back = {0, 0xffff,0xffff,0xffff, DoRed|DoGreen|DoBlue};
584 WMDraggingInfo dragInfo;
585 WMDraggingInfo oldDragInfo;
586 WMHandlerID timer = NULL;
587 WMData *draggedData = NULL;
590 wassertr(view->dragSourceProcs != NULL);
593 /* prepare icon to be dragged */
594 if (image == NULL)
595 image = scr->defaultObjectIcon;
597 size = WMGetPixmapSize(image);
599 icon = makeDragIcon(scr, image);
601 XMoveWindow(dpy, icon, event->xmotion.x_root-(int)size.width/2,
602 event->xmotion.y_root-(int)size.height/2);
603 XMapRaised(dpy, icon);
606 /* init dragging info */
607 memset(&dragInfo, 0, sizeof(WMDraggingInfo));
608 memset(&oldDragInfo, 0, sizeof(WMDraggingInfo));
609 dragInfo.image = image;
610 dragInfo.sourceWindow = W_VIEW_DRAWABLE(W_TopLevelOfView(view));
612 dragInfo.destinationWindow = dragInfo.sourceWindow;
614 dragInfo.location.x = event->xmotion.x_root;
615 dragInfo.location.y = event->xmotion.y_root;
616 dragInfo.imageLocation = atLocation;
619 /* start pointer grab */
620 XGrabPointer(dpy, scr->rootWin, False,
621 ButtonPressMask|ButtonReleaseMask|ButtonMotionMask,
622 GrabModeSync, GrabModeAsync, None, scr->defaultCursor,
623 CurrentTime);
625 XFlush(dpy);
627 _XErrorOccured = False;
629 /* XXX: take ownership of XdndSelection */
632 if (view->dragSourceProcs->beganDragImage != NULL) {
633 view->dragSourceProcs->beganDragImage(view, image, atLocation);
636 processMotion(scr, &dragInfo, &oldDragInfo, &rect, action);
638 state = 1;
640 while (state != 6 && state != 0 && !_XErrorOccured) {
641 XAllowEvents(dpy, SyncPointer, CurrentTime);
642 WMNextEvent(dpy, &ev);
644 switch (ev.type) {
645 case MotionNotify:
646 if (state >= 1 && state <= 4) {
647 while (XCheckTypedEvent(dpy, MotionNotify, &ev)) ;
649 protectBlock(True);
651 oldDragInfo = dragInfo;
653 updateDraggingInfo(scr, &dragInfo, &ev, icon);
655 XMoveWindow(dpy, icon, dragInfo.imageLocation.x,
656 dragInfo.imageLocation.y);
658 if (state != 2) {
659 processMotion(scr, &dragInfo, &oldDragInfo, &rect, action);
661 protectBlock(False);
663 /* XXXif entered a different destination, check the operation */
665 switch (state) {
666 case 1:
667 if (oldDragInfo.destinationWindow != None
668 && (dragInfo.destinationWindow == None
669 || dragInfo.destinationWindow == scr->rootWin)) {
670 /* left the droppable window */
671 state = 2;
672 action = -1;
674 break;
676 case 2:
677 if (dragInfo.destinationWindow != None) {
678 state = 1;
679 action = -1;
681 break;
683 case 3:
684 case 4:
685 if (oldDragInfo.destinationWindow != None
686 && (dragInfo.destinationWindow == None
687 || dragInfo.destinationWindow == scr->rootWin)) {
688 /* left the droppable window */
689 state = 2;
690 action = -1;
692 break;
695 break;
698 case ButtonRelease:
699 /* if (state >= 1 && state <= 4) */ {
701 protectBlock(True);
703 oldDragInfo = dragInfo;
705 updateDraggingInfo(scr, &dragInfo, &ev, icon);
707 XMoveWindow(dpy, icon, dragInfo.imageLocation.x,
708 dragInfo.imageLocation.y);
710 processMotion(scr, &dragInfo, &oldDragInfo, &rect,
711 action);
713 protectBlock(False);
715 switch (state) {
716 case 1:
717 state = 5;
718 timer = WMAddTimerHandler(3000, timeoutCallback,
719 (void*)dragInfo.destinationWindow);
720 break;
721 case 2:
722 state = 0;
723 break;
724 case 3:
725 state = 6;
726 break;
727 case 4:
728 state = 0;
729 break;
732 break;
735 case SelectionRequest:
737 draggedData = NULL;
739 break;
741 case ClientMessage:
742 if ((state == 1 || state == 3 || state == 4 || state == 5)
743 && ev.xclient.message_type == scr->xdndStatusAtom
744 && ev.xclient.window == dragInfo.destinationWindow) {
746 if (ev.xclient.data.l[1] & 1) {
747 puts("got accept msg");
748 /* will accept drop */
749 switch (state) {
750 case 1:
751 case 3:
752 case 4:
753 state = 3;
754 break;
755 case 5:
756 if (timer) {
757 WMDeleteTimerHandler(timer);
758 timer = NULL;
760 state = 6;
761 break;
763 if (ev.xclient.data.l[4] == None) {
764 action = 0;
765 } else {
766 action = ev.xclient.data.l[4];/*XXX*/
768 } else {
769 puts("got reject msg");
770 switch (state) {
771 case 1:
772 case 3:
773 case 4:
774 state = 4;
775 break;
776 case 5:
777 state = 0;
778 if (timer) {
779 WMDeleteTimerHandler(timer);
780 timer = NULL;
782 break;
784 action = 0;
787 if (ev.xclient.data.l[1] & (1<<1)) {
788 rect.pos.x = ev.xclient.data.l[2] >> 16;
789 rect.pos.y = ev.xclient.data.l[2] & 0xffff;
790 rect.size.width = ev.xclient.data.l[3] >> 16;
791 rect.size.height = ev.xclient.data.l[3] & 0xffff;
792 } else {
793 rect.size.width = 0;
796 } else if ((state >= 1 && state <= 5)
797 && ev.xclient.message_type == scr->xdndFinishedAtom
798 && ev.xclient.window == dragInfo.destinationWindow) {
800 wwarning("drag source received unexpected XdndFinished message from %x",
801 (unsigned)dragInfo.destinationWindow);
803 if (state == 3 || state == 4 || state == 5) {
804 state = 0;
805 if (timer) {
806 WMDeleteTimerHandler(timer);
807 timer = NULL;
812 default:
813 WMHandleEvent(&ev);
814 break;
817 if (ostate != state) {
818 printf("state changed to %i\n", state);
819 if (state == 3) {
820 XRecolorCursor(dpy, scr->defaultCursor, &green, &back);
821 } else if (ostate == 3) {
822 XRecolorCursor(dpy, scr->defaultCursor, &black, &back);
824 ostate = state;
828 if (timer) {
829 WMDeleteTimerHandler(timer);
830 timer = NULL;
833 XUngrabPointer(dpy, CurrentTime);
835 SPIT("exited main loop");
837 if (_XErrorOccured || state != 6) {
838 goto cancelled;
841 assert(dragInfo.destinationWindow != None);
843 protectBlock(True);
844 notifyDrop(scr, &dragInfo);
845 protectBlock(False);
847 if (_XErrorOccured)
848 goto cancelled;
851 SPIT("dropped");
852 /* wait for Finished message and SelectionRequest if not a local drop */
856 XDestroyWindow(dpy, icon);
857 if (view->dragSourceProcs->endedDragImage != NULL) {
858 view->dragSourceProcs->endedDragImage(view, image,
859 dragInfo.imageLocation,
860 True);
862 return;
864 cancelled:
865 if (draggedData) {
866 WMReleaseData(draggedData);
869 if (slideBack) {
870 slideWindow(dpy, icon,
871 dragInfo.imageLocation.x, dragInfo.imageLocation.y,
872 atLocation.x, atLocation.y);
874 XDestroyWindow(dpy, icon);
875 if (view->dragSourceProcs->endedDragImage != NULL) {
876 view->dragSourceProcs->endedDragImage(view, image,
877 dragInfo.imageLocation,
878 False);
899 static Atom*
900 getTypeList(Window window, XClientMessageEvent *event)
902 int i = 0;
903 Atom *types = NULL;
905 if (event->data.l[1] & 1) { /* > 3 types */
907 } else {
908 types = wmalloc(4 * sizeof(Atom));
909 if (event->data.l[2] != None)
910 types[i++] = event->data.l[2];
911 if (event->data.l[3] != None)
912 types[i++] = event->data.l[3];
913 if (event->data.l[4] != None)
914 types[i++] = event->data.l[4];
915 types[i] = NULL;
918 if (types[0] == NULL) {
919 wwarning("received invalid drag & drop type list");
920 //XXX return;
923 return types;
928 void
929 W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event)
931 WMScreen *scr = W_VIEW_SCREEN(toplevel);
932 WMView *view;
933 int operation;
935 if (event->message_type == scr->xdndEnterAtom) {
936 Atom *types;
937 Window foo, bar;
938 int bla;
939 unsigned ble;
940 puts("entered");
942 if (scr->dragInfo.sourceWindow != None) {
943 puts("received Enter event in bad order");
946 memset(&scr->dragInfo, 0, sizeof(WMDraggingInfo));
949 if ((event->data.l[0] >> 24) > XDND_VERSION) {
950 wwarning("received drag & drop request with unsupported version %i",
951 (event->data.l[0] >> 24));
952 return;
955 info.protocolVersion = event->data.l[0] >> 24;
957 info.sourceWindow = event->data.l[0];
958 info.destinationWindow = event->window;
960 /* XXX */
961 info.image = NULL;
963 XQueryPointer(scr->display, scr->rootWin, &foo, &bar,
964 &event->location.x, &event->location.y,
965 &bla, &bla, &ble);
967 view = findViewInToplevel(scr->display,
968 scr->dragInfo.destinationWindow,
969 scr->dragInfo.location.x,
970 scr->dragInfo.location.y);
972 if (IS_DROPPABLE(view)) {
973 operation =
974 view->dragDestinationProcs->draggingEntered(view,
975 &scr->dragInfo);
976 } else {
977 operation = 0;
981 } else if (event->message_type == scr->xdndPositionAtom
982 && scr->dragInfo.sourceWindow == event->data.l[0]) {
983 unsigned operation = 0;
985 scr->dragInfo.location.x = event->data.l[2] >> 16;
986 scr->dragInfo.location.y = event->data.l[2] 0xffff;
988 if (scr->dragInfo.protocolVersion >= 1) {
989 scr->dragInfo.timestamp = event->data.l[3];
990 scr->dragInfo.sourceOperation = event->data.l[4];
991 } else {
992 scr->dragInfo.timestamp = CurrentTime;
993 scr->dragInfo.sourceOperation = 0; /*XXX*/
996 child = findChildInWindow(scr->display, scr->dragInfo.destinationWindow,
997 scr->dragInfo.location.x,
998 scr->dragInfo.location.y);
999 if (child != None) {
1000 view = W_GetViewForXWindow(scr->display, child);
1001 } else {
1002 view = NULL;
1005 if (IS_DROPPABLE(view)) {
1006 operation =
1007 view->dragDestinationProcs->draggingUpdated(view,
1008 &scr->dragInfo);
1011 if (operation == 0) {
1012 sendClientMessage(scr->display, scr->xdndStatusAtom,
1013 scr->dragInfo.sourceWindow,
1014 scr->dragInfo.destinationWindow,
1015 0, 0, 0, None);
1016 } else {
1017 Atom action;
1019 switch (operation) {
1020 default:
1021 action =;
1022 break;
1025 sendClientMessage(scr->display, scr->xdndStatusAtom,
1026 scr->dragInfo.sourceWindow,
1027 scr->dragInfo.destinationWindow,
1028 1, 0, 0, action);
1031 puts("position");
1032 } else if (event->message_type == scr->xdndLeaveAtom
1033 && scr->dragInfo.sourceWindow == event->data.l[0]) {
1035 puts("leave");
1036 } else if (event->message_type == scr->xdndDropAtom
1037 && scr->dragInfo.sourceWindow == event->data.l[0]) {
1039 puts("drop");