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 <assert.h>
  41 
  42 #include <gtk/gtk.h>
  43 
  44 #include "glass_wrapper.h"
  45 
  46 int wrapper_debug = 0; // enable for development only
  47 int wrapper_loaded = 0;
  48 int wrapper_gtk_version = 0;
  49 int wrapper_gtk_versionDebug = 0;
  50 
  51 // our library combinations defined
  52 // "version" "libgtk", "libdgdk", "libpixbuf"
  53 // note that currently only the first char of the version is used
  54 static char * gtk2_versioned[] = {
  55    "2", "libgtk-x11-2.0.so.0", "libgdk-x11-2.0.so.0", "libgdk_pixbuf-2.0.so"
  56 };
  57 
  58 static char * gtk2_not_versioned[] = {
  59    "2", "libgtk-x11-2.0.so", "libgdk-x11-2.0.so", "libgdk_pixbuf-2.0.so"
  60 };
  61 
  62 static char * gtk3_versioned[] = {
  63    "3", "libgtk-3.so.0", "libgdk-3.so.0", "libgdk_pixbuf-2.0.so.0"
  64 };
  65 
  66 static char * gtk3_not_versioned[] = {
  67    "3", "libgtk-3.so", "libgdk-3.so", "libgdk_pixbuf-2.0.so"
  68 };
  69 
  70 // our library set orders defined, null terminated
  71 static char ** two_to_three[] = {
  72     gtk2_versioned, gtk2_not_versioned,
  73     gtk3_versioned, gtk3_not_versioned,
  74     0
  75 };
  76 
  77 static char ** three_to_two[] = {
  78     gtk3_versioned, gtk3_not_versioned,
  79     gtk2_versioned, gtk2_not_versioned,
  80     0
  81 };
  82 
  83 static int try_opening_libraries(char *names[3], void** gtk, void** gdk, void ** pix)
  84 {
  85     *gtk = dlopen (names[1], RTLD_LAZY | RTLD_GLOBAL);
  86     if (!*gtk) {
  87         if (wrapper_gtk_versionDebug) {
  88             fprintf(stderr, "failed to load %s\n", names[1]);
  89         }
  90         return 0;
  91     }
  92 
  93     *gdk = dlopen (names[2], RTLD_LAZY | RTLD_GLOBAL);
  94     if (!*gdk) {
  95         if (wrapper_gtk_versionDebug) {
  96             fprintf(stderr, "failed to load %s\n", names[2]);
  97         }
  98         dlclose(*gtk);
  99         *gtk = 0;
 100         return 0;
 101     }
 102 
 103     *pix = dlopen (names[3], RTLD_LAZY | RTLD_GLOBAL);
 104     if (!*pix) {
 105         if (wrapper_gtk_versionDebug) {
 106             fprintf(stderr, "failed to load %s\n", names[3]);
 107         }
 108         dlclose(*gtk);
 109         dlclose(*gdk);
 110         *gtk = *gdk = 0;
 111         return 0;
 112     }
 113 
 114     return 1;
 115 }
 116 
 117 int wrapper_load_symbols(int version, int verbose) {
 118     if (wrapper_loaded) {
 119         return wrapper_gtk_version;
 120     }
 121 
 122     wrapper_gtk_versionDebug = verbose;
 123 
 124     void *libgtk = 0, *libgdk = 0, *libpix = 0;
 125 
 126     int success = 1;
 127     char *** use_chain;
 128 
 129     if (version == 3) {
 130         use_chain = three_to_two;
 131         wrapper_gtk_version = 3;
 132     } else if (version == 0 || version == 2) {
 133         use_chain = two_to_three;
 134         wrapper_gtk_version = 2;
 135     } else {
 136         // should never happen, java should pass validated values
 137         fprintf(stderr, "Unrecognized GTK version requested, falling back to v 2.0\n");
 138         fflush(stderr);
 139         use_chain = two_to_three;
 140         wrapper_gtk_version = 2;
 141     }
 142 
 143     if (wrapper_gtk_versionDebug) {
 144         fprintf(stderr, "Loading GTK libraries version %d\n", version);
 145     }
 146 
 147     int i, found = 0;
 148     for(i = 0; use_chain[i] && !found; i++) {
 149         if (wrapper_gtk_versionDebug) {
 150             printf("trying GTK library set %s, %s, %s\n",
 151                  use_chain[i][1],
 152                  use_chain[i][2],
 153                  use_chain[i][3]);
 154         }
 155         found = try_opening_libraries(use_chain[i], &libgtk, &libgdk, &libpix);
 156 
 157         if (found) {
 158             if (use_chain[i][0][0] == '2') {
 159                 wrapper_gtk_version = 2;
 160             } else { // (use_chain[i][1][0] == '3') {
 161                 wrapper_gtk_version = 3;
 162             }
 163 
 164             if (wrapper_load_symbols_gtk(wrapper_gtk_version, libgtk) != 0) {
 165                 found = 0;
 166             } else if (wrapper_load_symbols_gdk(wrapper_gtk_version, libgdk) != 0) {
 167                 found = 0;
 168             } else if (wrapper_load_symbols_pix(wrapper_gtk_version, libpix) != 0) {
 169                 found = 0;
 170             }
 171         }
 172 
 173         if (!found) {
 174             if (libgtk) dlclose(libgtk);
 175             if (libgdk) dlclose(libgdk);
 176             if (libpix) dlclose(libpix);
 177         }
 178     }
 179 
 180     if (found) {
 181         if (wrapper_gtk_versionDebug) {
 182             i--;
 183             printf("using GTK library set %s, %s, %s\n",
 184                  use_chain[i][1],
 185                  use_chain[i][2],
 186                  use_chain[i][3]);
 187         }
 188     } else {
 189         return -1;
 190     }
 191 
 192     void *libgio = dlopen ("libgio-2.0.so", RTLD_LAZY | RTLD_GLOBAL);
 193     wrapper_load_symbols_gio(libgio);
 194 
 195     wrapper_loaded = 1;
 196 
 197     return wrapper_gtk_version;
 198 }