Print preview api
- From: Matthias Clasen <mclasen redhat com>
- To: gtk-devel-list gnome org
- Subject: Print preview api
- Date: Thu, 01 Jun 2006 19:13:59 -0400
Ok, after a lot of work (mostly by John and Alex),
we finally have a proposal for a print preview
api that will allow us to use an external viewer
by default, but also support internal preview.
It consists of the following pieces:
1) GtkPrintOperation gets a new signal
gboolean (*preview) (GtkPrintOperation *operation,
GtkPrintOperationPreview *preview,
GtkPrintContext *context,
GtkWindow *parent);
This signal is emitted when the user clicks the preview
button. It the application does not handle it, the
default handler will arrange for the external viewer
to be spawned.
An application that handles the preview internally
should return TRUE from the signal handler. The
GtkPrintOperationPreview that is passed to the signal
handler lets the application control the preview.
2) The GtkPrintOperationPreview interface has
a number of signals:
void (*ready) (GtkPrintOperationPreview *preview,
GtkPrintContext *context);
The ready signal is emitted when pagination is done. The
GtkPrintOperation::preview handler should connect to this
signal to know when it is safe to start displaying pages.
void (*got_page_size) (GtkPrintOperationPreview *preview,
GtkPrintContext *context,
GtkPageSetup *page_setup);
The got-page-size signal is emitted for every rendered
page, when the page setup for the page is know. This signal
can be used to adjust the cairo context used for rendering
the page (e.g. for resizing the preview window).
And methods:
void gtk_print_operation_preview_render_page
(GtkPrintOperationPreview *preview,
gint page_nr)
Renders the requested page to the cairo context currently
set on the print context for the preview.
void gtk_print_operation_preview_end_preview
(GtkPrintOperationPreview *preview)
Must be called to clean up when the preview is finished.
3) A new way of handling the cairo context associated
with a GtkPrintContext. A print context is no longer
directly associated with a cairo surface. Instead, a
cairo context is set with
void gtk_print_context_set_cairo_context
(GtkPrintContext *context,
cairo_t *cr,
double dpi_x,
double dpi_y);
And this can be repeated, typically in a got-page-size
handler.
The attached patch against current cvs has a
very basic preview implementation in print-editor.c
that demonstrates this api.
Comments appreciated,
Matthias
Index: gtk/Makefile.am
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/Makefile.am,v
retrieving revision 1.308
diff -u -p -r1.308 Makefile.am
--- gtk/Makefile.am 22 May 2006 17:19:09 -0000 1.308
+++ gtk/Makefile.am 1 Jun 2006 20:34:39 -0000
@@ -4,6 +4,7 @@ SUBDIRS=theme-bits
if OS_UNIX
SUBDIRS += xdgmime
+GTK_PRINT_PREVIEW_COMMAND="evince %f"
endif
DIST_SUBDIRS=theme-bits xdgmime
@@ -25,6 +26,7 @@ INCLUDES = \
-DGTK_HOST=\"$(host)\" \
-DGTK_COMPILATION \
-DGTK_PRINT_BACKENDS=\"$(GTK_PRINT_BACKENDS)\" \
+ -DGTK_PRINT_PREVIEW_COMMAND=\"$(GTK_PRINT_PREVIEW_COMMAND)\" \
-I$(top_builddir)/gtk \
-I$(top_srcdir) -I../gdk \
-I$(top_srcdir)/gdk \
@@ -231,6 +233,7 @@ gtk_public_h_sources = \
gtkpreview.h \
gtkprintcontext.h \
gtkprintoperation.h \
+ gtkprintoperationpreview.h \
gtkprintsettings.h \
gtkprivate.h \
gtkprogress.h \
@@ -487,6 +490,7 @@ gtk_c_sources = \
gtkpreview.c \
gtkprintcontext.c \
gtkprintoperation.c \
+ gtkprintoperationpreview.c \
gtkprintsettings.c \
gtkprintutils.c \
gtkprogress.c \
Index: gtk/gtkmarshalers.list
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkmarshalers.list,v
retrieving revision 1.67
diff -u -p -r1.67 gtkmarshalers.list
--- gtk/gtkmarshalers.list 22 May 2006 17:19:09 -0000 1.67
+++ gtk/gtkmarshalers.list 1 Jun 2006 20:34:39 -0000
@@ -32,6 +32,7 @@ BOOLEAN:OBJECT,INT,INT,UINT
BOOLEAN:OBJECT,STRING,STRING,BOXED
BOOLEAN:OBJECT,BOXED
BOOLEAN:OBJECT,BOXED,BOXED
+BOOLEAN:OBJECT,OBJECT,OBJECT
BOOLEAN:OBJECT,STRING,STRING
BOOLEAN:INT
BOOLEAN:INT,INT
Index: gtk/gtkprintbackend.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintbackend.c,v
retrieving revision 1.7
diff -u -p -r1.7 gtkprintbackend.c
--- gtk/gtkprintbackend.c 1 Jun 2006 05:02:56 -0000 1.7
+++ gtk/gtkprintbackend.c 1 Jun 2006 20:34:39 -0000
@@ -200,7 +200,6 @@ _gtk_print_backend_create (const char *b
GtkPrintBackendModule *pb_module;
GtkPrintBackend *pb;
- /* TODO: make module loading code work */
for (l = loaded_backends; l != NULL; l = l->next)
{
pb_module = l->data;
@@ -255,6 +254,11 @@ gtk_print_backend_initialize (void)
GTK_PRINT_BACKENDS,
GTK_PARAM_READWRITE));
+ gtk_settings_install_property (g_param_spec_string ("gtk-print-preview-command",
+ P_("Default command to run when displaying a print preview"),
+ P_("Command to run when displaying a print preview"),
+ GTK_PRINT_PREVIEW_COMMAND,
+ GTK_PARAM_READWRITE));
initialized = TRUE;
}
}
Index: gtk/gtkprintbackend.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintbackend.h,v
retrieving revision 1.8
diff -u -p -r1.8 gtkprintbackend.h
--- gtk/gtkprintbackend.h 24 May 2006 10:50:56 -0000 1.8
+++ gtk/gtkprintbackend.h 1 Jun 2006 20:34:39 -0000
@@ -140,6 +140,9 @@ void gtk_print_backend_print_stre
GList * gtk_print_backend_load_modules (void);
void gtk_print_backend_destroy (GtkPrintBackend *print_backend);
+/* Methods private to gtk */
+GtkPrintBackend * _gtk_print_backend_create (const char *backend_name);
+
/* Backend-only functions for GtkPrintBackend */
void gtk_print_backend_add_printer (GtkPrintBackend *print_backend,
Index: gtk/gtkprintcontext.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintcontext.c,v
retrieving revision 1.4
diff -u -p -r1.4 gtkprintcontext.c
--- gtk/gtkprintcontext.c 31 May 2006 13:38:10 -0000 1.4
+++ gtk/gtkprintcontext.c 1 Jun 2006 20:34:39 -0000
@@ -40,6 +40,9 @@ struct _GtkPrintContext
GtkPageSetup *page_setup;
PangoFontMap *fontmap;
+ gdouble surface_dpi_x;
+ gdouble surface_dpi_y;
+
gdouble pixels_per_unit_x;
gdouble pixels_per_unit_y;
};
@@ -60,8 +63,8 @@ gtk_print_context_finalize (GObject *obj
if (context->page_setup)
g_object_unref (context->page_setup);
- cairo_destroy (context->cr);
-
+ if (context->cr)
+ cairo_destroy (context->cr);
G_OBJECT_CLASS (gtk_print_context_parent_class)->finalize (object);
}
@@ -83,15 +86,31 @@ gtk_print_context_class_init (GtkPrintCo
GtkPrintContext *
_gtk_print_context_new (GtkPrintOperation *op)
{
- GtkPrintOperationPrivate *priv = op->priv;
GtkPrintContext *context;
context = g_object_new (GTK_TYPE_PRINT_CONTEXT, NULL);
context->op = op;
- context->cr = cairo_create (priv->surface);
+ context->cr = NULL;
+ context->fontmap = pango_cairo_font_map_new ();
+
+ return context;
+}
+
+void
+gtk_print_context_set_cairo_context (GtkPrintContext *context,
+ cairo_t *cr,
+ double dpi_x,
+ double dpi_y)
+{
+ if (context->cr)
+ cairo_destroy (context->cr);
+
+ context->cr = cairo_reference (cr);
+ context->surface_dpi_x = dpi_x;
+ context->surface_dpi_y = dpi_y;
- switch (priv->unit)
+ switch (context->op->priv->unit)
{
default:
case GTK_UNIT_PIXEL:
@@ -100,34 +119,31 @@ _gtk_print_context_new (GtkPrintOperatio
context->pixels_per_unit_y = 1.0;
break;
case GTK_UNIT_POINTS:
- context->pixels_per_unit_x = priv->dpi_x / POINTS_PER_INCH;
- context->pixels_per_unit_y = priv->dpi_y / POINTS_PER_INCH;
+ context->pixels_per_unit_x = dpi_x / POINTS_PER_INCH;
+ context->pixels_per_unit_y = dpi_y / POINTS_PER_INCH;
break;
case GTK_UNIT_INCH:
- context->pixels_per_unit_x = priv->dpi_x;
- context->pixels_per_unit_y = priv->dpi_y;
+ context->pixels_per_unit_x = dpi_x;
+ context->pixels_per_unit_y = dpi_y;
break;
case GTK_UNIT_MM:
- context->pixels_per_unit_x = priv->dpi_x / MM_PER_INCH;
- context->pixels_per_unit_y = priv->dpi_y / MM_PER_INCH;
+ context->pixels_per_unit_x = dpi_x / MM_PER_INCH;
+ context->pixels_per_unit_y = dpi_y / MM_PER_INCH;
break;
}
cairo_scale (context->cr,
context->pixels_per_unit_x,
context->pixels_per_unit_y);
- context->fontmap = pango_cairo_font_map_new ();
/* We use the unit-scaled resolution, as we still want fonts given in points to work */
pango_cairo_font_map_set_resolution (PANGO_CAIRO_FONT_MAP (context->fontmap),
- priv->dpi_y / context->pixels_per_unit_y);
-
- return context;
+ dpi_y / context->pixels_per_unit_y);
}
+
void
_gtk_print_context_rotate_according_to_orientation (GtkPrintContext *context)
{
- GtkPrintOperationPrivate *priv = context->op->priv;
cairo_t *cr = context->cr;
cairo_matrix_t matrix;
GtkPaperSize *paper_size;
@@ -136,9 +152,9 @@ _gtk_print_context_rotate_according_to_o
paper_size = gtk_page_setup_get_paper_size (context->page_setup);
width = gtk_paper_size_get_width (paper_size, GTK_UNIT_INCH);
- width = width * priv->dpi_x / context->pixels_per_unit_x;
+ width = width * context->surface_dpi_x / context->pixels_per_unit_x;
height = gtk_paper_size_get_height (paper_size, GTK_UNIT_INCH);
- height = height * priv->dpi_y / context->pixels_per_unit_y;
+ height = height * context->surface_dpi_y / context->pixels_per_unit_y;
switch (gtk_page_setup_get_orientation (context->page_setup))
{
@@ -188,8 +204,8 @@ _gtk_print_context_translate_into_margin
top = gtk_page_setup_get_top_margin (context->page_setup, GTK_UNIT_INCH);
cairo_translate (context->cr,
- left * priv->dpi_x / context->pixels_per_unit_x,
- top * priv->dpi_y / context->pixels_per_unit_y);
+ left * context->surface_dpi_x / context->pixels_per_unit_x,
+ top * context->surface_dpi_y / context->pixels_per_unit_y);
}
void
@@ -272,7 +288,7 @@ gtk_print_context_get_width (GtkPrintCon
width = gtk_page_setup_get_page_width (context->page_setup, GTK_UNIT_INCH);
/* Really dpi_x? What about landscape? what does dpi_x mean in that case? */
- return width * priv->dpi_x / context->pixels_per_unit_x;
+ return width * context->surface_dpi_x / context->pixels_per_unit_x;
}
/**
@@ -300,8 +316,8 @@ gtk_print_context_get_height (GtkPrintCo
else
height = gtk_page_setup_get_page_height (context->page_setup, GTK_UNIT_INCH);
- /* Really dpi_x? What about landscape? what does dpi_x mean in that case? */
- return height * priv->dpi_y / context->pixels_per_unit_y;
+ /* Really dpi_y? What about landscape? what does dpi_y mean in that case? */
+ return height * context->surface_dpi_y / context->pixels_per_unit_y;
}
/**
@@ -320,7 +336,7 @@ gtk_print_context_get_dpi_x (GtkPrintCon
{
g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
- return context->op->priv->dpi_x;
+ return context->surface_dpi_x;
}
/**
@@ -339,7 +355,7 @@ gtk_print_context_get_dpi_y (GtkPrintCon
{
g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
- return context->op->priv->dpi_y;
+ return context->surface_dpi_y;
}
/**
@@ -376,10 +392,16 @@ PangoContext *
gtk_print_context_create_pango_context (GtkPrintContext *context)
{
PangoContext *pango_context;
+ cairo_font_options_t *options;
g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
pango_context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (context->fontmap));
+
+ options = cairo_font_options_create ();
+ cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
+ pango_cairo_context_set_font_options (pango_context, options);
+ cairo_font_options_destroy (options);
return pango_context;
}
Index: gtk/gtkprintcontext.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintcontext.h,v
retrieving revision 1.3
diff -u -p -r1.3 gtkprintcontext.h
--- gtk/gtkprintcontext.h 31 May 2006 13:38:10 -0000 1.3
+++ gtk/gtkprintcontext.h 1 Jun 2006 20:34:39 -0000
@@ -51,6 +51,11 @@ PangoFontMap *gtk_print_context_get_pang
PangoContext *gtk_print_context_create_pango_context (GtkPrintContext *context);
PangoLayout *gtk_print_context_create_pango_layout (GtkPrintContext *context);
+/* Needed for preview implementations */
+void gtk_print_context_set_cairo_context (GtkPrintContext *context,
+ cairo_t *cr,
+ double dpi_x,
+ double dpi_y);
G_END_DECLS
Index: gtk/gtkprintjob.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintjob.c,v
retrieving revision 1.8
diff -u -p -r1.8 gtkprintjob.c
--- gtk/gtkprintjob.c 16 May 2006 16:13:48 -0000 1.8
+++ gtk/gtkprintjob.c 1 Jun 2006 20:34:39 -0000
@@ -212,14 +212,14 @@ gtk_print_job_constructor (GType
job = GTK_PRINT_JOB (object);
priv = job->priv;
- g_assert (priv->printer_set &&
- priv->settings_set &&
+ g_assert (priv->settings_set &&
priv->page_setup_set);
-
- _gtk_printer_prepare_for_print (priv->printer,
- job,
- priv->settings,
- priv->page_setup);
+
+ if (priv->printer)
+ _gtk_printer_prepare_for_print (priv->printer,
+ job,
+ priv->settings,
+ priv->page_setup);
return object;
}
@@ -545,8 +545,12 @@ gtk_print_job_set_property (GObject
case GTK_PRINT_JOB_PROP_PRINTER:
priv->printer = GTK_PRINTER (g_value_dup_object (value));
- priv->printer_set = TRUE;
- priv->backend = g_object_ref (gtk_printer_get_backend (priv->printer));
+
+ if (priv->printer != NULL)
+ {
+ priv->printer_set = TRUE;
+ priv->backend = g_object_ref (gtk_printer_get_backend (priv->printer));
+ }
break;
case GTK_PRINT_JOB_PROP_PAGE_SETUP:
Index: gtk/gtkprintoperation-private.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintoperation-private.h,v
retrieving revision 1.11
diff -u -p -r1.11 gtkprintoperation-private.h
--- gtk/gtkprintoperation-private.h 1 Jun 2006 12:38:07 -0000 1.11
+++ gtk/gtkprintoperation-private.h 1 Jun 2006 20:34:39 -0000
@@ -46,9 +46,11 @@ struct _GtkPrintOperationPrivate
guint print_pages_idle_id;
guint show_progress_timeout_id;
+ GtkPrintContext *print_context;
+
/* Data for the print job: */
- cairo_surface_t *surface;
- gdouble dpi_x, dpi_y;
+ /* cairo_surface_t *surface; */
+ /* gdouble dpi_x, dpi_y; */
GtkPrintPages print_pages;
GtkPageRange *page_ranges;
@@ -84,11 +86,23 @@ GtkPrintOperationResult _gtk_print_opera
GError **error);
typedef void (* GtkPrintOperationPrintFunc) (GtkPrintOperation *op,
- GtkWindow *parent);
+ GtkWindow *parent,
+ gboolean is_preview);
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,
+ GtkWindow *parent,
+ const char *filename);
+
+cairo_surface_t *_gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *operation,
+ gdouble width,
+ gdouble heigh,
+ gdouble *dpi_x,
+ gdouble *dpi_y,
+ const gchar *target);
void _gtk_print_operation_set_status (GtkPrintOperation *op,
GtkPrintStatus status,
Index: gtk/gtkprintoperation-unix.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintoperation-unix.c,v
retrieving revision 1.19
diff -u -p -r1.19 gtkprintoperation-unix.c
--- gtk/gtkprintoperation-unix.c 1 Jun 2006 12:38:07 -0000 1.19
+++ gtk/gtkprintoperation-unix.c 1 Jun 2006 20:34:39 -0000
@@ -25,6 +25,9 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
#include "gtkprintoperation-private.h"
#include "gtkmarshal.h"
@@ -41,13 +44,17 @@
#include "gtkalias.h"
#include "gtkintl.h"
-
typedef struct {
- GtkPrintJob *job; /* the job we are sending to the printer */
- gulong job_status_changed_tag;
GtkWindow *parent; /* just in case we need to throw error dialogs */
GMainLoop *loop;
gboolean data_sent;
+
+ /* Real printing (not preview: */
+ GtkPrintJob *job; /* the job we are sending to the printer */
+ cairo_surface_t *surface;
+ gulong job_status_changed_tag;
+
+
} GtkPrintOperationUnix;
typedef struct _PrinterFinder PrinterFinder;
@@ -62,21 +69,24 @@ unix_start_page (GtkPrintOperation *op,
GtkPrintContext *print_context,
GtkPageSetup *page_setup)
{
+ GtkPrintOperationUnix *op_unix;
GtkPaperSize *paper_size;
cairo_surface_type_t type;
double w, h;
+ op_unix = op->priv->platform_data;
+
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);
- type = cairo_surface_get_type (op->priv->surface);
+ type = cairo_surface_get_type (op_unix->surface);
if (type == CAIRO_SURFACE_TYPE_PS)
- cairo_ps_surface_set_size (op->priv->surface, w, h);
+ cairo_ps_surface_set_size (op_unix->surface, w, h);
else if (type == CAIRO_SURFACE_TYPE_PDF)
- cairo_pdf_surface_set_size (op->priv->surface, w, h);
+ cairo_pdf_surface_set_size (op_unix->surface, w, h);
}
static void
@@ -102,6 +112,112 @@ op_unix_free (GtkPrintOperationUnix *op_
g_free (op_unix);
}
+static char *
+shell_command_substitute_file (const gchar *cmd,
+ const gchar *filename)
+{
+ const char *inptr, *start;
+ char *result;
+ GString *final;
+
+ g_return_val_if_fail (cmd != NULL, NULL);
+ g_return_val_if_fail (filename != NULL, NULL);
+
+ result = NULL;
+ final = g_string_new (NULL);
+
+ start = inptr = cmd;
+
+ while ((inptr = strchr (inptr, '%')) != NULL)
+ {
+ g_string_append_len (final, start, inptr - start);
+ inptr++;
+ switch (*inptr)
+ {
+ case 'f':
+ g_string_append (final, filename ? filename : "");
+ break;
+
+ case '%':
+ g_string_append_c (final, '%');
+ break;
+
+ default:
+ g_string_append_c (final, '%');
+ if (*inptr)
+ g_string_append_c (final, *inptr);
+ break;
+ }
+ if (*inptr)
+ inptr++;
+ start = inptr;
+ }
+ g_string_append (final, start);
+
+ result = final->str;
+
+ g_string_free (final, FALSE);
+
+ return result;
+}
+
+void
+_gtk_print_operation_platform_backend_launch_preview (GtkPrintOperation *op,
+ GtkWindow *parent,
+ const char *filename)
+{
+ int argc;
+ gchar **argv;
+ gchar *cmd;
+ gchar *preview_cmd;
+ GtkSettings *settings;
+ gchar *quoted_filename;
+ GdkScreen *screen;
+ GError *error = NULL;
+
+ settings = gtk_settings_get_default ();
+ g_object_get (settings, "gtk-print-preview-command", &preview_cmd, NULL);
+
+ quoted_filename = g_shell_quote (filename);
+ cmd = shell_command_substitute_file (preview_cmd, quoted_filename);
+ g_shell_parse_argv (cmd, &argc, &argv, &error);
+
+ if (error !=NULL)
+ goto out;
+
+ if (parent)
+ screen = gtk_window_get_screen (parent);
+ else
+ screen = gdk_screen_get_default ();
+
+ gdk_spawn_on_screen (screen, NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error);
+
+ out:
+ if (error != NULL)
+ {
+ GtkWidget *edialog;
+ edialog = gtk_message_dialog_new (parent,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ _("Error launching preview") /* FIXME better text */);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (edialog),
+ "%s", error->message);
+ gtk_window_set_modal (GTK_WINDOW (edialog), TRUE);
+ g_signal_connect (edialog, "response",
+ G_CALLBACK (gtk_widget_destroy), NULL);
+
+ gtk_window_present (GTK_WINDOW (edialog));
+
+ g_error_free (error);
+ }
+
+ g_free (cmd);
+ g_free (quoted_filename);
+ g_free (preview_cmd);
+ g_strfreev (argv);
+}
+
static void
unix_finish_send (GtkPrintJob *job,
void *user_data,
@@ -129,6 +245,7 @@ unix_finish_send (GtkPrintJob *job,
}
op_unix->data_sent = TRUE;
+
if (op_unix->loop)
g_main_loop_quit (op_unix->loop);
}
@@ -140,6 +257,8 @@ unix_end_run (GtkPrintOperation *op,
{
GtkPrintOperationUnix *op_unix = op->priv->platform_data;
+ cairo_surface_finish (op_unix->surface);
+
if (cancelled)
return;
@@ -147,10 +266,11 @@ unix_end_run (GtkPrintOperation *op,
op_unix->loop = g_main_loop_new (NULL, FALSE);
/* TODO: Check for error */
- gtk_print_job_send (op_unix->job,
- unix_finish_send,
- op_unix, NULL,
- NULL);
+ if (op_unix->job != NULL)
+ gtk_print_job_send (op_unix->job,
+ unix_finish_send,
+ op_unix, NULL,
+ NULL);
if (wait)
{
@@ -253,64 +373,66 @@ finish_print (PrintResponseData *rdata,
{
GtkPrintOperation *op = rdata->op;
GtkPrintOperationPrivate *priv = op->priv;
+ gboolean is_preview;
- priv->start_page = unix_start_page;
- priv->end_page = unix_end_page;
- priv->end_run = unix_end_run;
+ g_print ("finish_print\n");
+
+ is_preview = rdata->result == GTK_PRINT_OPERATION_RESULT_PREVIEW;
if (rdata->do_print)
{
- GtkPrintOperationUnix *op_unix;
-
gtk_print_operation_set_print_settings (op, settings);
-
- op_unix = g_new0 (GtkPrintOperationUnix, 1);
- op_unix->job = gtk_print_job_new (priv->job_name,
- printer,
- settings,
- page_setup);
+ op->priv->print_context = _gtk_print_context_new (op);
- gtk_print_job_set_track_print_status (op_unix->job, priv->track_print_status);
-
- rdata->op->priv->surface = gtk_print_job_get_surface (op_unix->job, rdata->error);
- if (op->priv->surface == NULL)
+ if (!is_preview)
{
- rdata->do_print = FALSE;
- op_unix_free (op_unix);
- rdata->result = GTK_PRINT_OPERATION_RESULT_ERROR;
- goto out;
- }
-
- _gtk_print_operation_set_status (op, gtk_print_job_get_status (op_unix->job), NULL);
- op_unix->job_status_changed_tag =
- g_signal_connect (op_unix->job, "status-changed",
- G_CALLBACK (job_status_changed_cb), op);
-
- op_unix->parent = rdata->parent;
-
- priv->dpi_x = 72;
- priv->dpi_y = 72;
-
- priv->platform_data = op_unix;
- priv->free_platform_data = (GDestroyNotify) op_unix_free;
-
- priv->print_pages = op_unix->job->print_pages;
- priv->page_ranges = op_unix->job->page_ranges;
- priv->num_page_ranges = op_unix->job->num_page_ranges;
-
- priv->manual_num_copies = op_unix->job->num_copies;
- priv->manual_collation = op_unix->job->collate;
- priv->manual_reverse = op_unix->job->reverse;
- priv->manual_page_set = op_unix->job->page_set;
- priv->manual_scale = op_unix->job->scale;
- priv->manual_orientation = op_unix->job->rotate_to_orientation;
+ GtkPrintOperationUnix *op_unix;
+ cairo_t *cr;
+
+ op_unix = g_new0 (GtkPrintOperationUnix, 1);
+ priv->platform_data = op_unix;
+ priv->free_platform_data = (GDestroyNotify) op_unix_free;
+ op_unix->parent = rdata->parent;
+
+ priv->start_page = unix_start_page;
+ priv->end_page = unix_end_page;
+ priv->end_run = unix_end_run;
+
+ op_unix->job = gtk_print_job_new (priv->job_name,
+ printer,
+ settings,
+ page_setup);
+ gtk_print_job_set_track_print_status (op_unix->job, priv->track_print_status);
+ /* TODO: handle error */
+ op_unix->surface = gtk_print_job_get_surface (op_unix->job, rdata->error);
+ cr = cairo_create (op_unix->surface);
+ gtk_print_context_set_cairo_context (op->priv->print_context,
+ cr, 72, 72);
+ cairo_destroy (cr);
+
+ _gtk_print_operation_set_status (op, gtk_print_job_get_status (op_unix->job), NULL);
+
+ op_unix->job_status_changed_tag =
+ g_signal_connect (op_unix->job, "status-changed",
+ G_CALLBACK (job_status_changed_cb), op);
+
+ priv->print_pages = op_unix->job->print_pages;
+ priv->page_ranges = op_unix->job->page_ranges;
+ priv->num_page_ranges = op_unix->job->num_page_ranges;
+
+ priv->manual_num_copies = op_unix->job->num_copies;
+ priv->manual_collation = op_unix->job->collate;
+ priv->manual_reverse = op_unix->job->reverse;
+ priv->manual_page_set = op_unix->job->page_set;
+ priv->manual_scale = op_unix->job->scale;
+ priv->manual_orientation = op_unix->job->rotate_to_orientation;
+ }
}
-
- out:
+
if (rdata->print_cb)
{
if (rdata->do_print)
- rdata->print_cb (op, rdata->parent);
+ rdata->print_cb (op, rdata->parent, is_preview);
else
_gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL);
}
@@ -319,7 +441,7 @@ finish_print (PrintResponseData *rdata,
rdata->destroy (rdata);
}
-static void
+static void
handle_print_response (GtkWidget *dialog,
gint response,
gpointer data)
@@ -330,6 +452,8 @@ handle_print_response (GtkWidget *dialog
GtkPageSetup *page_setup = NULL;
GtkPrinter *printer = NULL;
+ g_print ("handle_print_response\n");
+
if (response == GTK_RESPONSE_OK)
{
rdata->result = GTK_PRINT_OPERATION_RESULT_APPLY;
@@ -345,14 +469,24 @@ handle_print_response (GtkWidget *dialog
g_signal_emit_by_name (rdata->op, "custom-widget-apply", rdata->op->priv->custom_widget);
}
+ else if (response == GTK_RESPONSE_APPLY)
+ {
+ /* print preview */
+ rdata->result = GTK_PRINT_OPERATION_RESULT_PREVIEW;
+ rdata->do_print = TRUE;
+ settings = gtk_print_unix_dialog_get_settings (GTK_PRINT_UNIX_DIALOG (pd));
+ page_setup = gtk_print_unix_dialog_get_page_setup (GTK_PRINT_UNIX_DIALOG (pd));
+ }
+
out:
finish_print (rdata, printer, page_setup, settings);
if (settings)
g_object_unref (settings);
-
+
gtk_widget_destroy (GTK_WIDGET (pd));
+
}
@@ -436,6 +570,19 @@ _gtk_print_operation_platform_backend_ru
}
}
+cairo_surface_t *
+_gtk_print_operation_platform_backend_create_preview_surface (GtkPrintOperation *op,
+ gdouble width,
+ gdouble height,
+ gdouble *dpi_x,
+ gdouble *dpi_y,
+ const gchar *target)
+{
+ g_print ("pdf surface size: %f x %f\n", width, height);
+ *dpi_x = *dpi_y = 72;
+ return cairo_pdf_surface_create (target, width, height);
+}
+
GtkPrintOperationResult
_gtk_print_operation_platform_backend_run_dialog (GtkPrintOperation *op,
GtkWindow *parent,
@@ -459,6 +606,7 @@ _gtk_print_operation_platform_backend_ru
if (op->priv->show_dialog)
{
pd = get_print_dialog (op, parent);
+
response = gtk_dialog_run (GTK_DIALOG (pd));
handle_print_response (pd, response, &rdata);
}
Index: gtk/gtkprintoperation-win32.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintoperation-win32.c,v
retrieving revision 1.9
diff -u -p -r1.9 gtkprintoperation-win32.c
--- gtk/gtkprintoperation-win32.c 23 May 2006 16:30:45 -0000 1.9
+++ gtk/gtkprintoperation-win32.c 1 Jun 2006 20:34:39 -0000
@@ -492,6 +492,7 @@ 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;
Index: gtk/gtkprintoperation.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintoperation.c,v
retrieving revision 1.24
diff -u -p -r1.24 gtkprintoperation.c
--- gtk/gtkprintoperation.c 1 Jun 2006 12:38:07 -0000 1.24
+++ gtk/gtkprintoperation.c 1 Jun 2006 20:34:39 -0000
@@ -19,6 +19,10 @@
*/
#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+
#include <string.h>
#include "gtkprintoperation-private.h"
#include "gtkmarshalers.h"
@@ -41,6 +45,7 @@ enum {
STATUS_CHANGED,
CREATE_CUSTOM_WIDGET,
CUSTOM_WIDGET_APPLY,
+ PREVIEW,
LAST_SIGNAL
};
@@ -65,7 +70,15 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
static int job_nr = 0;
-G_DEFINE_TYPE (GtkPrintOperation, gtk_print_operation, G_TYPE_OBJECT)
+static void preview_iface_init (GtkPrintOperationPreviewIface *iface);
+static GtkPageSetup *create_page_setup (GtkPrintOperation *op);
+static void common_render_page (GtkPrintOperation *op,
+ gint page_nr);
+
+
+G_DEFINE_TYPE_WITH_CODE (GtkPrintOperation, gtk_print_operation, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GTK_TYPE_PRINT_OPERATION_PREVIEW,
+ preview_iface_init))
/**
* gtk_print_error_quark:
@@ -146,6 +159,60 @@ gtk_print_operation_init (GtkPrintOperat
}
static void
+preview_iface_render_page (GtkPrintOperationPreview *preview,
+ gint page_nr)
+{
+ GtkPrintOperation *op;
+
+ op = GTK_PRINT_OPERATION (preview);
+ common_render_page (op, page_nr);
+}
+
+static void
+preview_iface_end_preview (GtkPrintOperationPreview *preview)
+{
+ GtkPrintOperation *op;
+
+ op = GTK_PRINT_OPERATION (preview);
+
+ g_signal_emit (op, signals[END_PRINT], 0, op->priv->print_context);
+
+ if (op->priv->rloop)
+ g_main_loop_quit (op->priv->rloop);
+
+ op->priv->end_run (op, op->priv->is_sync, TRUE);
+}
+
+static void
+preview_iface_init (GtkPrintOperationPreviewIface *iface)
+{
+ iface->render_page = preview_iface_render_page;
+ iface->end_preview = preview_iface_end_preview;
+}
+
+static void
+preview_start_page (GtkPrintOperation *op,
+ GtkPrintContext *print_context,
+ GtkPageSetup *page_setup)
+{
+ g_signal_emit_by_name (op, "got-page-size",print_context, page_setup);
+}
+
+static void
+preview_end_page (GtkPrintOperation *op,
+ GtkPrintContext *print_context)
+{
+}
+
+static void
+preview_end_run (GtkPrintOperation *op,
+ gboolean wait,
+ gboolean cancelled)
+{
+}
+
+
+static void
gtk_print_operation_set_property (GObject *object,
guint prop_id,
const GValue *value,
@@ -256,6 +323,158 @@ gtk_print_operation_get_property (GObjec
}
}
+typedef struct
+{
+ GtkPrintOperationPreview *preview;
+ GtkPrintContext *print_context;
+ GtkWindow *parent;
+ cairo_surface_t *surface;
+ gchar *filename;
+ guint page_nr;
+ gboolean wait;
+} PreviewOp;
+
+static void
+preview_print_idle_done (gpointer data)
+{
+ GtkPrintOperation *op;
+ PreviewOp *pop = (PreviewOp *) data;
+
+ op = GTK_PRINT_OPERATION (pop->preview);
+
+ _gtk_print_operation_platform_backend_launch_preview (op,
+ 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);
+}
+
+static gboolean
+preview_print_idle (gpointer data)
+{
+ PreviewOp *pop;
+ GtkPrintOperation *op;
+ gboolean retval = TRUE;
+ cairo_t *cr;
+
+ GDK_THREADS_ENTER ();
+
+ pop = (PreviewOp *) data;
+ op = GTK_PRINT_OPERATION (pop->preview);
+
+ 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);
+
+ /* TODO: print out sheets not pages and follow ranges */
+ pop->page_nr++;
+ if (op->priv->nr_of_pages <= pop->page_nr)
+ retval = FALSE;
+
+ GDK_THREADS_LEAVE ();
+
+ return retval;
+}
+
+static void
+preview_got_page_size (GtkPrintOperationPreview *preview,
+ GtkPrintContext *context,
+ GtkPageSetup *page_setup,
+ PreviewOp *pop)
+{
+ GtkPrintOperation *op = GTK_PRINT_OPERATION (preview);
+ GtkPaperSize *paper_size;
+ double w, h;
+
+ 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);
+
+ /* TODO: don't hardcode pdf */
+ cairo_pdf_surface_set_size (pop->surface, w, h);
+}
+
+static void
+preview_ready (GtkPrintOperationPreview *preview,
+ GtkPrintContext *context,
+ PreviewOp *pop)
+{
+
+ pop->page_nr = 0;
+ pop->print_context = context;
+
+ g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
+ preview_print_idle,
+ pop,
+ preview_print_idle_done);
+
+}
+
+/**
+ * gtk_print_operation_preview_handler:
+ *
+ * Default handler for preview operations
+ **/
+static gboolean
+gtk_print_operation_preview_handler (GtkPrintOperation *op,
+ GtkPrintOperationPreview *preview,
+ GtkPrintContext *context,
+ GtkWindow *parent)
+{
+ gdouble width, height, dpi_x, dpi_y;
+ gchar *tmp_dir;
+ gchar *dir_template;
+ gchar *preview_filename;
+ PreviewOp *pop;
+ GtkPrintSettings *settings;
+ 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 extentions
+ to determine the mine 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->preview = preview;
+ pop->parent = parent;
+
+ settings = op->priv->print_settings;
+
+ width = gtk_print_settings_get_paper_width (settings, GTK_UNIT_POINTS);
+ height = gtk_print_settings_get_paper_height (settings, GTK_UNIT_POINTS);
+
+ pop->surface =
+ _gtk_print_operation_platform_backend_create_preview_surface (op,
+ width, height,
+ &dpi_x, &dpi_y,
+ pop->filename);
+
+ cr = cairo_create (pop->surface);
+ gtk_print_context_set_cairo_context (op->priv->print_context, cr,
+ dpi_x, dpi_y);
+ cairo_destroy (cr);
+
+ g_signal_connect (preview, "ready", (GCallback) preview_ready, pop);
+ g_signal_connect (preview, "got-page-size", (GCallback) preview_got_page_size, pop);
+
+ return TRUE;
+}
+
static GtkWidget *
gtk_print_operation_create_custom_widget (GtkPrintOperation *operation)
{
@@ -287,7 +506,8 @@ gtk_print_operation_class_init (GtkPrint
gobject_class->set_property = gtk_print_operation_set_property;
gobject_class->get_property = gtk_print_operation_get_property;
gobject_class->finalize = gtk_print_operation_finalize;
-
+
+ class->preview = gtk_print_operation_preview_handler;
class->create_custom_widget = gtk_print_operation_create_custom_widget;
g_type_class_add_private (gobject_class, sizeof (GtkPrintOperationPrivate));
@@ -530,6 +750,33 @@ gtk_print_operation_class_init (GtkPrint
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
+ /**
+ * GtkPrintOperation::preview:
+ * @operation: the #GtkPrintOperation on which the signal was emitted
+ * @preview: the #GtkPrintPreviewOperation for the current operation
+ * @context: the #GtkPrintContext that will be used
+ * @parent: the #GtkWindow to use as window parent, or NULL
+ *
+ * Gets emitted when a preview is requested from the native dialog.
+ * If you handle this you must set the cairo_context on the printing context.
+ *
+ * Returns: #TRUE if the listener wants to take over control of the preview
+ *
+ * Since: 2.10
+ */
+ signals[PREVIEW] =
+ g_signal_new (I_("preview"),
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkPrintOperationClass, preview),
+ _gtk_boolean_handled_accumulator, NULL,
+ _gtk_marshal_BOOLEAN__OBJECT_OBJECT_OBJECT,
+ G_TYPE_BOOLEAN, 3,
+ GTK_TYPE_PRINT_OPERATION_PREVIEW,
+ GTK_TYPE_PRINT_CONTEXT,
+ GTK_TYPE_WINDOW);
+
+
/**
* GtkPrintOperation:default-page-setup:
*
@@ -1436,6 +1683,7 @@ pdf_start_page (GtkPrintOperation *op,
GtkPageSetup *page_setup)
{
GtkPaperSize *paper_size;
+ cairo_surface_t *surface = op->priv->platform_data;
double w, h;
paper_size = gtk_page_setup_get_paper_size (page_setup);
@@ -1443,7 +1691,7 @@ pdf_start_page (GtkPrintOperation *op,
w = gtk_paper_size_get_width (paper_size, GTK_UNIT_POINTS);
h = gtk_paper_size_get_height (paper_size, GTK_UNIT_POINTS);
- cairo_pdf_surface_set_size (op->priv->surface, w, h);
+ cairo_pdf_surface_set_size (surface, w, h);
}
static void
@@ -1462,9 +1710,10 @@ pdf_end_run (GtkPrintOperation *op,
gboolean cancelled)
{
GtkPrintOperationPrivate *priv = op->priv;
+ cairo_surface_t *surface = priv->platform_data;
- cairo_surface_destroy (priv->surface);
- priv->surface = NULL;
+ cairo_surface_finish (surface);
+ cairo_surface_destroy (surface);
}
static GtkPrintOperationResult
@@ -1475,6 +1724,8 @@ run_pdf (GtkPrintOperation *op,
{
GtkPrintOperationPrivate *priv = op->priv;
GtkPageSetup *page_setup;
+ cairo_surface_t *surface;
+ cairo_t *cr;
double width, height;
/* This will be overwritten later by the non-default size, but
we need to pass some size: */
@@ -1484,13 +1735,19 @@ run_pdf (GtkPrintOperation *op,
height = gtk_page_setup_get_paper_height (page_setup, GTK_UNIT_POINTS);
g_object_unref (page_setup);
- priv->surface = cairo_pdf_surface_create (priv->pdf_target,
+ surface = cairo_pdf_surface_create (priv->pdf_target,
width, height);
- cairo_pdf_surface_set_dpi (priv->surface, 300, 300);
-
- priv->dpi_x = 72;
- priv->dpi_y = 72;
+ cairo_pdf_surface_set_dpi (surface, 300, 300);
+
+ priv->platform_data = surface;
+ priv->free_platform_data = (GDestroyNotify) cairo_surface_destroy;
+ cr = cairo_create (surface);
+ gtk_print_context_set_cairo_context (op->priv->print_context,
+ cr, 72, 72);
+ cairo_destroy (cr);
+
+
priv->print_pages = GTK_PRINT_PAGES_ALL;
priv->page_ranges = NULL;
priv->num_page_ranges = 0;
@@ -1524,10 +1781,11 @@ typedef struct
gint page, start, end, inc;
- GtkPageSetup *initial_page_setup;
- GtkPrintContext *print_context;
+ gboolean initialized;
GtkWidget *progress;
+
+ gboolean is_preview;
} PrintPagesData;
static void
@@ -1599,12 +1857,9 @@ print_pages_idle_done (gpointer user_dat
if (data->progress)
gtk_widget_destroy (data->progress);
- g_object_unref (data->print_context);
- g_object_unref (data->initial_page_setup);
-
g_object_unref (data->op);
- if (priv->rloop)
+ if (priv->rloop && !data->is_preview)
g_main_loop_quit (priv->rloop);
g_free (data);
@@ -1640,15 +1895,62 @@ update_progress (PrintPagesData *data)
}
}
+static void
+common_render_page (GtkPrintOperation *op,
+ gint page_nr)
+{
+ GtkPrintOperationPrivate *priv = op->priv;
+ GtkPageSetup *page_setup;
+ GtkPrintContext *print_context;
+ cairo_t *cr;
+
+ print_context = priv->print_context;
+
+ page_setup = create_page_setup (op);
+
+ g_signal_emit (op, signals[REQUEST_PAGE_SETUP], 0,
+ print_context, page_nr, page_setup);
+
+ _gtk_print_context_set_page_setup (print_context, page_setup);
+
+ /* TODO: override for preview */
+ priv->start_page (op, print_context, page_setup);
+
+ cr = gtk_print_context_get_cairo_context (print_context);
+
+ cairo_save (cr);
+ if (priv->manual_scale != 1.0)
+ cairo_scale (cr,
+ priv->manual_scale,
+ priv->manual_scale);
+
+ if (priv->manual_orientation)
+ _gtk_print_context_rotate_according_to_orientation (print_context);
+
+ if (!priv->use_full_page)
+ _gtk_print_context_translate_into_margin (print_context);
+
+ g_signal_emit (op, signals[DRAW_PAGE], 0,
+ print_context, page_nr);
+
+ /* TODO: override for preview */
+ priv->end_page (op, print_context);
+
+ cairo_restore (cr);
+
+ g_object_unref (page_setup);
+}
+
static gboolean
print_pages_idle (gpointer user_data)
{
PrintPagesData *data;
GtkPrintOperationPrivate *priv;
GtkPageSetup *page_setup;
- cairo_t *cr;
gboolean done = FALSE;
+ g_print ("print_pages_idle\n");
+
GDK_THREADS_ENTER ();
data = (PrintPagesData*)user_data;
@@ -1656,15 +1958,15 @@ print_pages_idle (gpointer user_data)
if (priv->status == GTK_PRINT_STATUS_PREPARING)
{
- if (!data->print_context)
+ if (!data->initialized)
{
- data->print_context = _gtk_print_context_new (data->op);
- data->initial_page_setup = create_page_setup (data->op);
-
- _gtk_print_context_set_page_setup (data->print_context,
- data->initial_page_setup);
+ data->initialized = TRUE;
+ page_setup = create_page_setup (data->op);
+ _gtk_print_context_set_page_setup (priv->print_context,
+ page_setup);
+ g_object_unref (page_setup);
- g_signal_emit (data->op, signals[BEGIN_PRINT], 0, data->print_context);
+ g_signal_emit (data->op, signals[BEGIN_PRINT], 0, priv->print_context);
if (priv->manual_collation)
{
@@ -1684,7 +1986,7 @@ print_pages_idle (gpointer user_data)
{
gboolean paginated = FALSE;
- g_signal_emit (data->op, signals[PAGINATE], 0, data->print_context, &paginated);
+ g_signal_emit (data->op, signals[PAGINATE], 0, priv->print_context, &paginated);
if (!paginated)
goto out;
}
@@ -1751,36 +2053,18 @@ print_pages_idle (gpointer user_data)
goto out;
}
}
+
+ if (data->is_preview)
+ {
+ done = TRUE;
- page_setup = gtk_page_setup_copy (data->initial_page_setup);
- g_signal_emit (data->op, signals[REQUEST_PAGE_SETUP], 0,
- data->print_context, data->page, page_setup);
-
- _gtk_print_context_set_page_setup (data->print_context, page_setup);
- priv->start_page (data->op, data->print_context, page_setup);
-
- cr = gtk_print_context_get_cairo_context (data->print_context);
-
- cairo_save (cr);
- if (priv->manual_scale != 1.0)
- cairo_scale (cr,
- priv->manual_scale,
- priv->manual_scale);
-
- if (priv->manual_orientation)
- _gtk_print_context_rotate_according_to_orientation (data->print_context);
-
- if (!priv->use_full_page)
- _gtk_print_context_translate_into_margin (data->print_context);
-
- g_signal_emit (data->op, signals[DRAW_PAGE], 0,
- data->print_context, data->page);
-
- priv->end_page (data->op, data->print_context);
-
- cairo_restore (cr);
-
- g_object_unref (page_setup);
+ g_object_ref (data->op);
+
+ g_signal_emit_by_name (data->op, "ready", priv->print_context);
+ goto out;
+ }
+
+ common_render_page (data->op, data->page);
out:
@@ -1791,11 +2075,9 @@ print_pages_idle (gpointer user_data)
done = TRUE;
}
- if (done)
+ if (done && !data->is_preview)
{
- g_signal_emit (data->op, signals[END_PRINT], 0, data->print_context);
-
- cairo_surface_finish (priv->surface);
+ g_signal_emit (data->op, signals[END_PRINT], 0, priv->print_context);
priv->end_run (data->op, priv->is_sync, priv->cancelled);
}
@@ -1833,15 +2115,19 @@ show_progress_timeout (PrintPagesData *d
static void
print_pages (GtkPrintOperation *op,
- GtkWindow *parent)
+ GtkWindow *parent,
+ gboolean is_preview)
{
GtkPrintOperationPrivate *priv = op->priv;
PrintPagesData *data;
-
+
+ g_print ("print_pages\n");
+
_gtk_print_operation_set_status (op, GTK_PRINT_STATUS_PREPARING, NULL);
data = g_new0 (PrintPagesData, 1);
data->op = g_object_ref (op);
+ data->is_preview = is_preview;
if (priv->show_progress)
{
@@ -1862,6 +2148,37 @@ print_pages (GtkPrintOperation *op,
data->progress = progress;
}
+ if (is_preview)
+ {
+ gboolean handled;
+
+ g_signal_emit_by_name (op, "preview",
+ GTK_PRINT_OPERATION_PREVIEW (op),
+ op->priv->print_context,
+ parent,
+ &handled);
+
+ if (!handled ||
+ gtk_print_context_get_cairo_context (priv->print_context) == NULL) {
+ /* TODO: handle error */
+ }
+
+ priv->start_page = preview_start_page;
+ priv->end_page = preview_end_page;
+ priv->end_run = preview_end_run;
+
+ /* TODO: Do we really need to set these? */
+ priv->print_pages = GTK_PRINT_PAGES_ALL;
+ priv->page_ranges = NULL;
+ priv->num_page_ranges = 0;
+ priv->manual_num_copies = 1;
+ priv->manual_collation = FALSE;
+ priv->manual_reverse = FALSE;
+ priv->manual_page_set = GTK_PAGE_SET_ALL;
+ priv->manual_scale = 1.0;
+ priv->manual_orientation = TRUE;
+ }
+
priv->print_pages_idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
print_pages_idle,
data,
@@ -1877,9 +2194,10 @@ print_pages (GtkPrintOperation *op,
GDK_THREADS_LEAVE ();
g_main_loop_run (priv->rloop);
GDK_THREADS_ENTER ();
+
+ g_main_loop_unref (priv->rloop);
+ priv->rloop = NULL;
}
- g_main_loop_unref (priv->rloop);
- priv->rloop = NULL;
}
/**
@@ -1964,7 +2282,7 @@ gtk_print_operation_run (GtkPrintOperati
&do_print,
error);
if (do_print)
- print_pages (op, parent);
+ print_pages (op, parent, result == GTK_PRINT_OPERATION_RESULT_PREVIEW);
else
_gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL);
@@ -2006,7 +2324,7 @@ gtk_print_operation_run_async (GtkPrintO
{
run_pdf (op, parent, &do_print, NULL);
if (do_print)
- print_pages (op, parent);
+ print_pages (op, parent, FALSE);
else
_gtk_print_operation_set_status (op, GTK_PRINT_STATUS_FINISHED_ABORTED, NULL);
}
Index: gtk/gtkprintoperation.h
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintoperation.h,v
retrieving revision 1.10
diff -u -p -r1.10 gtkprintoperation.h
--- gtk/gtkprintoperation.h 24 May 2006 16:15:14 -0000 1.10
+++ gtk/gtkprintoperation.h 1 Jun 2006 20:34:39 -0000
@@ -29,6 +29,7 @@
#include "gtkpagesetup.h"
#include "gtkprintsettings.h"
#include "gtkprintcontext.h"
+#include "gtkprintoperationpreview.h"
G_BEGIN_DECLS
@@ -84,7 +85,13 @@ struct _GtkPrintOperationClass
GtkWidget *(*create_custom_widget) (GtkPrintOperation *operation);
void (*custom_widget_apply) (GtkPrintOperation *operation,
GtkWidget *widget);
+
+ gboolean (*preview) (GtkPrintOperation *operation,
+ GtkPrintOperationPreview *preview,
+ GtkPrintContext *context,
+ GtkWindow *parent);
+
/* Padding for future expansion */
void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
@@ -98,7 +105,8 @@ struct _GtkPrintOperationClass
typedef enum {
GTK_PRINT_OPERATION_RESULT_ERROR,
GTK_PRINT_OPERATION_RESULT_APPLY,
- GTK_PRINT_OPERATION_RESULT_CANCEL
+ GTK_PRINT_OPERATION_RESULT_CANCEL,
+ GTK_PRINT_OPERATION_RESULT_PREVIEW
} GtkPrintOperationResult;
#define GTK_PRINT_ERROR gtk_print_error_quark ()
Index: gtk/gtkprintoperationpreview.c
===================================================================
RCS file: gtk/gtkprintoperationpreview.c
diff -N gtk/gtkprintoperationpreview.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gtk/gtkprintoperationpreview.c 1 Jun 2006 20:34:39 -0000
@@ -0,0 +1,107 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintoperationpreview.c: Abstract print preview interface
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gtkprintoperationpreview.h"
+#include "gtkmarshalers.h"
+#include "gtkintl.h"
+
+static void gtk_print_operation_preview_base_init (gpointer g_iface);
+
+GType
+gtk_print_operation_preview_get_type (void)
+{
+ static GType print_operation_preview_type = 0;
+
+ if (!print_operation_preview_type)
+ {
+ static const GTypeInfo print_operation_preview_info =
+ {
+ sizeof (GtkPrintOperationPreviewIface), /* class_size */
+ gtk_print_operation_preview_base_init, /* base_init */
+ NULL, /* base_finalize */
+ NULL,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL
+ };
+
+ print_operation_preview_type =
+ g_type_register_static (G_TYPE_INTERFACE, I_("GtkPrintOperationPreview"),
+ &print_operation_preview_info, 0);
+
+ g_type_interface_add_prerequisite (print_operation_preview_type, G_TYPE_OBJECT);
+ }
+
+ return print_operation_preview_type;
+}
+
+static void
+gtk_print_operation_preview_base_init (gpointer g_iface)
+{
+ static gboolean initialized = FALSE;
+
+ if (!initialized)
+ {
+ g_signal_new (I_("ready"),
+ GTK_TYPE_PRINT_OPERATION_PREVIEW,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkPrintOperationPreviewIface, ready),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ G_TYPE_OBJECT);
+
+ g_signal_new (I_("got-page-size"),
+ GTK_TYPE_PRINT_OPERATION_PREVIEW,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkPrintOperationPreviewIface, ready),
+ NULL, NULL,
+ _gtk_marshal_VOID__OBJECT_OBJECT,
+ G_TYPE_NONE, 2,
+ GTK_TYPE_PRINT_CONTEXT,
+ GTK_TYPE_PAGE_SETUP);
+
+ initialized = TRUE;
+ }
+}
+
+
+void
+gtk_print_operation_preview_render_page (GtkPrintOperationPreview *preview,
+ gint page_nr)
+{
+ g_return_if_fail (GTK_IS_PRINT_OPERATION_PREVIEW (preview));
+
+ GTK_PRINT_OPERATION_PREVIEW_GET_IFACE (preview)->render_page (preview,
+ page_nr);
+}
+
+void
+gtk_print_operation_preview_end_preview (GtkPrintOperationPreview *preview)
+{
+ g_return_if_fail (GTK_IS_PRINT_OPERATION_PREVIEW (preview));
+
+ GTK_PRINT_OPERATION_PREVIEW_GET_IFACE (preview)->end_preview (preview);
+}
+
Index: gtk/gtkprintoperationpreview.h
===================================================================
RCS file: gtk/gtkprintoperationpreview.h
diff -N gtk/gtkprintoperationpreview.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gtk/gtkprintoperationpreview.h 1 Jun 2006 20:34:39 -0000
@@ -0,0 +1,75 @@
+/* GTK - The GIMP Toolkit
+ * gtkprintoperationpreview.h: Abstract print preview interface
+ * Copyright (C) 2006, Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GTK_PRINT_OPERATION_PREVIEW_H__
+#define __GTK_PRINT_OPERATION_PREVIEW_H__
+
+#include <glib-object.h>
+#include <cairo.h>
+
+#include "gtkprintcontext.h"
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_PRINT_OPERATION_PREVIEW (gtk_print_operation_preview_get_type ())
+#define GTK_PRINT_OPERATION_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_PRINT_OPERATION_PREVIEW, GtkPrintOperationPreview))
+#define GTK_IS_PRINT_OPERATION_PREVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_PRINT_OPERATION_PREVIEW))
+#define GTK_PRINT_OPERATION_PREVIEW_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GTK_TYPE_PRINT_OPERATION_PREVIEW, GtkPrintOperationPreviewIface))
+
+typedef struct _GtkPrintOperationPreview GtkPrintOperationPreview; /*dummy typedef */
+typedef struct _GtkPrintOperationPreviewIface GtkPrintOperationPreviewIface;
+
+
+struct _GtkPrintOperationPreviewIface
+{
+ GTypeInterface g_iface;
+
+ /* signals */
+ void (*ready) (GtkPrintOperationPreview *preview,
+ GtkPrintContext *context);
+ void (*got_page_size) (GtkPrintOperationPreview *preview,
+ GtkPrintContext *context,
+ GtkPageSetup *page_setup);
+
+ /* methods */
+ void (*render_page) (GtkPrintOperationPreview *preview,
+ gint page_nr);
+ void (*end_preview) (GtkPrintOperationPreview *preview);
+
+ /* Padding for future expansion */
+ void (*_gtk_reserved1) (void);
+ void (*_gtk_reserved2) (void);
+ void (*_gtk_reserved3) (void);
+ void (*_gtk_reserved4) (void);
+ void (*_gtk_reserved5) (void);
+ void (*_gtk_reserved6) (void);
+ void (*_gtk_reserved7) (void);
+};
+
+GType gtk_print_operation_preview_get_type (void) G_GNUC_CONST;
+
+void gtk_print_operation_preview_render_page (GtkPrintOperationPreview *preview,
+ gint page_nr);
+void gtk_print_operation_preview_render_sheet (GtkPrintOperationPreview *preview,
+ gint page_nr);
+void gtk_print_operation_preview_end_preview (GtkPrintOperationPreview *preview);
+
+
+#endif /* __GTK_PRINT_OPERATION_PREVIEW_H__ */
Index: gtk/gtkprintunixdialog.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkprintunixdialog.c,v
retrieving revision 1.22
diff -u -p -r1.22 gtkprintunixdialog.c
--- gtk/gtkprintunixdialog.c 1 Jun 2006 04:58:18 -0000 1.22
+++ gtk/gtkprintunixdialog.c 1 Jun 2006 20:34:39 -0000
@@ -275,7 +275,8 @@ gtk_print_unix_dialog_init (GtkPrintUnix
(GCallback) gtk_print_unix_dialog_destroy,
NULL);
- gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+ GTK_STOCK_PRINT_PREVIEW, GTK_RESPONSE_APPLY,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_PRINT, GTK_RESPONSE_OK,
NULL);
Index: tests/print-editor.c
===================================================================
RCS file: /cvs/gnome/gtk+/tests/print-editor.c,v
retrieving revision 1.7
diff -u -p -r1.7 print-editor.c
--- tests/print-editor.c 31 May 2006 14:06:02 -0000 1.7
+++ tests/print-editor.c 1 Jun 2006 20:34:39 -0000
@@ -262,6 +262,7 @@ begin_print (GtkPrintOperation *operatio
int num_lines;
int line;
+ g_print ("begin-print\n");
width = gtk_print_context_get_width (context);
height = gtk_print_context_get_height (context);
@@ -304,6 +305,7 @@ begin_print (GtkPrintOperation *operatio
print_data->page_breaks = page_breaks;
+ g_print ("found %d pages\n", g_list_length (page_breaks));
}
static void
@@ -317,6 +319,9 @@ draw_page (GtkPrintOperation *operation,
int start, end, i;
PangoLayoutIter *iter;
double start_pos;
+
+ g_print ("draw-page %d\n", page_nr);
+
if (page_nr == 0)
start = 0;
else
@@ -430,17 +435,205 @@ custom_widget_apply (GtkPrintOperation *
data->font = g_strdup (selected_font);
}
+typedef struct
+{
+ GtkPrintOperation *op;
+ GtkPrintOperationPreview *preview;
+ GtkWidget *spin;
+ GtkWidget *area;
+ gint page;
+ PrintData *data;
+ gdouble dpi_x, dpi_y;
+} PreviewOp;
+
+static gboolean
+preview_expose (GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer data)
+{
+ PreviewOp *pop = data;
+
+ gdk_window_clear (pop->area->window);
+ gtk_print_operation_preview_render_page (pop->preview,
+ pop->page - 1);
+
+ return TRUE;
+}
+
+static void
+preview_ready (GtkPrintOperationPreview *preview,
+ GtkPrintContext *context,
+ gpointer data)
+{
+ PreviewOp *pop = data;
+ gint n_pages;
+
+ g_object_get (pop->op, "n-pages", &n_pages, NULL);
+ g_print ("ready to preview %d pages\n", n_pages);
+
+ gtk_spin_button_set_range (GTK_SPIN_BUTTON (pop->spin),
+ 1.0, n_pages);
+
+ g_signal_connect (pop->area, "expose_event",
+ G_CALLBACK (preview_expose),
+ pop);
+
+ gtk_widget_queue_draw (pop->area);
+}
+
+static void
+preview_got_page_size (GtkPrintOperationPreview *preview,
+ GtkPrintContext *context,
+ GtkPageSetup *page_setup,
+ gpointer data)
+{
+ PreviewOp *pop = data;
+ GtkPaperSize *paper_size;
+ double w, h;
+ cairo_t *cr;
+ gdouble dpi_x, dpi_y;
+
+ paper_size = gtk_page_setup_get_paper_size (page_setup);
+
+ w = gtk_paper_size_get_width (paper_size, GTK_UNIT_INCH);
+ h = gtk_paper_size_get_height (paper_size, GTK_UNIT_INCH);
+
+ cr = gdk_cairo_create (pop->area->window);
+
+ dpi_x = pop->area->allocation.width/w;
+ dpi_y = pop->area->allocation.height/h;
+
+ g_print ("new dpi: %f, %f\n", dpi_x, dpi_y);
+ if (fabs (dpi_x - pop->dpi_x) > 0.001 ||
+ fabs (dpi_y - pop->dpi_y) > 0.001)
+ {
+ gtk_print_context_set_cairo_context (context, cr, dpi_x, dpi_y);
+ pop->dpi_x = dpi_x;
+ pop->dpi_y = dpi_y;
+ }
+
+ pango_cairo_update_layout (cr, pop->data->layout);
+ cairo_destroy (cr);
+}
+
+static void
+update_page (GtkSpinButton *widget,
+ gpointer data)
+{
+ PreviewOp *pop = data;
+
+ pop->page = gtk_spin_button_get_value_as_int (widget);
+ g_print ("go to page %d\n", pop->page);
+ gtk_widget_queue_draw (pop->area);
+}
+
+static void
+preview_destroy (GtkWindow *window,
+ PreviewOp *pop)
+{
+ gtk_print_operation_preview_end_preview (pop->preview);
+ g_object_unref (pop->op);
+
+ g_free (pop);
+}
+
+static gboolean
+do_preview (GtkPrintOperation *op,
+ GtkPrintOperationPreview *preview,
+ GtkPrintContext *context,
+ GtkWindow *parent,
+ gpointer data)
+{
+ GtkPrintSettings *settings;
+ GtkWidget *window, *close, *page, *hbox, *vbox, *da;
+ gdouble width, height;
+ cairo_t *cr;
+ PreviewOp *pop;
+ PrintData *print_data = data;
+
+ pop = g_new0 (PreviewOp, 1);
+
+ pop->data = print_data;
+ settings = gtk_print_operation_get_print_settings (op);
+
+#if 0
+ /* FIXME need to figure out the size */
+ width = gtk_print_settings_get_paper_width (settings, GTK_UNIT_PIXEL);
+ height = gtk_print_settings_get_paper_height (settings, GTK_UNIT_PIXEL);
+
+ g_print ("%f x %f\n", width, height);
+#endif
+ width = 200;
+ height = 300;
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_transient_for (GTK_WINDOW (window),
+ GTK_WINDOW (main_window));
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox,
+ FALSE, FALSE, 0);
+ page = gtk_spin_button_new_with_range (1, 100, 1);
+ gtk_box_pack_start (GTK_BOX (hbox), page, FALSE, FALSE, 0);
+
+ close = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
+ gtk_box_pack_start (GTK_BOX (hbox), close, FALSE, FALSE, 0);
+
+ da = gtk_drawing_area_new ();
+ gtk_widget_set_size_request (GTK_WIDGET (da), width, height);
+ gtk_box_pack_start (GTK_BOX (vbox), da, TRUE, TRUE, 0);
+
+ gtk_widget_set_double_buffered (da, FALSE);
+
+ gtk_widget_realize (da);
+
+ cr = gdk_cairo_create (da->window);
+
+ /* TODO: What dpi to use here? This will be used for pagination.. */
+ gtk_print_context_set_cairo_context (context, cr, 72, 72);
+ cairo_destroy (cr);
+
+ pop->op = op;
+ pop->preview = preview;
+ pop->spin = page;
+ pop->area = da;
+ pop->page = 1;
+
+ g_signal_connect (page, "value-changed",
+ G_CALLBACK (update_page), pop);
+ g_signal_connect_swapped (close, "clicked",
+ G_CALLBACK (gtk_widget_destroy), window);
+
+ g_signal_connect (preview, "ready",
+ G_CALLBACK (preview_ready), pop);
+ g_signal_connect (preview, "got-page-size",
+ G_CALLBACK (preview_got_page_size), pop);
+
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (preview_destroy), pop);
+
+ gtk_widget_show_all (window);
+
+ return TRUE;
+}
+
+/* FIXME had to move this to the heap, since previewing
+ * returns too early from the sync api
+ */
+PrintData *print_data;
+
static void
do_print (GtkAction *action)
{
GtkWidget *error_dialog;
GtkPrintOperation *print;
- PrintData print_data;
GtkPrintOperationResult res;
GError *error;
- print_data.text = get_text ();
- print_data.font = g_strdup ("Sans 12");
+ print_data = g_new0 (PrintData, 1);
+
+ print_data->text = get_text ();
+ print_data->font = g_strdup ("Sans 12");
print = gtk_print_operation_new ();
@@ -452,12 +645,15 @@ do_print (GtkAction *action)
if (page_setup != NULL)
gtk_print_operation_set_default_page_setup (print, page_setup);
- g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), &print_data);
- g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), &print_data);
- g_signal_connect (print, "create_custom_widget", G_CALLBACK (create_custom_widget), &print_data);
- g_signal_connect (print, "custom_widget_apply", G_CALLBACK (custom_widget_apply), &print_data);
-
+ g_signal_connect (print, "begin_print", G_CALLBACK (begin_print), print_data);
+ g_signal_connect (print, "draw_page", G_CALLBACK (draw_page), print_data);
+ g_signal_connect (print, "create_custom_widget", G_CALLBACK (create_custom_widget), print_data);
+ g_signal_connect (print, "custom_widget_apply", G_CALLBACK (custom_widget_apply), print_data);
+ g_signal_connect (print, "preview", G_CALLBACK (do_preview), print_data);
+
error = NULL;
+
+#if 1
res = gtk_print_operation_run (print, GTK_WINDOW (main_window), &error);
if (res == GTK_PRINT_OPERATION_RESULT_ERROR)
@@ -467,7 +663,7 @@ do_print (GtkAction *action)
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"Error printing file:\n%s",
- error->message);
+ error ? error->message : "no details");
g_signal_connect (error_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (error_dialog);
g_error_free (error);
@@ -489,10 +685,15 @@ do_print (GtkAction *action)
g_signal_connect (print, "status_changed",
G_CALLBACK (status_changed_cb), NULL);
}
+#else
+ gtk_print_operation_run_async (print, GTK_WINDOW (main_window));
+#endif
g_object_unref (print);
+#if 0
g_free (print_data.text);
g_free (print_data.font);
+#endif
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]