summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2019-09-15 15:57:29 +0200
committerManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>2019-09-15 15:57:29 +0200
commitc549b7acbd65674019b731c6648a9e8eb22f70dd (patch)
tree7e6b8745573d2b8c1f9a61a7393b1e7c2b0d8f69 /src
parent000807cc1d1a1c2f00274763f3e8e24145f1af00 (diff)
X11 platform: use Gnome printer dialog when the GTK library is available at run-time
The code to determine whether the GTK library is available is now in Fl_X11_System_Driver::probe_for_GTK() called both by Fl_Printer::begin_job() and Fl_Native_File_Chooser. New Fl::option OPTION_PRINTER_USES_GTK allows to deactivate use of the Gnome print dialog. Minor change in Fl_Native_File_Chooser: GTK version 3 is searched before version 2, whereas the search order was the opposite before.
Diffstat (limited to 'src')
-rw-r--r--src/Fl.cxx8
-rw-r--r--src/Fl_Native_File_Chooser_GTK.cxx72
-rw-r--r--src/drivers/Posix/Fl_Posix_Printer_Driver.cxx180
-rw-r--r--src/drivers/X11/Fl_X11_System_Driver.H4
-rw-r--r--src/drivers/X11/Fl_X11_System_Driver.cxx57
5 files changed, 261 insertions, 60 deletions
diff --git a/src/Fl.cxx b/src/Fl.cxx
index 1327509e8..0a4e22ee9 100644
--- a/src/Fl.cxx
+++ b/src/Fl.cxx
@@ -1866,7 +1866,9 @@ bool Fl::option(Fl_Option opt)
options_[OPTION_SHOW_TOOLTIPS] = tmp;
opt_prefs.get("FNFCUsesGTK", tmp, 1); // default: on
options_[OPTION_FNFC_USES_GTK] = tmp;
-
+ opt_prefs.get("PrintUsesGTK", tmp, 1); // default: on
+ options_[OPTION_PRINTER_USES_GTK] = tmp;
+
opt_prefs.get("ShowZoomFactor", tmp, 1); // default: on
options_[OPTION_SHOW_SCALING] = tmp;
}
@@ -1888,7 +1890,9 @@ bool Fl::option(Fl_Option opt)
if (tmp >= 0) options_[OPTION_SHOW_TOOLTIPS] = tmp;
opt_prefs.get("FNFCUsesGTK", tmp, -1);
if (tmp >= 0) options_[OPTION_FNFC_USES_GTK] = tmp;
-
+ opt_prefs.get("PrintUsesGTK", tmp, -1);
+ if (tmp >= 0) options_[OPTION_PRINTER_USES_GTK] = tmp;
+
opt_prefs.get("ShowZoomFactor", tmp, -1);
if (tmp >= 0) options_[OPTION_SHOW_SCALING] = tmp;
}
diff --git a/src/Fl_Native_File_Chooser_GTK.cxx b/src/Fl_Native_File_Chooser_GTK.cxx
index 2d6b819f9..575ab4c70 100644
--- a/src/Fl_Native_File_Chooser_GTK.cxx
+++ b/src/Fl_Native_File_Chooser_GTK.cxx
@@ -24,6 +24,7 @@
#if HAVE_DLSYM && HAVE_DLFCN_H
#include <dlfcn.h> // for dlopen et al
+#include "drivers/X11/Fl_X11_System_Driver.H"
#endif
#include <locale.h> // for setlocale
@@ -159,10 +160,6 @@ static XX_g_slist_length fl_g_slist_length = NULL;
typedef void (*XX_g_slist_free) (GSList *);
static XX_g_slist_free fl_g_slist_free = NULL;
-// gboolean gtk_init_check (int *argc, char ***argv);
-typedef gboolean (*XX_gtk_init_check)(int *, char ***);
-static XX_gtk_init_check fl_gtk_init_check = NULL;
-
// void gtk_widget_destroy (GtkWidget *widget);
typedef void (*XX_gtk_widget_destroy) (GtkWidget *);
static XX_gtk_widget_destroy fl_gtk_widget_destroy = NULL;
@@ -262,9 +259,9 @@ static XX_gtk_widget_show_now fl_gtk_widget_show_now = NULL;
typedef GdkWindow* (*XX_gtk_widget_get_window)(GtkWidget *);
static XX_gtk_widget_get_window fl_gtk_widget_get_window = NULL;
-// Window gdk_x11_drawable_get_xid(GdkWindow *);
-typedef Window (*XX_gdk_x11_drawable_get_xid)(GdkWindow *);
-static XX_gdk_x11_drawable_get_xid fl_gdk_x11_drawable_get_xid = NULL;
+// Window gdk_x11_drawable_get_xid(GdkWindow *); or gdk_x11_window_get_xid
+typedef Window (*gdk_to_X11_t)(GdkWindow*);
+static gdk_to_X11_t fl_gdk_to_X11 = NULL;
// GtkWidget *gtk_check_button_new_with_label(const gchar *);
typedef GtkWidget* (*XX_gtk_check_button_new_with_label)(const gchar *);
@@ -492,15 +489,8 @@ static void run_response_handler(GtkDialog *dialog, gint response_id, gpointer d
int Fl_GTK_Native_File_Chooser_Driver::fl_gtk_chooser_wrapper()
{
int result = 1;
- static int have_gtk_init = 0;
char *p;
-
- if(!have_gtk_init) {
- have_gtk_init = -1;
- int ac = 0;
- fl_gtk_init_check(&ac, NULL);
- }
-
+
if(gtkw_ptr) { // discard the previous dialog widget
fl_gtk_widget_destroy (gtkw_ptr);
gtkw_ptr = NULL;
@@ -611,7 +601,7 @@ int Fl_GTK_Native_File_Chooser_Driver::fl_gtk_chooser_wrapper()
fl_gtk_widget_show_now(gtkw_ptr); // map the GTK window on screen
if (firstw) {
GdkWindow* gdkw = fl_gtk_widget_get_window(gtkw_ptr);
- Window xw = fl_gdk_x11_drawable_get_xid(gdkw); // get the X11 ref of the GTK window
+ Window xw = fl_gdk_to_X11(gdkw); // get the X11 ref of the GTK window
XSetTransientForHint(fl_display, xw, fl_xid(firstw)); // set the GTK window transient for the last FLTK win
}
gboolean state = fl_gtk_file_chooser_get_show_hidden((GtkFileChooser *)gtkw_ptr);
@@ -701,57 +691,22 @@ fprintf(stderr, "%s\n", pc_dl_error); \
did_find_GTK_libs = 0; \
return; }
-static void* fl_dlopen(const char *filename1, const char *filename2)
-{
- void *ptr = dlopen(filename1, RTLD_LAZY | RTLD_GLOBAL);
- if (!ptr) ptr = dlopen(filename2, RTLD_LAZY | RTLD_GLOBAL);
- return ptr;
-}
+
#endif // HAVE_DLSYM && HAVE_DLFCN_H
-/*
+/*
* Use dlopen to see if we can load the gtk dynamic libraries that
* will allow us to create a GtkFileChooserDialog() on the fly,
* without linking to the GTK libs at compile time.
*/
void Fl_GTK_Native_File_Chooser_Driver::probe_for_GTK_libs(void) {
#if HAVE_DLSYM && HAVE_DLFCN_H
- void *ptr_glib = NULL;
- void *ptr_gtk = NULL;
-
-# ifdef __APPLE_CC__ // allows testing on Darwin + X11
- ptr_glib = dlopen("/sw/lib/libglib-2.0.dylib", RTLD_LAZY | RTLD_GLOBAL);
-# else
- ptr_glib = fl_dlopen("libglib-2.0.so", "libglib-2.0.so.0");
-# endif
- // Try first with GTK2
-# ifdef __APPLE_CC__ // allows testing on Darwin + X11
- ptr_gtk = dlopen("/sw/lib/libgtk-x11-2.0.dylib", RTLD_LAZY | RTLD_GLOBAL);
-#else
- ptr_gtk = fl_dlopen("libgtk-x11-2.0.so", "libgtk-x11-2.0.so.0");
-#endif
- if (ptr_gtk && ptr_glib) {
-#ifdef DEBUG
- puts("selected GTK-2\n");
-#endif
- }
- else {// Try then with GTK3
- ptr_gtk = fl_dlopen("libgtk-3.so", "libgtk-3.so.0");
-#ifdef DEBUG
- if (ptr_gtk && ptr_glib) {
- puts("selected GTK-3\n");
- }
-#endif
- }
-
- if((!ptr_glib) || (!ptr_gtk)) {
-#ifdef DEBUG
- puts("Failure to load libglib or libgtk");
-#endif
+ void *ptr_gtk;
+ if ( !Fl_X11_System_Driver::probe_for_GTK(2, 4, &ptr_gtk)) {
did_find_GTK_libs = 0;
return;
}
-
+ void *ptr_glib = ptr_gtk;
char *pc_dl_error; // used to report errors by the GET_SYM macro...
// items we need from GLib
GET_SYM(g_free, ptr_glib);
@@ -759,7 +714,6 @@ void Fl_GTK_Native_File_Chooser_Driver::probe_for_GTK_libs(void) {
GET_SYM(g_slist_length, ptr_glib);
GET_SYM(g_slist_free, ptr_glib);
// items we need from GTK
- GET_SYM(gtk_init_check, ptr_gtk);
GET_SYM(gtk_widget_destroy, ptr_gtk);
GET_SYM(gtk_file_chooser_set_select_multiple, ptr_gtk);
GET_SYM(gtk_file_chooser_set_do_overwrite_confirmation, ptr_gtk);
@@ -784,7 +738,9 @@ void Fl_GTK_Native_File_Chooser_Driver::probe_for_GTK_libs(void) {
GET_SYM(gtk_file_chooser_set_extra_widget, ptr_gtk);
GET_SYM(gtk_widget_show_now, ptr_gtk);
GET_SYM(gtk_widget_get_window, ptr_gtk);
- GET_SYM(gdk_x11_drawable_get_xid, ptr_gtk);
+ fl_gdk_to_X11 = (gdk_to_X11_t)dlsym(ptr_gtk, "gdk_x11_drawable_get_xid");
+ if (!fl_gdk_to_X11) fl_gdk_to_X11 = (gdk_to_X11_t)dlsym(ptr_gtk, "gdk_x11_window_get_xid");
+ if (!fl_gdk_to_X11) { did_find_GTK_libs = 0; return; }
GET_SYM(gtk_check_button_new_with_label, ptr_gtk);
GET_SYM(g_signal_connect_data, ptr_gtk);
GET_SYM(gtk_toggle_button_get_active, ptr_gtk);
diff --git a/src/drivers/Posix/Fl_Posix_Printer_Driver.cxx b/src/drivers/Posix/Fl_Posix_Printer_Driver.cxx
index 835529be1..926f1b3d6 100644
--- a/src/drivers/Posix/Fl_Posix_Printer_Driver.cxx
+++ b/src/drivers/Posix/Fl_Posix_Printer_Driver.cxx
@@ -31,8 +31,188 @@ class Fl_Posix_Printer_Driver : public Fl_PostScript_File_Device {
virtual int begin_job(int pagecount, int *frompage = NULL, int *topage = NULL);
};
+#if HAVE_DLSYM && HAVE_DLFCN_H
+// GTK types
+#include <dlfcn.h> // for dlopen et al
+#include <unistd.h> // for mkstemp
+#include <FL/filename.H>
+#include "../X11/Fl_X11_System_Driver.H"
+#define GTK_PAPER_NAME_LETTER "na_letter"
+#define GTK_RESPONSE_NONE 0
+#define GTK_RESPONSE_OK -5
+#define GTK_PRINT_PAGES_RANGES 2
+class Fl_GTK_Printer_Driver : public Fl_PostScript_File_Device {
+public:
+ typedef int gboolean;
+ typedef struct _GtkPrintUnixDialog GtkPrintUnixDialog;
+ typedef struct _GtkDialog GtkDialog;
+ typedef struct _GtkPrintSettings GtkPrintSettings;
+ typedef struct _GtkPageSetup GtkPageSetup;
+ enum GtkPageOrientation {GTK_PAGE_ORIENTATION_PORTRAIT, GTK_PAGE_ORIENTATION_LANDSCAPE};
+ typedef struct _GtkPaperSize GtkPaperSize;
+ typedef struct _GtkPrinter GtkPrinter;
+ typedef struct _GtkPrintJob GtkPrintJob;
+ typedef struct _GtkWidget GtkWidget;
+ struct GError;
+
+ GtkPrintJob *pjob; // data shared between begin_job() and end_job()
+ char tmpfilename[50]; // name of temporary PostScript file containing to-be-printed data
+ virtual int begin_job(int pagecount, int *frompage = NULL, int *topage = NULL);
+ virtual void end_job();
+ static bool probe_for_GTK();
+ static void *ptr_gtk; // points to the GTK dynamic lib or NULL
+
+ typedef GtkPrintUnixDialog* (*gtk_print_unix_dialog_new_t)(const char*, void*);
+ typedef int (*gtk_dialog_run_t)(GtkDialog*);
+ typedef GtkPrintSettings *(*gtk_print_unix_dialog_get_settings_t)(GtkPrintUnixDialog*);
+ typedef void (*gtk_print_unix_dialog_set_settings_t)(GtkPrintUnixDialog*, GtkPrintSettings*);
+ typedef GtkPageSetup *(*gtk_print_unix_dialog_get_page_setup_t)(GtkPrintUnixDialog*);
+ typedef GtkPageOrientation (*gtk_page_setup_get_orientation_t)(GtkPageSetup*);
+ typedef GtkPaperSize* (*gtk_page_setup_get_paper_size_t)(GtkPageSetup*);
+ typedef const char * (*gtk_paper_size_get_name_t)(GtkPaperSize*);
+ typedef GtkPrinter * (*gtk_print_unix_dialog_get_selected_printer_t)(GtkPrintUnixDialog*);
+ typedef int (*gtk_printer_accepts_ps_t)(GtkPrinter*);
+ typedef int (*gtk_printer_is_active_t)(GtkPrinter*);
+ typedef GtkPrintJob *(*gtk_print_job_new_t)(const char *, GtkPrinter *, GtkPrintSettings *, GtkPageSetup *);
+ typedef void (*gtk_widget_hide_t)(GtkWidget*);
+ typedef void (*gtk_widget_destroy_t)(GtkWidget*);
+ typedef gboolean (*gtk_events_pending_t)(void);
+ typedef void (*gtk_main_iteration_t)(void);
+ typedef int (*gtk_print_job_set_source_file_t)(GtkPrintJob *job, const char *filename, GError **error);
+ typedef void (*gtk_print_job_send_t)(GtkPrintJob *, void* , gboolean* , void* );
+ typedef void (*gtk_print_settings_set_t) (GtkPrintSettings *settings, const char *key, const char *value);
+ typedef const char * (*gtk_print_settings_get_t) (GtkPrintSettings *settings, const char *key );
+ typedef int (*gtk_print_settings_get_print_pages_t)(GtkPrintSettings*);
+ struct GtkPageRange { int start, end; };
+ typedef GtkPageRange* (*gtk_print_settings_get_page_ranges_t)(GtkPrintSettings*, int*);
+ typedef void (*g_object_unref_t)(void* object);
+};
+
+// the CALL_GTK macro produces the source code to call a GTK function given its name
+// or to get a pointer to this function :
+// CALL_GTK(gtk_my_function) produces ((gtk_my_function_t)dlsym(ptr_gtk, "gtk_my_function"))
+#define CALL_GTK(NAME) ((NAME##_t)dlsym(ptr_gtk, #NAME))
+
+void *Fl_GTK_Printer_Driver::ptr_gtk = NULL;
+
+// test wether GTK is available at run-time
+bool Fl_GTK_Printer_Driver::probe_for_GTK() {
+ return Fl_X11_System_Driver::probe_for_GTK(2, 10, &ptr_gtk);
+}
+
+
+int Fl_GTK_Printer_Driver::begin_job(int pagecount, int *firstpage, int *lastpage) {
+ enum Fl_Paged_Device::Page_Format format = Fl_Paged_Device::A4;
+ enum Fl_Paged_Device::Page_Layout layout = Fl_Paged_Device::PORTRAIT ;
+
+ GtkPrintUnixDialog *pdialog = CALL_GTK(gtk_print_unix_dialog_new)(Fl_Printer::dialog_title, NULL); //2.10
+ GtkPrintSettings *psettings = CALL_GTK(gtk_print_unix_dialog_get_settings)(pdialog); //2.10
+ CALL_GTK(gtk_print_settings_set)(psettings, "output-file-format", "ps"); //2.10
+ char line[FL_PATH_MAX + 20], cwd[FL_PATH_MAX];
+ sprintf(line, "file://%s/FLTK.ps", fl_getcwd(cwd, FL_PATH_MAX));
+ CALL_GTK(gtk_print_settings_set)(psettings, "output-uri", line); //2.10
+ CALL_GTK(gtk_print_unix_dialog_set_settings)(pdialog, psettings); //2.10
+ CALL_GTK(g_object_unref)(psettings);
+ int response_id = CALL_GTK(gtk_dialog_run)((GtkDialog*)pdialog);
+ if (response_id == GTK_RESPONSE_OK) {
+ GtkPageSetup *psetup = CALL_GTK(gtk_print_unix_dialog_get_page_setup)(pdialog); //2.10
+ GtkPageOrientation orient = CALL_GTK(gtk_page_setup_get_orientation)(psetup); //2.10
+ if (orient == GTK_PAGE_ORIENTATION_LANDSCAPE) layout = Fl_Paged_Device::LANDSCAPE;
+ GtkPaperSize* psize = CALL_GTK(gtk_page_setup_get_paper_size)(psetup); //2.10
+ const char *pname = CALL_GTK(gtk_paper_size_get_name)(psize); //2.10
+ if (strcmp(pname, GTK_PAPER_NAME_LETTER) == 0) format = Fl_Paged_Device::LETTER;
+ GtkPrinter *gprinter = CALL_GTK(gtk_print_unix_dialog_get_selected_printer)(pdialog); //2.10
+ psettings = CALL_GTK(gtk_print_unix_dialog_get_settings)(pdialog); //2.10
+ const char* p = CALL_GTK(gtk_print_settings_get)(psettings, "output-uri"); //2.10
+ bool printing_to_file = (p != NULL);
+ if (printing_to_file) {
+ p += 6; // skip "file://" prefix
+ strcpy(line, p);
+ int l = strlen(p);
+ if (strcmp(p+l-4, "/.ps") == 0) {
+ line[l-3] = 0;
+ strcat(line, "FLTK.ps");
+ }
+ }
+ if (firstpage && lastpage) {
+ *firstpage = 1; *lastpage = pagecount;
+ if (CALL_GTK(gtk_print_settings_get_print_pages)(psettings) == GTK_PRINT_PAGES_RANGES) { // 2.10
+ int num_ranges;
+ GtkPageRange *ranges = CALL_GTK(gtk_print_settings_get_page_ranges)(psettings, &num_ranges); //2.10
+ if (num_ranges > 0) {
+ *firstpage = ranges[0].start + 1;
+ *lastpage = ranges[0].end + 1;
+ free(ranges);
+ }
+ }
+ }
+ response_id = GTK_RESPONSE_NONE;
+ if (printing_to_file) {
+ pjob = NULL;
+ FILE *output = fopen(line, "w");
+ if (output) {
+ Fl_PostScript_File_Device::begin_job(output, 0, format, layout);
+ response_id = GTK_RESPONSE_OK;
+ }
+ } else if ( CALL_GTK(gtk_printer_accepts_ps)(gprinter) && //2.10
+ CALL_GTK(gtk_printer_is_active)(gprinter) ) { // 2.10
+ strcpy(tmpfilename, "/tmp/FLTKprintjobXXXXXX");
+ int fd = mkstemp(tmpfilename);
+ if (fd >= 0) {
+ FILE *output = fdopen(fd, "w");
+ Fl_PostScript_File_Device::begin_job(output, 0, format, layout);
+ pjob = CALL_GTK(gtk_print_job_new)("FLTK print job", gprinter, psettings, psetup); //2.10
+ response_id = GTK_RESPONSE_OK;
+ }
+ }
+ CALL_GTK(g_object_unref)(psettings);
+ }
+ CALL_GTK(gtk_widget_hide)((GtkWidget*)pdialog);
+ gtk_events_pending_t fl_gtk_events_pending = CALL_GTK(gtk_events_pending);
+ gtk_main_iteration_t fl_gtk_main_iteration = CALL_GTK(gtk_main_iteration);
+ while (fl_gtk_events_pending()) fl_gtk_main_iteration();
+ CALL_GTK(gtk_widget_destroy)((GtkWidget*)pdialog);
+ Fl_Window *first = Fl::first_window();
+ if (first) {
+ Fl_Surface_Device::push_current(Fl_Display_Device::display_device());
+ first->show();
+ while (Fl::ready()) Fl::check();
+ Fl_Surface_Device::pop_current();
+ }
+ return (response_id == GTK_RESPONSE_OK ? 0 : 1);
+}
+
+static void pJobCompleteFunc(Fl_GTK_Printer_Driver::GtkPrintJob *print_job, Fl_GTK_Printer_Driver::gboolean *user_data, const Fl_GTK_Printer_Driver::GError *error) {
+ *user_data = true;
+}
+static void pDestroyNotify(void* data) {}
+
+void Fl_GTK_Printer_Driver::end_job() {
+ Fl_PostScript_File_Device::end_job();
+ Fl_PostScript_Graphics_Driver *psgd = driver();
+ fclose(psgd->output);
+ if (!pjob) return;
+ GError *gerr;
+ gboolean gb = CALL_GTK(gtk_print_job_set_source_file)(pjob, tmpfilename, &gerr); //2.10
+ if (gb) {
+ gb = false;
+ CALL_GTK(gtk_print_job_send)(pjob, (void*)pJobCompleteFunc, &gb, (void*)pDestroyNotify); //2.10
+ gtk_main_iteration_t fl_gtk_main_iteration = CALL_GTK(gtk_main_iteration);
+ while (!gb) {
+ fl_gtk_main_iteration();
+ }
+ }
+ fl_unlink(tmpfilename);
+}
+#endif // HAVE_DLSYM && HAVE_DLFCN_H
+
+
Fl_Paged_Device* Fl_Printer::newPrinterDriver(void)
{
+#if HAVE_DLSYM && HAVE_DLFCN_H
+ static bool gtk = ( Fl::option(Fl::OPTION_PRINTER_USES_GTK) ? Fl_GTK_Printer_Driver::probe_for_GTK() : false);
+ if (gtk) return new Fl_GTK_Printer_Driver();
+#endif
return new Fl_Posix_Printer_Driver();
}
diff --git a/src/drivers/X11/Fl_X11_System_Driver.H b/src/drivers/X11/Fl_X11_System_Driver.H
index b7d6e9ff7..138959d75 100644
--- a/src/drivers/X11/Fl_X11_System_Driver.H
+++ b/src/drivers/X11/Fl_X11_System_Driver.H
@@ -20,6 +20,7 @@
#ifndef FL_X11_SYSTEM_DRIVER_H
#define FL_X11_SYSTEM_DRIVER_H
+#include "../../config_lib.h"
#include "../Posix/Fl_Posix_System_Driver.H"
class Fl_X11_System_Driver : public Fl_Posix_System_Driver {
@@ -63,6 +64,9 @@ public:
virtual void add_fd(int fd, Fl_FD_Handler cb, void* = 0);
virtual void remove_fd(int, int when);
virtual void remove_fd(int);
+#if HAVE_DLSYM && HAVE_DLFCN_H
+ static bool probe_for_GTK(int major, int minor, void **ptr_gtk);
+#endif
};
#endif /* FL_X11_SYSTEM_DRIVER_H */
diff --git a/src/drivers/X11/Fl_X11_System_Driver.cxx b/src/drivers/X11/Fl_X11_System_Driver.cxx
index 42d403299..f406dce02 100644
--- a/src/drivers/X11/Fl_X11_System_Driver.cxx
+++ b/src/drivers/X11/Fl_X11_System_Driver.cxx
@@ -517,6 +517,63 @@ int Fl_X11_System_Driver::utf8locale() {
return ret;
}
+#if HAVE_DLSYM && HAVE_DLFCN_H
+#include <dlfcn.h> // for dlopen et al
+
+static void* fl_dlopen(const char *filename1, const char *filename2)
+{
+ void *ptr = dlopen(filename1, RTLD_LAZY | RTLD_GLOBAL);
+ if (!ptr) ptr = dlopen(filename2, RTLD_LAZY | RTLD_GLOBAL);
+ return ptr;
+}
+
+bool Fl_X11_System_Driver::probe_for_GTK(int major, int minor, void **ptr_gtk) {
+ typedef void (*init_t)(int*, void*);
+ *ptr_gtk = NULL;
+ // was GTK previously loaded?
+ init_t init_f = (init_t)dlsym(RTLD_DEFAULT, "gtk_init_check");
+ if (init_f) { // yes it was.
+ *ptr_gtk = RTLD_DEFAULT; // Caution: NULL under linux, not-NULL under Darwin
+ } else {
+ // Try first with GTK3
+ *ptr_gtk = fl_dlopen("libgtk-3.so", "libgtk-3.so.0");
+ if (*ptr_gtk) {
+#ifdef DEBUG
+ puts("selected GTK-3\n");
+#endif
+ } else {
+ // Try then with GTK2
+# ifdef __APPLE_CC__ // allows testing on Darwin + X11
+ *ptr_gtk = ::dlopen("/sw/lib/libgtk-x11-2.0.dylib", RTLD_LAZY | RTLD_GLOBAL);
+#else
+ *ptr_gtk = fl_dlopen("libgtk-x11-2.0.so", "libgtk-x11-2.0.so.0");
+#endif
+ }
+ if (*ptr_gtk) {
+#ifdef DEBUG
+ puts("selected GTK-2\n");
+#endif
+ } else {
+#ifdef DEBUG
+ puts("Failure to load libgtk");
+#endif
+ return false;
+ }
+ init_f = (init_t)dlsym(*ptr_gtk, "gtk_init_check");
+ if (!init_f) return false;
+ }
+ int ac = 0;
+ init_f(&ac, NULL);
+ // now check if running version is high enough
+ if (dlsym(*ptr_gtk, "gtk_get_major_version") == NULL) { // YES indicates V 3
+ typedef const char* (*check_t)(int, int, int);
+ check_t check_f = (check_t)dlsym(*ptr_gtk, "gtk_check_version");
+ if (!check_f || check_f(major, minor, 0) ) return false;
+ }
+ return true;
+}
+#endif // HAVE_DLSYM && HAVE_DLFCN_H
+
#if !defined(FL_DOXYGEN)
const char *Fl_X11_System_Driver::shortcut_add_key_name(unsigned key, char *p, char *buf, const char **eom)