From 79041f07cd6b9be3e091f86b1b3439108a5bce5b Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 8 Jun 2006 09:09:50 +0000 Subject: [PATCH] Update windows to build with new APIs and first cut at preview work. 2006-06-08 Alexander Larsson * gtk/gtkprintoperation-win32.c: Update windows to build with new APIs and first cut at preview work. * gtk/gtkprintoperation-private.h: * gtk/gtkprintoperation-unix.c: * gtk/gtkprintoperation.c Various updates needed when making the preview work on win32. * tests/print-editor.c: Print, don't preview. --- ChangeLog | 14 +++ ChangeLog.pre-2-10 | 14 +++ gtk/gtkprintoperation-private.h | 13 ++- gtk/gtkprintoperation-unix.c | 35 +++++- gtk/gtkprintoperation-win32.c | 198 +++++++++++++++++++++++++++----- gtk/gtkprintoperation.c | 36 +++--- tests/print-editor.c | 4 +- 7 files changed, 254 insertions(+), 60 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0f68b3992b..188b2a1370 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2006-06-08 Alexander Larsson + + * gtk/gtkprintoperation-win32.c: + Update windows to build with new APIs and first cut + at preview work. + + * gtk/gtkprintoperation-private.h: + * gtk/gtkprintoperation-unix.c: + * gtk/gtkprintoperation.c + Various updates needed when making the preview work on win32. + + * tests/print-editor.c: + Print, don't preview. + 2006-06-07 Matthias Clasen * gtk/gtkentry.c (popup_targets_received): Make Delete diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 0f68b3992b..188b2a1370 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,17 @@ +2006-06-08 Alexander Larsson + + * gtk/gtkprintoperation-win32.c: + Update windows to build with new APIs and first cut + at preview work. + + * gtk/gtkprintoperation-private.h: + * gtk/gtkprintoperation-unix.c: + * gtk/gtkprintoperation.c + Various updates needed when making the preview work on win32. + + * tests/print-editor.c: + Print, don't preview. + 2006-06-07 Matthias Clasen * gtk/gtkentry.c (popup_targets_received): Make Delete diff --git a/gtk/gtkprintoperation-private.h b/gtk/gtkprintoperation-private.h index 73f44e5353..a727da4ace 100644 --- a/gtk/gtkprintoperation-private.h +++ b/gtk/gtkprintoperation-private.h @@ -50,10 +50,6 @@ struct _GtkPrintOperationPrivate GtkPrintContext *print_context; - /* Data for the print job: */ - /* cairo_surface_t *surface; */ - /* gdouble dpi_x, dpi_y; */ - GtkPrintPages print_pages; GtkPageRange *page_ranges; gint num_page_ranges; @@ -97,16 +93,23 @@ void _gtk_print_operation_platform_backend_run_dialog_async GtkWindow *parent, GtkPrintOperationPrintFunc print_cb); void _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op, + cairo_surface_t *surface, GtkWindow *parent, const char *filename); cairo_surface_t * _gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *op, GtkPageSetup *page_setup, gdouble *dpi_x, gdouble *dpi_y, - const gchar *target); + gchar **target); void _gtk_print_operation_platform_backend_resize_preview_surface (GtkPrintOperation *op, GtkPageSetup *page_setup, cairo_surface_t *surface); +void _gtk_print_operation_platform_backend_preview_start_page (GtkPrintOperation *op, + cairo_surface_t *surface, + cairo_t *cr); +void _gtk_print_operation_platform_backend_preview_end_page (GtkPrintOperation *op, + cairo_surface_t *surface, + cairo_t *cr); void _gtk_print_operation_set_status (GtkPrintOperation *op, GtkPrintStatus status, diff --git a/gtk/gtkprintoperation-unix.c b/gtk/gtkprintoperation-unix.c index d5389f92c7..46ce889be9 100644 --- a/gtk/gtkprintoperation-unix.c +++ b/gtk/gtkprintoperation-unix.c @@ -164,6 +164,7 @@ shell_command_substitute_file (const gchar *cmd, void _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op, + cairo_surface_t *surface, GtkWindow *parent, const gchar *filename) { @@ -175,6 +176,8 @@ _gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op, gchar *quoted_filename; GdkScreen *screen; GError *error = NULL; + + cairo_surface_destroy (pop->surface); settings = gtk_settings_get_default (); g_object_get (settings, "gtk-print-preview-command", &preview_cmd, NULL); @@ -570,17 +573,45 @@ _gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation GtkPageSetup *page_setup, gdouble *dpi_x, gdouble *dpi_y, - const gchar *target) + gchar **target) { + gchar *tmp_dir, *dir_template, *preview_filename; GtkPaperSize *paper_size; gdouble w, h; + dir_template = g_build_filename (g_get_tmp_dir (), "print-preview-XXXXXX", NULL); + + /* use temp dirs because apps like evince need to have extensions + * to determine the mime type + */ + tmp_dir = mkdtemp(dir_template); + preview_filename = g_build_filename (tmp_dir, + "Print Preview.pdf", + NULL); + g_free (dir_template); + *target = preview_filename; + paper_size = gtk_page_setup_get_paper_size (page_setup); w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS); h = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS); *dpi_x = *dpi_y = 72; - return cairo_pdf_surface_create (target, w, h); + return cairo_pdf_surface_create (preview_filename, w, h); +} + +void +_gtk_print_operation_platform_backend_preview_start_page (GtkPrintOperation *op, + cairo_surface_t *surface, + cairo_t *cr) +{ +} + +void +_gtk_print_operation_platform_backend_preview_end_page (GtkPrintOperation *op, + cairo_surface_t *surface, + cairo_t *cr) +{ + cairo_show_page (cr); } void diff --git a/gtk/gtkprintoperation-win32.c b/gtk/gtkprintoperation-win32.c index c546ea4c83..dd37581de9 100644 --- a/gtk/gtkprintoperation-win32.c +++ b/gtk/gtkprintoperation-win32.c @@ -26,6 +26,10 @@ #define COBJMACROS #include "config.h" #include +#ifdef HAVE_UNISTD_H +#include +#endif +#include #include #include #include @@ -58,6 +62,7 @@ typedef struct { int job_id; guint timeout_id; + cairo_surface_t *surface; GtkWidget *embed_widget; } GtkPrintOperationWin32; @@ -492,9 +497,9 @@ win32_end_run (GtkPrintOperation *op, GlobalFree(op_win32->devmode); GlobalFree(op_win32->devnames); - cairo_surface_finish (op->priv->surface); - cairo_surface_destroy (op->priv->surface); - op->priv->surface = NULL; + cairo_surface_finish (op_win32->surface); + cairo_surface_destroy (op_win32->surface); + op_win32->surface = NULL; DeleteDC(op_win32->hdc); @@ -1394,11 +1399,46 @@ create_application_page (GtkPrintOperation *op) return hpage; } +static GtkPageSetup * +create_page_setup (GtkPrintOperation *op) +{ + GtkPrintOperationPrivate *priv = op->priv; + GtkPageSetup *page_setup; + GtkPrintSettings *settings; + + if (priv->default_page_setup) + page_setup = gtk_page_setup_copy (priv->default_page_setup); + else + page_setup = gtk_page_setup_new (); + + settings = priv->print_settings; + if (settings) + { + GtkPaperSize *paper_size; + + if (gtk_print_settings_has_key (settings, GTK_PRINT_SETTINGS_ORIENTATION)) + gtk_page_setup_set_orientation (page_setup, + gtk_print_settings_get_orientation (settings)); + + + paper_size = gtk_print_settings_get_paper_size (settings); + if (paper_size) + { + gtk_page_setup_set_paper_size (page_setup, paper_size); + gtk_paper_size_free (paper_size); + } + + /* TODO: Margins? */ + } + + return page_setup; +} + GtkPrintOperationResult _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, + gboolean show_dialog, GtkWindow *parent, - gboolean *do_print, - GError **error) + gboolean *do_print) { HRESULT hResult; LPPRINTDLGEXW printdlgex = NULL; @@ -1407,14 +1447,17 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, GtkWidget *invisible = NULL; GtkPrintOperationResult result; GtkPrintOperationWin32 *op_win32; + GtkPrintOperationPrivate *priv; IPrintDialogCallback *callback; HPROPSHEETPAGE prop_page; *do_print = FALSE; + priv = op->priv; + op_win32 = g_new0 (GtkPrintOperationWin32, 1); - op->priv->platform_data = op_win32; - op->priv->free_platform_data = (GDestroyNotify) op_win32_free; + priv->platform_data = op_win32; + priv->free_platform_data = (GDestroyNotify) op_win32_free; if (parent == NULL) { @@ -1428,7 +1471,7 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, if (!printdlgex) { result = GTK_PRINT_OPERATION_RESULT_ERROR; - g_set_error (error, + g_set_error (&priv->error, GTK_PRINT_ERROR, GTK_PRINT_ERROR_NOMEM, _("Not enough free memory")); @@ -1451,7 +1494,7 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, if (!page_ranges) { result = GTK_PRINT_OPERATION_RESULT_ERROR; - g_set_error (error, + g_set_error (&priv->error, GTK_PRINT_ERROR, GTK_PRINT_ERROR_NOMEM, _("Not enough free memory")); @@ -1499,27 +1542,27 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, { result = GTK_PRINT_OPERATION_RESULT_ERROR; if (hResult == E_OUTOFMEMORY) - g_set_error (error, + g_set_error (&priv->error, GTK_PRINT_ERROR, GTK_PRINT_ERROR_NOMEM, _("Not enough free memory")); else if (hResult == E_INVALIDARG) - g_set_error (error, + g_set_error (&priv->error, GTK_PRINT_ERROR, GTK_PRINT_ERROR_INTERNAL_ERROR, _("Invalid argument to PrintDlgEx")); else if (hResult == E_POINTER) - g_set_error (error, + g_set_error (&priv->error, GTK_PRINT_ERROR, GTK_PRINT_ERROR_INTERNAL_ERROR, _("Invalid pointer to PrintDlgEx")); else if (hResult == E_HANDLE) - g_set_error (error, + g_set_error (&priv->error, GTK_PRINT_ERROR, GTK_PRINT_ERROR_INTERNAL_ERROR, _("Invalid handle to PrintDlgEx")); else /* E_FAIL */ - g_set_error (error, + g_set_error (&priv->error, GTK_PRINT_ERROR, GTK_PRINT_ERROR_GENERAL, _("Unspecified error")); @@ -1539,13 +1582,25 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, { DOCINFOW docinfo; int job_id; + double dpi_x, dpi_y; + cairo_t *cr; + GtkPageSetup *page_setup; + priv->print_context = _gtk_print_context_new (op); + page_setup = create_page_setup (op); + _gtk_print_context_set_page_setup (priv->print_context, page_setup); + g_object_unref (page_setup); + *do_print = TRUE; - op->priv->surface = cairo_win32_surface_create (printdlgex->hDC); - op->priv->dpi_x = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSX); - op->priv->dpi_y = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSY); + op_win32->surface = cairo_win32_surface_create (printdlgex->hDC); + dpi_x = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSX); + dpi_y = (double)GetDeviceCaps (printdlgex->hDC, LOGPIXELSY); + cr = cairo_create (op_win32->surface); + gtk_print_context_set_cairo_context (priv->print_context, cr, dpi_x, dpi_y); + cairo_destroy (cr); + memset( &docinfo, 0, sizeof (DOCINFOW)); docinfo.cbSize = sizeof (DOCINFOW); docinfo.lpszDocName = g_utf8_to_utf16 (op->priv->job_name, -1, NULL, NULL, NULL); @@ -1558,13 +1613,13 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, if (job_id <= 0) { result = GTK_PRINT_OPERATION_RESULT_ERROR; - g_set_error (error, + g_set_error (&priv->error, GTK_PRINT_ERROR, GTK_PRINT_ERROR_GENERAL, _("Error from StartDoc")); *do_print = FALSE; - cairo_surface_destroy (op->priv->surface); - op->priv->surface = NULL; + cairo_surface_destroy (op_win32->surface); + op_win32->surface = NULL; goto out; } @@ -1609,18 +1664,101 @@ _gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op, return result; } -void -_gtk_print_operation_platform_backend_run_dialog_async (GtkPrintOperation *op, - GtkWindow *parent, - GtkPrintOperationPrintFunc print_cb) +void +_gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op, + cairo_surface_t *surface, + GtkWindow *parent, + const gchar *filename) { - gboolean do_print; + HDC dc; + HENHMETAFILE metafile; + + dc = cairo_win32_surface_get_dc (surface); + cairo_surface_destroy (surface); + metafile = CloseEnhMetaFile (dc); + DeleteEnhMetaFile (metafile); + + ShellExecuteW (NULL, L"open", (gunichar2 *)filename, NULL, NULL, SW_SHOW); +} - _gtk_print_operation_platform_backend_run_dialog (op, parent, &do_print, NULL); - if (do_print) - print_cb (op, parent, FALSE); - else - _gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL); +void +_gtk_print_operation_platform_backend_preview_start_page (GtkPrintOperation *op, + cairo_surface_t *surface, + cairo_t *cr) +{ + HDC dc = cairo_win32_surface_get_dc (surface); + StartPage (dc); +} + +void +_gtk_print_operation_platform_backend_preview_end_page (GtkPrintOperation *op, + cairo_surface_t *surface, + cairo_t *cr) +{ + /* TODO: This doesn't actually seem to work. + * Do enhanced metafiles really support multiple pages? + */ + HDC dc = cairo_win32_surface_get_dc (surface); + EndPage (dc); +} + +cairo_surface_t * +_gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *op, + GtkPageSetup *page_setup, + gdouble *dpi_x, + gdouble *dpi_y, + gchar **target) +{ + GtkPaperSize *paper_size; + double w, h; + HDC metafile_dc; + RECT rect; + char *template; + char *filename; + gunichar2 *filename_utf16; + int fd; + + template = g_build_filename (g_get_tmp_dir (), "prXXXXXX", NULL); + fd = g_mkstemp (template); + close(fd); + + filename = g_strconcat (template, ".emf", NULL); + g_free (template); + + filename_utf16 = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL); + g_free (filename); + + paper_size = gtk_page_setup_get_paper_size (page_setup); + w = gtk_paper_size_get_width (paper_size, GTK_UNIT_MM); + h = gtk_paper_size_get_height (paper_size, GTK_UNIT_MM); + + rect.left = 0; + rect.right = w*100; + rect.top = 0; + rect.bottom = h*100; + + metafile_dc = CreateEnhMetaFileW (NULL, filename_utf16, + &rect, L"Gtk+\0Print Preview\0\0"); + if (metafile_dc == NULL) + { + g_warning ("Can't create metafile"); + return NULL; + } + + *target = (char *)filename_utf16; + + *dpi_x = (double)GetDeviceCaps (metafile_dc, LOGPIXELSX); + *dpi_y = (double)GetDeviceCaps (metafile_dc, LOGPIXELSY); + + return cairo_win32_surface_create (metafile_dc); +} + +void +_gtk_print_operation_platform_backend_resize_preview_surface (GtkPrintOperation *op, + GtkPageSetup *page_setup, + cairo_surface_t *surface) +{ + /* TODO: Implement */ } GtkPageSetup * diff --git a/gtk/gtkprintoperation.c b/gtk/gtkprintoperation.c index 78d68aa1b8..b39ac1f94a 100644 --- a/gtk/gtkprintoperation.c +++ b/gtk/gtkprintoperation.c @@ -387,13 +387,14 @@ preview_print_idle_done (gpointer data) op = GTK_PRINT_OPERATION (pop->preview); + cairo_surface_finish (pop->surface); + /* Surface is destroyed in launch_preview */ _gtk_print_operation_platform_backend_launch_preview (op, + pop->surface, pop->parent, pop->filename); g_free (pop->filename); - cairo_surface_finish (pop->surface); - cairo_surface_destroy (pop->surface); gtk_print_operation_preview_end_preview (pop->preview); g_free (pop); @@ -417,7 +418,8 @@ preview_print_idle (gpointer data) gtk_print_operation_preview_render_page (pop->preview, pop->page_nr); cr = gtk_print_context_get_cairo_context (pop->print_context); - cairo_show_page (cr); + _gtk_print_operation_platform_backend_preview_end_page (op, pop->surface, + cr); /* TODO: print out sheets not pages and follow ranges */ pop->page_nr++; @@ -436,8 +438,14 @@ preview_got_page_size (GtkPrintOperationPreview *preview, PreviewOp *pop) { GtkPrintOperation *op = GTK_PRINT_OPERATION (preview); + cairo_t *cr; _gtk_print_operation_platform_backend_resize_preview_surface (op, page_setup, pop->surface); + + cr = gtk_print_context_get_cairo_context (pop->print_context); + _gtk_print_operation_platform_backend_preview_start_page (op, pop->surface, + cr); + } static void @@ -462,28 +470,12 @@ gtk_print_operation_preview_handler (GtkPrintOperation *op, GtkWindow *parent) { gdouble dpi_x, dpi_y; - gchar *tmp_dir; - gchar *dir_template; - gchar *preview_filename; PreviewOp *pop; GtkPageSetup *page_setup; cairo_t *cr; - dir_template = g_build_filename (g_get_tmp_dir (), "print-preview-XXXXXX", NULL); - - /* use temp dirs because apps like evince need to have extensions - * to determine the mime type - */ - tmp_dir = mkdtemp(dir_template); - - preview_filename = g_build_filename (tmp_dir, - "Print Preview.pdf", - NULL); - - g_free (dir_template); - pop = g_new0 (PreviewOp, 1); - pop->filename = preview_filename; + pop->filename = NULL; pop->preview = preview; pop->parent = parent; @@ -493,7 +485,7 @@ gtk_print_operation_preview_handler (GtkPrintOperation *op, _gtk_print_operation_platform_backend_create_preview_surface (op, page_setup, &dpi_x, &dpi_y, - pop->filename); + &pop->filename); cr = cairo_create (pop->surface); gtk_print_context_set_cairo_context (op->priv->print_context, cr, @@ -2403,6 +2395,7 @@ gtk_print_operation_run (GtkPrintOperation *op, priv->is_sync = !priv->allow_async; } +#ifndef G_OS_WIN32 else if (priv->allow_async) { priv->is_sync = FALSE; @@ -2412,6 +2405,7 @@ gtk_print_operation_run (GtkPrintOperation *op, print_pages); result = GTK_PRINT_OPERATION_RESULT_IN_PROGRESS; } +#endif else { priv->is_sync = TRUE; diff --git a/tests/print-editor.c b/tests/print-editor.c index e8d6a0e5fd..ee839c1d53 100644 --- a/tests/print-editor.c +++ b/tests/print-editor.c @@ -497,7 +497,7 @@ preview_got_page_size (GtkPrintOperationPreview *preview, dpi_x = pop->area->allocation.width/w; dpi_y = pop->area->allocation.height/h; - + if (fabs (dpi_x - pop->dpi_x) > 0.001 || fabs (dpi_y - pop->dpi_y) > 0.001) { @@ -683,7 +683,7 @@ do_print (GtkAction *action) #if 0 gtk_print_operation_set_allow_async (print, TRUE); #endif - gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PREVIEW, GTK_WINDOW (main_window), NULL); + gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, GTK_WINDOW (main_window), NULL); g_object_unref (print); }