jdk/src/solaris/native/sun/awt/awt_DataTransferer.c
changeset 1192 715cf9378c53
parent 1051 90cf935adb35
parent 1191 f142c1da78c2
child 1193 41afb8ee8f45
equal deleted inserted replaced
1051:90cf935adb35 1192:715cf9378c53
     1 /*
       
     2  * Copyright 2000-2005 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_p.h"
       
    31 #include <X11/Intrinsic.h>
       
    32 #include <X11/Xutil.h>
       
    33 
       
    34 #include <sys/utsname.h>
       
    35 
       
    36 #include <jni.h>
       
    37 #include <jni_util.h>
       
    38 
       
    39 #include "sun_awt_datatransfer_DataTransferer.h"
       
    40 #include "sun_awt_motif_MDataTransferer.h"
       
    41 
       
    42 #include "awt_XmDnD.h"
       
    43 #include "awt_DataTransferer.h"
       
    44 
       
    45 static jclass string;
       
    46 
       
    47 XContext awt_convertDataContext = 0;
       
    48 
       
    49 Atom XA_TARGETS;
       
    50 
       
    51 extern struct X11GraphicsConfigIDs x11GraphicsConfigIDs;
       
    52 
       
    53 typedef enum {
       
    54     SelectionPending,
       
    55     SelectionSuccess,
       
    56     SelectionFailure,
       
    57     SelectionOwnerTimedOut
       
    58 } SelectionStatus;
       
    59 
       
    60 /* Should only be accessed by the current owner of AWT_LOCK. */
       
    61 static SelectionStatus globalSelectionStatus = SelectionPending;
       
    62 
       
    63 static SelectionStatus get_selection_status() {
       
    64     return globalSelectionStatus;
       
    65 }
       
    66 
       
    67 static void set_selection_status(SelectionStatus status) {
       
    68     globalSelectionStatus = status;
       
    69 }
       
    70 
       
    71 static void
       
    72 selection_request_filter(Widget widget, XtPointer closure, XEvent *event,
       
    73                          Boolean *cont) {
       
    74     if (event->type == SelectionRequest) {
       
    75         Window awt_root_window = XtWindow(awt_root_shell);
       
    76         Atom selection = event->xselectionrequest.selection;
       
    77         Window owner = XGetSelectionOwner(event->xany.display, selection);
       
    78 
       
    79         if (owner != awt_root_window) {
       
    80             XSelectionEvent notify;
       
    81 
       
    82             notify.type = SelectionNotify;
       
    83             notify.display = event->xselectionrequest.display;
       
    84             notify.requestor = event->xselectionrequest.requestor;
       
    85             notify.selection = event->xselectionrequest.selection;
       
    86             notify.time = event->xselectionrequest.time;
       
    87             notify.target = event->xselectionrequest.target;
       
    88             notify.property = None;
       
    89 
       
    90             XSendEvent(notify.display, notify.requestor, False,
       
    91                        (unsigned long)0, (XEvent*)&notify);
       
    92             *cont = False;
       
    93         }
       
    94     }
       
    95 }
       
    96 
       
    97 /**
       
    98  * global function to initialize this client as a Dynamic-only app.
       
    99  *
       
   100  * gets called once during toolkit initialization.
       
   101  */
       
   102 
       
   103 void awt_initialize_DataTransferer() {
       
   104     JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
       
   105     jclass stringClassLocal = NULL;
       
   106 
       
   107     DASSERT(string == NULL);
       
   108 
       
   109     stringClassLocal = (*env)->FindClass(env, "java/lang/String");
       
   110 
       
   111     if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   112         (*env)->ExceptionDescribe(env);
       
   113         (*env)->ExceptionClear(env);
       
   114         DASSERT(False);
       
   115     }
       
   116 
       
   117     if (JNU_IsNull(env, stringClassLocal)) return;
       
   118 
       
   119     string = (*env)->NewGlobalRef(env, stringClassLocal); /* never freed! */
       
   120     (*env)->DeleteLocalRef(env, stringClassLocal);
       
   121 
       
   122     if (JNU_IsNull(env, string)) {
       
   123         JNU_ThrowOutOfMemoryError(env, "");
       
   124         return;
       
   125     }
       
   126 
       
   127     DASSERT(awt_convertDataContext == 0);
       
   128     awt_convertDataContext = XUniqueContext();
       
   129     DASSERT(awt_convertDataContext != 0);
       
   130 
       
   131     /*
       
   132      * Fixes for 4513976 and 4818143.
       
   133      */
       
   134     XtAppSetSelectionTimeout(awt_appContext,
       
   135             JNU_CallStaticMethodByName(env, NULL, "sun/awt/UNIXToolkit",
       
   136                                        "getDatatransferTimeout", "()I").i);
       
   137 
       
   138     /*
       
   139      * Xt selection machinery doesn't respond to SelectionRequests if the
       
   140      * event arrives on a widget that is not the current selection owner.
       
   141      * This can happen if XtDisownSelection was called when SelectionRequest was
       
   142      * already on the native queue.
       
   143      * If the requestor is another JVM, it hangs for the selection timeout
       
   144      * as SelectionNotify is never sent.
       
   145      * We install an event handler that filters out SelectionRequests if the
       
   146      * awt_root_shell is not the current selection owner.
       
   147      */
       
   148     XtAddEventHandler(awt_root_shell, (EventMask)0, True,
       
   149                       selection_request_filter, NULL);
       
   150 
       
   151     XA_TARGETS = XInternAtom(awt_display, "TARGETS", False);
       
   152 }
       
   153 
       
   154 /*
       
   155  * Single routine to convert to target FILE_NAME or _DT_FILENAME
       
   156  */
       
   157 Boolean
       
   158 convertFileType(jbyteArray data, Atom * type, XtPointer * value,
       
   159                 unsigned long *length, int32_t *format)
       
   160 {
       
   161     /*
       
   162      * Convert the internal representation to an File Name.
       
   163      * The data passed is an array of
       
   164      * null separated bytes. Each series of bytes is a string
       
   165      * that is then converted to an XString which are then put
       
   166      * into an XStringList and put into an XTextProperty for
       
   167      * usage in other programs.
       
   168      *
       
   169      * It would be desireable to have dataConvert to this conversion
       
   170      * but it isn't possible to return a byte array that represents
       
   171      * the XTextProperty.
       
   172      */
       
   173 
       
   174     JNIEnv*       env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
       
   175     jboolean      isCopy=JNI_FALSE;
       
   176     XTextProperty tp;
       
   177     jsize         len;
       
   178     jsize         strings = 0;
       
   179     jsize         i;
       
   180     char**        stringList;
       
   181     Status        s;
       
   182     jbyte*        bytes;
       
   183     char*         start;
       
   184     size_t        slen;
       
   185     char*         utf;
       
   186 
       
   187     if ((*env)->PushLocalFrame(env, 16) < 0) {
       
   188         return False;
       
   189     }
       
   190 
       
   191     /* convert the data to an Array of Byte Elements */
       
   192     bytes = (*env)->GetByteArrayElements(env, data, &isCopy);
       
   193     if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   194         (*env)->ExceptionDescribe(env);
       
   195         (*env)->ExceptionClear(env);
       
   196         (*env)->PopLocalFrame(env, NULL);
       
   197         return False;
       
   198     }
       
   199 
       
   200     if (JNU_IsNull(env, bytes)) {
       
   201         (*env)->PopLocalFrame(env, NULL);
       
   202         return False;
       
   203     }
       
   204 
       
   205     /* Get the length of the area */
       
   206     len = (*env)->GetArrayLength(env, data);
       
   207     if (len == 0) {
       
   208         (*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT);
       
   209         (*env)->PopLocalFrame(env, NULL);
       
   210         return False;
       
   211     }
       
   212 
       
   213     /*
       
   214      * determine the number of lists. The byteArray is null separated list of
       
   215      * strings.
       
   216      */
       
   217     for (i = 0; i < len; i++) {
       
   218         if (bytes[i] == '\0') {
       
   219             strings++;
       
   220         }
       
   221     }
       
   222 
       
   223     /* Allocate an X11 string list */
       
   224     stringList = (char **)XtCalloc(strings, sizeof(char *));
       
   225     if (stringList == (char**)NULL) {
       
   226         (*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT);
       
   227         (*env)->PopLocalFrame(env, NULL);
       
   228         return False;
       
   229     }
       
   230 
       
   231     for (i = 0; i < strings; i++) {
       
   232         if (i == 0) {
       
   233             start = (char*)bytes;
       
   234         } else {
       
   235             start = (char*)&bytes[slen];
       
   236         }
       
   237 
       
   238         /*
       
   239          * if start is a NULL we're at the end of the list
       
   240          * We'll just a have null entry on the end of the list
       
   241          */
       
   242         if (start[0] == '\0') {
       
   243             stringList[i] = NULL;
       
   244             continue;
       
   245         }
       
   246         slen = strlen(start) + 1;
       
   247 
       
   248         stringList[i] = (char*)XtCalloc(slen, sizeof(char));
       
   249 
       
   250         if (stringList[i] == (char *)NULL) {
       
   251             jsize j;
       
   252 
       
   253             (*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT);
       
   254 
       
   255             for (j = 0; j < i; j++) {
       
   256                 XtFree((void *)stringList[j]);
       
   257             }
       
   258 
       
   259             (*env)->PopLocalFrame(env, NULL);
       
   260 
       
   261             return False;
       
   262         }
       
   263 
       
   264         memcpy((void *)stringList[i], (const void*)start, slen);
       
   265     }
       
   266 
       
   267     (*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT);
       
   268     s = XStringListToTextProperty(stringList, strings, &tp);
       
   269 
       
   270     /* free the strings that were created */
       
   271     for (i = 0; i < strings; i++) {
       
   272         if (stringList[i] != NULL) {
       
   273             XtFree((void*)stringList[i]);
       
   274         }
       
   275     }
       
   276 
       
   277     XtFree((void*)stringList);
       
   278 
       
   279     if (s == 0) {
       
   280         (*env)->PopLocalFrame(env, NULL);
       
   281         return False;
       
   282     }
       
   283 
       
   284     *value = (XtPointer)XtCalloc(tp.nitems, sizeof(char));
       
   285 
       
   286     if (*value == (XtPointer)NULL) {
       
   287         XFree((void*)tp.value);
       
   288 
       
   289         (*env)->PopLocalFrame(env, NULL);
       
   290 
       
   291         return False;
       
   292     }
       
   293 
       
   294     memcpy((void *)(*value), (const void *)tp.value, tp.nitems);
       
   295 
       
   296     XFree((void*)tp.value);
       
   297 
       
   298     *length = tp.nitems;
       
   299     *type   = tp.encoding;
       
   300     *format = tp.format;
       
   301     (*env)->PopLocalFrame(env, NULL);
       
   302     return True;
       
   303 }
       
   304 
       
   305 /*
       
   306  * Class:     sun_awt_motif_MDataTransferer
       
   307  * Method:    getAtomForTarget
       
   308  * Signature: (Ljava/lang/String;)J
       
   309  */
       
   310 
       
   311 JNIEXPORT jlong JNICALL
       
   312 Java_sun_awt_motif_MDataTransferer_getAtomForTarget(JNIEnv *env,
       
   313                                                     jclass cls,
       
   314                                                     jstring targetString)
       
   315 {
       
   316     Atom target;
       
   317     char *target_str;
       
   318 
       
   319     if (JNU_IsNull(env, targetString)) {
       
   320         JNU_ThrowNullPointerException(env, "NullPointerException");
       
   321         return -1;
       
   322     }
       
   323     target_str = (char *) JNU_GetStringPlatformChars(env, targetString, NULL);
       
   324 
       
   325     AWT_LOCK();
       
   326 
       
   327     target = XInternAtom(awt_display, target_str, False);
       
   328 
       
   329     AWT_UNLOCK();
       
   330 
       
   331     JNU_ReleaseStringPlatformChars(env, targetString,
       
   332                                    (const char *) target_str);
       
   333     return target;
       
   334 }
       
   335 
       
   336 /*
       
   337  * Class:     sun_awt_motif_MDataTransferer
       
   338  * Method:    getTargetNameForAtom
       
   339  * Signature: (J)Ljava/lang/String;
       
   340  */
       
   341 
       
   342 JNIEXPORT jstring JNICALL
       
   343 Java_sun_awt_motif_MDataTransferer_getTargetNameForAtom(JNIEnv *env,
       
   344                                                         jclass cls,
       
   345                                                         jlong atom)
       
   346 {
       
   347     jstring targetString;
       
   348     char *name;
       
   349 
       
   350     AWT_LOCK();
       
   351 
       
   352     name = XGetAtomName(awt_display, (Atom) atom);
       
   353 
       
   354     if (name == NULL) {
       
   355         JNU_ThrowNullPointerException(env, "Failed to retrieve atom name.");
       
   356         AWT_UNLOCK();
       
   357         return NULL;
       
   358     }
       
   359 
       
   360     targetString = (*env)->NewStringUTF(env, (const char *)name);
       
   361 
       
   362     if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   363         (*env)->ExceptionDescribe(env);
       
   364         (*env)->ExceptionClear(env);
       
   365         XFree (name);
       
   366         AWT_UNLOCK();
       
   367         return NULL;
       
   368     }
       
   369 
       
   370     if (JNU_IsNull(env, targetString)) {
       
   371         JNU_ThrowNullPointerException(env, "Failed to create a string.");
       
   372         XFree (name);
       
   373         AWT_UNLOCK();
       
   374         return NULL;
       
   375     }
       
   376 
       
   377     XFree (name);
       
   378 
       
   379     AWT_UNLOCK();
       
   380     return targetString;
       
   381 }
       
   382 
       
   383 /*
       
   384  * Class:     sun_awt_datatransfer_DataTransferer
       
   385  * Method:    dragQueryFile
       
   386  * Signature: ([B)[Ljava/lang/String;
       
   387  *
       
   388  * This method converts a byte array that came from File most likely from a
       
   389  * drag operation into a String array.
       
   390  */
       
   391 
       
   392 JNIEXPORT jobjectArray JNICALL
       
   393 Java_sun_awt_motif_MDataTransferer_dragQueryFile
       
   394     (JNIEnv *env, jobject this, jbyteArray bytes)
       
   395 {
       
   396     XTextProperty tp;
       
   397     jbyte         *value;
       
   398 
       
   399     char**        strings  = (char **)NULL;
       
   400     int32_t       nstrings = 0;
       
   401     jobject       filenames;
       
   402     jobject       ret = NULL;
       
   403     int32_t       i;
       
   404     jsize         len;
       
   405     jboolean      isCopy=JNI_FALSE;
       
   406 
       
   407     /*
       
   408      * If the length of the byte array is 0 just return a null
       
   409      */
       
   410     len = (*env)->GetArrayLength(env, bytes);
       
   411     if (len == 0) {
       
   412         return NULL;
       
   413     }
       
   414 
       
   415     value = (*env)->GetByteArrayElements(env, bytes, &isCopy);
       
   416     if (JNU_IsNull(env, value)) {
       
   417         return NULL;
       
   418     }
       
   419 
       
   420     AWT_LOCK();
       
   421 
       
   422     tp.encoding = XInternAtom(awt_display, "STRING", False);
       
   423     tp.value    = (unsigned char *)value;
       
   424     tp.nitems   = len;
       
   425     tp.format   = 8;
       
   426 
       
   427     /*
       
   428      * Convert the byte stream into a list of X11 strings
       
   429      */
       
   430     if (XTextPropertyToStringList(&tp, &strings, &nstrings) == 0 ||
       
   431         nstrings == 0)
       
   432         {
       
   433             (*env)->ReleaseByteArrayElements(env, bytes, value, JNI_ABORT);
       
   434             AWT_UNLOCK();
       
   435             return NULL;
       
   436         }
       
   437 
       
   438     (*env)->ReleaseByteArrayElements(env, bytes, value, JNI_ABORT);
       
   439 
       
   440     filenames = (*env)->NewObjectArray(env, nstrings, string, NULL);
       
   441 
       
   442     if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   443         (*env)->ExceptionDescribe(env);
       
   444         (*env)->ExceptionClear(env);
       
   445         goto wayout;
       
   446     }
       
   447 
       
   448     if (JNU_IsNull(env, filenames)) {
       
   449         goto wayout;
       
   450     }
       
   451 
       
   452     /*
       
   453      * Actuall conversion code per X11 String
       
   454      */
       
   455     for (i = 0; i < nstrings; i++) {
       
   456         jstring string = (*env)->NewStringUTF(env,
       
   457                                               (const char *)strings[i]);
       
   458         if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   459             (*env)->ExceptionDescribe(env);
       
   460             (*env)->ExceptionClear(env);
       
   461             goto wayout;
       
   462         }
       
   463 
       
   464         if (JNU_IsNull(env, string)) {
       
   465             goto wayout;
       
   466         }
       
   467 
       
   468         (*env)->SetObjectArrayElement(env, filenames, i, string);
       
   469 
       
   470         if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   471             (*env)->ExceptionDescribe(env);
       
   472             (*env)->ExceptionClear(env);
       
   473             goto wayout;
       
   474         }
       
   475 
       
   476         (*env)->DeleteLocalRef(env, string);
       
   477     }
       
   478 
       
   479     ret = filenames;
       
   480  wayout:
       
   481     /*
       
   482      * Clean up and return
       
   483      */
       
   484     XFreeStringList(strings);
       
   485     AWT_UNLOCK();
       
   486     return ret;
       
   487 }
       
   488 
       
   489 DECLARE_JAVA_CLASS(dataTransfererClazz, "sun/awt/datatransfer/DataTransferer")
       
   490 
       
   491 /**
       
   492  * Returns a local reference to the singleton DataTransferer instance.
       
   493  * The caller should delete the reference when done.
       
   494  */
       
   495 static jobject
       
   496 get_data_transferer(JNIEnv* env) {
       
   497     jobject transferer = NULL;
       
   498 
       
   499     DECLARE_STATIC_OBJECT_JAVA_METHOD(getInstanceMethodID, dataTransfererClazz,
       
   500                                      "getInstance",
       
   501                                      "()Lsun/awt/datatransfer/DataTransferer;");
       
   502 
       
   503     transferer = (*env)->CallStaticObjectMethod(env, clazz, getInstanceMethodID);
       
   504 
       
   505     if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   506         (*env)->ExceptionDescribe(env);
       
   507         (*env)->ExceptionClear(env);
       
   508     }
       
   509 
       
   510     DASSERT(!JNU_IsNull(env, transferer));
       
   511 
       
   512     return transferer;
       
   513 }
       
   514 
       
   515 static jobject
       
   516 call_convertData(JNIEnv* env, jobject source, jobject contents, jlong format,
       
   517                  jobject formatMap) {
       
   518     jobject transferer = get_data_transferer(env);
       
   519     jobject ret = NULL;
       
   520     DECLARE_OBJECT_JAVA_METHOD(convertDataMethodID, dataTransfererClazz,
       
   521                                "convertData",
       
   522                                "(Ljava/lang/Object;Ljava/awt/datatransfer/Transferable;JLjava/util/Map;Z)[B");
       
   523 
       
   524     ret = (*env)->CallObjectMethod(env, transferer, convertDataMethodID,
       
   525                                    source, contents, format, formatMap,
       
   526                                    awt_currentThreadIsPrivileged(env));
       
   527 
       
   528     if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   529         (*env)->ExceptionDescribe(env);
       
   530         (*env)->ExceptionClear(env);
       
   531     }
       
   532 
       
   533     (*env)->DeleteLocalRef(env, transferer);
       
   534 
       
   535     return ret;
       
   536 }
       
   537 
       
   538 static void
       
   539 process_convert_data_requests() {
       
   540     JNIEnv* env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_4);
       
   541     jobject transferer = get_data_transferer(env);
       
   542 
       
   543     DECLARE_VOID_JAVA_METHOD(processDataConversionRequestsMethodID,
       
   544                              dataTransfererClazz,
       
   545                              "processDataConversionRequests",
       
   546                              "()V");
       
   547 
       
   548     (*env)->CallVoidMethod(env, transferer,
       
   549                            processDataConversionRequestsMethodID);
       
   550 
       
   551     if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   552         (*env)->ExceptionDescribe(env);
       
   553         (*env)->ExceptionClear(env);
       
   554     }
       
   555 
       
   556     (*env)->DeleteLocalRef(env, transferer);
       
   557 }
       
   558 
       
   559 Boolean
       
   560 awt_convertData(Widget w, Atom * selection, Atom * target, Atom * type,
       
   561                 XtPointer * value, unsigned long *length, int32_t *format) {
       
   562     JNIEnv*  env  = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
       
   563     Display* dpy = XtDisplay(w);
       
   564     awt_convertDataCallbackStruct* structPtr = NULL;
       
   565 
       
   566     if (XFindContext(dpy, *selection, awt_convertDataContext,
       
   567                      (XPointer*)&structPtr) == XCNOMEM || structPtr == NULL) {
       
   568         return False;
       
   569     }
       
   570 
       
   571     if ((*env)->PushLocalFrame(env, 2) < 0) {
       
   572         (*env)->ExceptionDescribe(env);
       
   573         (*env)->ExceptionClear(env);
       
   574         return False;
       
   575     }
       
   576 
       
   577     if (*target == XA_TARGETS) {
       
   578         jlongArray formats = structPtr->formats;
       
   579         jsize      count;
       
   580         jlong*     targets;
       
   581         jboolean   isCopy;
       
   582 
       
   583 #ifndef _LP64 /* Atom and jlong are different sizes in the 32-bit build */
       
   584         Atom*      aValue;
       
   585         jlong*     saveTargets;
       
   586         jsize      i;
       
   587 #endif
       
   588 
       
   589         if (JNU_IsNull(env, formats)) {
       
   590             (*env)->PopLocalFrame(env, NULL);
       
   591             return False;
       
   592         }
       
   593 
       
   594         count = (*env)->GetArrayLength(env, formats);
       
   595         if (count == 0) {
       
   596             (*env)->PopLocalFrame(env, NULL);
       
   597             return False;
       
   598         }
       
   599 
       
   600         targets = (*env)->GetLongArrayElements(env, formats, &isCopy);
       
   601 
       
   602         *type = XA_ATOM;
       
   603         *format = 32;
       
   604 
       
   605 #ifdef _LP64
       
   606         *value = XtMalloc(count * sizeof(Atom));
       
   607         memcpy((void *)*value, (void *)targets, count * sizeof(Atom));
       
   608 #else
       
   609         *value = aValue = (Atom *)XtMalloc(count * sizeof(Atom));
       
   610         saveTargets = targets;
       
   611         for (i = 0; i < count; i++, aValue++, targets++) {
       
   612             *aValue = (Atom)*targets;
       
   613         }
       
   614         targets = saveTargets;
       
   615 #endif
       
   616         (*env)->ReleaseLongArrayElements(env, formats, targets, JNI_ABORT);
       
   617 
       
   618         *length = count;
       
   619 
       
   620     } else if (*target == XInternAtom(dpy, _XA_DELETE, False)) {
       
   621 
       
   622         /*
       
   623          * acknowledge the DELETE target here ... the "delete" semantic
       
   624          * of move will take place after the drop is complete.
       
   625          */
       
   626 
       
   627         *type   = XInternAtom(dpy, _XA_NULL, False);
       
   628         *length = 0;
       
   629         *value  = (XtPointer)NULL;
       
   630         /* Uninitialized format can cause crash in Xt conversion code. */
       
   631         *format = 8;
       
   632     } else if (*target == XInternAtom(dpy, _XA_HOSTNAME, False)) {
       
   633         struct utsname name;
       
   634         XTextProperty  tp;
       
   635 
       
   636         uname(&name);
       
   637 
       
   638         if (!XStringListToTextProperty((char **)&name.nodename, 1, &tp)) {
       
   639             (*env)->PopLocalFrame(env, NULL);
       
   640             return False;
       
   641         }
       
   642 
       
   643         *value = (XtPointer)XtCalloc(tp.nitems, sizeof(char));
       
   644 
       
   645         memcpy((void *)*value, (const void *)tp.value, tp.nitems);
       
   646 
       
   647         XFree((void *)tp.value);
       
   648 
       
   649         *type   = tp.encoding;
       
   650         *length = tp.nitems + 1;
       
   651         *format = tp.format;
       
   652     } else if (*target == XInternAtom(dpy, _XA_FILENAME, False) ||
       
   653                *target == XInternAtom(dpy, _DT_FILENAME, False)) {
       
   654 
       
   655         /*
       
   656          * Convert the internal representation to an File Name.
       
   657          * The data returned from dataConvert is a an array of
       
   658          * null separated bytes. Each series of bytes is a string
       
   659          * that is then converted to an XString which are then put
       
   660          * into an XStringList and put into an XTextProperty for
       
   661          * usage in other programs.
       
   662          *
       
   663          * It would be desireable to have dataConvert to this conversion
       
   664          * but it isn't possible to return a byte array that represents
       
   665          * the XTextProperty.
       
   666          */
       
   667         jbyteArray    data;
       
   668 
       
   669         /*
       
   670          * Fix for 4513976.
       
   671          * Type None should be used instead of XT_CONVERT_FAIL
       
   672          * to report conversion failure.
       
   673          */
       
   674         /*  assume forthcoming error */
       
   675         *type   = None;
       
   676         *value  = (XtPointer)NULL;
       
   677         *length = 0;
       
   678         *format = 8;
       
   679 
       
   680         data = call_convertData(env, structPtr->source, structPtr->transferable,
       
   681                                 (jlong)*target, structPtr->formatMap);
       
   682 
       
   683         /* error test */
       
   684         if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   685             (*env)->ExceptionDescribe(env);
       
   686             (*env)->ExceptionClear(env);
       
   687             (*env)->PopLocalFrame(env, NULL);
       
   688             return False;
       
   689         }
       
   690         if (JNU_IsNull(env, data)) {
       
   691             (*env)->PopLocalFrame(env, NULL);
       
   692             return False;
       
   693         }
       
   694 
       
   695         if (convertFileType(data, type, value, length, format) == False) {
       
   696             (*env)->PopLocalFrame(env, NULL);
       
   697             return False;
       
   698         }
       
   699     } else {
       
   700         jbyteArray bytes = NULL;
       
   701         jbyte*     copy = NULL;
       
   702 
       
   703         /*
       
   704          * Fix for 4513976.
       
   705          * Type None should be used instead of XT_CONVERT_FAIL
       
   706          * to report conversion failure.
       
   707          */
       
   708         *type   = None; /* assume forthcoming error */
       
   709         *value  = (XtPointer)NULL;
       
   710         *length = 0;
       
   711         *format = 8;
       
   712 
       
   713         bytes = call_convertData(env, structPtr->source, structPtr->transferable,
       
   714                                  (jlong)*target, structPtr->formatMap);
       
   715 
       
   716         if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   717             (*env)->ExceptionDescribe(env);
       
   718             (*env)->ExceptionClear(env);
       
   719             (*env)->PopLocalFrame(env, NULL);
       
   720             return False;
       
   721         }
       
   722 
       
   723         if (bytes == NULL) {
       
   724             (*env)->PopLocalFrame(env, NULL);
       
   725             return False;
       
   726         } else {
       
   727             jsize len = (*env)->GetArrayLength(env, bytes);
       
   728 
       
   729             if (len == 0) {
       
   730                 *type   = *target;
       
   731                 *format = 8;
       
   732                 (*env)->PopLocalFrame(env, NULL);
       
   733                 return True;
       
   734             }
       
   735 
       
   736             copy = (jbyte*)XtCalloc(1, len * sizeof(jbyte));
       
   737             if (copy == (jbyte*)NULL) {
       
   738                 JNU_ThrowOutOfMemoryError(env, "OutOfMemoryError");
       
   739                 (*env)->PopLocalFrame(env, NULL);
       
   740                 return False;
       
   741             }
       
   742 
       
   743             (*env)->GetByteArrayRegion(env, (jbyteArray)bytes, 0, len, copy);
       
   744 
       
   745             if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   746                 (*env)->ExceptionDescribe(env);
       
   747                 (*env)->ExceptionClear(env);
       
   748                 XtFree((void *)copy);
       
   749                 (*env)->PopLocalFrame(env, NULL);
       
   750                 return False;
       
   751             }
       
   752 
       
   753             *value  = (XtPointer)copy;
       
   754             *type   = *target;
       
   755             *length = len;
       
   756             *format = 8;
       
   757         }
       
   758     }
       
   759 
       
   760     (*env)->PopLocalFrame(env, NULL);
       
   761     return True;
       
   762 }
       
   763 
       
   764 
       
   765 jlongArray
       
   766 getSelectionTargetsHelper(JNIEnv* env, XtPointer value, unsigned long length)
       
   767 {
       
   768     Atom* targets = (Atom*)value;
       
   769     jlongArray targetArray = NULL;
       
   770     jlong* checkedTargets = NULL;
       
   771     size_t count = 0, i = 0, j = 0;
       
   772 
       
   773     /* Get rid of zero atoms if there are any. */
       
   774     for (; i < length; i++) {
       
   775         if (targets[i] != 0) {
       
   776             count++;
       
   777         }
       
   778     }
       
   779     checkedTargets = calloc(count, sizeof(jlong));
       
   780     if (checkedTargets == NULL) {
       
   781         JNU_ThrowOutOfMemoryError(env, "");
       
   782         (*env)->ExceptionDescribe(env);
       
   783         (*env)->ExceptionClear(env);
       
   784     } else {
       
   785         for (i = 0; i < length; i++) {
       
   786             if (targets[i] != 0) {
       
   787                 checkedTargets[j++] = targets[i];
       
   788             }
       
   789         }
       
   790 
       
   791         DASSERT(j == count);
       
   792 
       
   793         if ((*env)->EnsureLocalCapacity(env, 1) >= 0) {
       
   794 
       
   795             targetArray = (*env)->NewLongArray(env, count);
       
   796 
       
   797             if (!JNU_IsNull(env, targetArray)) {
       
   798                 (*env)->SetLongArrayRegion(env, targetArray, 0, count,
       
   799                                            checkedTargets);
       
   800 
       
   801                 if ((*env)->ExceptionCheck(env)) {
       
   802                     (*env)->ExceptionDescribe(env);
       
   803                     (*env)->ExceptionClear(env);
       
   804 
       
   805                     (*env)->DeleteLocalRef(env, targetArray);
       
   806                     targetArray = NULL;
       
   807                 }
       
   808             }
       
   809         }
       
   810         free(checkedTargets);
       
   811     }
       
   812 
       
   813     return targetArray;
       
   814 }
       
   815 
       
   816 static void
       
   817 get_selection_targets_callback(Widget w, XtPointer client_data, Atom* selection,
       
   818                                Atom* type, XtPointer value,
       
   819                                unsigned long* length, int32_t* format) {
       
   820     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
       
   821     jobject* pReturnArray = (jobject*)client_data;
       
   822     SelectionStatus status = SelectionFailure;
       
   823 
       
   824     /*
       
   825      * It is highly unlikely that TARGETS will ever be passed even though that
       
   826      * was what was requested. However, XA_ATOM ("ATOM") is likely.
       
   827      * Actually they are the same so treat them as such. See XToolKit
       
   828      * Intrinsic Manual on XtSelectionCallbackProc for more details on type.
       
   829      */
       
   830     if (*type == XA_TARGETS || *type == XA_ATOM) {
       
   831         jlongArray targetArray = getSelectionTargetsHelper(env, value, *length);
       
   832         if (!JNU_IsNull(env, targetArray)) {
       
   833             *pReturnArray = (*env)->NewGlobalRef(env, targetArray);
       
   834             status = SelectionSuccess;
       
   835             (*env)->DeleteLocalRef(env, targetArray);
       
   836         }
       
   837     } else if (*type == XT_CONVERT_FAIL) {
       
   838         status = SelectionOwnerTimedOut;
       
   839     } else {
       
   840         /*
       
   841          * A part of the fix for 4259272.
       
   842          * Actually Xt Intrinsics says about XtSelectionCallback that
       
   843          * "if there is no owner for the specified selection, or that owner
       
   844          * cannot convert the selected data to the requested type, then this
       
   845          * callback is called with value NULL and length zero".
       
   846          * But we report success if type is not TARGETS, XA_ATOM or XT_CONVERT_FAIL,
       
   847          * and we should not change this behaviour. We just return zero-length
       
   848          * array instead of null, because null denotes that we could not get
       
   849          * selection targets at the time of tracking changes of available on
       
   850          * the selection data flavors.
       
   851          */
       
   852         jlongArray targetArray = (*env)->NewLongArray(env, 0);
       
   853         *pReturnArray = (*env)->NewGlobalRef(env, targetArray);
       
   854         /*
       
   855          * Fix for 4655996.
       
   856          * Report success if there is no owner for this selection or the owner
       
   857          * fails to provide target types.
       
   858          */
       
   859         status = SelectionSuccess;
       
   860         (*env)->DeleteLocalRef(env, targetArray);
       
   861     }
       
   862 
       
   863     if (value != NULL) {
       
   864         XtFree(value);
       
   865         value = NULL;
       
   866     }
       
   867 
       
   868     set_selection_status(status);
       
   869 }
       
   870 
       
   871 static void
       
   872 get_selection_data_callback(Widget w, XtPointer client_data, Atom * selection,
       
   873                             Atom * type, XtPointer value, unsigned long *length,
       
   874                             int32_t *format) {
       
   875     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
       
   876     jobject* pData = (jobject*)client_data;
       
   877     SelectionStatus status = SelectionFailure;
       
   878 
       
   879     if (*type == XT_CONVERT_FAIL) {
       
   880         status = SelectionOwnerTimedOut;
       
   881     } else if (*type != None) {
       
   882         if ((*env)->EnsureLocalCapacity(env, 1) >= 0) {
       
   883             jsize size = (*length <= INT_MAX) ? *length : INT_MAX;
       
   884             jbyteArray array = (*env)->NewByteArray(env, size);
       
   885 
       
   886             if (!JNU_IsNull(env, array)) {
       
   887                 (*env)->SetByteArrayRegion(env, array, 0, size, (jbyte*)value);
       
   888                 if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
       
   889                     (*env)->ExceptionDescribe(env);
       
   890                     (*env)->ExceptionClear(env);
       
   891                 } else {
       
   892                     *pData = (*env)->NewGlobalRef(env, array);
       
   893                     status = SelectionSuccess;
       
   894                 }
       
   895 
       
   896                 (*env)->DeleteLocalRef(env, array);
       
   897             }
       
   898         }
       
   899     }
       
   900 
       
   901     if (value != NULL) {
       
   902         XtFree(value);
       
   903         value = NULL;
       
   904     }
       
   905 
       
   906     set_selection_status(status);
       
   907 }
       
   908 
       
   909 static int32_t
       
   910 wait_for_selection_event(void *data) {
       
   911     process_convert_data_requests();
       
   912     return get_selection_status() != SelectionPending;
       
   913 }
       
   914 
       
   915 jlongArray
       
   916 get_selection_targets(JNIEnv *env, Atom selection, Time time_stamp) {
       
   917     jlongArray ret     = NULL;
       
   918     jlongArray targets = NULL;
       
   919     SelectionStatus status = SelectionPending;
       
   920 
       
   921     AWT_LOCK();
       
   922 
       
   923     XtAppSetSelectionTimeout(awt_appContext,
       
   924             JNU_CallStaticMethodByName(env, NULL, "sun/awt/UNIXToolkit",
       
   925                                        "getDatatransferTimeout", "()I").i);
       
   926 
       
   927     set_selection_status(SelectionPending);
       
   928     XtGetSelectionValue(awt_root_shell, selection, XA_TARGETS,
       
   929                         get_selection_targets_callback, (XtPointer)&targets,
       
   930                         time_stamp);
       
   931 
       
   932     awt_MToolkit_modalWait(wait_for_selection_event, NULL);
       
   933     status = get_selection_status();
       
   934 
       
   935     AWT_FLUSH_UNLOCK();
       
   936 
       
   937     if (!JNU_IsNull(env, targets)) {
       
   938         ret = (*env)->NewLocalRef(env, targets);
       
   939         (*env)->DeleteGlobalRef(env, targets);
       
   940     }
       
   941 
       
   942     switch (status) {
       
   943     case SelectionSuccess:
       
   944         break;
       
   945     case SelectionFailure:
       
   946         JNU_ThrowByName(env, "java/lang/IllegalStateException",
       
   947                         "Failed to get selection targets");
       
   948         break;
       
   949     case SelectionOwnerTimedOut:
       
   950         // return an empty array of targets if the selection owner timed out
       
   951         ret = (*env)->NewLongArray(env, 0);
       
   952         break;
       
   953     default:
       
   954         JNU_ThrowByName(env, "java/lang/IllegalStateException",
       
   955                         "Unexpected selection status");
       
   956         break;
       
   957     }
       
   958 
       
   959     return ret;
       
   960 }
       
   961 
       
   962 jbyteArray
       
   963 get_selection_data(JNIEnv *env, Atom selection, Atom target, Time time_stamp) {
       
   964     jbyteArray ret    = NULL;
       
   965     jbyteArray data   = NULL;
       
   966     SelectionStatus status = SelectionPending;
       
   967 
       
   968     AWT_LOCK();
       
   969 
       
   970     XtAppSetSelectionTimeout(awt_appContext,
       
   971             JNU_CallStaticMethodByName(env, NULL, "sun/awt/UNIXToolkit",
       
   972                                        "getDatatransferTimeout", "()I").i);
       
   973 
       
   974     set_selection_status(SelectionPending);
       
   975     XtGetSelectionValue(awt_root_shell, selection, target,
       
   976                         get_selection_data_callback,
       
   977                         (XtPointer)&data, time_stamp);
       
   978 
       
   979     awt_MToolkit_modalWait(wait_for_selection_event, NULL);
       
   980     status = get_selection_status();
       
   981 
       
   982     AWT_FLUSH_UNLOCK();
       
   983 
       
   984     if (!JNU_IsNull(env, data)) {
       
   985         ret = (*env)->NewLocalRef(env, data);
       
   986         (*env)->DeleteGlobalRef(env, data);
       
   987     }
       
   988 
       
   989     switch (status) {
       
   990     case SelectionSuccess:
       
   991         break;
       
   992     case SelectionFailure:
       
   993         JNU_ThrowIOException(env, "Failed to get selection data");
       
   994         break;
       
   995     case SelectionOwnerTimedOut:
       
   996         JNU_ThrowIOException(env, "Selection owner timed out");
       
   997         break;
       
   998     default:
       
   999         JNU_ThrowIOException(env, "Unexpected selection status");
       
  1000         break;
       
  1001     }
       
  1002 
       
  1003     return ret;
       
  1004 }
       
  1005 
       
  1006 void
       
  1007 awt_cleanupConvertDataContext(JNIEnv *env, Atom selectionAtom) {
       
  1008     awt_convertDataCallbackStruct* structPtr = NULL;
       
  1009 
       
  1010     if (XFindContext(awt_display, selectionAtom, awt_convertDataContext,
       
  1011                      (XPointer*)&structPtr) == 0 && structPtr != NULL) {
       
  1012 
       
  1013         (*env)->DeleteGlobalRef(env, structPtr->source);
       
  1014         (*env)->DeleteGlobalRef(env, structPtr->transferable);
       
  1015         (*env)->DeleteGlobalRef(env, structPtr->formatMap);
       
  1016         (*env)->DeleteGlobalRef(env, structPtr->formats);
       
  1017         free(structPtr);
       
  1018     }
       
  1019     /*
       
  1020      * Xlib Programming Manual says that it is better to erase
       
  1021      * the current entry with XDeleteContext() before XSaveContext().
       
  1022      */
       
  1023     XDeleteContext(awt_display, selectionAtom, awt_convertDataContext);
       
  1024     if (XSaveContext(awt_display, selectionAtom, awt_convertDataContext,
       
  1025                      (XPointer)NULL) == XCNOMEM) {
       
  1026         JNU_ThrowInternalError(env, "XError");
       
  1027         (*env)->ExceptionDescribe(env);
       
  1028         (*env)->ExceptionClear(env);
       
  1029     }
       
  1030 }
       
  1031 
       
  1032 static Bool exitSecondaryLoop = True;
       
  1033 
       
  1034 /*
       
  1035  * This predicate procedure allows the Toolkit thread to process specific events
       
  1036  * while it is blocked waiting for the event dispatch thread to process
       
  1037  * a SunDropTargetEvent. We need this to prevent deadlock when the client code
       
  1038  * processing SunDropTargetEvent sets or gets the contents of the system
       
  1039  * clipboard/selection. In this case the event dispatch thread waits for the
       
  1040  * Toolkit thread to process PropertyNotify or SelectionNotify events.
       
  1041  */
       
  1042 static Bool
       
  1043 secondary_loop_event(Display* dpy, XEvent* event, char* arg) {
       
  1044     return (event->type == SelectionNotify ||
       
  1045             event->type == SelectionClear  ||
       
  1046             event->type == PropertyNotify) ? True : False;
       
  1047 }
       
  1048 
       
  1049 
       
  1050 JNIEXPORT void JNICALL
       
  1051 Java_sun_awt_motif_MToolkitThreadBlockedHandler_enter(JNIEnv *env, jobject this) {
       
  1052     DASSERT(exitSecondaryLoop && awt_currentThreadIsPrivileged(env));
       
  1053     exitSecondaryLoop = False;
       
  1054     while (!exitSecondaryLoop) {
       
  1055         XEvent event;
       
  1056         while (XCheckIfEvent(awt_display, &event, secondary_loop_event, NULL)) {
       
  1057             XtDispatchEvent(&event);
       
  1058         }
       
  1059         AWT_WAIT(AWT_DND_POLL_INTERVAL);
       
  1060     }
       
  1061 }
       
  1062 
       
  1063 JNIEXPORT void JNICALL
       
  1064 Java_sun_awt_motif_MToolkitThreadBlockedHandler_exit(JNIEnv *env, jobject this) {
       
  1065     DASSERT(!exitSecondaryLoop && !awt_currentThreadIsPrivileged(env));
       
  1066     exitSecondaryLoop = True;
       
  1067     AWT_NOTIFY_ALL();
       
  1068 }