1 /*
   2  * Copyright (c) 2000, 2015, 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 #include <stdio.h>
  27 #include <dlfcn.h>
  28 #include <string.h>
  29 #include <stdlib.h>
  30 #include <jni.h>
  31 #include <jni_util.h>
  32 #include <jvm.h>
  33 #include "gdefs.h"
  34 
  35 #include <sys/param.h>
  36 #include <sys/utsname.h>
  37 
  38 #ifdef AIX
  39 #include "porting_aix.h" /* For the 'dladdr' function. */
  40 #endif
  41 
  42 #ifdef DEBUG
  43 #define VERBOSE_AWT_DEBUG
  44 #endif
  45 
  46 static void *awtHandle = NULL;
  47 
  48 typedef jint JNICALL JNI_OnLoad_type(JavaVM *vm, void *reserved);
  49 
  50 /* Initialize the Java VM instance variable when the library is
  51    first loaded */
  52 JavaVM *jvm;
  53 
  54 JNIEXPORT jboolean JNICALL AWTIsHeadless() {
  55     static JNIEnv *env = NULL;
  56     static jboolean isHeadless;
  57     jmethodID headlessFn;
  58     jclass graphicsEnvClass;
  59 
  60     if (env == NULL) {
  61         env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
  62         graphicsEnvClass = (*env)->FindClass(env,
  63                                              "java/awt/GraphicsEnvironment");
  64         if (graphicsEnvClass == NULL) {
  65             return JNI_TRUE;
  66         }
  67         headlessFn = (*env)->GetStaticMethodID(env,
  68                                                graphicsEnvClass, "isHeadless", "()Z");
  69         if (headlessFn == NULL) {
  70             return JNI_TRUE;
  71         }
  72         isHeadless = (*env)->CallStaticBooleanMethod(env, graphicsEnvClass,
  73                                                      headlessFn);
  74         if ((*env)->ExceptionCheck(env)) {
  75             (*env)->ExceptionClear(env);
  76             return JNI_TRUE;
  77         }
  78     }
  79     return isHeadless;
  80 }
  81 
  82 #define CHECK_EXCEPTION_FATAL(env, message) \
  83     if ((*env)->ExceptionCheck(env)) { \
  84         (*env)->ExceptionClear(env); \
  85         (*env)->FatalError(env, message); \
  86     }
  87 
  88 /*
  89  * Pathnames to the various awt toolkits
  90  */
  91 
  92 #ifdef MACOSX
  93   #define LWAWT_PATH "/libawt_lwawt.dylib"
  94   #define DEFAULT_PATH LWAWT_PATH
  95 #else
  96   #define XAWT_PATH "/libawt_xawt.so"
  97   #define DEFAULT_PATH XAWT_PATH
  98   #define HEADLESS_PATH "/libawt_headless.so"
  99 #endif
 100 
 101 jint
 102 AWT_OnLoad(JavaVM *vm, void *reserved)
 103 {
 104     Dl_info dlinfo;
 105     char buf[MAXPATHLEN];
 106     int32_t len;
 107     char *p, *tk;
 108     JNI_OnLoad_type *JNI_OnLoad_ptr;
 109     struct utsname name;
 110     JNIEnv *env = (JNIEnv *)JNU_GetEnv(vm, JNI_VERSION_1_2);
 111     void *v;
 112     jstring fmanager = NULL;
 113     jstring fmProp = NULL;
 114 
 115     if (awtHandle != NULL) {
 116         /* Avoid several loading attempts */
 117         return JNI_VERSION_1_2;
 118     }
 119 
 120     jvm = vm;
 121 
 122     /* Get address of this library and the directory containing it. */
 123     dladdr((void *)AWT_OnLoad, &dlinfo);
 124     realpath((char *)dlinfo.dli_fname, buf);
 125     len = strlen(buf);
 126     p = strrchr(buf, '/');
 127 
 128     /*
 129      * The code below is responsible for:
 130      * 1. Loading appropriate awt library, i.e. libawt_xawt or libawt_headless
 131      * 2. Set the "sun.font.fontmanager" system property.
 132      */
 133 
 134     fmProp = (*env)->NewStringUTF(env, "sun.font.fontmanager");
 135     CHECK_EXCEPTION_FATAL(env, "Could not allocate font manager property");
 136 
 137 #ifdef MACOSX
 138         fmanager = (*env)->NewStringUTF(env, "sun.font.CFontManager");
 139         tk = LWAWT_PATH;
 140 #else
 141         fmanager = (*env)->NewStringUTF(env, "sun.awt.X11FontManager");
 142         tk = XAWT_PATH;
 143 #endif
 144     CHECK_EXCEPTION_FATAL(env, "Could not allocate font manager name");
 145 
 146     if (fmanager && fmProp) {
 147         JNU_CallStaticMethodByName(env, NULL, "java/lang/System", "setProperty",
 148                                    "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
 149                                    fmProp, fmanager);
 150         CHECK_EXCEPTION_FATAL(env, "Could not allocate set properties");
 151     }
 152 
 153 #ifndef MACOSX
 154     if (AWTIsHeadless()) {
 155         tk = HEADLESS_PATH;
 156     }
 157 #endif
 158 
 159     /* Calculate library name to load */
 160     strncpy(p, tk, MAXPATHLEN-len-1);
 161 
 162     if (fmProp) {
 163         (*env)->DeleteLocalRef(env, fmProp);
 164     }
 165     if (fmanager) {
 166         (*env)->DeleteLocalRef(env, fmanager);
 167     }
 168 
 169     jstring jbuf = JNU_NewStringPlatform(env, buf);
 170     CHECK_EXCEPTION_FATAL(env, "Could not allocate library name");
 171     JNU_CallStaticMethodByName(env, NULL, "java/lang/System", "load",
 172                                "(Ljava/lang/String;)V",
 173                                jbuf);
 174 
 175     awtHandle = dlopen(buf, RTLD_LAZY | RTLD_GLOBAL);
 176 
 177     return JNI_VERSION_1_2;
 178 }
 179 
 180 JNIEXPORT jint JNICALL
 181 DEF_JNI_OnLoad(JavaVM *vm, void *reserved)
 182 {
 183     return AWT_OnLoad(vm, reserved);
 184 }
 185 
 186 /*
 187  * This entry point must remain in libawt.so as part of a contract
 188  * with the CDE variant of Java Media Framework. (sdtjmplay)
 189  * Reflect this call over to the correct libawt_<toolkit>.so.
 190  */
 191 JNIEXPORT void JNICALL
 192 Java_sun_awt_motif_XsessionWMcommand(JNIEnv *env, jobject this,
 193                                      jobject frame, jstring jcommand)
 194 {
 195     /* type of the old backdoor function */
 196     typedef void JNICALL
 197         XsessionWMcommand_type(JNIEnv *env, jobject this,
 198                                jobject frame, jstring jcommand);
 199 
 200     static XsessionWMcommand_type *XsessionWMcommand = NULL;
 201 
 202     if (XsessionWMcommand == NULL && awtHandle == NULL) {
 203         return;
 204     }
 205 
 206     XsessionWMcommand = (XsessionWMcommand_type *)
 207         dlsym(awtHandle, "Java_sun_awt_motif_XsessionWMcommand");
 208 
 209     if (XsessionWMcommand == NULL)
 210         return;
 211 
 212     (*XsessionWMcommand)(env, this, frame, jcommand);
 213 }
 214 
 215 
 216 /*
 217  * This entry point must remain in libawt.so as part of a contract
 218  * with the CDE variant of Java Media Framework. (sdtjmplay)
 219  * Reflect this call over to the correct libawt_<toolkit>.so.
 220  */
 221 JNIEXPORT void JNICALL
 222 Java_sun_awt_motif_XsessionWMcommand_New(JNIEnv *env, jobjectArray jargv)
 223 {
 224     typedef void JNICALL
 225         XsessionWMcommand_New_type(JNIEnv *env, jobjectArray jargv);
 226 
 227     static XsessionWMcommand_New_type *XsessionWMcommand = NULL;
 228 
 229     if (XsessionWMcommand == NULL && awtHandle == NULL) {
 230         return;
 231     }
 232 
 233     XsessionWMcommand = (XsessionWMcommand_New_type *)
 234         dlsym(awtHandle, "Java_sun_awt_motif_XsessionWMcommand_New");
 235 
 236     if (XsessionWMcommand == NULL)
 237         return;
 238 
 239     (*XsessionWMcommand)(env, jargv);
 240 }