/* #include */ #include "WINGsP.h" #define VERSION_INFO(dragInfo) dragInfo->protocolVersion #define XDND_DEST_INFO(dragInfo) dragInfo->destInfo #define XDND_DEST_VIEW(dragInfo) dragInfo->destInfo->destView #define XDND_DEST_VIEW_STORED(dragInfo) ((dragInfo->destInfo) != NULL)\ && ((dragInfo->destInfo->destView) != NULL) static Bool _WindowExists; Atom W_OperationToAction(WMScreen *scr, WMDragOperationType operation) { switch (operation) { case WDOperationNone: return None; case WDOperationCopy: return scr->xdndActionCopy; case WDOperationMove: return scr->xdndActionMove; case WDOperationLink: return scr->xdndActionLink; case WDOperationAsk: return scr->xdndActionAsk; case WDOperationPrivate: return scr->xdndActionPrivate; default: return None; } } WMDragOperationType W_ActionToOperation(WMScreen *scr, Atom action) { if (action == scr->xdndActionCopy) { return WDOperationCopy; } else if (action == scr->xdndActionMove) { return WDOperationMove; } else if (action == scr->xdndActionLink) { return WDOperationLink; } else if (action == scr->xdndActionAsk) { return WDOperationAsk; } else if (action == scr->xdndActionPrivate) { return WDOperationPrivate; } else if (action == None) { return WDOperationNone; } else { char *tmp = XGetAtomName(scr->display, action); wwarning("unknown XDND action %s ", tmp); XFree(tmp); return WDOperationCopy; } } static void freeDragOperationItem(void* item) { wfree(item); } WMArray* WMCreateDragOperationArray(int initialSize) { return WMCreateArrayWithDestructor(initialSize, freeDragOperationItem); } WMDragOperationItem* WMCreateDragOperationItem(WMDragOperationType type, char* text) { W_DragOperationItem *result = wmalloc(sizeof(W_DragOperationItem)); result->type = type; result->text = text; return (WMDragOperationItem*) result; } WMDragOperationType WMGetDragOperationItemType(WMDragOperationItem* item) { return ((W_DragOperationItem*)item)->type; } char* WMGetDragOperationItemText(WMDragOperationItem* item) { return ((W_DragOperationItem*)item)->text; } static int handleNoWindowXError(Display *dpy, XErrorEvent *errEvt) { if (errEvt->error_code == BadWindow || errEvt->error_code == BadDrawable) { _WindowExists = False; return Success; } return errEvt->error_code; } static Bool windowExists(Display *dpy, Window win) { void* previousErrorHandler; XWindowAttributes attr; XSynchronize(dpy, True); previousErrorHandler = XSetErrorHandler(handleNoWindowXError); _WindowExists = True; /* can generate BadDrawable or BadWindow */ XGetWindowAttributes(dpy, win, &attr); XSetErrorHandler(previousErrorHandler); XSynchronize(dpy, False); return _WindowExists; } Bool W_SendDnDClientMessage(Display *dpy, Window win, Atom message, unsigned long data0, unsigned long data1, unsigned long data2, unsigned long data3, unsigned long data4) { XEvent ev; if (! windowExists(dpy, win)) { wwarning("xdnd message target %d does no longer exist.", win); return False; /* message not sent */ } ev.type = ClientMessage; ev.xclient.message_type = message; ev.xclient.format = 32; ev.xclient.window = win; ev.xclient.data.l[0] = data0; ev.xclient.data.l[1] = data1; ev.xclient.data.l[2] = data2; ev.xclient.data.l[3] = data3; ev.xclient.data.l[4] = data4; XSendEvent(dpy, win, False, 0, &ev); XFlush(dpy); return True; /* message sent */ } static void handleLeaveMessage(WMDraggingInfo *info) { if (XDND_DEST_INFO(info) != NULL) { if (XDND_DEST_VIEW(info) != NULL) { XDND_DEST_VIEW(info)->dragDestinationProcs->concludeDragOperation( XDND_DEST_VIEW(info)); } W_DragDestinationInfoClear(info); } } void W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event) { WMScreen *scr = W_VIEW_SCREEN(toplevel); WMDraggingInfo *info = &scr->dragInfo; Atom messageType = event->message_type; #ifdef XDND_DEBUG { char* msgTypeName = XGetAtomName(scr->display, messageType); if (msgTypeName != NULL) printf("event type = %s\n", msgTypeName); else printf("pb with event type !\n"); } #endif /* Messages from destination to source */ if (messageType == scr->xdndStatusAtom || messageType == scr->xdndFinishedAtom) { W_DragSourceStopTimer(); W_DragSourceStateHandler(info, event); return; } /* Messages from source to destination */ if (messageType == scr->xdndEnterAtom) { W_DragDestinationStopTimer(); W_DragDestinationStoreEnterMsgInfo(info, toplevel, event); if (VERSION_INFO(info) <= XDND_VERSION) { if (XDND_DEST_VIEW_STORED(info)) { /* xdndPosition previously received on xdnd aware view */ W_DragDestinationStateHandler(info, event); return; } else { W_DragDestinationStartTimer(info); return; } } else { wwarning("received dnd enter msg with unsupported version %i", VERSION_INFO(info)); W_DragDestinationCancelDropOnEnter(toplevel, info); return; } } if (messageType == scr->xdndPositionAtom) { W_DragDestinationStopTimer(); W_DragDestinationStorePositionMsgInfo(info, toplevel, event); W_DragDestinationStateHandler(info, event); return; } if (messageType == scr->xdndSelectionAtom || messageType == scr->xdndDropAtom) { W_DragDestinationStopTimer(); W_DragDestinationStateHandler(info, event); return; } if (messageType == scr->xdndLeaveAtom) { /* conclude drop operation, and clear dragging info */ W_DragDestinationStopTimer(); handleLeaveMessage(info); } } /* called in destroyView (wview.c) */ void W_FreeViewXdndPart(WMView *view) { WMUnregisterViewDraggedTypes(view); if (view->dragSourceProcs) wfree(view->dragSourceProcs); if (view->dragDestinationProcs) wfree(view->dragDestinationProcs); if (view->dragImage) WMReleasePixmap(view->dragImage); }