jdk/src/solaris/native/sun/awt/awt_dnd_dt.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 #include "jlong.h"
       
    33 
       
    34 #include "awt_DataTransferer.h"
       
    35 #include "awt_MToolkit.h"
       
    36 
       
    37 #include "java_awt_dnd_DnDConstants.h"
       
    38 #include "java_awt_event_MouseEvent.h"
       
    39 
       
    40 #include "sun_awt_motif_MComponentPeer.h"
       
    41 #include "awt_xembed.h"
       
    42 
       
    43 #define DT_INITIAL_STATE 0
       
    44 #define DT_ENTERED_STATE 1
       
    45 #define DT_OVER_STATE    2
       
    46 
       
    47 extern struct ComponentIDs componentIDs;
       
    48 extern struct MComponentPeerIDs mComponentPeerIDs;
       
    49 
       
    50 /**************************** XEmbed server DnD support ***********************/
       
    51 extern void
       
    52 set_xembed_drop_target(JNIEnv* env, jobject server);
       
    53 extern void
       
    54 remove_xembed_drop_target(JNIEnv* env, jobject server);
       
    55 extern Boolean
       
    56 is_xembed_client(Window window);
       
    57 
       
    58 DECLARE_JAVA_CLASS(MEmbedCanvasPeerClass, "sun/awt/motif/MEmbedCanvasPeer");
       
    59 /******************************************************************************/
       
    60 
       
    61 typedef enum {
       
    62     EventSuccess,    /* Event is successfully processed. */
       
    63     EventFailure     /* Failed to process the event. */
       
    64 } EventStatus;
       
    65 
       
    66 typedef enum {
       
    67     EnterEvent,    /* XdndEnter, TOP_LEVEL_ENTER */
       
    68     MotionEvent,   /* XdndPosition, DRAG_MOTION, OPERATION_CHANGED */
       
    69     LeaveEvent,    /* XdndLeave, TOP_LEVEL_LEAVE */
       
    70     DropEvent,     /* XdndDrop, DROP_START */
       
    71     UnknownEvent
       
    72 } EventType;
       
    73 
       
    74 static Protocol source_protocol = NO_PROTOCOL;
       
    75 static unsigned int source_protocol_version = 0;
       
    76 static Window source_window = None;
       
    77 static Atom source_atom = None;
       
    78 static long source_window_mask = None;
       
    79 static jint source_actions = java_awt_dnd_DnDConstants_ACTION_NONE;
       
    80 /*
       
    81  * According to XDnD protocol, XdndActionList is optional.
       
    82  * In case if XdndActionList is not set on the source, the list of drop actions
       
    83  * supported by the source is constructed as follows:
       
    84  *  - "copy" is always included;
       
    85  *  - "move" is included if at least one XdndPosition message received
       
    86  *    after the latest XdndEnter passed XdndActionMove in data.l[4];
       
    87  *  - "link" is included if at least one XdndPosition message received
       
    88  *    after the latest XdndEnter passed XdndActionLink in data.l[4].
       
    89  * We use a boolean flag to signal that we are building the list of drop actions
       
    90  * supported by the source.
       
    91  */
       
    92 static Boolean track_source_actions = False;
       
    93 static jint user_action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
    94 static jlongArray source_data_types = NULL;
       
    95 static Atom* source_data_types_native = NULL;
       
    96 static unsigned int source_data_types_count = 0;
       
    97 static int source_x = 0;
       
    98 static int source_y = 0;
       
    99 static jobject target_component = NULL;
       
   100 /*
       
   101  * The Motif DnD protocol prescribes that DROP_START message should always be
       
   102  * preceeded with TOP_LEVEL_LEAVE message. We need to cleanup on TOP_LEVEL_LEAVE
       
   103  * message, but DROP_START wouldn't be processed properly.
       
   104  * To resolve this issue we postpone cleanup using a boolean flag this flag is
       
   105  * set when we receive the TOP_LEVEL_LEAVE message and cleared when the next
       
   106  * client message arrives if that message is not DROP_START. If that message is
       
   107  * a DROP_START message, the flag is cleared after the DROP_START is processed.
       
   108  */
       
   109 static Boolean motif_top_level_leave_postponed = False;
       
   110 /*
       
   111  * We store a postponed TOP_LEVEL_LEAVE message here.
       
   112  */
       
   113 static XClientMessageEvent motif_top_level_leave_postponed_event;
       
   114 
       
   115 /* Forward declarations */
       
   116 static Window get_root_for_window(Window window);
       
   117 static Window get_outer_canvas_for_window(Window window);
       
   118 static Boolean register_drop_site(Widget outer_canvas, XtPointer componentRef);
       
   119 static Boolean is_xdnd_drag_message_type(unsigned long message_type);
       
   120 static Boolean register_xdnd_drop_site(Display* dpy, Window toplevel,
       
   121                                        Window window);
       
   122 
       
   123 /**************************** JNI stuff ***************************************/
       
   124 
       
   125 DECLARE_JAVA_CLASS(dtcp_clazz, "sun/awt/motif/X11DropTargetContextPeer")
       
   126 
       
   127 static void
       
   128 dt_postDropTargetEvent(JNIEnv* env, jobject component, int x, int y,
       
   129                        jint dropAction, jint event_id,
       
   130                        XClientMessageEvent* event) {
       
   131     DECLARE_STATIC_VOID_JAVA_METHOD(dtcp_postDropTargetEventToPeer, dtcp_clazz,
       
   132                                     "postDropTargetEventToPeer",
       
   133                                     "(Ljava/awt/Component;IIII[JJI)V");
       
   134 
       
   135     {
       
   136         void* copy = NULL;
       
   137 
       
   138         if (event != NULL) {
       
   139             /*
       
   140              * For XDnD messages we append the information from the latest
       
   141              * XdndEnter to the context. It is done to be able to reconstruct
       
   142              * XdndEnter for an XEmbed client.
       
   143              */
       
   144             Boolean isXDnDMessage =
       
   145                 is_xdnd_drag_message_type(event->message_type);
       
   146 
       
   147             if (isXDnDMessage) {
       
   148                 copy = malloc(sizeof(XClientMessageEvent) +
       
   149                                                  4 * sizeof(long));
       
   150             } else {
       
   151                 copy = malloc(sizeof(XClientMessageEvent));
       
   152             }
       
   153 
       
   154             if (copy == NULL) {
       
   155                 DTRACE_PRINTLN2("%s:%d malloc failed.", __FILE__, __LINE__);
       
   156                 return;
       
   157             }
       
   158 
       
   159             memcpy(copy, event, sizeof(XClientMessageEvent));
       
   160 
       
   161             if (isXDnDMessage) {
       
   162                 size_t msgSize = sizeof(XClientMessageEvent);
       
   163                 long data1 = source_protocol_version << XDND_PROTOCOL_SHIFT;
       
   164                 long * appended_data;
       
   165                 if (source_data_types_native != NULL &&
       
   166                     source_data_types_count > 3) {
       
   167 
       
   168                     data1 |= XDND_DATA_TYPES_BIT;
       
   169                 }
       
   170 
       
   171                 appended_data = (long*)((char*)copy + msgSize);
       
   172                 appended_data[0] = data1;
       
   173                 appended_data[1] = source_data_types_count > 0 ?
       
   174                     source_data_types_native[0] : 0;
       
   175                 appended_data[2] = source_data_types_count > 1 ?
       
   176                     source_data_types_native[1] : 0;
       
   177                 appended_data[3] = source_data_types_count > 2 ?
       
   178                     source_data_types_native[2] : 0;
       
   179             }
       
   180         }
       
   181 
       
   182         DASSERT(!JNU_IsNull(env, component));
       
   183 
       
   184         (*env)->CallStaticVoidMethod(env, clazz, dtcp_postDropTargetEventToPeer,
       
   185                                      component, x, y, dropAction,
       
   186                                      source_actions, source_data_types,
       
   187                                      ptr_to_jlong(copy), event_id);
       
   188     }
       
   189 }
       
   190 
       
   191 /******************************************************************************/
       
   192 
       
   193 /********************* Embedded drop site list support ************************/
       
   194 
       
   195 struct EmbeddedDropSiteListEntryRec;
       
   196 
       
   197 typedef struct EmbeddedDropSiteListEntryRec EmbeddedDropSiteListEntry;
       
   198 
       
   199 struct EmbeddedDropSiteListEntryRec {
       
   200     Window toplevel;
       
   201     Window root;
       
   202     /*
       
   203      * We select for PropertyNotify events on the toplevel, so we need to
       
   204      * restore the event mask when we are done with this toplevel.
       
   205      */
       
   206     long event_mask;
       
   207     unsigned int embedded_sites_count;
       
   208     Window* embedded_sites;
       
   209     EmbeddedDropSiteListEntry* next;
       
   210 };
       
   211 
       
   212 static EmbeddedDropSiteListEntry* embedded_drop_site_list = NULL;
       
   213 
       
   214 struct EmbeddedDropSiteProtocolListEntryRec;
       
   215 
       
   216 typedef struct EmbeddedDropSiteProtocolListEntryRec EmbeddedDropSiteProtocolListEntry;
       
   217 
       
   218 struct EmbeddedDropSiteProtocolListEntryRec {
       
   219     Window window;
       
   220     Window proxy;
       
   221     /*
       
   222      * We override the XdndAware property on the toplevel, so we should keep its
       
   223      * original contents - the XDnD protocol version supported by the browser.
       
   224      * This is needed to adjust XDnD messages forwarded to the browser.
       
   225      */
       
   226     unsigned int protocol_version;
       
   227     /* True if the toplevel was already registered as a drag receiver and
       
   228        we just changed the proxy. False, otherwise */
       
   229     Boolean overriden;
       
   230     EmbeddedDropSiteProtocolListEntry* next;
       
   231 };
       
   232 
       
   233 static EmbeddedDropSiteProtocolListEntry* embedded_motif_protocol_list = NULL;
       
   234 static EmbeddedDropSiteProtocolListEntry* embedded_xdnd_protocol_list = NULL;
       
   235 
       
   236 typedef enum {
       
   237     RegFailure, /* Proxy registration failed */
       
   238     RegSuccess, /* The new drop site is registered with the new proxy */
       
   239     RegOverride, /* The new proxy is set for the existing drop site */
       
   240     RegAlreadyRegistered /* This proxy is already set for this drop site */
       
   241 } ProxyRegistrationStatus;
       
   242 
       
   243 /* Forward declarations. */
       
   244 static EmbeddedDropSiteProtocolListEntry*
       
   245 get_xdnd_protocol_entry_for_toplevel(Window toplevel);
       
   246 static EmbeddedDropSiteProtocolListEntry*
       
   247 get_motif_protocol_entry_for_toplevel(Window toplevel);
       
   248 static void remove_xdnd_protocol_entry_for_toplevel(Window toplevel);
       
   249 static void remove_motif_protocol_entry_for_toplevel(Window toplevel);
       
   250 
       
   251 /*
       
   252  * Registers the toplevel as a Motif drag receiver if it is not registered yet,
       
   253  * sets the specified new_proxy for it and returns the previous proxy in old_proxy.
       
   254  * Does nothing if the new_proxy is already set as a proxy for this toplevel.
       
   255  * Returns the completion status.
       
   256  */
       
   257 static ProxyRegistrationStatus
       
   258 set_motif_proxy(Display* dpy, Window toplevel, Window new_proxy, Window *old_proxy) {
       
   259     Boolean        override = False;
       
   260 
       
   261     Atom           type;
       
   262     int            format;
       
   263     unsigned long  nitems;
       
   264     unsigned long  after;
       
   265     unsigned char* data;
       
   266     unsigned char  ret;
       
   267 
       
   268     DASSERT(old_proxy != NULL);
       
   269 
       
   270     *old_proxy = None;
       
   271 
       
   272     data = NULL;
       
   273     ret = checked_XGetWindowProperty(dpy, toplevel,
       
   274                                      _XA_MOTIF_DRAG_RECEIVER_INFO, 0, 0xFFFF,
       
   275                                      False, AnyPropertyType, &type, &format,
       
   276                                      &nitems, &after, &data);
       
   277 
       
   278     /* Check if toplevel is a valid window. */
       
   279     if (ret != Success) {
       
   280         return RegFailure;
       
   281     }
       
   282 
       
   283     if (ret == Success && data != NULL && type != None && format == 8
       
   284         && nitems >= MOTIF_RECEIVER_INFO_SIZE) {
       
   285         unsigned char byte_order = read_card8((char*)data, 0);
       
   286         void* p = (char*)data + 4;
       
   287 
       
   288         /* Browser and plugin have different byte orders - report failure for now. */
       
   289         if (MOTIF_BYTE_ORDER != byte_order) {
       
   290             XFree(data);
       
   291             return RegFailure;
       
   292         }
       
   293 
       
   294         *old_proxy = read_card32((char*)data, 4, byte_order);
       
   295 
       
   296         /* If the proxy is already set to the specified window - return. */
       
   297         if (*old_proxy == new_proxy) {
       
   298             XFree(data);
       
   299             return RegAlreadyRegistered;
       
   300         }
       
   301 
       
   302         /* replace the proxy window */
       
   303         write_card32(&p, new_proxy);
       
   304 
       
   305         override = True;
       
   306     } else {
       
   307         void* p;
       
   308 
       
   309         if (ret == Success) {
       
   310             XFree(data);
       
   311             data = NULL;
       
   312         }
       
   313 
       
   314         data = malloc(MOTIF_RECEIVER_INFO_SIZE);
       
   315 
       
   316         if (data == NULL) {
       
   317             DTRACE_PRINTLN2("%s:%d malloc failed.", __FILE__, __LINE__);
       
   318             return RegFailure;
       
   319         }
       
   320 
       
   321         p = data;
       
   322 
       
   323         write_card8(&p, MOTIF_BYTE_ORDER);
       
   324         write_card8(&p, MOTIF_DND_PROTOCOL_VERSION); /* protocol version */
       
   325         write_card8(&p, MOTIF_DYNAMIC_STYLE); /* protocol style */
       
   326         write_card8(&p, 0); /* pad */
       
   327         write_card32(&p, new_proxy); /* proxy window */
       
   328         write_card16(&p, 0); /* num_drop_sites */
       
   329         write_card16(&p, 0); /* pad */
       
   330         write_card32(&p, MOTIF_RECEIVER_INFO_SIZE);
       
   331     }
       
   332 
       
   333     ret = checked_XChangeProperty(dpy, toplevel,
       
   334                                   _XA_MOTIF_DRAG_RECEIVER_INFO,
       
   335                                   _XA_MOTIF_DRAG_RECEIVER_INFO, 8,
       
   336                                   PropModeReplace, (unsigned char*)data,
       
   337                                   MOTIF_RECEIVER_INFO_SIZE);
       
   338 
       
   339     if (data != NULL) {
       
   340         XFree(data);
       
   341         data = NULL;
       
   342     }
       
   343 
       
   344     if (ret == Success) {
       
   345         if (override) {
       
   346             return RegOverride;
       
   347         } else {
       
   348             return RegSuccess;
       
   349         }
       
   350     } else {
       
   351         return RegFailure;
       
   352     }
       
   353 }
       
   354 
       
   355 /*
       
   356  * Registers the toplevel as a XDnD drag receiver if it is not registered yet,
       
   357  * sets the specified new_proxy for it and returns the previous proxy in
       
   358  * old_proxy and the original XDnD protocol version in old_version.
       
   359  * Does nothing if the new_proxy is already set as a proxy for this toplevel.
       
   360  * Returns the completion status.
       
   361  */
       
   362 static ProxyRegistrationStatus
       
   363 set_xdnd_proxy(Display* dpy, Window toplevel, Window new_proxy,
       
   364                Window* old_proxy, unsigned int* old_version) {
       
   365     Atom version_atom = XDND_PROTOCOL_VERSION;
       
   366     Window xdnd_proxy = None;
       
   367     Boolean override = False;
       
   368 
       
   369     Atom           type;
       
   370     int            format;
       
   371     unsigned long  nitems;
       
   372     unsigned long  after;
       
   373     unsigned char* data;
       
   374     unsigned char  ret;
       
   375 
       
   376     DASSERT(old_proxy != NULL);
       
   377 
       
   378     *old_proxy = None;
       
   379 
       
   380     data = NULL;
       
   381     ret = checked_XGetWindowProperty(dpy, toplevel, XA_XdndAware, 0, 1,
       
   382                                      False, AnyPropertyType, &type, &format,
       
   383                                      &nitems, &after, &data);
       
   384 
       
   385     if (ret != Success) {
       
   386         return RegFailure;
       
   387     }
       
   388 
       
   389     if (ret == Success && data != NULL && type == XA_ATOM) {
       
   390         unsigned int protocol_version = *((unsigned int*)data);
       
   391 
       
   392         override = True;
       
   393         *old_version = protocol_version;
       
   394 
       
   395         /* XdndProxy is not supported for prior to XDnD version 4 */
       
   396         if (protocol_version >= 4) {
       
   397             int status;
       
   398 
       
   399             XFree(data);
       
   400 
       
   401             data = NULL;
       
   402             status = XGetWindowProperty(dpy, toplevel, XA_XdndProxy, 0, 1,
       
   403                                         False, XA_WINDOW, &type, &format,
       
   404                                         &nitems, &after, &data);
       
   405 
       
   406             if (status == Success && data != NULL && type == XA_WINDOW) {
       
   407                 xdnd_proxy = *((Window*)data);
       
   408 
       
   409                 if (xdnd_proxy != None) {
       
   410                     XFree(data);
       
   411 
       
   412                     data = NULL;
       
   413                     status = XGetWindowProperty(dpy, xdnd_proxy, XA_XdndProxy,
       
   414                                                 0, 1, False, XA_WINDOW, &type,
       
   415                                                 &format, &nitems, &after, &data);
       
   416 
       
   417                     if (status != Success || data == NULL || type != XA_WINDOW ||
       
   418                         *((Window*)data) != xdnd_proxy) {
       
   419                         /* Ignore invalid proxy. */
       
   420                         xdnd_proxy = None;
       
   421                     }
       
   422                 }
       
   423 
       
   424                 if (xdnd_proxy != None) {
       
   425                     XFree(data);
       
   426 
       
   427                     data = NULL;
       
   428                     status = XGetWindowProperty(dpy, xdnd_proxy, XA_XdndAware,
       
   429                                                 0, 1, False, AnyPropertyType,
       
   430                                                 &type, &format, &nitems, &after,
       
   431                                                 &data);
       
   432 
       
   433                     if (status == Success && data != NULL && type == XA_ATOM) {
       
   434                         unsigned int proxy_version = *((unsigned int*)data);
       
   435 
       
   436                         if (proxy_version != protocol_version) {
       
   437                             /* Ignore invalid proxy. */
       
   438                             xdnd_proxy = None;
       
   439                         }
       
   440                     } else {
       
   441                         /* Ignore invalid proxy. */
       
   442                         xdnd_proxy = None;
       
   443                     }
       
   444                 }
       
   445             }
       
   446 
       
   447             *old_proxy = xdnd_proxy;
       
   448         }
       
   449     }
       
   450 
       
   451     XFree(data);
       
   452 
       
   453     /* If the proxy is already set to the specified window - return. */
       
   454     if (xdnd_proxy == new_proxy) {
       
   455         return RegAlreadyRegistered;
       
   456     }
       
   457 
       
   458     /* The proxy window must have the XdndAware set, as XDnD protocol prescribes
       
   459        to check the proxy window for XdndAware. */
       
   460     ret = checked_XChangeProperty(dpy, new_proxy, XA_XdndAware, XA_ATOM, 32,
       
   461                                   PropModeReplace,
       
   462                                   (unsigned char*)&version_atom, 1);
       
   463 
       
   464     if (ret != Success) {
       
   465         return RegFailure;
       
   466     }
       
   467 
       
   468     /* The proxy window must have the XdndProxy set to point to itself. */
       
   469     ret = checked_XChangeProperty(dpy, new_proxy, XA_XdndProxy, XA_WINDOW, 32,
       
   470                                   PropModeReplace,
       
   471                                   (unsigned char*)&new_proxy, 1);
       
   472 
       
   473     if (ret != Success) {
       
   474         return RegFailure;
       
   475     }
       
   476 
       
   477     ret = checked_XChangeProperty(dpy, toplevel, XA_XdndAware, XA_ATOM, 32,
       
   478                                   PropModeReplace,
       
   479                                   (unsigned char*)&version_atom, 1);
       
   480 
       
   481     if (ret != Success) {
       
   482         return RegFailure;
       
   483     }
       
   484 
       
   485     ret = checked_XChangeProperty(dpy, toplevel, XA_XdndProxy, XA_WINDOW, 32,
       
   486                                   PropModeReplace,
       
   487                                   (unsigned char*)&new_proxy, 1);
       
   488 
       
   489     if (ret == Success) {
       
   490         if (override) {
       
   491             return RegOverride;
       
   492         } else {
       
   493             return RegSuccess;
       
   494         }
       
   495     } else {
       
   496         return RegFailure;
       
   497     }
       
   498 }
       
   499 
       
   500 /*
       
   501  * 'toplevel' is the browser toplevel window. To register a drop site on the
       
   502  * plugin window we set the proxy for the browser toplevel window to point to
       
   503  * the awt_root_shell window.
       
   504  *
       
   505  * We assume that only one JVM per browser instance is possible. This
       
   506  * assumption is true with the current plugin implementation - it creates a
       
   507  * single JVM for all plugin instances created by the given plugin factory.
       
   508  *
       
   509  * When a client message event for the browser toplevel window is received, we
       
   510  * will iterate over drop sites registered with this toplevel and determine if
       
   511  * the mouse pointer is currently over one of them (there could be several
       
   512  * plugin windows in one browser window - for example if an HTML page contains
       
   513  * frames and several frames contain a plugin object).
       
   514  *
       
   515  * If the pointer is not over any of the plugin drop sites the client message
       
   516  * will be resent to the browser, otherwise it will be processed normally.
       
   517  */
       
   518 static EmbeddedDropSiteListEntry*
       
   519 awt_dnd_dt_init_proxy(Display* dpy, Window root, Window toplevel, Window window) {
       
   520     Window         awt_root_window = get_awt_root_window();
       
   521     Window         motif_proxy = None;
       
   522     Boolean        motif_override = False;
       
   523     unsigned long  event_mask = 0;
       
   524 
       
   525     if (awt_root_window == None) {
       
   526         return NULL;
       
   527     }
       
   528 
       
   529     /* Grab server, since we are working with the window that belongs to
       
   530        another client. REMIND: ungrab when done!!! */
       
   531     XGrabServer(dpy);
       
   532 
       
   533     {
       
   534         ProxyRegistrationStatus motif_status = RegFailure;
       
   535 
       
   536         motif_status = set_motif_proxy(dpy, toplevel, awt_root_window, &motif_proxy);
       
   537 
       
   538         switch (motif_status) {
       
   539         case RegFailure:
       
   540         case RegAlreadyRegistered:
       
   541             XUngrabServer(dpy);
       
   542             /* Workaround for bug 5039226 */
       
   543             XSync(dpy, False);
       
   544             return NULL;
       
   545         case RegOverride:
       
   546             motif_override = True;
       
   547             break;
       
   548         case RegSuccess:
       
   549             motif_override = False;
       
   550             break;
       
   551         default:
       
   552             DASSERT(False);
       
   553         }
       
   554 
       
   555 
       
   556     }
       
   557 
       
   558     {
       
   559         XWindowAttributes xwa;
       
   560         XGetWindowAttributes(dpy, toplevel, &xwa);
       
   561         event_mask = xwa.your_event_mask;
       
   562         if ((event_mask & PropertyChangeMask) == 0) {
       
   563             XSelectInput(dpy, toplevel, event_mask | PropertyChangeMask);
       
   564         }
       
   565     }
       
   566 
       
   567     XUngrabServer(dpy);
       
   568     /* Workaround for bug 5039226 */
       
   569     XSync(dpy, False);
       
   570 
       
   571     /* Add protocol specific entries for the toplevel. */
       
   572     {
       
   573         EmbeddedDropSiteProtocolListEntry* motif_entry = NULL;
       
   574 
       
   575         motif_entry = malloc(sizeof(EmbeddedDropSiteProtocolListEntry));
       
   576 
       
   577         if (motif_entry == NULL) {
       
   578             return NULL;
       
   579         }
       
   580 
       
   581         motif_entry->window = toplevel;
       
   582         motif_entry->proxy = motif_proxy;
       
   583         motif_entry->protocol_version = 0;
       
   584         motif_entry->overriden = motif_override;
       
   585         motif_entry->next = embedded_motif_protocol_list;
       
   586         embedded_motif_protocol_list = motif_entry;
       
   587     }
       
   588 
       
   589     {
       
   590         EmbeddedDropSiteListEntry* entry = NULL;
       
   591         Window* sites = NULL;
       
   592 
       
   593         entry = malloc(sizeof(EmbeddedDropSiteListEntry));
       
   594 
       
   595         if (entry == NULL) {
       
   596             return NULL;
       
   597         }
       
   598 
       
   599         sites = malloc(sizeof(Window));
       
   600 
       
   601         if (sites == NULL) {
       
   602             free(entry);
       
   603             return NULL;
       
   604         }
       
   605 
       
   606         sites[0] = window;
       
   607 
       
   608         entry->toplevel = toplevel;
       
   609         entry->root = root;
       
   610         entry->event_mask = event_mask;
       
   611         entry->embedded_sites_count = 1;
       
   612         entry->embedded_sites = sites;
       
   613         entry->next = NULL;
       
   614 
       
   615         return entry;
       
   616     }
       
   617 }
       
   618 
       
   619 static void
       
   620 register_xdnd_embedder(Display* dpy, EmbeddedDropSiteListEntry* entry, long window) {
       
   621     Window         awt_root_window = get_awt_root_window();
       
   622     Window         toplevel = entry->toplevel;
       
   623     Window         xdnd_proxy = None;
       
   624     unsigned int   xdnd_protocol_version = 0;
       
   625     Boolean        xdnd_override = False;
       
   626     Boolean        register_xdnd = True;
       
   627     Boolean        motif_overriden = False;
       
   628 
       
   629     EmbeddedDropSiteProtocolListEntry* motif_entry = embedded_motif_protocol_list;
       
   630     while (motif_entry != NULL) {
       
   631         if (motif_entry->window == toplevel) {
       
   632             motif_overriden = motif_entry->overriden;
       
   633             break;
       
   634         }
       
   635         motif_entry = motif_entry->next;
       
   636     }
       
   637 
       
   638     /*
       
   639      * First check if the window is an XEmbed client.
       
   640      * In this case we don't have to setup a proxy on the toplevel,
       
   641      * instead we register the XDnD drop site on the embedded window.
       
   642      */
       
   643     if (isXEmbedActiveByWindow(window)) {
       
   644         register_xdnd_drop_site(dpy, toplevel, window);
       
   645         return;
       
   646     }
       
   647 
       
   648     /*
       
   649      * By default, we register a drop site that supports both dnd
       
   650      * protocols. This approach is not appropriate in plugin
       
   651      * scenario if the browser doesn't support XDnD. If we forcibly set
       
   652      * XdndAware on the browser toplevel, any drag source that supports both
       
   653      * protocols and prefers XDnD will be unable to drop anything on the
       
   654      * browser.
       
   655      * The solution for this problem is not to register XDnD drop site
       
   656      * if the browser supports only Motif DnD.
       
   657      */
       
   658     if (motif_overriden) {
       
   659         int            status;
       
   660         Atom           type;
       
   661         int            format;
       
   662         unsigned long  nitems;
       
   663         unsigned long  after;
       
   664         unsigned char* data;
       
   665 
       
   666         data = NULL;
       
   667         status = XGetWindowProperty(dpy, toplevel, XA_XdndAware, 0, 1,
       
   668                                     False, AnyPropertyType, &type, &format,
       
   669                                     &nitems, &after, &data);
       
   670 
       
   671         XFree(data);
       
   672         data = NULL;
       
   673 
       
   674         if (type != XA_ATOM) {
       
   675             register_xdnd = False;
       
   676         }
       
   677     }
       
   678 
       
   679     if (register_xdnd) {
       
   680         ProxyRegistrationStatus xdnd_status;
       
   681         /* Grab server, since we are working with the window that belongs to
       
   682            another client. REMIND: ungrab when done!!! */
       
   683         XGrabServer(dpy);
       
   684 
       
   685         xdnd_status =
       
   686             set_xdnd_proxy(dpy, toplevel, awt_root_window, &xdnd_proxy,
       
   687                            &xdnd_protocol_version);
       
   688 
       
   689         XUngrabServer(dpy);
       
   690 
       
   691         switch (xdnd_status) {
       
   692         case RegFailure:
       
   693         case RegAlreadyRegistered:
       
   694             return;
       
   695         case RegOverride:
       
   696             xdnd_override = True;
       
   697             break;
       
   698         case RegSuccess:
       
   699             xdnd_override = False;
       
   700             break;
       
   701         default:
       
   702             DASSERT(False);
       
   703         }
       
   704 
       
   705         {
       
   706             EmbeddedDropSiteProtocolListEntry* xdnd_entry = NULL;
       
   707 
       
   708             xdnd_entry = malloc(sizeof(EmbeddedDropSiteProtocolListEntry));
       
   709 
       
   710             if (xdnd_entry == NULL) {
       
   711                 return;
       
   712             }
       
   713 
       
   714             xdnd_entry->window = toplevel;
       
   715             xdnd_entry->proxy = xdnd_proxy;
       
   716             xdnd_entry->protocol_version = xdnd_protocol_version;
       
   717             xdnd_entry->overriden = xdnd_override;
       
   718             xdnd_entry->next = embedded_xdnd_protocol_list;
       
   719             embedded_xdnd_protocol_list = xdnd_entry;
       
   720         }
       
   721     }
       
   722 }
       
   723 
       
   724 /*
       
   725  * If embedded_drop_site_list already contains an entry with the specified
       
   726  * 'toplevel', the method registers the specified 'window' as an embedded drop
       
   727  * site for this 'toplevel' and returns True.
       
   728  * Otherwise, it checks if the 'toplevel' is a registered drop site for adds
       
   729  * (window, component) pair to the list and returns True
       
   730  * if completes successfully.
       
   731  */
       
   732 static Boolean
       
   733 add_to_embedded_drop_site_list(Display* dpy, Window root, Window toplevel,
       
   734                                Window window) {
       
   735     EmbeddedDropSiteListEntry* entry = embedded_drop_site_list;
       
   736 
       
   737     while (entry != NULL) {
       
   738         if (entry->toplevel == toplevel) {
       
   739             void* p = realloc(entry->embedded_sites,
       
   740                               sizeof(Window) *
       
   741                               (entry->embedded_sites_count + 1));
       
   742             if (p == NULL) {
       
   743                 return False;
       
   744             }
       
   745             entry->embedded_sites = p;
       
   746             entry->embedded_sites[entry->embedded_sites_count++] = window;
       
   747 
       
   748             register_xdnd_embedder(dpy, entry, window);
       
   749 
       
   750             return True;
       
   751         }
       
   752         entry = entry->next;
       
   753     }
       
   754 
       
   755     entry = awt_dnd_dt_init_proxy(dpy, root, toplevel, window);
       
   756 
       
   757     if (entry == NULL) {
       
   758         return False;
       
   759     }
       
   760 
       
   761     register_xdnd_embedder(dpy, entry, window);
       
   762 
       
   763     entry->next = embedded_drop_site_list;
       
   764     embedded_drop_site_list = entry;
       
   765 
       
   766     return True;
       
   767 }
       
   768 
       
   769 /*
       
   770  * Removes the window from the list of embedded drop sites for the toplevel.
       
   771  * Returns True if the window was successfully removed, False otherwise.
       
   772  */
       
   773 static Boolean
       
   774 remove_from_embedded_drop_site_list(Display* dpy, Window toplevel, Window window) {
       
   775     EmbeddedDropSiteListEntry* entry = embedded_drop_site_list;
       
   776     EmbeddedDropSiteListEntry* prev = NULL;
       
   777 
       
   778     while (entry != NULL) {
       
   779         if (entry->toplevel == toplevel) {
       
   780             unsigned int idx;
       
   781 
       
   782             for (idx = 0; idx < entry->embedded_sites_count; idx++) {
       
   783                 if (entry->embedded_sites[idx] == window) {
       
   784                     int tail = entry->embedded_sites_count - idx - 1;
       
   785                     if (tail > 0) {
       
   786                         memmove(entry->embedded_sites + idx,
       
   787                                 entry->embedded_sites + idx + 1,
       
   788                                 tail * sizeof(Window));
       
   789                     }
       
   790                     entry->embedded_sites_count--;
       
   791 
       
   792                     /* If the list of embedded drop sites for this toplevel
       
   793                        becomes empty - restore the original proxies and remove
       
   794                        the entry. */
       
   795                     if (entry->embedded_sites_count == 0) {
       
   796                         Widget w = XtWindowToWidget(dpy, toplevel);
       
   797 
       
   798                         if (w != NULL) {
       
   799                             JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
   800                             Widget copy = w;
       
   801                             jobject peer = findPeer(&w);
       
   802 
       
   803                             if (!JNU_IsNull(env, peer) &&
       
   804                                 (*env)->IsInstanceOf(env, peer,
       
   805                                                      get_MEmbedCanvasPeerClass(env)) == JNI_TRUE) {
       
   806                                 remove_xembed_drop_target(env, peer);
       
   807                             }
       
   808                         } else {
       
   809                             EmbeddedDropSiteProtocolListEntry* xdnd_entry =
       
   810                                 get_xdnd_protocol_entry_for_toplevel(toplevel);
       
   811                             EmbeddedDropSiteProtocolListEntry* motif_entry =
       
   812                                 get_motif_protocol_entry_for_toplevel(toplevel);
       
   813 
       
   814                             if (xdnd_entry != NULL) {
       
   815                                 if (xdnd_entry->overriden == True) {
       
   816                                     XChangeProperty(dpy, toplevel, XA_XdndAware,
       
   817                                                     XA_ATOM, 32,
       
   818                                                     PropModeReplace,
       
   819                                                     (unsigned char*)&xdnd_entry->protocol_version,
       
   820                                                     1);
       
   821 
       
   822                                     XChangeProperty(dpy, toplevel, XA_XdndProxy,
       
   823                                                     XA_WINDOW, 32,
       
   824                                                     PropModeReplace,
       
   825                                                     (unsigned char*)&xdnd_entry->proxy, 1);
       
   826                                 } else {
       
   827                                     XDeleteProperty(dpy, toplevel, XA_XdndAware);
       
   828                                     XDeleteProperty(dpy, toplevel, XA_XdndProxy);
       
   829                                 }
       
   830                                 remove_xdnd_protocol_entry_for_toplevel(toplevel);
       
   831                             }
       
   832 
       
   833                             if (motif_entry != NULL) {
       
   834                                 if (motif_entry->overriden == True) {
       
   835                                     /* Request status */
       
   836                                     int status;
       
   837 
       
   838                                     Atom           type;
       
   839                                     int            format;
       
   840                                     unsigned long  nitems;
       
   841                                     unsigned long  after;
       
   842                                     unsigned char* data;
       
   843 
       
   844                                     data = NULL;
       
   845                                     status = XGetWindowProperty(dpy, toplevel,
       
   846                                                                 _XA_MOTIF_DRAG_RECEIVER_INFO, 0, 0xFFFF,
       
   847                                                                 False, AnyPropertyType, &type, &format,
       
   848                                                                 &nitems, &after, &data);
       
   849 
       
   850                                     if (status == Success && data != NULL && type != None &&
       
   851                                         format == 8 && nitems >= MOTIF_RECEIVER_INFO_SIZE) {
       
   852                                         unsigned char byte_order = read_card8((char*)data, 0);
       
   853                                         void* p = (char*)data + 4;
       
   854 
       
   855                                         DASSERT(MOTIF_BYTE_ORDER == byte_order);
       
   856 
       
   857                                         if (MOTIF_BYTE_ORDER == byte_order) {
       
   858                                             /* restore the original proxy window */
       
   859                                             write_card32(&p, motif_entry->proxy);
       
   860 
       
   861                                             XChangeProperty(dpy, toplevel,
       
   862                                                             _XA_MOTIF_DRAG_RECEIVER_INFO,
       
   863                                                             _XA_MOTIF_DRAG_RECEIVER_INFO, 8,
       
   864                                                             PropModeReplace,
       
   865                                                             (unsigned char*)data,
       
   866                                                             MOTIF_RECEIVER_INFO_SIZE);
       
   867                                         }
       
   868                                     }
       
   869 
       
   870                                     if (status == Success) {
       
   871                                         XFree(data);
       
   872                                     }
       
   873                                 } else {
       
   874                                     XDeleteProperty(dpy, toplevel, _XA_MOTIF_DRAG_RECEIVER_INFO);
       
   875                                 }
       
   876 
       
   877                                 remove_motif_protocol_entry_for_toplevel(toplevel);
       
   878                             }
       
   879 
       
   880                             if ((entry->event_mask & PropertyChangeMask) == 0) {
       
   881                                 XSelectInput(dpy, toplevel, entry->event_mask);
       
   882                             }
       
   883                         }
       
   884 
       
   885                         if (prev == NULL) {
       
   886                             embedded_drop_site_list = entry->next;
       
   887                         } else {
       
   888                             prev->next = entry->next;
       
   889                         }
       
   890 
       
   891                         free(entry);
       
   892                     }
       
   893                     return True;
       
   894                 }
       
   895             }
       
   896             return False;
       
   897         }
       
   898         prev = entry;
       
   899         entry = entry->next;
       
   900     }
       
   901     return False;
       
   902 }
       
   903 
       
   904 static EmbeddedDropSiteListEntry*
       
   905 get_entry_for_toplevel(Window toplevel) {
       
   906     EmbeddedDropSiteListEntry* entry = embedded_drop_site_list;
       
   907 
       
   908     while (entry != NULL) {
       
   909         if (entry->toplevel == toplevel) {
       
   910             return entry;
       
   911         }
       
   912         entry = entry->next;
       
   913     }
       
   914     return NULL;
       
   915 }
       
   916 
       
   917 static EmbeddedDropSiteProtocolListEntry*
       
   918 get_motif_protocol_entry_for_toplevel(Window toplevel) {
       
   919     EmbeddedDropSiteProtocolListEntry* entry = embedded_motif_protocol_list;
       
   920 
       
   921     while (entry != NULL) {
       
   922         if (entry->window == toplevel) {
       
   923             return entry;
       
   924         }
       
   925         entry = entry->next;
       
   926     }
       
   927     return NULL;
       
   928 }
       
   929 
       
   930 static EmbeddedDropSiteProtocolListEntry*
       
   931 get_xdnd_protocol_entry_for_toplevel(Window toplevel) {
       
   932     EmbeddedDropSiteProtocolListEntry* entry = embedded_xdnd_protocol_list;
       
   933 
       
   934     while (entry != NULL) {
       
   935         if (entry->window == toplevel) {
       
   936             return entry;
       
   937         }
       
   938         entry = entry->next;
       
   939     }
       
   940     return NULL;
       
   941 }
       
   942 
       
   943 static void
       
   944 remove_motif_protocol_entry_for_toplevel(Window toplevel) {
       
   945     EmbeddedDropSiteProtocolListEntry* entry = embedded_motif_protocol_list;
       
   946     EmbeddedDropSiteProtocolListEntry* prev_entry = NULL;
       
   947 
       
   948     while (entry != NULL) {
       
   949         if (entry->window == toplevel) {
       
   950             if (prev_entry != NULL) {
       
   951                 prev_entry->next = entry->next;
       
   952             } else {
       
   953                 embedded_motif_protocol_list = entry->next;
       
   954             }
       
   955             free(entry);
       
   956         }
       
   957         entry = entry->next;
       
   958         prev_entry = entry;
       
   959     }
       
   960 }
       
   961 
       
   962 static void
       
   963 remove_xdnd_protocol_entry_for_toplevel(Window toplevel) {
       
   964     EmbeddedDropSiteProtocolListEntry* entry = embedded_xdnd_protocol_list;
       
   965     EmbeddedDropSiteProtocolListEntry* prev_entry = NULL;
       
   966 
       
   967     while (entry != NULL) {
       
   968         if (entry->window == toplevel) {
       
   969             if (prev_entry != NULL) {
       
   970                 prev_entry->next = entry->next;
       
   971             } else {
       
   972                 embedded_xdnd_protocol_list = entry->next;
       
   973             }
       
   974             free(entry);
       
   975         }
       
   976         entry = entry->next;
       
   977     }
       
   978 }
       
   979 
       
   980 static Boolean
       
   981 is_embedding_toplevel(Window toplevel) {
       
   982     return get_entry_for_toplevel(toplevel) != NULL;
       
   983 }
       
   984 
       
   985 static Window
       
   986 get_embedded_window(Display* dpy, Window toplevel, int x, int y) {
       
   987     EmbeddedDropSiteListEntry* entry = get_entry_for_toplevel(toplevel);
       
   988 
       
   989     if (entry != NULL) {
       
   990         unsigned int idx;
       
   991 
       
   992         for (idx = 0; idx < entry->embedded_sites_count; idx++) {
       
   993             Window site = entry->embedded_sites[idx];
       
   994             Window child = None;
       
   995             int x_return, y_return;
       
   996 
       
   997             if (XTranslateCoordinates(dpy, entry->root, site, x, y,
       
   998                                       &x_return, &y_return, &child)) {
       
   999                 if (x_return >= 0 && y_return >= 0) {
       
  1000                     XWindowAttributes xwa;
       
  1001                     XGetWindowAttributes(dpy, site, &xwa);
       
  1002                     if (xwa.map_state != IsUnmapped &&
       
  1003                         x_return < xwa.width && y_return < xwa.height) {
       
  1004                         return site;
       
  1005                     }
       
  1006                 }
       
  1007             }
       
  1008         }
       
  1009     }
       
  1010 
       
  1011     return None;
       
  1012 }
       
  1013 
       
  1014 /*
       
  1015  * If the toplevel is not an embedding toplevel does nothing and returns False.
       
  1016  * Otherwise, sets xdnd_proxy for the specified toplevel to the 'proxy_window',
       
  1017  * xdnd_protocol_version to 'version', xdnd_override to 'override', returns True.
       
  1018  */
       
  1019 static Boolean
       
  1020 set_xdnd_proxy_for_toplevel(Window toplevel, Window proxy_window,
       
  1021                             unsigned int version, Boolean override) {
       
  1022     EmbeddedDropSiteProtocolListEntry* entry =
       
  1023         get_xdnd_protocol_entry_for_toplevel(toplevel);
       
  1024 
       
  1025     if (entry == NULL) {
       
  1026         return False;
       
  1027     }
       
  1028 
       
  1029     entry->proxy = proxy_window;
       
  1030     entry->protocol_version = version;
       
  1031     entry->overriden = override;
       
  1032 
       
  1033     return True;
       
  1034 }
       
  1035 
       
  1036 /*
       
  1037  * If the toplevel is not an embedding toplevel does nothing and returns False.
       
  1038  * Otherwise, sets motif_proxy for the specified toplevel to the proxy_window,
       
  1039  * motif_override to 'override' and returns True.
       
  1040  */
       
  1041 static Boolean
       
  1042 set_motif_proxy_for_toplevel(Window toplevel, Window proxy_window, Boolean override) {
       
  1043     EmbeddedDropSiteProtocolListEntry* entry =
       
  1044         get_motif_protocol_entry_for_toplevel(toplevel);
       
  1045 
       
  1046     if (entry == NULL) {
       
  1047         return False;
       
  1048     }
       
  1049 
       
  1050     entry->proxy = proxy_window;
       
  1051     entry->overriden = override;
       
  1052 
       
  1053     return True;
       
  1054 }
       
  1055 
       
  1056 /*
       
  1057  * Forwards a drag notification to the embedding toplevel modifying the event
       
  1058  * to match the protocol version supported by the toplevel.
       
  1059  * Returns True if the event is sent, False otherwise.
       
  1060  */
       
  1061 static Boolean
       
  1062 forward_client_message_to_toplevel(Window toplevel, XClientMessageEvent* event) {
       
  1063     EmbeddedDropSiteProtocolListEntry* protocol_entry = NULL;
       
  1064     Window proxy = None;
       
  1065 
       
  1066     if (event->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) {
       
  1067         protocol_entry = get_motif_protocol_entry_for_toplevel(toplevel);
       
  1068     } else {
       
  1069         /* Assume XDnD */
       
  1070         protocol_entry = get_xdnd_protocol_entry_for_toplevel(toplevel);
       
  1071         if (protocol_entry != NULL) {
       
  1072             /* Adjust the event to match the XDnD protocol version. */
       
  1073             unsigned int version = protocol_entry->protocol_version;
       
  1074             if (event->message_type == XA_XdndEnter) {
       
  1075                 unsigned int min_version = source_protocol_version < version ?
       
  1076                     source_protocol_version : version;
       
  1077                 event->data.l[1] = min_version << XDND_PROTOCOL_SHIFT;
       
  1078                 event->data.l[1] |= source_data_types_count > 3 ? XDND_DATA_TYPES_BIT : 0;
       
  1079             }
       
  1080         }
       
  1081     }
       
  1082 
       
  1083     if (protocol_entry == NULL) {
       
  1084         return False;
       
  1085     }
       
  1086 
       
  1087     if (!protocol_entry->overriden) {
       
  1088         return False;
       
  1089     }
       
  1090     proxy = protocol_entry->proxy;
       
  1091 
       
  1092     if (proxy == None) {
       
  1093         proxy = toplevel;
       
  1094     }
       
  1095 
       
  1096     event->window = toplevel;
       
  1097 
       
  1098     XSendEvent(event->display, proxy, False, NoEventMask, (XEvent*)event);
       
  1099 
       
  1100     return True;
       
  1101 }
       
  1102 
       
  1103 /******************************************************************************/
       
  1104 
       
  1105 /********************* Drop site list support *********************************/
       
  1106 
       
  1107 struct DropSiteListEntryRec;
       
  1108 
       
  1109 typedef struct DropSiteListEntryRec DropSiteListEntry;
       
  1110 
       
  1111 struct DropSiteListEntryRec {
       
  1112     Window             window;
       
  1113     Window             root;
       
  1114     /*
       
  1115      * The closest to the root ancestor with WM_STATE property set.
       
  1116      * Normally toplevel == window.
       
  1117      * In plugin scenario toplevel is the browser toplevel window.
       
  1118      */
       
  1119     Window             toplevel;
       
  1120     /*
       
  1121      * Java top-level position is the outer canvas position, not the shell
       
  1122      * window position. We need to keep the outer canvas ID (and the root ID) to
       
  1123      * translate from mouse position root coordinates to the Java component
       
  1124      * coordinates.
       
  1125      */
       
  1126     Window             outer_canvas;
       
  1127     jobject            component;
       
  1128     DropSiteListEntry* next;
       
  1129 };
       
  1130 
       
  1131 static DropSiteListEntry* drop_site_list = NULL;
       
  1132 
       
  1133 /*
       
  1134  * If drop_site_list already contains an entry with the same window,
       
  1135  * does nothing and returns False.
       
  1136  * Otherwise, adds a new entry the list and returns True
       
  1137  * if completes successfully.
       
  1138  */
       
  1139 static Boolean
       
  1140 add_to_drop_site_list(Window window, Window root, Window toplevel,
       
  1141                       Window outer_canvas, jobject component) {
       
  1142     DropSiteListEntry* entry = drop_site_list;
       
  1143 
       
  1144     while (entry != NULL) {
       
  1145         if (entry->window == window) {
       
  1146             return False;
       
  1147         }
       
  1148         entry = entry->next;
       
  1149     }
       
  1150 
       
  1151     entry = malloc(sizeof(DropSiteListEntry));
       
  1152 
       
  1153     if (entry == NULL) {
       
  1154         return False;
       
  1155     }
       
  1156 
       
  1157     entry->window = window;
       
  1158     entry->root = root;
       
  1159     entry->toplevel = toplevel;
       
  1160     entry->outer_canvas = outer_canvas;
       
  1161     entry->component = component;
       
  1162     entry->next = drop_site_list;
       
  1163     drop_site_list = entry;
       
  1164 
       
  1165     return True;
       
  1166 }
       
  1167 
       
  1168 /*
       
  1169  * Returns True if the list entry for the specified window has been successfully
       
  1170  * removed from the list. Otherwise, returns False.
       
  1171  */
       
  1172 static Boolean
       
  1173 remove_from_drop_site_list(Window window) {
       
  1174     DropSiteListEntry* entry = drop_site_list;
       
  1175     DropSiteListEntry* prev = NULL;
       
  1176 
       
  1177     while (entry != NULL) {
       
  1178         if (entry->window == window) {
       
  1179             if (prev != NULL) {
       
  1180                 prev->next = entry->next;
       
  1181             } else {
       
  1182                 drop_site_list = entry->next;
       
  1183             }
       
  1184             free(entry);
       
  1185             return True;
       
  1186         }
       
  1187         prev = entry;
       
  1188         entry = entry->next;
       
  1189     }
       
  1190 
       
  1191     return False;
       
  1192 }
       
  1193 
       
  1194 static jobject
       
  1195 get_component_for_window(Window window) {
       
  1196     DropSiteListEntry* entry = drop_site_list;
       
  1197 
       
  1198     while (entry != NULL) {
       
  1199         if (entry->window == window) {
       
  1200             return entry->component;
       
  1201         }
       
  1202         entry = entry->next;
       
  1203     }
       
  1204 
       
  1205     return NULL;
       
  1206 }
       
  1207 
       
  1208 static Window
       
  1209 get_root_for_window(Window window) {
       
  1210     DropSiteListEntry* entry = drop_site_list;
       
  1211 
       
  1212     while (entry != NULL) {
       
  1213         if (entry->window == window) {
       
  1214             return entry->root;
       
  1215         }
       
  1216         entry = entry->next;
       
  1217     }
       
  1218 
       
  1219     return None;
       
  1220 }
       
  1221 
       
  1222 static Window
       
  1223 get_toplevel_for_window(Window window) {
       
  1224     DropSiteListEntry* entry = drop_site_list;
       
  1225 
       
  1226     while (entry != NULL) {
       
  1227         if (entry->window == window) {
       
  1228             return entry->toplevel;
       
  1229         }
       
  1230         entry = entry->next;
       
  1231     }
       
  1232 
       
  1233     return None;
       
  1234 }
       
  1235 
       
  1236 static Window
       
  1237 get_outer_canvas_for_window(Window window) {
       
  1238     DropSiteListEntry* entry = drop_site_list;
       
  1239 
       
  1240     while (entry != NULL) {
       
  1241         if (entry->window == window) {
       
  1242             return entry->outer_canvas;
       
  1243         }
       
  1244         entry = entry->next;
       
  1245     }
       
  1246 
       
  1247     return None;
       
  1248 }
       
  1249 /******************************************************************************/
       
  1250 
       
  1251 /******************* Delayed drop site registration stuff *********************/
       
  1252 struct DelayedRegistrationEntryRec;
       
  1253 
       
  1254 typedef struct DelayedRegistrationEntryRec DelayedRegistrationEntry;
       
  1255 
       
  1256 struct DelayedRegistrationEntryRec {
       
  1257     Widget outer_canvas;
       
  1258     jobject component;
       
  1259     XtIntervalId timer;
       
  1260     DelayedRegistrationEntry* next;
       
  1261 };
       
  1262 
       
  1263 static DelayedRegistrationEntry* delayed_registration_list = NULL;
       
  1264 
       
  1265 static const int DELAYED_REGISTRATION_PERIOD = 500;
       
  1266 
       
  1267 /* Timer callback. */
       
  1268 static void
       
  1269 register_drop_site_later(XtPointer client_data, XtIntervalId* id);
       
  1270 
       
  1271 /*
       
  1272  * Enqueues the specified widget and component for delayed drop site
       
  1273  * registration. If this widget has already been registered, does nothing and
       
  1274  * returns False. Otherwise, schedules a timer callback that will repeatedly
       
  1275  * attempt to register the drop site until the registration succeeds.
       
  1276  * To remove this widget from the queue of delayed registration call
       
  1277  * remove_delayed_registration_entry().
       
  1278  *
       
  1279  * The caller must own AWT_LOCK.
       
  1280  */
       
  1281 static Boolean
       
  1282 add_delayed_registration_entry(Widget outer_canvas, XtPointer componentRef) {
       
  1283     DelayedRegistrationEntry* entry = delayed_registration_list;
       
  1284 
       
  1285     if (outer_canvas == NULL || componentRef == NULL) {
       
  1286         return False;
       
  1287     }
       
  1288 
       
  1289     while (entry != NULL && entry->outer_canvas != outer_canvas) {
       
  1290         entry = entry->next;
       
  1291     }
       
  1292 
       
  1293     if (entry != NULL) {
       
  1294         return False;
       
  1295     }
       
  1296 
       
  1297     entry = malloc(sizeof(DelayedRegistrationEntry));
       
  1298 
       
  1299     if (entry == NULL) {
       
  1300         return False;
       
  1301     }
       
  1302 
       
  1303     entry->outer_canvas = outer_canvas;
       
  1304     entry->component = componentRef;
       
  1305     entry->timer = XtAppAddTimeOut(awt_appContext, DELAYED_REGISTRATION_PERIOD,
       
  1306                                    register_drop_site_later, entry);
       
  1307     entry->next = delayed_registration_list;
       
  1308     delayed_registration_list = entry;
       
  1309 
       
  1310     return True;
       
  1311 }
       
  1312 
       
  1313 /*
       
  1314  * Unregisters the timer callback and removes this widget from the queue of
       
  1315  * delayed drop site registration.
       
  1316  *
       
  1317  * The caller must own AWT_LOCK.
       
  1318  */
       
  1319 static Boolean
       
  1320 remove_delayed_registration_entry(Widget outer_canvas) {
       
  1321     DelayedRegistrationEntry* entry = delayed_registration_list;
       
  1322     DelayedRegistrationEntry* prev = NULL;
       
  1323 
       
  1324     if (outer_canvas == NULL) {
       
  1325         return False;
       
  1326     }
       
  1327 
       
  1328     while (entry != NULL && entry->outer_canvas != outer_canvas) {
       
  1329         prev = entry;
       
  1330         entry = entry->next;
       
  1331     }
       
  1332 
       
  1333     if (entry == NULL) {
       
  1334         return False;
       
  1335     }
       
  1336 
       
  1337     if (prev != NULL) {
       
  1338         prev->next = entry->next;
       
  1339     } else {
       
  1340         delayed_registration_list = entry->next;
       
  1341     }
       
  1342 
       
  1343     if (entry->timer) {
       
  1344         XtRemoveTimeOut(entry->timer);
       
  1345         entry->timer = (XtIntervalId)0;
       
  1346     }
       
  1347 
       
  1348     free(entry);
       
  1349 
       
  1350     return True;
       
  1351 }
       
  1352 
       
  1353 static void
       
  1354 register_drop_site_later(XtPointer client_data, XtIntervalId* id) {
       
  1355     DelayedRegistrationEntry* entry = (DelayedRegistrationEntry*)client_data;
       
  1356 
       
  1357     if (XtIsRealized(entry->outer_canvas) &&
       
  1358         register_drop_site(entry->outer_canvas, entry->component)) {
       
  1359         remove_delayed_registration_entry(entry->outer_canvas);
       
  1360     } else {
       
  1361         entry->timer = XtAppAddTimeOut(awt_appContext, DELAYED_REGISTRATION_PERIOD,
       
  1362                                        register_drop_site_later, entry);
       
  1363     }
       
  1364 }
       
  1365 /******************************************************************************/
       
  1366 
       
  1367 static void
       
  1368 awt_dnd_cleanup() {
       
  1369     JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
  1370 
       
  1371     if (!JNU_IsNull(env, target_component)) {
       
  1372         /* Trigger dragExit */
       
  1373         /*
       
  1374          * Note: we pass NULL native context. This indicates that response
       
  1375          * shouldn't be sent to the source.
       
  1376          */
       
  1377         dt_postDropTargetEvent(env, target_component, 0, 0,
       
  1378                                java_awt_dnd_DnDConstants_ACTION_NONE,
       
  1379                                java_awt_event_MouseEvent_MOUSE_EXITED,
       
  1380                                NULL);
       
  1381     }
       
  1382 
       
  1383     if (motif_top_level_leave_postponed) {
       
  1384         XClientMessageEvent* leave = &motif_top_level_leave_postponed_event;
       
  1385         if (leave->type == ClientMessage) {
       
  1386             Window win = leave->window;
       
  1387             if (is_embedding_toplevel(win)) {
       
  1388                 forward_client_message_to_toplevel(win, leave);
       
  1389             }
       
  1390         }
       
  1391     }
       
  1392 
       
  1393     if (source_window != None) {
       
  1394         XSelectInput(awt_display, source_window, source_window_mask);
       
  1395     }
       
  1396 
       
  1397     source_protocol = NO_PROTOCOL;
       
  1398     source_protocol_version = 0;
       
  1399     source_window = None;
       
  1400     source_atom = None;
       
  1401     source_window_mask = 0;
       
  1402     source_actions = java_awt_dnd_DnDConstants_ACTION_NONE;
       
  1403     track_source_actions = False;
       
  1404     (*env)->DeleteGlobalRef(env, source_data_types);
       
  1405     source_data_types = NULL;
       
  1406     if (source_data_types_native != NULL) {
       
  1407         free(source_data_types_native);
       
  1408         source_data_types_native = NULL;
       
  1409     }
       
  1410     source_data_types_count = 0;
       
  1411     source_x = 0;
       
  1412     source_y = 0;
       
  1413     target_component = NULL;
       
  1414     motif_top_level_leave_postponed = False;
       
  1415     memset(&motif_top_level_leave_postponed_event, 0,
       
  1416            sizeof(XClientMessageEvent));
       
  1417 }
       
  1418 
       
  1419 static jlongArray
       
  1420 get_data_types_array(JNIEnv* env, Atom* types, unsigned int types_count) {
       
  1421     jlongArray array = NULL;
       
  1422     jboolean isCopy;
       
  1423     jlong*   jTargets;
       
  1424 #ifndef _LP64 /* Atom and jlong are different sizes in the 32-bit build */
       
  1425     unsigned int i;
       
  1426 #endif
       
  1427 
       
  1428     if ((*env)->PushLocalFrame(env, 1) < 0) {
       
  1429         return NULL;
       
  1430     }
       
  1431 
       
  1432     array = (*env)->NewLongArray(env, types_count);
       
  1433 
       
  1434     if (JNU_IsNull(env, array)) {
       
  1435         return NULL;
       
  1436     }
       
  1437 
       
  1438     if (types_count == 0) {
       
  1439         return array;
       
  1440     }
       
  1441 
       
  1442     jTargets = (*env)->GetLongArrayElements(env, array, &isCopy);
       
  1443     if (jTargets == NULL) {
       
  1444         (*env)->PopLocalFrame(env, NULL);
       
  1445         return NULL;
       
  1446     }
       
  1447 
       
  1448 #ifdef _LP64
       
  1449     memcpy(jTargets, types, types_count * sizeof(Atom));
       
  1450 #else
       
  1451     for (i = 0; i < types_count; i++) {
       
  1452         jTargets[i] = (types[i] & 0xFFFFFFFFLU);
       
  1453     }
       
  1454 #endif
       
  1455 
       
  1456     (*env)->ReleaseLongArrayElements(env, array, jTargets, 0);
       
  1457 
       
  1458     array = (*env)->NewGlobalRef(env, array);
       
  1459 
       
  1460     (*env)->PopLocalFrame(env, NULL);
       
  1461 
       
  1462     return array;
       
  1463 }
       
  1464 
       
  1465 static Boolean
       
  1466 is_xdnd_drag_message_type(unsigned long message_type) {
       
  1467     return message_type == XA_XdndEnter ||
       
  1468         message_type == XA_XdndPosition ||
       
  1469         message_type == XA_XdndLeave ||
       
  1470         message_type == XA_XdndDrop ? True : False;
       
  1471 }
       
  1472 
       
  1473 /*
       
  1474  * Returns EventConsume if the event should be consumed,
       
  1475  * EventPassAlong otherwise.
       
  1476  */
       
  1477 static EventStatus
       
  1478 handle_xdnd_enter(XClientMessageEvent* event) {
       
  1479     JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
  1480     Display* dpy = event->display;
       
  1481     long* event_data = event->data.l;
       
  1482     Window source_win = None;
       
  1483     long source_win_mask = 0;
       
  1484     unsigned int protocol_version = 0;
       
  1485     unsigned int data_types_count = 0;
       
  1486     Atom* data_types = NULL;
       
  1487     jlongArray java_data_types = NULL;
       
  1488     jint actions = java_awt_dnd_DnDConstants_ACTION_NONE;
       
  1489     Boolean track = False;
       
  1490 
       
  1491     DTRACE_PRINTLN5("%s:%d XdndEnter comp=%X src_win=%ld protocol=%d.",
       
  1492                     __FILE__, __LINE__,
       
  1493                     target_component, source_window, source_protocol);
       
  1494 
       
  1495     if (!JNU_IsNull(env, target_component) || source_window != None ||
       
  1496         source_protocol != NO_PROTOCOL) {
       
  1497         DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid state.",
       
  1498                         __FILE__, __LINE__);
       
  1499         return EventFailure;
       
  1500     }
       
  1501 
       
  1502     /*
       
  1503      * NOTE: the component can be NULL if the event was sent to the embedding
       
  1504      * toplevel.
       
  1505      */
       
  1506     if (JNU_IsNull(env, get_component_for_window(event->window)) &&
       
  1507         !is_embedding_toplevel(event->window)) {
       
  1508         DTRACE_PRINTLN2("%s:%d XdndEnter rejected - window is not a registered drop site.",
       
  1509                         __FILE__, __LINE__);
       
  1510         return EventFailure;
       
  1511     }
       
  1512 
       
  1513     protocol_version =
       
  1514         (event_data[1] & XDND_PROTOCOL_MASK) >> XDND_PROTOCOL_SHIFT;
       
  1515 
       
  1516     /* XDnD compliance only requires supporting version 3 and up. */
       
  1517     if (protocol_version < XDND_MIN_PROTOCOL_VERSION) {
       
  1518         DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid protocol version.",
       
  1519                         __FILE__, __LINE__);
       
  1520         return EventFailure;
       
  1521     }
       
  1522 
       
  1523     /* Ignore the source if the protocol version is higher than we support. */
       
  1524     if (protocol_version > XDND_PROTOCOL_VERSION) {
       
  1525         DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid protocol version.",
       
  1526                         __FILE__, __LINE__);
       
  1527         return EventFailure;
       
  1528     }
       
  1529 
       
  1530     source_win = event_data[0];
       
  1531 
       
  1532     /* Extract the list of supported actions. */
       
  1533     if (protocol_version < 2) {
       
  1534         /* Prior to XDnD version 2 only COPY action was supported. */
       
  1535         actions = java_awt_dnd_DnDConstants_ACTION_COPY;
       
  1536     } else {
       
  1537         unsigned char  ret;
       
  1538         Atom           type;
       
  1539         int            format;
       
  1540         unsigned long  nitems;
       
  1541         unsigned long  after;
       
  1542         unsigned char  *data;
       
  1543 
       
  1544         data = NULL;
       
  1545         ret = checked_XGetWindowProperty(dpy, source_win, XA_XdndActionList,
       
  1546                                          0, 0xFFFF, False, XA_ATOM, &type,
       
  1547                                          &format, &nitems, &after, &data);
       
  1548 
       
  1549         /* Ignore the source if the window is destroyed. */
       
  1550         if (ret == BadWindow) {
       
  1551             DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid window.",
       
  1552                             __FILE__, __LINE__);
       
  1553             return EventFailure;
       
  1554         }
       
  1555 
       
  1556         if (ret == Success) {
       
  1557             if (type == XA_ATOM && format == 32) {
       
  1558                 unsigned int i;
       
  1559                 Atom* action_atoms = (Atom*)data;
       
  1560 
       
  1561                 for (i = 0; i < nitems; i++) {
       
  1562                     actions |= xdnd_to_java_action(action_atoms[i]);
       
  1563                 }
       
  1564             }
       
  1565 
       
  1566             /*
       
  1567              * According to XDnD protocol, XdndActionList is optional.
       
  1568              * If XdndActionList is not set we try to guess which actions are
       
  1569              * supported.
       
  1570              */
       
  1571             if (type == None) {
       
  1572                 actions = java_awt_dnd_DnDConstants_ACTION_COPY;
       
  1573                 track = True;
       
  1574             }
       
  1575 
       
  1576             XFree(data);
       
  1577         }
       
  1578     }
       
  1579 
       
  1580     /* Extract the available data types. */
       
  1581     if (event_data[1] & XDND_DATA_TYPES_BIT) {
       
  1582         unsigned char  ret;
       
  1583         Atom           type;
       
  1584         int            format;
       
  1585         unsigned long  nitems;
       
  1586         unsigned long  after;
       
  1587         unsigned char  *data;
       
  1588 
       
  1589         data = NULL;
       
  1590         ret = checked_XGetWindowProperty(dpy, source_win, XA_XdndTypeList,
       
  1591                                          0, 0xFFFF, False, XA_ATOM, &type,
       
  1592                                          &format, &nitems, &after, &data);
       
  1593 
       
  1594         /* Ignore the source if the window is destroyed. */
       
  1595         if (ret == BadWindow) {
       
  1596             DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid window.",
       
  1597                             __FILE__, __LINE__);
       
  1598             return EventFailure;
       
  1599         }
       
  1600 
       
  1601         if (ret == Success) {
       
  1602             if (type == XA_ATOM && format == 32 && nitems > 0) {
       
  1603                 data_types_count = nitems;
       
  1604                 data_types = (Atom*)malloc(data_types_count * sizeof(Atom));
       
  1605 
       
  1606                 if (data_types == NULL) {
       
  1607                     XFree(data);
       
  1608                     DTRACE_PRINTLN2("%s:%d XdndEnter rejected - malloc fails.",
       
  1609                                     __FILE__, __LINE__);
       
  1610                     return EventFailure;
       
  1611                 }
       
  1612 
       
  1613                 memcpy((void *)data_types, (void *)data,
       
  1614                        data_types_count * sizeof(Atom));
       
  1615             }
       
  1616 
       
  1617             XFree(data);
       
  1618         }
       
  1619     } else {
       
  1620         int i;
       
  1621         data_types = (Atom*)malloc(3 * sizeof (Atom));
       
  1622         if (data_types == NULL) {
       
  1623             DTRACE_PRINTLN2("%s:%d XdndEnter rejected - malloc fails.",
       
  1624                             __FILE__, __LINE__);
       
  1625             return EventFailure;
       
  1626         }
       
  1627         for (i = 0; i < 3; i++) {
       
  1628             Atom j;
       
  1629             if ((j = event_data[2 + i]) != None) {
       
  1630                 data_types[data_types_count++] = j;
       
  1631             }
       
  1632         }
       
  1633     }
       
  1634 
       
  1635     java_data_types = get_data_types_array(env, data_types, data_types_count);
       
  1636 
       
  1637     if (JNU_IsNull(env, java_data_types)) {
       
  1638         DTRACE_PRINTLN2("%s:%d XdndEnter rejected - cannot create types array.",
       
  1639                         __FILE__, __LINE__);
       
  1640         free((char*)data_types);
       
  1641         return EventFailure;
       
  1642     }
       
  1643 
       
  1644     /*
       
  1645      * Select for StructureNotifyMask to receive DestroyNotify in case of source
       
  1646      * crash.
       
  1647      */
       
  1648     {
       
  1649         unsigned char ret;
       
  1650         XWindowAttributes xwa;
       
  1651 
       
  1652         XGetWindowAttributes(dpy, source_win, &xwa);
       
  1653 
       
  1654         source_win_mask = xwa.your_event_mask;
       
  1655 
       
  1656         ret = checked_XSelectInput(dpy, source_win,
       
  1657                                    (source_win_mask | StructureNotifyMask));
       
  1658 
       
  1659         if (ret == BadWindow) {
       
  1660             DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid window.",
       
  1661                             __FILE__, __LINE__);
       
  1662             free((char*)data_types);
       
  1663             (*env)->DeleteGlobalRef(env, java_data_types);
       
  1664             return EventFailure;
       
  1665         }
       
  1666     }
       
  1667 
       
  1668     /* Update the global state. */
       
  1669     source_protocol = XDND_PROTOCOL;
       
  1670     source_protocol_version = protocol_version;
       
  1671     source_window = source_win;
       
  1672     source_window_mask = source_win_mask;
       
  1673     source_actions = actions;
       
  1674     track_source_actions = track;
       
  1675     source_data_types = java_data_types;
       
  1676     source_data_types_native = data_types;
       
  1677     source_data_types_count = data_types_count;
       
  1678 
       
  1679     DTRACE_PRINTLN5("%s:%d XdndEnter handled src_win=%ld protocol=%d fmt=%d.",
       
  1680                     __FILE__, __LINE__,
       
  1681                     source_window, source_protocol, data_types_count);
       
  1682 
       
  1683     return EventSuccess;
       
  1684 }
       
  1685 
       
  1686 /*
       
  1687  * Returns EventConsume if the event should be consumed,
       
  1688  * EventPassAlong otherwise.
       
  1689  */
       
  1690 static EventStatus
       
  1691 handle_xdnd_position(XClientMessageEvent* event) {
       
  1692     JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
  1693     long* event_data = event->data.l;
       
  1694     Window source_win = None;
       
  1695     Time time_stamp = CurrentTime;
       
  1696     Atom action_atom = None;
       
  1697     jint action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
  1698     int x = 0;
       
  1699     int y = 0;
       
  1700     jint java_event_id = 0;
       
  1701     jobject component = NULL;
       
  1702     Window receiver = None;
       
  1703 
       
  1704     DTRACE_PRINTLN5("%s:%d XdndPosition comp=%X src_win=%ld protocol=%d.",
       
  1705                     __FILE__, __LINE__,
       
  1706                     target_component, source_window, source_protocol);
       
  1707 
       
  1708     if (source_protocol != XDND_PROTOCOL) {
       
  1709         DTRACE_PRINTLN2("%s:%d XdndPosition rejected - invalid state.",
       
  1710                         __FILE__, __LINE__);
       
  1711         return EventFailure;
       
  1712     }
       
  1713 
       
  1714     source_win = event_data[0];
       
  1715 
       
  1716     /* Ignore XDnD messages from all other windows. */
       
  1717     if (source_window != source_win) {
       
  1718         DTRACE_PRINTLN4("%s:%d XdndPosition rejected - invalid source window cur=%ld this=%ld.",
       
  1719                         __FILE__, __LINE__, source_window, source_win);
       
  1720         return EventFailure;
       
  1721     }
       
  1722 
       
  1723     x = event_data[2] >> 16;
       
  1724     y = event_data[2] & 0xFFFF;
       
  1725 
       
  1726     component = get_component_for_window(event->window);
       
  1727 
       
  1728     if (JNU_IsNull(env, component)) {
       
  1729         /*
       
  1730          * The window must be the embedding toplevel, since otherwise we would reject the
       
  1731          * XdndEnter and never get to this point.
       
  1732          */
       
  1733         DASSERT(is_embedding_toplevel(event->window));
       
  1734 
       
  1735         receiver = get_embedded_window(event->display, event->window, x, y);
       
  1736 
       
  1737         if (receiver != None) {
       
  1738             component = get_component_for_window(receiver);
       
  1739         }
       
  1740     } else {
       
  1741         receiver = event->window;
       
  1742     }
       
  1743 
       
  1744     /* Translate mouse position from root coordinates
       
  1745        to the target window coordinates. */
       
  1746     if (receiver != None) {
       
  1747         Window child = None;
       
  1748         XTranslateCoordinates(event->display,
       
  1749                               get_root_for_window(receiver),
       
  1750                               get_outer_canvas_for_window(receiver),
       
  1751                               x, y, &x, &y, &child);
       
  1752     }
       
  1753 
       
  1754     /* Time stamp - new in XDnD version 1. */
       
  1755     if (source_protocol_version > 0) {
       
  1756         time_stamp = event_data[3];
       
  1757     }
       
  1758 
       
  1759     /* User action - new in XDnD version 1. */
       
  1760     if (source_protocol_version > 1) {
       
  1761         action_atom = event_data[4];
       
  1762     } else {
       
  1763         /* The default action is XdndActionCopy */
       
  1764         action_atom = XA_XdndActionCopy;
       
  1765     }
       
  1766 
       
  1767     action = xdnd_to_java_action(action_atom);
       
  1768 
       
  1769     if (track_source_actions) {
       
  1770         source_actions |= action;
       
  1771     }
       
  1772 
       
  1773     if (JNU_IsNull(env, component)) {
       
  1774         if (!JNU_IsNull(env, target_component)) {
       
  1775             dt_postDropTargetEvent(env, target_component, x, y,
       
  1776                                    java_awt_dnd_DnDConstants_ACTION_NONE,
       
  1777                                    java_awt_event_MouseEvent_MOUSE_EXITED,
       
  1778                                    NULL);
       
  1779         }
       
  1780     } else {
       
  1781         if (JNU_IsNull(env, target_component)) {
       
  1782             java_event_id = java_awt_event_MouseEvent_MOUSE_ENTERED;
       
  1783         } else {
       
  1784             java_event_id = java_awt_event_MouseEvent_MOUSE_DRAGGED;
       
  1785         }
       
  1786 
       
  1787         dt_postDropTargetEvent(env, component, x, y, action,
       
  1788                                java_event_id, event);
       
  1789     }
       
  1790 
       
  1791     user_action = action;
       
  1792     source_x = x;
       
  1793     source_y = y;
       
  1794     target_component = component;
       
  1795 
       
  1796     return EventSuccess;
       
  1797 }
       
  1798 
       
  1799 /*
       
  1800  * Returns EventConsume if the event should be consumed,
       
  1801  * EventPassAlong otherwise.
       
  1802  */
       
  1803 static EventStatus
       
  1804 handle_xdnd_leave(XClientMessageEvent* event) {
       
  1805     JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
  1806     long* event_data = event->data.l;
       
  1807     Window source_win = None;
       
  1808 
       
  1809     if (source_protocol != XDND_PROTOCOL) {
       
  1810         DTRACE_PRINTLN2("%s:%d XdndLeave rejected - invalid state.",
       
  1811                         __FILE__, __LINE__);
       
  1812         return EventFailure;
       
  1813     }
       
  1814 
       
  1815     source_win = event_data[0];
       
  1816 
       
  1817     /* Ignore XDnD messages from all other windows. */
       
  1818     if (source_window != source_win) {
       
  1819         DTRACE_PRINTLN4("%s:%d XdndLeave rejected - invalid source window cur=%ld this=%ld.",
       
  1820                         __FILE__, __LINE__, source_window, source_win);
       
  1821         return EventFailure;
       
  1822     }
       
  1823 
       
  1824     awt_dnd_cleanup();
       
  1825 
       
  1826     return EventSuccess;
       
  1827 }
       
  1828 
       
  1829 /*
       
  1830  * Returns EventConsume if the event should be consumed,
       
  1831  * EventPassAlong otherwise.
       
  1832  */
       
  1833 static EventStatus
       
  1834 handle_xdnd_drop(XClientMessageEvent* event) {
       
  1835     JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
  1836     long* event_data = event->data.l;
       
  1837     Window source_win = None;
       
  1838 
       
  1839     DTRACE_PRINTLN5("%s:%d XdndDrop comp=%X src_win=%ld protocol=%d.",
       
  1840                     __FILE__, __LINE__,
       
  1841                     target_component, source_window, source_protocol);
       
  1842 
       
  1843     if (source_protocol != XDND_PROTOCOL) {
       
  1844         DTRACE_PRINTLN2("%s:%d XdndDrop rejected - invalid state.",
       
  1845                         __FILE__, __LINE__);
       
  1846         return EventFailure;
       
  1847     }
       
  1848 
       
  1849     source_win = event_data[0];
       
  1850 
       
  1851     /* Ignore XDnD messages from all other windows. */
       
  1852     if (source_window != source_win) {
       
  1853         DTRACE_PRINTLN4("%s:%d XdndDrop rejected - invalid source window cur=%ld this=%ld.",
       
  1854                         __FILE__, __LINE__, source_window, source_win);
       
  1855         return EventFailure;
       
  1856     }
       
  1857 
       
  1858     if (!JNU_IsNull(env, target_component)) {
       
  1859         dt_postDropTargetEvent(env, target_component, source_x, source_y, user_action,
       
  1860                                java_awt_event_MouseEvent_MOUSE_RELEASED, event);
       
  1861     }
       
  1862 
       
  1863     return EventSuccess;
       
  1864 }
       
  1865 
       
  1866 /*
       
  1867  * Returns EventPassAlong if the event should be passed to the original proxy.
       
  1868  * TOP_LEVEL_ENTER should be passed to the original proxy only if the event is
       
  1869  * invalid.
       
  1870  */
       
  1871 static EventStatus
       
  1872 handle_motif_top_level_enter(XClientMessageEvent* event) {
       
  1873     JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
  1874     Display* dpy = event->display;
       
  1875     char* event_data = event->data.b;
       
  1876     unsigned char event_byte_order = 0;
       
  1877     Window source_win = None;
       
  1878     long source_win_mask = 0;
       
  1879     unsigned int protocol_version = MOTIF_DND_PROTOCOL_VERSION;
       
  1880     Atom property_atom = None;
       
  1881     unsigned int data_types_count = 0;
       
  1882     Atom* data_types = NULL;
       
  1883     jlongArray java_data_types = NULL;
       
  1884 
       
  1885     DTRACE_PRINTLN5("%s:%d TOP_LEVEL_ENTER comp=%X src_win=%ld protocol=%d.",
       
  1886                     __FILE__, __LINE__,
       
  1887                     target_component, source_window, source_protocol);
       
  1888 
       
  1889     if (!JNU_IsNull(env, target_component) || source_window != None ||
       
  1890         source_protocol != NO_PROTOCOL) {
       
  1891         DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - invalid state.",
       
  1892                         __FILE__, __LINE__);
       
  1893         return EventFailure;
       
  1894     }
       
  1895 
       
  1896     if (JNU_IsNull(env, get_component_for_window(event->window)) &&
       
  1897         !is_embedding_toplevel(event->window)) {
       
  1898         DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - window is not a registered drop site.",
       
  1899                         __FILE__, __LINE__);
       
  1900         return EventFailure;
       
  1901     }
       
  1902 
       
  1903     event_byte_order = read_card8(event_data, 1);
       
  1904     source_win = read_card32(event_data, 8, event_byte_order);
       
  1905     property_atom = read_card32(event_data, 12, event_byte_order);
       
  1906 
       
  1907     /* Extract the available data types. */
       
  1908     {
       
  1909         unsigned char  ret;
       
  1910         Atom           type;
       
  1911         int            format;
       
  1912         unsigned long  nitems;
       
  1913         unsigned long  after;
       
  1914         unsigned char  *data;
       
  1915 
       
  1916         data = NULL;
       
  1917         ret = checked_XGetWindowProperty(dpy, source_win, property_atom, 0,
       
  1918                                          0xFFFF, False,
       
  1919                                          _XA_MOTIF_DRAG_INITIATOR_INFO, &type,
       
  1920                                          &format, &nitems, &after, &data);
       
  1921 
       
  1922         /* Ignore the source if the window is destroyed. */
       
  1923         if (ret == BadWindow) {
       
  1924             DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - invalid window.",
       
  1925                             __FILE__, __LINE__);
       
  1926             return EventFailure;
       
  1927         }
       
  1928 
       
  1929         if (ret == BadAtom) {
       
  1930             DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - invalid property atom.",
       
  1931                             __FILE__, __LINE__);
       
  1932             return EventFailure;
       
  1933         }
       
  1934 
       
  1935         if (ret == Success) {
       
  1936             if (type == _XA_MOTIF_DRAG_INITIATOR_INFO && format == 8 &&
       
  1937                 nitems == MOTIF_INITIATOR_INFO_SIZE) {
       
  1938                 unsigned char property_byte_order = read_card8((char*)data, 0);
       
  1939                 int index = read_card16((char*)data, 2, property_byte_order);
       
  1940 
       
  1941                 protocol_version = read_card8((char*)data, 1);
       
  1942 
       
  1943                 if (protocol_version > MOTIF_DND_PROTOCOL_VERSION) {
       
  1944                     DTRACE_PRINTLN3("%s:%d TOP_LEVEL_ENTER rejected - invalid protocol version: %d.",
       
  1945                                     __FILE__, __LINE__, protocol_version);
       
  1946                     XFree(data);
       
  1947                     return EventFailure;
       
  1948                 }
       
  1949 
       
  1950                 get_target_list_for_index(dpy, index, &data_types, &data_types_count);
       
  1951             }
       
  1952 
       
  1953             XFree(data);
       
  1954         }
       
  1955     }
       
  1956 
       
  1957     java_data_types = get_data_types_array(env, data_types, data_types_count);
       
  1958 
       
  1959     if (JNU_IsNull(env, java_data_types)) {
       
  1960         DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - cannot create types array.",
       
  1961                         __FILE__, __LINE__);
       
  1962         free((char*)data_types);
       
  1963         return EventFailure;
       
  1964     }
       
  1965 
       
  1966     /*
       
  1967      * Select for StructureNotifyMask to receive DestroyNotify in case of source
       
  1968      * crash.
       
  1969      */
       
  1970     {
       
  1971         unsigned char ret;
       
  1972         XWindowAttributes xwa;
       
  1973 
       
  1974         XGetWindowAttributes(dpy, source_win, &xwa);
       
  1975 
       
  1976         source_win_mask = xwa.your_event_mask;
       
  1977 
       
  1978         ret = checked_XSelectInput(dpy, source_win,
       
  1979                                    (source_win_mask | StructureNotifyMask));
       
  1980 
       
  1981         if (ret == BadWindow) {
       
  1982             DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid window.",
       
  1983                             __FILE__, __LINE__);
       
  1984             free((char*)data_types);
       
  1985             (*env)->DeleteGlobalRef(env, java_data_types);
       
  1986             return EventFailure;
       
  1987         }
       
  1988     }
       
  1989 
       
  1990     source_protocol = MOTIF_DND_PROTOCOL;
       
  1991     source_protocol_version = protocol_version;
       
  1992     source_window = source_win;
       
  1993     source_atom = property_atom;
       
  1994     source_window_mask = source_win_mask;
       
  1995     /*
       
  1996      * TOP_LEVEL_ENTER doesn't communicate the list of supported actions
       
  1997      * They are provided in DRAG_MOTION.
       
  1998      */
       
  1999     source_actions = java_awt_dnd_DnDConstants_ACTION_NONE;
       
  2000     track_source_actions = False;
       
  2001     source_data_types = java_data_types;
       
  2002     source_data_types_native = data_types;
       
  2003     source_data_types_count = data_types_count;
       
  2004     DTRACE_PRINTLN6("%s:%d TOP_LEVEL_ENTER comp=%d src_win=%ld protocol=%d fmt=%d.",
       
  2005                     __FILE__, __LINE__,
       
  2006                     target_component, source_window, source_protocol, data_types_count);
       
  2007 
       
  2008     return EventSuccess;
       
  2009 }
       
  2010 
       
  2011 /*
       
  2012  * Returns EventPassAlong if the event should be passed to the original proxy.
       
  2013  * DRAG_MOTION event shouldn't be passed to the original proxy only if it is
       
  2014  * a valid event and the mouse coordinates passed in it specify the point over
       
  2015  * a Java component in this JVM.
       
  2016  */
       
  2017 static EventStatus
       
  2018 handle_motif_drag_motion(XClientMessageEvent* event) {
       
  2019     JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
  2020     char* event_data = event->data.b;
       
  2021     unsigned char event_reason = 0;
       
  2022     unsigned char event_byte_order = 0;
       
  2023     Window source_win = None;
       
  2024     CARD16 flags = 0;
       
  2025     unsigned char motif_action = 0;
       
  2026     unsigned char motif_actions = 0;
       
  2027     jint java_action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
  2028     jint java_actions = java_awt_dnd_DnDConstants_ACTION_NONE;
       
  2029     int x = 0;
       
  2030     int y = 0;
       
  2031     jint java_event_id = 0;
       
  2032     jobject component = NULL;
       
  2033 
       
  2034     DTRACE_PRINTLN5("%s:%d DRAG_MOTION comp=%X src_win=%ld protocol=%d.",
       
  2035                     __FILE__, __LINE__,
       
  2036                     target_component, source_window, source_protocol);
       
  2037 
       
  2038     if (source_protocol != MOTIF_DND_PROTOCOL) {
       
  2039         DTRACE_PRINTLN2("%s:%d DRAG_MOTION rejected - invalid state.",
       
  2040                         __FILE__, __LINE__);
       
  2041         return EventFailure;
       
  2042     }
       
  2043 
       
  2044     event_reason = read_card8(event_data, 0) & MOTIF_MESSAGE_REASON_MASK;
       
  2045     event_byte_order = read_card8(event_data, 1);
       
  2046 
       
  2047     flags = read_card16(event_data, 2, event_byte_order);
       
  2048 
       
  2049     motif_action = (flags & MOTIF_DND_ACTION_MASK) >> MOTIF_DND_ACTION_SHIFT;
       
  2050     motif_actions = (flags & MOTIF_DND_ACTIONS_MASK) >> MOTIF_DND_ACTIONS_SHIFT;
       
  2051 
       
  2052     java_action = motif_to_java_actions(motif_action);
       
  2053     java_actions = motif_to_java_actions(motif_actions);
       
  2054 
       
  2055     /* Append source window id to the event data, so that we can send the
       
  2056        response properly. */
       
  2057     {
       
  2058         Window win = source_window;
       
  2059         void* p = &event->data.b[12];
       
  2060         if (event_byte_order != MOTIF_BYTE_ORDER) {
       
  2061             SWAP4BYTES(win);
       
  2062         }
       
  2063         write_card32(&p, (CARD32)win);
       
  2064     }
       
  2065 
       
  2066     component = get_component_for_window(event->window);
       
  2067 
       
  2068     if (event_reason == OPERATION_CHANGED) {
       
  2069         /* OPERATION_CHANGED event doesn't provide coordinates, so we use
       
  2070            previously stored position and component ref. */
       
  2071         x = source_x;
       
  2072         y = source_y;
       
  2073 
       
  2074         if (JNU_IsNull(env, component)) {
       
  2075             component = target_component;
       
  2076         }
       
  2077     } else {
       
  2078         Window receiver = None;
       
  2079 
       
  2080         x = read_card16(event_data, 8, event_byte_order);
       
  2081         y = read_card16(event_data, 10, event_byte_order);
       
  2082 
       
  2083         if (JNU_IsNull(env, component)) {
       
  2084             /*
       
  2085              * The window must be the embedding toplevel, since otherwise we
       
  2086              * would reject the TOP_LEVEL_ENTER and never get to this point.
       
  2087              */
       
  2088             DASSERT(is_embedding_toplevel(event->window));
       
  2089 
       
  2090             receiver = get_embedded_window(event->display, event->window, x, y);
       
  2091 
       
  2092             if (receiver != None) {
       
  2093                 component = get_component_for_window(receiver);
       
  2094             }
       
  2095         } else {
       
  2096             receiver = event->window;
       
  2097         }
       
  2098 
       
  2099         /* Translate mouse position from root coordinates
       
  2100            to the target window coordinates. */
       
  2101         if (receiver != None) {
       
  2102             Window child = None;
       
  2103             XTranslateCoordinates(event->display,
       
  2104                                   get_root_for_window(receiver),
       
  2105                                   get_outer_canvas_for_window(receiver),
       
  2106                                   x, y, &x, &y, &child);
       
  2107         }
       
  2108     }
       
  2109 
       
  2110     if (JNU_IsNull(env, component)) {
       
  2111         if (!JNU_IsNull(env, target_component)) {
       
  2112             /* Triggers dragExit */
       
  2113             dt_postDropTargetEvent(env, target_component, x, y,
       
  2114                                    java_awt_dnd_DnDConstants_ACTION_NONE,
       
  2115                                    java_awt_event_MouseEvent_MOUSE_EXITED,
       
  2116                                    NULL);
       
  2117         }
       
  2118     } else {
       
  2119         if (JNU_IsNull(env, target_component)) {
       
  2120             /* Triggers dragEnter */
       
  2121             java_event_id = java_awt_event_MouseEvent_MOUSE_ENTERED;
       
  2122         } else {
       
  2123             /* Triggers dragOver */
       
  2124             java_event_id = java_awt_event_MouseEvent_MOUSE_DRAGGED;
       
  2125         }
       
  2126 
       
  2127         dt_postDropTargetEvent(env, component, x, y, java_action, java_event_id,
       
  2128                                event);
       
  2129     }
       
  2130 
       
  2131     source_actions = java_actions;
       
  2132     track_source_actions = False;
       
  2133     user_action = java_action;
       
  2134     source_x = x;
       
  2135     source_y = y;
       
  2136     target_component = component;
       
  2137 
       
  2138     return EventSuccess;
       
  2139 }
       
  2140 
       
  2141 /*
       
  2142  * Returns EventPassAlong if the event should be passed to the original proxy.
       
  2143  * TOP_LEVEL_LEAVE should be passed to the original proxy only if the event
       
  2144  * is invalid.
       
  2145  */
       
  2146 static EventStatus
       
  2147 handle_motif_top_level_leave(XClientMessageEvent* event) {
       
  2148     JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
  2149     char* event_data = event->data.b;
       
  2150     unsigned char event_byte_order = 0;
       
  2151     Window source_win = None;
       
  2152 
       
  2153     DTRACE_PRINTLN5("%s:%d TOP_LEVEL_LEAVE comp=%X src_win=%ld protocol=%d.",
       
  2154                     __FILE__, __LINE__,
       
  2155                     target_component, source_window, source_protocol);
       
  2156 
       
  2157     if (source_protocol != MOTIF_DND_PROTOCOL) {
       
  2158         DTRACE_PRINTLN2("%s:%d TOP_LEVEL_LEAVE rejected - invalid state.",
       
  2159                         __FILE__, __LINE__);
       
  2160         return EventFailure;
       
  2161     }
       
  2162 
       
  2163     event_byte_order = read_card8(event_data, 1);
       
  2164     source_win = read_card32(event_data, 8, event_byte_order);
       
  2165 
       
  2166     /* Ignore Motif DnD messages from all other windows. */
       
  2167     if (source_window != source_win) {
       
  2168         DTRACE_PRINTLN4("%s:%d TOP_LEVEL_LEAVE rejected - invalid source window cur=%ld this=%ld.",
       
  2169                         __FILE__, __LINE__, source_window, source_win);
       
  2170         return EventFailure;
       
  2171     }
       
  2172 
       
  2173     /*
       
  2174      * Postpone upcall to java, so that we can abort it in case
       
  2175      * if drop immediatelly follows (see BugTraq ID 4395290).
       
  2176      * Send a dummy ClientMessage event to guarantee that a postponed java
       
  2177      * upcall will be processed.
       
  2178      */
       
  2179     motif_top_level_leave_postponed = True;
       
  2180     {
       
  2181         XClientMessageEvent dummy;
       
  2182         Window proxy;
       
  2183 
       
  2184         dummy.display      = event->display;
       
  2185         dummy.type         = ClientMessage;
       
  2186         dummy.window       = event->window;
       
  2187         dummy.format       = 32;
       
  2188         dummy.message_type = None;
       
  2189 
       
  2190         /*
       
  2191          * If this is an embedded drop site, the event should go to the
       
  2192          * awt_root_window as this is a proxy for all embedded drop sites.
       
  2193          * Otherwise the event should go to the event->window, as we don't use
       
  2194          * proxies for normal drop sites.
       
  2195          */
       
  2196         if (is_embedding_toplevel(event->window)) {
       
  2197             proxy = get_awt_root_window();
       
  2198         } else {
       
  2199             proxy = event->window;
       
  2200         }
       
  2201 
       
  2202         XSendEvent(event->display, proxy, False, NoEventMask,
       
  2203                    (XEvent*)&dummy);
       
  2204     }
       
  2205 
       
  2206     return EventSuccess;
       
  2207 }
       
  2208 
       
  2209 /*
       
  2210  * Returns EventPassAlong if the event should be passed to the original proxy.
       
  2211  * DROP_START event shouldn't be passed to the original proxy only if it is
       
  2212  * a valid event and the mouse coordinates passed in it specify the point over
       
  2213  * a Java component in this JVM.
       
  2214  */
       
  2215 static EventStatus
       
  2216 handle_motif_drop_start(XClientMessageEvent* event) {
       
  2217     JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
  2218     char* event_data = event->data.b;
       
  2219     unsigned char event_byte_order = 0;
       
  2220     Window source_win = None;
       
  2221     Atom property_atom = None;
       
  2222     CARD16 flags = 0;
       
  2223     unsigned char motif_action = 0;
       
  2224     unsigned char motif_actions = 0;
       
  2225     jint java_action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
  2226     jint java_actions = java_awt_dnd_DnDConstants_ACTION_NONE;
       
  2227     int x = 0;
       
  2228     int y = 0;
       
  2229     jobject component = NULL;
       
  2230     Window receiver = None;
       
  2231 
       
  2232     DTRACE_PRINTLN5("%s:%d DROP_START comp=%X src_win=%ld protocol=%d.",
       
  2233                     __FILE__, __LINE__,
       
  2234                     target_component, source_window, source_protocol);
       
  2235 
       
  2236     if (source_protocol != MOTIF_DND_PROTOCOL) {
       
  2237         DTRACE_PRINTLN2("%s:%d DROP_START rejected - invalid state.",
       
  2238                         __FILE__, __LINE__);
       
  2239         return EventFailure;
       
  2240     }
       
  2241 
       
  2242     event_byte_order = read_card8(event_data, 1);
       
  2243     source_win = read_card32(event_data, 16, event_byte_order);
       
  2244 
       
  2245     /* Ignore Motif DnD messages from all other windows. */
       
  2246     if (source_window != source_win) {
       
  2247         DTRACE_PRINTLN4("%s:%d DROP_START rejected - invalid source window cur=%ld this=%ld.",
       
  2248                         __FILE__, __LINE__, source_window, source_win);
       
  2249         return EventFailure;
       
  2250     }
       
  2251 
       
  2252     property_atom = read_card32(event_data, 12, event_byte_order);
       
  2253 
       
  2254     flags = read_card16(event_data, 2, event_byte_order);
       
  2255 
       
  2256     motif_action = (flags & MOTIF_DND_ACTION_MASK) >> MOTIF_DND_ACTION_SHIFT;
       
  2257     motif_actions = (flags & MOTIF_DND_ACTIONS_MASK) >> MOTIF_DND_ACTIONS_SHIFT;
       
  2258 
       
  2259     java_action = motif_to_java_actions(motif_action);
       
  2260     java_actions = motif_to_java_actions(motif_actions);
       
  2261 
       
  2262     x = read_card16(event_data, 8, event_byte_order);
       
  2263     y = read_card16(event_data, 10, event_byte_order);
       
  2264 
       
  2265     source_actions = java_actions;
       
  2266 
       
  2267     component = get_component_for_window(event->window);
       
  2268 
       
  2269     if (JNU_IsNull(env, component)) {
       
  2270         /*
       
  2271          * The window must be the embedding toplevel, since otherwise we would reject the
       
  2272          * TOP_LEVEL_ENTER and never get to this point.
       
  2273          */
       
  2274         DASSERT(is_embedding_toplevel(event->window));
       
  2275 
       
  2276         receiver = get_embedded_window(event->display, event->window, x, y);
       
  2277 
       
  2278         if (receiver != None) {
       
  2279             component = get_component_for_window(receiver);
       
  2280         }
       
  2281     } else {
       
  2282         receiver = event->window;
       
  2283     }
       
  2284 
       
  2285     /* Translate mouse position from root coordinates
       
  2286        to the target window coordinates. */
       
  2287     if (receiver != None) {
       
  2288         Window child = None;
       
  2289         XTranslateCoordinates(event->display,
       
  2290                               get_root_for_window(receiver),
       
  2291                               get_outer_canvas_for_window(receiver),
       
  2292                               x, y, &x, &y, &child);
       
  2293     }
       
  2294 
       
  2295     if (JNU_IsNull(env, component)) {
       
  2296         if (!JNU_IsNull(env, target_component)) {
       
  2297             /* Triggers dragExit */
       
  2298             dt_postDropTargetEvent(env, target_component, x, y,
       
  2299                                    java_awt_dnd_DnDConstants_ACTION_NONE,
       
  2300                                    java_awt_event_MouseEvent_MOUSE_EXITED,
       
  2301                                    NULL);
       
  2302         }
       
  2303     } else {
       
  2304         dt_postDropTargetEvent(env, component, x, y, java_action,
       
  2305                                java_awt_event_MouseEvent_MOUSE_RELEASED,
       
  2306                                event);
       
  2307     }
       
  2308 
       
  2309     return EventSuccess;
       
  2310 }
       
  2311 
       
  2312 static void
       
  2313 send_enter_message_to_toplevel(Window toplevel, XClientMessageEvent* xclient) {
       
  2314     XClientMessageEvent enter;
       
  2315 
       
  2316     if (source_protocol == XDND_PROTOCOL) {
       
  2317         enter.display = xclient->display;
       
  2318         enter.type = ClientMessage;
       
  2319         enter.window = toplevel;
       
  2320         enter.format = 32;
       
  2321         enter.message_type = XA_XdndEnter;
       
  2322         enter.data.l[0] = xclient->data.l[0]; /* XID of the source window */
       
  2323         enter.data.l[1] = source_protocol_version << XDND_PROTOCOL_SHIFT;
       
  2324         enter.data.l[1] |= source_data_types_count > 3 ? XDND_DATA_TYPES_BIT : 0;
       
  2325         enter.data.l[2] =
       
  2326             source_data_types_count > 0 ? source_data_types_native[0] : None;
       
  2327         enter.data.l[3] =
       
  2328             source_data_types_count > 1 ? source_data_types_native[1] : None;
       
  2329         enter.data.l[4] =
       
  2330             source_data_types_count > 2 ? source_data_types_native[2] : None;
       
  2331     } else if (source_protocol == MOTIF_DND_PROTOCOL) {
       
  2332         int reason = (int)(xclient->data.b[0] & MOTIF_MESSAGE_REASON_MASK);
       
  2333         unsigned char byte_order = xclient->data.b[1];
       
  2334 
       
  2335         enter.display = xclient->display;
       
  2336         enter.type = ClientMessage;
       
  2337         enter.window = toplevel;
       
  2338         enter.format = 8;
       
  2339         enter.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE;
       
  2340 
       
  2341         {
       
  2342             void* p = &enter.data.b[0];
       
  2343             int flags = 0;
       
  2344 
       
  2345             flags |= java_to_motif_actions(user_action) << MOTIF_DND_ACTION_SHIFT;
       
  2346             flags |= java_to_motif_actions(source_actions) << MOTIF_DND_ACTIONS_SHIFT;
       
  2347 
       
  2348             write_card8(&p, TOP_LEVEL_ENTER | MOTIF_MESSAGE_FROM_INITIATOR);
       
  2349             write_card8(&p, byte_order);
       
  2350             write_card16(&p, flags);
       
  2351             {
       
  2352                 Time time_stamp = read_card32(xclient->data.b, 4, byte_order);
       
  2353                 Window src_window = source_window;
       
  2354                 Atom motif_atom = _XA_MOTIF_ATOM_0;
       
  2355 
       
  2356                 if (byte_order != MOTIF_BYTE_ORDER) {
       
  2357                     SWAP4BYTES(time_stamp);
       
  2358                     SWAP4BYTES(src_window);
       
  2359                     SWAP4BYTES(motif_atom);
       
  2360                 }
       
  2361                 write_card32(&p, time_stamp);
       
  2362                 write_card32(&p, src_window);
       
  2363                 write_card32(&p, motif_atom);
       
  2364             }
       
  2365         }
       
  2366     } else {
       
  2367         return;
       
  2368     }
       
  2369 
       
  2370     forward_client_message_to_toplevel(toplevel, &enter);
       
  2371 }
       
  2372 
       
  2373 static void
       
  2374 send_leave_message_to_toplevel(Window toplevel, XClientMessageEvent* xclient) {
       
  2375     XClientMessageEvent leave;
       
  2376 
       
  2377     if (source_protocol == XDND_PROTOCOL) {
       
  2378         leave.display = xclient->display;
       
  2379         leave.type = ClientMessage;
       
  2380         leave.window = toplevel;
       
  2381         leave.format = 32;
       
  2382         leave.message_type = XA_XdndLeave;
       
  2383         leave.data.l[0] = xclient->data.l[0]; /* XID of the source window */
       
  2384         leave.data.l[1] = 0; /* flags */
       
  2385     } else if (source_protocol == MOTIF_DND_PROTOCOL) {
       
  2386         int reason = (int)(xclient->data.b[0] & MOTIF_MESSAGE_REASON_MASK);
       
  2387         unsigned char byte_order = xclient->data.b[1];
       
  2388 
       
  2389         leave.display = xclient->display;
       
  2390         leave.type = ClientMessage;
       
  2391         leave.window = toplevel;
       
  2392         leave.format = 8;
       
  2393         leave.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE;
       
  2394 
       
  2395         {
       
  2396             void* p = &leave.data.b[0];
       
  2397             int flags = 0;
       
  2398 
       
  2399             write_card8(&p, TOP_LEVEL_LEAVE | MOTIF_MESSAGE_FROM_INITIATOR);
       
  2400             write_card8(&p, byte_order);
       
  2401 
       
  2402             {
       
  2403                 Time time_stamp = read_card32(xclient->data.b, 4, byte_order);
       
  2404                 Window src_window = source_window;
       
  2405 
       
  2406                 if (byte_order != MOTIF_BYTE_ORDER) {
       
  2407                     SWAP4BYTES(time_stamp);
       
  2408                     SWAP4BYTES(src_window);
       
  2409                 }
       
  2410                 write_card32(&p, time_stamp);
       
  2411                 write_card32(&p, src_window);
       
  2412             }
       
  2413         }
       
  2414     } else {
       
  2415         return;
       
  2416     }
       
  2417 
       
  2418     forward_client_message_to_toplevel(toplevel, &leave);
       
  2419 }
       
  2420 
       
  2421 static void
       
  2422 post_process_client_message(XClientMessageEvent* xclient, EventStatus status,
       
  2423                             EventType type) {
       
  2424     Window win = xclient->window;
       
  2425     Boolean postponed_leave = motif_top_level_leave_postponed;
       
  2426 
       
  2427     motif_top_level_leave_postponed = False;
       
  2428 
       
  2429     if (is_embedding_toplevel(win)) {
       
  2430         Boolean server_grabbed = False;
       
  2431 
       
  2432         if (postponed_leave) {
       
  2433             XClientMessageEvent* leave = &motif_top_level_leave_postponed_event;
       
  2434             DASSERT(leave->type == ClientMessage && type == DropEvent);
       
  2435             /* Grab the server to ensure that no event is sent between
       
  2436                the TOP_LEVEL_LEAVE and the next message. */
       
  2437             XGrabServer(awt_display);
       
  2438             forward_client_message_to_toplevel(leave->window, leave);
       
  2439             memset(&motif_top_level_leave_postponed_event, 0,
       
  2440                    sizeof(XClientMessageEvent));
       
  2441         }
       
  2442 
       
  2443         /*
       
  2444          * This code forwards drag notifications to the browser according to the
       
  2445          * following rules:
       
  2446          *  - the messages that we failed to process are always forwarded to the
       
  2447          *    browser;
       
  2448          *  - MotionEvents and DropEvents are forwarded if and only if the drag
       
  2449          *    is not over a plugin window;
       
  2450          *  - XDnD: EnterEvents and LeaveEvents are never forwarded, instead, we
       
  2451          *    send synthesized EnterEvents or LeaveEvents when the drag
       
  2452          *    respectively exits or enters plugin windows;
       
  2453          *  - Motif DnD: EnterEvents and LeaveEvents are always forwarded.
       
  2454          * Synthetic EnterEvents and LeaveEvents are needed, because the XDnD drop
       
  2455          * site implemented Netscape 6.2 has a nice feature: when it receives
       
  2456          * the first XdndPosition it continuously sends XdndStatus messages to
       
  2457          * the source (every 100ms) until the drag terminates or leaves the drop
       
  2458          * site. When the mouse is dragged over plugin window embedded in the
       
  2459          * browser frame, these XdndStatus messages are mixed with the XdndStatus
       
  2460          * messages sent from the plugin.
       
  2461          * For Motif DnD, synthetic events cause Motif warnings being displayed,
       
  2462          * so these events are always forwarded. However, Motif DnD drop site in
       
  2463          * Netscape 6.2 is implemented in the same way, so there could be similar
       
  2464          * problems if the drag source choose Motif DnD for communication.
       
  2465          */
       
  2466         switch (status) {
       
  2467         case EventFailure:
       
  2468             forward_client_message_to_toplevel(win, xclient);
       
  2469             break;
       
  2470         case EventSuccess:
       
  2471         {
       
  2472             /* True iff the previous notification was MotionEvent and it was
       
  2473                forwarded to the browser. */
       
  2474             static Boolean motion_passed_along = False;
       
  2475 
       
  2476             Boolean motif_protocol =
       
  2477                 xclient->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE;
       
  2478 
       
  2479             switch (type) {
       
  2480             case MotionEvent:
       
  2481                 if (JNU_IsNull(env, target_component)) {
       
  2482                     if (!motion_passed_along && !motif_protocol) {
       
  2483                         send_enter_message_to_toplevel(win, xclient);
       
  2484                     }
       
  2485                     forward_client_message_to_toplevel(win, xclient);
       
  2486                     motion_passed_along = True;
       
  2487                 } else {
       
  2488                     if (motion_passed_along && !motif_protocol) {
       
  2489                         send_leave_message_to_toplevel(win, xclient);
       
  2490                     }
       
  2491                     motion_passed_along = False;
       
  2492                 }
       
  2493                 break;
       
  2494             case DropEvent:
       
  2495                 if (JNU_IsNull(env, target_component)) {
       
  2496                     forward_client_message_to_toplevel(win, xclient);
       
  2497                     /* The last chance to cleanup. */
       
  2498                     awt_dnd_cleanup();
       
  2499                 }
       
  2500                 motion_passed_along = False;
       
  2501                 break;
       
  2502             case EnterEvent:
       
  2503             case LeaveEvent:
       
  2504                 if (motif_protocol) {
       
  2505                     forward_client_message_to_toplevel(win, xclient);
       
  2506                 }
       
  2507                 motion_passed_along = False;
       
  2508                 break;
       
  2509             }
       
  2510         }
       
  2511         }
       
  2512 
       
  2513         if (postponed_leave) {
       
  2514             XUngrabServer(awt_display);
       
  2515         }
       
  2516     }
       
  2517 }
       
  2518 
       
  2519 /*
       
  2520  * Returns True if the event is processed and shouldn't be passed along to Java.
       
  2521  * Otherwise, return False.
       
  2522  */
       
  2523 Boolean
       
  2524 awt_dnd_dt_process_event(XEvent* event) {
       
  2525     Display* dpy = event->xany.display;
       
  2526     EventStatus status = EventFailure;
       
  2527     EventType type = UnknownEvent;
       
  2528 
       
  2529     if (event->type == DestroyNotify) {
       
  2530         if (event->xany.window == source_window) {
       
  2531             awt_dnd_cleanup();
       
  2532         }
       
  2533         /* pass along */
       
  2534         return False;
       
  2535     }
       
  2536 
       
  2537     if (event->type == PropertyNotify) {
       
  2538         if (is_embedding_toplevel(event->xany.window)) {
       
  2539             Atom atom = event->xproperty.atom;
       
  2540             /*
       
  2541              * If some other client replaced the XDnD or Motif DnD proxy with
       
  2542              * another window we set the proxy back to the awt_root_window
       
  2543              * and update the entry in the embedded_drop_site_list.
       
  2544              * This code is needed, as for example Netscape 4.7 resets the proxy
       
  2545              * when the browser shell is resized.
       
  2546              */
       
  2547             if (atom == _XA_MOTIF_DRAG_RECEIVER_INFO) {
       
  2548                 Window prev_motif_proxy;
       
  2549                 ProxyRegistrationStatus status;
       
  2550                 status = set_motif_proxy(event->xany.display, event->xany.window,
       
  2551                                          get_awt_root_window(), &prev_motif_proxy);
       
  2552                 if (status != RegFailure && status != RegAlreadyRegistered) {
       
  2553                     set_motif_proxy_for_toplevel(event->xany.window,
       
  2554                                                  prev_motif_proxy,
       
  2555                                                  status == RegOverride);
       
  2556                 }
       
  2557             }
       
  2558 
       
  2559             if (atom == XA_XdndAware || atom == XA_XdndProxy) {
       
  2560                 Window prev_xdnd_proxy;
       
  2561                 unsigned int prev_protocol_version;
       
  2562                 ProxyRegistrationStatus status;
       
  2563                 status = set_xdnd_proxy(event->xany.display, event->xany.window,
       
  2564                                         get_awt_root_window(), &prev_xdnd_proxy,
       
  2565                                         &prev_protocol_version);
       
  2566                 if (status != RegFailure && status != RegAlreadyRegistered) {
       
  2567                     set_xdnd_proxy_for_toplevel(event->xany.window,
       
  2568                                                 prev_xdnd_proxy,
       
  2569                                                 prev_protocol_version,
       
  2570                                                 status == RegOverride);
       
  2571                 }
       
  2572             }
       
  2573         }
       
  2574         /* pass along */
       
  2575         return False;
       
  2576     }
       
  2577 
       
  2578     if (event->type != ClientMessage) {
       
  2579         return False;
       
  2580     }
       
  2581 
       
  2582     if (get_component_for_window(event->xany.window) == NULL &&
       
  2583         !is_embedding_toplevel(event->xany.window)) {
       
  2584         return False;
       
  2585     }
       
  2586 
       
  2587     if (motif_top_level_leave_postponed) {
       
  2588         /* Sanity check. */
       
  2589         if (source_protocol != MOTIF_DND_PROTOCOL) {
       
  2590             DTRACE_PRINTLN2("%s:%d TOP_LEVEL_LEAVE rejected - invalid state.",
       
  2591                             __FILE__, __LINE__);
       
  2592             awt_dnd_cleanup();
       
  2593         } else if (event->xclient.message_type ==
       
  2594                    _XA_MOTIF_DRAG_AND_DROP_MESSAGE) {
       
  2595             unsigned char first_byte = event->xclient.data.b[0];
       
  2596             unsigned char reason = first_byte & MOTIF_MESSAGE_REASON_MASK;
       
  2597             unsigned char origin = first_byte & MOTIF_MESSAGE_SENDER_MASK;
       
  2598 
       
  2599             if (origin == MOTIF_MESSAGE_FROM_INITIATOR &&
       
  2600                 reason != DROP_START) {
       
  2601                 awt_dnd_cleanup();
       
  2602             }
       
  2603         } else {
       
  2604             awt_dnd_cleanup();
       
  2605         }
       
  2606     }
       
  2607 
       
  2608     if (event->xclient.message_type == XA_XdndEnter) {
       
  2609         status = handle_xdnd_enter(&event->xclient);
       
  2610         type = EnterEvent;
       
  2611     } else if (event->xclient.message_type == XA_XdndPosition) {
       
  2612         status = handle_xdnd_position(&event->xclient);
       
  2613         type = MotionEvent;
       
  2614     } else if (event->xclient.message_type == XA_XdndLeave) {
       
  2615         status = handle_xdnd_leave(&event->xclient);
       
  2616         type = LeaveEvent;
       
  2617     } else if (event->xclient.message_type == XA_XdndDrop) {
       
  2618         status = handle_xdnd_drop(&event->xclient);
       
  2619         type = DropEvent;
       
  2620     } else if (event->xclient.message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) {
       
  2621         unsigned char reason = event->xclient.data.b[0] & MOTIF_MESSAGE_REASON_MASK;
       
  2622         unsigned char origin = event->xclient.data.b[0] & MOTIF_MESSAGE_SENDER_MASK;
       
  2623 
       
  2624         /* Only initiator messages should be handled. */
       
  2625         if (origin == MOTIF_MESSAGE_FROM_INITIATOR) {
       
  2626             switch (reason) {
       
  2627             case DRAG_MOTION:
       
  2628             case OPERATION_CHANGED:
       
  2629                 status = handle_motif_drag_motion(&event->xclient);
       
  2630                 type = MotionEvent;
       
  2631                 break;
       
  2632             case TOP_LEVEL_ENTER:
       
  2633                 status = handle_motif_top_level_enter(&event->xclient);
       
  2634                 type = EnterEvent;
       
  2635                 break;
       
  2636             case TOP_LEVEL_LEAVE:
       
  2637                 status = handle_motif_top_level_leave(&event->xclient);
       
  2638                 type = LeaveEvent;
       
  2639                 break;
       
  2640             case DROP_START:
       
  2641                 status = handle_motif_drop_start(&event->xclient);
       
  2642                 type = DropEvent;
       
  2643                 break;
       
  2644             }
       
  2645         }
       
  2646     } else {
       
  2647         /* Unknown message type. */
       
  2648         return False;
       
  2649     }
       
  2650 
       
  2651     /*
       
  2652      * We need to handle a special case here: Motif DnD protocol prescribed that
       
  2653      * DROP_START message should always be preceeded with TOP_LEVEL_LEAVE
       
  2654      * message. We need to cleanup on TOP_LEVEL_LEAVE message, but DROP_START
       
  2655      * wouldn't be processed properly. Instead we postpone the cleanup and
       
  2656      * send a dummy client message to ourselves. If dummy arrives first we do a
       
  2657      * normal cleanup. If DROP_START arrives before the dummy we discard delayed
       
  2658      * cleanup.
       
  2659      * In case of forwarding events from an embedded Java app to an embedding
       
  2660      * Java app it could happen that the embedding app receives the dummy before
       
  2661      * the DROP_START message arrives from the embedding app. In this case the
       
  2662      * drop operation on the embedding app fails to complete.
       
  2663      * To resolve this problem we postpone forwarding of TOP_LEVEL_LEAVE message
       
  2664      * until the next client message is about to be forwarded.
       
  2665      */
       
  2666     if (motif_top_level_leave_postponed && type == LeaveEvent) {
       
  2667         /* motif_top_level_leave_postponed can be set only if the latest client
       
  2668            message has been processed successfully. */
       
  2669         DASSERT(status == EventSuccess);
       
  2670         memcpy(&motif_top_level_leave_postponed_event, &event->xclient,
       
  2671                sizeof(XClientMessageEvent));
       
  2672     } else {
       
  2673         post_process_client_message(&event->xclient, status, type);
       
  2674     }
       
  2675 
       
  2676     return True;
       
  2677 }
       
  2678 
       
  2679 static Boolean
       
  2680 register_xdnd_drop_site(Display* dpy, Window toplevel, Window window) {
       
  2681     unsigned char ret;
       
  2682     Atom version_atom = XDND_PROTOCOL_VERSION;
       
  2683 
       
  2684     ret = checked_XChangeProperty(dpy, window, XA_XdndAware, XA_ATOM, 32,
       
  2685                                   PropModeReplace,
       
  2686                                   (unsigned char*)&version_atom, 1);
       
  2687 
       
  2688     return (ret == Success);
       
  2689 }
       
  2690 
       
  2691 static Boolean
       
  2692 register_motif_drop_site(Display* dpy, Window toplevel, Window window) {
       
  2693     unsigned char status;
       
  2694     size_t data_size = MOTIF_RECEIVER_INFO_SIZE;
       
  2695     char* data = malloc(data_size);
       
  2696     void* p = data;
       
  2697 
       
  2698     if (data == NULL) {
       
  2699         DTRACE_PRINTLN2("%s:%d malloc failed.", __FILE__, __LINE__);
       
  2700         return False;
       
  2701     }
       
  2702 
       
  2703     write_card8(&p, MOTIF_BYTE_ORDER);
       
  2704     write_card8(&p, MOTIF_DND_PROTOCOL_VERSION); /* protocol version */
       
  2705     write_card8(&p, MOTIF_DYNAMIC_STYLE); /* protocol style */
       
  2706     write_card8(&p, 0); /* pad */
       
  2707     write_card32(&p, window); /* proxy window */
       
  2708     write_card16(&p, 0); /* num_drop_sites */
       
  2709     write_card16(&p, 0); /* pad */
       
  2710     write_card32(&p, data_size);
       
  2711 
       
  2712     status = checked_XChangeProperty(dpy, window, _XA_MOTIF_DRAG_RECEIVER_INFO,
       
  2713                                      _XA_MOTIF_DRAG_RECEIVER_INFO, 8, PropModeReplace,
       
  2714                                      (unsigned char*)data, data_size);
       
  2715 
       
  2716     free(data);
       
  2717 
       
  2718     return (status == Success);
       
  2719 }
       
  2720 
       
  2721 static Window
       
  2722 find_toplevel_window(Display* dpy, Window window) {
       
  2723     Window         ret = None;
       
  2724     Window         root = None;
       
  2725     Window         parent = None;
       
  2726     Window         *children;
       
  2727     unsigned int   nchildren;
       
  2728 
       
  2729     int            status;
       
  2730 
       
  2731     Atom           type;
       
  2732     int            format;
       
  2733     unsigned long  nitems;
       
  2734     unsigned long  after;
       
  2735     unsigned char  *data;
       
  2736 
       
  2737     /* Traverse the ancestor tree from window up to the root and find
       
  2738        the top-level client window nearest to the root. */
       
  2739     do {
       
  2740         type = None;
       
  2741 
       
  2742         data = NULL;
       
  2743         status = XGetWindowProperty(dpy, window, XA_WM_STATE, 0, 0, False,
       
  2744                                     AnyPropertyType, &type, &format, &nitems,
       
  2745                                     &after, &data);
       
  2746 
       
  2747         if (status == Success) {
       
  2748             XFree(data);
       
  2749         }
       
  2750 
       
  2751         if (type != None) {
       
  2752             ret = window;
       
  2753         }
       
  2754 
       
  2755         if (!XQueryTree(dpy, window, &root, &parent, &children, &nchildren)) {
       
  2756             return None;
       
  2757         }
       
  2758 
       
  2759         XFree(children);
       
  2760 
       
  2761         window = parent;
       
  2762     } while (window != root);
       
  2763 
       
  2764     return ret;
       
  2765 }
       
  2766 
       
  2767 static Boolean
       
  2768 register_drop_site(Widget outer_canvas, XtPointer componentRef) {
       
  2769     Display* dpy = XtDisplay(outer_canvas);
       
  2770     Widget shell = NULL;
       
  2771     /* Shell window. */
       
  2772     Window window = None;
       
  2773     Window root = None;
       
  2774     Window toplevel = None;
       
  2775 
       
  2776     for (shell = outer_canvas; shell != NULL && !XtIsShell(shell);
       
  2777          shell = XtParent(shell));
       
  2778 
       
  2779     if (shell == NULL || !XtIsRealized(shell)) {
       
  2780         DTRACE_PRINTLN2("%s:%d Cannot find a realized shell for the widget.",
       
  2781                        __FILE__, __LINE__);
       
  2782         return False;
       
  2783     }
       
  2784 
       
  2785     window = XtWindow(shell);
       
  2786 
       
  2787     if (!awt_dnd_init(dpy)) {
       
  2788         DTRACE_PRINTLN2("%s:%d Fail to initialize.", __FILE__, __LINE__);
       
  2789         return False;
       
  2790     }
       
  2791 
       
  2792     {
       
  2793         XWindowAttributes xwa;
       
  2794 
       
  2795         if (!XGetWindowAttributes(dpy, window, &xwa)) {
       
  2796             DTRACE_PRINTLN2("%s:%d XGetWindowAttributes failed.", __FILE__, __LINE__);
       
  2797             return False;
       
  2798         }
       
  2799 
       
  2800         root = xwa.root;
       
  2801 
       
  2802         if (root == None) {
       
  2803             DTRACE_PRINTLN2("%s:%d Bad root.", __FILE__, __LINE__);
       
  2804             return False;
       
  2805         }
       
  2806     }
       
  2807 
       
  2808     toplevel = find_toplevel_window(dpy, window);
       
  2809 
       
  2810     /*
       
  2811      * No window with WM_STATE property is found.
       
  2812      * Since the window can be a plugin window reparented to the browser
       
  2813      * toplevel, we cannot determine which window will eventually have WM_STATE
       
  2814      * property set. So we schedule a timer callback that will periodically
       
  2815      * attempt to find an ancestor with WM_STATE and register the drop site
       
  2816      * appropriately.
       
  2817      */
       
  2818     if (toplevel == None) {
       
  2819         add_delayed_registration_entry(outer_canvas, componentRef);
       
  2820         return False;
       
  2821     }
       
  2822 
       
  2823     if (toplevel == window) {
       
  2824         Boolean xdnd_registered = False;
       
  2825         Boolean motif_registered = False;
       
  2826 
       
  2827         xdnd_registered = register_xdnd_drop_site(dpy, toplevel, window);
       
  2828 
       
  2829         motif_registered = register_motif_drop_site(dpy, toplevel, window);
       
  2830 
       
  2831         if (!xdnd_registered && !motif_registered) {
       
  2832             DTRACE_PRINTLN2("%s:%d Failed to register.", __FILE__, __LINE__);
       
  2833             return False;
       
  2834         }
       
  2835     } else {
       
  2836         if (!add_to_embedded_drop_site_list(dpy, root, toplevel, window)) {
       
  2837             DTRACE_PRINTLN2("%s:%d Failed to init proxy.", __FILE__, __LINE__);
       
  2838             return False;
       
  2839         }
       
  2840     }
       
  2841 
       
  2842     /* There is no need to update the window for the component later, since the
       
  2843        window is destroyed only when the component is disposed in which case the
       
  2844        drop site will be unregistered as well. */
       
  2845     if (add_to_drop_site_list(window, root, toplevel, XtWindow(outer_canvas),
       
  2846                               (jobject)componentRef)) {
       
  2847         DTRACE_PRINTLN2("%s:%d Drop site registered.", __FILE__, __LINE__);
       
  2848         return True;
       
  2849     } else {
       
  2850         DTRACE_PRINTLN2("%s:%d Failed to register.", __FILE__, __LINE__);
       
  2851         return False;
       
  2852     }
       
  2853 }
       
  2854 
       
  2855 static void
       
  2856 register_drop_site_when_realized(Widget outer_canvas, XtPointer client_data,
       
  2857                                  XEvent *event, Boolean *dontSwallow) {
       
  2858     if (XtIsRealized(outer_canvas)) {
       
  2859         XtRemoveEventHandler(outer_canvas, StructureNotifyMask, False,
       
  2860                              register_drop_site_when_realized, client_data);
       
  2861 
       
  2862         register_drop_site(outer_canvas, client_data);
       
  2863     }
       
  2864 }
       
  2865 
       
  2866 /*
       
  2867  * Registers the top-level Window that contains the specified widget as a drop
       
  2868  * site that supports XDnD and Motif DnD protocols.
       
  2869  * If the registration fails for some reason, adds an event handler that will
       
  2870  * attempt to register the drop site later.
       
  2871  *
       
  2872  * Returns True if the drop site is registered successfully.
       
  2873  */
       
  2874 static Boolean
       
  2875 awt_dnd_register_drop_site(Widget outer_canvas, XtPointer componentRef) {
       
  2876     if (XtIsRealized(outer_canvas)) {
       
  2877         return register_drop_site(outer_canvas, componentRef);
       
  2878     } else {
       
  2879         XtAddEventHandler(outer_canvas, StructureNotifyMask, False,
       
  2880                           register_drop_site_when_realized,
       
  2881                           componentRef);
       
  2882 
       
  2883         DTRACE_PRINTLN2("%s:%d Unrealized shell. Register later.",
       
  2884                         __FILE__, __LINE__);
       
  2885 
       
  2886         return True;
       
  2887     }
       
  2888 }
       
  2889 
       
  2890 /*
       
  2891  * Unregisters the drop site associated with the top-level Window that contains
       
  2892  * the specified widget .
       
  2893  *
       
  2894  * Returns True if completes successfully, False otherwise.
       
  2895  */
       
  2896 static Boolean
       
  2897 awt_dnd_unregister_drop_site(Widget outer_canvas, XtPointer componentRef) {
       
  2898     Widget shell = NULL;
       
  2899 
       
  2900     XtRemoveEventHandler(outer_canvas, StructureNotifyMask, False,
       
  2901                          register_drop_site_when_realized, componentRef);
       
  2902 
       
  2903     remove_delayed_registration_entry(outer_canvas);
       
  2904 
       
  2905     for (shell = outer_canvas; shell != NULL && !XtIsShell(shell);
       
  2906          shell = XtParent(shell));
       
  2907 
       
  2908     if (shell != NULL && XtIsShell(shell) && XtIsRealized(shell)) {
       
  2909         Window win = XtWindow(shell);
       
  2910         Window toplevel = get_toplevel_for_window(win);
       
  2911         /*
       
  2912          * Cleanup the global state if this drop site participate in the current
       
  2913          * drag operation. Particularly, this allows to delete global ref to the
       
  2914          * component safely.
       
  2915          */
       
  2916         if (get_component_for_window(win) == target_component) {
       
  2917             awt_dnd_cleanup();
       
  2918         }
       
  2919         if (toplevel != win) {
       
  2920             remove_from_embedded_drop_site_list(awt_display, toplevel, win);
       
  2921         }
       
  2922         return remove_from_drop_site_list(win);
       
  2923     }
       
  2924 
       
  2925     return True;
       
  2926 }
       
  2927 
       
  2928 /**************************** XEmbed server DnD support ***********************/
       
  2929 
       
  2930 /*
       
  2931  *
       
  2932  *
       
  2933  */
       
  2934 Boolean
       
  2935 register_xembed_drop_site(JNIEnv* env, Display* dpy, jobject server,
       
  2936                           Window serverHandle, Window clientHandle) {
       
  2937     Atom           type;
       
  2938     int            format;
       
  2939     unsigned long  nitems;
       
  2940     unsigned long  after;
       
  2941     unsigned char* data;
       
  2942     unsigned char  ret;
       
  2943     unsigned int   protocol_version;
       
  2944 
       
  2945     Window         xdnd_proxy = None;
       
  2946     unsigned int   xdnd_protocol_version = 0;
       
  2947     Boolean        xdnd_override = False;
       
  2948 
       
  2949     if (!awt_dnd_init(dpy)) {
       
  2950         DTRACE_PRINTLN2("%s:%d Fail to initialize.", __FILE__, __LINE__);
       
  2951         return False;
       
  2952     }
       
  2953 
       
  2954     /* Get the XDnD protocol version and XDnD proxy of the XEmbed client. */
       
  2955     data = NULL;
       
  2956     ret = checked_XGetWindowProperty(dpy, clientHandle, XA_XdndAware, 0, 1,
       
  2957                                      False, AnyPropertyType, &type, &format,
       
  2958                                      &nitems, &after, &data);
       
  2959 
       
  2960     /* XEmbed client doesn't have an associated XDnD drop site -
       
  2961        do nothing and return True to indicate success. */
       
  2962     if (ret != Success || data == NULL || nitems == 0 || type != XA_ATOM) {
       
  2963         XFree(data);
       
  2964         return False;
       
  2965     }
       
  2966 
       
  2967     protocol_version = *((unsigned int*)data);
       
  2968 
       
  2969     XFree(data);
       
  2970 
       
  2971     if (protocol_version < XDND_MIN_PROTOCOL_VERSION) {
       
  2972         return False;
       
  2973     }
       
  2974 
       
  2975     xdnd_protocol_version = protocol_version;
       
  2976 
       
  2977     /* XdndProxy is not supported prior to XDnD version 4 */
       
  2978     if (protocol_version >= 4) {
       
  2979         int status;
       
  2980 
       
  2981         data = NULL;
       
  2982         status = XGetWindowProperty(dpy, clientHandle, XA_XdndProxy, 0, 1,
       
  2983                                     False, XA_WINDOW, &type, &format,
       
  2984                                     &nitems, &after, &data);
       
  2985 
       
  2986         if (status == Success && data != NULL && type == XA_WINDOW) {
       
  2987             xdnd_proxy = *((Window*)data);
       
  2988 
       
  2989             if (xdnd_proxy != None) {
       
  2990                 XFree(data);
       
  2991 
       
  2992                 data = NULL;
       
  2993                 status = XGetWindowProperty(dpy, xdnd_proxy, XA_XdndProxy,
       
  2994                                             0, 1, False, XA_WINDOW, &type,
       
  2995                                             &format, &nitems, &after,
       
  2996                                             &data);
       
  2997 
       
  2998                 if (status != Success || data == NULL || type != XA_WINDOW ||
       
  2999                     *((Window*)data) != xdnd_proxy) {
       
  3000                     /* Ignore invalid proxy. */
       
  3001                     xdnd_proxy = None;
       
  3002                 }
       
  3003             }
       
  3004 
       
  3005             if (xdnd_proxy != None) {
       
  3006                 XFree(data);
       
  3007 
       
  3008                 data = NULL;
       
  3009                 status = XGetWindowProperty(dpy, xdnd_proxy, XA_XdndAware, 0, 1,
       
  3010                                             False, AnyPropertyType, &type,
       
  3011                                             &format, &nitems, &after, &data);
       
  3012 
       
  3013                 if (status == Success && data != NULL && type == XA_ATOM) {
       
  3014                     unsigned int proxy_version = *((unsigned int*)data);
       
  3015 
       
  3016                     if (proxy_version != protocol_version) {
       
  3017                         /* Ignore invalid proxy. */
       
  3018                         xdnd_proxy = None;
       
  3019                     }
       
  3020                 } else {
       
  3021                     /* Ignore invalid proxy. */
       
  3022                     xdnd_proxy = None;
       
  3023                 }
       
  3024             }
       
  3025         }
       
  3026 
       
  3027         XFree(data);
       
  3028     }
       
  3029 
       
  3030     set_xembed_drop_target(env, server);
       
  3031 
       
  3032     /* Add protocol specific entries for the embedded window. */
       
  3033     /* Only XDnD protocol is supported for XEmbed clients. */
       
  3034     {
       
  3035         EmbeddedDropSiteProtocolListEntry* xdnd_entry = NULL;
       
  3036 
       
  3037         xdnd_entry = malloc(sizeof(EmbeddedDropSiteProtocolListEntry));
       
  3038 
       
  3039         if (xdnd_entry == NULL) {
       
  3040             return False;
       
  3041         }
       
  3042 
       
  3043         xdnd_entry->window = clientHandle;
       
  3044         xdnd_entry->proxy = xdnd_proxy;
       
  3045         xdnd_entry->protocol_version = xdnd_protocol_version;
       
  3046         xdnd_entry->overriden = True;
       
  3047         xdnd_entry->next = embedded_xdnd_protocol_list;
       
  3048         embedded_xdnd_protocol_list = xdnd_entry;
       
  3049     }
       
  3050 
       
  3051     {
       
  3052         EmbeddedDropSiteListEntry* entry = NULL;
       
  3053         Window* sites = NULL;
       
  3054 
       
  3055         entry = malloc(sizeof(EmbeddedDropSiteListEntry));
       
  3056 
       
  3057         if (entry == NULL) {
       
  3058             return False;
       
  3059         }
       
  3060 
       
  3061         sites = malloc(sizeof(Window));
       
  3062 
       
  3063         if (sites == NULL) {
       
  3064             free(entry);
       
  3065             return False;
       
  3066         }
       
  3067 
       
  3068         sites[0] = clientHandle;
       
  3069 
       
  3070         entry->toplevel = serverHandle;
       
  3071         entry->root = None;
       
  3072         entry->event_mask = 0;
       
  3073         entry->embedded_sites_count = 1;
       
  3074         entry->embedded_sites = sites;
       
  3075         entry->next = embedded_drop_site_list;
       
  3076         embedded_drop_site_list = entry;
       
  3077     }
       
  3078 
       
  3079     return True;
       
  3080 }
       
  3081 
       
  3082 Boolean
       
  3083 unregister_xembed_drop_site(JNIEnv* env, Display* dpy, jobject server,
       
  3084                             Window serverHandle, Window clientHandle) {
       
  3085     remove_from_embedded_drop_site_list(dpy, serverHandle, clientHandle);
       
  3086     return True;
       
  3087 }
       
  3088 
       
  3089 void
       
  3090 forward_event_to_embedded(Window embedded, jlong ctxt, jint eventID) {
       
  3091     static XClientMessageEvent* prevMessage = NULL;
       
  3092     static Boolean overXEmbedClient = False;
       
  3093 
       
  3094     XClientMessageEvent* xclient =
       
  3095         (XClientMessageEvent*)jlong_to_ptr(ctxt);
       
  3096 
       
  3097     if (xclient == NULL && prevMessage == NULL) {
       
  3098         return;
       
  3099     }
       
  3100 
       
  3101     if (xclient != NULL) {
       
  3102         /*
       
  3103          * NOTE: this check guarantees that prevMessage will always be an XDnD
       
  3104          * drag message.
       
  3105          */
       
  3106         if (!is_xdnd_drag_message_type(xclient->message_type)) {
       
  3107             return;
       
  3108         }
       
  3109 
       
  3110         if (!overXEmbedClient) {
       
  3111             long* appended_data = jlong_to_ptr(ctxt) +
       
  3112                 sizeof(XClientMessageEvent);
       
  3113 
       
  3114             /* Copy XdndTypeList from source to proxy. */
       
  3115             if ((appended_data[0] & XDND_DATA_TYPES_BIT) != 0) {
       
  3116                 unsigned char  ret;
       
  3117                 Atom           type;
       
  3118                 int            format;
       
  3119                 unsigned long  nitems;
       
  3120                 unsigned long  after;
       
  3121                 unsigned char  *data;
       
  3122 
       
  3123                 data = NULL;
       
  3124                 ret = checked_XGetWindowProperty(xclient->display,
       
  3125                                                  xclient->data.l[0],
       
  3126                                                  XA_XdndTypeList, 0, 0xFFFF,
       
  3127                                                  False, XA_ATOM, &type, &format,
       
  3128                                                  &nitems, &after, &data);
       
  3129 
       
  3130                 /* Ignore the source if the window is destroyed. */
       
  3131                 if (ret == BadWindow) {
       
  3132                     return;
       
  3133                 }
       
  3134 
       
  3135                 if (ret == Success) {
       
  3136                     if (type == XA_ATOM && format == 32) {
       
  3137                         ret = checked_XChangeProperty(xclient->display,
       
  3138                                                       xclient->window,
       
  3139                                                       XA_XdndTypeList, XA_ATOM,
       
  3140                                                       32, PropModeReplace, data,
       
  3141                                                       nitems);
       
  3142                     }
       
  3143 
       
  3144                     XFree(data);
       
  3145                 }
       
  3146             }
       
  3147 
       
  3148             set_proxy_mode_source_window(xclient->data.l[0]);
       
  3149 
       
  3150             {
       
  3151                 XClientMessageEvent enter;
       
  3152                 enter.display = xclient->display;
       
  3153                 enter.type = ClientMessage;
       
  3154                 enter.window = embedded;
       
  3155                 enter.format = 32;
       
  3156                 enter.message_type = XA_XdndEnter;
       
  3157 
       
  3158                 enter.data.l[0] = xclient->window; /* XID of the source window */
       
  3159                 enter.data.l[1] = appended_data[0];
       
  3160                 enter.data.l[2] = appended_data[1];
       
  3161                 enter.data.l[3] = appended_data[2];
       
  3162                 enter.data.l[4] = appended_data[3];
       
  3163 
       
  3164                 forward_client_message_to_toplevel(embedded, &enter);
       
  3165             }
       
  3166 
       
  3167             overXEmbedClient = True;
       
  3168         }
       
  3169 
       
  3170         /* Make a copy of the original event, since we are going to modify the
       
  3171            event while it still can be referenced from other Java events. */
       
  3172         {
       
  3173             XClientMessageEvent copy;
       
  3174             memcpy(&copy, xclient, sizeof(XClientMessageEvent));
       
  3175             copy.data.l[0] = xclient->window;
       
  3176 
       
  3177             forward_client_message_to_toplevel(embedded, &copy);
       
  3178         }
       
  3179     }
       
  3180 
       
  3181     if (eventID == java_awt_event_MouseEvent_MOUSE_EXITED) {
       
  3182         if (overXEmbedClient) {
       
  3183             if (xclient != NULL || prevMessage != NULL) {
       
  3184                 /* Last chance to send XdndLeave to the XEmbed client. */
       
  3185                 XClientMessageEvent leave;
       
  3186 
       
  3187                 leave.display = xclient != NULL ?
       
  3188                     xclient->display : prevMessage->display;
       
  3189                 leave.type = ClientMessage;
       
  3190                 leave.window = embedded;
       
  3191                 leave.format = 32;
       
  3192                 leave.message_type = XA_XdndLeave;
       
  3193                 leave.data.l[0] = xclient != NULL ?
       
  3194                     xclient->window : prevMessage->window; /* XID of the source window */
       
  3195                 leave.data.l[1] = 0; /* flags */
       
  3196 
       
  3197                 forward_client_message_to_toplevel(embedded, &leave);
       
  3198             }
       
  3199             overXEmbedClient = False;
       
  3200         }
       
  3201     }
       
  3202 
       
  3203     if (eventID == java_awt_event_MouseEvent_MOUSE_RELEASED) {
       
  3204         overXEmbedClient = False;
       
  3205         awt_dnd_cleanup();
       
  3206     }
       
  3207 
       
  3208     if (prevMessage != 0) {
       
  3209         free(prevMessage);
       
  3210         prevMessage = 0;
       
  3211     }
       
  3212 
       
  3213     if (xclient != 0 && overXEmbedClient) {
       
  3214         prevMessage = malloc(sizeof(XClientMessageEvent));
       
  3215 
       
  3216         memcpy(prevMessage, xclient, sizeof(XClientMessageEvent));
       
  3217     }
       
  3218 }
       
  3219 
       
  3220 /******************************************************************************/
       
  3221 
       
  3222 /*
       
  3223  * Class:     sun_awt_motif_MWindowPeer
       
  3224  * Method:    registerX11DropTarget
       
  3225  * Signature: (Ljava/awt/Component;)V
       
  3226  */
       
  3227 
       
  3228 JNIEXPORT void JNICALL
       
  3229 Java_sun_awt_motif_MWindowPeer_registerX11DropTarget(JNIEnv *env, jobject this,
       
  3230                                                      jobject target) {
       
  3231     struct FrameData* wdata = NULL;
       
  3232     DropSitePtr dsi = NULL;
       
  3233 
       
  3234     wdata = (struct FrameData *)
       
  3235         JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData);
       
  3236 
       
  3237     if (wdata == NULL || wdata->winData.comp.widget == NULL) {
       
  3238         JNU_ThrowNullPointerException(env, "NULL component data");
       
  3239         return;
       
  3240     }
       
  3241 
       
  3242     if (wdata->winData.shell == NULL) {
       
  3243         JNU_ThrowNullPointerException(env, "Null shell widget");
       
  3244         return;
       
  3245     }
       
  3246 
       
  3247     DASSERT(wdata->winData.comp.dsi == NULL);
       
  3248 
       
  3249     dsi = (DropSitePtr)calloc(1, sizeof(struct DropSiteInfo));
       
  3250 
       
  3251     if (dsi == NULL) {
       
  3252         JNU_ThrowOutOfMemoryError(env, "");
       
  3253         return;
       
  3254     }
       
  3255 
       
  3256     dsi->component = (*env)->NewGlobalRef(env, target);
       
  3257     dsi->isComposite = False;
       
  3258 
       
  3259     wdata->winData.comp.dsi = dsi;
       
  3260 
       
  3261     AWT_LOCK();
       
  3262 
       
  3263     awt_dnd_register_drop_site(wdata->winData.comp.widget,
       
  3264                                dsi->component);
       
  3265 
       
  3266     AWT_UNLOCK();
       
  3267 }
       
  3268 
       
  3269 /*
       
  3270  * Class:     sun_awt_motif_MWindowPeer
       
  3271  * Method:    unregisterX11DropTarget
       
  3272  * Signature: (Ljava/awt/Component;)V
       
  3273  */
       
  3274 
       
  3275 JNIEXPORT void JNICALL
       
  3276 Java_sun_awt_motif_MWindowPeer_unregisterX11DropTarget(JNIEnv *env,
       
  3277                                                        jobject this,
       
  3278                                                        jobject target) {
       
  3279     struct FrameData* wdata = NULL;
       
  3280     DropSitePtr dsi = NULL;
       
  3281 
       
  3282     wdata = (struct FrameData *)
       
  3283         JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData);
       
  3284 
       
  3285     if (wdata == NULL) {
       
  3286         JNU_ThrowNullPointerException(env, "Null component data");
       
  3287         return;
       
  3288     }
       
  3289 
       
  3290     if (wdata->winData.shell == NULL) {
       
  3291         JNU_ThrowNullPointerException(env, "Null shell widget");
       
  3292         return;
       
  3293     }
       
  3294 
       
  3295     dsi = wdata->winData.comp.dsi;
       
  3296 
       
  3297     if (dsi == NULL) {
       
  3298         JNU_ThrowNullPointerException(env, "Null DropSiteInfo");
       
  3299         return;
       
  3300     }
       
  3301 
       
  3302     AWT_LOCK();
       
  3303 
       
  3304     awt_dnd_unregister_drop_site(wdata->winData.comp.widget, dsi->component);
       
  3305 
       
  3306     AWT_UNLOCK();
       
  3307 
       
  3308     wdata->winData.comp.dsi = NULL;
       
  3309 
       
  3310     (*env)->DeleteGlobalRef(env, dsi->component);
       
  3311 
       
  3312     free(dsi);
       
  3313 }
       
  3314 
       
  3315 static void
       
  3316 dt_send_event_to_source(XClientMessageEvent* xclient) {
       
  3317     /* Shortcut if the source is in the same JVM. */
       
  3318     if (xclient->window == awt_dnd_ds_get_source_window()) {
       
  3319         awt_dnd_ds_process_event((XEvent*)xclient);
       
  3320     } else {
       
  3321         unsigned char ret;
       
  3322 
       
  3323         ret = checked_XSendEvent(xclient->display, xclient->window, False,
       
  3324                                  NoEventMask, (XEvent*)xclient);
       
  3325 
       
  3326         if (ret == BadWindow) {
       
  3327             DTRACE_PRINTLN2("%s:%d XSendEvent - invalid window.",
       
  3328                             __FILE__, __LINE__);
       
  3329 
       
  3330             /* Cleanup if we are still communicating with this window. */
       
  3331             if (source_window == xclient->window) {
       
  3332                 awt_dnd_cleanup();
       
  3333             }
       
  3334         }
       
  3335     }
       
  3336 }
       
  3337 
       
  3338 static void
       
  3339 dt_send_response(XClientMessageEvent* xclient, jint eventID, jint action) {
       
  3340     Display* dpy = xclient->display;
       
  3341     XClientMessageEvent response;
       
  3342 
       
  3343     if (xclient->message_type == XA_XdndPosition) {
       
  3344         long* event_data = xclient->data.l;
       
  3345 
       
  3346         if (eventID == java_awt_event_MouseEvent_MOUSE_EXITED) {
       
  3347             action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
  3348         }
       
  3349 
       
  3350         response.display = dpy;
       
  3351         response.type = ClientMessage;
       
  3352         response.window = event_data[0];
       
  3353         response.format = 32;
       
  3354         response.message_type = XA_XdndStatus;
       
  3355         /* target window */
       
  3356         response.data.l[0] = xclient->window;
       
  3357         /* flags */
       
  3358         response.data.l[1] = 0;
       
  3359         if (action != java_awt_dnd_DnDConstants_ACTION_NONE) {
       
  3360             response.data.l[1] |= XDND_ACCEPT_DROP_FLAG;
       
  3361         }
       
  3362         /* specify an empty rectangle */
       
  3363         response.data.l[2] = 0; /* x, y */
       
  3364         response.data.l[3] = 0; /* w, h */
       
  3365         /* action accepted by the target */
       
  3366         response.data.l[4] = java_to_xdnd_action(action);
       
  3367     } else if (xclient->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) {
       
  3368         int reason = (int)(xclient->data.b[0] & MOTIF_MESSAGE_REASON_MASK);
       
  3369         int origin = (int)(xclient->data.b[0] & MOTIF_MESSAGE_SENDER_MASK);
       
  3370         unsigned char byte_order = xclient->data.b[1];
       
  3371         CARD16 response_flags = 0;
       
  3372         CARD8 response_reason = 0;
       
  3373         void* p = &response.data.b;
       
  3374 
       
  3375         /* Only initiator messages should be handled. */
       
  3376         if (origin != MOTIF_MESSAGE_FROM_INITIATOR) {
       
  3377             DTRACE_PRINTLN2("%s:%d Receiver message.", __FILE__, __LINE__);
       
  3378             return;
       
  3379         }
       
  3380 
       
  3381         switch (reason) {
       
  3382         case DRAG_MOTION:
       
  3383             switch (eventID) {
       
  3384             case java_awt_event_MouseEvent_MOUSE_ENTERED:
       
  3385                 response_reason = DROP_SITE_ENTER;
       
  3386                 break;
       
  3387             case java_awt_event_MouseEvent_MOUSE_DRAGGED:
       
  3388                 response_reason = DRAG_MOTION;
       
  3389                 break;
       
  3390             case java_awt_event_MouseEvent_MOUSE_EXITED:
       
  3391                 response_reason = DROP_SITE_LEAVE;
       
  3392                 break;
       
  3393             }
       
  3394         }
       
  3395 
       
  3396         response.display = dpy;
       
  3397         response.type = ClientMessage;
       
  3398         response.window = read_card32(xclient->data.b, 12, byte_order);
       
  3399         response.format = 8;
       
  3400         response.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE;
       
  3401 
       
  3402         write_card8(&p, response_reason | MOTIF_MESSAGE_FROM_RECEIVER);
       
  3403         write_card8(&p, MOTIF_BYTE_ORDER);
       
  3404 
       
  3405         if (response_reason != DROP_SITE_LEAVE) {
       
  3406             CARD16 flags = read_card16(xclient->data.b, 2, byte_order);
       
  3407             unsigned char drop_site_status =
       
  3408                 (action == java_awt_dnd_DnDConstants_ACTION_NONE) ?
       
  3409                 MOTIF_INVALID_DROP_SITE : MOTIF_VALID_DROP_SITE;
       
  3410 
       
  3411             /* Clear action and drop site status bits. */
       
  3412             response_flags =
       
  3413                 flags & ~MOTIF_DND_ACTION_MASK & ~MOTIF_DND_STATUS_MASK;
       
  3414 
       
  3415             /* Fill in new action and drop site status. */
       
  3416             response_flags |=
       
  3417                 java_to_motif_actions(action) << MOTIF_DND_ACTION_SHIFT;
       
  3418             response_flags |=
       
  3419                 drop_site_status << MOTIF_DND_STATUS_SHIFT;
       
  3420         } else {
       
  3421             response_flags = 0;
       
  3422         }
       
  3423 
       
  3424         write_card16(&p, response_flags);
       
  3425 
       
  3426         /* Write time stamp. */
       
  3427         write_card32(&p, read_card32(xclient->data.b, 4, byte_order));
       
  3428 
       
  3429         /* Write coordinates. */
       
  3430         if (response_reason != DROP_SITE_LEAVE) {
       
  3431             write_card16(&p, read_card16(xclient->data.b, 8, byte_order));
       
  3432             write_card16(&p, read_card16(xclient->data.b, 10, byte_order));
       
  3433         } else {
       
  3434             write_card16(&p, 0);
       
  3435             write_card16(&p, 0);
       
  3436         }
       
  3437     } else {
       
  3438         return;
       
  3439     }
       
  3440 
       
  3441     dt_send_event_to_source(&response);
       
  3442 }
       
  3443 
       
  3444 static void
       
  3445 dummy_selection_callback(Widget w, XtPointer client_data, Atom* selection,
       
  3446                          Atom* type, XtPointer value, unsigned long *length,
       
  3447                          int32_t *format) {
       
  3448     /* The selection callback is responsible for freeing the data. */
       
  3449     if (value != NULL) {
       
  3450         XtFree(value);
       
  3451         value = NULL;
       
  3452     }
       
  3453 }
       
  3454 
       
  3455 static void
       
  3456 dt_notify_drop_done(JNIEnv* env, XClientMessageEvent* xclient, jboolean success,
       
  3457                     jint action) {
       
  3458     if (xclient->message_type == XA_XdndDrop) {
       
  3459         Display* dpy = xclient->display;
       
  3460         XClientMessageEvent finished;
       
  3461         long* event_data = xclient->data.l;
       
  3462 
       
  3463         /*
       
  3464          * The XDnD protocol recommends that the target requests the special
       
  3465          * target DELETE in case if the drop action is XdndActionMove.
       
  3466          */
       
  3467         if (action == java_awt_dnd_DnDConstants_ACTION_MOVE &&
       
  3468             success == JNI_TRUE) {
       
  3469 
       
  3470             Time time_stamp = event_data[2];
       
  3471 
       
  3472             XtGetSelectionValue(awt_root_shell, XA_XdndSelection, XA_DELETE,
       
  3473                                 dummy_selection_callback, NULL, time_stamp);
       
  3474         }
       
  3475 
       
  3476         finished.display = dpy;
       
  3477         finished.type = ClientMessage;
       
  3478         finished.window = event_data[0];
       
  3479         finished.format = 32;
       
  3480         finished.message_type = XA_XdndFinished;
       
  3481         finished.data.l[0] = xclient->window;
       
  3482         finished.data.l[1] = 0; /* flags */
       
  3483         finished.data.l[2] = None;
       
  3484         if (source_protocol_version >= 5) {
       
  3485             if (success == JNI_TRUE) {
       
  3486                 finished.data.l[1] |= XDND_ACCEPT_DROP_FLAG;
       
  3487             }
       
  3488             finished.data.l[2] = java_to_xdnd_action(action);
       
  3489         }
       
  3490 
       
  3491         dt_send_event_to_source(&finished);
       
  3492     } else if (xclient->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) {
       
  3493         char* event_data = xclient->data.b;
       
  3494         unsigned char event_byte_order = read_card8(event_data, 1);
       
  3495         unsigned char first_byte = read_card8(event_data, 0);
       
  3496         unsigned char reason = first_byte & MOTIF_MESSAGE_REASON_MASK;
       
  3497         unsigned char origin = first_byte & MOTIF_MESSAGE_SENDER_MASK;
       
  3498         Atom selection = None;
       
  3499         Time time_stamp = CurrentTime;
       
  3500         Atom status_atom = None;
       
  3501 
       
  3502         if (origin != MOTIF_MESSAGE_FROM_INITIATOR) {
       
  3503             DTRACE_PRINTLN2("%s:%d Invalid origin.", __FILE__, __LINE__);
       
  3504             return;
       
  3505         }
       
  3506 
       
  3507         if (reason != DROP_START) {
       
  3508             DTRACE_PRINTLN2("%s:%d Invalid reason.", __FILE__, __LINE__);
       
  3509             return;
       
  3510         }
       
  3511 
       
  3512         selection = read_card32(event_data, 12, event_byte_order);
       
  3513         time_stamp = read_card32(event_data, 4, event_byte_order);
       
  3514 
       
  3515         if (success == JNI_TRUE) {
       
  3516             status_atom = XA_XmTRANSFER_SUCCESS;
       
  3517         } else {
       
  3518             status_atom = XA_XmTRANSFER_FAILURE;
       
  3519         }
       
  3520 
       
  3521         /*
       
  3522          * This is just the way to communicate the drop completion status back
       
  3523          * to the initiator as prescribed by the Motif DnD protocol.
       
  3524          */
       
  3525         XtGetSelectionValue(awt_root_shell, selection, status_atom,
       
  3526                             dummy_selection_callback, NULL, time_stamp);
       
  3527     }
       
  3528 
       
  3529     /*
       
  3530      * Flush the buffer to guarantee that the drop completion event is sent
       
  3531      * to the source before the method returns.
       
  3532      */
       
  3533     XFlush(awt_display);
       
  3534 
       
  3535     /* Trick to prevent awt_dnd_cleanup() from posting dragExit */
       
  3536     target_component = NULL;
       
  3537     /* Cannot do cleanup before the drop finishes as we need source protocol
       
  3538        version to send XdndFinished message. */
       
  3539     awt_dnd_cleanup();
       
  3540 }
       
  3541 
       
  3542 /*
       
  3543  * Class:     sun_awt_motif_X11DropTargetContextPeer
       
  3544  * Method:    sendResponse
       
  3545  * Signature: (IIJZ)V
       
  3546  */
       
  3547 
       
  3548 JNIEXPORT void JNICALL
       
  3549 Java_sun_awt_motif_X11DropTargetContextPeer_sendResponse(JNIEnv *env,
       
  3550                                                          jobject this,
       
  3551                                                          jint eventID,
       
  3552                                                          jint action,
       
  3553                                                          jlong nativeCtxt,
       
  3554                                                          jboolean dispatcherDone,
       
  3555                                                          jboolean consumed) {
       
  3556     XClientMessageEvent* xclient =
       
  3557         (XClientMessageEvent*)jlong_to_ptr(nativeCtxt);
       
  3558 
       
  3559     AWT_LOCK();
       
  3560 
       
  3561     if (consumed == JNI_FALSE) {
       
  3562         dt_send_response(xclient, eventID, action);
       
  3563     }
       
  3564 
       
  3565     /*
       
  3566      * Free the native context only if all copies of the original event are
       
  3567      * processed.
       
  3568      */
       
  3569     if (dispatcherDone == JNI_TRUE) {
       
  3570         XtFree((char*)xclient);
       
  3571     }
       
  3572 
       
  3573     AWT_UNLOCK();
       
  3574 }
       
  3575 
       
  3576 /*
       
  3577  * Class:     sun_awt_motif_X11DropTargetContextPeer
       
  3578  * Method:    dropDone
       
  3579  * Signature: (JZI)V
       
  3580  */
       
  3581 
       
  3582 JNIEXPORT void JNICALL
       
  3583 Java_sun_awt_motif_X11DropTargetContextPeer_dropDone(JNIEnv *env,
       
  3584                                                      jobject this,
       
  3585                                                      jlong nativeCtxt,
       
  3586                                                      jboolean success,
       
  3587                                                      jint action) {
       
  3588     XClientMessageEvent* xclient =
       
  3589         (XClientMessageEvent*)jlong_to_ptr(nativeCtxt);
       
  3590 
       
  3591     AWT_LOCK();
       
  3592 
       
  3593     dt_notify_drop_done(env, xclient, success, action);
       
  3594 
       
  3595     XtFree((char*)xclient);
       
  3596 
       
  3597     AWT_UNLOCK();
       
  3598 }
       
  3599 
       
  3600 /*
       
  3601  * Class:     sun_awt_motif_X11DropTargetContextPeer
       
  3602  * Method:    getData
       
  3603  * Signature: (IJ)Ljava/lang/Object;
       
  3604  */
       
  3605 
       
  3606 JNIEXPORT jobject JNICALL
       
  3607 Java_sun_awt_motif_X11DropTargetContextPeer_getData(JNIEnv *env,
       
  3608                                                     jobject this,
       
  3609                                                     jlong nativeCtxt,
       
  3610                                                     jlong formatAtom) {
       
  3611     XClientMessageEvent* xclient =
       
  3612         (XClientMessageEvent*)jlong_to_ptr(nativeCtxt);
       
  3613 
       
  3614     Atom selection    = None;
       
  3615     Time time_stamp   = CurrentTime;
       
  3616     Atom target       = (Atom)formatAtom;
       
  3617 
       
  3618     if (xclient->message_type == XA_XdndDrop ||
       
  3619         xclient->message_type == XA_XdndPosition) {
       
  3620         Display* dpy = xclient->display;
       
  3621         Window source_win = xclient->data.l[0];
       
  3622         Atom protocol_version = 0;
       
  3623 
       
  3624         int            status;
       
  3625 
       
  3626         Atom           type;
       
  3627         int            format;
       
  3628         unsigned long  nitems;
       
  3629         unsigned long  after;
       
  3630         unsigned char  *data;
       
  3631 
       
  3632         AWT_LOCK();
       
  3633 
       
  3634         data = NULL;
       
  3635         status = XGetWindowProperty(dpy, source_win, XA_XdndAware, 0, 0xFFFF,
       
  3636                                     False, XA_ATOM, &type, &format, &nitems,
       
  3637                                     &after, &data);
       
  3638 
       
  3639         if (status == Success && data != NULL && type == XA_ATOM && format == 32
       
  3640             && nitems > 0) {
       
  3641             protocol_version = (protocol_version > XDND_PROTOCOL_VERSION) ?
       
  3642                 XDND_PROTOCOL_VERSION : protocol_version;
       
  3643 
       
  3644             if (protocol_version > 0) {
       
  3645                 if (xclient->message_type == XA_XdndDrop) {
       
  3646                     time_stamp = xclient->data.l[2];
       
  3647                 } else if (xclient->message_type == XA_XdndPosition) {
       
  3648                     time_stamp = xclient->data.l[3];
       
  3649                 }
       
  3650             }
       
  3651         }
       
  3652 
       
  3653         if (status == Success) {
       
  3654             XFree(data);
       
  3655             data = NULL;
       
  3656         }
       
  3657 
       
  3658         AWT_FLUSH_UNLOCK();
       
  3659 
       
  3660         selection = XA_XdndSelection;
       
  3661         if (time_stamp == CurrentTime) {
       
  3662             time_stamp = awt_util_getCurrentServerTime();
       
  3663         }
       
  3664 
       
  3665     } else if (xclient->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) {
       
  3666         char* event_data = xclient->data.b;
       
  3667         unsigned char event_byte_order = read_card8(event_data, 1);
       
  3668         unsigned char first_byte = read_card8(event_data, 0);
       
  3669         unsigned char reason = first_byte & MOTIF_MESSAGE_REASON_MASK;
       
  3670         unsigned char origin = first_byte & MOTIF_MESSAGE_SENDER_MASK;
       
  3671 
       
  3672         if (origin != MOTIF_MESSAGE_FROM_INITIATOR) {
       
  3673             DTRACE_PRINTLN2("%s:%d Invalid origin.", __FILE__, __LINE__);
       
  3674             return NULL;
       
  3675         }
       
  3676 
       
  3677         switch (reason) {
       
  3678         case DROP_START:
       
  3679             selection = read_card32(event_data, 12, event_byte_order);
       
  3680             break;
       
  3681         case DRAG_MOTION:
       
  3682         case OPERATION_CHANGED:
       
  3683             selection = source_atom;
       
  3684             break;
       
  3685         default:
       
  3686             DTRACE_PRINTLN2("%s:%d Invalid reason.", __FILE__, __LINE__);
       
  3687             return NULL;
       
  3688         }
       
  3689 
       
  3690         if (selection == None) {
       
  3691             return NULL;
       
  3692         }
       
  3693 
       
  3694         time_stamp = read_card32(event_data, 4, event_byte_order);
       
  3695     } else {
       
  3696         return NULL;
       
  3697     }
       
  3698 
       
  3699     return get_selection_data(env, selection, target, time_stamp);
       
  3700 }