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