jdk/src/solaris/native/sun/awt/awt_dnd.c
changeset 1203 3e5496df0d2b
parent 1202 5a725d2f0daa
parent 1201 e87f9c042699
child 1211 b659a7cee935
equal deleted inserted replaced
1202:5a725d2f0daa 1203:3e5496df0d2b
     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 "awt_p.h"
       
    33 
       
    34 #include "java_awt_dnd_DnDConstants.h"
       
    35 
       
    36 /* Shared atoms */
       
    37 
       
    38 Atom XA_WM_STATE;
       
    39 Atom XA_DELETE;
       
    40 
       
    41 /* XDnD atoms */
       
    42 
       
    43 Atom XA_XdndAware;
       
    44 Atom XA_XdndProxy;
       
    45 
       
    46 Atom XA_XdndEnter;
       
    47 Atom XA_XdndPosition;
       
    48 Atom XA_XdndLeave;
       
    49 Atom XA_XdndDrop;
       
    50 Atom XA_XdndStatus;
       
    51 Atom XA_XdndFinished;
       
    52 
       
    53 Atom XA_XdndTypeList;
       
    54 Atom XA_XdndSelection;
       
    55 
       
    56 Atom XA_XdndActionCopy;
       
    57 Atom XA_XdndActionMove;
       
    58 Atom XA_XdndActionLink;
       
    59 Atom XA_XdndActionAsk;
       
    60 Atom XA_XdndActionPrivate;
       
    61 Atom XA_XdndActionList;
       
    62 
       
    63 /* Motif DnD atoms */
       
    64 
       
    65 Atom _XA_MOTIF_DRAG_WINDOW;
       
    66 Atom _XA_MOTIF_DRAG_TARGETS;
       
    67 Atom _XA_MOTIF_DRAG_INITIATOR_INFO;
       
    68 Atom _XA_MOTIF_DRAG_RECEIVER_INFO;
       
    69 Atom _XA_MOTIF_DRAG_AND_DROP_MESSAGE;
       
    70 Atom _XA_MOTIF_ATOM_0;
       
    71 Atom XA_XmTRANSFER_SUCCESS;
       
    72 Atom XA_XmTRANSFER_FAILURE;
       
    73 
       
    74 unsigned char MOTIF_BYTE_ORDER = 0;
       
    75 
       
    76 static Window awt_root_window = None;
       
    77 
       
    78 static Boolean
       
    79 init_atoms(Display* display) {
       
    80     struct atominit {
       
    81         Atom *atomptr;
       
    82         const char *name;
       
    83     };
       
    84 
       
    85     /* Add new atoms to this list */
       
    86     static struct atominit atom_list[] = {
       
    87         /* Shared atoms */
       
    88         { &XA_WM_STATE,                     "WM_STATE"                     },
       
    89         { &XA_DELETE,                       "DELETE"                       },
       
    90 
       
    91         /* XDnD atoms */
       
    92         { &XA_XdndAware,                    "XdndAware"                    },
       
    93         { &XA_XdndProxy,                    "XdndProxy"                    },
       
    94         { &XA_XdndEnter,                    "XdndEnter"                    },
       
    95         { &XA_XdndPosition,                 "XdndPosition"                 },
       
    96         { &XA_XdndLeave,                    "XdndLeave"                    },
       
    97         { &XA_XdndDrop,                     "XdndDrop"                     },
       
    98         { &XA_XdndStatus,                   "XdndStatus"                   },
       
    99         { &XA_XdndFinished,                 "XdndFinished"                 },
       
   100         { &XA_XdndTypeList,                 "XdndTypeList"                 },
       
   101         { &XA_XdndSelection,                "XdndSelection"                },
       
   102         { &XA_XdndActionCopy,               "XdndActionCopy"               },
       
   103         { &XA_XdndActionMove,               "XdndActionMove"               },
       
   104         { &XA_XdndActionLink,               "XdndActionLink"               },
       
   105         { &XA_XdndActionAsk,                "XdndActionAsk"                },
       
   106         { &XA_XdndActionPrivate,            "XdndActionPrivate"            },
       
   107         { &XA_XdndActionList,               "XdndActionList"               },
       
   108 
       
   109         /* Motif DnD atoms */
       
   110         { &_XA_MOTIF_DRAG_WINDOW,           "_MOTIF_DRAG_WINDOW"           },
       
   111         { &_XA_MOTIF_DRAG_TARGETS,          "_MOTIF_DRAG_TARGETS"          },
       
   112         { &_XA_MOTIF_DRAG_INITIATOR_INFO,   "_MOTIF_DRAG_INITIATOR_INFO"   },
       
   113         { &_XA_MOTIF_DRAG_RECEIVER_INFO,    "_MOTIF_DRAG_RECEIVER_INFO"    },
       
   114         { &_XA_MOTIF_DRAG_AND_DROP_MESSAGE, "_MOTIF_DRAG_AND_DROP_MESSAGE" },
       
   115         { &_XA_MOTIF_ATOM_0,                "_MOTIF_ATOM_0"                },
       
   116         { &XA_XmTRANSFER_SUCCESS,           "XmTRANSFER_SUCCESS"           },
       
   117         { &XA_XmTRANSFER_FAILURE,           "XmTRANSFER_FAILURE"           }
       
   118     };
       
   119 
       
   120 #define ATOM_LIST_LENGTH (sizeof(atom_list)/sizeof(atom_list[0]))
       
   121 
       
   122     const char *names[ATOM_LIST_LENGTH];
       
   123     Atom atoms[ATOM_LIST_LENGTH];
       
   124     Status status;
       
   125     size_t i;
       
   126 
       
   127     /* Fill the array of atom names */
       
   128     for (i = 0; i < ATOM_LIST_LENGTH; ++i) {
       
   129         names[i] = atom_list[i].name;
       
   130     }
       
   131 
       
   132     DTRACE_PRINT2("%s:%d initializing atoms ... ", __FILE__, __LINE__);
       
   133 
       
   134     status = XInternAtoms(awt_display, (char**)names, ATOM_LIST_LENGTH,
       
   135                           False, atoms);
       
   136     if (status == 0) {
       
   137         DTRACE_PRINTLN("failed");
       
   138         return False;
       
   139     }
       
   140 
       
   141     /* Store returned atoms into corresponding global variables */
       
   142     DTRACE_PRINTLN("ok");
       
   143     for (i = 0; i < ATOM_LIST_LENGTH; ++i) {
       
   144         *atom_list[i].atomptr = atoms[i];
       
   145     }
       
   146 
       
   147     return True;
       
   148 #undef ATOM_LIST_LENGTH
       
   149 }
       
   150 
       
   151 /*
       
   152  * NOTE: must be called after awt_root_shell is created and realized.
       
   153  */
       
   154 Boolean
       
   155 awt_dnd_init(Display* display) {
       
   156     static Boolean inited = False;
       
   157 
       
   158     if (!inited) {
       
   159         Boolean atoms_inited = False;
       
   160         Boolean ds_inited = False;
       
   161         unsigned int value = 1;
       
   162         MOTIF_BYTE_ORDER = (*((char*)&value) != 0) ? 'l' : 'B';
       
   163 
       
   164         /* NOTE: init_atoms() should be called before the rest of initialization
       
   165            so that atoms can be used. */
       
   166         inited = init_atoms(display);
       
   167 
       
   168         if (inited) {
       
   169             if (XtIsRealized(awt_root_shell)) {
       
   170                 awt_root_window = XtWindow(awt_root_shell);
       
   171             } else {
       
   172                 inited = False;
       
   173             }
       
   174         }
       
   175 
       
   176         inited = inited && awt_dnd_ds_init(display);
       
   177     }
       
   178 
       
   179     return inited;
       
   180 }
       
   181 
       
   182 /*
       
   183  * Returns a window of awt_root_shell.
       
   184  */
       
   185 Window
       
   186 get_awt_root_window() {
       
   187     return awt_root_window;
       
   188 }
       
   189 
       
   190 static unsigned char local_xerror_code = Success;
       
   191 
       
   192 static int
       
   193 xerror_handler(Display *dpy, XErrorEvent *err) {
       
   194     local_xerror_code = err->error_code;
       
   195     return 0;
       
   196 }
       
   197 
       
   198 /**************** checked_X* wrappers *****************************************/
       
   199 #undef NO_SYNC
       
   200 #undef SYNC_TRACE
       
   201 
       
   202 unsigned char
       
   203 checked_XChangeProperty(Display* display, Window w, Atom property, Atom type,
       
   204                         int format, int mode, unsigned char* data,
       
   205                         int nelements) {
       
   206     XErrorHandler xerror_saved_handler;
       
   207 
       
   208 #ifndef NO_SYNC
       
   209     XSync(display, False);
       
   210 #ifdef SYNC_TRACE
       
   211     fprintf(stderr,"XSync 1\n");
       
   212 #endif
       
   213 #endif
       
   214     local_xerror_code = Success;
       
   215     xerror_saved_handler = XSetErrorHandler(xerror_handler);
       
   216 
       
   217     XChangeProperty(display, w, property, type, format, mode, data, nelements);
       
   218 
       
   219 #ifndef NO_SYNC
       
   220     XSync(display, False);
       
   221 #ifdef SYNC_TRACE
       
   222     fprintf(stderr,"XSync 2\n");
       
   223 #endif
       
   224 #endif
       
   225     XSetErrorHandler(xerror_saved_handler);
       
   226 
       
   227     return local_xerror_code;
       
   228 }
       
   229 
       
   230 unsigned char
       
   231 checked_XGetWindowProperty(Display* display, Window w, Atom property, long long_offset,
       
   232                            long long_length, Bool delete, Atom req_type,
       
   233                            Atom* actual_type_return, int* actual_format_return,
       
   234                            unsigned long* nitems_return, unsigned long* bytes_after_return,
       
   235                            unsigned char** prop_return) {
       
   236 
       
   237     XErrorHandler xerror_saved_handler;
       
   238     int ret_val = Success;
       
   239 
       
   240 #ifndef NO_SYNC
       
   241     XSync(display, False);
       
   242 #ifdef SYNC_TRACE
       
   243     fprintf(stderr,"XSync 3\n");
       
   244 #endif
       
   245 #endif
       
   246     local_xerror_code = Success;
       
   247     xerror_saved_handler = XSetErrorHandler(xerror_handler);
       
   248 
       
   249     ret_val = XGetWindowProperty(display, w, property, long_offset, long_length,
       
   250                                  delete, req_type, actual_type_return,
       
   251                                  actual_format_return, nitems_return,
       
   252                                  bytes_after_return, prop_return);
       
   253 
       
   254 #ifndef NO_SYNC
       
   255     XSync(display, False);
       
   256 #ifdef SYNC_TRACE
       
   257     fprintf(stderr,"XSync 4\n");
       
   258 #endif
       
   259 #endif
       
   260     XSetErrorHandler(xerror_saved_handler);
       
   261 
       
   262     return ret_val != Success ? local_xerror_code : Success;
       
   263 }
       
   264 
       
   265 unsigned char
       
   266 checked_XSendEvent(Display* display, Window w, Bool propagate, long event_mask,
       
   267                    XEvent* event_send) {
       
   268 
       
   269     XErrorHandler xerror_saved_handler;
       
   270     Status ret_val = 0;
       
   271 
       
   272 #ifndef NO_SYNC
       
   273     XSync(display, False);
       
   274 #ifdef SYNC_TRACE
       
   275     fprintf(stderr,"XSync 5\n");
       
   276 #endif
       
   277 #endif
       
   278     local_xerror_code = Success;
       
   279     xerror_saved_handler = XSetErrorHandler(xerror_handler);
       
   280 
       
   281     ret_val = XSendEvent(display, w, propagate, event_mask, event_send);
       
   282 
       
   283 #ifndef NO_SYNC
       
   284     XSync(display, False);
       
   285 #ifdef SYNC_TRACE
       
   286     fprintf(stderr,"XSync 6\n");
       
   287 #endif
       
   288 #endif
       
   289     XSetErrorHandler(xerror_saved_handler);
       
   290 
       
   291     return ret_val == 0 ? local_xerror_code : Success;
       
   292 }
       
   293 
       
   294 /*
       
   295  * NOTE: returns Success even if the two windows aren't on the same screen.
       
   296  */
       
   297 unsigned char
       
   298 checked_XTranslateCoordinates(Display* display, Window src_w, Window dest_w,
       
   299                               int src_x, int src_y, int* dest_x_return,
       
   300                               int* dest_y_return, Window* child_return) {
       
   301 
       
   302     XErrorHandler xerror_saved_handler;
       
   303     Bool ret_val = True;
       
   304 
       
   305 #ifndef NO_SYNC
       
   306     XSync(display, False);
       
   307 #ifdef SYNC_TRACE
       
   308     fprintf(stderr,"XSync 7\n");
       
   309 #endif
       
   310 #endif
       
   311     local_xerror_code = Success;
       
   312     xerror_saved_handler = XSetErrorHandler(xerror_handler);
       
   313 
       
   314     ret_val = XTranslateCoordinates(display, src_w, dest_w, src_x, src_y,
       
   315                                     dest_x_return, dest_y_return, child_return);
       
   316 
       
   317 #ifndef NO_SYNC
       
   318     XSync(display, False);
       
   319 #ifdef SYNC_TRACE
       
   320     fprintf(stderr,"XSync 8\n");
       
   321 #endif
       
   322 #endif
       
   323     XSetErrorHandler(xerror_saved_handler);
       
   324 
       
   325     return local_xerror_code;
       
   326 }
       
   327 
       
   328 unsigned char
       
   329 checked_XSelectInput(Display* display, Window w, long event_mask) {
       
   330     XErrorHandler xerror_saved_handler;
       
   331     Bool ret_val = True;
       
   332 
       
   333 #ifndef NO_SYNC
       
   334     XSync(display, False);
       
   335 #ifdef SYNC_TRACE
       
   336     fprintf(stderr,"XSync 7\n");
       
   337 #endif
       
   338 #endif
       
   339     local_xerror_code = Success;
       
   340     xerror_saved_handler = XSetErrorHandler(xerror_handler);
       
   341 
       
   342     XSelectInput(display, w, event_mask);
       
   343 
       
   344 #ifndef NO_SYNC
       
   345     XSync(display, False);
       
   346 #ifdef SYNC_TRACE
       
   347     fprintf(stderr,"XSync 8\n");
       
   348 #endif
       
   349 #endif
       
   350     XSetErrorHandler(xerror_saved_handler);
       
   351 
       
   352     return local_xerror_code;
       
   353 }
       
   354 /******************************************************************************/
       
   355 
       
   356 jint
       
   357 xdnd_to_java_action(Atom action) {
       
   358     if (action == XA_XdndActionCopy) {
       
   359         return java_awt_dnd_DnDConstants_ACTION_COPY;
       
   360     } else if (action == XA_XdndActionMove) {
       
   361         return java_awt_dnd_DnDConstants_ACTION_MOVE;
       
   362     } else if (action == XA_XdndActionLink) {
       
   363         return java_awt_dnd_DnDConstants_ACTION_LINK;
       
   364     } else if (action == None) {
       
   365         return java_awt_dnd_DnDConstants_ACTION_NONE;
       
   366     } else {
       
   367         /* XdndActionCopy is the default. */
       
   368         return java_awt_dnd_DnDConstants_ACTION_COPY;
       
   369     }
       
   370 }
       
   371 
       
   372 Atom
       
   373 java_to_xdnd_action(jint action) {
       
   374     switch (action) {
       
   375     case java_awt_dnd_DnDConstants_ACTION_COPY: return XA_XdndActionCopy;
       
   376     case java_awt_dnd_DnDConstants_ACTION_MOVE: return XA_XdndActionMove;
       
   377     case java_awt_dnd_DnDConstants_ACTION_LINK: return XA_XdndActionLink;
       
   378     default:                                    return None;
       
   379     }
       
   380 }
       
   381 
       
   382 void
       
   383 write_card8(void** p, CARD8 value) {
       
   384     CARD8** card8_pp = (CARD8**)p;
       
   385     **card8_pp = value;
       
   386     (*card8_pp)++;
       
   387 }
       
   388 
       
   389 void
       
   390 write_card16(void** p, CARD16 value) {
       
   391     CARD16** card16_pp = (CARD16**)p;
       
   392     **card16_pp = value;
       
   393     (*card16_pp)++;
       
   394 }
       
   395 
       
   396 void
       
   397 write_card32(void** p, CARD32 value) {
       
   398     CARD32** card32_pp = (CARD32**)p;
       
   399     **card32_pp = value;
       
   400     (*card32_pp)++;
       
   401 }
       
   402 
       
   403 CARD8
       
   404 read_card8(char* data, size_t offset) {
       
   405     return *((CARD8*)(data + offset));
       
   406 }
       
   407 
       
   408 CARD16
       
   409 read_card16(char* data, size_t offset, char byte_order) {
       
   410     CARD16 card16 = *((CARD16*)(data + offset));
       
   411 
       
   412     if (byte_order != MOTIF_BYTE_ORDER) {
       
   413         SWAP2BYTES(card16);
       
   414     }
       
   415 
       
   416     return card16;
       
   417 }
       
   418 
       
   419 CARD32
       
   420 read_card32(char* data, size_t offset, char byte_order) {
       
   421     CARD32 card32 = *((CARD32*)(data + offset));
       
   422 
       
   423     if (byte_order != MOTIF_BYTE_ORDER) {
       
   424         SWAP4BYTES(card32);
       
   425     }
       
   426 
       
   427     return card32;
       
   428 }
       
   429 
       
   430 static Window
       
   431 read_motif_window(Display* dpy) {
       
   432     Window         root_window = DefaultRootWindow(dpy);
       
   433     Window         motif_window = None;
       
   434 
       
   435     unsigned char  ret;
       
   436     Atom           type;
       
   437     int            format;
       
   438     unsigned long  nitems;
       
   439     unsigned long  after;
       
   440     unsigned char  *data;
       
   441 
       
   442     ret = checked_XGetWindowProperty(dpy, root_window, _XA_MOTIF_DRAG_WINDOW,
       
   443                                      0, 0xFFFF, False, AnyPropertyType, &type,
       
   444                                      &format, &nitems, &after, &data);
       
   445 
       
   446     if (ret != Success) {
       
   447         DTRACE_PRINTLN2("%s:%d Failed to read _MOTIF_DRAG_WINDOW.",
       
   448                         __FILE__, __LINE__);
       
   449         return None;
       
   450     }
       
   451 
       
   452 
       
   453     if (type == XA_WINDOW && format == 32 && nitems == 1) {
       
   454         motif_window = *((Window*)data);
       
   455     }
       
   456 
       
   457     XFree ((char *)data);
       
   458 
       
   459     return motif_window;
       
   460 }
       
   461 
       
   462 static Window
       
   463 create_motif_window(Display* dpy) {
       
   464     Window   root_window = DefaultRootWindow(dpy);
       
   465     Window   motif_window = None;
       
   466     Display* display = NULL;
       
   467     XSetWindowAttributes swa;
       
   468 
       
   469     display = XOpenDisplay(XDisplayString(dpy));
       
   470     if (display == NULL) {
       
   471         return None;
       
   472     }
       
   473 
       
   474     XGrabServer(display);
       
   475 
       
   476     XSetCloseDownMode(display, RetainPermanent);
       
   477 
       
   478     swa.override_redirect = True;
       
   479     swa.event_mask = PropertyChangeMask;
       
   480     motif_window = XCreateWindow(display, root_window,
       
   481                                  -10, -10, 1, 1, 0, 0,
       
   482                                  InputOnly, CopyFromParent,
       
   483                                  (CWOverrideRedirect|CWEventMask),
       
   484                                  &swa);
       
   485     XMapWindow(display, motif_window);
       
   486 
       
   487     XChangeProperty(display, root_window, _XA_MOTIF_DRAG_WINDOW, XA_WINDOW, 32,
       
   488                     PropModeReplace, (unsigned char *)&motif_window, 1);
       
   489 
       
   490     XUngrabServer(display);
       
   491 
       
   492     XCloseDisplay(display);
       
   493 
       
   494     return motif_window;
       
   495 }
       
   496 
       
   497 Window
       
   498 get_motif_window(Display* dpy) {
       
   499     /*
       
   500      * Note: it is unsafe to cache the motif drag window handle, as another
       
   501      * client can change the _MOTIF_DRAG_WINDOW property on the root, the handle
       
   502      * becomes out-of-sync and all subsequent drag operations will fail.
       
   503      */
       
   504     Window motif_window = read_motif_window(dpy);
       
   505     if (motif_window == None) {
       
   506         motif_window = create_motif_window(dpy);
       
   507     }
       
   508 
       
   509     return motif_window;
       
   510 }
       
   511 
       
   512 typedef struct {
       
   513     CARD16 num_targets;
       
   514     Atom* targets;
       
   515 } TargetsTableEntry;
       
   516 
       
   517 typedef struct {
       
   518     CARD16 num_entries;
       
   519     TargetsTableEntry* entries;
       
   520 } TargetsTable;
       
   521 
       
   522 typedef struct {
       
   523     CARD8       byte_order;
       
   524     CARD8       protocol_version;
       
   525     CARD16      num_entries B16;
       
   526     CARD32      heap_offset B32;
       
   527 } TargetsPropertyRec;
       
   528 
       
   529 static TargetsTable*
       
   530 get_target_list_table(Display* dpy) {
       
   531     Window motif_window = get_motif_window(dpy);
       
   532     TargetsTable* targets_table = NULL;
       
   533     TargetsPropertyRec* targets_property_rec_ptr;
       
   534     char* bufptr;
       
   535 
       
   536     unsigned char  ret;
       
   537     Atom           type;
       
   538     int            format;
       
   539     unsigned long  nitems;
       
   540     unsigned long  after;
       
   541     unsigned char  *data;
       
   542     unsigned int   i, j;
       
   543 
       
   544     ret = checked_XGetWindowProperty(dpy, motif_window, _XA_MOTIF_DRAG_TARGETS,
       
   545                                      0L, 100000L, False, _XA_MOTIF_DRAG_TARGETS,
       
   546                                      &type, &format, &nitems, &after,
       
   547                                      (unsigned char**)&targets_property_rec_ptr);
       
   548 
       
   549     if (ret != Success || type != _XA_MOTIF_DRAG_TARGETS ||
       
   550         targets_property_rec_ptr == NULL) {
       
   551 
       
   552         DTRACE_PRINT2("%s:%d Cannot read _XA_MOTIF_DRAG_TARGETS", __FILE__, __LINE__);
       
   553         return NULL;
       
   554     }
       
   555 
       
   556     if (targets_property_rec_ptr->protocol_version !=
       
   557         MOTIF_DND_PROTOCOL_VERSION) {
       
   558         DTRACE_PRINT2("%s:%d incorrect protocol version", __FILE__, __LINE__);
       
   559         return NULL;
       
   560     }
       
   561 
       
   562     if (targets_property_rec_ptr->byte_order != MOTIF_BYTE_ORDER) {
       
   563         SWAP2BYTES(targets_property_rec_ptr->num_entries);
       
   564         SWAP4BYTES(targets_property_rec_ptr->heap_offset);
       
   565     }
       
   566 
       
   567     targets_table = (TargetsTable*)malloc(sizeof(TargetsTable));
       
   568     if (targets_table == NULL) {
       
   569         DTRACE_PRINT2("%s:%d malloc failed", __FILE__, __LINE__);
       
   570         return NULL;
       
   571     }
       
   572     targets_table->num_entries = targets_property_rec_ptr->num_entries;
       
   573     targets_table->entries =
       
   574         (TargetsTableEntry*)malloc(sizeof(TargetsTableEntry) *
       
   575                                    targets_property_rec_ptr->num_entries);
       
   576     if (targets_table->entries == NULL) {
       
   577         DTRACE_PRINT2("%s:%d malloc failed", __FILE__, __LINE__);
       
   578         free(targets_table);
       
   579         return NULL;
       
   580     }
       
   581 
       
   582     bufptr = (char *)targets_property_rec_ptr + sizeof(TargetsPropertyRec);
       
   583     for (i = 0; i < targets_table->num_entries; i++) {
       
   584         CARD16 num_targets;
       
   585         Atom* targets;
       
   586         memcpy(&num_targets, bufptr, 2 );
       
   587         bufptr += 2;
       
   588         if (targets_property_rec_ptr->byte_order != MOTIF_BYTE_ORDER) {
       
   589             SWAP2BYTES(num_targets);
       
   590         }
       
   591 
       
   592         targets = (Atom*)malloc(sizeof(Atom) * num_targets);
       
   593         if (targets == NULL) {
       
   594             DTRACE_PRINT2("%s:%d malloc failed", __FILE__, __LINE__);
       
   595             free(targets_table->entries);
       
   596             free(targets_table);
       
   597             return NULL;
       
   598         }
       
   599         for (j = 0; j < num_targets; j++) {
       
   600             CARD32 target;
       
   601             memcpy(&target, bufptr, 4 );
       
   602             bufptr += 4;
       
   603             if (targets_property_rec_ptr->byte_order != MOTIF_BYTE_ORDER) {
       
   604                 SWAP4BYTES(target);
       
   605             }
       
   606             targets[j] = (Atom)target;
       
   607         }
       
   608 
       
   609         targets_table->entries[i].num_targets = num_targets;
       
   610         targets_table->entries[i].targets = targets;
       
   611     }
       
   612 
       
   613     free(targets_property_rec_ptr);
       
   614 
       
   615     return targets_table;
       
   616 }
       
   617 
       
   618 static void
       
   619 put_target_list_table(Display* dpy, TargetsTable* table) {
       
   620     Window motif_window = get_motif_window(dpy);
       
   621     TargetsPropertyRec* targets_property_rec_ptr;
       
   622     size_t table_size = sizeof(TargetsPropertyRec);
       
   623     unsigned char ret;
       
   624     int i, j;
       
   625     char* buf;
       
   626 
       
   627     for (i = 0; i < table->num_entries; i++) {
       
   628         table_size += table->entries[i].num_targets * sizeof(Atom) + 2;
       
   629     }
       
   630 
       
   631     targets_property_rec_ptr = (TargetsPropertyRec*)malloc(table_size);
       
   632     if (targets_property_rec_ptr == NULL) {
       
   633         DTRACE_PRINT2("%s:%d malloc failed", __FILE__, __LINE__);
       
   634         return;
       
   635     }
       
   636     targets_property_rec_ptr->byte_order = MOTIF_BYTE_ORDER;
       
   637     targets_property_rec_ptr->protocol_version = MOTIF_DND_PROTOCOL_VERSION;
       
   638     targets_property_rec_ptr->num_entries = table->num_entries;
       
   639     targets_property_rec_ptr->heap_offset = table_size;
       
   640 
       
   641     buf = (char*)targets_property_rec_ptr + sizeof(TargetsPropertyRec);
       
   642 
       
   643     for (i = 0; i < table->num_entries; i++) {
       
   644         CARD16 num_targets = table->entries[i].num_targets;
       
   645         memcpy(buf, &num_targets, 2);
       
   646         buf += 2;
       
   647 
       
   648         for (j = 0; j < num_targets; j++) {
       
   649             CARD32 target = table->entries[i].targets[j];
       
   650             memcpy(buf, &target, 4);
       
   651             buf += 4;
       
   652         }
       
   653     }
       
   654 
       
   655     ret = checked_XChangeProperty(dpy, motif_window, _XA_MOTIF_DRAG_TARGETS,
       
   656                                   _XA_MOTIF_DRAG_TARGETS, 8, PropModeReplace,
       
   657                                   (unsigned char*)targets_property_rec_ptr,
       
   658                                   (int)table_size);
       
   659 
       
   660     if (ret != Success) {
       
   661         DTRACE_PRINT2("%s:%d XChangeProperty failed", __FILE__, __LINE__);
       
   662     }
       
   663 
       
   664     XtFree((char*)targets_property_rec_ptr);
       
   665 }
       
   666 
       
   667 static int
       
   668 _compare(const void* p1, const void* p2) {
       
   669     long diff = *(Atom*)p1 - *(Atom*)p2;
       
   670 
       
   671     if (diff > 0) {
       
   672         return 1;
       
   673     } else if (diff < 0) {
       
   674         return -1;
       
   675     } else {
       
   676         return 0;
       
   677     }
       
   678 }
       
   679 
       
   680 /*
       
   681  * Returns the index for the specified target list or -1 on failure.
       
   682  */
       
   683 int
       
   684 get_index_for_target_list(Display* dpy, Atom* targets, unsigned int num_targets) {
       
   685     TargetsTable* targets_table = NULL;
       
   686     Atom* sorted_targets = NULL;
       
   687     int i, j;
       
   688     int ret = -1;
       
   689 
       
   690     if (targets == NULL && num_targets > 0) {
       
   691         DTRACE_PRINT4("%s:%d targets=%X num_targets=%d",
       
   692                       __FILE__, __LINE__, targets, num_targets);
       
   693         return -1;
       
   694     }
       
   695 
       
   696     if (num_targets > 0) {
       
   697         sorted_targets = (Atom*)malloc(sizeof(Atom) * num_targets);
       
   698         if (sorted_targets == NULL) {
       
   699             DTRACE_PRINT2("%s:%d malloc failed.", __FILE__, __LINE__);
       
   700             return -1;
       
   701         }
       
   702 
       
   703         memcpy(sorted_targets, targets, sizeof(Atom) * num_targets);
       
   704         qsort ((void *)sorted_targets, (size_t)num_targets, (size_t)sizeof(Atom),
       
   705                _compare);
       
   706     }
       
   707 
       
   708     XGrabServer(dpy);
       
   709     targets_table = get_target_list_table(dpy);
       
   710 
       
   711     if (targets_table != NULL) {
       
   712         for (i = 0; i < targets_table->num_entries; i++) {
       
   713             TargetsTableEntry* entry_ptr = &targets_table->entries[i];
       
   714             Boolean equals = True;
       
   715             if (num_targets == entry_ptr->num_targets) {
       
   716                 for (j = 0; j < entry_ptr->num_targets; j++) {
       
   717                     if (sorted_targets[j] != entry_ptr->targets[j]) {
       
   718                         equals = False;
       
   719                         break;
       
   720                     }
       
   721                 }
       
   722             } else {
       
   723                 equals = False;
       
   724             }
       
   725 
       
   726             if (equals) {
       
   727                 XUngrabServer(dpy);
       
   728                 /* Workaround for bug 5039226 */
       
   729                 XSync(dpy, False);
       
   730                 free((char*)sorted_targets);
       
   731                 return i;
       
   732             }
       
   733         }
       
   734     } else {
       
   735         targets_table = (TargetsTable*)malloc(sizeof(TargetsTable));
       
   736         targets_table->num_entries = 0;
       
   737         targets_table->entries = NULL;
       
   738     }
       
   739 
       
   740     /* Index not found - expand the table. */
       
   741     targets_table->entries =
       
   742         (TargetsTableEntry*)realloc((char*)targets_table->entries,
       
   743                                     sizeof(TargetsTableEntry) *
       
   744                                     (targets_table->num_entries + 1));
       
   745     if (targets_table->entries == NULL) {
       
   746         DTRACE_PRINT2("%s:%d realloc failed.", __FILE__, __LINE__);
       
   747         XUngrabServer(dpy);
       
   748         /* Workaround for bug 5039226 */
       
   749         XSync(dpy, False);
       
   750         free((char*)sorted_targets);
       
   751         return -1;
       
   752     }
       
   753 
       
   754     /* Fill in the new entry */
       
   755     {
       
   756         TargetsTableEntry* new_entry =
       
   757             &targets_table->entries[targets_table->num_entries];
       
   758 
       
   759         new_entry->num_targets = num_targets;
       
   760         if (num_targets > 0) {
       
   761             new_entry->targets = (Atom*)malloc(sizeof(Atom) * num_targets);
       
   762             if (new_entry->targets == NULL) {
       
   763                 DTRACE_PRINT2("%s:%d malloc failed.", __FILE__, __LINE__);
       
   764                 XUngrabServer(dpy);
       
   765                 /* Workaround for bug 5039226 */
       
   766                 XSync(dpy, False);
       
   767                 free((char*)sorted_targets);
       
   768                 return -1;
       
   769             }
       
   770             memcpy(new_entry->targets, sorted_targets,
       
   771                    sizeof(Atom) * num_targets);
       
   772         } else {
       
   773             new_entry->targets = NULL;
       
   774         }
       
   775     }
       
   776 
       
   777     targets_table->num_entries++;
       
   778 
       
   779     put_target_list_table(dpy, targets_table);
       
   780 
       
   781     XUngrabServer(dpy);
       
   782     /* Workaround for bug 5039226 */
       
   783     XSync(dpy, False);
       
   784 
       
   785     ret = targets_table->num_entries - 1;
       
   786 
       
   787     free((char*)sorted_targets);
       
   788 
       
   789     for (i = 0; i < targets_table->num_entries; i++) {
       
   790         free((char*)targets_table->entries[i].targets);
       
   791     }
       
   792 
       
   793     free((char*)targets_table->entries);
       
   794     free((char*)targets_table);
       
   795     return ret;
       
   796 }
       
   797 
       
   798 /*
       
   799  * Retrieves the target list for the specified index.
       
   800  * Stores the number of targets in the list to 'num_targets' and the targets
       
   801  * to 'targets'. On failure stores 0 and NULL respectively.
       
   802  * The caller should free the allocated array when done with it.
       
   803  */
       
   804 void
       
   805 get_target_list_for_index(Display* dpy, int index, Atom** targets, unsigned int* num_targets) {
       
   806     TargetsTable* table = get_target_list_table(dpy);
       
   807     TargetsTableEntry* entry = NULL;
       
   808 
       
   809     if (table == NULL) {
       
   810         DTRACE_PRINT2("%s:%d No target table.", __FILE__, __LINE__);
       
   811         *targets = NULL;
       
   812         *num_targets = 0;
       
   813         return;
       
   814     }
       
   815 
       
   816     if (table->num_entries <= index) {
       
   817         DTRACE_PRINT4("%s:%d index out of bounds idx=%d entries=%d",
       
   818                       __FILE__, __LINE__, index, table->num_entries);
       
   819         *targets = NULL;
       
   820         *num_targets = 0;
       
   821         return;
       
   822     }
       
   823 
       
   824     entry = &table->entries[index];
       
   825 
       
   826     *targets = (Atom*)malloc(entry->num_targets * sizeof(Atom));
       
   827 
       
   828     if (*targets == NULL) {
       
   829         DTRACE_PRINT2("%s:%d malloc failed.", __FILE__, __LINE__);
       
   830         *num_targets = 0;
       
   831         return;
       
   832     }
       
   833 
       
   834     memcpy(*targets, entry->targets, entry->num_targets * sizeof(Atom));
       
   835     *num_targets = entry->num_targets;
       
   836 }
       
   837 
       
   838 jint
       
   839 motif_to_java_actions(unsigned char motif_action) {
       
   840     jint java_action = java_awt_dnd_DnDConstants_ACTION_NONE;
       
   841 
       
   842     if (motif_action & MOTIF_DND_COPY) {
       
   843         java_action |= java_awt_dnd_DnDConstants_ACTION_COPY;
       
   844     }
       
   845 
       
   846     if (motif_action & MOTIF_DND_MOVE) {
       
   847         java_action |= java_awt_dnd_DnDConstants_ACTION_MOVE;
       
   848     }
       
   849 
       
   850     if (motif_action & MOTIF_DND_LINK) {
       
   851         java_action |= java_awt_dnd_DnDConstants_ACTION_LINK;
       
   852     }
       
   853 
       
   854     return java_action;
       
   855 }
       
   856 
       
   857 unsigned char
       
   858 java_to_motif_actions(jint java_action) {
       
   859     unsigned char motif_action = MOTIF_DND_NOOP;
       
   860 
       
   861     if (java_action & java_awt_dnd_DnDConstants_ACTION_COPY) {
       
   862         motif_action |= MOTIF_DND_COPY;
       
   863     }
       
   864 
       
   865     if (java_action & java_awt_dnd_DnDConstants_ACTION_MOVE) {
       
   866         motif_action |= MOTIF_DND_MOVE;
       
   867     }
       
   868 
       
   869     if (java_action & java_awt_dnd_DnDConstants_ACTION_LINK) {
       
   870         motif_action |= MOTIF_DND_LINK;
       
   871     }
       
   872 
       
   873     return motif_action;
       
   874 }
       
   875 
       
   876 Boolean
       
   877 awt_dnd_process_event(XEvent* event) {
       
   878     Boolean ret = awt_dnd_ds_process_event(event) ||
       
   879         awt_dnd_dt_process_event(event);
       
   880 
       
   881     /* Extract the event from the queue if it is processed. */
       
   882     if (ret) {
       
   883         XNextEvent(event->xany.display, event);
       
   884     }
       
   885 
       
   886     return ret;
       
   887 }