X11 drag-and-drop support (files only)

svn: r4957
This commit is contained in:
Matthew Flatt 2006-11-27 06:50:19 +00:00
parent 7225c5f60e
commit 7b185d5ae4
6 changed files with 706 additions and 9 deletions

View File

@ -455,14 +455,14 @@ static void abandoned_clip(void *_cb)
cb->in_progress = -1;
}
char *wxClipboard::GetClipboardData(char *format, long *length, long time)
char *wxClipboard::GetClipboardData(char *format, long *length, long time, int alt_sel)
{
if (clipOwner) {
if (clipOwner && !alt_sel) {
if (clipOwner->formats->Member(format))
return wxsGetDataInEventspace(clipOwner, format, length);
else
return NULL;
} else if (cbString) {
} else if (cbString && !alt_sel) {
if (!strcmp(format, "TEXT"))
return copystring(cbString);
else
@ -482,7 +482,7 @@ char *wxClipboard::GetClipboardData(char *format, long *length, long time)
receivedString = NULL;
receivedTargets = NULL;
XtGetSelectionValue(getClipWindow, is_sel ? XA_PRIMARY : xa_clipboard,
XtGetSelectionValue(getClipWindow, alt_sel ? alt_sel : (is_sel ? XA_PRIMARY : xa_clipboard),
xa_targets, wxGetTargets, (XtPointer)saferef, time);
start_time = scheme_get_inexact_milliseconds();
@ -517,7 +517,7 @@ char *wxClipboard::GetClipboardData(char *format, long *length, long time)
return NULL;
}
XtGetSelectionValue(getClipWindow, is_sel ? XA_PRIMARY : xa_clipboard,
XtGetSelectionValue(getClipWindow, alt_sel ? alt_sel : (is_sel ? XA_PRIMARY : xa_clipboard),
xa, wxGetSelection, (XtPointer)saferef, 0);
start_time = scheme_get_inexact_milliseconds();

View File

@ -63,7 +63,7 @@ class wxClipboard : public wxObject
wxBitmap *GetClipboardBitmap(long time);
/* Get data from the clipboard */
char *GetClipboardData(char *format, long *length, long time);
char *GetClipboardData(char *format, long *length, long time, int alt_sel = 0);
/* Get the clipboard client directly. Will be NULL if clipboard data
is a string, or if some other application owns the clipboard.

View File

@ -38,6 +38,7 @@
#define Uses_wxItem
#define Uses_wxCanvas
#define Uses_wxApp
#define Uses_wxClipboard
#include "wx.h"
#define Uses_ScrollWinWidget
#define Uses_Scrollbar
@ -49,6 +50,8 @@
#define Uses_ScrollbarWidget
#include "widgets.h"
#include "xdnd.h"
#include <X11/Xatom.h>
#include <X11/keysym.h> // needed for IsFunctionKey, etc.
#ifdef WX_USE_XFT
@ -60,11 +63,17 @@ static Atom utf8_atom = 0, net_wm_name_atom, net_wm_icon_name_atom;
extern void wxSetSensitive(Widget, Bool enabled);
extern int wxLocaleStringToChar(char *str, int slen);
extern int wxUTF8StringToChar(char *str, int slen);
extern wxWindow *wxLocationToWindow(int x, int y);
static wxWindow *grabbing_panel;
static Time grabbing_panel_time;
static Bool grabbing_panel_regsitered;
#include "xdnd.c"
static int dnd_inited = 0;
static DndClass dnd;
#ifndef NO_XMB_LOOKUP_STRING
static XIM the_im;
#endif
@ -146,7 +155,9 @@ wxWindow::~wxWindow(void)
// destroy widgets
wxSetSensitive(X->frame, TRUE);
*saferef = NULL; /* MATTHEW */
*saferef = NULL;
dndTarget = NULL; /* just in case */
if (X->frame) XtDestroyWidget(X->frame); X->frame = X->handle = X->scroll = NULL;
DELETE_OBJ constraints; constraints = NULL;
@ -1397,6 +1408,91 @@ void wxWindow::FrameEventHandler(Widget w,
if (win->OnClose())
win->Show(FALSE);
}
if (dnd_inited) {
if (xev->xclient.message_type == dnd.XdndEnter) {
/* Ok... */
} else if (xev->xclient.message_type == dnd.XdndPosition) {
wxWindow *target = NULL;
/* Find immediate target window: */
{
Display *dpy = XtDisplay(w);
Screen *scn = XtScreen(w);
Window root = RootWindowOfScreen(scn);
Window xwin = XtWindow(w);
Window child = 0;
int cx, cy;
cx = XDND_POSITION_ROOT_X(xev);
cy = XDND_POSITION_ROOT_Y(xev);
while (1) {
if (XTranslateCoordinates(dpy, root, xwin, cx, cy,
&cx, &cy, &child)) {
if (!child)
break;
else {
root = xwin;
xwin = child;
}
} else
break;
}
if (xwin) {
Widget cw;
cw = XtWindowToWidget(dpy, xwin);
if (cw) {
target = win->FindChildByWidget(cw);
}
}
}
/* Does this window (if found) accept drops? Or maybe a parent? */
while (target && !target->drag_accept) {
if (wxSubType(target->__type, wxTYPE_FRAME)
|| wxSubType(target->__type, wxTYPE_DIALOG_BOX)) {
target = NULL;
break;
} else {
target = target->GetParent();
}
}
xdnd_send_status(&dnd, XDND_ENTER_SOURCE_WIN(xev), xev->xclient.window,
!!target,
0, 0, 0, 10, 10, dnd.XdndActionPrivate);
win->dndTarget = target;
} else if (xev->xclient.message_type == dnd.XdndDrop) {
if (win->dndTarget) {
wxWindow *target = win->dndTarget;
win->dndTarget = NULL;
if (!xdnd_convert_selection(&dnd, XDND_DROP_SOURCE_WIN(xev), xev->xclient.window, dnd.text_uri_list)) {
long len;
char *data;
data = wxTheClipboard->GetClipboardData("text/uri-list", &len, XDND_DROP_TIME(xev), dnd.XdndSelection);
if (data) {
/* If file://... prefix (then drop it) */
if (!strncmp(data, "file://", 7)) {
int i = 7;
char *data2;
while ((i < len) && (data[i] != '/')) {
i++;
}
if (i < len) {
data2 = new WXGC_ATOMIC char[len - i + 1];
memcpy(data2, data + i, len - i);
data2[len - i] = 0;
target->OnDropFile(data2);
}
}
}
}
}
xdnd_send_finished(&dnd, XDND_DROP_SOURCE_WIN(xev), XtWindow(w), 0);
} else if (xev->xclient.message_type == dnd.XdndLeave) {
win->dndTarget = NULL;
xdnd_send_finished(&dnd, XDND_LEAVE_SOURCE_WIN(xev), XtWindow(w), 0);
}
}
break;
case CreateNotify:
break;
@ -2256,3 +2352,64 @@ long wxWindow::GetWindowHandle()
{
return (long)X->handle;
}
//-----------------------------------------------------------------------------
// drag & drop
//-----------------------------------------------------------------------------
void wxWindow::DragAcceptFiles(Bool accept)
{
wxWindow *p;
if (!drag_accept == !accept)
return;
drag_accept = accept;
if (!dnd_inited) {
xdnd_init(&dnd, wxAPP_DISPLAY);
dnd_inited = 1;
}
/* Declare drag-and-drop possible at this
window's top-level frame: */
p = this;
while (p) {
if (wxSubType(p->__type, wxTYPE_FRAME)
|| wxSubType(p->__type, wxTYPE_DIALOG_BOX))
break;
p = p->GetParent();
}
{
Atom l[2];
l[0] = dnd.text_uri_list;
l[1] = 0;
xdnd_set_dnd_aware(&dnd, XtWindow(p->X->frame), l);
}
}
wxWindow *wxWindow::FindChildByWidget(Widget w)
{
wxChildNode *node, *next;
wxWindow *r;
if ((w == X->frame)
|| (w == X->handle))
return this;
for (node = children->First(); node; node = next) {
wxWindow *child;
next = node->Next();
child = (wxWindow*)(node->Data());
if (child) {
r = child->FindChildByWidget(w);
if (r)
return r;
}
}
return NULL;
}

View File

@ -133,7 +133,7 @@ public:
// miscellaneous
virtual void AllowDoubleClick(Bool allow) { allow_dclicks = allow; }
virtual void CaptureMouse(void);
virtual void DragAcceptFiles(Bool accept) { drag_accept = accept; }
virtual void DragAcceptFiles(Bool accept);
virtual void Enable(Bool enable);
virtual void EnablePainting(Bool enable) { painting_enabled = enable; }
virtual void Fit(void) {}
@ -196,6 +196,7 @@ protected:
static Status LookupKey(int unshifted, int unalted,
Widget w, wxWindow *win, XEvent *xev, KeySym *_keysym, char *s, int *_len);
void RegisterAll(Widget ww);
wxWindow *FindChildByWidget(Widget w);
# endif
protected:
friend void wxXSetBusyCursor(wxWindow *, wxCursor *);
@ -224,6 +225,8 @@ protected:
wxWindow **saferef; /* indirection for safety in callbacks */
wxWindow *dndTarget; /* set between XdndPosition and XdndDrop/XdndLeave */
long misc_flags;
unsigned long current_state;

402
src/wxxt/src/Windows/xdnd.c Normal file
View File

@ -0,0 +1,402 @@
/*
xdnd.c, xdnd.h - C program library for handling the Xdnd protocol
Copyright (C) 1998 Paul Sheer
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
http://www.cco.caltech.edu/~jafl/xdnd/
Further info can also be obtained by emailing the author at,
psheer@obsidian.co.za
Released 1998-08-07
*/
#include <X11/Xlib.h>
#include <X11/X.h>
#include <X11/Xatom.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "xdnd.h"
// #define DND_DEBUG
#define dnd_version_at_least(a,b) ((a) <= (b))
#ifdef DND_DEBUG
#define dnd_debug(a,b...) printf("%s: %d: " a "\n", __FILE__, __LINE__ , ## b)
#else
#ifdef NeXT_RUNTIME
#define dnd_debug //
#else /* !NeXT_RUNTIME */
#define dnd_debug(a,b...)
#endif /* NeXT_RUNTIME */
#endif
void
xdnd_reset(DndClass * dnd)
{
dnd->stage = XDND_DROP_STAGE_IDLE;
dnd->dragging_version = 0;
dnd->internal_drag = 0;
dnd->want_position = 0;
dnd->ready_to_drop = 0;
dnd->will_accept = 0;
dnd->rectangle.x = dnd->rectangle.y = 0;
dnd->rectangle.width = dnd->rectangle.height = 0;
dnd->dropper_window = 0;
dnd->dragger_window = 0;
dnd->dragger_typelist = 0;
dnd->desired_type = 0;
dnd->time = 0;
}
void
xdnd_init(DndClass * dnd, Display * display)
{
memset (dnd, 0, sizeof (*dnd));
dnd->display = display;
dnd->root_window = DefaultRootWindow (display);
dnd->version = XDND_VERSION;
dnd->XdndAware = XInternAtom (dnd->display, "XdndAware", False);
dnd->XdndSelection = XInternAtom (dnd->display, "XdndSelection", False);
dnd->XdndEnter = XInternAtom (dnd->display, "XdndEnter", False);
dnd->XdndLeave = XInternAtom (dnd->display, "XdndLeave", False);
dnd->XdndPosition = XInternAtom (dnd->display, "XdndPosition", False);
dnd->XdndDrop = XInternAtom (dnd->display, "XdndDrop", False);
dnd->XdndFinished = XInternAtom (dnd->display, "XdndFinished", False);
dnd->XdndStatus = XInternAtom (dnd->display, "XdndStatus", False);
dnd->XdndActionCopy = XInternAtom (dnd->display, "XdndActionCopy", False);
dnd->XdndActionMove = XInternAtom (dnd->display, "XdndActionMove", False);
dnd->XdndActionLink = XInternAtom (dnd->display, "XdndActionLink", False);
dnd->XdndActionAsk = XInternAtom (dnd->display, "XdndActionAsk", False);
dnd->XdndActionPrivate=XInternAtom(dnd->display,"XdndActionPrivate",False);
dnd->XdndTypeList = XInternAtom (dnd->display, "XdndTypeList", False);
dnd->XdndActionList = XInternAtom (dnd->display, "XdndActionList", False);
dnd->XdndActionDescription = XInternAtom(dnd->display,
"XdndActionDescription", False);
dnd->text_uri_list = XInternAtom(dnd->display, "text/uri-list", False);
xdnd_reset(dnd);
}
static int
array_length(Atom * a)
{ // typelist is a null terminated array
int n = 0;
while (a[n])
n++;
return n;
}
void
xdnd_set_dnd_aware (DndClass * dnd, Window window, Atom * typelist)
{
XChangeProperty (dnd->display, window, dnd->XdndAware, XA_ATOM, 32,
PropModeReplace, (unsigned char *) &dnd->version, 1);
if (typelist)
{
int n = array_length (typelist);
if (n)
XChangeProperty (dnd->display, window, dnd->XdndAware, XA_ATOM, 32,
PropModeAppend, (unsigned char *) typelist, n);
}
}
void
xdnd_set_dnd_unaware (DndClass * dnd, Window window)
{
XDeleteProperty (dnd->display, window, dnd->XdndAware);
}
int
xdnd_is_dnd_aware(DndClass *dnd, Window window, int *version, Atom *typelist)
{
Atom actual;
int format;
unsigned long count, remaining;
unsigned char *data = 0;
Atom *types, *t;
int result = 1;
*version = 0;
XGetWindowProperty (dnd->display, window, dnd->XdndAware,
0, 0x8000000L, False, XA_ATOM, &actual, &format,
&count, &remaining, &data);
if (actual != XA_ATOM || format != 32 || count == 0 || !data)
{
dnd_debug("XGetWindowProperty failed in xdnd_is_dnd_aware - XdndAware = %ld", dnd->XdndAware);
if (data)
XFree(data);
return 0;
}
types = (Atom *) data;
*version = dnd->version < types[0] ? dnd->version : types[0]; // minimum
dnd_debug ("Using XDND version %d", *version);
if (count > 1)
{
result = 0;
for (t = typelist; *t; t++)
{
unsigned long j;
for (j = 1; j < count; j++)
{
if (types[j] == *t)
{
result = 1;
break;
}
}
if (result)
break;
}
}
XFree(data);
return result;
}
void
xdnd_send_enter(DndClass *dnd, Window window, Window from, Atom *typelist)
{
XEvent xevent;
int n, i;
n = array_length (typelist);
memset(&xevent, 0, sizeof (xevent));
xevent.xany.type = ClientMessage;
xevent.xany.display = dnd->display;
xevent.xclient.window = window;
xevent.xclient.message_type = dnd->XdndEnter;
xevent.xclient.format = 32;
XDND_ENTER_SOURCE_WIN (&xevent) = from;
XDND_ENTER_THREE_TYPES_SET (&xevent, n > XDND_THREE);
XDND_ENTER_VERSION_SET (&xevent, dnd->version);
for (i = 0; i < n && i < XDND_THREE; i++)
{
XDND_ENTER_TYPE (&xevent, i) = typelist[i];
}
XSendEvent (dnd->display, window, 0, 0, &xevent);
}
void
xdnd_send_position(DndClass *dnd, Window window, Window from, Atom action,
int x, int y, unsigned long time)
{
XEvent xevent;
memset (&xevent, 0, sizeof (xevent));
xevent.xany.type = ClientMessage;
xevent.xany.display = dnd->display;
xevent.xclient.window = window;
xevent.xclient.message_type = dnd->XdndPosition;
xevent.xclient.format = 32;
XDND_POSITION_SOURCE_WIN (&xevent) = from;
XDND_POSITION_ROOT_SET (&xevent, x, y);
if (dnd_version_at_least (dnd->dragging_version, 1))
XDND_POSITION_TIME (&xevent) = time;
if (dnd_version_at_least (dnd->dragging_version, 2))
XDND_POSITION_ACTION (&xevent) = action;
XSendEvent (dnd->display, window, 0, 0, &xevent);
}
void
xdnd_send_status(DndClass *dnd, Window window, Window from, int will_accept,
int want_position, int x, int y, int w, int h, Atom action)
{
XEvent xevent;
memset (&xevent, 0, sizeof (xevent));
xevent.xany.type = ClientMessage;
xevent.xany.display = dnd->display;
xevent.xclient.window = window;
xevent.xclient.message_type = dnd->XdndStatus;
xevent.xclient.format = 32;
XDND_STATUS_TARGET_WIN (&xevent) = from;
XDND_STATUS_WILL_ACCEPT_SET (&xevent, will_accept);
if (will_accept)
XDND_STATUS_WANT_POSITION_SET (&xevent, want_position);
if (want_position)
XDND_STATUS_RECT_SET (&xevent, x, y, w, h);
if (dnd_version_at_least (dnd->dragging_version, 2))
if (will_accept)
XDND_STATUS_ACTION (&xevent) = action;
XSendEvent (dnd->display, window, 0, 0, &xevent);
}
void
xdnd_send_leave(DndClass *dnd, Window window, Window from)
{
XEvent xevent;
memset(&xevent, 0, sizeof (xevent));
xevent.xany.type = ClientMessage;
xevent.xany.display = dnd->display;
xevent.xclient.window = window;
xevent.xclient.message_type = dnd->XdndLeave;
xevent.xclient.format = 32;
XDND_LEAVE_SOURCE_WIN (&xevent) = from;
XSendEvent (dnd->display, window, 0, 0, &xevent);
}
void
xdnd_send_drop(DndClass *dnd, Window window, Window from, unsigned long time)
{
XEvent xevent;
memset (&xevent, 0, sizeof (xevent));
xevent.xany.type = ClientMessage;
xevent.xany.display = dnd->display;
xevent.xclient.window = window;
xevent.xclient.message_type = dnd->XdndDrop;
xevent.xclient.format = 32;
XDND_DROP_SOURCE_WIN (&xevent) = from;
if (dnd_version_at_least (dnd->dragging_version, 1))
XDND_DROP_TIME (&xevent) = time;
XSendEvent (dnd->display, window, 0, 0, &xevent);
}
void
xdnd_send_finished(DndClass * dnd, Window window, Window from, int error)
{
XEvent xevent;
memset (&xevent, 0, sizeof (xevent));
xevent.xany.type = ClientMessage;
xevent.xany.display = dnd->display;
xevent.xclient.window = window;
xevent.xclient.message_type = dnd->XdndFinished;
xevent.xclient.format = 32;
XDND_FINISHED_TARGET_WIN (&xevent) = from;
XSendEvent (dnd->display, window, 0, 0, &xevent);
}
int
xdnd_convert_selection(DndClass *dnd, Window window, Window requester, Atom type)
{
if (window != XGetSelectionOwner (dnd->display, dnd->XdndSelection))
{
dnd_debug ("xdnd_convert_selection(): XGetSelectionOwner failed");
return 1;
}
XConvertSelection (dnd->display, dnd->XdndSelection, type,
dnd->Xdnd_NON_PROTOCOL_ATOM, requester, CurrentTime);
return 0;
}
int
xdnd_set_selection_owner(DndClass * dnd, Window window, Atom type)
{
if (!XSetSelectionOwner(dnd->display,dnd->XdndSelection,window,CurrentTime))
{
dnd_debug ("xdnd_set_selection_owner(): XSetSelectionOwner failed");
return 1;
}
return 0;
}
void
xdnd_selection_send(DndClass * dnd, XSelectionRequestEvent * request,
unsigned char *data, int length)
{
XEvent xevent;
dnd_debug (" requestor = %ld", request->requestor);
dnd_debug (" property = %ld", request->property);
dnd_debug (" length = %d", length);
XChangeProperty (dnd->display, request->requestor, request->property,
request->target, 8, PropModeReplace, data, length);
xevent.xselection.type = SelectionNotify;
xevent.xselection.property = request->property;
xevent.xselection.display = request->display;
xevent.xselection.requestor = request->requestor;
xevent.xselection.selection = request->selection;
xevent.xselection.target = request->target;
xevent.xselection.time = request->time;
XSendEvent (dnd->display, request->requestor, 0, 0, &xevent);
}
//
// Unused
//
void
xdnd_set_type_list(DndClass * dnd, Window window, Atom * typelist)
{
int n = array_length (typelist);
XChangeProperty (dnd->display, window, dnd->XdndTypeList, XA_ATOM, 32,
PropModeReplace, (unsigned char *) typelist, n);
}
void
xdnd_get_type_list(DndClass * dnd, Window window, Atom ** typelist)
{
Atom type, *a, *tl;
int format;
unsigned long i, count, remaining;
unsigned char *data = NULL;
*typelist = 0;
XGetWindowProperty (dnd->display, window, dnd->XdndTypeList,
0, 0x8000000L, False, XA_ATOM, &type, &format, &count, &remaining, &data);
if (type != XA_ATOM || format != 32 || count == 0 || !data)
{
if (data)
XFree (data);
dnd_debug ("XGetWindowProperty failed in xdnd_get_type_list - dnd->XdndTypeList = %ld", dnd->XdndTypeList);
return;
}
tl = (Atom *)(new WXGC_ATOMIC char[(count + 1) * sizeof (Atom)]);
*typelist = tl;
a = (Atom *) data;
for (i = 0; i < count; i++)
(*typelist)[i] = a[i];
(*typelist)[count] = 0;
XFree (data);
}

135
src/wxxt/src/Windows/xdnd.h Normal file
View File

@ -0,0 +1,135 @@
/*
xdnd.c, xdnd.h - C program library for handling the Xdnd protocol
Copyright (C) 1998 Paul Sheer
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
Further info can also be obtained by emailing the author at,
psheer@obsidian.co.za
*/
#ifndef _X_DND_H
#define _X_DND_H
#define XDND_VERSION 3
/* XdndEnter */
#define XDND_THREE 3
#define XDND_ENTER_SOURCE_WIN(e) ((e)->xclient.data.l[0])
#define XDND_ENTER_THREE_TYPES(e) (((e)->xclient.data.l[1] & 0x1UL) == 0)
#define XDND_ENTER_THREE_TYPES_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x1UL) | (((b) == 0) ? 0 : 0x1UL)
#define XDND_ENTER_VERSION(e) ((e)->xclient.data.l[1] >> 24)
#define XDND_ENTER_VERSION_SET(e,v) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~(0xFF << 24)) | ((v) << 24)
#define XDND_ENTER_TYPE(e,i) ((e)->xclient.data.l[2 + i]) /* i => (0, 1, 2) */
/* XdndPosition */
#define XDND_POSITION_SOURCE_WIN(e) ((e)->xclient.data.l[0])
#define XDND_POSITION_ROOT_X(e) ((e)->xclient.data.l[2] >> 16)
#define XDND_POSITION_ROOT_Y(e) ((e)->xclient.data.l[2] & 0xFFFFUL)
#define XDND_POSITION_ROOT_SET(e,x,y) (e)->xclient.data.l[2] = ((x) << 16) | ((y) & 0xFFFFUL)
#define XDND_POSITION_TIME(e) ((e)->xclient.data.l[3])
#define XDND_POSITION_ACTION(e) ((e)->xclient.data.l[4])
/* XdndStatus */
#define XDND_STATUS_TARGET_WIN(e) ((e)->xclient.data.l[0])
#define XDND_STATUS_WILL_ACCEPT(e) ((e)->xclient.data.l[1] & 0x1L)
#define XDND_STATUS_WILL_ACCEPT_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x1UL) | (((b) == 0) ? 0 : 0x1UL)
#define XDND_STATUS_WANT_POSITION(e) ((e)->xclient.data.l[1] & 0x2UL)
#define XDND_STATUS_WANT_POSITION_SET(e,b) (e)->xclient.data.l[1] = ((e)->xclient.data.l[1] & ~0x2UL) | (((b) == 0) ? 0 : 0x2UL)
#define XDND_STATUS_RECT_X(e) ((e)->xclient.data.l[2] >> 16)
#define XDND_STATUS_RECT_Y(e) ((e)->xclient.data.l[2] & 0xFFFFL)
#define XDND_STATUS_RECT_WIDTH(e) ((e)->xclient.data.l[3] >> 16)
#define XDND_STATUS_RECT_HEIGHT(e) ((e)->xclient.data.l[3] & 0xFFFFL)
#define XDND_STATUS_RECT_SET(e,x,y,w,h) {(e)->xclient.data.l[2] = ((x) << 16) | ((y) & 0xFFFFUL); (e)->xclient.data.l[3] = ((w) << 16) | ((h) & 0xFFFFUL); }
#define XDND_STATUS_ACTION(e) ((e)->xclient.data.l[4])
/* XdndLeave */
#define XDND_LEAVE_SOURCE_WIN(e) ((e)->xclient.data.l[0])
/* XdndDrop */
#define XDND_DROP_SOURCE_WIN(e) ((e)->xclient.data.l[0])
#define XDND_DROP_TIME(e) ((e)->xclient.data.l[2])
/* XdndFinished */
#define XDND_FINISHED_TARGET_WIN(e) ((e)->xclient.data.l[0])
typedef struct _DndClass DndClass;
struct _DndClass {
Display *display;
Atom XdndAware;
Atom XdndSelection;
Atom XdndEnter;
Atom XdndLeave;
Atom XdndPosition;
Atom XdndDrop;
Atom XdndFinished;
Atom XdndStatus;
Atom XdndActionCopy;
Atom XdndActionMove;
Atom XdndActionLink;
Atom XdndActionAsk;
Atom XdndActionPrivate;
Atom XdndTypeList;
Atom XdndActionList;
Atom XdndActionDescription;
Atom Xdnd_NON_PROTOCOL_ATOM;
Atom version;
Atom text_uri_list;
Window root_window;
#define XDND_DROP_STAGE_IDLE 0
#define XDND_DRAG_STAGE_DRAGGING 1
#define XDND_DRAG_STAGE_ENTERED 2
#define XDND_DROP_STAGE_CONVERTING 3
#define XDND_DROP_STAGE_ENTERED 4
int stage;
int dragging_version;
int internal_drag;
int want_position;
int ready_to_drop;
int will_accept;
XRectangle rectangle;
Window dropper_window, dragger_window;
Atom *dragger_typelist;
Atom desired_type;
Atom supported_action;
Time time;
/* drop position from last XdndPosition */
int x, y;
/* block for only this many seconds on not receiving a XdndFinished from target, default : 10 */
int time_out;
};
void xdnd_init (DndClass * dnd, Display * display);
void xdnd_set_dnd_aware (DndClass * dnd, Window window, Atom * typelist);
void xdnd_set_dnd_unaware (DndClass * dnd, Window window);
int xdnd_is_dnd_aware (DndClass * dnd, Window window, int *version, Atom * typelist);
void xdnd_set_type_list (DndClass * dnd, Window window, Atom * typelist);
void xdnd_send_enter (DndClass * dnd, Window window, Window from, Atom * typelist);
void xdnd_send_position (DndClass * dnd, Window window, Window from, Atom action, int x, int y, unsigned long etime);
void xdnd_send_status (DndClass * dnd, Window window, Window from, int will_accept,
int want_position, int x, int y, int w, int h, Atom action);
void xdnd_send_leave (DndClass * dnd, Window window, Window from);
void xdnd_send_drop (DndClass * dnd, Window window, Window from, unsigned long etime);
void xdnd_send_finished (DndClass * dnd, Window window, Window from, int error);
int xdnd_convert_selection (DndClass * dnd, Window window, Window requester, Atom type);
void xdnd_selection_send (DndClass * dnd, XSelectionRequestEvent * request, unsigned char *data, int length);
#endif /* !_X_DND_H */