printing.c 5.68 KB
Newer Older
Matthias Clasen's avatar
Matthias Clasen committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* Printing
 *
 * GtkPrintOperation offers a simple API to support printing
 * in a cross-platform way.
 *
 */

#include <math.h>
#include <gtk/gtk.h>
#include "demo-common.h"

/* In points */
#define HEADER_HEIGHT (10*72/25.4)
#define HEADER_GAP (3*72/25.4)

Matthias Clasen's avatar
Matthias Clasen committed
16
typedef struct
Matthias Clasen's avatar
Matthias Clasen committed
17 18 19 20
{
  gchar *filename;
  gdouble font_size;

Matthias Clasen's avatar
Matthias Clasen committed
21
  gint lines_per_page;
Matthias Clasen's avatar
Matthias Clasen committed
22 23 24 25 26 27
  gchar **lines;
  gint num_lines;
  gint num_pages;
} PrintData;

static void
Matthias Clasen's avatar
Matthias Clasen committed
28
begin_print (GtkPrintOperation *operation,
Matthias Clasen's avatar
Matthias Clasen committed
29 30 31 32 33 34 35 36 37
	     GtkPrintContext   *context,
	     gpointer           user_data)
{
  PrintData *data = (PrintData *)user_data;
  char *contents;
  int i;
  double height;

  height = gtk_print_context_get_height (context) - HEADER_HEIGHT - HEADER_GAP;
Matthias Clasen's avatar
Matthias Clasen committed
38

Matthias Clasen's avatar
Matthias Clasen committed
39
  data->lines_per_page = floor (height / data->font_size);
Matthias Clasen's avatar
Matthias Clasen committed
40

Matthias Clasen's avatar
Matthias Clasen committed
41 42 43 44 45 46 47 48
  g_file_get_contents (data->filename, &contents, NULL, NULL);

  data->lines = g_strsplit (contents, "\n", 0);
  g_free (contents);

  i = 0;
  while (data->lines[i] != NULL)
    i++;
Matthias Clasen's avatar
Matthias Clasen committed
49

Matthias Clasen's avatar
Matthias Clasen committed
50 51
  data->num_lines = i;
  data->num_pages = (data->num_lines - 1) / data->lines_per_page + 1;
52

Alexander Larsson's avatar
Alexander Larsson committed
53
  gtk_print_operation_set_n_pages (operation, data->num_pages);
Matthias Clasen's avatar
Matthias Clasen committed
54 55 56 57 58 59 60 61 62 63 64
}

static void
draw_page (GtkPrintOperation *operation,
	   GtkPrintContext   *context,
	   gint               page_nr,
	   gpointer           user_data)
{
  PrintData *data = (PrintData *)user_data;
  cairo_t *cr;
  PangoLayout *layout;
65 66 67
  gint text_width, text_height;
  gdouble width;
  gint line, i;
Matthias Clasen's avatar
Matthias Clasen committed
68 69 70
  PangoFontDescription *desc;
  gchar *page_str;

71
  cr = gtk_print_context_get_cairo_context (context);
Matthias Clasen's avatar
Matthias Clasen committed
72 73 74
  width = gtk_print_context_get_width (context);

  cairo_rectangle (cr, 0, 0, width, HEADER_HEIGHT);
Matthias Clasen's avatar
Matthias Clasen committed
75

Matthias Clasen's avatar
Matthias Clasen committed
76 77
  cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
  cairo_fill_preserve (cr);
Matthias Clasen's avatar
Matthias Clasen committed
78

Matthias Clasen's avatar
Matthias Clasen committed
79 80 81 82
  cairo_set_source_rgb (cr, 0, 0, 0);
  cairo_set_line_width (cr, 1);
  cairo_stroke (cr);

83
  layout = gtk_print_context_create_pango_layout (context);
Matthias Clasen's avatar
Matthias Clasen committed
84 85 86 87 88 89

  desc = pango_font_description_from_string ("sans 14");
  pango_layout_set_font_description (layout, desc);
  pango_font_description_free (desc);

  pango_layout_set_text (layout, data->filename, -1);
90
  pango_layout_get_pixel_size (layout, &text_width, &text_height);
Matthias Clasen's avatar
Matthias Clasen committed
91

92 93 94 95 96 97 98 99
  if (text_width > width)
    {
      pango_layout_set_width (layout, width);
      pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_START);
      pango_layout_get_pixel_size (layout, &text_width, &text_height);
    }

  cairo_move_to (cr, (width - text_width) / 2,  (HEADER_HEIGHT - text_height) / 2);
Matthias Clasen's avatar
Matthias Clasen committed
100 101 102 103 104
  pango_cairo_show_layout (cr, layout);

  page_str = g_strdup_printf ("%d/%d", page_nr + 1, data->num_pages);
  pango_layout_set_text (layout, page_str, -1);
  g_free (page_str);
105 106 107 108

  pango_layout_set_width (layout, -1);
  pango_layout_get_pixel_size (layout, &text_width, &text_height);
  cairo_move_to (cr, width - text_width - 4, (HEADER_HEIGHT - text_height) / 2);
Matthias Clasen's avatar
Matthias Clasen committed
109
  pango_cairo_show_layout (cr, layout);
Matthias Clasen's avatar
Matthias Clasen committed
110

Matthias Clasen's avatar
Matthias Clasen committed
111
  g_object_unref (layout);
