1 /* 2 * Copyright (c) 2016, 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 #define LOAD_SYMBOL(s, x) \ 49 if (s == NULL) { \ 50 s = dlsym(libraryHandle, #x); \ 51 if (s == NULL) { \ 52 fprintf(stderr,"failed loading %s\n", #x); \ 53 exit(-1); \ 54 } else { \ 55 fprintf(stderr,"loading %s\n", #x); \ 56 } \ 57 } else { \ 58 fprintf(stderr,"have %s\n", #x); \ 59 } 60 61 static const char * gtk2_chain[] = { 62 "libglassgtk2.so", "libglassgtk3.so", 0 63 }; 64 65 static const char * gtk3_chain[] = { 66 "libglassgtk3.so", "libglassgtk2.so", 0 67 }; 68 69 static JavaVM* javaVM; 70 71 JNIEXPORT jint JNICALL 72 JNI_OnLoad(JavaVM *jvm, void *reserved) 73 { 74 (void) reserved; 75 76 javaVM = jvm; 77 // better way to get/save this? 78 return JNI_VERSION_1_6; 79 } 80 81 // our library combinations defined 82 // "version" "libgtk", "libdgdk", "libpixbuf" 83 // note that currently only the first char of the version is used 84 static char * gtk2_versioned[] = { 85 "2", "libgtk-x11-2.0.so.0", "libgdk-x11-2.0.so.0", "libgdk_pixbuf-2.0.so" 86 }; 87 88 static char * gtk2_not_versioned[] = { 89 "2", "libgtk-x11-2.0.so", "libgdk-x11-2.0.so", "libgdk_pixbuf-2.0.so" 90 }; 91 92 static char * gtk3_versioned[] = { 93 "3", "libgtk-3.so.0", "libgdk-3.so.0", "libgdk_pixbuf-2.0.so.0" 94 }; 95 96 static char * gtk3_not_versioned[] = { 97 "3", "libgtk-3.so", "libgdk-3.so", "libgdk_pixbuf-2.0.so" 98 }; 99 100 // our library set orders defined, null terminated 101 static char ** two_to_three[] = { 102 gtk2_versioned, gtk2_not_versioned, 103 gtk3_versioned, gtk3_not_versioned, 104 0 105 }; 106 107 static char ** three_to_two[] = { 108 gtk3_versioned, gtk3_not_versioned, 109 gtk2_versioned, gtk2_not_versioned, 110 0 111 }; 112 113 static int try_opening_libraries(char *names[3]) 114 { 115 void * gtk; 116 void * gdk; 117 void * pix; 118 119 gtk = dlopen (names[1], RTLD_LAZY | RTLD_GLOBAL); 120 if (!gtk) { 121 return 0; 122 } 123 124 gdk = dlopen (names[2], RTLD_LAZY | RTLD_GLOBAL); 125 if (!gdk) { 126 dlclose(gtk); 127 return 0; 128 } 129 130 pix = dlopen (names[3], RTLD_LAZY | RTLD_GLOBAL); 131 if (!pix) { 132 dlclose(gtk); 133 dlclose(gdk); 134 gtk = gdk = 0; 135 return 0; 136 } 137 138 dlclose(gtk); 139 dlclose(gdk); 140 dlclose(pix); 141 142 return 1; 143 } 144 145 static int sniffLibs(int wantVersion) { 146 147 printf("trying for version %d\n",wantVersion); 148 149 int success = 1; 150 char *** use_chain; 151 int wrapper_gtk_version; 152 int wrapper_gtk_versionDebug = 1; 153 154 if (wantVersion == 0 || wantVersion == 2) { 155 use_chain = two_to_three; 156 wrapper_gtk_version = 2; 157 } else if (wantVersion == 3) { 158 use_chain = three_to_two; 159 wrapper_gtk_version = 3; 160 } else { 161 printf(" Huh ? what version is %d\n", wantVersion); 162 exit (-3); 163 } 164 165 int i, found = 0; 166 for(i = 0; use_chain[i] && !found; i++) { 167 if (wrapper_gtk_versionDebug) { 168 printf("trying GTK library set %s, %s, %s\n", use_chain[i][1], use_chain[i][2], use_chain[i][3]); 169 } 170 found = try_opening_libraries(use_chain[i]); 171 172 if (found) { 173 if (use_chain[i][0][0] == '2') { 174 wrapper_gtk_version = 2; 175 } else { 176 wrapper_gtk_version = 3; 177 } 178 } 179 } 180 181 if (found) { 182 if (wrapper_gtk_versionDebug) { 183 i--; 184 printf("using GTK library version %s set %s, %s, %s\n", 185 use_chain[i][0], 186 use_chain[i][1], 187 use_chain[i][2], 188 use_chain[i][3]); 189 } 190 return use_chain[i][0][0]; 191 } 192 193 return -1; 194 } 195 /* 196 * Class: com_sun_glass_ui_gtk_GtkApplication 197 * Method: _queryLibrary 198 * Signature: Signature: (IZ)I 199 */ 200 JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkApplication__1queryLibrary 201 (JNIEnv *env, jclass clazz, jint suggestedVersion, jboolean verbose) 202 { 203 (void) env; 204 (void) clazz; 205 (void) verbose; 206 207 // Before doing anything with GTK we validate that the DISPLAY can be opened 208 Display *display = XOpenDisplay(NULL); 209 if (display == NULL) { 210 return com_sun_glass_ui_gtk_GtkApplication_QUERY_NO_DISPLAY; 211 } 212 XCloseDisplay(display); 213 214 // now check the the presence of the libraries 215 216 char version = sniffLibs(suggestedVersion); 217 218 if (version == '2') { 219 return com_sun_glass_ui_gtk_GtkApplication_QUERY_LOAD_GTK2; 220 } else if (version == '3') { 221 return com_sun_glass_ui_gtk_GtkApplication_QUERY_LOAD_GTK3; 222 } 223 224 return com_sun_glass_ui_gtk_GtkApplication_QUERY_ERROR; 225 } 226