1 /*
   2  * Copyright (c) 2003, 2008, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.awt.X11;
  27 
  28 import java.awt.dnd.DnDConstants;
  29 
  30 import java.nio.ByteOrder;
  31 
  32 import java.util.Arrays;
  33 
  34 import sun.misc.Unsafe;
  35 
  36 /**
  37  * Motif DnD protocol global constants and convenience routines.
  38  *
  39  * @since 1.5
  40  */
  41 class MotifDnDConstants {
  42     // utility class can not be instantiated
  43     private MotifDnDConstants() {}
  44     // Note that offsets in all native structures below do not depend on the
  45     // architecture.
  46     private static final Unsafe unsafe = XlibWrapper.unsafe;
  47     static final XAtom XA_MOTIF_ATOM_0 = XAtom.get("_MOTIF_ATOM_0");
  48     static final XAtom XA_MOTIF_DRAG_WINDOW = XAtom.get("_MOTIF_DRAG_WINDOW");
  49     static final XAtom XA_MOTIF_DRAG_TARGETS = XAtom.get("_MOTIF_DRAG_TARGETS");
  50     static final XAtom XA_MOTIF_DRAG_INITIATOR_INFO =
  51         XAtom.get("_MOTIF_DRAG_INITIATOR_INFO");
  52     static final XAtom XA_MOTIF_DRAG_RECEIVER_INFO =
  53         XAtom.get("_MOTIF_DRAG_RECEIVER_INFO");
  54     static final XAtom XA_MOTIF_DRAG_AND_DROP_MESSAGE =
  55         XAtom.get("_MOTIF_DRAG_AND_DROP_MESSAGE");
  56     static final XAtom XA_XmTRANSFER_SUCCESS =
  57         XAtom.get("XmTRANSFER_SUCCESS");
  58     static final XAtom XA_XmTRANSFER_FAILURE =
  59         XAtom.get("XmTRANSFER_FAILURE");
  60     static final XSelection MotifDnDSelection = new XSelection(XA_MOTIF_ATOM_0);
  61 
  62     public static final byte MOTIF_DND_PROTOCOL_VERSION = 0;
  63 
  64     /* Supported protocol styles */
  65     public static final int MOTIF_PREFER_PREREGISTER_STYLE = 2;
  66     public static final int MOTIF_PREFER_DYNAMIC_STYLE     = 4;
  67     public static final int MOTIF_DYNAMIC_STYLE            = 5;
  68     public static final int MOTIF_PREFER_RECEIVER_STYLE    = 6;
  69 
  70     /* Info structure sizes */
  71     public static final int MOTIF_INITIATOR_INFO_SIZE      = 8;
  72     public static final int MOTIF_RECEIVER_INFO_SIZE       = 16;
  73 
  74     /* Sender/reason message masks */
  75     public static final byte MOTIF_MESSAGE_REASON_MASK      = (byte)0x7F;
  76     public static final byte MOTIF_MESSAGE_SENDER_MASK      = (byte)0x80;
  77     public static final byte MOTIF_MESSAGE_FROM_RECEIVER    = (byte)0x80;
  78     public static final byte MOTIF_MESSAGE_FROM_INITIATOR   = (byte)0;
  79 
  80     /* Message flags masks and shifts */
  81     public static final int MOTIF_DND_ACTION_MASK   = 0x000F;
  82     public static final int MOTIF_DND_ACTION_SHIFT  =      0;
  83     public static final int MOTIF_DND_STATUS_MASK   = 0x00F0;
  84     public static final int MOTIF_DND_STATUS_SHIFT  =      4;
  85     public static final int MOTIF_DND_ACTIONS_MASK  = 0x0F00;
  86     public static final int MOTIF_DND_ACTIONS_SHIFT =      8;
  87 
  88     /* message type constants */
  89     public static final byte TOP_LEVEL_ENTER   = 0;
  90     public static final byte TOP_LEVEL_LEAVE   = 1;
  91     public static final byte DRAG_MOTION       = 2;
  92     public static final byte DROP_SITE_ENTER   = 3;
  93     public static final byte DROP_SITE_LEAVE   = 4;
  94     public static final byte DROP_START        = 5;
  95     public static final byte DROP_FINISH       = 6;
  96     public static final byte DRAG_DROP_FINISH  = 7;
  97     public static final byte OPERATION_CHANGED = 8;
  98 
  99     /* drop action constants */
 100     public static final int MOTIF_DND_NOOP = 0;
 101     public static final int MOTIF_DND_MOVE = 1 << 0;
 102     public static final int MOTIF_DND_COPY = 1 << 1;
 103     public static final int MOTIF_DND_LINK = 1 << 2;
 104 
 105     /* drop site status constants */
 106     public static final byte MOTIF_NO_DROP_SITE      = (byte)1;
 107     public static final byte MOTIF_INVALID_DROP_SITE = (byte)2;
 108     public static final byte MOTIF_VALID_DROP_SITE   = (byte)3;
 109 
 110     private static long readMotifWindow() throws XException {
 111         long defaultScreenNumber = XlibWrapper.DefaultScreen(XToolkit.getDisplay());
 112         long defaultRootWindow =
 113             XlibWrapper.RootWindow(XToolkit.getDisplay(), defaultScreenNumber);
 114 
 115         long motifWindow = 0;
 116 
 117         WindowPropertyGetter wpg = new WindowPropertyGetter(defaultRootWindow,
 118                                                             XA_MOTIF_DRAG_WINDOW,
 119                                                             0, 1,
 120                                                             false,
 121                                                             XConstants.AnyPropertyType);
 122         try {
 123             int status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
 124 
 125             if (status == XConstants.Success &&
 126                 wpg.getData() != 0 &&
 127                 wpg.getActualType() == XAtom.XA_WINDOW &&
 128                 wpg.getActualFormat() == 32 &&
 129                 wpg.getNumberOfItems() == 1) {
 130                 long data = wpg.getData();
 131                 // XID is CARD32.
 132                 motifWindow = Native.getLong(data);
 133             }
 134 
 135             return motifWindow;
 136         } finally {
 137             wpg.dispose();
 138         }
 139     }
 140 
 141     private static long createMotifWindow() throws XException {
 142         assert XToolkit.isAWTLockHeldByCurrentThread();
 143 
 144         long defaultScreenNumber =
 145             XlibWrapper.DefaultScreen(XToolkit.getDisplay());
 146         long defaultRootWindow =
 147             XlibWrapper.RootWindow(XToolkit.getDisplay(), defaultScreenNumber);
 148 
 149         long motifWindow = 0;
 150 
 151         long displayString = XlibWrapper.XDisplayString(XToolkit.getDisplay());
 152 
 153         if (displayString == 0) {
 154             throw new XException("XDisplayString returns NULL");
 155         }
 156 
 157         long newDisplay = XlibWrapper.XOpenDisplay(displayString);
 158 
 159         if (newDisplay == 0) {
 160             throw new XException("XOpenDisplay returns NULL");
 161         }
 162 
 163         XlibWrapper.XGrabServer(newDisplay);
 164 
 165         try {
 166             XlibWrapper.XSetCloseDownMode(newDisplay, (int)XConstants.RetainPermanent);
 167 
 168             XSetWindowAttributes xwa = new XSetWindowAttributes();
 169 
 170             try {
 171                 xwa.set_override_redirect(true);
 172                 xwa.set_event_mask(XConstants.PropertyChangeMask);
 173 
 174                 motifWindow = XlibWrapper.XCreateWindow(newDisplay, defaultRootWindow,
 175                                                         -10, -10, 1, 1, 0, 0,
 176                                                         XConstants.InputOnly,
 177                                                         XConstants.CopyFromParent,
 178                                                         (XConstants.CWOverrideRedirect |
 179                                                          XConstants.CWEventMask),
 180                                                         xwa.pData);
 181 
 182                 if (motifWindow == 0) {
 183                     throw new XException("XCreateWindow returns NULL");
 184                 }
 185 
 186                 XlibWrapper.XMapWindow(newDisplay, motifWindow);
 187 
 188                 long data = Native.allocateLongArray(1);
 189 
 190                 try {
 191                     Native.putLong(data, motifWindow);
 192 
 193                     XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
 194                     XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
 195                                                 defaultRootWindow,
 196                                                 XA_MOTIF_DRAG_WINDOW.getAtom(),
 197                                                 XAtom.XA_WINDOW, 32,
 198                                                 XConstants.PropModeReplace,
 199                                                 data, 1);
 200 
 201                     XToolkit.RESTORE_XERROR_HANDLER();
 202 
 203                     if (XToolkit.saved_error != null &&
 204                         XToolkit.saved_error.get_error_code() != XConstants.Success) {
 205                         throw new XException("Cannot write motif drag window handle.");
 206                     }
 207 
 208                     return motifWindow;
 209                 } finally {
 210                     unsafe.freeMemory(data);
 211                 }
 212             } finally {
 213                 xwa.dispose();
 214             }
 215         } finally {
 216             XlibWrapper.XUngrabServer(newDisplay);
 217             XlibWrapper.XCloseDisplay(newDisplay);
 218         }
 219     }
 220 
 221     private static long getMotifWindow() throws XException {
 222         /*
 223          * Note: it is unsafe to cache the motif drag window handle, as another
 224          * client can change the _MOTIF_DRAG_WINDOW property on the root, the handle
 225          * becomes out-of-sync and all subsequent drag operations will fail.
 226          */
 227         long motifWindow = readMotifWindow();
 228         if (motifWindow == 0) {
 229             motifWindow = createMotifWindow();
 230         }
 231         return motifWindow;
 232     }
 233 
 234     public static final class Swapper {
 235         // utility class can not be instantiated
 236         private Swapper() {}
 237 
 238         public static short swap(short s) {
 239             return (short)(((s & 0xFF00) >>> 8) | ((s & 0xFF) << 8));
 240         }
 241         public static int swap(int i) {
 242             return ((i & 0xFF000000) >>> 24) | ((i & 0x00FF0000) >>> 8) |
 243                 ((i & 0x0000FF00) << 8) | ((i & 0x000000FF) << 24);
 244         }
 245 
 246         public static short getShort(long data, byte order) {
 247             short s = unsafe.getShort(data);
 248             if (order != MotifDnDConstants.getByteOrderByte()) {
 249                 return swap(s);
 250             } else {
 251                 return s;
 252             }
 253         }
 254         public static int getInt(long data, byte order) {
 255             int i = unsafe.getInt(data);
 256             if (order != MotifDnDConstants.getByteOrderByte()) {
 257                 return swap(i);
 258             } else {
 259                 return i;
 260             }
 261         }
 262     }
 263 
 264     /**
 265      * DragBSI.h:
 266      *
 267      * typedef struct {
 268      *    BYTE          byte_order;
 269      *    BYTE          protocol_version;
 270      *    CARD16        num_target_lists B16;
 271      *    CARD32        heap_offset B32;
 272      * } xmMotifTargetsPropertyRec;
 273      */
 274     private static long[][] getTargetListTable(long motifWindow)
 275       throws XException {
 276 
 277         WindowPropertyGetter wpg = new WindowPropertyGetter(motifWindow,
 278                                                             XA_MOTIF_DRAG_TARGETS,
 279                                                             0, 100000L,
 280                                                             false,
 281                                                             XA_MOTIF_DRAG_TARGETS.getAtom());
 282         try {
 283             int status = wpg.execute(XErrorHandler.IgnoreBadWindowHandler.getInstance());
 284 
 285             if (status != XConstants.Success
 286                 || wpg.getActualType() != XA_MOTIF_DRAG_TARGETS.getAtom()
 287                 || wpg.getData() == 0) {
 288 
 289                 return null;
 290             }
 291 
 292             long data = wpg.getData();
 293 
 294             if (unsafe.getByte(data + 1) != MOTIF_DND_PROTOCOL_VERSION) {
 295                 return null;
 296             }
 297 
 298             boolean swapNeeded = unsafe.getByte(data + 0) != getByteOrderByte();
 299 
 300             short numTargetLists = unsafe.getShort(data + 2);
 301 
 302             if (swapNeeded) {
 303                 numTargetLists = Swapper.swap(numTargetLists);
 304             }
 305 
 306             long[][] table = new long[numTargetLists][];
 307             ByteOrder byteOrder = ByteOrder.nativeOrder();
 308             if (swapNeeded) {
 309                 byteOrder = (byteOrder == ByteOrder.LITTLE_ENDIAN) ?
 310                     ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
 311             }
 312 
 313             long bufptr = data + 8;
 314             for (short i = 0; i < numTargetLists; i++) {
 315                 short numTargets = unsafe.getShort(bufptr);
 316                 bufptr += 2;
 317                 if (swapNeeded) {
 318                     numTargets = Swapper.swap(numTargets);
 319                 }
 320 
 321                 table[i] = new long[numTargets];
 322 
 323                 for (short j = 0; j < numTargets; j++) {
 324                     // NOTE: cannot use Unsafe.getInt(), since it crashes on
 325                     // Solaris/Sparc if the address is not a multiple of 4.
 326                     int target = 0;
 327                     if (byteOrder == ByteOrder.LITTLE_ENDIAN) {
 328                         for (int idx = 0; idx < 4; idx++) {
 329                             target |= (unsafe.getByte(bufptr + idx) << 8*idx)
 330                                 & (0xFF << 8*idx);
 331                         }
 332                     } else {
 333                         for (int idx = 0; idx < 4; idx++) {
 334                             target |= (unsafe.getByte(bufptr + idx) << 8*(3-idx))
 335                                 & (0xFF << 8*(3-idx));
 336                         }
 337                     }
 338                     // NOTE: don't need to swap, since we read it in the proper
 339                     // order already.
 340                     table[i][j] = target;
 341                     bufptr += 4;
 342                 }
 343             }
 344             return table;
 345         } finally {
 346             wpg.dispose();
 347         }
 348     }
 349 
 350     private static void putTargetListTable(long motifWindow, long[][] table)
 351       throws XException {
 352         assert XToolkit.isAWTLockHeldByCurrentThread();
 353 
 354         int tableSize = 8; /* The size of leading xmMotifTargetsPropertyRec. */
 355 
 356         for (int i = 0; i < table.length; i++) {
 357             tableSize += table[i].length * 4 + 2;
 358         }
 359 
 360         long data = unsafe.allocateMemory(tableSize);
 361 
 362         try {
 363             // BYTE          byte_order;
 364             unsafe.putByte(data + 0, getByteOrderByte());
 365             // BYTE          protocol_version;
 366             unsafe.putByte(data + 1, MOTIF_DND_PROTOCOL_VERSION);
 367             // CARD16        num_target_lists B16;
 368             unsafe.putShort(data + 2, (short)table.length);
 369             // CARD32        heap_offset B32;
 370             unsafe.putInt(data + 4, tableSize);
 371 
 372             long bufptr = data + 8;
 373 
 374             for (int i = 0; i < table.length; i++) {
 375                 unsafe.putShort(bufptr, (short)table[i].length);
 376                 bufptr += 2;
 377 
 378                 for (int j = 0; j < table[i].length; j++) {
 379                     int target = (int)table[i][j];
 380                     // NOTE: cannot use Unsafe.putInt(), since it crashes on
 381                     // Solaris/Sparc if the address is not a multiple of 4.
 382                     if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
 383                         for (int idx = 0; idx < 4; idx++) {
 384                             byte b = (byte)((target & (0xFF << (8*idx))) >> (8*idx));
 385                             unsafe.putByte(bufptr + idx, b);
 386                         }
 387                     } else {
 388                         for (int idx = 0; idx < 4; idx++) {
 389                             byte b = (byte)((target & (0xFF << (8*idx))) >> (8*idx));
 390                             unsafe.putByte(bufptr + (3-idx), b);
 391                         }
 392                     }
 393                     bufptr += 4;
 394                 }
 395             }
 396 
 397             XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
 398             XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
 399                                         motifWindow,
 400                                         XA_MOTIF_DRAG_TARGETS.getAtom(),
 401                                         XA_MOTIF_DRAG_TARGETS.getAtom(), 8,
 402                                         XConstants.PropModeReplace,
 403                                         data, tableSize);
 404 
 405             XToolkit.RESTORE_XERROR_HANDLER();
 406 
 407             if (XToolkit.saved_error != null &&
 408                 XToolkit.saved_error.get_error_code() != XConstants.Success) {
 409 
 410                 // Create a new motif window and retry.
 411                 motifWindow = createMotifWindow();
 412 
 413                 XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
 414                 XlibWrapper.XChangeProperty(XToolkit.getDisplay(),
 415                                             motifWindow,
 416                                             XA_MOTIF_DRAG_TARGETS.getAtom(),
 417                                             XA_MOTIF_DRAG_TARGETS.getAtom(), 8,
 418                                             XConstants.PropModeReplace,
 419                                             data, tableSize);
 420 
 421                 XToolkit.RESTORE_XERROR_HANDLER();
 422 
 423                 if (XToolkit.saved_error != null &&
 424                     XToolkit.saved_error.get_error_code() != XConstants.Success) {
 425                     throw new XException("Cannot write motif drag targets property.");
 426                 }
 427             }
 428         } finally {
 429             unsafe.freeMemory(data);
 430         }
 431     }
 432 
 433     static int getIndexForTargetList(long[] formats) throws XException {
 434         assert XToolkit.isAWTLockHeldByCurrentThread();
 435 
 436         if (formats.length > 0) {
 437             // Make a defensive copy.
 438             formats = (long[])formats.clone();
 439 
 440             Arrays.sort(formats);
 441         }
 442 
 443         // NOTE: getMotifWindow() should never be called if the server is
 444         // grabbed. This will lock up the application as it grabs the server
 445         // itself.
 446         // Since we don't grab the server before getMotifWindow(), another
 447         // client might replace motif window after we read it from the root, but
 448         // before we grab the server.
 449         // We cannot resolve this problem, but we believe that this scenario is
 450         // very unlikely to happen.
 451         long motifWindow = getMotifWindow();
 452 
 453         XlibWrapper.XGrabServer(XToolkit.getDisplay());
 454 
 455         try {
 456             long[][] table = getTargetListTable(motifWindow);
 457 
 458             if (table != null) {
 459                 for (int i = 0; i < table.length; i++) {
 460                     boolean equals = true;
 461                     if (table[i].length == formats.length) {
 462                         for (int j = 0; j < table[i].length; j++) {
 463                             if (table[i][j] != formats[j]) {
 464                                 equals = false;
 465                                 break;
 466                             }
 467                         }
 468                     } else {
 469                         equals = false;
 470                     }
 471 
 472                     if (equals) {
 473                         XlibWrapper.XUngrabServer(XToolkit.getDisplay());
 474                         return i;
 475                     }
 476                 }
 477             } else {
 478                 // Create a new table.
 479                 // The first two entries must always be the same.
 480                 // (see DragBS.c)
 481                 table = new long[2][];
 482                 table[0] = new long[] { 0 };
 483                 table[1] = new long[] { XAtom.XA_STRING };
 484             }
 485 
 486             /* Index not found - expand the targets table. */
 487             long[][] new_table = new long[table.length + 1][];
 488 
 489             /* Copy the old contents to the new table. */
 490             for (int i = 0; i < table.length; i++) {
 491                 new_table[i] = table[i];
 492             }
 493 
 494             /* Fill in the new entry */
 495             new_table[new_table.length - 1] = formats;
 496 
 497             putTargetListTable(motifWindow, new_table);
 498 
 499             return new_table.length - 1;
 500         } finally {
 501             XlibWrapper.XUngrabServer(XToolkit.getDisplay());
 502         }
 503     }
 504 
 505     static long[] getTargetListForIndex(int index) {
 506         long motifWindow = getMotifWindow();
 507         long[][] table = getTargetListTable(motifWindow);
 508 
 509         if (index < 0 || index >= table.length) {
 510             return new long[0];
 511         } else {
 512             return table[index];
 513         }
 514     }
 515 
 516     static byte getByteOrderByte() {
 517         // 'l' - for little endian, 'B' - for big endian.
 518         return ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN ?
 519             (byte)0x6C : (byte)0x42;
 520     }
 521 
 522     static void writeDragInitiatorInfoStruct(long window, int index) throws XException {
 523         assert XToolkit.isAWTLockHeldByCurrentThread();
 524 
 525         long structData = unsafe.allocateMemory(MOTIF_INITIATOR_INFO_SIZE);
 526 
 527         try {
 528             // BYTE byte_order
 529             unsafe.putByte(structData, getByteOrderByte());
 530             // BYTE protocol_version
 531             unsafe.putByte(structData + 1, MOTIF_DND_PROTOCOL_VERSION);
 532             // CARD16 protocol_version
 533             unsafe.putShort(structData + 2, (short)index);
 534             // CARD32 icc_handle
 535             unsafe.putInt(structData + 4, (int)XA_MOTIF_ATOM_0.getAtom());
 536 
 537             XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
 538             XlibWrapper.XChangeProperty(XToolkit.getDisplay(), window,
 539                                         XA_MOTIF_ATOM_0.getAtom(),
 540                                         XA_MOTIF_DRAG_INITIATOR_INFO.getAtom(),
 541                                         8, XConstants.PropModeReplace,
 542                                         structData, MOTIF_INITIATOR_INFO_SIZE);
 543             XToolkit.RESTORE_XERROR_HANDLER();
 544 
 545             if (XToolkit.saved_error != null &&
 546                 XToolkit.saved_error.get_error_code() != XConstants.Success) {
 547                 throw new XException("Cannot write drag initiator info");
 548             }
 549         } finally {
 550             unsafe.freeMemory(structData);
 551         }
 552     }
 553 
 554     static void writeDragReceiverInfoStruct(long window) throws XException {
 555         assert XToolkit.isAWTLockHeldByCurrentThread();
 556 
 557         int dataSize = MotifDnDConstants.MOTIF_RECEIVER_INFO_SIZE;
 558         long data = unsafe.allocateMemory(dataSize);
 559 
 560         try {
 561             unsafe.putByte(data, MotifDnDConstants.getByteOrderByte()); /* byte order */
 562             unsafe.putByte(data + 1, MotifDnDConstants.MOTIF_DND_PROTOCOL_VERSION); /* protocol version */
 563             unsafe.putByte(data + 2, (byte)MotifDnDConstants.MOTIF_DYNAMIC_STYLE); /* protocol style */
 564             unsafe.putByte(data + 3, (byte)0); /* pad */
 565             unsafe.putInt(data + 4, (int)window); /* proxy window */
 566             unsafe.putShort(data + 8, (short)0); /* num_drop_sites */
 567             unsafe.putShort(data + 10, (short)0); /* pad */
 568             unsafe.putInt(data + 12, dataSize);
 569 
 570             XToolkit.WITH_XERROR_HANDLER(XErrorHandler.VerifyChangePropertyHandler.getInstance());
 571             XlibWrapper.XChangeProperty(XToolkit.getDisplay(), window,
 572                                         XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
 573                                         XA_MOTIF_DRAG_RECEIVER_INFO.getAtom(),
 574                                         8, XConstants.PropModeReplace,
 575                                         data, dataSize);
 576             XToolkit.RESTORE_XERROR_HANDLER();
 577 
 578             if (XToolkit.saved_error != null &&
 579                 XToolkit.saved_error.get_error_code() != XConstants.Success) {
 580                 throw new XException("Cannot write Motif receiver info property");
 581             }
 582         } finally {
 583             unsafe.freeMemory(data);
 584         }
 585     }
 586 
 587     public static int getMotifActionsForJavaActions(int javaActions) {
 588         int motifActions = MOTIF_DND_NOOP;
 589 
 590         if ((javaActions & DnDConstants.ACTION_MOVE) != 0) {
 591             motifActions |= MOTIF_DND_MOVE;
 592         }
 593         if ((javaActions & DnDConstants.ACTION_COPY) != 0) {
 594             motifActions |= MOTIF_DND_COPY;
 595         }
 596         if ((javaActions & DnDConstants.ACTION_LINK) != 0) {
 597             motifActions |= MOTIF_DND_LINK;
 598         }
 599 
 600         return motifActions;
 601     }
 602 
 603     public static int getJavaActionsForMotifActions(int motifActions) {
 604         int javaActions = DnDConstants.ACTION_NONE;
 605 
 606         if ((motifActions & MOTIF_DND_MOVE) != 0) {
 607             javaActions |= DnDConstants.ACTION_MOVE;
 608         }
 609         if ((motifActions & MOTIF_DND_COPY) != 0) {
 610             javaActions |= DnDConstants.ACTION_COPY;
 611         }
 612         if ((motifActions & MOTIF_DND_LINK) != 0) {
 613             javaActions |= DnDConstants.ACTION_LINK;
 614         }
 615 
 616         return javaActions;
 617     }
 618 }
--- EOF ---