Matthias Clasen's avatar
Matthias Clasen committed
112

113
  layout = gtk_print_context_create_pango_layout (context);
Matthias Clasen's avatar
Matthias Clasen committed
114

115
  desc = pango_font_description_from_string ("monospace");
Matthias Clasen's avatar
Matthias Clasen committed
116 117 118
  pango_font_description_set_size (desc, data->font_size * PANGO_SCALE);
  pango_layout_set_font_description (layout, desc);
  pango_font_description_free (desc);
Matthias Clasen's avatar
Matthias Clasen committed
119

Matthias Clasen's avatar
Matthias Clasen committed
120 121
  cairo_move_to (cr, 0, HEADER_HEIGHT + HEADER_GAP);
  line = page_nr * data->lines_per_page;
Matthias Clasen's avatar
Matthias Clasen committed
122
  for (i = 0; i < data->lines_per_page && line < data->num_lines; i++)
Matthias Clasen's avatar
Matthias Clasen committed
123 124 125
    {
      pango_layout_set_text (layout, data->lines[line], -1);
      pango_cairo_show_layout (cr, layout);
Matthias Clasen's avatar
Matthias Clasen committed
126
      cairo_rel_move_to (cr, 0, data->font_size);
Matthias Clasen's avatar
Matthias Clasen committed
127 128 129 130 131 132 133
      line++;
    }

  g_object_unref (layout);
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
134
end_print (GtkPrintOperation *operation,
Matthias Clasen's avatar
Matthias Clasen committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
	   GtkPrintContext   *context,
	   gpointer           user_data)
{
  PrintData *data = (PrintData *)user_data;

  g_free (data->filename);
  g_strfreev (data->lines);
  g_free (data);
}


GtkWidget *
do_printing (GtkWidget *do_widget)
{
  GtkPrintOperation *operation;
150
  GtkPrintSettings *settings;
Matthias Clasen's avatar
Matthias Clasen committed
151
  PrintData *data;
152 153
  gchar *uri, *ext;
  const gchar *dir;
Matthias Clasen's avatar
Matthias Clasen committed
154 155 156 157 158 159 160
  GError *error = NULL;

  operation = gtk_print_operation_new ();
  data = g_new0 (PrintData, 1);
  data->filename = demo_find_file ("printing.c", NULL);
  data->font_size = 12.0;

161
  g_signal_connect (G_OBJECT (operation), "begin-print",
Matthias Clasen's avatar
Matthias Clasen committed
162
		    G_CALLBACK (begin_print), data);
163
  g_signal_connect (G_OBJECT (operation), "draw-page",
Matthias Clasen's avatar
Matthias Clasen committed
164
		    G_CALLBACK (draw_page), data);
165
  g_signal_connect (G_OBJECT (operation), "end-print",
Matthias Clasen's avatar
Matthias Clasen committed
166 167
		    G_CALLBACK (end_print), data);

168 169
  gtk_print_operation_set_use_full_page (operation, FALSE);
  gtk_print_operation_set_unit (operation, GTK_UNIT_POINTS);
170
  gtk_print_operation_set_embed_page_setup (operation, TRUE);
171

172
  settings = gtk_print_settings_new ();
Matthias Clasen's avatar
Matthias Clasen committed
173 174 175 176 177
  dir = g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS);
  if (dir == NULL)
    dir = g_get_home_dir ();
  if (g_strcmp0 (gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT), "ps") == 0)
    ext = ".ps";
178 179
  else if (g_strcmp0 (gtk_print_settings_get (settings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT), "svg") == 0)
    ext = ".svg";
Matthias Clasen's avatar
Matthias Clasen committed
180 181 182 183
  else
    ext = ".pdf";

  uri = g_strconcat ("file://", dir, "/", "gtk-demo", ext, NULL);
184 185 186
  gtk_print_settings_set (settings, GTK_PRINT_SETTINGS_OUTPUT_URI, uri);
  gtk_print_operation_set_print_settings (operation, settings);

187
  gtk_print_operation_run (operation, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, GTK_WINDOW (do_widget), &error);
Matthias Clasen's avatar
Matthias Clasen committed
188 189

  g_object_unref (operation);
190 191
  g_object_unref (settings);
  g_free (uri);
Matthias Clasen's avatar
Matthias Clasen committed
192 193 194 195

  if (error)
    {
      GtkWidget *dialog;
Matthias Clasen's avatar
Matthias Clasen committed
196

Matthias Clasen's avatar
Matthias Clasen committed
197 198 199 200 201 202
      dialog = gtk_message_dialog_new (GTK_WINDOW (do_widget),
				       GTK_DIALOG_DESTROY_WITH_PARENT,
				       GTK_MESSAGE_ERROR,
				       GTK_BUTTONS_CLOSE,
				       "%s", error->message);
      g_error_free (error);
Matthias Clasen's avatar
Matthias Clasen committed
203

Matthias Clasen's avatar
Matthias Clasen committed
204 205
      g_signal_connect (dialog, "response",
			G_CALLBACK (gtk_widget_destroy), NULL);
Matthias Clasen's avatar
Matthias Clasen committed
206 207

      gtk_widget_show (dialog);
Matthias Clasen's avatar
Matthias Clasen committed
208
    }
Matthias Clasen's avatar
Matthias Clasen committed
209

Matthias Clasen's avatar
Matthias Clasen committed
210 211 212

  return NULL;
}