added sorting to tree bag
[wmaker-crm.git] / WINGs / dragsource.c
blob1fdf7ba82e34090650bfbff55132e3e6285f15f9
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 == None)
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;
379 static void
380 translateCoordinates(WMScreen *scr, Window target, int fromX, int fromY,
381 int *x, int *y)
383 Window child;
385 XTranslateCoordinates(scr->display, scr->rootWin, target,
386 fromX, fromY, x, y, &child);
390 static void
391 updateDraggingInfo(WMScreen *scr, WMDraggingInfo *info,
392 XEvent *event, Window iconWindow)
394 Window toplevel;
395 WMSize size;
397 size = WMGetPixmapSize(info->image);
399 if (event->type == MotionNotify) {
400 info->imageLocation.x = event->xmotion.x_root-(int)size.width/2;
401 info->imageLocation.y = event->xmotion.y_root-(int)size.height/2;
403 info->location.x = event->xmotion.x_root;
404 info->location.y = event->xmotion.y_root;
405 info->timestamp = event->xmotion.time;
407 } else if (event->type == ButtonRelease) {
408 info->imageLocation.x = event->xbutton.x_root-(int)size.width/2;
409 info->imageLocation.y = event->xbutton.y_root-(int)size.height/2;
411 info->location.x = event->xbutton.x_root;
412 info->location.y = event->xbutton.y_root;
413 info->timestamp = event->xbutton.time;
416 toplevel = findToplevelUnderDragPointer(scr,
417 info->location.x,
418 info->location.y,
419 iconWindow);
420 info->destinationWindow = toplevel;
422 if (toplevel == None) {
423 info->destinationWindow = None;
424 } else if (toplevel == scr->rootWin) {
425 info->destinationWindow = scr->rootWin;
426 } else {
427 Window child;
428 int x, y;
430 XTranslateCoordinates(scr->display, scr->rootWin, toplevel,
431 info->location.x, info->location.y,
432 &x, &y, &child);
434 child = findChildInWindow(scr->display, toplevel, x, y);
436 if (child != None) {
437 info->destination = W_GetViewForXWindow(scr->display, child);
438 if (info->destination->droppableTypes == NULL) {
439 info->destination = NULL;
440 } else if (info->destination->dragDestinationProcs == NULL) {
441 info->destination = NULL;
443 } else {
444 info->destination = NULL;
446 info->destinationWindow = toplevel;
454 static void
455 processMotion(WMScreen *scr, WMDraggingInfo *info, WMDraggingInfo *oldInfo,
456 WMRect *rect, unsigned currentAction)
458 unsigned action;
460 if (info->destinationWindow == None) { /* entered an unsupporeted window */
462 if (oldInfo->destinationWindow != None
463 && oldInfo->destinationWindow != scr->rootWin) {
464 SPIT("left window");
466 notifyDragLeave(scr, oldInfo);
469 } else if (info->destinationWindow == scr->rootWin) {
471 if (oldInfo->destinationWindow != None
472 && oldInfo->destinationWindow != scr->rootWin) {
473 SPIT("left window to root");
475 notifyDragLeave(scr, oldInfo);
476 } else {
477 /* nothing */
480 } else if (oldInfo->destinationWindow != info->destinationWindow) {
482 if (oldInfo->destinationWindow != None
483 && oldInfo->destinationWindow != scr->rootWin) {
484 notifyDragLeave(scr, oldInfo);
485 SPIT("crossed");
486 } else {
487 SPIT("entered window");
490 action = notifyDragEnter(scr, info);
492 } else {
494 #define LEFT_RECT(r, X, Y) (X < r->pos.x || Y < r->pos.y \
495 || X >= r->pos.x + r->size.width \
496 || Y >= r->pos.y + r->size.height)
498 if (rect->size.width == 0 ||
499 (LEFT_RECT(rect, info->location.x, info->location.y))) {
501 action = notifyPosition(scr, info);
503 rect->size.width = 0;
507 /* little trick to simulate XdndStatus for local dnd */
509 if (bla && action != currentAction) {
510 XEvent ev;
512 ev.type = ClientMessage;
513 ev.xclient.display = scr->display;
514 ev.xclient.message_type = scr->xdndStatusAtom;
515 ev.xclient.format = 32;
516 ev.xclient.window = info->destinationWindow;
517 ev.xclient.data.l[0] = info->sourceWindow;
518 ev.xclient.data.l[1] = (action ? 1 : 0);
519 ev.xclient.data.l[2] = 0;
520 ev.xclient.data.l[3] = 0;
521 ev.xclient.data.l[4] = action;
523 XPutBackEvent(scr->display, &ev);
530 static void
531 timeoutCallback(void *data)
533 wwarning("drag & drop timed out while waiting for response from 0x%x\n",
534 (unsigned)data);
535 _XErrorOccured = 1;
539 * State Machine For Drag Source:
540 * ------------------------------
541 * Events
542 * State Call Mtn Ent Lea Crs BUp StA StR Fin TO
543 * 0) idle 1bu - - - - - - - - -
544 * 1) drag over target - 1au - 2cu 1cbu 5fu 3 4 1w -
545 * 2) drag over nothing - 2 1bu - - 0 - - 2w -
546 * 3) drag targ+accept - 3u - 2cu 1cbu 6f 3 4w 0z -
547 * 4) drag targ+reject - 4u - 2cu 1cbu 0 3w 4 0z -
548 * 5) waiting status - 5X 5X 5X 5X - 6f 0 0z 0w
549 * 6) dropped - - - - - - - - 0 0w
551 * Events:
552 * Call - called WMDragImageFromView()
553 * Mtn - Motion
554 * Ent - Enter droppable window
555 * Lea - Leave droppable window (or rectangle)
556 * Crs - Leave droppable window (or rectangle) and enter another
557 * BUp - Button Released
558 * StA - XdndStatus client msg with Accept drop
559 * StR - XdndStatus client msg with Reject drop
560 * Fin - XdndFinish client msg
561 * TO - timeout
563 * Actions:
564 * a - send update message
565 * b - send enter message
566 * c - send leave message
567 * d - release drag section info
568 * e - send drop message
569 * f - setup timeout
570 * u - update dragInfo
572 * X - ignore
573 * w - warn about unexpected reply
574 * z - abort operation.. unexpected reply
575 * - shouldnt happen
577 void
578 WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],
579 WMPoint atLocation, WMSize mouseOffset, XEvent *event,
580 Bool slideBack)
582 WMScreen *scr = view->screen;
583 Display *dpy = scr->display;
584 Window icon;
585 XEvent ev;
586 WMSize size;
587 WMRect rect = {{0,0},{0,0}};
588 int ostate = -1;
589 int state;
590 int action = -1;
591 XColor black = {0, 0,0,0, DoRed|DoGreen|DoBlue};
592 XColor green = {0x0045b045, 0x4500,0xb000,0x4500, DoRed|DoGreen|DoBlue};
593 XColor back = {0, 0xffff,0xffff,0xffff, DoRed|DoGreen|DoBlue};
594 WMDraggingInfo dragInfo;
595 WMDraggingInfo oldDragInfo;
596 WMHandlerID timer = NULL;
597 WMData *draggedData = NULL;
600 wassertr(view->dragSourceProcs != NULL);
603 /* prepare icon to be dragged */
604 if (image == NULL)
605 image = scr->defaultObjectIcon;
607 size = WMGetPixmapSize(image);
609 icon = makeDragIcon(scr, image);
611 XMoveWindow(dpy, icon, event->xmotion.x_root-(int)size.width/2,
612 event->xmotion.y_root-(int)size.height/2);
613 XMapRaised(dpy, icon);
616 /* init dragging info */
617 memset(&dragInfo, 0, sizeof(WMDraggingInfo));
618 memset(&oldDragInfo, 0, sizeof(WMDraggingInfo));
619 dragInfo.image = image;
620 dragInfo.sourceWindow = W_VIEW_DRAWABLE(W_TopLevelOfView(view));
622 dragInfo.destinationWindow = dragInfo.sourceWindow;
624 dragInfo.location.x = event->xmotion.x_root;
625 dragInfo.location.y = event->xmotion.y_root;
626 dragInfo.imageLocation = atLocation;
629 /* start pointer grab */
630 XGrabPointer(dpy, scr->rootWin, False,
631 ButtonPressMask|ButtonReleaseMask|ButtonMotionMask,
632 GrabModeSync, GrabModeAsync, None, scr->defaultCursor,
633 CurrentTime);
635 XFlush(dpy);
637 _XErrorOccured = False;
639 /* XXX: take ownership of XdndSelection */
642 if (view->dragSourceProcs->beganDragImage != NULL) {
643 view->dragSourceProcs->beganDragImage(view, image, atLocation);
646 processMotion(scr, &dragInfo, &oldDragInfo, &rect, action);
648 state = 1;
650 while (state != 6 && state != 0 && !_XErrorOccured) {
651 XAllowEvents(dpy, SyncPointer, CurrentTime);
652 WMNextEvent(dpy, &ev);
654 switch (ev.type) {
655 case MotionNotify:
656 if (state >= 1 && state <= 4) {
657 while (XCheckTypedEvent(dpy, MotionNotify, &ev)) ;
659 protectBlock(True);
661 oldDragInfo = dragInfo;
663 updateDraggingInfo(scr, &dragInfo, &ev, icon);
665 XMoveWindow(dpy, icon, dragInfo.imageLocation.x,
666 dragInfo.imageLocation.y);
668 if (state != 2) {
669 processMotion(scr, &dragInfo, &oldDragInfo, &rect, action);
671 protectBlock(False);
673 /* XXXif entered a different destination, check the operation */
675 switch (state) {
676 case 1:
677 if (oldDragInfo.destinationWindow != None
678 && (dragInfo.destinationWindow == None
679 || dragInfo.destinationWindow == scr->rootWin)) {
680 /* left the droppable window */
681 state = 2;
682 action = -1;
684 break;
686 case 2:
687 if (dragInfo.destinationWindow != None) {
688 state = 1;
689 action = -1;
691 break;
693 case 3:
694 case 4:
695 if (oldDragInfo.destinationWindow != None
696 && (dragInfo.destinationWindow == None
697 || dragInfo.destinationWindow == scr->rootWin)) {
698 /* left the droppable window */
699 state = 2;
700 action = -1;
702 break;
705 break;
708 case ButtonRelease:
709 /* if (state >= 1 && state <= 4) */ {
711 protectBlock(True);
713 oldDragInfo = dragInfo;
715 updateDraggingInfo(scr, &dragInfo, &ev, icon);
717 XMoveWindow(dpy, icon, dragInfo.imageLocation.x,
718 dragInfo.imageLocation.y);
720 processMotion(scr, &dragInfo, &oldDragInfo, &rect,
721 action);
723 protectBlock(False);
725 switch (state) {
726 case 1:
727 state = 5;
728 timer = WMAddTimerHandler(3000, timeoutCallback,
729 (void*)dragInfo.destinationWindow);
730 break;
731 case 2:
732 state = 0;
733 break;
734 case 3:
735 state = 6;
736 break;
737 case 4:
738 state = 0;
739 break;
742 break;
745 case SelectionRequest:
747 draggedData = NULL;
749 break;
751 case ClientMessage:
752 if ((state == 1 || state == 3 || state == 4 || state == 5)
753 && ev.xclient.message_type == scr->xdndStatusAtom
754 && ev.xclient.window == dragInfo.destinationWindow) {
756 if (ev.xclient.data.l[1] & 1) {
757 puts("got accept msg");
758 /* will accept drop */
759 switch (state) {
760 case 1:
761 case 3:
762 case 4:
763 state = 3;
764 break;
765 case 5:
766 if (timer) {
767 WMDeleteTimerHandler(timer);
768 timer = NULL;
770 state = 6;
771 break;
773 if (ev.xclient.data.l[4] == None) {
774 action = 0;
775 } else {
776 action = ev.xclient.data.l[4];/*XXX*/
778 } else {
779 puts("got reject msg");
780 switch (state) {
781 case 1:
782 case 3:
783 case 4:
784 state = 4;
785 break;
786 case 5:
787 state = 0;
788 if (timer) {
789 WMDeleteTimerHandler(timer);
790 timer = NULL;
792 break;
794 action = 0;
797 if (ev.xclient.data.l[1] & (1<<1)) {
798 rect.pos.x = ev.xclient.data.l[2] >> 16;
799 rect.pos.y = ev.xclient.data.l[2] & 0xffff;
800 rect.size.width = ev.xclient.data.l[3] >> 16;
801 rect.size.height = ev.xclient.data.l[3] & 0xffff;
802 } else {
803 rect.size.width = 0;
806 } else if ((state >= 1 && state <= 5)
807 && ev.xclient.message_type == scr->xdndFinishedAtom
808 && ev.xclient.window == dragInfo.destinationWindow) {
810 wwarning("drag source received unexpected XdndFinished message from %x",
811 (unsigned)dragInfo.destinationWindow);
813 if (state == 3 || state == 4 || state == 5) {
814 state = 0;
815 if (timer) {
816 WMDeleteTimerHandler(timer);
817 timer = NULL;
822 default:
823 WMHandleEvent(&ev);
824 break;
827 if (ostate != state) {
828 printf("state changed to %i\n", state);
829 if (state == 3) {
830 XRecolorCursor(dpy, scr->defaultCursor, &green, &back);
831 } else if (ostate == 3) {
832 XRecolorCursor(dpy, scr->defaultCursor, &black, &back);
834 ostate = state;
838 if (timer) {
839 WMDeleteTimerHandler(timer);
840 timer = NULL;
843 XUngrabPointer(dpy, CurrentTime);
845 SPIT("exited main loop");
847 if (_XErrorOccured || state != 6) {
848 goto cancelled;
851 assert(dragInfo.destinationWindow != None);
853 protectBlock(True);
854 notifyDrop(scr, &dragInfo);
855 protectBlock(False);
857 if (_XErrorOccured)
858 goto cancelled;
861 SPIT("dropped");
862 /* wait for Finished message and SelectionRequest if not a local drop */
866 XDestroyWindow(dpy, icon);
867 if (view->dragSourceProcs->endedDragImage != NULL) {
868 view->dragSourceProcs->endedDragImage(view, image,
869 dragInfo.imageLocation,
870 True);
872 return;
874 cancelled:
875 if (draggedData) {
876 WMReleaseData(draggedData);
879 if (slideBack) {
880 slideWindow(dpy, icon,
881 dragInfo.imageLocation.x, dragInfo.imageLocation.y,
882 atLocation.x, atLocation.y);
884 XDestroyWindow(dpy, icon);
885 if (view->dragSourceProcs->endedDragImage != NULL) {
886 view->dragSourceProcs->endedDragImage(view, image,
887 dragInfo.imageLocation,
888 False);
909 static Atom*
910 getTypeList(Window window, XClientMessageEvent *event)
912 int i = 0;
913 Atom *types = NULL;
915 if (event->data.l[1] & 1) { /* > 3 types */
917 } else {
918 types = wmalloc(4 * sizeof(Atom));
919 if (event->data.l[2] != None)
920 types[i++] = event->data.l[2];
921 if (event->data.l[3] != None)
922 types[i++] = event->data.l[3];
923 if (event->data.l[4] != None)
924 types[i++] = event->data.l[4];
925 types[i] = 0;
928 if (types[0] == 0) {
929 wwarning("received invalid drag & drop type list");
930 /*XXX return;*/
933 return types;
937 void
938 W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event)
940 #if 0
941 WMScreen *scr = W_VIEW_SCREEN(toplevel);
942 WMView *oldView = NULL, *newView = NULL;
943 unsigned operation = 0;
944 int x, y;
946 if (event->message_type == scr->xdndEnterAtom) {
947 Window foo, bar;
948 int bla;
949 unsigned ble;
950 puts("entered");
952 if (scr->dragInfo.sourceWindow != None) {
953 puts("received Enter event in bad order");
956 memset(&scr->dragInfo, 0, sizeof(WMDraggingInfo));
959 if ((event->data.l[0] >> 24) > XDND_VERSION) {
960 wwarning("received drag & drop request with unsupported version %i",
961 (event->data.l[0] >> 24));
962 return;
965 scr->dragInfo.protocolVersion = event->data.l[1] >> 24;
966 scr->dragInfo.sourceWindow = event->data.l[0];
967 scr->dragInfo.destinationWindow = event->window;
969 /* XXX */
970 scr->dragInfo.image = NULL;
972 XQueryPointer(scr->display, scr->rootWin, &foo, &bar,
973 &scr->dragInfo.location.x, &scr->dragInfo.location.y,
974 &bla, &bla, &ble);
976 translateCoordinates(scr, scr->dragInfo.destinationWindow,
977 scr->dragInfo.location.x,
978 scr->dragInfo.location.y, &x, &y);
981 newView = findViewInToplevel(scr->display,
982 scr->dragInfo.destinationWindow,
983 x, y);
985 if (IS_DROPPABLE(view)) {
987 scr->dragInfo.destinationView = view;
989 operation =
990 view->dragDestinationProcs->draggingEntered(view,
991 &scr->dragInfo);
993 if (operation > 0) {
994 Atom action;
996 switch (operation) {
997 default:
998 action = 0;
999 break;
1002 sendClientMessage(scr->display, scr->dragInfo.sourceWindow,
1003 scr->xdndStatusAtom,
1004 scr->dragInfo.destinationWindow,
1005 1, 0, 0, action);
1008 } else if (event->message_type == scr->xdndPositionAtom
1009 && scr->dragInfo.sourceWindow == event->data.l[0]) {
1011 scr->dragInfo.location.x = event->data.l[2] >> 16;
1012 scr->dragInfo.location.y = event->data.l[2] & 0xffff;
1014 if (scr->dragInfo.protocolVersion >= 1) {
1015 scr->dragInfo.timestamp = event->data.l[3];
1016 scr->dragInfo.sourceOperation = event->data.l[4];
1017 } else {
1018 scr->dragInfo.timestamp = CurrentTime;
1019 scr->dragInfo.sourceOperation = 0; /*XXX*/
1022 translateCoordinates(scr, scr->dragInfo.destinationWindow,
1023 scr->dragInfo.location.x,
1024 scr->dragInfo.location.y, &x, &y);
1026 view = findViewInToplevel(scr->display,
1027 scr->dragInfo.destinationWindow,
1028 x, y);
1030 if (scr->dragInfo.destinationView != view) {
1031 WMView *oldVIew = scr->dragInfo.destinationView;
1033 oldView->dragDestinationProcs->draggingExited(oldView,
1034 &scr->dragInfo);
1036 scr->dragInfo.destinationView = NULL;
1040 if (IS_DROPPABLE(view)) {
1043 operation =
1044 view->dragDestinationProcs->draggingUpdated(view,
1045 &scr->dragInfo);
1048 if (operation == 0) {
1049 sendClientMessage(scr->display, scr->dragInfo.sourceWindow,
1050 scr->xdndStatusAtom,
1051 scr->dragInfo.destinationWindow,
1052 0, 0, 0, None);
1053 } else {
1054 Atom action;
1056 switch (operation) {
1057 default:
1058 action = 0;
1059 break;
1062 sendClientMessage(scr->display, scr->dragInfo.sourceWindow,
1063 scr->xdndStatusAtom,
1064 scr->dragInfo.destinationWindow,
1065 1, 0, 0, action);
1068 } else if (event->message_type == scr->xdndLeaveAtom
1069 && scr->dragInfo.sourceWindow == event->data.l[0]) {
1071 void (*draggingExited)(WMView *self, WMDraggingInfo *info);
1073 puts("leave");
1074 } else if (event->message_type == scr->xdndDropAtom
1075 && scr->dragInfo.sourceWindow == event->data.l[0]) {
1079 puts("drop");
1081 #endif