diff options
| author | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2019-09-15 15:57:29 +0200 |
|---|---|---|
| committer | ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> | 2019-09-15 15:57:29 +0200 |
| commit | c549b7acbd65674019b731c6648a9e8eb22f70dd (patch) | |
| tree | 7e6b8745573d2b8c1f9a61a7393b1e7c2b0d8f69 /src/drivers/Posix | |
| parent | 000807cc1d1a1c2f00274763f3e8e24145f1af00 (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.cxx | 180 |
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(); } |
