--- /dev/null 2014-07-31 16:13:19.122792434 +0400 +++ new/test/java/awt/reliability/xdnd-child.c 2014-07-31 17:28:03.558614710 +0400 @@ -0,0 +1,903 @@ +/* + * Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @summary Native window for TaskXDragDrop. This is taken from + * XDnD Tiger AWT testsuite. + * @author Aruna Samji (aruna.samji@sun.com) + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +//#define TRACE + +/* XDnD atom names */ +static const char* XAtomName_XdndActionCopy = "XdndActionCopy"; +static const char* XAtomName_XdndAware = "XdndAware"; +static const char* XAtomName_XdndDrop = "XdndDrop"; +static const char* XAtomName_XdndEnter = "XdndEnter"; +static const char* XAtomName_XdndFinished = "XdndFinished"; +static const char* XAtomName_XdndLeave = "XdndLeave"; +static const char* XAtomName_XdndPosition = "XdndPosition"; +static const char* XAtomName_XdndProxy = "XdndProxy"; +static const char* XAtomName_XdndSelection = "XdndSelection"; +static const char* XAtomName_XdndStatus = "XdndStatus"; + +static const char* XAtomName_XdndActionMove = "XdndActionMove"; +static const char* XAtomName_XdndActionLink = "XdndActionLink"; + +static const char* XAtomName_TextPlain = "text/plain"; + +/* XDnD atoms */ +static Atom _XA_XdndActionCopy = None; +static Atom _XA_XdndAware = None; +static Atom _XA_XdndDrop = None; +static Atom _XA_XdndEnter = None; +static Atom _XA_XdndFinished = None; +static Atom _XA_XdndLeave = None; +static Atom _XA_XdndPosition = None; +static Atom _XA_XdndProxy = None; +static Atom _XA_XdndSelection = None; +static Atom _XA_XdndStatus = None; +static Atom _XA_TextPlain = None; + +static Atom _XA_XdndActionMove = None; +static Atom _XA_XdndActionLink = None; + +/* XDnD constants */ +static const Atom XDnDVersion = 4; +static const unsigned int DND_VERSION_SHIFT = 24; +static const unsigned int ACCEPT_DROP_FLAG = 1; + +/* shared constants */ +static const EventMask DRAG_MASK = ButtonMotionMask | PointerMotionMask | + KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask; + +/* shared function prototypes */ +static void init(); +static void remove_dnd_grab(Display* dpy, Time time); +static void cleanup_drag(Display* dpy); +static void register_drag_source(Widget widget); + +/* XDnD support */ +static Boolean intern_xdnd_atoms(Display* dpy); +static void update_dnd_version(int version); +static int get_dnd_version(); +static void set_same_answer(int x, int y, int w, int h); +static Boolean is_same_answer(int x, int y); +static Boolean register_xdnd_drop_target(Widget widget); + +/* shared state variables */ +static Boolean drag_in_progress = False; + +static Window target_win = None; +static Window target_proxy_win = None; + +static char* drop_data = NULL; + +int main(int argc, char **argv) { + XtAppContext app; + Widget widget = XtAppInitialize (&app, "XDnD_main", + NULL, 0, + &argc, argv, + NULL, NULL, 0); + + XtVaSetValues(widget, XtNx, 550, XtNy, 220, + XtNwidth, 200, XtNheight, 150, NULL); + XtRealizeWidget(widget); + + init(); + intern_xdnd_atoms(XtDisplay(widget)); + + register_drag_source(widget); + register_xdnd_drop_target(widget); + + XSetSelectionOwner(XtDisplay(widget), XA_PRIMARY, None, CurrentTime); + +#ifdef DEBUG + fprintf(stderr,"Root=%X\n", XRootWindowOfScreen(XtScreen(widget))); +#endif + for (;;) { + XEvent event; + Window root_win = XRootWindowOfScreen(XtScreen(widget)); + XtAppNextEvent(app, &event); +#ifdef DEBUG + fprintf(stderr,"Event type=%d win=%X\n", event.type, event.xany.window); + if (event.type == MotionNotify) { + fprintf(stderr," subwin=%X\n", event.xmotion.subwindow); + } +#endif + if (drag_in_progress && event.xany.window == root_win) { + switch (event.type) { + case ButtonPress: + case ButtonRelease: + case MotionNotify: + case EnterNotify: + case LeaveNotify: + { + Window child; + XTranslateCoordinates(XtDisplay(widget), root_win, + XtWindow(widget), + event.xbutton.x, event.xbutton.y, + &event.xbutton.x, &event.xbutton.y, + &child); + } + case KeyPress: + case KeyRelease: + event.xany.window = XtWindow(widget); + } + } + XtDispatchEvent(&event); + } + + return 0; +} + +static Boolean bad_window = False; +static int (*original_x_errhandler)(Display* dpy, XErrorEvent*); + +static int x_errhandler(Display *dpy, XErrorEvent *err) { + if (err->error_code == BadWindow) { + bad_window = True; + } + + { + char errstr[256]; + XGetErrorText( dpy, err->error_code, errstr, 256 ); + fprintf(stderr, "Error: %s %d\n Major opcode: %d\n Resource id: 0x%lx\n", + errstr, err->error_code, err->request_code, err->resourceid); + } + return 0; +} + +static void init() { + original_x_errhandler = XSetErrorHandler(x_errhandler); +} + +static Boolean intern_xdnd_atoms(Display* dpy) { + _XA_XdndActionCopy = XInternAtom(dpy, XAtomName_XdndActionCopy, False); + if (_XA_XdndActionCopy == None) { + return False; + } + + _XA_XdndActionMove = XInternAtom(dpy, XAtomName_XdndActionMove, False); + if (_XA_XdndActionMove == None) { + return False; + } + + _XA_XdndActionLink = XInternAtom(dpy, XAtomName_XdndActionLink, False); + if (_XA_XdndActionLink == None) { + return False; + } + + _XA_XdndAware = XInternAtom(dpy, XAtomName_XdndAware, False); + if (_XA_XdndAware == None) { + return False; + } + + _XA_XdndDrop = XInternAtom(dpy, XAtomName_XdndDrop, False); + if (_XA_XdndDrop == None) { + return False; + } + + _XA_XdndEnter = XInternAtom(dpy, XAtomName_XdndEnter, False); + if (_XA_XdndEnter == None) { + return False; + } + + _XA_XdndFinished = XInternAtom(dpy, XAtomName_XdndFinished, False); + if (_XA_XdndFinished == None) { + return False; + } + + _XA_XdndLeave = XInternAtom(dpy, XAtomName_XdndLeave, False); + if (_XA_XdndLeave == None) { + return False; + } + + _XA_XdndPosition = XInternAtom(dpy, XAtomName_XdndPosition, False); + if (_XA_XdndPosition == None) { + return False; + } + + _XA_XdndProxy = XInternAtom(dpy, XAtomName_XdndProxy, False); + if (_XA_XdndProxy == None) { + return False; + } + + _XA_XdndSelection = XInternAtom(dpy, XAtomName_XdndSelection, False); + if (_XA_XdndSelection == None) { + return False; + } + + _XA_XdndStatus = XInternAtom(dpy, XAtomName_XdndStatus, False); + if (_XA_XdndStatus == None) { + return False; + } + + _XA_TextPlain = XInternAtom(dpy, XAtomName_TextPlain, False); + if (_XA_TextPlain == None) { + return False; + } + + return True; +} + +/******************************* Drag source support **************************/ + +static Boolean +xdnd_convert_proc(Widget w, Atom * selection, Atom * target, Atom * type, + XtPointer * value, unsigned long *length, int32_t *format) { + +#ifdef DEBUG + fprintf(stderr,"xdnd_convert_proc\n"); +#endif + if (*target == _XA_TextPlain) { + char* str = drop_data; + int len = strlen(str); + + char* copy = (char*)XtMalloc(len); + strcpy(copy, str); + + *type = *target; + *value = (XtPointer)copy; + *length = len; + *format = 8; + + return True; + } + return False; +} + +static Window find_receiver_window(Widget wid, int x, int y) { + Display* dpy = XtDisplay(wid); + Atom type; + int format; + unsigned long nitems; + unsigned long after; + unsigned char *data; + + Window src_w = XtWindow(wid); + Window dest_w = XRootWindowOfScreen(XtScreen(wid)); + Window ret_w = None; + Window child_w = None; + int src_x = x; + int src_y = y; + + while (dest_w != None) { + XTranslateCoordinates(dpy, src_w, dest_w, + src_x, src_y, &src_x, &src_y, &child_w); + + if (child_w == None) { + break; + } + + src_w = dest_w; + dest_w = child_w; + + type = None; + XGetWindowProperty(dpy, dest_w, _XA_XdndAware, 0, 1, False, + AnyPropertyType, &type, &format, &nitems, + &after, &data); + + if (type == XA_ATOM && data != NULL) { + ret_w = dest_w; + } + + XFree(data); + data = NULL; + } + + return ret_w; +} + +static void update_receiver_window(Display* dpy, Window win) { + Atom type; + int format; + unsigned long nitems; + unsigned long after; + unsigned char *data; + + if (win == None) { + target_win = None; + target_proxy_win = None; + return; + } + + XGetWindowProperty(dpy, win, _XA_XdndAware, 0, 1, False, + AnyPropertyType, &type, &format, &nitems, + &after, &data); + + if (type == XA_ATOM && data != NULL) { + Window proxy_win = None; + int target_version = *((int*)data); + update_dnd_version(target_version); + + XFree(data); + + XGetWindowProperty(dpy, win, _XA_XdndProxy, 0, 1, False, + XA_WINDOW, &type, &format, &nitems, &after, &data); + + if (type == XA_WINDOW && data != None) { + proxy_win = *((Window*)data); + XFree(data); + + XGetWindowProperty(dpy, proxy_win, _XA_XdndProxy, 0, 1, False, + XA_WINDOW, &type, &format, &nitems, &after, &data); + + if (type != XA_WINDOW || data == NULL || + *((Window*)data) != proxy_win) { + proxy_win = None; + } + + XFree(data); + + if (proxy_win == None) { + proxy_win = win; + } + } + + target_win = win; + target_proxy_win = proxy_win; + } else { + XFree(data); + } + + if (target_proxy_win == None) { + target_proxy_win = target_win; + } + + { + XWindowAttributes xwa; + + XGetWindowAttributes(dpy, win, &xwa); + XSelectInput(dpy, win, + xwa.your_event_mask | EnterWindowMask | LeaveWindowMask); + } +} + +static void xdnd_send_enter(Display* dpy, Window source_win, XMotionEvent* event) { + XClientMessageEvent enter; + + enter.type = ClientMessage; + enter.window = target_win; + enter.format = 32; + enter.message_type = _XA_XdndEnter; + enter.data.l[0] = source_win; + enter.data.l[1] = get_dnd_version() << DND_VERSION_SHIFT; + enter.data.l[2] = _XA_TextPlain; + enter.data.l[3] = 0; + enter.data.l[4] = 0; + + set_same_answer(event->x_root - 1, + event->y_root - 1, 3, 3); + +#ifdef DEBUG + fprintf(stderr,"xdnd_send_enter win=%X\n", target_proxy_win); +#endif + XSendEvent(dpy, target_proxy_win, False, NoEventMask, + (XEvent*)&enter); +} + +static void +send_enter(Display* dpy, Window source_win, XMotionEvent* event) { + xdnd_send_enter(dpy, source_win, event); +} + + +static void +xdnd_send_leave(Display* dpy, Window source_win, XMotionEvent* event) { + XClientMessageEvent leave; + + leave.type = ClientMessage; + leave.window = target_win; + leave.format = 32; + leave.message_type = _XA_XdndLeave; + leave.data.l[0] = source_win; + leave.data.l[1] = 0; + leave.data.l[2] = 0; + leave.data.l[3] = 0; + leave.data.l[4] = 0; + +#ifdef DEBUG + fprintf(stderr,"xdnd_send_leave win=%X\n", target_proxy_win); +#endif + XSendEvent(dpy, target_proxy_win, False, NoEventMask, + (XEvent*)&leave); +} + +static void +send_leave(Display* dpy, Window source_win, XMotionEvent* event) { + xdnd_send_leave(dpy, source_win, event); +} + +static void +xdnd_send_move(Display* dpy, Window source_win, XMotionEvent* event) { + XClientMessageEvent move; + + move.type = ClientMessage; + move.window = target_win; + move.format = 32; + move.message_type = _XA_XdndPosition; + move.data.l[0] = source_win; + move.data.l[1] = 0; /* flags */ + move.data.l[2] = event->x_root << 16 | event->y_root; + move.data.l[3] = event->time; + /*move.data.l[4] = _XA_XdndActionCopy;*/ + move.data.l[4] = _XA_XdndActionMove; + + if (event != NULL) { + switch (event->state & (ShiftMask | ControlMask)) { + case 0 : move.data.l[4] = _XA_XdndActionCopy; break; + case ShiftMask : move.data.l[4] = _XA_XdndActionMove; break; + case ControlMask : move.data.l[4] = _XA_XdndActionCopy; break; + case (ShiftMask | ControlMask) : move.data.l[4] = _XA_XdndActionLink; break; + } + } + +#ifdef DEBUG + fprintf(stderr,"xdnd_send_move win=%X\n", target_proxy_win); +#endif + XSendEvent(dpy, target_proxy_win, False, NoEventMask, + (XEvent*)&move); +} + +static void send_move(Display* dpy, Window source_win, XMotionEvent* event) { + xdnd_send_move(dpy, source_win, event); +} + +static void handle_move(Widget w, XMotionEvent* event) { + Display* dpy = XtDisplay(w); + Window source_win = XtWindow(w); + Window receiver_win = None; + int flags = 2 | 3 << 4 | 2 << 8; + + receiver_win = find_receiver_window(w, event->x, event->y); +#ifdef DEBUG + fprintf(stderr,"handle_move receiver=%X\n", receiver_win); + fprintf(stderr," target=%X proxy=%X\n", target_win, target_proxy_win); +#endif + + if (target_win != receiver_win) { + if (target_win != None) { + send_leave(dpy, source_win, event); + } + + update_receiver_window(dpy, receiver_win); + + if (target_win != None) { + send_enter(dpy, source_win, event); + } + } + + if (target_win != None) { + send_move(dpy, source_win, event); + } +} + +static void handle_xdnd_status(Widget w, XClientMessageEvent* event) { +#ifdef TRACE + fprintf(stderr,"[Source] dragOver {XDnD}\n"); +#endif + +#ifdef DEBUG + fprintf(stderr,"handle_xdnd_status\n"); +#endif +} + +static void +handle_xdnd_finished(Widget w, XClientMessageEvent* event) { +#ifdef TRACE + fprintf(stderr,"[Source] dragDropEnd {XDnD}\n"); +#endif + +#ifdef DEBUG + fprintf(stderr,"handle_xdnd_finished\n"); +#endif + cleanup_drag(XtDisplay(w)); + fprintf(stderr,"finished\n"); + //exit(0); +} + +static void +xdnd_handle_client_message(Widget w, XClientMessageEvent* event) { + if (event->message_type == _XA_XdndStatus) { + handle_xdnd_status(w, event); + } else if (event->message_type == _XA_XdndFinished) { + handle_xdnd_finished(w, event); + } +} + +static void +handle_client_message(Widget w, XClientMessageEvent* event) { + xdnd_handle_client_message(w, event); +} + +static void +xdnd_send_drop(Display* dpy, Window source_win, XButtonEvent* event) { + XClientMessageEvent drop; + drop.type = ClientMessage; + drop.window = target_win; + drop.format = 32; + drop.message_type = _XA_XdndDrop; + drop.data.l[0] = source_win; + drop.data.l[1] = 1 << 24; /* flags */ + drop.data.l[2] = 0; /* ### */ + drop.data.l[3] = event->time; + drop.data.l[4] = 0; + + XSendEvent(dpy, target_proxy_win, False, NoEventMask, (XEvent*)&drop); +} + +static void +send_drop(Display* dpy, Window source_win, XButtonEvent* event) { + xdnd_send_drop(dpy, source_win, event); +} + +static void +drag_event_handler(Widget w, XtPointer client_data, + XEvent * event, Boolean * cont) { +#ifdef DEBUG + fprintf(stderr,"drag_event_handler type=%d in_progress=%X\n", event->type, drag_in_progress); +#endif + + if (!drag_in_progress) { + XtRemoveEventHandler(w, DRAG_MASK, False, drag_event_handler, NULL); + return; + } + + switch (event->type) { + case KeyRelease: { + KeySym keysym = XKeycodeToKeysym(XtDisplay(w), event->xkey.keycode, 0); + #ifdef DEBUG + fprintf(stderr,"\tKeyRelease code=%X sym=%X\n", event->xkey.keycode); + #endif + if (keysym == XK_Escape) { + remove_dnd_grab(XtDisplay(w), event->xkey.time); + cleanup_drag(XtDisplay(w)); + } + *cont = False; + break; + } + case KeyPress: + case ButtonPress: + break; + case MotionNotify: { + handle_move(w, (XMotionEvent*)event); + break; + } + case ButtonRelease: + #ifdef DEBUG + fprintf(stderr,"\tButtonRelease button=%d\n", event->xbutton.button); + #endif + if (event->xbutton.button == Button1) { + remove_dnd_grab(XtDisplay(w), event->xbutton.time); + if (target_win != None) { + send_drop(XtDisplay(w), XtWindow(w), &event->xbutton); + #ifdef DEBUG + fprintf(stderr,"DROP_START sent\n"); + #endif + } else { + cleanup_drag(XtDisplay(w)); + } + *cont = True; + } else { + *cont = False; + } + break; + case ClientMessage: + handle_client_message(w, &event->xclient); + break; + } +} + +static void initiate_drag(Widget w, XEvent* event) { + Display* dpy = XtDisplay(w); + int num_targets = 1; + Atom target = XA_STRING; + int index = -1; + unsigned int event_mask = + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | EnterWindowMask | LeaveWindowMask; + unsigned int root_event_mask = + ButtonMotionMask | EnterWindowMask | LeaveWindowMask | KeyPressMask | KeyReleaseMask; + + if (XtOwnSelection(w, _XA_XdndSelection, event->xmotion.time, + xdnd_convert_proc, NULL, NULL) != True) { +#ifdef DEBUG + fprintf(stderr,"initiate_drag: cannot own selection\n"); +#endif + return; + } + + { + Window root_win = RootWindowOfScreen(XtScreen(w)); + XWindowAttributes xwa; + Cursor cursor = XCreateFontCursor(dpy, XC_hand2); + + XGetWindowAttributes(dpy, root_win, &xwa); + XSelectInput(dpy, root_win, xwa.your_event_mask | root_event_mask); + + if (XGrabPointer(dpy, root_win, + True, + event_mask, + GrabModeSync, + GrabModeAsync, + None, + cursor, + event->xmotion.time) != GrabSuccess) { + #ifdef DEBUG + fprintf(stderr,"initiate_drag: XGrabPointer fails\n"); + #endif + return; + } + + if (XGrabKeyboard(dpy, root_win, + False, + GrabModeSync, + GrabModeAsync, + event->xmotion.time) != GrabSuccess) { + #ifdef DEBUG + fprintf(stderr,"initiate_drag: XGrabKeyboard fails\n"); + #endif + return; + } + XAllowEvents(dpy, SyncPointer, event->xmotion.time); + } + XtInsertEventHandler(w, DRAG_MASK, + True, drag_event_handler, NULL, XtListHead); +} + +static void +drag_gesture_recognizer(Widget w, XtPointer client_data, + XEvent * event, Boolean * cont) { +#ifdef DEBUG + fprintf(stderr,"drag_gesture_recognizer: type=%d\n", event->type); +#endif + if (event->type != MotionNotify) { + return; + } + + if (drag_in_progress) { +#ifdef DEBUG + fprintf(stderr,"initiate_drag: in progress\n"); +#endif + return; + } + +#ifdef DEBUG + fprintf(stderr,"drag_gesture_recognizer: start\n"); +#endif + initiate_drag(w, event); + drag_in_progress = True; +} + +static void register_drag_source(Widget w) { +#ifdef DEBUG + fprintf(stderr,"register_drag_source: w=%X\n", w); +#endif + XtAddEventHandler(w, ButtonMotionMask | ButtonPressMask, + False, drag_gesture_recognizer, (XtPointer)NULL); +} + +static void remove_dnd_grab(Display* dpy, Time time) { + XUngrabPointer(dpy, time); + XUngrabKeyboard(dpy, time); +} + +static void cleanup_drag(Display* dpy) { +#ifdef DEBUG + fprintf(stderr,"cleanup_drag\n"); +#endif + + drag_in_progress = False; + target_win = None; + target_proxy_win = None; +} + +/* XDnD state variables */ +static int dnd_version = 0; + +static int same_x = 0; +static int same_y = 0; +static int same_w = 0; +static int same_h = 0; + +static void set_same_answer(int x, int y, int w, int h) { + same_x = x; + same_y = y; + same_w = w; + same_h = h; +} + +static Boolean is_same_answer(int x, int y) { + if (!drag_in_progress) { + return False; + } + + if (x >= same_x && x < same_x + same_w && + y >= same_y && y < same_y + same_h) { + return True; + } + + return False; +} + +static void update_dnd_version(int version) { + dnd_version = XDnDVersion < version ? XDnDVersion : version; +} + +static int get_dnd_version() { + return dnd_version; +} + +/******************************* Drop target support **************************/ + +static void handle_xdnd_enter(Widget w, XEvent* event) { +#ifdef TRACE + fprintf(stderr,"[Target] dragEnter {XDnD}\n"); +#endif + +#ifdef DEBUG + fprintf(stderr,"handle_xdnd_enter\n"); +#endif +} + +static void handle_xdnd_leave(Widget w, XEvent* event) { +#ifdef TRACE + fprintf(stderr,"[Target] dragExit {XDnD}\n"); +#endif +#ifdef DEBUG + fprintf(stderr,"handle_xdnd_leave\n"); +#endif +} + +static void handle_xdnd_position(Widget w, XEvent* event) { + Window drag_source = event->xclient.data.l[0]; + XClientMessageEvent response; + response.type = ClientMessage; + response.window = drag_source; + response.format = 32; + response.message_type = _XA_XdndStatus; + response.data.l[0] = XtWindow(w); + response.data.l[1] = 0; /* flags */ + response.data.l[2] = 0; /* x, y */ + response.data.l[3] = 0; /* w, h */ + response.data.l[4] = 0; /* action */ + + response.data.l[1] |= ACCEPT_DROP_FLAG; + /*response.data.l[4] = _XA_XdndActionCopy;*/ + response.data.l[4] = _XA_XdndActionMove; + +#ifdef TRACE + fprintf(stderr,"[Target] dragOver {XDnD}\n"); +#endif +#ifdef DEBUG + fprintf(stderr,"handle_xdnd_position win=%ld\n", event->xclient.data.l[0]); +#endif + XSendEvent(XtDisplay(w), drag_source, False, + NoEventMask, (XEvent*)&response); +} + +static void +selection_callback_proc(Widget w, XtPointer client_data, Atom* selection, + Atom* type, XtPointer value, unsigned long* length, + int* format) { + + if (*type == _XA_TextPlain) { +#ifdef DEBUG + fprintf(stderr,"selection_callback_proc data=%s\n", (char*)value); +#endif +#ifdef TRACE + fprintf(stderr,"[Target] drop {XDnD} data=%s\n", (char*)value); +#endif + } + + if (value != NULL && *length != 0) { + drop_data = calloc(1, 2*(*length)); + strcpy(drop_data, (char*)value); + strcpy(drop_data + (*length), (char*)value); +#ifdef TRACE + fprintf(stderr,"[Target] drag data=%s\n", drop_data); +#endif + } + + if (value != NULL) { + XtFree((char*)value); + } +} + +static void handle_xdnd_drop(Widget w, XEvent* event) { +#ifdef TRACE + fprintf(stderr,"[Target] drop {XDnD}\n"); +#endif + XtGetSelectionValue(w, _XA_XdndSelection, _XA_TextPlain, + selection_callback_proc, NULL, + XtLastTimestampProcessed(XtDisplay(w))); +#ifdef DEBUG + fprintf(stderr,"handle_xdnd_drop\n"); +#endif + { + Window drag_source = event->xclient.data.l[0]; + XClientMessageEvent finished; + finished.type = ClientMessage; + finished.window = drag_source; + finished.format = 32; + finished.message_type = _XA_XdndFinished; + finished.data.l[0] = XtWindow(w); + finished.data.l[1] = 0; /* flags */ + XSendEvent(XtDisplay(w), drag_source, False, + NoEventMask, (XEvent*)&finished); + } +} + +static void +target_client_message_handler(Widget w, XtPointer client_data, + XEvent* event, Boolean* cont) { +#ifdef DEBUG + fprintf(stderr,"target_client_message_handler\n"); +#endif + + if (event->type != ClientMessage) { + return; + } + + if (event->xclient.message_type == _XA_XdndEnter) { + handle_xdnd_enter(w, event); + } else if (event->xclient.message_type == _XA_XdndPosition) { + handle_xdnd_position(w, event); + } else if (event->xclient.message_type == _XA_XdndLeave) { + handle_xdnd_leave(w, event); + } else if (event->xclient.message_type == _XA_XdndDrop) { + handle_xdnd_drop(w, event); + } +} + +static Boolean register_xdnd_drop_target(Widget widget) { + Widget w = NULL; + + for (w = widget; w != NULL && !XtIsShell(w); w = XtParent(w)); + + if (w == NULL || XtWindow(w) == None) { + return False; + } + +#ifdef DEBUG + fprintf(stderr,"register_xdnd_drop_target win=%X\n", XtWindow(w)); +#endif + XChangeProperty(XtDisplay(w), XtWindow(w), + _XA_XdndAware, XA_ATOM, 32, + PropModeReplace, + (unsigned char*)&XDnDVersion, 1); + + XtAddEventHandler(w, EnterWindowMask | LeaveWindowMask, + True, target_client_message_handler, NULL); +} +/*************************** End drop target support **************************/