rem: GrabModeSync, GrabModeAsync, None, scr->defaultCursor,
add: GrabModeAsync, GrabModeAsync, None, scr->defaultCursor,
context: WMDragImageFromView(WMView *view, WMPixmap *image, char *dataTypes[],		    WMPoint atLocation, WMSize mouseOffset, XEvent *event,		    Bool slideBack){    WMScreen *scr = view->screen;    Display *dpy = scr->display;    WMView *toplevel = W_TopLevelOfView(view);    Window icon;    XEvent ev;    WMRect rect = {{0,0},{0,0}};    int ostate = -1;    int state;    int action = -1;    XColor black = {0, 0,0,0, DoRed|DoGreen|DoBlue};    XColor green = {0x0045b045, 0x4500,0xb000,0x4500, DoRed|DoGreen|DoBlue};    XColor back = {0, 0xffff,0xffff,0xffff, DoRed|DoGreen|DoBlue};    WMDraggingInfo dragInfo;    WMDraggingInfo oldDragInfo;    WMHandlerID timer = NULL;    static WMSelectionProcs handler = {	convertSelection,	    selectionLost,	    selectionDone    };        if (scr->dragSourceView != NULL)	return;        wassertr(view->dragSourceProcs != NULL);        /* prepare icon to be dragged */    if (image == NULL)	image = scr->defaultObjectIcon;    icon = makeDragIcon(scr, image);    XMoveWindow(dpy, icon, atLocation.x, atLocation.y);    XMapRaised(dpy, icon);        /* init dragging info */        scr->dragSourceView = view;    memset(&dragInfo, 0, sizeof(WMDraggingInfo));    memset(&oldDragInfo, 0, sizeof(WMDraggingInfo));    dragInfo.image = image;    dragInfo.sourceView = view;    dragInfo.sourceWindow = W_VIEW_DRAWABLE(toplevel);    dragInfo.destinationWindow = dragInfo.sourceWindow;    dragInfo.location.x = atLocation.x + mouseOffset.width;    dragInfo.location.y = atLocation.y + mouseOffset.height;    dragInfo.imageLocation = atLocation;            /* start pointer grab */    XGrabPointer(dpy, scr->rootWin, False,		 ButtonPressMask|ButtonReleaseMask|ButtonMotionMask,		 GrabModeSync, GrabModeAsync, None, scr->defaultCursor,		 CurrentTime);    XFlush(dpy);    _XErrorOccured = False;        /* take ownership of XdndSelection */    if (!WMCreateSelectionHandler(view, scr->xdndSelectionAtom,				  event->xmotion.time,				  &handler, NULL)) {	wwarning("could not get ownership or DND selection");	return;    }        setMouseOffsetHint(toplevel, mouseOffset);    if (view->dragSourceProcs->beganDragImage != NULL) {	view->dragSourceProcs->beganDragImage(view, image, atLocation);    }    processMotion(scr, &dragInfo, &oldDragInfo, &rect, action);    state = 1;    while (state != 6 && state != 0 && !_XErrorOccured) {	XAllowEvents(dpy, SyncPointer, CurrentTime);	WMNextEvent(dpy, &ev);	switch (ev.type) {	 case MotionNotify:	    if (state >= 1 && state <= 4) {		while (XCheckTypedEvent(dpy, MotionNotify, &ev)) ;		protectBlock(True);		oldDragInfo = dragInfo;		updateDraggingInfo(scr, &dragInfo, mouseOffset, &ev, icon);		XMoveWindow(dpy, icon, dragInfo.imageLocation.x,			    dragInfo.imageLocation.y);		processMotion(scr, &dragInfo, &oldDragInfo, &rect, action);		protectBlock(False);		/* XXXif entered a different destination, check the operation */		switch (state) {		 case 1:		    if (oldDragInfo.destinationWindow != None			 && oldDragInfo.destinationWindow != scr->rootWin			 && (dragInfo.destinationWindow == None			     || dragInfo.destinationWindow == scr->rootWin)) {			/* left the droppable window */			state = 2;			action = -1;		    }		    break;		    		 case 2:		    if (dragInfo.destinationWindow != None			&& dragInfo.destinationWindow != scr->rootWin) {			state = 1;			action = -1;		    }		    break;		 case 3:		 case 4:		    if (oldDragInfo.destinationWindow != None			 && oldDragInfo.destinationWindow != scr->rootWin			 && (dragInfo.destinationWindow == None			     || dragInfo.destinationWindow == scr->rootWin)) {			/* left the droppable window */			state = 2;			action = -1;		    }		    break;		}	    }	    break;	    	 case ButtonRelease:	    /* if (state >= 1 && state <= 4) */ {				protectBlock(True);	    		oldDragInfo = dragInfo;		updateDraggingInfo(scr, &dragInfo, mouseOffset, &ev, icon);		XMoveWindow(dpy, icon, dragInfo.imageLocation.x,			    dragInfo.imageLocation.y);		if (state == 4 || state == 1) {		    dragInfo.destinationWindow = None;		    dragInfo.destView = NULL;		}		processMotion(scr, &dragInfo, &oldDragInfo, &rect, action);				dragInfo.timestamp = ev.xbutton.time;		protectBlock(False);				switch (state) {		 case 1:		    state = 5;		    timer = WMAddTimerHandler(3000, timeoutCallback,					      (void*)dragInfo.destinationWindow);		    break;		 case 2:		    state = 0;		    break;		 case 3:		    state = 6;		    break;		 case 4:		    state = 0;		    break;		}	    }	    break;	 case ClientMessage:	    if ((state == 1 || state == 3 || state == 4 || state == 5)		&& ev.xclient.message_type == scr->xdndStatusAtom		&& ev.xclient.data.l[0] == dragInfo.destinationWindow) {		if (ev.xclient.data.l[1] & 1) {		    SPIT("got accept msg");		    /* will accept drop */		    switch (state) {		     case 1:		     case 3:		     case 4:			state = 3;			break;		     case 5:			if (timer) {			    WMDeleteTimerHandler(timer);			    timer = NULL;			}			state = 6;			break;		    }		    action = actionToOperation(scr, ev.xclient.data.l[4]);		} else {		    SPIT("got reject msg");		    switch (state) {		     case 1:		     case 3:		     case 4:			state = 4;			break;		     case 5:			state = 0;			if (timer) {			    WMDeleteTimerHandler(timer);			    timer = NULL;			}			break;		    }		    action = 0;		}		if (ev.xclient.data.l[1] & (1<<1)) {		    rect.pos.x = ev.xclient.data.l[2] >> 16;		    rect.pos.y = ev.xclient.data.l[2] & 0xffff;		    rect.size.width = ev.xclient.data.l[3] >> 16;		    rect.size.height = ev.xclient.data.l[3] & 0xffff;		} else {		    rect.size.width = 0;		}					    } else if ((state >= 1 && state <= 5)		       && ev.xclient.message_type == scr->xdndFinishedAtom		       && ev.xclient.window == dragInfo.destinationWindow) {		wwarning("drag source received unexpected XdndFinished message from %x",			 (unsigned)dragInfo.destinationWindow);		if (state == 3 || state == 4 || state == 5) {		    state = 0;		    if (timer) {			WMDeleteTimerHandler(timer);			timer = NULL;		    }		}	    }	    	 default:	    WMHandleEvent(&ev);	    break;	}		if (ostate != state) {	    if (state == 3) {		XRecolorCursor(dpy, scr->defaultCursor, &green, &back);	    } else if (ostate == 3) {		XRecolorCursor(dpy, scr->defaultCursor, &black, &back);	    }	    ostate = state;	}    }        if (timer) {	WMDeleteTimerHandler(timer);	timer = NULL;    } else if (_XErrorOccured) {	/* got a timeout, send leave */	notifyDragLeave(scr, &dragInfo);    }    XUngrabPointer(dpy, CurrentTime);        SPIT("exited main loop");    if (_XErrorOccured || state != 6) {	goto cancelled;    }    assert(dragInfo.destinationWindow != None);        protectBlock(True);    notifyDrop(scr, &dragInfo);    protectBlock(False);        if (_XErrorOccured)	goto cancelled;            SPIT("dropped");        XDestroyWindow(dpy, icon);        return;cancelled:    scr->dragSourceView = NULL;        WMDeleteSelectionHandler(view, scr->xdndSelectionAtom, 			     event->xmotion.time);    if (slideBack) {	slideWindow(dpy, icon,		    dragInfo.imageLocation.x, dragInfo.imageLocation.y,		    atLocation.x, atLocation.y);    }    XDestroyWindow(dpy, icon);    if (view->dragSourceProcs->endedDragImage != NULL) {	view->dragSourceProcs->endedDragImage(view, image, 					      dragInfo.imageLocation,					      False);    }}