summaryrefslogtreecommitdiff
path: root/src/drivers/Posix
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/drivers/Posix
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/drivers/Posix')
-rw-r--r--src/drivers/Posix/Fl_Posix_Printer_Driver.cxx180
1 files changed, 180 insertions, 0 deletions
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();
}