1 /*
2  * Copyright (c) 2003, 2014, 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 jdk.internal.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
MotifDnDConstants()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 
readMotifWindow()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 
createMotifWindow()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, 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                     XErrorHandlerUtil.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                     XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
202 
203                     if ((XErrorHandlerUtil.saved_error != null) &&
204                         (XErrorHandlerUtil.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 
getMotifWindow()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
Swapper()236         private Swapper() {}
237 
swap(short s)238         public static short swap(short s) {
239             return (short)(((s & 0xFF00) >>> 8) | ((s & 0xFF) << 8));
240         }
swap(int i)241         public static int swap(int i) {
242             return ((i & 0xFF000000) >>> 24) | ((i & 0x00FF0000) >>> 8) |
243                 ((i & 0x0000FF00) << 8) | ((i & 0x000000FF) << 24);
244         }
245 
getShort(long data, byte order)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         }
getInt(long data, byte order)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      */
getTargetListTable(long motifWindow)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 
putTargetListTable(long motifWindow, long[][] table)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             XErrorHandlerUtil.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             XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
406 
407             if ((XErrorHandlerUtil.saved_error != null) &&
408                 (XErrorHandlerUtil.saved_error.get_error_code() != XConstants.Success)) {
409 
410                 // Create a new motif window and retry.
411                 motifWindow = createMotifWindow();
412 
413                 XErrorHandlerUtil.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                 XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
422 
423                 if ((XErrorHandlerUtil.saved_error != null) &&
424                     (XErrorHandlerUtil.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 
getIndexForTargetList(long[] formats)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 = 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 
getTargetListForIndex(int index)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 
getByteOrderByte()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 
writeDragInitiatorInfoStruct(long window, int index)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             XErrorHandlerUtil.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             XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
544 
545             if ((XErrorHandlerUtil.saved_error != null) &&
546                 (XErrorHandlerUtil.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 
writeDragReceiverInfoStruct(long window)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             XErrorHandlerUtil.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             XErrorHandlerUtil.RESTORE_XERROR_HANDLER();
577 
578             if ((XErrorHandlerUtil.saved_error != null) &&
579                 (XErrorHandlerUtil.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 
getMotifActionsForJavaActions(int javaActions)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 
getJavaActionsForMotifActions(int motifActions)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 }
619