jdk/src/solaris/native/sun/awt/awt_dnd_ds.c
changeset 1192 715cf9378c53
parent 1051 90cf935adb35
parent 1191 f142c1da78c2
child 1193 41afb8ee8f45
equal deleted inserted replaced
1051:90cf935adb35 1192:715cf9378c53
     1 /*
       
     2  * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 #ifdef HEADLESS
       
    27     #error This file should not be included in headless library
       
    28 #endif
       
    29 
       
    30 #include "awt_dnd.h"
       
    31 
       
    32 /* Declares getCursor(JNIEnv, jobject) */
       
    33 #include "awt_Cursor.h"
       
    34 
       
    35 /* Define java constants */
       
    36 #include "java_awt_dnd_DnDConstants.h"
       
    37 #include "sun_awt_dnd_SunDragSourceContextPeer.h"
       
    38 
       
    39 /* Define DECLARE_* macros */
       
    40 #include "awt_DataTransferer.h"
       
    41 
       
    42 #define GRAB_EVENT_MASK                                          \
       
    43    (ButtonPressMask | ButtonMotionMask | ButtonReleaseMask)
       
    44 
       
    45 /* Events selected on the root window during drag. */
       
    46 #define ROOT_EVENT_MASK                                          \
       
    47    (ButtonMotionMask | KeyPressMask | KeyReleaseMask)
       
    48 
       
    49 /* Events selected on registered receiver windows during drag. */
       
    50 #define RECEIVER_EVENT_MASK                                      \
       
    51    (StructureNotifyMask)
       
    52 
       
    53 
       
    54 /* in canvas.c */
       
    55 extern jint getModifiers(uint32_t state, jint button, jint keyCode);
       
    56 
       
    57 typedef struct {
       
    58     CARD8    byte_order;
       
    59     CARD8    protocol_version;
       
    60     CARD16   index;
       
    61     CARD32   selection_atom;
       
    62 } InitiatorInfo;
       
    63 
       
    64 typedef enum {
       
    65     /*
       
    66      * Communicate with receivers of both protocols.
       
    67      * If the receiver supports both protocols,
       
    68      * choose Motif DnD for communication.
       
    69      */
       
    70     DS_POLICY_PREFER_MOTIF,
       
    71     /*
       
    72      * Communicate with receivers of both protocols.
       
    73      * If the receiver supports both protocols,
       
    74      * choose XDnD for communication. [default]
       
    75      */
       
    76     DS_POLICY_PREFER_XDND,
       
    77     /* Communicate only with Motif DnD receivers. */
       
    78     DS_POLICY_ONLY_MOTIF,
       
    79     /* Communicate only with XDnD receivers. */
       
    80     DS_POLICY_ONLY_XDND
       
    81 } DragSourcePolicy;
       
    82 
       
    83 
       
    84 /* The drag source policy. */
       
    85 static DragSourcePolicy drag_source_policy = DS_POLICY_PREFER_XDND;
       
    86 
       
    87 static Boolean dnd_in_progress = False;
       
    88 static Boolean drag_in_progress = False;
       
    89 static jobject source_peer = NULL;
       
    90 static Atom* data_types = NULL;
       
    91 static unsigned int data_types_count = 0;
       
    92 static Window drag_root_window = None;
       
    93 static EventMask your_root_event_mask = NoEventMask;
       
    94 static Time latest_time_stamp = CurrentTime;
       
    95 
       
    96 /* The child of the root which is currently under the mouse. */
       
    97 static Window target_root_subwindow = None;
       
    98 
       
    99 static Window target_window = None;
       
   100 static long target_window_mask = 0;
       
   101 static Window target_proxy_window = None;
       
   102 static Protocol target_protocol = NO_PROTOCOL;
       
   103 static unsigned int target_protocol_version = 0;
       
   104 /*
       
   105  * The server time when the pointer entered the current target -
       
   106  * needed on Motif DnD to filter out messages from the previous
       
   107  * target.
       
   108  * It is updated whenever the target_window is updated.
       
   109  * If the target_window is set to non-None, it is set to the time stamp
       
   110  * of the X event that trigger the update. Otherwise, it is set to CurrentTime.
       
   111  */
       
   112 static Time target_enter_server_time = CurrentTime;
       
   113 
       
   114 static int x_root = 0;
       
   115 static int y_root = 0;
       
   116 static unsigned int event_state = 0;
       
   117 
       
   118 static jint source_action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
   119 static jint source_actions = java_awt_dnd_DnDConstants_ACTION_NONE;
       
   120 static jint target_action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
   121 
       
   122 /* Forward declarations */
       
   123 static void cleanup_drag(Display* dpy, Time time);
       
   124 static Boolean process_proxy_mode_event(XEvent* xev);
       
   125 
       
   126 /**************************** XEmbed server DnD support ***********************/
       
   127 static Window proxy_mode_source_window = None;
       
   128 /******************************************************************************/
       
   129 
       
   130 /**************************** JNI stuff ***************************************/
       
   131 
       
   132 DECLARE_JAVA_CLASS(dscp_clazz, "sun/awt/dnd/SunDragSourceContextPeer")
       
   133 
       
   134 static void
       
   135 ds_postDragSourceDragEvent(JNIEnv* env, jint targetAction, unsigned int state,
       
   136                            int x, int y, jint dispatch_type) {
       
   137     DECLARE_VOID_JAVA_METHOD(dscp_postDragSourceDragEvent, dscp_clazz,
       
   138                              "postDragSourceDragEvent", "(IIIII)V");
       
   139 
       
   140     DASSERT(!JNU_IsNull(env, source_peer));
       
   141     if (JNU_IsNull(env, source_peer)) {
       
   142         return;
       
   143     }
       
   144 
       
   145     (*env)->CallVoidMethod(env, source_peer, dscp_postDragSourceDragEvent,
       
   146                            targetAction, getModifiers(state, 0, 0), x, y,
       
   147                            dispatch_type);
       
   148 }
       
   149 
       
   150 static jint
       
   151 ds_convertModifiersToDropAction(JNIEnv* env, unsigned int state) {
       
   152     jint action;
       
   153     DECLARE_STATIC_JINT_JAVA_METHOD(dscp_convertModifiersToDropAction, dscp_clazz,
       
   154                                     "convertModifiersToDropAction", "(II)I");
       
   155     action = (*env)->CallStaticIntMethod(env, clazz, dscp_convertModifiersToDropAction,
       
   156                                               getModifiers(state, 0, 0), source_actions);
       
   157     if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   158         (*env)->ExceptionDescribe(env);
       
   159         (*env)->ExceptionClear(env);
       
   160         return java_awt_dnd_DnDConstants_ACTION_NONE;
       
   161     }
       
   162     return action;
       
   163 }
       
   164 
       
   165 static void
       
   166 ds_postDragSourceEvent(JNIEnv* env, int x, int y) {
       
   167     DECLARE_VOID_JAVA_METHOD(dscp_dragExit, dscp_clazz,
       
   168                              "dragExit", "(II)V");
       
   169 
       
   170     DASSERT(!JNU_IsNull(env, source_peer));
       
   171     if (JNU_IsNull(env, source_peer)) {
       
   172         return;
       
   173     }
       
   174 
       
   175     (*env)->CallVoidMethod(env, source_peer, dscp_dragExit, x, y);
       
   176 }
       
   177 
       
   178 static void
       
   179 ds_postDragSourceDropEvent(JNIEnv* env, jboolean success, jint targetAction,
       
   180                            int x, int y) {
       
   181     DECLARE_VOID_JAVA_METHOD(dscp_dragDropFinished, dscp_clazz,
       
   182                              "dragDropFinished", "(ZIII)V");
       
   183 
       
   184     DASSERT(!JNU_IsNull(env, source_peer));
       
   185     if (JNU_IsNull(env, source_peer)) {
       
   186         return;
       
   187     }
       
   188 
       
   189     (*env)->CallVoidMethod(env, source_peer, dscp_dragDropFinished,
       
   190                            success, targetAction, x, y);
       
   191 }
       
   192 
       
   193 /******************************************************************************/
       
   194 
       
   195 static void
       
   196 cancel_drag(XtPointer client_data, XtIntervalId* id) {
       
   197     Time time_stamp = awt_util_getCurrentServerTime();
       
   198 
       
   199     cleanup_drag(awt_display, time_stamp);
       
   200 }
       
   201 
       
   202 #define DONT_CARE -1
       
   203 
       
   204 static void
       
   205 awt_popupCallback(Widget shell, XtPointer closure, XtPointer call_data) {
       
   206     XtGrabKind grab_kind = XtGrabNone;
       
   207 
       
   208     if (call_data != NULL) {
       
   209         grab_kind = *((XtGrabKind*)call_data);
       
   210     }
       
   211 
       
   212     if (XmIsVendorShell(shell)) {
       
   213         int input_mode;
       
   214         XtVaGetValues(shell, XmNmwmInputMode, &input_mode, NULL);
       
   215         switch (input_mode) {
       
   216         case DONT_CARE:
       
   217         case MWM_INPUT_MODELESS:
       
   218             grab_kind = XtGrabNonexclusive; break;
       
   219         case MWM_INPUT_PRIMARY_APPLICATION_MODAL:
       
   220         case MWM_INPUT_SYSTEM_MODAL:
       
   221         case MWM_INPUT_FULL_APPLICATION_MODAL:
       
   222             grab_kind = XtGrabExclusive; break;
       
   223         }
       
   224     }
       
   225 
       
   226     if (grab_kind == XtGrabExclusive) {
       
   227         /*
       
   228          * We should cancel the drag on the toolkit thread. Otherwise, it can be
       
   229          * called while the toolkit thread is waiting inside some drag callback.
       
   230          * In this case Motif will crash when the drag callback returns.
       
   231          */
       
   232         XtAppAddTimeOut(awt_appContext, 0L, cancel_drag, NULL);
       
   233     }
       
   234 }
       
   235 
       
   236 static XtInitProc xt_shell_initialize = NULL;
       
   237 
       
   238 static void
       
   239 awt_ShellInitialize(Widget req, Widget new, ArgList args, Cardinal *num_args) {
       
   240     XtAddCallback(new, XtNpopupCallback, awt_popupCallback, NULL);
       
   241     (*xt_shell_initialize)(req, new, args, num_args);
       
   242 }
       
   243 
       
   244 /*
       
   245  * Fix for 4484572 (copied from awt_XmDnD.c).
       
   246  * Modify the 'initialize' routine for all ShellWidget instances, so that it
       
   247  * will install an XtNpopupCallback that cancels the current drag operation.
       
   248  * It is needed, since AWT doesn't have full control over all ShellWidget
       
   249  * instances (e.g. XmPopupMenu internally creates and popups an XmMenuShell).
       
   250  */
       
   251 static void
       
   252 awt_set_ShellInitialize() {
       
   253     static Boolean inited = False;
       
   254 
       
   255     DASSERT(!inited);
       
   256     if (inited) {
       
   257         return;
       
   258     }
       
   259 
       
   260     xt_shell_initialize = shellWidgetClass->core_class.initialize;
       
   261     shellWidgetClass->core_class.initialize = (XtInitProc)awt_ShellInitialize;
       
   262     inited = True;
       
   263 }
       
   264 
       
   265 /*
       
   266  * Returns True if initialization completes successfully.
       
   267  */
       
   268 Boolean
       
   269 awt_dnd_ds_init(Display* display) {
       
   270     if (XSaveContext(display, XA_XdndSelection, awt_convertDataContext,
       
   271                      (XPointer)NULL) == XCNOMEM) {
       
   272         return False;
       
   273     }
       
   274 
       
   275     if (XSaveContext(display, _XA_MOTIF_ATOM_0, awt_convertDataContext,
       
   276                      (XPointer)NULL) == XCNOMEM) {
       
   277         return False;
       
   278     }
       
   279 
       
   280     {
       
   281         char *ev = getenv("_JAVA_DRAG_SOURCE_POLICY");
       
   282 
       
   283         /* By default XDnD protocol is preferred. */
       
   284         drag_source_policy = DS_POLICY_PREFER_XDND;
       
   285 
       
   286         if (ev != NULL) {
       
   287             if (strcmp(ev, "PREFER_XDND") == 0) {
       
   288                 drag_source_policy = DS_POLICY_PREFER_XDND;
       
   289             } else if (strcmp(ev, "PREFER_MOTIF") == 0) {
       
   290                 drag_source_policy = DS_POLICY_PREFER_MOTIF;
       
   291             } else if (strcmp(ev, "ONLY_MOTIF") == 0) {
       
   292                 drag_source_policy = DS_POLICY_ONLY_MOTIF;
       
   293             } else if (strcmp(ev, "ONLY_XDND") == 0) {
       
   294                 drag_source_policy = DS_POLICY_ONLY_XDND;
       
   295             }
       
   296         }
       
   297     }
       
   298 
       
   299     awt_set_ShellInitialize();
       
   300 
       
   301     return True;
       
   302 }
       
   303 
       
   304 /*
       
   305  * Returns a handle of the window used as a drag source.
       
   306  */
       
   307 Window
       
   308 awt_dnd_ds_get_source_window() {
       
   309     return get_awt_root_window();
       
   310 }
       
   311 
       
   312 /*
       
   313  * Returns True if a drag operation initiated by this client
       
   314  * is still in progress.
       
   315  */
       
   316 Boolean
       
   317 awt_dnd_ds_in_progress() {
       
   318     return dnd_in_progress;
       
   319 }
       
   320 
       
   321 static void
       
   322 ds_send_event_to_target(XClientMessageEvent* xclient) {
       
   323     /* Shortcut if the source is in the same JVM. */
       
   324     if (XtWindowToWidget(xclient->display, target_proxy_window) != NULL) {
       
   325         awt_dnd_dt_process_event((XEvent*)xclient);
       
   326     } else {
       
   327         XSendEvent(xclient->display, target_proxy_window, False, NoEventMask,
       
   328                    (XEvent*)xclient);
       
   329     }
       
   330 }
       
   331 
       
   332 static void
       
   333 xdnd_send_enter(Display* dpy, Time time) {
       
   334     XClientMessageEvent enter;
       
   335 
       
   336     enter.display = dpy;
       
   337     enter.type = ClientMessage;
       
   338     enter.window = target_window;
       
   339     enter.format = 32;
       
   340     enter.message_type = XA_XdndEnter;
       
   341     enter.data.l[0] = awt_dnd_ds_get_source_window();
       
   342     enter.data.l[1] = target_protocol_version << XDND_PROTOCOL_SHIFT;
       
   343     enter.data.l[1] |= data_types_count > 3 ? XDND_DATA_TYPES_BIT : 0;
       
   344     enter.data.l[2] = data_types_count > 0 ? data_types[0] : None;
       
   345     enter.data.l[3] = data_types_count > 1 ? data_types[1] : None;
       
   346     enter.data.l[4] = data_types_count > 2 ? data_types[2] : None;
       
   347 
       
   348     ds_send_event_to_target(&enter);
       
   349 }
       
   350 
       
   351 static void
       
   352 motif_send_enter(Display* dpy, Time time) {
       
   353     XClientMessageEvent enter;
       
   354 
       
   355     enter.display = dpy;
       
   356     enter.type = ClientMessage;
       
   357     enter.window = target_window;
       
   358     enter.format = 8;
       
   359     enter.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE;
       
   360 
       
   361     {
       
   362         void* p = &enter.data.b[0];
       
   363         int flags = 0;
       
   364 
       
   365         flags |= java_to_motif_actions(source_action) << MOTIF_DND_ACTION_SHIFT;
       
   366         flags |= java_to_motif_actions(source_actions) << MOTIF_DND_ACTIONS_SHIFT;
       
   367 
       
   368         write_card8(&p, TOP_LEVEL_ENTER | MOTIF_MESSAGE_FROM_INITIATOR);
       
   369         write_card8(&p, MOTIF_BYTE_ORDER);
       
   370         write_card16(&p, flags);
       
   371         write_card32(&p, time);
       
   372         write_card32(&p, awt_dnd_ds_get_source_window());
       
   373         write_card32(&p, _XA_MOTIF_ATOM_0);
       
   374     }
       
   375 
       
   376     ds_send_event_to_target(&enter);
       
   377 }
       
   378 
       
   379 static void
       
   380 send_enter(Display* dpy, Time time) {
       
   381     switch (target_protocol) {
       
   382     case XDND_PROTOCOL:
       
   383         xdnd_send_enter(dpy, time);
       
   384         break;
       
   385     case MOTIF_DND_PROTOCOL:
       
   386         motif_send_enter(dpy, time);
       
   387         break;
       
   388     case NO_PROTOCOL:
       
   389     default:
       
   390         DTRACE_PRINTLN2("%s:%d send_enter: unknown DnD protocol.", __FILE__, __LINE__);
       
   391         break;
       
   392     }
       
   393 }
       
   394 
       
   395 static void
       
   396 xdnd_send_move(XMotionEvent* event) {
       
   397     XClientMessageEvent move;
       
   398 
       
   399     move.display = event->display;
       
   400     move.type = ClientMessage;
       
   401     move.window = target_window;
       
   402     move.format = 32;
       
   403     move.message_type = XA_XdndPosition;
       
   404     move.data.l[0] = awt_dnd_ds_get_source_window();
       
   405     move.data.l[1] = 0; /* flags */
       
   406     move.data.l[2] = event->x_root << 16 | event->y_root;
       
   407     move.data.l[3] = event->time;
       
   408     move.data.l[4] = java_to_xdnd_action(source_action);
       
   409 
       
   410     ds_send_event_to_target(&move);
       
   411 }
       
   412 
       
   413 static void
       
   414 motif_send_move(XMotionEvent* event) {
       
   415     XClientMessageEvent move;
       
   416 
       
   417     move.display = event->display;
       
   418     move.type = ClientMessage;
       
   419     move.window = target_window;
       
   420     move.format = 8;
       
   421     move.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE;
       
   422 
       
   423     {
       
   424         void* p = move.data.b;
       
   425         int flags = 0;
       
   426 
       
   427         flags |= java_to_motif_actions(source_action) << MOTIF_DND_ACTION_SHIFT;
       
   428         flags |= java_to_motif_actions(source_actions) << MOTIF_DND_ACTIONS_SHIFT;
       
   429 
       
   430         write_card8(&p, DRAG_MOTION | MOTIF_MESSAGE_FROM_INITIATOR);
       
   431         write_card8(&p, MOTIF_BYTE_ORDER);
       
   432         write_card16(&p, flags);
       
   433         write_card32(&p, event->time);
       
   434         write_card16(&p, event->x_root);
       
   435         write_card16(&p, event->y_root);
       
   436     }
       
   437 
       
   438     ds_send_event_to_target(&move);
       
   439 }
       
   440 
       
   441 static void
       
   442 send_move(XMotionEvent* event) {
       
   443     switch (target_protocol) {
       
   444     case XDND_PROTOCOL:
       
   445         xdnd_send_move(event);
       
   446         break;
       
   447     case MOTIF_DND_PROTOCOL:
       
   448         motif_send_move(event);
       
   449         break;
       
   450     case NO_PROTOCOL:
       
   451     default:
       
   452         DTRACE_PRINTLN2("%s:%d send_move: unknown DnD protocol.", __FILE__, __LINE__);
       
   453         break;
       
   454     }
       
   455 }
       
   456 
       
   457 static void
       
   458 xdnd_send_leave(Display* dpy, Time time) {
       
   459     XClientMessageEvent leave;
       
   460 
       
   461     leave.display = dpy;
       
   462     leave.type = ClientMessage;
       
   463     leave.window = target_window;
       
   464     leave.format = 32;
       
   465     leave.message_type = XA_XdndLeave;
       
   466     leave.data.l[0] = awt_dnd_ds_get_source_window();
       
   467     leave.data.l[1] = 0;
       
   468     leave.data.l[2] = 0;
       
   469     leave.data.l[3] = 0;
       
   470     leave.data.l[4] = 0;
       
   471 
       
   472     ds_send_event_to_target(&leave);
       
   473 }
       
   474 
       
   475 static void
       
   476 motif_send_leave(Display* dpy, Time time) {
       
   477     XClientMessageEvent leave;
       
   478 
       
   479     leave.display = dpy;
       
   480     leave.type = ClientMessage;
       
   481     leave.window = target_window;
       
   482     leave.format = 8;
       
   483     leave.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE;
       
   484 
       
   485     {
       
   486         void* p = &leave.data.b[0];
       
   487 
       
   488         write_card8(&p, TOP_LEVEL_LEAVE | MOTIF_MESSAGE_FROM_INITIATOR);
       
   489         write_card8(&p, MOTIF_BYTE_ORDER);
       
   490         write_card16(&p, 0);
       
   491         write_card32(&p, time);
       
   492         write_card32(&p, awt_dnd_ds_get_source_window());
       
   493     }
       
   494 
       
   495     ds_send_event_to_target(&leave);
       
   496 }
       
   497 
       
   498 static void
       
   499 send_leave(Display* dpy, Time time) {
       
   500     switch (target_protocol) {
       
   501     case XDND_PROTOCOL:
       
   502         xdnd_send_leave(dpy, time);
       
   503         break;
       
   504     case MOTIF_DND_PROTOCOL:
       
   505         motif_send_leave(dpy, time);
       
   506         break;
       
   507     case NO_PROTOCOL:
       
   508     default:
       
   509         DTRACE_PRINTLN2("%s:%d send_leave: unknown DnD protocol.", __FILE__, __LINE__);
       
   510         break;
       
   511     }
       
   512 }
       
   513 
       
   514 
       
   515 static void
       
   516 xdnd_send_drop(XButtonEvent* event) {
       
   517     XClientMessageEvent drop;
       
   518 
       
   519     drop.display = event->display;
       
   520     drop.type = ClientMessage;
       
   521     drop.window = target_window;
       
   522     drop.format = 32;
       
   523     drop.message_type = XA_XdndDrop;
       
   524     drop.data.l[0] = awt_dnd_ds_get_source_window();
       
   525     drop.data.l[1] = 0; /* flags */
       
   526     drop.data.l[2] = event->time; /* ### */
       
   527     drop.data.l[3] = 0;
       
   528     drop.data.l[4] = 0;
       
   529 
       
   530     ds_send_event_to_target(&drop);
       
   531 }
       
   532 
       
   533 static void
       
   534 motif_send_drop(XButtonEvent* event) {
       
   535     XClientMessageEvent drop;
       
   536 
       
   537     /*
       
   538      * Motif drop sites expect TOP_LEVEL_LEAVE before DROP_START.
       
   539      */
       
   540     motif_send_leave(event->display, event->time);
       
   541 
       
   542     drop.display = event->display;
       
   543     drop.type = ClientMessage;
       
   544     drop.window = target_window;
       
   545     drop.format = 8;
       
   546     drop.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE;
       
   547 
       
   548     {
       
   549         void* p = &drop.data.b[0];
       
   550         int flags = 0;
       
   551 
       
   552         flags |= java_to_motif_actions(source_action) << MOTIF_DND_ACTION_SHIFT;
       
   553         flags |= java_to_motif_actions(source_actions) << MOTIF_DND_ACTIONS_SHIFT;
       
   554 
       
   555         write_card8(&p, DROP_START | MOTIF_MESSAGE_FROM_INITIATOR);
       
   556         write_card8(&p, MOTIF_BYTE_ORDER);
       
   557         write_card16(&p, flags);
       
   558         write_card32(&p, event->time);
       
   559         write_card16(&p, event->x_root);
       
   560         write_card16(&p, event->y_root);
       
   561         write_card32(&p, _XA_MOTIF_ATOM_0);
       
   562         write_card32(&p, awt_dnd_ds_get_source_window());
       
   563     }
       
   564 
       
   565     ds_send_event_to_target(&drop);
       
   566 }
       
   567 
       
   568 static void
       
   569 send_drop(XButtonEvent* event) {
       
   570     switch (target_protocol) {
       
   571     case XDND_PROTOCOL:
       
   572         xdnd_send_drop(event);
       
   573         break;
       
   574     case MOTIF_DND_PROTOCOL:
       
   575         motif_send_drop(event);
       
   576         break;
       
   577     case NO_PROTOCOL:
       
   578     default:
       
   579         DTRACE_PRINTLN2("%s:%d send_drop: unknown DnD protocol.", __FILE__, __LINE__);
       
   580         break;
       
   581     }
       
   582 }
       
   583 
       
   584 static void
       
   585 remove_dnd_grab(Display* dpy, Time time) {
       
   586     XUngrabPointer(dpy, time);
       
   587     XUngrabKeyboard(dpy, time);
       
   588 
       
   589     /* Restore the root event mask if it was changed. */
       
   590     if ((your_root_event_mask | ROOT_EVENT_MASK) != your_root_event_mask &&
       
   591         drag_root_window != None) {
       
   592 
       
   593         XSelectInput(dpy, drag_root_window, your_root_event_mask);
       
   594 
       
   595         drag_root_window = None;
       
   596         your_root_event_mask = NoEventMask;
       
   597     }
       
   598 }
       
   599 
       
   600 static void
       
   601 cleanup_target_info(Display* dpy) {
       
   602     target_root_subwindow = None;
       
   603 
       
   604     target_window = None;
       
   605     target_proxy_window = None;
       
   606     target_protocol = NO_PROTOCOL;
       
   607     target_protocol_version = 0;
       
   608     target_enter_server_time = CurrentTime;
       
   609     target_action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
   610 }
       
   611 
       
   612 static void
       
   613 cleanup_drag(Display* dpy, Time time) {
       
   614     JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
   615 
       
   616     if (dnd_in_progress) {
       
   617         if (target_window != None) {
       
   618             send_leave(dpy, time);
       
   619         }
       
   620 
       
   621         if (target_action != java_awt_dnd_DnDConstants_ACTION_NONE) {
       
   622             JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
   623             ds_postDragSourceEvent(env, x_root, y_root);
       
   624         }
       
   625 
       
   626         ds_postDragSourceDropEvent(env, JNI_FALSE,
       
   627                                    java_awt_dnd_DnDConstants_ACTION_NONE,
       
   628                                    x_root, y_root);
       
   629     }
       
   630 
       
   631     /* Cleanup the global state */
       
   632     dnd_in_progress = False;
       
   633     drag_in_progress = False;
       
   634     data_types_count = 0;
       
   635     if (data_types != NULL) {
       
   636         free(data_types);
       
   637         data_types = NULL;
       
   638     }
       
   639     if (!JNU_IsNull(env, source_peer)) {
       
   640         (*env)->DeleteGlobalRef(env, source_peer);
       
   641         source_peer = NULL;
       
   642     }
       
   643 
       
   644     cleanup_target_info(dpy);
       
   645 
       
   646     remove_dnd_grab(dpy, time);
       
   647 
       
   648     XDeleteProperty(awt_display, awt_dnd_ds_get_source_window(), _XA_MOTIF_ATOM_0);
       
   649     XDeleteProperty(awt_display, awt_dnd_ds_get_source_window(), XA_XdndTypeList);
       
   650     XDeleteProperty(awt_display, awt_dnd_ds_get_source_window(), XA_XdndActionList);
       
   651     XtDisownSelection(awt_root_shell, _XA_MOTIF_ATOM_0, time);
       
   652     XtDisownSelection(awt_root_shell, XA_XdndSelection, time);
       
   653 
       
   654     awt_cleanupConvertDataContext(env, _XA_MOTIF_ATOM_0);
       
   655     awt_cleanupConvertDataContext(env, XA_XdndSelection);
       
   656 }
       
   657 
       
   658 static void
       
   659 process_drop(XButtonEvent* event) {
       
   660     unsigned char ret;
       
   661     XWindowAttributes xwa;
       
   662 
       
   663     DASSERT(target_window != None);
       
   664 
       
   665     XGetWindowAttributes(event->display, target_window, &xwa);
       
   666 
       
   667     target_window_mask = xwa.your_event_mask;
       
   668 
       
   669     /* Select for DestoyNotify to cleanup if the target crashes. */
       
   670     ret = checked_XSelectInput(event->display, target_window,
       
   671                                (target_window_mask | StructureNotifyMask));
       
   672 
       
   673     if (ret == Success) {
       
   674         send_drop(event);
       
   675     } else {
       
   676         DTRACE_PRINTLN2("%s:%d drop rejected - invalid window.",
       
   677                         __FILE__, __LINE__);
       
   678         cleanup_drag(event->display, event->time);
       
   679     }
       
   680 }
       
   681 
       
   682 static Window
       
   683 find_client_window(Display* dpy, Window window) {
       
   684     Window root, parent, *children;
       
   685     unsigned int nchildren, idx;
       
   686 
       
   687     Atom           type;
       
   688     int            format;
       
   689     unsigned long  nitems;
       
   690     unsigned long  after;
       
   691     unsigned char  *data;
       
   692     Status ret;
       
   693 
       
   694     if (XGetWindowProperty(dpy, window, XA_WM_STATE, 0, 0, False,
       
   695                            AnyPropertyType, &type, &format, &nitems,
       
   696                            &after, &data) == Success) {
       
   697         XFree(data);
       
   698     }
       
   699 
       
   700     if (type != None) {
       
   701         return window;
       
   702     }
       
   703 
       
   704     if (!XQueryTree(dpy, window, &root, &parent, &children, &nchildren)) {
       
   705         return None;
       
   706     }
       
   707 
       
   708     if (children == NULL) {
       
   709         return None;
       
   710     }
       
   711 
       
   712     for (idx = 0; idx < nchildren; idx++) {
       
   713         Window win = find_client_window(dpy, children[idx]);
       
   714         if (win != None) {
       
   715             XFree(children);
       
   716             return win;
       
   717         }
       
   718     }
       
   719 
       
   720     XFree(children);
       
   721     return None;
       
   722 }
       
   723 
       
   724 static void
       
   725 do_update_target_window(Display* dpy, Window subwindow, Time time) {
       
   726     Window client_window = None;
       
   727     Window proxy_window = None;
       
   728     Protocol protocol = NO_PROTOCOL;
       
   729     unsigned int protocol_version = 0;
       
   730     Boolean is_receiver = False;
       
   731 
       
   732     client_window = find_client_window(dpy, subwindow);
       
   733 
       
   734     if (client_window != None) {
       
   735         /* Request status */
       
   736         int            status;
       
   737 
       
   738         /* Returns of XGetWindowProperty */
       
   739         Atom           type;
       
   740         int            format;
       
   741         unsigned long  nitems;
       
   742         unsigned long  after;
       
   743         unsigned char  *data;
       
   744 
       
   745         /*
       
   746          * No need for checked_XGetWindowProperty, since we check the returned
       
   747          * property type anyway.
       
   748          */
       
   749         if (drag_source_policy != DS_POLICY_ONLY_XDND) {
       
   750 
       
   751             data = NULL;
       
   752             status = XGetWindowProperty(dpy, client_window,
       
   753                                         _XA_MOTIF_DRAG_RECEIVER_INFO,
       
   754                                         0, 0xFFFF, False, AnyPropertyType,
       
   755                                         &type, &format, &nitems, &after, &data);
       
   756 
       
   757             if (status == Success && data != NULL && type != None && format == 8
       
   758                 && nitems >= MOTIF_RECEIVER_INFO_SIZE) {
       
   759                 unsigned char byte_order = read_card8((char*)data, 0);
       
   760                 unsigned char drag_protocol_style = read_card8((char*)data, 2);
       
   761 
       
   762                 switch (drag_protocol_style) {
       
   763                 case MOTIF_PREFER_PREREGISTER_STYLE :
       
   764                 case MOTIF_PREFER_DYNAMIC_STYLE :
       
   765                 case MOTIF_DYNAMIC_STYLE :
       
   766                 case MOTIF_PREFER_RECEIVER_STYLE :
       
   767                     proxy_window = read_card32((char*)data, 4, byte_order);
       
   768                     protocol = MOTIF_DND_PROTOCOL;
       
   769                     protocol_version = read_card8((char*)data, 1);
       
   770                     is_receiver = True;
       
   771                     break;
       
   772                 default:
       
   773                     DTRACE_PRINTLN3("%s:%d unsupported protocol style (%d).",
       
   774                                     __FILE__, __LINE__, (int)drag_protocol_style);
       
   775                 }
       
   776             }
       
   777 
       
   778             if (status == Success) {
       
   779                 XFree(data);
       
   780                 data = NULL;
       
   781             }
       
   782         }
       
   783 
       
   784         if (drag_source_policy != DS_POLICY_ONLY_MOTIF &&
       
   785             (drag_source_policy != DS_POLICY_PREFER_MOTIF || !is_receiver)) {
       
   786 
       
   787             data = NULL;
       
   788             status = XGetWindowProperty(dpy, client_window, XA_XdndAware, 0, 1,
       
   789                                         False, AnyPropertyType, &type, &format,
       
   790                                         &nitems, &after, &data);
       
   791 
       
   792             if (status == Success && data != NULL && type == XA_ATOM) {
       
   793                 unsigned int target_version = *((unsigned int*)data);
       
   794 
       
   795                 if (target_version >= XDND_MIN_PROTOCOL_VERSION) {
       
   796                     proxy_window = None;
       
   797                     protocol = XDND_PROTOCOL;
       
   798                     protocol_version = target_version < XDND_PROTOCOL_VERSION ?
       
   799                         target_version : XDND_PROTOCOL_VERSION;
       
   800                     is_receiver = True;
       
   801                 }
       
   802             }
       
   803 
       
   804             /* Retrieve the proxy window handle and check if it is valid. */
       
   805             if (protocol == XDND_PROTOCOL) {
       
   806                 if (status == Success) {
       
   807                     XFree(data);
       
   808                 }
       
   809 
       
   810                 data = NULL;
       
   811                 status = XGetWindowProperty(dpy, client_window, XA_XdndProxy, 0,
       
   812                                             1, False, XA_WINDOW, &type, &format,
       
   813                                             &nitems, &after, &data);
       
   814 
       
   815                 if (status == Success && data != NULL && type == XA_WINDOW) {
       
   816                     proxy_window = *((Window*)data);
       
   817                 }
       
   818 
       
   819                 if (proxy_window != None) {
       
   820                     if (status == Success) {
       
   821                         XFree(data);
       
   822                     }
       
   823 
       
   824                     data = NULL;
       
   825                     status = XGetWindowProperty(dpy, proxy_window, XA_XdndProxy,
       
   826                                                 0, 1, False, XA_WINDOW, &type,
       
   827                                                 &format, &nitems, &after, &data);
       
   828 
       
   829                     if (status != Success || data == NULL || type != XA_WINDOW ||
       
   830                         *((Window*)data) != proxy_window) {
       
   831                         proxy_window = None;
       
   832                     } else {
       
   833                         if (status == Success) {
       
   834                             XFree(data);
       
   835                         }
       
   836 
       
   837                         data = NULL;
       
   838                         status = XGetWindowProperty(dpy, proxy_window,
       
   839                                                     XA_XdndAware,  0, 1, False,
       
   840                                                     AnyPropertyType, &type,
       
   841                                                     &format, &nitems, &after,
       
   842                                                     &data);
       
   843 
       
   844                         if (status != Success || data == NULL || type != XA_ATOM) {
       
   845                             proxy_window = None;
       
   846                         }
       
   847                     }
       
   848                 }
       
   849             }
       
   850 
       
   851             XFree(data);
       
   852         }
       
   853 
       
   854         if (proxy_window == None) {
       
   855             proxy_window = client_window;
       
   856         }
       
   857     }
       
   858 
       
   859     if (is_receiver) {
       
   860         target_window = client_window;
       
   861         target_proxy_window = proxy_window;
       
   862         target_protocol = protocol;
       
   863         target_protocol_version = protocol_version;
       
   864     } else {
       
   865         target_window = None;
       
   866         target_proxy_window = None;
       
   867         target_protocol = NO_PROTOCOL;
       
   868         target_protocol_version = 0;
       
   869     }
       
   870 
       
   871     target_action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
   872 
       
   873     if (target_window != None) {
       
   874         target_enter_server_time = time;
       
   875     } else {
       
   876         target_enter_server_time = CurrentTime;
       
   877     }
       
   878 
       
   879     target_root_subwindow = subwindow;
       
   880 }
       
   881 
       
   882 static void
       
   883 update_target_window(XMotionEvent* event) {
       
   884     Display* dpy = event->display;
       
   885     int x = event->x_root;
       
   886     int y = event->x_root;
       
   887     Time time = event->time;
       
   888     Window subwindow = event->subwindow;
       
   889 
       
   890     /*
       
   891      * If this event had occurred before the pointer was grabbed,
       
   892      * query the server for the current root subwindow.
       
   893      */
       
   894     if (event->window != event->root) {
       
   895         int xw, yw, xr, yr;
       
   896         unsigned int modifiers;
       
   897         XQueryPointer(dpy, event->root, &event->root, &subwindow,
       
   898                       &xr, &yr, &xw, &yw, &modifiers);
       
   899     }
       
   900 
       
   901     if (target_root_subwindow != subwindow) {
       
   902         if (target_window != None) {
       
   903             send_leave(dpy, time);
       
   904 
       
   905             /*
       
   906              * Neither Motif DnD nor XDnD provide a mean for the target
       
   907              * to notify the source that the pointer exits the drop site
       
   908              * that occupies the whole top level.
       
   909              * We detect this situation and post dragExit.
       
   910              */
       
   911             if (target_action != java_awt_dnd_DnDConstants_ACTION_NONE) {
       
   912                 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
   913                 ds_postDragSourceEvent(env, x, y);
       
   914             }
       
   915         }
       
   916 
       
   917         /* Update the global state. */
       
   918         do_update_target_window(dpy, subwindow, time);
       
   919 
       
   920         if (target_window != None) {
       
   921             send_enter(dpy, time);
       
   922         }
       
   923     }
       
   924 }
       
   925 
       
   926 /*
       
   927  * Updates the source action based on the specified event state.
       
   928  * Returns True if source action changed, False otherwise.
       
   929  */
       
   930 static Boolean
       
   931 update_source_action(unsigned int state) {
       
   932     JNIEnv* env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
   933     jint action = ds_convertModifiersToDropAction(env, state);
       
   934     if (source_action == action) {
       
   935         return False;
       
   936     }
       
   937     source_action = action;
       
   938     return True;
       
   939 }
       
   940 
       
   941 static void
       
   942 handle_mouse_move(XMotionEvent* event) {
       
   943     if (!drag_in_progress) {
       
   944         return;
       
   945     }
       
   946 
       
   947     if (x_root != event->x_root || y_root != event->y_root) {
       
   948         JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
   949         ds_postDragSourceDragEvent(env, target_action, event->state,
       
   950                                    event->x_root, event->y_root,
       
   951                                    sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_MOUSE_MOVED);
       
   952 
       
   953         x_root = event->x_root;
       
   954         y_root = event->y_root;
       
   955     }
       
   956 
       
   957     if (event_state != event->state) {
       
   958         if (update_source_action(event->state) && target_window != None) {
       
   959             JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
   960             ds_postDragSourceDragEvent(env, target_action, event->state,
       
   961                                        event->x_root, event->y_root,
       
   962                                        sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_CHANGED);
       
   963         }
       
   964         event_state = event->state;
       
   965     }
       
   966 
       
   967     update_target_window(event);
       
   968 
       
   969     if (target_window != None) {
       
   970         send_move(event);
       
   971     }
       
   972 }
       
   973 
       
   974 static Boolean
       
   975 handle_xdnd_status(XClientMessageEvent* event) {
       
   976     JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
   977     long* event_data = event->data.l;
       
   978     Window target_win = None;
       
   979     jint action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
   980 
       
   981     DTRACE_PRINTLN4("%s:%d XdndStatus target_window=%ld target_protocol=%d.",
       
   982                     __FILE__, __LINE__, target_window, target_protocol);
       
   983 
       
   984     if (target_protocol != XDND_PROTOCOL) {
       
   985         DTRACE_PRINTLN2("%s:%d XdndStatus rejected - invalid state.",
       
   986                         __FILE__, __LINE__);
       
   987         return True;
       
   988     }
       
   989 
       
   990     target_win = event_data[0];
       
   991 
       
   992     /* Ignore XDnD messages from all other windows. */
       
   993     if (target_window != target_win) {
       
   994         DTRACE_PRINTLN4("%s:%d XdndStatus rejected - invalid target window cur=%ld this=%ld.",
       
   995                         __FILE__, __LINE__, target_window, target_win);
       
   996         return True;
       
   997     }
       
   998 
       
   999     if (event_data[1] & XDND_ACCEPT_DROP_FLAG) {
       
  1000         /* This feature is new in XDnD version 2, but we can use it as XDnD
       
  1001            compliance only requires supporting version 3 and up. */
       
  1002         action = xdnd_to_java_action(event_data[4]);
       
  1003     }
       
  1004 
       
  1005     if (action == java_awt_dnd_DnDConstants_ACTION_NONE &&
       
  1006         target_action != java_awt_dnd_DnDConstants_ACTION_NONE) {
       
  1007         ds_postDragSourceEvent(env, x_root, y_root);
       
  1008     } else if (action != java_awt_dnd_DnDConstants_ACTION_NONE) {
       
  1009         jint type = 0;
       
  1010 
       
  1011         if (target_action == java_awt_dnd_DnDConstants_ACTION_NONE) {
       
  1012             type = sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_ENTER;
       
  1013         } else {
       
  1014             type = sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_MOTION;
       
  1015         }
       
  1016 
       
  1017         ds_postDragSourceDragEvent(env, action, event_state,
       
  1018                                    x_root, y_root, type);
       
  1019     }
       
  1020 
       
  1021     target_action = action;
       
  1022 
       
  1023     return True;
       
  1024 }
       
  1025 
       
  1026 static Boolean
       
  1027 handle_xdnd_finished(XClientMessageEvent* event) {
       
  1028     JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
  1029     long* event_data = event->data.l;
       
  1030     Window target_win = None;
       
  1031     jboolean success = JNI_TRUE;
       
  1032     jint action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
  1033 
       
  1034     if (target_protocol != XDND_PROTOCOL) {
       
  1035         DTRACE_PRINTLN2("%s:%d XdndStatus rejected - invalid state.",
       
  1036                         __FILE__, __LINE__);
       
  1037         return True;
       
  1038     }
       
  1039 
       
  1040     target_win = event_data[0];
       
  1041 
       
  1042     /* Ignore XDnD messages from all other windows. */
       
  1043     if (target_window != target_win) {
       
  1044         DTRACE_PRINTLN4("%s:%d XdndStatus rejected - invalid target window cur=%ld this=%ld.",
       
  1045                         __FILE__, __LINE__, target_window, target_win);
       
  1046         return True;
       
  1047     }
       
  1048 
       
  1049     if (target_protocol_version >= 5) {
       
  1050         success = (event_data[1] & XDND_ACCEPT_DROP_FLAG) != 0 ?
       
  1051             JNI_TRUE : JNI_FALSE;
       
  1052         action = xdnd_to_java_action(event_data[2]);
       
  1053     } else {
       
  1054         /* Assume that the drop was successful and the performed drop action is
       
  1055            the drop action accepted with the latest XdndStatus message. */
       
  1056         success = JNI_TRUE;
       
  1057         action = target_action;
       
  1058     }
       
  1059 
       
  1060     ds_postDragSourceDropEvent(env, success, action, x_root, y_root);
       
  1061 
       
  1062     dnd_in_progress = False;
       
  1063 
       
  1064     XSelectInput(event->display, target_win, target_window_mask);
       
  1065 
       
  1066     cleanup_drag(event->display, CurrentTime);
       
  1067 
       
  1068     return True;
       
  1069 }
       
  1070 
       
  1071 static Boolean
       
  1072 handle_motif_client_message(XClientMessageEvent* event) {
       
  1073     JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
  1074     int reason = (int)(event->data.b[0] & MOTIF_MESSAGE_REASON_MASK);
       
  1075     int origin = (int)(event->data.b[0] & MOTIF_MESSAGE_SENDER_MASK);
       
  1076     unsigned char byte_order = event->data.b[1];
       
  1077     jint action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
  1078     Time time = CurrentTime;
       
  1079     int x = 0, y = 0;
       
  1080 
       
  1081     /* Only receiver messages should be handled. */
       
  1082     if (origin != MOTIF_MESSAGE_FROM_RECEIVER) {
       
  1083         return False;
       
  1084     }
       
  1085 
       
  1086     if (target_protocol != MOTIF_DND_PROTOCOL) {
       
  1087         DTRACE_PRINTLN2("%s:%d _MOTIF_DRAG_AND_DROP_MESSAGE rejected - invalid state.",
       
  1088                         __FILE__, __LINE__);
       
  1089         return True;
       
  1090     }
       
  1091 
       
  1092     switch (reason) {
       
  1093     case DROP_SITE_ENTER:
       
  1094     case DROP_SITE_LEAVE:
       
  1095     case DRAG_MOTION:
       
  1096     case OPERATION_CHANGED:
       
  1097         break;
       
  1098     default:
       
  1099         return False;
       
  1100     }
       
  1101 
       
  1102     time = read_card32(event->data.b, 4, byte_order);
       
  1103 
       
  1104     /* Discard events from the previous receiver. */
       
  1105     if (target_enter_server_time == CurrentTime ||
       
  1106         time < target_enter_server_time) {
       
  1107         DTRACE_PRINTLN2("%s:%d _MOTIF_DRAG_AND_DROP_MESSAGE rejected - invalid time.",
       
  1108                         __FILE__, __LINE__);
       
  1109         return True;
       
  1110     }
       
  1111 
       
  1112     if (reason != DROP_SITE_LEAVE) {
       
  1113         CARD16 flags = read_card16(event->data.b, 2, byte_order);
       
  1114         unsigned char status = (flags & MOTIF_DND_STATUS_MASK) >>
       
  1115             MOTIF_DND_STATUS_SHIFT;
       
  1116         unsigned char motif_action = (flags & MOTIF_DND_ACTION_MASK) >>
       
  1117             MOTIF_DND_ACTION_SHIFT;
       
  1118 
       
  1119         if (status == MOTIF_VALID_DROP_SITE) {
       
  1120             action = motif_to_java_actions(motif_action);
       
  1121         } else {
       
  1122             action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
  1123         }
       
  1124 
       
  1125         x = read_card16(event->data.b, 8, byte_order);
       
  1126         y = read_card16(event->data.b, 10, byte_order);
       
  1127     }
       
  1128 
       
  1129     /*
       
  1130      * We should derive the type of java event to post not from the message
       
  1131      * reason, but from the combination of the current and previous target
       
  1132      * actions:
       
  1133      * Even if the reason is DROP_SITE_LEAVE we shouldn't post dragExit
       
  1134      * if the drag was rejected earlier.
       
  1135      * Even if the reason is DROP_SITE_ENTER we shouldn't post dragEnter
       
  1136      * if the drag is not accepted.
       
  1137      */
       
  1138     if (target_action != java_awt_dnd_DnDConstants_ACTION_NONE &&
       
  1139         action == java_awt_dnd_DnDConstants_ACTION_NONE) {
       
  1140 
       
  1141         ds_postDragSourceEvent(env, x, y);
       
  1142     } else if (action != java_awt_dnd_DnDConstants_ACTION_NONE) {
       
  1143         jint type = 0;
       
  1144 
       
  1145         if (target_action == java_awt_dnd_DnDConstants_ACTION_NONE) {
       
  1146             type = sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_ENTER;
       
  1147         } else {
       
  1148             type = sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_MOTION;
       
  1149         }
       
  1150 
       
  1151         ds_postDragSourceDragEvent(env, action, event_state, x, y, type);
       
  1152     }
       
  1153 
       
  1154     target_action = action;
       
  1155 
       
  1156     return True;
       
  1157 }
       
  1158 
       
  1159 /*
       
  1160  * Handles client messages.
       
  1161  * Returns True if the event is processed, False otherwise.
       
  1162  */
       
  1163 static Boolean
       
  1164 handle_client_message(XClientMessageEvent* event) {
       
  1165     if (event->message_type == XA_XdndStatus) {
       
  1166         return handle_xdnd_status(event);
       
  1167     } else if (event->message_type == XA_XdndFinished) {
       
  1168         return handle_xdnd_finished(event);
       
  1169     } else if (event->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) {
       
  1170         return handle_motif_client_message(event);
       
  1171     }
       
  1172     return False;
       
  1173 }
       
  1174 
       
  1175 /*
       
  1176  * Similar to XtLastTimestampProcessed(). We cannot use Xt time stamp, as it is
       
  1177  * updated in XtDispatchEvent that may not be called if a java event is
       
  1178  * consumed. This can make Xt time stamp out-of-date and cause XGrab* failures
       
  1179  * with GrabInvalidTime reason.
       
  1180  */
       
  1181 static Time
       
  1182 get_latest_time_stamp() {
       
  1183     return latest_time_stamp;
       
  1184 }
       
  1185 
       
  1186 static void
       
  1187 update_latest_time_stamp(XEvent* event) {
       
  1188     Time time = latest_time_stamp;
       
  1189 
       
  1190     switch (event->type) {
       
  1191     case KeyPress:
       
  1192     case KeyRelease:     time = event->xkey.time;            break;
       
  1193     case ButtonPress:
       
  1194     case ButtonRelease:  time = event->xbutton.time;         break;
       
  1195     case MotionNotify:   time = event->xmotion.time;         break;
       
  1196     case EnterNotify:
       
  1197     case LeaveNotify:    time = event->xcrossing.time;       break;
       
  1198     case PropertyNotify: time = event->xproperty.time;       break;
       
  1199     case SelectionClear: time = event->xselectionclear.time; break;
       
  1200     }
       
  1201 
       
  1202     latest_time_stamp = time;
       
  1203 }
       
  1204 
       
  1205 Boolean
       
  1206 awt_dnd_ds_process_event(XEvent* event) {
       
  1207     Display* dpy = event->xany.display;
       
  1208 
       
  1209     update_latest_time_stamp(event);
       
  1210 
       
  1211     if (process_proxy_mode_event(event)) {
       
  1212         return True;
       
  1213     }
       
  1214 
       
  1215     if (!dnd_in_progress) {
       
  1216         return False;
       
  1217     }
       
  1218 
       
  1219     /* Process drag and drop messages. */
       
  1220     switch (event->type) {
       
  1221     case ClientMessage:
       
  1222         return handle_client_message(&event->xclient);
       
  1223     case DestroyNotify:
       
  1224         /* Target crashed during drop processing - cleanup. */
       
  1225         if (!drag_in_progress &&
       
  1226             event->xdestroywindow.window == target_window) {
       
  1227             cleanup_drag(dpy, CurrentTime);
       
  1228             return True;
       
  1229         }
       
  1230         /* Pass along */
       
  1231         return False;
       
  1232     }
       
  1233 
       
  1234     if (!drag_in_progress) {
       
  1235         return False;
       
  1236     }
       
  1237 
       
  1238     /* Process drag-only messages. */
       
  1239     switch (event->type) {
       
  1240     case KeyRelease:
       
  1241     case KeyPress: {
       
  1242         KeySym keysym = XKeycodeToKeysym(dpy, event->xkey.keycode, 0);
       
  1243         switch (keysym) {
       
  1244         case XK_Escape: {
       
  1245             if (keysym == XK_Escape) {
       
  1246                 remove_dnd_grab(dpy, event->xkey.time);
       
  1247                 cleanup_drag(dpy, event->xkey.time);
       
  1248             }
       
  1249             break;
       
  1250         }
       
  1251         case XK_Control_R:
       
  1252         case XK_Control_L:
       
  1253         case XK_Shift_R:
       
  1254         case XK_Shift_L: {
       
  1255             Window subwindow;
       
  1256             int xw, yw, xr, yr;
       
  1257             unsigned int modifiers;
       
  1258             XQueryPointer(event->xkey.display, event->xkey.root, &event->xkey.root, &subwindow,
       
  1259                           &xr, &yr, &xw, &yw, &modifiers);
       
  1260             event->xkey.state = modifiers;
       
  1261             //It's safe to use key event as motion event since we use only their common fields.
       
  1262             handle_mouse_move(&event->xmotion);
       
  1263             break;
       
  1264         }
       
  1265         }
       
  1266         return True;
       
  1267     }
       
  1268     case ButtonPress:
       
  1269         return True;
       
  1270     case MotionNotify:
       
  1271         handle_mouse_move(&event->xmotion);
       
  1272         return True;
       
  1273     case ButtonRelease:
       
  1274         /*
       
  1275          * On some X servers it could happen that ButtonRelease coordinates
       
  1276          * differ from the latest MotionNotify coordinates, so we need to
       
  1277          * process it as a mouse motion.
       
  1278          * MotionNotify differs from ButtonRelease only in is_hint member, but
       
  1279          * we never use it, so it is safe to cast to MotionNotify.
       
  1280          */
       
  1281         handle_mouse_move(&event->xmotion);
       
  1282         if (event->xbutton.button == Button1 || event->xbutton.button == Button2) {
       
  1283             // drag is initiated with Button1 or Button2 pressed and
       
  1284             // ended on release of either of these buttons (as the same
       
  1285             // behavior was with our old Motif DnD-based implementation)
       
  1286             remove_dnd_grab(dpy, event->xbutton.time);
       
  1287             drag_in_progress = False;
       
  1288             if (target_window != None && target_action != java_awt_dnd_DnDConstants_ACTION_NONE) {
       
  1289                 /*
       
  1290                  * ACTION_NONE indicates that either the drop target rejects the
       
  1291                  * drop or it haven't responded yet. The latter could happen in
       
  1292                  * case of fast drag, slow target-server connection or slow
       
  1293                  * drag notifications processing on the target side.
       
  1294                  */
       
  1295                 process_drop(&event->xbutton);
       
  1296             } else {
       
  1297                 cleanup_drag(dpy, event->xbutton.time);
       
  1298             }
       
  1299         }
       
  1300         return True;
       
  1301     default:
       
  1302         return False;
       
  1303     }
       
  1304 }
       
  1305 
       
  1306 static Boolean
       
  1307 motif_convert_proc(Widget w, Atom* selection, Atom* target, Atom* type,
       
  1308                    XtPointer* value, unsigned long* length, int32_t* format) {
       
  1309 
       
  1310     if (*target == XA_XmTRANSFER_SUCCESS ||
       
  1311         *target == XA_XmTRANSFER_FAILURE) {
       
  1312 
       
  1313         JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
  1314         jboolean success =
       
  1315             (*target == XA_XmTRANSFER_SUCCESS) ? JNI_TRUE : JNI_FALSE;
       
  1316 
       
  1317         ds_postDragSourceDropEvent(env, success, target_action,
       
  1318                                    x_root, y_root);
       
  1319 
       
  1320         dnd_in_progress = False;
       
  1321 
       
  1322         XSelectInput(XtDisplay(w), target_window, target_window_mask);
       
  1323 
       
  1324         cleanup_drag(XtDisplay(w), CurrentTime);
       
  1325 
       
  1326         *type = *target;
       
  1327         *length = 0;
       
  1328         *format = 32;
       
  1329         *value = NULL;
       
  1330 
       
  1331         return True;
       
  1332     } else {
       
  1333         return awt_convertData(w, selection, target, type, value, length,
       
  1334                                format);
       
  1335     }
       
  1336 }
       
  1337 
       
  1338 static Boolean
       
  1339 set_convert_data_context(JNIEnv* env, Display* dpy, XID xid, jobject component,
       
  1340                          jobject transferable, jobject formatMap,
       
  1341                          jlongArray formats) {
       
  1342     awt_convertDataCallbackStruct* structPtr = NULL;
       
  1343 
       
  1344     if (XFindContext(awt_display, xid, awt_convertDataContext,
       
  1345                      (XPointer*)&structPtr) == XCNOMEM || structPtr != NULL) {
       
  1346         return False;
       
  1347     }
       
  1348 
       
  1349     structPtr = calloc(1, sizeof(awt_convertDataCallbackStruct));
       
  1350     if (structPtr == NULL) {
       
  1351         return False;
       
  1352     }
       
  1353 
       
  1354     structPtr->source              = (*env)->NewGlobalRef(env, component);
       
  1355     structPtr->transferable        = (*env)->NewGlobalRef(env, transferable);
       
  1356     structPtr->formatMap           = (*env)->NewGlobalRef(env, formatMap);
       
  1357     structPtr->formats             = (*env)->NewGlobalRef(env, formats);
       
  1358 
       
  1359     if (JNU_IsNull(env, structPtr->source) ||
       
  1360         JNU_IsNull(env, structPtr->transferable) ||
       
  1361         JNU_IsNull(env, structPtr->formatMap) ||
       
  1362         JNU_IsNull(env, structPtr->formats)) {
       
  1363 
       
  1364         if (!JNU_IsNull(env, structPtr->source)) {
       
  1365             (*env)->DeleteGlobalRef(env, structPtr->source);
       
  1366         }
       
  1367         if (!JNU_IsNull(env, structPtr->transferable)) {
       
  1368             (*env)->DeleteGlobalRef(env, structPtr->transferable);
       
  1369         }
       
  1370         if (!JNU_IsNull(env, structPtr->formatMap)) {
       
  1371             (*env)->DeleteGlobalRef(env, structPtr->formatMap);
       
  1372         }
       
  1373         if (!JNU_IsNull(env, structPtr->formats)) {
       
  1374             (*env)->DeleteGlobalRef(env, structPtr->formats);
       
  1375         }
       
  1376         free(structPtr);
       
  1377         return False;
       
  1378     }
       
  1379 
       
  1380     if (XSaveContext(dpy, xid, awt_convertDataContext,
       
  1381                      (XPointer)structPtr) == XCNOMEM) {
       
  1382         free(structPtr);
       
  1383         return False;
       
  1384     }
       
  1385 
       
  1386     return True;
       
  1387 }
       
  1388 
       
  1389 /*
       
  1390  * Convenience routine. Constructs an appropriate exception message based on the
       
  1391  * specified prefix and the return code of XGrab* function and throws an
       
  1392  * InvalidDnDOperationException with the constructed message.
       
  1393  */
       
  1394 static void
       
  1395 throw_grab_failure_exception(JNIEnv* env, int ret_code, char* msg_prefix) {
       
  1396     char msg[200];
       
  1397     char* msg_cause = "";
       
  1398 
       
  1399     switch (ret_code) {
       
  1400     case GrabNotViewable:  msg_cause = "not viewable";    break;
       
  1401     case AlreadyGrabbed:   msg_cause = "already grabbed"; break;
       
  1402     case GrabInvalidTime:  msg_cause = "invalid time";    break;
       
  1403     case GrabFrozen:       msg_cause = "grab frozen";     break;
       
  1404     default:               msg_cause = "unknown failure"; break;
       
  1405     }
       
  1406 
       
  1407     sprintf(msg, "%s: %s.", msg_prefix, msg_cause);
       
  1408     JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1409                     msg);
       
  1410 }
       
  1411 
       
  1412 /*
       
  1413  * Sets the proxy mode source window - the source window which the drag
       
  1414  * notifications from an XEmbed client should be forwarded to.
       
  1415  * If the window is not None and there is a drag operation in progress,
       
  1416  * throws InvalidDnDOperationException and doesn't change
       
  1417  * proxy_mode_source_window.
       
  1418  * The caller mush hold AWT_LOCK.
       
  1419  */
       
  1420 void
       
  1421 set_proxy_mode_source_window(Window window) {
       
  1422     if (window != None && dnd_in_progress) {
       
  1423         JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
  1424         JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1425                         "Drag and drop is already in progress.");
       
  1426         return;
       
  1427     }
       
  1428 
       
  1429     proxy_mode_source_window = window;
       
  1430 }
       
  1431 
       
  1432 /*
       
  1433  * Checks if the event is a drag notification from an XEmbed client.
       
  1434  * If it is, forwards this event back to the current source and returns True.
       
  1435  * Otherwise, returns False.
       
  1436  * Currently only XDnD protocol notifications are recognized.
       
  1437  * The caller must hold AWT_LOCK.
       
  1438  */
       
  1439 static Boolean
       
  1440 process_proxy_mode_event(XEvent* event) {
       
  1441     if (proxy_mode_source_window == None) {
       
  1442         return False;
       
  1443     }
       
  1444 
       
  1445     if (event->type == ClientMessage) {
       
  1446         XClientMessageEvent* xclient = &event->xclient;
       
  1447         if (xclient->message_type == XA_XdndStatus ||
       
  1448             xclient->message_type == XA_XdndFinished) {
       
  1449             Window source = proxy_mode_source_window;
       
  1450 
       
  1451             xclient->data.l[0] = xclient->window;
       
  1452             xclient->window = source;
       
  1453 
       
  1454             XSendEvent(xclient->display, source, False, NoEventMask,
       
  1455                        (XEvent*)xclient);
       
  1456 
       
  1457             if (xclient->message_type == XA_XdndFinished) {
       
  1458                 proxy_mode_source_window = None;
       
  1459             }
       
  1460 
       
  1461             return True;
       
  1462         }
       
  1463     }
       
  1464 
       
  1465     return False;
       
  1466 }
       
  1467 
       
  1468 /*
       
  1469  * Class:     sun_awt_motif_X11DragSourceContextPeer
       
  1470  * Method:    startDrag
       
  1471  * Signature: ()V
       
  1472  */
       
  1473 JNIEXPORT void JNICALL
       
  1474 Java_sun_awt_motif_X11DragSourceContextPeer_startDrag(JNIEnv *env,
       
  1475                                                       jobject this,
       
  1476                                                       jobject component,
       
  1477                                                       jobject wpeer,
       
  1478                                                       jobject transferable,
       
  1479                                                       jobject trigger,
       
  1480                                                       jobject cursor,
       
  1481                                                       jint ctype,
       
  1482                                                       jint actions,
       
  1483                                                       jlongArray formats,
       
  1484                                                       jobject formatMap) {
       
  1485     Time time_stamp = CurrentTime;
       
  1486     Cursor xcursor = None;
       
  1487     Window root_window = None;
       
  1488     Atom* targets = NULL;
       
  1489     jsize num_targets = 0;
       
  1490 
       
  1491     AWT_LOCK();
       
  1492 
       
  1493     if (dnd_in_progress) {
       
  1494         JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1495                         "Drag and drop is already in progress.");
       
  1496         AWT_UNLOCK();
       
  1497         return;
       
  1498     }
       
  1499 
       
  1500     if (proxy_mode_source_window != None) {
       
  1501         JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1502                         "Proxy drag is in progress.");
       
  1503         AWT_UNLOCK();
       
  1504         return;
       
  1505     }
       
  1506 
       
  1507     if (!awt_dnd_init(awt_display)) {
       
  1508         JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1509                         "DnD subsystem initialization failed.");
       
  1510         AWT_UNLOCK();
       
  1511         return;
       
  1512     }
       
  1513 
       
  1514     if (!JNU_IsNull(env, cursor)) {
       
  1515         xcursor = getCursor(env, cursor);
       
  1516 
       
  1517         if (xcursor == None) {
       
  1518             JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1519                             "Invalid drag cursor");
       
  1520             AWT_UNLOCK();
       
  1521         }
       
  1522     }
       
  1523 
       
  1524     /* Determine the root window for the drag operation. */
       
  1525     {
       
  1526         struct FrameData* wdata = (struct FrameData*)
       
  1527             JNU_GetLongFieldAsPtr(env, wpeer, mComponentPeerIDs.pData);
       
  1528 
       
  1529         if (wdata == NULL) {
       
  1530             JNU_ThrowNullPointerException(env, "Null component data");
       
  1531             AWT_UNLOCK();
       
  1532             return;
       
  1533         }
       
  1534 
       
  1535         if (wdata->winData.shell == NULL) {
       
  1536             JNU_ThrowNullPointerException(env, "Null shell widget");
       
  1537             AWT_UNLOCK();
       
  1538             return;
       
  1539         }
       
  1540 
       
  1541         root_window = RootWindowOfScreen(XtScreen(wdata->winData.shell));
       
  1542 
       
  1543         if (root_window == None) {
       
  1544             JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1545                             "Cannot get the root window for the drag operation.");
       
  1546             AWT_UNLOCK();
       
  1547             return;
       
  1548         }
       
  1549     }
       
  1550 
       
  1551     time_stamp = get_latest_time_stamp();
       
  1552 
       
  1553     /* Extract the targets from java array. */
       
  1554     {
       
  1555         targets = NULL;
       
  1556         num_targets = (*env)->GetArrayLength(env, formats);
       
  1557 
       
  1558         /*
       
  1559          * In debug build GetLongArrayElements aborts with assertion on an empty
       
  1560          * array.
       
  1561          */
       
  1562         if (num_targets > 0) {
       
  1563             jboolean isCopy = JNI_TRUE;
       
  1564             jlong* java_targets = (*env)->GetLongArrayElements(env, formats,
       
  1565                                                                &isCopy);
       
  1566 
       
  1567             if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
  1568                 AWT_UNLOCK();
       
  1569                 return;
       
  1570             }
       
  1571 
       
  1572             if (java_targets != NULL) {
       
  1573                 targets = (Atom*)malloc(num_targets * sizeof(Atom));
       
  1574                 if (targets != NULL) {
       
  1575 #ifdef _LP64
       
  1576                     memcpy(targets, java_targets, num_targets * sizeof(Atom));
       
  1577 #else
       
  1578                     jsize i;
       
  1579 
       
  1580                     for (i = 0; i < num_targets; i++) {
       
  1581                         targets[i] = (Atom)java_targets[i];
       
  1582                     }
       
  1583 #endif
       
  1584                 }
       
  1585                 (*env)->ReleaseLongArrayElements(env, formats, java_targets,
       
  1586                                                  JNI_ABORT);
       
  1587             }
       
  1588         }
       
  1589         if (targets == NULL) {
       
  1590             num_targets = 0;
       
  1591         }
       
  1592     }
       
  1593 
       
  1594     /* Write the XDnD initiator info on the awt_root_shell. */
       
  1595     {
       
  1596         unsigned char ret;
       
  1597         Atom action_atoms[3];
       
  1598         unsigned int action_count = 0;
       
  1599 
       
  1600         if (actions & java_awt_dnd_DnDConstants_ACTION_COPY) {
       
  1601             action_atoms[action_count] = XA_XdndActionCopy;
       
  1602             action_count++;
       
  1603         }
       
  1604         if (actions & java_awt_dnd_DnDConstants_ACTION_MOVE) {
       
  1605             action_atoms[action_count] = XA_XdndActionMove;
       
  1606             action_count++;
       
  1607         }
       
  1608         if (actions & java_awt_dnd_DnDConstants_ACTION_LINK) {
       
  1609             action_atoms[action_count] = XA_XdndActionLink;
       
  1610             action_count++;
       
  1611         }
       
  1612 
       
  1613         ret = checked_XChangeProperty(awt_display, awt_dnd_ds_get_source_window(),
       
  1614                                       XA_XdndActionList, XA_ATOM, 32,
       
  1615                                       PropModeReplace, (unsigned char*)action_atoms,
       
  1616                                       action_count * sizeof(Atom));
       
  1617 
       
  1618         if (ret != Success) {
       
  1619             cleanup_drag(awt_display, time_stamp);
       
  1620             JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1621                             "Cannot write XdndActionList property");
       
  1622             AWT_UNLOCK();
       
  1623             return;
       
  1624         }
       
  1625 
       
  1626         ret = checked_XChangeProperty(awt_display, awt_dnd_ds_get_source_window(),
       
  1627                                       XA_XdndTypeList, XA_ATOM, 32,
       
  1628                                       PropModeReplace, (unsigned char*)targets,
       
  1629                                       num_targets);
       
  1630 
       
  1631         if (ret != Success) {
       
  1632             cleanup_drag(awt_display, time_stamp);
       
  1633             JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1634                             "Cannot write XdndTypeList property");
       
  1635             AWT_UNLOCK();
       
  1636             return;
       
  1637         }
       
  1638     }
       
  1639 
       
  1640     /* Write the Motif DnD initiator info on the awt_root_shell. */
       
  1641     {
       
  1642         InitiatorInfo info;
       
  1643         unsigned char ret;
       
  1644         int target_list_index =
       
  1645             get_index_for_target_list(awt_display, targets, num_targets);
       
  1646 
       
  1647         if (target_list_index == -1) {
       
  1648             cleanup_drag(awt_display, time_stamp);
       
  1649             JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1650                             "Cannot determine the target list index.");
       
  1651             AWT_UNLOCK();
       
  1652             return;
       
  1653         }
       
  1654 
       
  1655         info.byte_order = MOTIF_BYTE_ORDER;
       
  1656         info.protocol_version = MOTIF_DND_PROTOCOL_VERSION;
       
  1657         info.index = target_list_index;
       
  1658         info.selection_atom = _XA_MOTIF_ATOM_0;
       
  1659 
       
  1660         ret = checked_XChangeProperty(awt_display, awt_dnd_ds_get_source_window(),
       
  1661                                       _XA_MOTIF_ATOM_0,
       
  1662                                       _XA_MOTIF_DRAG_INITIATOR_INFO, 8,
       
  1663                                       PropModeReplace, (unsigned char*)&info,
       
  1664                                       sizeof(InitiatorInfo));
       
  1665 
       
  1666         if (ret != Success) {
       
  1667             cleanup_drag(awt_display, time_stamp);
       
  1668             JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1669                             "Cannot write the Motif DnD initiator info");
       
  1670             AWT_UNLOCK();
       
  1671             return;
       
  1672         }
       
  1673     }
       
  1674 
       
  1675     /* Acquire XDnD selection ownership. */
       
  1676     if (XtOwnSelection(awt_root_shell, XA_XdndSelection, time_stamp,
       
  1677                        awt_convertData, NULL, NULL) != True) {
       
  1678         cleanup_drag(awt_display, time_stamp);
       
  1679         JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1680                         "Cannot acquire XdndSelection ownership.");
       
  1681         AWT_UNLOCK();
       
  1682         return;
       
  1683     }
       
  1684 
       
  1685     /* Acquire Motif DnD selection ownership. */
       
  1686     if (XtOwnSelection(awt_root_shell, _XA_MOTIF_ATOM_0, time_stamp,
       
  1687                        motif_convert_proc, NULL, NULL) != True) {
       
  1688         cleanup_drag(awt_display, time_stamp);
       
  1689         JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1690                         "Cannot acquire Motif DnD selection ownership.");
       
  1691         AWT_UNLOCK();
       
  1692         return;
       
  1693     }
       
  1694 
       
  1695     /*
       
  1696      * Store the information needed to convert data for both selections
       
  1697      * in awt_convertDataContext.
       
  1698      */
       
  1699     {
       
  1700         if (!set_convert_data_context(env, awt_display, XA_XdndSelection,
       
  1701                                       component, transferable, formatMap,
       
  1702                                       formats)) {
       
  1703             cleanup_drag(awt_display, time_stamp);
       
  1704             JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1705                             "Cannot save context for XDnD selection data conversion.");
       
  1706             AWT_UNLOCK();
       
  1707             return;
       
  1708         }
       
  1709 
       
  1710         if (!set_convert_data_context(env, awt_display, _XA_MOTIF_ATOM_0,
       
  1711                                       component, transferable, formatMap,
       
  1712                                       formats)) {
       
  1713             cleanup_drag(awt_display, time_stamp);
       
  1714             JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException",
       
  1715                             "Cannot save context for Motif DnD selection data conversion.");
       
  1716             AWT_UNLOCK();
       
  1717             return;
       
  1718         }
       
  1719     }
       
  1720 
       
  1721     /* Install X grabs. */
       
  1722     {
       
  1723         XWindowAttributes xwa;
       
  1724         int ret;
       
  1725 
       
  1726         XGetWindowAttributes(awt_display, root_window, &xwa);
       
  1727 
       
  1728         your_root_event_mask = xwa.your_event_mask;
       
  1729 
       
  1730         XSelectInput(awt_display, root_window,
       
  1731                      your_root_event_mask | ROOT_EVENT_MASK);
       
  1732 
       
  1733         ret = XGrabPointer(awt_display,
       
  1734                            root_window,
       
  1735                            False,
       
  1736                            GRAB_EVENT_MASK,
       
  1737                            GrabModeAsync,
       
  1738                            GrabModeAsync,
       
  1739                            None,
       
  1740                            xcursor,
       
  1741                            time_stamp);
       
  1742 
       
  1743         if (ret != GrabSuccess) {
       
  1744             cleanup_drag(awt_display, time_stamp);
       
  1745             throw_grab_failure_exception(env, ret, "Cannot grab pointer");
       
  1746             AWT_UNLOCK();
       
  1747             return;
       
  1748         }
       
  1749 
       
  1750         ret = XGrabKeyboard(awt_display,
       
  1751                             root_window,
       
  1752                             False,
       
  1753                             GrabModeAsync,
       
  1754                             GrabModeAsync,
       
  1755                             time_stamp);
       
  1756 
       
  1757         if (ret != GrabSuccess) {
       
  1758             cleanup_drag(awt_display, time_stamp);
       
  1759             throw_grab_failure_exception(env, ret, "Cannot grab keyboard");
       
  1760             AWT_UNLOCK();
       
  1761             return;
       
  1762         }
       
  1763     }
       
  1764 
       
  1765     /* Update the global state. */
       
  1766     source_peer = (*env)->NewGlobalRef(env, this);
       
  1767     dnd_in_progress = True;
       
  1768     drag_in_progress = True;
       
  1769     data_types = targets;
       
  1770     data_types_count = num_targets;
       
  1771     source_actions = actions;
       
  1772     drag_root_window = root_window;
       
  1773 
       
  1774     AWT_UNLOCK();
       
  1775 }
       
  1776 
       
  1777 /*
       
  1778  * Class:     sun_awt_motif_X11DragSourceContextPeer
       
  1779  * Method:    setNativeCursor
       
  1780  * Signature: ()V
       
  1781  */
       
  1782 JNIEXPORT void JNICALL
       
  1783 Java_sun_awt_motif_X11DragSourceContextPeer_setNativeCursor(JNIEnv *env,
       
  1784                                                             jobject this,
       
  1785                                                             jlong nativeCtxt,
       
  1786                                                             jobject cursor,
       
  1787                                                             jint type) {
       
  1788     if (JNU_IsNull(env, cursor)) {
       
  1789         return;
       
  1790     }
       
  1791 
       
  1792     XChangeActivePointerGrab(awt_display,
       
  1793                              GRAB_EVENT_MASK,
       
  1794                              getCursor(env, cursor),
       
  1795                              CurrentTime);
       
  1796 }