]> Pileus Git - ~andy/gtk/blob - gtk/gtkprintcontext.c
[GI] Add missing (transfer) annotations
[~andy/gtk] / gtk / gtkprintcontext.c
1 /* GTK - The GIMP Toolkit
2  * gtkprintcontext.c: Print Context
3  * Copyright (C) 2006, Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22 #include "gtkprintoperation-private.h"
23
24 typedef struct _GtkPrintContextClass GtkPrintContextClass;
25
26 #define GTK_IS_PRINT_CONTEXT_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_PRINT_CONTEXT))
27 #define GTK_PRINT_CONTEXT_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_PRINT_CONTEXT, GtkPrintContextClass))
28 #define GTK_PRINT_CONTEXT_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_PRINT_CONTEXT, GtkPrintContextClass))
29
30 #define MM_PER_INCH 25.4
31 #define POINTS_PER_INCH 72
32
33 struct _GtkPrintContext
34 {
35   GObject parent_instance;
36
37   GtkPrintOperation *op;
38   cairo_t *cr;
39   GtkPageSetup *page_setup;
40
41   gdouble surface_dpi_x;
42   gdouble surface_dpi_y;
43   
44   gdouble pixels_per_unit_x;
45   gdouble pixels_per_unit_y;
46
47   gboolean has_hard_margins;
48   gdouble hard_margin_top;
49   gdouble hard_margin_bottom;
50   gdouble hard_margin_left;
51   gdouble hard_margin_right;
52
53 };
54
55 struct _GtkPrintContextClass
56 {
57   GObjectClass parent_class;
58 };
59
60 G_DEFINE_TYPE (GtkPrintContext, gtk_print_context, G_TYPE_OBJECT)
61
62 static void
63 gtk_print_context_finalize (GObject *object)
64 {
65   GtkPrintContext *context = GTK_PRINT_CONTEXT (object);
66
67   if (context->page_setup)
68     g_object_unref (context->page_setup);
69
70   if (context->cr)
71     cairo_destroy (context->cr);
72   
73   G_OBJECT_CLASS (gtk_print_context_parent_class)->finalize (object);
74 }
75
76 static void
77 gtk_print_context_init (GtkPrintContext *context)
78 {
79 }
80
81 static void
82 gtk_print_context_class_init (GtkPrintContextClass *class)
83 {
84   GObjectClass *gobject_class = (GObjectClass *)class;
85
86   gobject_class->finalize = gtk_print_context_finalize;
87 }
88
89
90 GtkPrintContext *
91 _gtk_print_context_new (GtkPrintOperation *op)
92 {
93   GtkPrintContext *context;
94
95   context = g_object_new (GTK_TYPE_PRINT_CONTEXT, NULL);
96
97   context->op = op;
98   context->cr = NULL;
99   context->has_hard_margins = FALSE;
100   
101   return context;
102 }
103
104 static PangoFontMap *
105 _gtk_print_context_get_fontmap (GtkPrintContext *context)
106 {
107   return pango_cairo_font_map_get_default ();
108 }
109
110 /**
111  * gtk_print_context_set_cairo_context:
112  * @context: a #GtkPrintContext
113  * @cr: the cairo context
114  * @dpi_x: the horizontal resolution to use with @cr
115  * @dpi_y: the vertical resolution to use with @cr
116  *
117  * Sets a new cairo context on a print context. 
118  * 
119  * This function is intended to be used when implementing
120  * an internal print preview, it is not needed for printing,
121  * since GTK+ itself creates a suitable cairo context in that
122  * case.
123  *
124  * Since: 2.10 
125  */
126 void
127 gtk_print_context_set_cairo_context (GtkPrintContext *context,
128                                      cairo_t         *cr,
129                                      double           dpi_x,
130                                      double           dpi_y)
131 {
132   if (context->cr)
133     cairo_destroy (context->cr);
134
135   context->cr = cairo_reference (cr);
136   context->surface_dpi_x = dpi_x;
137   context->surface_dpi_y = dpi_y;
138
139   switch (context->op->priv->unit)
140     {
141     default:
142     case GTK_UNIT_PIXEL:
143       /* Do nothing, this is the cairo default unit */
144       context->pixels_per_unit_x = 1.0;
145       context->pixels_per_unit_y = 1.0;
146       break;
147     case GTK_UNIT_POINTS:
148       context->pixels_per_unit_x = dpi_x / POINTS_PER_INCH;
149       context->pixels_per_unit_y = dpi_y / POINTS_PER_INCH;
150       break;
151     case GTK_UNIT_INCH:
152       context->pixels_per_unit_x = dpi_x;
153       context->pixels_per_unit_y = dpi_y;
154       break;
155     case GTK_UNIT_MM:
156       context->pixels_per_unit_x = dpi_x / MM_PER_INCH;
157       context->pixels_per_unit_y = dpi_y / MM_PER_INCH;
158       break;
159     }
160   cairo_scale (context->cr,
161                context->pixels_per_unit_x,
162                context->pixels_per_unit_y);
163 }
164
165
166 void
167 _gtk_print_context_rotate_according_to_orientation (GtkPrintContext *context)
168 {
169   cairo_t *cr = context->cr;
170   cairo_matrix_t matrix;
171   GtkPaperSize *paper_size;
172   gdouble width, height;
173
174   paper_size = gtk_page_setup_get_paper_size (context->page_setup);
175
176   width = gtk_paper_size_get_width (paper_size, GTK_UNIT_INCH);
177   width = width * context->surface_dpi_x / context->pixels_per_unit_x;
178   height = gtk_paper_size_get_height (paper_size, GTK_UNIT_INCH);
179   height = height * context->surface_dpi_y / context->pixels_per_unit_y;
180   
181   switch (gtk_page_setup_get_orientation (context->page_setup))
182     {
183     default:
184     case GTK_PAGE_ORIENTATION_PORTRAIT:
185       break;
186     case GTK_PAGE_ORIENTATION_LANDSCAPE:
187       cairo_translate (cr, 0, height);
188       cairo_matrix_init (&matrix,
189                          0, -1,
190                          1,  0,
191                          0,  0);
192       cairo_transform (cr, &matrix);
193       break;
194     case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
195       cairo_translate (cr, width, height);
196       cairo_matrix_init (&matrix,
197                          -1,  0,
198                           0, -1,
199                           0,  0);
200       cairo_transform (cr, &matrix);
201       break;
202     case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
203       cairo_translate (cr, width, 0);
204       cairo_matrix_init (&matrix,
205                           0,  1,
206                          -1,  0,
207                           0,  0);
208       cairo_transform (cr, &matrix);
209       break;
210     }
211 }
212
213 void
214 _gtk_print_context_translate_into_margin (GtkPrintContext *context)
215 {
216   GtkPrintOperationPrivate *priv;
217   gdouble left, top;
218
219   g_return_if_fail (GTK_IS_PRINT_CONTEXT (context));
220
221   priv = context->op->priv;
222
223   /* We do it this way to also handle GTK_UNIT_PIXELS */
224   
225   left = gtk_page_setup_get_left_margin (context->page_setup, GTK_UNIT_INCH);
226   top = gtk_page_setup_get_top_margin (context->page_setup, GTK_UNIT_INCH);
227
228   cairo_translate (context->cr,
229                    left * context->surface_dpi_x / context->pixels_per_unit_x,
230                    top * context->surface_dpi_y / context->pixels_per_unit_y);
231 }
232
233 void
234 _gtk_print_context_set_page_setup (GtkPrintContext *context,
235                                    GtkPageSetup    *page_setup)
236 {
237   g_return_if_fail (GTK_IS_PRINT_CONTEXT (context));
238   g_return_if_fail (page_setup == NULL ||
239                     GTK_IS_PAGE_SETUP (page_setup));
240   
241   g_object_ref (page_setup);
242
243   if (context->page_setup != NULL)
244     g_object_unref (context->page_setup);
245
246   context->page_setup = page_setup;
247 }
248
249 /**
250  * gtk_print_context_get_cairo_context:
251  * @context: a #GtkPrintContext
252  *
253  * Obtains the cairo context that is associated with the
254  * #GtkPrintContext.
255  *
256  * Return value: (transfer none): the cairo context of @context
257  *
258  * Since: 2.10
259  */
260 cairo_t *
261 gtk_print_context_get_cairo_context (GtkPrintContext *context)
262 {
263   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
264
265   return context->cr;
266 }
267
268 /**
269  * gtk_print_context_get_page_setup:
270  * @context: a #GtkPrintContext
271  *
272  * Obtains the #GtkPageSetup that determines the page
273  * dimensions of the #GtkPrintContext.
274  *
275  * Return value: (transfer none): the page setup of @context
276  *
277  * Since: 2.10
278  */
279 GtkPageSetup *
280 gtk_print_context_get_page_setup (GtkPrintContext *context)
281 {
282   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
283
284   return context->page_setup;
285 }
286
287 /**
288  * gtk_print_context_get_width:
289  * @context: a #GtkPrintContext
290  *
291  * Obtains the width of the #GtkPrintContext, in pixels.
292  *
293  * Return value: the width of @context
294  *
295  * Since: 2.10 
296  */
297 gdouble
298 gtk_print_context_get_width (GtkPrintContext *context)
299 {
300   GtkPrintOperationPrivate *priv;
301   gdouble width;
302
303   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
304
305   priv = context->op->priv;
306
307   if (priv->use_full_page)
308     width = gtk_page_setup_get_paper_width (context->page_setup, GTK_UNIT_INCH);
309   else
310     width = gtk_page_setup_get_page_width (context->page_setup, GTK_UNIT_INCH);
311
312   /* Really dpi_x? What about landscape? what does dpi_x mean in that case? */
313   return width * context->surface_dpi_x / context->pixels_per_unit_x;
314 }
315
316 /**
317  * gtk_print_context_get_height:
318  * @context: a #GtkPrintContext
319  * 
320  * Obtains the height of the #GtkPrintContext, in pixels.
321  *
322  * Return value: the height of @context
323  *
324  * Since: 2.10
325  */
326 gdouble
327 gtk_print_context_get_height (GtkPrintContext *context)
328 {
329   GtkPrintOperationPrivate *priv;
330   gdouble height;
331
332   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
333
334   priv = context->op->priv;
335
336   if (priv->use_full_page)
337     height = gtk_page_setup_get_paper_height (context->page_setup, GTK_UNIT_INCH);
338   else
339     height = gtk_page_setup_get_page_height (context->page_setup, GTK_UNIT_INCH);
340
341   /* Really dpi_y? What about landscape? what does dpi_y mean in that case? */
342   return height * context->surface_dpi_y / context->pixels_per_unit_y;
343 }
344
345 /**
346  * gtk_print_context_get_dpi_x:
347  * @context: a #GtkPrintContext
348  * 
349  * Obtains the horizontal resolution of the #GtkPrintContext,
350  * in dots per inch.
351  *
352  * Return value: the horizontal resolution of @context
353  *
354  * Since: 2.10
355  */
356 gdouble
357 gtk_print_context_get_dpi_x (GtkPrintContext *context)
358 {
359   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
360
361   return context->surface_dpi_x;
362 }
363
364 /**
365  * gtk_print_context_get_dpi_y:
366  * @context: a #GtkPrintContext
367  * 
368  * Obtains the vertical resolution of the #GtkPrintContext,
369  * in dots per inch.
370  *
371  * Return value: the vertical resolution of @context
372  *
373  * Since: 2.10
374  */
375 gdouble
376 gtk_print_context_get_dpi_y (GtkPrintContext *context)
377 {
378   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), 0);
379
380   return context->surface_dpi_y;
381 }
382
383 /**
384  * gtk_print_context_get_hard_margins:
385  * @context: a #GtkPrintContext
386  * @top: top hardware printer margin
387  * @bottom: bottom hardware printer margin
388  * @left: left hardware printer margin
389  * @right: right hardware printer margin
390  *
391  * Obtains the hardware printer margins of the #GtkPrintContext, in units.
392  *
393  * Return value: %TRUE if the hard margins were retrieved
394  *
395  * Since: 2.20
396  */
397 gboolean
398 gtk_print_context_get_hard_margins (GtkPrintContext *context,
399                                     gdouble         *top,
400                                     gdouble         *bottom,
401                                     gdouble         *left,
402                                     gdouble         *right)
403 {
404   if (context->has_hard_margins)
405     {
406       *top    = context->hard_margin_top / context->pixels_per_unit_y;
407       *bottom = context->hard_margin_bottom / context->pixels_per_unit_y;
408       *left   = context->hard_margin_left / context->pixels_per_unit_x;
409       *right  = context->hard_margin_right / context->pixels_per_unit_x;
410     }
411
412   return context->has_hard_margins;
413 }
414
415 /**
416  * gtk_print_context_set_hard_margins:
417  * @context: a #GtkPrintContext
418  * @top: top hardware printer margin
419  * @bottom: bottom hardware printer margin
420  * @left: left hardware printer margin
421  * @right: right hardware printer margin
422  *
423  * set the hard margins in pixel coordinates
424  */
425 void
426 _gtk_print_context_set_hard_margins (GtkPrintContext *context,
427                                      gdouble          top,
428                                      gdouble          bottom,
429                                      gdouble          left,
430                                      gdouble          right)
431 {
432   context->hard_margin_top    = top;
433   context->hard_margin_bottom = bottom;
434   context->hard_margin_left   = left;
435   context->hard_margin_right  = right;
436   context->has_hard_margins   = TRUE;
437 }
438
439 /**
440  * gtk_print_context_get_pango_fontmap:
441  * @context: a #GtkPrintContext
442  *
443  * Returns a #PangoFontMap that is suitable for use
444  * with the #GtkPrintContext.
445  *
446  * Return value: (transfer none): the font map of @context
447  *
448  * Since: 2.10
449  */
450 PangoFontMap *
451 gtk_print_context_get_pango_fontmap (GtkPrintContext *context)
452 {
453   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
454
455   return _gtk_print_context_get_fontmap (context);
456 }
457
458 /**
459  * gtk_print_context_create_pango_context:
460  * @context: a #GtkPrintContext
461  *
462  * Creates a new #PangoContext that can be used with the
463  * #GtkPrintContext.
464  *
465  * Return value: (transfer full): a new Pango context for @context
466  * 
467  * Since: 2.10
468  */
469 PangoContext *
470 gtk_print_context_create_pango_context (GtkPrintContext *context)
471 {
472   PangoContext *pango_context;
473   cairo_font_options_t *options;
474
475   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
476   
477   pango_context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (_gtk_print_context_get_fontmap (context)));
478
479   options = cairo_font_options_create ();
480   cairo_font_options_set_hint_metrics (options, CAIRO_HINT_METRICS_OFF);
481   pango_cairo_context_set_font_options (pango_context, options);
482   cairo_font_options_destroy (options);
483   
484   /* We use the unit-scaled resolution, as we still want 
485    * fonts given in points to work 
486    */
487   pango_cairo_context_set_resolution (pango_context,
488                                       context->surface_dpi_y / context->pixels_per_unit_y);
489   return pango_context;
490 }
491
492 /**
493  * gtk_print_context_create_pango_layout:
494  * @context: a #GtkPrintContext
495  *
496  * Creates a new #PangoLayout that is suitable for use
497  * with the #GtkPrintContext.
498  * 
499  * Return value: (transfer full): a new Pango layout for @context
500  *
501  * Since: 2.10
502  */
503 PangoLayout *
504 gtk_print_context_create_pango_layout (GtkPrintContext *context)
505 {
506   PangoContext *pango_context;
507   PangoLayout *layout;
508
509   g_return_val_if_fail (GTK_IS_PRINT_CONTEXT (context), NULL);
510
511   pango_context = gtk_print_context_create_pango_context (context);
512   layout = pango_layout_new (pango_context);
513
514   pango_cairo_update_context (context->cr, pango_context);
515   g_object_unref (pango_context);
516
517   return layout;
518 }