1 /* 2 * Copyright (c) 2016, 2018, 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 <stdlib.h> 28 #include <linux/fb.h> 29 #include <fcntl.h> 30 #ifndef __USE_GNU // required for dladdr() & Dl_info 31 #define __USE_GNU 32 #endif 33 #include <dlfcn.h> 34 #include <sys/ioctl.h> 35 36 #include <string.h> 37 #include <strings.h> 38 #include <stdlib.h> 39 40 #include <X11/Xlib.h> 41 42 #include <assert.h> 43 44 #include <jni.h> 45 46 #include <com_sun_glass_ui_gtk_GtkApplication.h> 47 48 static jboolean gtk_versionDebug = JNI_FALSE; 49 50 static const char * gtk2_chain[] = { 51 "libglassgtk2.so", "libglassgtk3.so", 0 52 }; 53 54 static const char * gtk3_chain[] = { 55 "libglassgtk3.so", "libglassgtk2.so", 0 56 }; 57 58 static JavaVM* javaVM; 59 60 JNIEXPORT jint JNICALL 61 JNI_OnLoad(JavaVM *jvm, void *reserved) 62 { 63 (void) reserved; 64 65 javaVM = jvm; 66 67 return JNI_VERSION_1_6; 68 } 69 70 // our library combinations defined 71 // "version" "libgtk", "libdgdk", "libpixbuf" 72 // note that currently only the first char of the version is used 73 static char * gtk2_versioned[] = { 74 "2", "libgtk-x11-2.0.so.0" 75 }; 76 77 static char * gtk2_not_versioned[] = { 78 "2", "libgtk-x11-2.0.so" 79 }; 80 81 static char * gtk3_versioned[] = { 82 "3", "libgtk-3.so.0" 83 }; 84 85 static char * gtk3_not_versioned[] = { 86 "3", "libgtk-3.so" 87 }; 88 89 // our library set orders defined, null terminated 90 static char ** two_to_three[] = { 91 gtk2_versioned, gtk2_not_versioned, 92 gtk3_versioned, gtk3_not_versioned, 93 0 94 }; 95 96 static char ** three_to_two[] = { 97 gtk3_versioned, gtk3_not_versioned, 98 gtk2_versioned, gtk2_not_versioned, 99 0 100 }; 101 102 static int try_opening_libraries(char *names[3]) 103 { 104 void * gtk; 105 106 gtk = dlopen (names[1], RTLD_LAZY | RTLD_GLOBAL); 107 if (!gtk) { 108 return 0; 109 } 110 111 return 1; 112 } 113 114 static int try_libraries_noload(char *names[3]) 115 { 116 #ifdef RTLD_NOLOAD 117 void *gtk; 118 gtk = dlopen(names[1], RTLD_LAZY | RTLD_NOLOAD); 119 return gtk ? 1 : 0; 120 #else 121 return 0; 122 #endif 123 } 124 125 static int sniffLibs(int wantVersion) { 126 127 if (gtk_versionDebug) { 128 printf("checking GTK version %d\n",wantVersion); 129 } 130 131 int success = 1; 132 char *** use_chain = three_to_two; 133 int i, found = 0; 134 135 //at first try to detect already loaded GTK version 136 for (i = 0; use_chain[i] && !found; i++) { 137 found = try_libraries_noload(use_chain[i]); 138 if (found && gtk_versionDebug) { 139 printf("found already loaded GTK library %s\n", use_chain[i][1]); 140 } 141 } 142 143 if (!found) { 144 if (wantVersion == 0 || wantVersion == 3) { 145 use_chain = three_to_two; 146 } else if (wantVersion == 2) { 147 use_chain = two_to_three; 148 } else { 149 // Note, this should never happen, java should be protecting us 150 if (gtk_versionDebug) { 151 printf("bad GTK version specified, assuming 3\n"); 152 } 153 wantVersion = 3; 154 use_chain = three_to_two; 155 } 156 157 for (i = 0; use_chain[i] && !found; i++) { 158 if (gtk_versionDebug) { 159 printf("trying GTK library %s\n", use_chain[i][1]); 160 } 161 found = try_opening_libraries(use_chain[i]); 162 } 163 } 164 165 if (found) { 166 if (gtk_versionDebug) { 167 i--; 168 printf("using GTK library version %s set %s\n", 169 use_chain[i][0], 170 use_chain[i][1]); 171 fflush(stdout); 172 } 173 return use_chain[i][0][0]; 174 } 175 if (gtk_versionDebug) { 176 fflush(stdout); 177 } 178 return -1; 179 } 180 181 /* 182 * Class: com_sun_glass_ui_gtk_GtkApplication 183 * Method: _queryLibrary 184 * Signature: Signature: (IZ)I 185 */ 186 JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkApplication__1queryLibrary 187 (JNIEnv *env, jclass clazz, jint suggestedVersion, jboolean verbose) 188 { 189 (void) env; 190 (void) clazz; 191 192 gtk_versionDebug = verbose; 193 194 // Before doing anything with GTK we validate that the DISPLAY can be opened 195 Display *display = XOpenDisplay(NULL); 196 if (display == NULL) { 197 return com_sun_glass_ui_gtk_GtkApplication_QUERY_NO_DISPLAY; 198 } 199 XCloseDisplay(display); 200 201 // now check the the presence of the libraries 202 203 char version = sniffLibs(suggestedVersion); 204 205 if (version == '2') { 206 return com_sun_glass_ui_gtk_GtkApplication_QUERY_LOAD_GTK2; 207 } else if (version == '3') { 208 return com_sun_glass_ui_gtk_GtkApplication_QUERY_LOAD_GTK3; 209 } 210 211 return com_sun_glass_ui_gtk_GtkApplication_QUERY_ERROR; 212 } 213