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
46static void *awtHandle = NULL;
47
48typedef jint JNICALL JNI_OnLoad_type(JavaVM *vm, void *reserved);
49
50/* Initialize the Java VM instance variable when the library is
51   first loaded */
52JavaVM *jvm;
53
54JNIEXPORT 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
101jint
102AWT_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
180JNIEXPORT jint JNICALL
181DEF_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 */
191JNIEXPORT void JNICALL
192Java_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 */
221JNIEXPORT void JNICALL
222Java_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}
241