1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-19 04:20:27 +01:00
Files
wmaker/WINGs/dragcommon.c
dan 085e9d6254 - updated the XDND code in WINGs to work with GDK based applications.
WINGs based applications should now work with both KDE and GNOME
  applications (Sylvain Reynal <sreynal@nerim.net>)
- better check for the XDND protocol version when interoperating with other
  applications. As it seems xdnd version 3 (which WINGs supports) and newer
  are not backward compatible with xdnd version 1 and 2. This is why WINGs
  applications cannot interoperate with GNUstep applications (which uses
  xdnd version 2). Xdnd version 4 and 5 are backwards compatible with
  version 3 though. (Sylvain Reynal <sreynal@nerim.net>)
2006-01-22 20:33:19 +00:00

291 lines
6.9 KiB
C

#include "WINGsP.h"
#define XDND_SOURCE_VERSION(dragInfo) dragInfo->protocolVersion
#define XDND_DEST_INFO(dragInfo) dragInfo->destInfo
#define XDND_DEST_VIEW(dragInfo) dragInfo->destInfo->destView
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;
#ifdef XDND_DEBUG
char* msgName = XGetAtomName(dpy, message);
printf("sending message %s ... ", msgName);
XFree(msgName);
#endif
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);
#ifdef XDND_DEBUG
printf("sent\n");
#endif
return True; /* message sent */
}
static void
handleLeaveMessage(WMDraggingInfo *info)
{
if (XDND_DEST_INFO(info) != NULL) {
/* XDND_DEST_VIEW is never NULL (it's the xdnd aware view) */
wassertr(XDND_DEST_VIEW(info) != NULL);
if (XDND_DEST_VIEW(info)->dragDestinationProcs != 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) {
Bool positionSent = (XDND_DEST_INFO(info) != NULL);
W_DragDestinationStopTimer();
W_DragDestinationStoreEnterMsgInfo(info, toplevel, event);
/* Xdnd version 3 and up are not compatible with version 1 or 2 */
if (XDND_SOURCE_VERSION(info) > 2) {
if (positionSent) {
/* 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",
XDND_SOURCE_VERSION(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);
}