Add support for GTK print, modified from patch 1782055
[wxWidgets.git] / src / gtk / print.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: wx/gtk/print.cpp
3 // Author: Anthony Bretaudeau
4 // Purpose: GTK printing support
5 // Created: 2007-08-25
6 // RCS-ID: $Id: print.cpp,v 1 2007-08-25 05:44:44 PC Exp $
7 // Copyright: (c) 2007 wxWidgets development team
8 // Licence: wxWindows Licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #if wxUSE_GTKPRINT
19
20 #include "wx/gtk/print.h"
21
22 #ifndef WX_PRECOMP
23 #include "wx/log.h"
24 #include "wx/dcmemory.h"
25 #include "wx/icon.h"
26 #include "wx/math.h"
27 #include "wx/image.h"
28 #include "wx/module.h"
29 #endif
30
31 #include "wx/fontutil.h"
32 #include "wx/gtk/private.h"
33 #include "wx/dynlib.h"
34 #include "wx/paper.h"
35 #include "wx/rawbmp.h"
36
37 #include <gtk/gtk.h>
38 #include <gtk/gtkpagesetupunixdialog.h>
39
40 #include "wx/link.h"
41 wxFORCE_LINK_THIS_MODULE(gtk_print)
42
43 #if wxUSE_LIBGNOMEPRINT
44 #include "wx/gtk/gnome/gprint.h"
45 #endif
46
47 // Usefull to convert angles from/to Rad to/from Deg.
48 static const double RAD2DEG = 180.0 / M_PI;
49 static const double DEG2RAD = M_PI / 180.0;
50
51 //----------------------------------------------------------------------------
52 // wxGtkPrintModule
53 // Initialized when starting the app : if it successfully load the gtk-print framework,
54 // it uses it. If not, it falls back to gnome print (see /gtk/gnome/gprint.cpp) then
55 // to postscript if gnomeprint is not available.
56 //----------------------------------------------------------------------------
57
58 class wxGtkPrintModule: public wxModule
59 {
60 public:
61 wxGtkPrintModule()
62 {
63 #if wxUSE_LIBGNOMEPRINT
64 // This module must be initialized AFTER gnomeprint's one
65 AddDependency(CLASSINFO(wxGnomePrintModule));
66 #endif
67 }
68 bool OnInit();
69 void OnExit();
70
71 private:
72 DECLARE_DYNAMIC_CLASS(wxGtkPrintModule)
73 };
74
75 bool wxGtkPrintModule::OnInit()
76 {
77 if (gtk_check_version(2,10,0) == NULL)
78 wxPrintFactory::SetPrintFactory( new wxGtkPrintFactory );
79
80 return true;
81 }
82
83 void wxGtkPrintModule::OnExit()
84 {
85 }
86
87 IMPLEMENT_DYNAMIC_CLASS(wxGtkPrintModule, wxModule)
88
89
90 //----------------------------------------------------------------------------
91 // wxGtkPrintFactory
92 //----------------------------------------------------------------------------
93
94 wxPrinterBase* wxGtkPrintFactory::CreatePrinter( wxPrintDialogData *data )
95 {
96 return new wxGtkPrinter( data );
97 }
98
99 wxPrintPreviewBase *wxGtkPrintFactory::CreatePrintPreview( wxPrintout *preview,
100 wxPrintout *printout,
101 wxPrintDialogData *data )
102 {
103 return new wxGtkPrintPreview( preview, printout, data );
104 }
105
106 wxPrintPreviewBase *wxGtkPrintFactory::CreatePrintPreview( wxPrintout *preview,
107 wxPrintout *printout,
108 wxPrintData *data )
109 {
110 return new wxGtkPrintPreview( preview, printout, data );
111 }
112
113 wxPrintDialogBase *wxGtkPrintFactory::CreatePrintDialog( wxWindow *parent,
114 wxPrintDialogData *data )
115 {
116 return new wxGtkPrintDialog( parent, data );
117 }
118
119 wxPrintDialogBase *wxGtkPrintFactory::CreatePrintDialog( wxWindow *parent,
120 wxPrintData *data )
121 {
122 return new wxGtkPrintDialog( parent, data );
123 }
124
125 wxPageSetupDialogBase *wxGtkPrintFactory::CreatePageSetupDialog( wxWindow *parent,
126 wxPageSetupDialogData * data )
127 {
128 return new wxGtkPageSetupDialog( parent, data );
129 }
130
131 bool wxGtkPrintFactory::HasPrintSetupDialog()
132 {
133 return false;
134 }
135
136 wxDialog *wxGtkPrintFactory::CreatePrintSetupDialog( wxWindow *parent, wxPrintData *data )
137 {
138 return NULL;
139 }
140
141 wxDC* wxGtkPrintFactory::CreatePrinterDC( const wxPrintData& data )
142 {
143 return new wxGtkPrintDC(data);
144 }
145
146 bool wxGtkPrintFactory::HasOwnPrintToFile()
147 {
148 return true;
149 }
150
151 bool wxGtkPrintFactory::HasPrinterLine()
152 {
153 return true;
154 }
155
156 wxString wxGtkPrintFactory::CreatePrinterLine()
157 {
158 // redundant now
159 return wxEmptyString;
160 }
161
162 bool wxGtkPrintFactory::HasStatusLine()
163 {
164 // redundant now
165 return true;
166 }
167
168 wxString wxGtkPrintFactory::CreateStatusLine()
169 {
170 // redundant now
171 return wxEmptyString;
172 }
173
174 wxPrintNativeDataBase *wxGtkPrintFactory::CreatePrintNativeData()
175 {
176 return new wxGtkPrintNativeData;
177 }
178
179 //----------------------------------------------------------------------------
180 // Callback functions for Gtk Printings.
181 //----------------------------------------------------------------------------
182
183 // We use it to pass useful objets to gtk printing callback functions.
184 typedef struct
185 {
186 wxGtkPrinter * printer;
187 wxPrintout * printout;
188 }
189 wxPrinterToGtkData;
190
191 extern "C"
192 {
193 static void gtk_begin_print_callback (GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data)
194 {
195 wxPrinterToGtkData *data = (wxPrinterToGtkData *) user_data;
196
197 data->printer->BeginPrint(data->printout, operation, context);
198 }
199
200 static void gtk_draw_page_print_callback (GtkPrintOperation *operation, GtkPrintContext *context, gint page_nr, gpointer user_data)
201 {
202 wxPrinterToGtkData *data = (wxPrinterToGtkData *) user_data;
203
204 data->printer->DrawPage(data->printout, operation, context, page_nr);
205 }
206
207 static void gtk_end_print_callback (GtkPrintOperation *operation, GtkPrintContext *context, gpointer user_data)
208 {
209 wxPrintout *printout = (wxPrintout *) user_data;
210
211 printout->OnEndPrinting();
212 }
213
214 static gboolean gtk_preview_print_callback (GtkPrintOperation *operation, GtkPrintOperationPreview *preview, GtkPrintContext *context, GtkWindow *parent, gpointer user_data)
215 {
216 wxPrintout *printout = (wxPrintout *) user_data;
217
218 printout->SetIsPreview(true);
219
220 /* We create a cairo context with 72dpi resolution. This resolution is only used for positionning. */
221 cairo_t *cairo = gdk_cairo_create(GTK_WIDGET(parent)->window);
222 gtk_print_context_set_cairo_context(context, cairo, 72, 72);
223
224 return false;
225 }
226 }
227
228 //----------------------------------------------------------------------------
229 // wxGtkPrintNativeData
230 //----------------------------------------------------------------------------
231
232 IMPLEMENT_CLASS(wxGtkPrintNativeData, wxPrintNativeDataBase)
233
234 wxGtkPrintNativeData::wxGtkPrintNativeData()
235 {
236 m_config = gtk_print_settings_new();
237 }
238
239 wxGtkPrintNativeData::~wxGtkPrintNativeData()
240 {
241 g_object_unref (m_config);
242 }
243
244 // Convert datas stored in m_config to a wxPrintData.
245 // Called by wxPrintData::ConvertFromNative().
246 bool wxGtkPrintNativeData::TransferTo( wxPrintData &data )
247 {
248 if(!m_config)
249 return false;
250
251 GtkPrintQuality quality = gtk_print_settings_get_quality(m_config);
252 if (quality == GTK_PRINT_QUALITY_HIGH)
253 data.SetQuality(wxPRINT_QUALITY_HIGH);
254 else if (quality == GTK_PRINT_QUALITY_LOW)
255 data.SetQuality(wxPRINT_QUALITY_LOW);
256 else if (quality == GTK_PRINT_QUALITY_DRAFT)
257 data.SetQuality(wxPRINT_QUALITY_DRAFT);
258 else
259 data.SetQuality(wxPRINT_QUALITY_MEDIUM);
260
261 data.SetNoCopies(gtk_print_settings_get_n_copies(m_config));
262
263 data.SetColour(gtk_print_settings_get_use_color(m_config));
264
265 switch (gtk_print_settings_get_duplex(m_config))
266 {
267 case GTK_PRINT_DUPLEX_SIMPLEX: data.SetDuplex (wxDUPLEX_SIMPLEX);
268 break;
269
270 case GTK_PRINT_DUPLEX_HORIZONTAL: data.SetDuplex (wxDUPLEX_HORIZONTAL);
271 break;
272
273 default:
274 case GTK_PRINT_DUPLEX_VERTICAL: data.SetDuplex (wxDUPLEX_VERTICAL);
275 break;
276 }
277
278 GtkPageOrientation orientation = gtk_print_settings_get_orientation (m_config);
279 if (orientation == GTK_PAGE_ORIENTATION_PORTRAIT)
280 {
281 data.SetOrientation(wxPORTRAIT);
282 data.SetOrientationReversed(false);
283 }
284 else if (orientation == GTK_PAGE_ORIENTATION_LANDSCAPE)
285 {
286 data.SetOrientation(wxLANDSCAPE);
287 data.SetOrientationReversed(false);
288 }
289 else if (orientation == GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT)
290 {
291 data.SetOrientation(wxPORTRAIT);
292 data.SetOrientationReversed(true);
293 }
294 else if (orientation == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE)
295 {
296 data.SetOrientation(wxLANDSCAPE);
297 data.SetOrientationReversed(true);
298 }
299
300 data.SetCollate(gtk_print_settings_get_collate (m_config));
301
302 // Paper formats : these are the most common paper formats.
303 GtkPaperSize *paper_size = gtk_print_settings_get_paper_size (m_config);
304 if (!paper_size)
305 data.SetPaperId(wxPAPER_NONE);
306 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_A3)))
307 data.SetPaperId(wxPAPER_A3);
308 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_A4)))
309 data.SetPaperId(wxPAPER_A4);
310 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_A5)))
311 data.SetPaperId(wxPAPER_A5);
312 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_B5)))
313 data.SetPaperId(wxPAPER_B5);
314 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_LETTER)))
315 data.SetPaperId(wxPAPER_LETTER);
316 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_LEGAL)))
317 data.SetPaperId(wxPAPER_LEGAL);
318 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new (GTK_PAPER_NAME_EXECUTIVE)))
319 data.SetPaperId(wxPAPER_EXECUTIVE);
320 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"na_number-10")))
321 data.SetPaperId(wxPAPER_ENV_10);
322 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-c5")))
323 data.SetPaperId(wxPAPER_ENV_C5);
324 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-c6")))
325 data.SetPaperId(wxPAPER_ENV_C6);
326 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"jis-b5")))
327 data.SetPaperId(wxPAPER_B5_TRANSVERSE);
328 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-b5")))
329 data.SetPaperId(wxPAPER_ENV_B5);
330 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"na_monarch")))
331 data.SetPaperId(wxPAPER_ENV_MONARCH);
332 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"engineering-c")))
333 data.SetPaperId( wxPAPER_CSHEET);
334 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"engineering-d")))
335 data.SetPaperId( wxPAPER_DSHEET);
336 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"engineering-e")))
337 data.SetPaperId( wxPAPER_ESHEET);
338 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"letter")))
339 data.SetPaperId( wxPAPER_LETTERSMALL);
340 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"engineering-b")))
341 data.SetPaperId( wxPAPER_TABLOID);
342 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"ledger")))
343 data.SetPaperId( wxPAPER_LEDGER);
344 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"statement")))
345 data.SetPaperId( wxPAPER_STATEMENT);
346 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( GTK_PAPER_NAME_A4 )))
347 data.SetPaperId( wxPAPER_A4SMALL);
348 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-b4")))
349 data.SetPaperId( wxPAPER_B4);
350 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"folio")))
351 data.SetPaperId( wxPAPER_FOLIO);
352 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"quarto")))
353 data.SetPaperId( wxPAPER_QUARTO);
354 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"10x14")))
355 data.SetPaperId( wxPAPER_10X14);
356 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"ledger")))
357 data.SetPaperId( wxPAPER_11X17);
358 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"letter")))
359 data.SetPaperId( wxPAPER_NOTE);
360 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"na-number-9-envelope")))
361 data.SetPaperId( wxPAPER_ENV_9);
362 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"number-11")))
363 data.SetPaperId( wxPAPER_ENV_11);
364 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"number-12")))
365 data.SetPaperId( wxPAPER_ENV_12);
366 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"number-14")))
367 data.SetPaperId( wxPAPER_ENV_14);
368 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-designated")))
369 data.SetPaperId( wxPAPER_ENV_DL);
370 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-c3")))
371 data.SetPaperId( wxPAPER_ENV_C3);
372 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-c4")))
373 data.SetPaperId( wxPAPER_ENV_C4);
374 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"c6/c5")))
375 data.SetPaperId( wxPAPER_ENV_C65);
376 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-b4")))
377 data.SetPaperId( wxPAPER_ENV_B4);
378 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"iso-b6")))
379 data.SetPaperId( wxPAPER_ENV_B6);
380 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"Italian")))
381 data.SetPaperId( wxPAPER_ENV_ITALY);
382 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"personal")))
383 data.SetPaperId( wxPAPER_ENV_PERSONAL);
384 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"fanfold-us")))
385 data.SetPaperId( wxPAPER_FANFOLD_US);
386 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"fanfold-European")))
387 data.SetPaperId( wxPAPER_FANFOLD_STD_GERMAN);
388 else if (gtk_paper_size_is_equal(paper_size,gtk_paper_size_new ( (const gchar*)"foolscap")))
389 data.SetPaperId( wxPAPER_FANFOLD_LGL_GERMAN);
390 else
391 data.SetPaperId(wxPAPER_NONE);
392 return true;
393 }
394
395 // Put datas given by the wxPrintData into m_config.
396 // Called by wxPrintData::ConvertToNative().
397 bool wxGtkPrintNativeData::TransferFrom( const wxPrintData &data )
398 {
399 if(!m_config)
400 return false;
401
402 wxPrintQuality quality = data.GetQuality();
403 if (quality == wxPRINT_QUALITY_HIGH)
404 gtk_print_settings_set_quality (m_config, GTK_PRINT_QUALITY_HIGH);
405 else if (quality == wxPRINT_QUALITY_MEDIUM)
406 gtk_print_settings_set_quality (m_config, GTK_PRINT_QUALITY_NORMAL);
407 else if (quality == wxPRINT_QUALITY_LOW)
408 gtk_print_settings_set_quality (m_config, GTK_PRINT_QUALITY_LOW);
409 else if (quality == wxPRINT_QUALITY_DRAFT)
410 gtk_print_settings_set_quality (m_config, GTK_PRINT_QUALITY_DRAFT);
411 else if (quality > 1)
412 gtk_print_settings_set_resolution (m_config, quality);
413 else
414 gtk_print_settings_set_quality (m_config, GTK_PRINT_QUALITY_NORMAL);
415
416 gtk_print_settings_set_n_copies(m_config, data.GetNoCopies());
417
418 gtk_print_settings_set_use_color(m_config, data.GetColour());
419
420 switch (data.GetDuplex())
421 {
422 case wxDUPLEX_SIMPLEX: gtk_print_settings_set_duplex (m_config, GTK_PRINT_DUPLEX_SIMPLEX);
423 break;
424
425 case wxDUPLEX_HORIZONTAL: gtk_print_settings_set_duplex (m_config, GTK_PRINT_DUPLEX_HORIZONTAL);
426 break;
427
428 default:
429 case wxDUPLEX_VERTICAL: gtk_print_settings_set_duplex (m_config, GTK_PRINT_DUPLEX_VERTICAL);
430 break;
431 }
432
433 if (!data.IsOrientationReversed())
434 {
435 if (data.GetOrientation() == wxLANDSCAPE)
436 gtk_print_settings_set_orientation (m_config, GTK_PAGE_ORIENTATION_LANDSCAPE);
437 else
438 gtk_print_settings_set_orientation (m_config, GTK_PAGE_ORIENTATION_PORTRAIT);
439 }
440 else {
441 if (data.GetOrientation() == wxLANDSCAPE)
442 gtk_print_settings_set_orientation (m_config, GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE);
443 else
444 gtk_print_settings_set_orientation (m_config, GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT);
445 }
446
447 gtk_print_settings_set_collate (m_config, data.GetCollate());
448
449 // Paper formats: these are the most common paper formats.
450 switch (data.GetPaperId())
451 {
452 case wxPAPER_A3: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_A3));
453 break;
454 case wxPAPER_A4: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_A4));
455 break;
456 case wxPAPER_A5: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_A5));
457 break;
458 case wxPAPER_B5_TRANSVERSE: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "jis-b5"));
459 break;
460 case wxPAPER_B5: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_B5));
461 break;
462 case wxPAPER_LETTER: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_LETTER));
463 break;
464 case wxPAPER_LEGAL: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_LEGAL));
465 break;
466 case wxPAPER_EXECUTIVE: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_EXECUTIVE));
467 break;
468 case wxPAPER_ENV_10: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "na_number-10"));
469 break;
470 case wxPAPER_ENV_C5: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-c5"));
471 break;
472 case wxPAPER_ENV_C6: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-c6"));
473 break;
474 case wxPAPER_ENV_B5: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-c5b5"));
475 break;
476 case wxPAPER_ENV_MONARCH: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "na_monarch"));
477 break;
478 case wxPAPER_CSHEET: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "engineering-c"));
479 break;
480 case wxPAPER_DSHEET: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "engineering-d"));
481 break;
482 case wxPAPER_ESHEET: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "engineering-e"));
483 break;
484 case wxPAPER_LETTERSMALL: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "letter"));
485 break;
486 case wxPAPER_TABLOID: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "engineering-b"));
487 break;
488 case wxPAPER_LEDGER: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "ledger"));
489 break;
490 case wxPAPER_STATEMENT: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "statement"));
491 break;
492 case wxPAPER_A4SMALL: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new (GTK_PAPER_NAME_A4));
493 break;
494 case wxPAPER_B4: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-b4"));
495 break;
496 case wxPAPER_FOLIO: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "folio"));
497 break;
498 case wxPAPER_QUARTO: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "quarto"));
499 break;
500 case wxPAPER_10X14: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "10x14"));
501 break;
502 case wxPAPER_11X17: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "ledger"));
503 break;
504 case wxPAPER_NOTE: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "letter"));
505 break;
506 case wxPAPER_ENV_9: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "na-number-9-envelope"));
507 break;
508 case wxPAPER_ENV_11: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "number-11"));
509 break;
510 case wxPAPER_ENV_12: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "number-12"));
511 break;
512 case wxPAPER_ENV_14: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "number-14"));
513 break;
514 case wxPAPER_ENV_DL: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-designated"));
515 break;
516 case wxPAPER_ENV_C3: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-c3"));
517 break;
518 case wxPAPER_ENV_C4: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-c4"));
519 break;
520 case wxPAPER_ENV_C65: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "c6/c5"));
521 break;
522 case wxPAPER_ENV_B4: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-b4"));
523 break;
524 case wxPAPER_ENV_B6: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "iso-b6"));
525 break;
526 case wxPAPER_ENV_ITALY: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "Italian"));
527 break;
528 case wxPAPER_ENV_PERSONAL: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "personal"));
529 break;
530 case wxPAPER_FANFOLD_US: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "fanfold-us"));
531 break;
532 case wxPAPER_FANFOLD_STD_GERMAN: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "fanfold-European"));
533 break;
534 case wxPAPER_FANFOLD_LGL_GERMAN: gtk_print_settings_set_paper_size(m_config, gtk_paper_size_new ((const gchar*) "foolscap"));
535 break;
536 case wxPAPER_NONE:
537 default: break;
538 }
539
540 return true;
541 }
542
543 void wxGtkPrintNativeData::SetPrintConfig( GtkPrintSettings * config )
544 {
545 if (config)
546 m_config = gtk_print_settings_copy(config);
547 }
548
549 // Extract page setup from settings.
550 GtkPageSetup* wxGtkPrintNativeData::GetPageSetupFromSettings(GtkPrintSettings* settings)
551 {
552 GtkPageSetup* page_setup = gtk_page_setup_new();
553 gtk_page_setup_set_orientation (page_setup, gtk_print_settings_get_orientation (settings));
554
555 GtkPaperSize *paper_size = gtk_print_settings_get_paper_size (settings);
556 if (paper_size != NULL)
557 gtk_page_setup_set_paper_size_and_default_margins (page_setup, paper_size);
558
559 return page_setup;
560 }
561
562 // Insert page setup into a given GtkPrintSettings.
563 void wxGtkPrintNativeData::SetPageSetupToSettings(GtkPrintSettings* settings, GtkPageSetup* page_setup)
564 {
565 gtk_print_settings_set_orientation ( settings, gtk_page_setup_get_orientation (page_setup));
566 gtk_print_settings_set_paper_size ( settings, gtk_page_setup_get_paper_size (page_setup));
567 }
568
569 //----------------------------------------------------------------------------
570 // wxGtkPrintDialog
571 //----------------------------------------------------------------------------
572
573 IMPLEMENT_CLASS(wxGtkPrintDialog, wxPrintDialogBase)
574
575 wxGtkPrintDialog::wxGtkPrintDialog( wxWindow *parent, wxPrintDialogData *data )
576 : wxPrintDialogBase(parent, wxID_ANY, _("Print"),
577 wxPoint(0, 0), wxSize(600, 600),
578 wxDEFAULT_DIALOG_STYLE |
579 wxTAB_TRAVERSAL)
580 {
581 if (data)
582 m_printDialogData = *data;
583
584 m_parent = parent;
585 SetShowDialog(true);
586 }
587
588 wxGtkPrintDialog::wxGtkPrintDialog( wxWindow *parent, wxPrintData *data )
589 : wxPrintDialogBase(parent, wxID_ANY, _("Print"),
590 wxPoint(0, 0), wxSize(600, 600),
591 wxDEFAULT_DIALOG_STYLE |
592 wxTAB_TRAVERSAL)
593 {
594 if (data)
595 m_printDialogData = *data;
596
597 m_parent = parent;
598 SetShowDialog(true);
599 }
600
601
602 wxGtkPrintDialog::~wxGtkPrintDialog()
603 {
604 }
605
606 // This is called even if we actually don't want the dialog to appear.
607 int wxGtkPrintDialog::ShowModal()
608 {
609 GtkPrintOperationResult response;
610
611 // We need to restore the settings given in the constructor.
612 wxPrintData data = m_printDialogData.GetPrintData();
613 wxGtkPrintNativeData *native =
614 (wxGtkPrintNativeData*) data.GetNativeData();
615 data.ConvertToNative();
616
617 GtkPrintSettings * settings = native->GetPrintConfig();
618
619 // We have to restore pages to print here because they're stored in a wxPrintDialogData and ConvertToNative only works for wxPrintData.
620 int fromPage = m_printDialogData.GetFromPage();
621 int toPage = m_printDialogData.GetToPage();
622 if (m_printDialogData.GetSelection())
623 gtk_print_settings_set_print_pages(settings, GTK_PRINT_PAGES_CURRENT);
624 else if (m_printDialogData.GetAllPages())
625 gtk_print_settings_set_print_pages(settings, GTK_PRINT_PAGES_ALL);
626 else {
627 gtk_print_settings_set_print_pages(settings, GTK_PRINT_PAGES_RANGES);
628 GtkPageRange *range;
629 range = g_new (GtkPageRange, 1);
630 range[0].start = fromPage-1;
631 range[0].end = (toPage >= fromPage) ? toPage-1 : fromPage-1;
632 gtk_print_settings_set_page_ranges (settings, range, 1);
633 }
634
635 // If the settings are OK, we restore it.
636 if (settings != NULL)
637 gtk_print_operation_set_print_settings (native->GetPrintJob(), settings);
638 gtk_print_operation_set_default_page_setup (native->GetPrintJob(), native->GetPageSetupFromSettings(settings));
639
640 // Show the dialog if needed.
641 GError* gError = NULL;
642 if (GetShowDialog())
643 response = gtk_print_operation_run (native->GetPrintJob(), GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, GTK_WINDOW(gtk_widget_get_toplevel(m_parent->m_widget) ), &gError);
644 else
645 response = gtk_print_operation_run (native->GetPrintJob(), GTK_PRINT_OPERATION_ACTION_PRINT, (GtkWindow *) m_parent, &gError);
646
647 // Does everything went well?
648 if (response == GTK_PRINT_OPERATION_RESULT_CANCEL)
649 {
650 return wxID_CANCEL;
651 }
652 else if (response == GTK_PRINT_OPERATION_RESULT_ERROR)
653 {
654 g_error_free (gError);
655 wxLogError(_("Error while printing: ") + wxString::Format(_("%s"), gError->message));
656 return wxID_NO; // We use wxID_NO because there is no wxID_ERROR available
657 }
658
659 // Now get the settings and save it.
660 GtkPrintSettings* newSettings = gtk_print_operation_get_print_settings (native->GetPrintJob());
661 native->SetPrintConfig(newSettings);
662 data.ConvertFromNative();
663
664 // Same problem as a few lines before.
665 switch (gtk_print_settings_get_print_pages(newSettings))
666 {
667 case GTK_PRINT_PAGES_CURRENT:
668 m_printDialogData.SetSelection( true );
669 break;
670 case GTK_PRINT_PAGES_ALL:
671 m_printDialogData.SetAllPages( true );
672 m_printDialogData.SetFromPage( 0 );
673 m_printDialogData.SetToPage( 9999 );
674 break;
675 case GTK_PRINT_PAGES_RANGES:
676 default:
677 // wxWidgets doesn't support multiple ranges, so we can only save the first one even if the user wants to print others.
678 // For example, the user enters "1-3;5-7" in the dialog: pages 1-3 and 5-7 will be correctly printed when the user
679 // will hit "OK" button. However we can only save 1-3 in the print data.
680 gint num_ranges = 0;
681 GtkPageRange* range;
682 range = gtk_print_settings_get_page_ranges (newSettings, &num_ranges);
683 m_printDialogData.SetFromPage( range[0].start );
684 m_printDialogData.SetToPage( range[0].end );
685 break;
686 }
687
688 return wxID_OK;
689 }
690
691 //----------------------------------------------------------------------------
692 // wxGtkPageSetupDialog
693 //----------------------------------------------------------------------------
694
695 IMPLEMENT_CLASS(wxGtkPageSetupDialog, wxPageSetupDialogBase)
696
697 wxGtkPageSetupDialog::wxGtkPageSetupDialog( wxWindow *parent,
698 wxPageSetupDialogData* data )
699 {
700 if (data)
701 m_pageDialogData = *data;
702
703 m_parent = parent;
704 }
705
706 wxGtkPageSetupDialog::~wxGtkPageSetupDialog()
707 {
708 }
709
710 int wxGtkPageSetupDialog::ShowModal()
711 {
712 // Get the config.
713 m_pageDialogData.GetPrintData().ConvertToNative();
714 wxGtkPrintNativeData *native = (wxGtkPrintNativeData*) m_pageDialogData.GetPrintData().GetNativeData();
715 GtkPrintSettings* nativeData = native->GetPrintConfig();
716
717 // We only need the pagesetup data which are part of the settings.
718 GtkPageSetup* oldPageSetup = native->GetPageSetupFromSettings(nativeData);
719
720 // If the user used a custom paper format the last time he printed, we have to restore it too.
721 if (m_pageDialogData.GetPrintData().GetPaperId() == wxPAPER_NONE)
722 {
723 wxSize customPaperSize = m_pageDialogData.GetPaperSize();
724 if (customPaperSize.GetWidth() > 0 && customPaperSize.GetHeight() > 0)
725 {
726 wxString title = _("Custom size");
727 GtkPaperSize* customSize = gtk_paper_size_new_custom ("custom", title.mb_str(), (gdouble) customPaperSize.GetWidth(), (gdouble) customPaperSize.GetHeight(), GTK_UNIT_MM);
728 gtk_page_setup_set_paper_size_and_default_margins (oldPageSetup, customSize);
729 g_object_unref(customSize);
730 }
731 }
732
733 // Now show the dialog.
734 GtkPageSetup* newPageSetup = gtk_print_run_page_setup_dialog (GTK_WINDOW(m_parent->m_widget),
735 oldPageSetup,
736 nativeData);
737
738 int ret;
739 if (newPageSetup != oldPageSetup)
740 {
741 native->SetPageSetupToSettings(nativeData, newPageSetup);
742 m_pageDialogData.GetPrintData().ConvertFromNative();
743
744 // Store custom paper format if any.
745 if (m_pageDialogData.GetPrintData().GetPaperId() == wxPAPER_NONE)
746 {
747 gdouble ml,mr,mt,mb,pw,ph;
748 ml = gtk_page_setup_get_left_margin (newPageSetup, GTK_UNIT_MM);
749 mr = gtk_page_setup_get_right_margin (newPageSetup, GTK_UNIT_MM);
750 mt = gtk_page_setup_get_top_margin (newPageSetup, GTK_UNIT_MM);
751 mb = gtk_page_setup_get_bottom_margin (newPageSetup, GTK_UNIT_MM);
752
753 pw = gtk_page_setup_get_paper_width (newPageSetup, GTK_UNIT_MM);
754 ph = gtk_page_setup_get_paper_height (newPageSetup, GTK_UNIT_MM);
755
756 m_pageDialogData.SetMarginTopLeft( wxPoint( (int)(ml+0.5), (int)(mt+0.5)) );
757 m_pageDialogData.SetMarginBottomRight( wxPoint( (int)(mr+0.5), (int)(mb+0.5)) );
758
759 m_pageDialogData.SetPaperSize( wxSize( (int)(pw+0.5), (int)(ph+0.5) ) );
760 }
761
762 ret = wxID_OK;
763 }
764 else
765 {
766 ret = wxID_CANCEL;
767 }
768
769 return ret;
770 }
771
772 //----------------------------------------------------------------------------
773 // wxGtkPrinter
774 //----------------------------------------------------------------------------
775
776 IMPLEMENT_CLASS(wxGtkPrinter, wxPrinterBase)
777
778 wxGtkPrinter::wxGtkPrinter( wxPrintDialogData *data ) :
779 wxPrinterBase( data )
780 {
781 m_gpc = NULL;
782
783 if (data)
784 m_printDialogData = *data;
785 }
786
787 wxGtkPrinter::~wxGtkPrinter()
788 {
789 }
790
791 bool wxGtkPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt )
792 {
793 if (!printout)
794 {
795 sm_lastError = wxPRINTER_ERROR;
796 return false;
797 }
798
799 // Let's correct the PageInfo just in case the app gives wrong values.
800 int fromPage, toPage;
801 int minPage, maxPage;
802 printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage);
803 m_printDialogData.SetAllPages(true);
804
805 if (minPage < 1) minPage = 1;
806 if (maxPage < 1) maxPage = 9999;
807 if (maxPage < minPage) maxPage = minPage;
808
809 m_printDialogData.SetMinPage(minPage);
810 m_printDialogData.SetMaxPage(maxPage);
811 if (fromPage != 0)
812 {
813 if (fromPage < minPage) fromPage = minPage;
814 else if (fromPage > maxPage) fromPage = maxPage;
815 m_printDialogData.SetFromPage(fromPage);
816 }
817 if (toPage != 0)
818 {
819 m_printDialogData.SetToPage(toPage);
820 if (toPage > maxPage) toPage = maxPage;
821 else if (toPage < minPage) toPage = minPage;
822 }
823
824 if (((minPage != fromPage) && fromPage != 0) || ((maxPage != toPage) && toPage != 0)) m_printDialogData.SetAllPages(false);
825
826
827 wxPrintData printdata = GetPrintDialogData().GetPrintData();
828 wxGtkPrintNativeData *native = (wxGtkPrintNativeData*) printdata.GetNativeData();
829
830 GtkPrintOperation *printOp = gtk_print_operation_new ();
831
832 native->SetPrintJob( printOp );
833
834 printout->SetIsPreview(false);
835
836 wxPrinterToGtkData dataToSend;
837 dataToSend.printer = this;
838 dataToSend.printout = printout;
839
840 // These Gtk signals are catched here.
841 g_signal_connect (printOp, "begin-print", G_CALLBACK (gtk_begin_print_callback), &dataToSend);
842 g_signal_connect (printOp, "draw-page", G_CALLBACK (gtk_draw_page_print_callback), &dataToSend);
843 g_signal_connect (printOp, "end-print", G_CALLBACK (gtk_end_print_callback), printout);
844 g_signal_connect (printOp, "preview", G_CALLBACK (gtk_preview_print_callback), printout);
845
846 m_showDialog = true;
847 if (!prompt)
848 m_showDialog = false;
849
850 // PrintDialog returns a wxDC but we created it before so we don't need it anymore: we just delete it.
851 wxDC* uselessdc = PrintDialog( parent );
852 delete uselessdc;
853
854 g_object_unref (printOp);
855
856 return (sm_lastError == wxPRINTER_NO_ERROR);
857 }
858
859 void wxGtkPrinter::BeginPrint(wxPrintout *printout, GtkPrintOperation *operation, GtkPrintContext *context)
860 {
861 wxPrintData printdata = GetPrintDialogData().GetPrintData();
862 wxGtkPrintNativeData *native = (wxGtkPrintNativeData*) printdata.GetNativeData();
863
864 SetPrintContext(context);
865 native->SetPrintContext( context );
866
867 m_dc = new wxGtkPrintDC( printdata );
868
869 if (!m_dc->IsOk())
870 {
871 if (sm_lastError != wxPRINTER_CANCELLED)
872 {
873 sm_lastError = wxPRINTER_ERROR;
874 wxFAIL_MSG(_("The wxGtkPrintDC cannot be used."));
875 }
876 return;
877 }
878 wxSize ScreenPixels = wxGetDisplaySize();
879 wxSize ScreenMM = wxGetDisplaySizeMM();
880
881 printout->SetPPIScreen( (int) ((ScreenPixels.GetWidth() * 25.4) / ScreenMM.GetWidth()),
882 (int) ((ScreenPixels.GetHeight() * 25.4) / ScreenMM.GetHeight()) );
883 printout->SetPPIPrinter( wxGtkPrintDC::GetResolution(),
884 wxGtkPrintDC::GetResolution() );
885
886 printout->SetDC(m_dc);
887
888 int w, h;
889 m_dc->GetSize(&w, &h);
890 printout->SetPageSizePixels((int)w, (int)h);
891 printout->SetPaperRectPixels(wxRect(0, 0, w, h));
892 int mw, mh;
893 m_dc->GetSizeMM(&mw, &mh);
894 printout->SetPageSizeMM((int)mw, (int)mh);
895 printout->OnPreparePrinting();
896
897 // Get some parameters from the printout, if defined.
898 int fromPage, toPage;
899 int minPage, maxPage;
900 printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage);
901
902 if (maxPage == 0)
903 {
904 sm_lastError = wxPRINTER_ERROR;
905 wxFAIL_MSG(_("wxPrintout::GetPageInfo gives a null maxPage."));
906 return;
907 }
908
909 printout->OnBeginPrinting();
910
911 int numPages = 0;
912
913 // If we're not previewing we need to calculate the number of pages to print.
914 // If we're previewing, Gtk Print will render every pages without wondering about the page ranges the user may
915 // have defined in the dialog. So the number of pages is the maximum available.
916 if (!printout->IsPreview())
917 {
918 GtkPrintSettings * settings = gtk_print_operation_get_print_settings (operation);
919 switch (gtk_print_settings_get_print_pages(settings))
920 {
921 case GTK_PRINT_PAGES_CURRENT:
922 numPages = 1;
923 break;
924 case GTK_PRINT_PAGES_RANGES:
925 {gint num_ranges = 0;
926 GtkPageRange* range;
927 int i;
928 range = gtk_print_settings_get_page_ranges (settings, &num_ranges);
929 for (i=0; i<num_ranges; i++)
930 {
931 if (range[i].end < range[i].start) range[i].end = range[i].start;
932 if (range[i].start < minPage-1) range[i].start = minPage-1;
933 if (range[i].end > maxPage-1) range[i].end = maxPage-1;
934 if (range[i].start > maxPage-1) range[i].start = maxPage-1;
935 numPages += range[i].end - range[i].start + 1;
936 }
937 gtk_print_settings_set_page_ranges (settings, range, 1);
938 break;}
939 case GTK_PRINT_PAGES_ALL:
940 default:
941 numPages = maxPage - minPage + 1;
942 break;
943 }
944 }
945 else numPages = maxPage - minPage + 1;
946
947 gtk_print_operation_set_n_pages(operation, numPages);
948 }
949
950 void wxGtkPrinter::DrawPage(wxPrintout *printout, GtkPrintOperation *operation, GtkPrintContext *context, int page_nr)
951 {
952 int fromPage, toPage, minPage, maxPage, startPage, endPage;
953 printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage);
954
955 int numPageToDraw = page_nr + minPage;
956 if (numPageToDraw < minPage) numPageToDraw = minPage;
957 if (numPageToDraw > maxPage) numPageToDraw = maxPage;
958
959 GtkPrintSettings * settings = gtk_print_operation_get_print_settings (operation);
960 switch (gtk_print_settings_get_print_pages(settings))
961 {
962 case GTK_PRINT_PAGES_CURRENT:
963 g_object_get_property((GObject*) operation, (const gchar *) "current-page", (GValue*) &startPage);
964 g_object_get_property((GObject*) operation, (const gchar *) "current-page", (GValue*) &endPage);
965 break;
966 case GTK_PRINT_PAGES_RANGES:
967 {gint num_ranges = 0;
968 GtkPageRange* range;
969 range = gtk_print_settings_get_page_ranges (settings, &num_ranges);
970 // We don't need to verify these values as it has already been done in wxGtkPrinter::BeginPrint.
971 startPage = range[0].start + 1;
972 endPage = range[0].end + 1;
973 break;}
974 case GTK_PRINT_PAGES_ALL:
975 default:
976 startPage = minPage;
977 endPage = maxPage;
978 break;
979 }
980
981 if(numPageToDraw == startPage)
982 {
983 if (!printout->OnBeginDocument(startPage, endPage))
984 {
985 wxLogError(_("Could not start printing."));
986 sm_lastError = wxPRINTER_ERROR;
987 }
988 }
989
990 // The app can render the page numPageToDraw.
991 if (printout->HasPage(numPageToDraw))
992 {
993 m_dc->StartPage();
994 printout->OnPrintPage(numPageToDraw);
995 m_dc->EndPage();
996 }
997
998
999 if(numPageToDraw == endPage)
1000 {
1001 printout->OnEndDocument();
1002 }
1003 }
1004
1005 wxDC* wxGtkPrinter::PrintDialog( wxWindow *parent )
1006 {
1007 wxGtkPrintDialog dialog( parent, &m_printDialogData );
1008 int ret;
1009
1010 dialog.SetPrintDC(m_dc);
1011
1012 dialog.SetShowDialog(m_showDialog);
1013
1014 ret = dialog.ShowModal();
1015
1016 if (ret == wxID_CANCEL)
1017 {
1018 sm_lastError = wxPRINTER_CANCELLED;
1019 return NULL;
1020 }
1021 if (ret == wxID_NO)
1022 {
1023 sm_lastError = wxPRINTER_ERROR;
1024 wxFAIL_MSG(_("The print dialog returned an error."));
1025 return NULL;
1026 }
1027
1028 m_printDialogData = dialog.GetPrintDialogData();
1029 return new wxGtkPrintDC( m_printDialogData.GetPrintData() );
1030 }
1031
1032 bool wxGtkPrinter::Setup( wxWindow *parent )
1033 {
1034 // Obsolete, for backward compatibility.
1035 return false;
1036 }
1037
1038 //-----------------------------------------------------------------------------
1039 // wxGtkPrintDC
1040 //-----------------------------------------------------------------------------
1041
1042 IMPLEMENT_CLASS(wxGtkPrintDC, wxDC)
1043
1044 // Define the default resolution for this DC. This resolution is just used for positioning as the cairo context is scalable.
1045 int wxGtkPrintDC::ms_resolution = 72;
1046
1047 wxGtkPrintDC::wxGtkPrintDC( const wxPrintData& data )
1048 {
1049 m_printData = data;
1050
1051 wxGtkPrintNativeData *native =
1052 (wxGtkPrintNativeData*) m_printData.GetNativeData();
1053
1054 m_gpc = native->GetPrintContext();
1055
1056 ms_resolution = (int) gtk_print_context_get_dpi_x(m_gpc);
1057 m_context = gtk_print_context_create_pango_context( m_gpc );
1058 m_layout = gtk_print_context_create_pango_layout ( m_gpc );
1059 m_fontdesc = pango_font_description_from_string( "Sans 12" );
1060
1061 m_cairo = gtk_print_context_get_cairo_context ( m_gpc );
1062
1063 m_currentRed = 0;
1064 m_currentBlue = 0;
1065 m_currentGreen = 0;
1066
1067 m_signX = 1; // default x-axis left to right.
1068 m_signY = 1; // default y-axis bottom up -> top down.
1069
1070 GetSize( &m_deviceOffsetX, &m_deviceOffsetY );
1071 }
1072
1073 wxGtkPrintDC::~wxGtkPrintDC()
1074 {
1075 g_object_unref(m_context);
1076 g_object_unref(m_layout);
1077 }
1078
1079 bool wxGtkPrintDC::IsOk() const
1080 {
1081 return true;
1082 }
1083
1084 void wxGtkPrintDC::ComputeScaleAndOrigin()
1085 {
1086 // Called when the scale and/or origin of the context has to be changed.
1087 m_scaleX = m_logicalScaleX * m_userScaleX;
1088 m_scaleY = m_logicalScaleY * m_userScaleY;
1089
1090 cairo_translate(m_cairo, m_deviceOriginX, m_deviceOriginY);
1091 cairo_scale(m_cairo, m_scaleX, m_scaleY );
1092 }
1093
1094 bool wxGtkPrintDC::DoFloodFill(wxCoord x1, wxCoord y1, const wxColour &col, int style )
1095 {
1096 // We can't access the given coord as a cairo context is scalable, ie a coord doesn't mean anything in this context.
1097 wxFAIL_MSG(_("not implemented"));
1098 return false;
1099 }
1100
1101 void wxGtkPrintDC::DoGradientFillConcentric(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, const wxPoint& circleCenter)
1102 {
1103 wxCoord xC = circleCenter.x;
1104 wxCoord yC = circleCenter.y;
1105 wxCoord xR = rect.x;
1106 wxCoord yR = rect.y;
1107 wxCoord w = rect.width;
1108 wxCoord h = rect.height;
1109
1110 double radius = sqrt((w/2)*(w/2)+(h/2)*(h/2));
1111
1112 unsigned char redI = initialColour.Red();
1113 unsigned char blueI = initialColour.Blue();
1114 unsigned char greenI = initialColour.Green();
1115 unsigned char alphaI = initialColour.Alpha();
1116 unsigned char redD = destColour.Red();
1117 unsigned char blueD = destColour.Blue();
1118 unsigned char greenD = destColour.Green();
1119 unsigned char alphaD = destColour.Alpha();
1120
1121 double redIPS = (double)(redI) / 255.0;
1122 double blueIPS = (double)(blueI) / 255.0;
1123 double greenIPS = (double)(greenI) / 255.0;
1124 double alphaIPS = (double)(alphaI) / 255.0;
1125 double redDPS = (double)(redD) / 255.0;
1126 double blueDPS = (double)(blueD) / 255.0;
1127 double greenDPS = (double)(greenD) / 255.0;
1128 double alphaDPS = (double)(alphaD) / 255.0;
1129
1130 // Create a pattern with the gradient.
1131 cairo_pattern_t* gradient;
1132 gradient = cairo_pattern_create_radial (LogicalToDeviceX(xC+xR), LogicalToDeviceY(yC+yR), 0, LogicalToDeviceX(xC+xR), LogicalToDeviceY(yC+yR), radius);
1133 cairo_pattern_add_color_stop_rgba (gradient, 0.0, redIPS, greenIPS, blueIPS, alphaIPS);
1134 cairo_pattern_add_color_stop_rgba (gradient, 1.0, redDPS, greenDPS, blueDPS, alphaDPS);
1135
1136 // Fill the rectangle with this pattern.
1137 cairo_set_source(m_cairo, gradient);
1138 cairo_rectangle (m_cairo, LogicalToDeviceX(xR), LogicalToDeviceY(yR), LogicalToDeviceXRel(w), LogicalToDeviceYRel(h) );
1139 cairo_fill(m_cairo);
1140
1141 cairo_pattern_destroy(gradient);
1142
1143 CalcBoundingBox(xR, yR);
1144 CalcBoundingBox(xR+w, yR+h);
1145 }
1146
1147 void wxGtkPrintDC::DoGradientFillLinear(const wxRect& rect, const wxColour& initialColour, const wxColour& destColour, wxDirection nDirection)
1148 {
1149 wxCoord x = rect.x;
1150 wxCoord y = rect.y;
1151 wxCoord w = rect.width;
1152 wxCoord h = rect.height;
1153
1154 unsigned char redI = initialColour.Red();
1155 unsigned char blueI = initialColour.Blue();
1156 unsigned char greenI = initialColour.Green();
1157 unsigned char alphaI = initialColour.Alpha();
1158 unsigned char redD = destColour.Red();
1159 unsigned char blueD = destColour.Blue();
1160 unsigned char greenD = destColour.Green();
1161 unsigned char alphaD = destColour.Alpha();
1162
1163 double redIPS = (double)(redI) / 255.0;
1164 double blueIPS = (double)(blueI) / 255.0;
1165 double greenIPS = (double)(greenI) / 255.0;
1166 double alphaIPS = (double)(alphaI) / 255.0;
1167 double redDPS = (double)(redD) / 255.0;
1168 double blueDPS = (double)(blueD) / 255.0;
1169 double greenDPS = (double)(greenD) / 255.0;
1170 double alphaDPS = (double)(alphaD) / 255.0;
1171
1172 // Create a pattern with the gradient.
1173 cairo_pattern_t* gradient;
1174 gradient = cairo_pattern_create_linear (LogicalToDeviceX(x), LogicalToDeviceY(y), LogicalToDeviceX(x+w), LogicalToDeviceY(y));
1175
1176 if (nDirection == wxWEST)
1177 {
1178 cairo_pattern_add_color_stop_rgba (gradient, 0.0, redDPS, greenDPS, blueDPS, alphaDPS);
1179 cairo_pattern_add_color_stop_rgba (gradient, 1.0, redIPS, greenIPS, blueIPS, alphaIPS);
1180 }
1181 else {
1182 cairo_pattern_add_color_stop_rgba (gradient, 0.0, redIPS, greenIPS, blueIPS, alphaIPS);
1183 cairo_pattern_add_color_stop_rgba (gradient, 1.0, redDPS, greenDPS, blueDPS, alphaDPS);
1184 }
1185
1186 // Fill the rectangle with this pattern.
1187 cairo_set_source(m_cairo, gradient);
1188 cairo_rectangle (m_cairo, LogicalToDeviceX(x), LogicalToDeviceY(y), LogicalToDeviceXRel(w), LogicalToDeviceYRel(h) );
1189 cairo_fill(m_cairo);
1190
1191 cairo_pattern_destroy(gradient);
1192
1193 CalcBoundingBox(x, y);
1194 CalcBoundingBox(x+w, y+h);
1195 }
1196
1197 bool wxGtkPrintDC::DoGetPixel(wxCoord x1, wxCoord y1, wxColour *col) const
1198 {
1199 // We can't access the given coord as a cairo context is scalable, ie a coord doesn't mean anything in this context.
1200 wxFAIL_MSG(_("not implemented"));
1201 return false;
1202 }
1203
1204 void wxGtkPrintDC::DoDrawLine(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
1205 {
1206 if (m_pen.GetStyle() == wxTRANSPARENT) return;
1207
1208 SetPen( m_pen );
1209 cairo_move_to ( m_cairo, LogicalToDeviceX(x1), LogicalToDeviceY(y1) );
1210 cairo_line_to ( m_cairo, LogicalToDeviceX(x2), LogicalToDeviceY(y2) );
1211 cairo_stroke ( m_cairo );
1212
1213 CalcBoundingBox( x1, y1 );
1214 CalcBoundingBox( x2, y2 );
1215 }
1216
1217 void wxGtkPrintDC::DoCrossHair(wxCoord x, wxCoord y)
1218 {
1219 int *w, *h;
1220 w = new int;
1221 h = new int;
1222 DoGetSize(w, h);
1223
1224 SetPen(m_pen);
1225
1226 cairo_move_to (m_cairo, LogicalToDeviceX(x), 0);
1227 cairo_line_to (m_cairo, LogicalToDeviceX(x), *h);
1228 cairo_move_to (m_cairo, 0, LogicalToDeviceY(y));
1229 cairo_line_to (m_cairo, *w, LogicalToDeviceY(y));
1230
1231 cairo_stroke (m_cairo);
1232 CalcBoundingBox( 0, 0 );
1233 CalcBoundingBox( *w, *h );
1234
1235 delete w;
1236 delete h;
1237 }
1238
1239 void wxGtkPrintDC::DoDrawArc(wxCoord x1,wxCoord y1,wxCoord x2,wxCoord y2,wxCoord xc,wxCoord yc)
1240 {
1241 double dx = x1 - xc;
1242 double dy = y1 - yc;
1243 double radius = sqrt((double)(dx*dx+dy*dy));
1244
1245 double alpha1, alpha2;
1246 if (x1 == x2 && y1 == y2)
1247 {
1248 alpha1 = 0.0;
1249 alpha2 = 360.0;
1250 }
1251 else
1252 if (radius == 0.0)
1253 {
1254 alpha1 = alpha2 = 0.0;
1255 }
1256 else
1257 {
1258 alpha1 = (x1 - xc == 0) ?
1259 (y1 - yc < 0) ? 90.0 : -90.0 :
1260 atan2(double(y1-yc), double(x1-xc)) * RAD2DEG;
1261 alpha2 = (x2 - xc == 0) ?
1262 (y2 - yc < 0) ? 90.0 : -90.0 :
1263 atan2(double(y2-yc), double(x2-xc)) * RAD2DEG;
1264
1265 while (alpha1 <= 0) alpha1 += 360;
1266 while (alpha2 <= 0) alpha2 += 360; // adjust angles to be between.
1267 while (alpha1 > 360) alpha1 -= 360; // 0 and 360 degree.
1268 while (alpha2 > 360) alpha2 -= 360;
1269 }
1270
1271 alpha1 *= DEG2RAD;
1272 alpha2 *= DEG2RAD;
1273
1274 cairo_arc_negative ( m_cairo, LogicalToDeviceX(xc), LogicalToDeviceY(yc), LogicalToDeviceXRel((int)radius), alpha1, alpha2);
1275 cairo_line_to(m_cairo, LogicalToDeviceX(xc), LogicalToDeviceY(yc));
1276 cairo_close_path (m_cairo);
1277
1278 SetBrush( m_brush );
1279 cairo_fill_preserve( m_cairo );
1280
1281 SetPen (m_pen);
1282 cairo_stroke( m_cairo );
1283
1284 CalcBoundingBox (x1, y1);
1285 CalcBoundingBox (xc, yc);
1286 CalcBoundingBox (x2, y2);
1287 }
1288
1289 void wxGtkPrintDC::DoDrawEllipticArc(wxCoord x,wxCoord y,wxCoord w,wxCoord h,double sa,double ea)
1290 {
1291 cairo_save( m_cairo );
1292
1293 cairo_translate( m_cairo, LogicalToDeviceX((wxCoord) (x + w / 2.)), LogicalToDeviceX((wxCoord) (y + h / 2.)) );
1294 double scale = (double)LogicalToDeviceYRel(h) / (double) LogicalToDeviceXRel(w);
1295 cairo_scale( m_cairo, 1.0, scale );
1296
1297 cairo_arc_negative ( m_cairo, 0, 0, LogicalToDeviceXRel(w/2), -sa*DEG2RAD, -ea*DEG2RAD);
1298
1299 SetPen (m_pen);
1300 cairo_stroke_preserve( m_cairo );
1301
1302 cairo_line_to(m_cairo, 0,0);
1303
1304 SetBrush( m_brush );
1305 cairo_fill( m_cairo );
1306
1307 cairo_restore( m_cairo );
1308
1309 CalcBoundingBox( x, y);
1310 CalcBoundingBox( x+w, y+h );
1311 }
1312
1313 void wxGtkPrintDC::DoDrawPoint(wxCoord x, wxCoord y)
1314 {
1315 if (m_pen.GetStyle() == wxTRANSPARENT) return;
1316
1317 SetPen( m_pen );
1318
1319 cairo_move_to ( m_cairo, LogicalToDeviceX(x), LogicalToDeviceY(y) );
1320 cairo_line_to ( m_cairo, LogicalToDeviceX(x), LogicalToDeviceY(y) );
1321 cairo_stroke ( m_cairo );
1322
1323 CalcBoundingBox( x, y );
1324 }
1325
1326 void wxGtkPrintDC::DoDrawLines(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset)
1327 {
1328 if (m_pen.GetStyle() == wxTRANSPARENT) return;
1329
1330 if (n <= 0) return;
1331
1332 SetPen (m_pen);
1333
1334 int i;
1335 for ( i =0; i<n ; i++ )
1336 CalcBoundingBox( points[i].x+xoffset, points[i].y+yoffset);
1337
1338 cairo_move_to ( m_cairo, LogicalToDeviceX(points[0].x+xoffset), LogicalToDeviceY(points[0].y+yoffset) );
1339
1340 for (i = 1; i < n; i++)
1341 cairo_line_to ( m_cairo, LogicalToDeviceX(points[i].x+xoffset), LogicalToDeviceY(points[i].y+yoffset) );
1342
1343 cairo_stroke ( m_cairo);
1344 }
1345
1346 void wxGtkPrintDC::DoDrawPolygon(int n, wxPoint points[], wxCoord xoffset, wxCoord yoffset, int fillStyle)
1347 {
1348 if (n==0) return;
1349
1350 cairo_save(m_cairo);
1351 if (fillStyle == wxWINDING_RULE)
1352 cairo_set_fill_rule( m_cairo, CAIRO_FILL_RULE_WINDING);
1353 else
1354 cairo_set_fill_rule( m_cairo, CAIRO_FILL_RULE_EVEN_ODD);
1355
1356 int x = points[0].x + xoffset;
1357 int y = points[0].y + yoffset;
1358 cairo_new_path(m_cairo);
1359 cairo_move_to( m_cairo, LogicalToDeviceX(x), LogicalToDeviceY(y) );
1360 int i;
1361 for (i = 1; i < n; i++)
1362 {
1363 int x = points[i].x + xoffset;
1364 int y = points[i].y + yoffset;
1365 cairo_line_to( m_cairo, LogicalToDeviceX(x), LogicalToDeviceY(y) );
1366 }
1367 cairo_close_path(m_cairo);
1368
1369 SetBrush( m_brush );
1370 cairo_fill_preserve( m_cairo );
1371
1372 SetPen (m_pen);
1373 cairo_stroke( m_cairo );
1374
1375 CalcBoundingBox( x, y );
1376
1377 cairo_restore(m_cairo);
1378 }
1379
1380 void wxGtkPrintDC::DoDrawPolyPolygon(int n, int count[], wxPoint points[], wxCoord xoffset, wxCoord yoffset, int fillStyle)
1381 {
1382 wxDC::DoDrawPolyPolygon( n, count, points, xoffset, yoffset, fillStyle );
1383 }
1384
1385 void wxGtkPrintDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1386 {
1387 cairo_rectangle ( m_cairo, LogicalToDeviceX(x), LogicalToDeviceY(y), LogicalToDeviceXRel(width), LogicalToDeviceYRel(height));
1388
1389 SetBrush( m_brush );
1390 cairo_fill_preserve( m_cairo );
1391
1392 SetPen (m_pen);
1393 cairo_stroke( m_cairo );
1394
1395 CalcBoundingBox( x, y );
1396 CalcBoundingBox( x + width, y + height );
1397 }
1398
1399 void wxGtkPrintDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, wxCoord width, wxCoord height, double radius)
1400 {
1401 if (radius < 0.0) radius = - radius * ((width < height) ? width : height);
1402
1403 wxCoord dd = 2 * (wxCoord) radius;
1404 if (dd > width) dd = width;
1405 if (dd > height) dd = height;
1406 radius = dd / 2;
1407
1408 wxCoord rad = (wxCoord) radius;
1409
1410 cairo_new_path(m_cairo);
1411 cairo_move_to(m_cairo,LogicalToDeviceX(x + rad),LogicalToDeviceY(y));
1412 cairo_curve_to(m_cairo,
1413 LogicalToDeviceX(x + rad),LogicalToDeviceY(y),
1414 LogicalToDeviceX(x),LogicalToDeviceY(y),
1415 LogicalToDeviceX(x),LogicalToDeviceY(y + rad));
1416 cairo_line_to(m_cairo,LogicalToDeviceX(x),LogicalToDeviceY(y + height - rad));
1417 cairo_curve_to(m_cairo,
1418 LogicalToDeviceX(x),LogicalToDeviceY(y + height - rad),
1419 LogicalToDeviceX(x),LogicalToDeviceY(y + height),
1420 LogicalToDeviceX(x + rad),LogicalToDeviceY(y + height));
1421 cairo_line_to(m_cairo,LogicalToDeviceX(x + width - rad),LogicalToDeviceY(y + height));
1422 cairo_curve_to(m_cairo,
1423 LogicalToDeviceX(x + width - rad),LogicalToDeviceY(y + height),
1424 LogicalToDeviceX(x + width),LogicalToDeviceY(y + height),
1425 LogicalToDeviceX(x + width),LogicalToDeviceY(y + height - rad));
1426 cairo_line_to(m_cairo,LogicalToDeviceX(x + width),LogicalToDeviceY(y + rad));
1427 cairo_curve_to(m_cairo,
1428 LogicalToDeviceX(x + width),LogicalToDeviceY(y + rad),
1429 LogicalToDeviceX(x + width),LogicalToDeviceY(y),
1430 LogicalToDeviceX(x + width - rad),LogicalToDeviceY(y));
1431 cairo_line_to(m_cairo,LogicalToDeviceX(x + rad),LogicalToDeviceY(y));
1432 cairo_close_path(m_cairo);
1433
1434 SetBrush(m_brush);
1435 cairo_fill_preserve(m_cairo);
1436
1437 SetPen(m_pen);
1438 cairo_stroke(m_cairo);
1439
1440 CalcBoundingBox(x,y);
1441 CalcBoundingBox(x+width,y+height);
1442 }
1443
1444 void wxGtkPrintDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
1445 {
1446 cairo_save (m_cairo);
1447
1448 cairo_translate (m_cairo, LogicalToDeviceX((wxCoord) (x + width / 2.)), LogicalToDeviceY((wxCoord) (y + height / 2.)));
1449 cairo_scale(m_cairo, 1, (double)LogicalToDeviceYRel(height)/(double)LogicalToDeviceXRel(width));
1450 cairo_arc ( m_cairo, 0, 0, LogicalToDeviceXRel(width/2), 0, 2 * M_PI);
1451
1452 SetBrush( m_brush );
1453 cairo_fill_preserve( m_cairo );
1454
1455 SetPen (m_pen);
1456 cairo_stroke( m_cairo );
1457
1458 CalcBoundingBox( x, y );
1459 CalcBoundingBox( x + width, y + height );
1460
1461 cairo_restore (m_cairo);
1462 }
1463
1464 #if wxUSE_SPLINES
1465 void wxGtkPrintDC::DoDrawSpline(wxList *points)
1466 {
1467 SetPen (m_pen);
1468
1469 double c, d, x1, y1, x2, y2, x3, y3;
1470 wxPoint *p, *q;
1471
1472 wxList::compatibility_iterator node = points->GetFirst();
1473 p = (wxPoint *)node->GetData();
1474 x1 = p->x;
1475 y1 = p->y;
1476
1477 node = node->GetNext();
1478 p = (wxPoint *)node->GetData();
1479 c = p->x;
1480 d = p->y;
1481 x3 =
1482 (double)(x1 + c) / 2;
1483 y3 =
1484 (double)(y1 + d) / 2;
1485
1486 cairo_new_path( m_cairo );
1487 cairo_move_to( m_cairo, LogicalToDeviceX((wxCoord)x1), LogicalToDeviceY((wxCoord)y1) );
1488 cairo_line_to( m_cairo, LogicalToDeviceX((wxCoord)x3), LogicalToDeviceY((wxCoord)y3) );
1489
1490 CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 );
1491 CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 );
1492
1493 node = node->GetNext();
1494 while (node)
1495 {
1496 q = (wxPoint *)node->GetData();
1497
1498 x1 = x3;
1499 y1 = y3;
1500 x2 = c;
1501 y2 = d;
1502 c = q->x;
1503 d = q->y;
1504 x3 = (double)(x2 + c) / 2;
1505 y3 = (double)(y2 + d) / 2;
1506
1507 cairo_curve_to(m_cairo,
1508 LogicalToDeviceX((wxCoord)x1), LogicalToDeviceY((wxCoord)y1),
1509 LogicalToDeviceX((wxCoord)x2), LogicalToDeviceY((wxCoord)y2),
1510 LogicalToDeviceX((wxCoord)x3), LogicalToDeviceY((wxCoord)y3) );
1511
1512 CalcBoundingBox( (wxCoord)x1, (wxCoord)y1 );
1513 CalcBoundingBox( (wxCoord)x3, (wxCoord)y3 );
1514
1515 node = node->GetNext();
1516 }
1517
1518 cairo_line_to ( m_cairo, LogicalToDeviceX((wxCoord)c), LogicalToDeviceY((wxCoord)d) );
1519
1520 cairo_stroke( m_cairo );
1521 }
1522 #endif // wxUSE_SPLINES
1523
1524 bool wxGtkPrintDC::DoBlit(wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height,
1525 wxDC *source, wxCoord xsrc, wxCoord ysrc, int rop, bool useMask,
1526 wxCoord xsrcMask, wxCoord ysrcMask)
1527 {
1528 wxCHECK_MSG( source, false, wxT("invalid source dc") );
1529
1530 // Blit into a bitmap.
1531 wxBitmap bitmap( width, height );
1532 wxMemoryDC memDC;
1533 memDC.SelectObject(bitmap);
1534 memDC.Blit(0, 0, width, height, source, xsrc, ysrc, rop);
1535 memDC.SelectObject(wxNullBitmap);
1536
1537 // Draw bitmap. scaling and positioning is done there.
1538 DrawBitmap( bitmap, xdest, ydest, useMask );
1539
1540 return true;
1541 }
1542
1543 void wxGtkPrintDC::DoDrawIcon( const wxIcon& icon, wxCoord x, wxCoord y )
1544 {
1545 DoDrawBitmap( icon, x, y, true );
1546 }
1547
1548 void wxGtkPrintDC::DoDrawBitmap( const wxBitmap& bitmap, wxCoord x, wxCoord y, bool useMask )
1549 {
1550 wxCHECK_RET( bitmap.IsOk(), wxT("Invalid bitmap in wxGtkPrintDC::DoDrawBitmap"));
1551
1552 cairo_surface_t* surface;
1553 x = LogicalToDeviceX(x);
1554 y = LogicalToDeviceY(y);
1555 int bw = bitmap.GetWidth();
1556 int bh = bitmap.GetHeight();
1557 wxBitmap bmpSource = bitmap; // we need a non-const instance.
1558 unsigned char* buffer = new unsigned char[bw*bh*4];
1559 wxUint32* data = (wxUint32*)buffer;
1560
1561 wxMask *mask = NULL;
1562 if (useMask) mask = bmpSource.GetMask();
1563
1564 // Create a surface object and copy the bitmap pixel data to it. If the image has alpha (or a mask represented as alpha)
1565 // then we'll use a different format and iterator than if it doesn't.
1566 if (bmpSource.HasAlpha() || mask)
1567 {
1568 surface = cairo_image_surface_create_for_data(
1569 buffer, CAIRO_FORMAT_ARGB32, bw, bh, bw*4);
1570 wxAlphaPixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh));
1571 wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
1572
1573 wxAlphaPixelData::Iterator p(pixData);
1574 int y, x;
1575 for (y=0; y<bh; y++)
1576 {
1577 wxAlphaPixelData::Iterator rowStart = p;
1578 for (x=0; x<bw; x++)
1579 {
1580 // Each pixel in CAIRO_FORMAT_ARGB32 is a 32-bit quantity,
1581 // with alpha in the upper 8 bits, then red, then green, then
1582 // blue. The 32-bit quantities are stored native-endian.
1583 // Pre-multiplied alpha is used.
1584 unsigned char alpha = p.Alpha();
1585 if (alpha == 0)
1586 *data = 0;
1587 else
1588 *data = ( alpha/255 << 24
1589 | (p.Red() * alpha/255) << 16
1590 | (p.Green() * alpha/255) << 8
1591 | (p.Blue() * alpha/255) );
1592 ++data;
1593 ++p;
1594 }
1595 p = rowStart;
1596 p.OffsetY(pixData, 1);
1597 }
1598 }
1599 else // no alpha
1600 {
1601 surface = cairo_image_surface_create_for_data(
1602 buffer, CAIRO_FORMAT_RGB24, bw, bh, bw*4);
1603 wxNativePixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh));
1604 wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
1605
1606 wxNativePixelData::Iterator p(pixData);
1607 int y, x;
1608 for (y=0; y<bh; y++)
1609 {
1610 wxNativePixelData::Iterator rowStart = p;
1611 for (x=0; x<bw; x++)
1612 {
1613 // Each pixel in CAIRO_FORMAT_RGB24 is a 32-bit quantity, with
1614 // the upper 8 bits unused. Red, Green, and Blue are stored in
1615 // the remaining 24 bits in that order. The 32-bit quantities
1616 // are stored native-endian.
1617 *data = ( p.Red() << 16 | p.Green() << 8 | p.Blue() );
1618 ++data;
1619 ++p;
1620 }
1621 p = rowStart;
1622 p.OffsetY(pixData, 1);
1623 }
1624 }
1625
1626
1627 cairo_save(m_cairo);
1628 // In case we're scaling the image by using a width and height different
1629 // than the bitmap's size create a pattern transformation on the surface and
1630 // draw the transformed pattern.
1631 cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
1632
1633 // Prepare to draw the image.
1634 cairo_translate(m_cairo, x, y);
1635 cairo_set_source(m_cairo, pattern);
1636 // Use the original size here since the context is scaled already.
1637 cairo_rectangle(m_cairo, 0, 0, bw, bh);
1638 // Fill the rectangle using the pattern.
1639 cairo_fill(m_cairo);
1640
1641 // Clean up.
1642 cairo_pattern_destroy(pattern);
1643 cairo_surface_destroy(surface);
1644 delete [] buffer;
1645
1646 CalcBoundingBox(0,0);
1647 CalcBoundingBox(bw,bh);
1648
1649 cairo_restore(m_cairo);
1650 }
1651
1652 // wxGtkPrintDC has a constant resolution of 72dpi. If we want an higher resolution for printing
1653 // an image, the scaling has to be done by cairo.
1654 void wxGtkPrintDC::DoDrawScaledBitmap( const wxBitmap& bitmap, wxCoord x, wxCoord y, wxCoord w, wxCoord h, bool useMask, int quality )
1655 {
1656 wxCHECK_RET( bitmap.IsOk(), wxT("Invalid bitmap in wxGtkPrintDC::DoDrawBitmap"));
1657
1658 cairo_surface_t* surface;
1659 int bw = bitmap.GetWidth();
1660 int bh = bitmap.GetHeight();
1661 x = LogicalToDeviceX(x);
1662 y = LogicalToDeviceY(y);
1663 w = LogicalToDeviceXRel(w);
1664 h = LogicalToDeviceYRel(h);
1665 wxBitmap bmpSource = bitmap; // we need a non-const instance.
1666 unsigned char* buffer = new unsigned char[bw*bh*4];
1667 wxUint32* data = (wxUint32*)buffer;
1668
1669 // Create a surface object and copy the bitmap pixel data to it. If the image has alpha (or a mask represented as alpha)
1670 // then we'll use a different format and iterator than if it doesn't.
1671 if (bmpSource.HasAlpha() || bmpSource.GetMask())
1672 {
1673 surface = cairo_image_surface_create_for_data(
1674 buffer, CAIRO_FORMAT_ARGB32, bw, bh, bw*4);
1675 wxAlphaPixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh));
1676 wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
1677
1678 wxAlphaPixelData::Iterator p(pixData);
1679 int y, x;
1680 for (y=0; y<bh; y++)
1681 {
1682 wxAlphaPixelData::Iterator rowStart = p;
1683 for (x=0; x<bw; x++)
1684 {
1685 // Each pixel in CAIRO_FORMAT_ARGB32 is a 32-bit quantity,
1686 // with alpha in the upper 8 bits, then red, then green, then
1687 // blue. The 32-bit quantities are stored native-endian.
1688 // Pre-multiplied alpha is used.
1689 unsigned char alpha = p.Alpha();
1690 if (alpha == 0)
1691 *data = 0;
1692 else
1693 *data = ( alpha << 24
1694 | (p.Red() * alpha/255) << 16
1695 | (p.Green() * alpha/255) << 8
1696 | (p.Blue() * alpha/255) );
1697 ++data;
1698 ++p;
1699 }
1700 p = rowStart;
1701 p.OffsetY(pixData, 1);
1702 }
1703 }
1704 else // no alpha
1705 {
1706 surface = cairo_image_surface_create_for_data(
1707 buffer, CAIRO_FORMAT_RGB24, bw, bh, bw*4);
1708 wxNativePixelData pixData(bmpSource, wxPoint(0,0), wxSize(bw, bh));
1709 wxCHECK_RET( pixData, wxT("Failed to gain raw access to bitmap data."));
1710
1711 wxNativePixelData::Iterator p(pixData);
1712 int y, x;
1713 for (y=0; y<bh; y++)
1714 {
1715 wxNativePixelData::Iterator rowStart = p;
1716 for (x=0; x<bw; x++)
1717 {
1718 // Each pixel in CAIRO_FORMAT_RGB24 is a 32-bit quantity, with
1719 // the upper 8 bits unused. Red, Green, and Blue are stored in
1720 // the remaining 24 bits in that order. The 32-bit quantities
1721 // are stored native-endian.
1722 *data = ( p.Red() << 16 | p.Green() << 8 | p.Blue() );
1723 ++data;
1724 ++p;
1725 }
1726 p = rowStart;
1727 p.OffsetY(pixData, 1);
1728 }
1729 }
1730
1731
1732 cairo_save(m_cairo);
1733
1734 // Prepare to draw the image.
1735 cairo_translate(m_cairo, x, y);
1736
1737 // In case we're scaling the image by using a width and height different
1738 // than the bitmap's size create a pattern transformation on the surface and
1739 // draw the transformed pattern.
1740 cairo_filter_t filter;
1741 if (quality == wxIMAGE_QUALITY_HIGH) filter = CAIRO_FILTER_BILINEAR;
1742 else filter = CAIRO_FILTER_GOOD;
1743 cairo_pattern_t* pattern = cairo_pattern_create_for_surface(surface);
1744 cairo_pattern_set_filter(pattern,filter);
1745 wxDouble scaleX = (wxDouble) w / (wxDouble) bw;
1746 wxDouble scaleY = (wxDouble) h / (wxDouble) bh;
1747 cairo_scale(m_cairo, scaleX, scaleY);
1748
1749 cairo_set_source(m_cairo, pattern);
1750 // Use the original size here since the context is scaled already.
1751 cairo_rectangle(m_cairo, 0, 0, bw, bh);
1752 // Fill the rectangle using the pattern.
1753 cairo_fill(m_cairo);
1754
1755 // Clean up.
1756 cairo_pattern_destroy(pattern);
1757 cairo_surface_destroy(surface);
1758 delete [] buffer;
1759
1760 CalcBoundingBox(0,0);
1761 CalcBoundingBox(bw,bh);
1762
1763 cairo_restore(m_cairo);
1764 }
1765
1766 void wxGtkPrintDC::DoDrawText(const wxString& text, wxCoord x, wxCoord y )
1767 {
1768 DoDrawRotatedText( text, x, y, 0.0 );
1769 }
1770
1771 void wxGtkPrintDC::DoDrawRotatedText(const wxString& text, wxCoord x, wxCoord y, double angle)
1772 {
1773 x = LogicalToDeviceX(x);
1774 y = LogicalToDeviceY(y);
1775
1776 angle = -angle;
1777
1778 bool underlined = m_font.Ok() && m_font.GetUnderlined();
1779
1780 // FIXME-UTF8: wouldn't be needed if utf8_str() always returned a buffer
1781 #if wxUSE_UNICODE_UTF8
1782 const char *data = text.utf8_str();
1783 #else
1784 const wxCharBuffer data = text.utf8_str();
1785 #endif
1786
1787 size_t datalen = strlen(data);
1788 pango_layout_set_text( m_layout, data, datalen);
1789
1790 if (underlined)
1791 {
1792 PangoAttrList *attrs = pango_attr_list_new();
1793 PangoAttribute *a = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
1794 a->start_index = 0;
1795 a->end_index = datalen;
1796 pango_attr_list_insert(attrs, a);
1797 pango_layout_set_attributes(m_layout, attrs);
1798 pango_attr_list_unref(attrs);
1799 }
1800
1801 if (m_textForegroundColour.Ok())
1802 {
1803 unsigned char red = m_textForegroundColour.Red();
1804 unsigned char blue = m_textForegroundColour.Blue();
1805 unsigned char green = m_textForegroundColour.Green();
1806 unsigned char alpha = m_textForegroundColour.Alpha();
1807
1808 if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue && alpha == m_currentAlpha))
1809 {
1810 double redPS = (double)(red) / 255.0;
1811 double bluePS = (double)(blue) / 255.0;
1812 double greenPS = (double)(green) / 255.0;
1813 double alphaPS = (double)(alpha) / 255.0;
1814
1815 cairo_set_source_rgba( m_cairo, redPS, greenPS, bluePS, alphaPS );
1816
1817 m_currentRed = red;
1818 m_currentBlue = blue;
1819 m_currentGreen = green;
1820 m_currentAlpha = alpha;
1821 }
1822 }
1823
1824 int w,h;
1825
1826 if (fabs(m_scaleY - 1.0) > 0.00001)
1827 {
1828 // If there is a user or actually any scale applied to the device context, scale the font.
1829
1830 // Scale font description.
1831 gint oldSize = pango_font_description_get_size( m_fontdesc );
1832 double size = oldSize;
1833 size = size * m_scaleY;
1834 pango_font_description_set_size( m_fontdesc, (gint)size );
1835
1836 // Actually apply scaled font.
1837 pango_layout_set_font_description( m_layout, m_fontdesc );
1838
1839 pango_layout_get_pixel_size( m_layout, &w, &h );
1840 w = LogicalToDeviceXRel(w);
1841 h = LogicalToDeviceYRel(h);
1842
1843 if ( m_backgroundMode == wxSOLID )
1844 {
1845 unsigned char red = m_textBackgroundColour.Red();
1846 unsigned char blue = m_textBackgroundColour.Blue();
1847 unsigned char green = m_textBackgroundColour.Green();
1848 unsigned char alpha = m_textBackgroundColour.Alpha();
1849
1850 double redPS = (double)(red) / 255.0;
1851 double bluePS = (double)(blue) / 255.0;
1852 double greenPS = (double)(green) / 255.0;
1853 double alphaPS = (double)(alpha) / 255.0;
1854
1855 cairo_save(m_cairo);
1856 cairo_translate(m_cairo, x, y);
1857 cairo_set_source_rgba( m_cairo, redPS, greenPS, bluePS, alphaPS );
1858 cairo_rotate(m_cairo,angle*DEG2RAD);
1859 cairo_rectangle(m_cairo, 0, 0, w, h);
1860 cairo_fill(m_cairo);
1861 cairo_restore(m_cairo);
1862 }
1863
1864 // Draw layout.
1865 cairo_move_to (m_cairo, x, y);
1866 if (fabs(angle) > 0.00001)
1867 {
1868 cairo_save( m_cairo );
1869 cairo_rotate( m_cairo, angle*DEG2RAD );
1870 pango_cairo_update_layout (m_cairo, m_layout);
1871 pango_cairo_show_layout (m_cairo, m_layout);
1872 cairo_restore( m_cairo );
1873 }
1874 else
1875 {
1876 pango_cairo_update_layout (m_cairo, m_layout);
1877 pango_cairo_show_layout (m_cairo, m_layout);
1878 }
1879
1880 // Reset unscaled size.
1881 pango_font_description_set_size( m_fontdesc, oldSize );
1882
1883 // Actually apply unscaled font.
1884 pango_layout_set_font_description( m_layout, m_fontdesc );
1885 }
1886 else
1887 {
1888 pango_layout_get_pixel_size( m_layout, &w, &h );
1889
1890 if ( m_backgroundMode == wxSOLID )
1891 {
1892 unsigned char red = m_textBackgroundColour.Red();
1893 unsigned char blue = m_textBackgroundColour.Blue();
1894 unsigned char green = m_textBackgroundColour.Green();
1895 unsigned char alpha = m_textBackgroundColour.Alpha();
1896
1897 double redPS = (double)(red) / 255.0;
1898 double bluePS = (double)(blue) / 255.0;
1899 double greenPS = (double)(green) / 255.0;
1900 double alphaPS = (double)(alpha) / 255.0;
1901
1902 cairo_save(m_cairo);
1903 cairo_translate(m_cairo, x, y);
1904 cairo_set_source_rgba( m_cairo, redPS, greenPS, bluePS, alphaPS );
1905 cairo_rotate(m_cairo,angle*DEG2RAD);
1906 cairo_rectangle(m_cairo, 0, 0, w, h);
1907 cairo_fill(m_cairo);
1908 cairo_restore(m_cairo);
1909 }
1910
1911 // Draw layout.
1912 cairo_move_to (m_cairo, x, y);
1913 if (fabs(angle) > 0.00001)
1914 {
1915 cairo_save( m_cairo );
1916 cairo_rotate( m_cairo, angle*DEG2RAD );
1917 pango_cairo_update_layout (m_cairo, m_layout);
1918 pango_cairo_show_layout (m_cairo, m_layout);
1919 cairo_restore( m_cairo );
1920 }
1921 else
1922 {
1923 pango_cairo_update_layout (m_cairo, m_layout);
1924 pango_cairo_show_layout (m_cairo, m_layout);
1925 }
1926 }
1927
1928 if (underlined)
1929 {
1930 // Undo underline attributes setting
1931 pango_layout_set_attributes(m_layout, NULL);
1932 }
1933
1934 CalcBoundingBox (x,y);
1935 CalcBoundingBox (x + w, y + h);
1936 }
1937
1938 void wxGtkPrintDC::Clear()
1939 {
1940 cairo_save(m_cairo);
1941 cairo_set_operator (m_cairo, CAIRO_OPERATOR_SOURCE);
1942 SetBrush(m_backgroundBrush);
1943 cairo_paint(m_cairo);
1944 cairo_restore(m_cairo);
1945 }
1946
1947 void wxGtkPrintDC::SetFont( const wxFont& font )
1948 {
1949 m_font = font;
1950
1951 if (m_font.Ok())
1952 {
1953 if (m_fontdesc)
1954 pango_font_description_free( m_fontdesc );
1955
1956 m_fontdesc = pango_font_description_copy( m_font.GetNativeFontInfo()->description );
1957
1958 pango_layout_set_font_description( m_layout, m_fontdesc );
1959 }
1960 }
1961
1962 void wxGtkPrintDC::SetPen( const wxPen& pen )
1963 {
1964 if (!pen.Ok()) return;
1965
1966 m_pen = pen;
1967
1968 double width = (double) m_pen.GetWidth();
1969 if (width == 0) width = 0.1;
1970
1971 cairo_set_line_width( m_cairo, LogicalToDeviceXRel( (wxCoord) (1000 * width )) / 1000.0f );
1972 static const double dotted[] = {2.0, 5.0};
1973 static const double short_dashed[] = {4.0, 4.0};
1974 static const double long_dashed[] = {4.0, 8.0};
1975 static const double dotted_dashed[] = {6.0, 6.0, 2.0, 6.0};
1976
1977 switch (m_pen.GetStyle())
1978 {
1979 case wxDOT: cairo_set_dash( m_cairo, dotted, 1, 0 ); break;
1980 case wxSHORT_DASH: cairo_set_dash( m_cairo, short_dashed, 1, 0 ); break;
1981 case wxLONG_DASH: cairo_set_dash( m_cairo, long_dashed, 1, 0 ); break;
1982 case wxDOT_DASH: cairo_set_dash( m_cairo, dotted_dashed, 3, 0 ); break;
1983 case wxUSER_DASH:
1984 {
1985 wxDash *wx_dashes;
1986 int num = m_pen.GetDashes (&wx_dashes) - 1;
1987 gdouble *g_dashes = g_new( gdouble, num );
1988 int i;
1989 for (i = 0; i < num; ++i)
1990 g_dashes[i] = (gdouble) wx_dashes[i];
1991 cairo_set_dash( m_cairo, g_dashes, num, 0);
1992 g_free( g_dashes );
1993 }
1994 break;
1995 case wxSOLID:
1996 case wxTRANSPARENT:
1997 default: cairo_set_dash( m_cairo, NULL, 0, 0 ); break;
1998 }
1999
2000 switch (m_pen.GetCap())
2001 {
2002 case wxCAP_PROJECTING: cairo_set_line_cap (m_cairo, CAIRO_LINE_CAP_SQUARE); break;
2003 case wxCAP_BUTT: cairo_set_line_cap (m_cairo, CAIRO_LINE_CAP_BUTT); break;
2004 case wxCAP_ROUND:
2005 default: cairo_set_line_cap (m_cairo, CAIRO_LINE_CAP_ROUND); break;
2006 }
2007
2008 switch (m_pen.GetJoin())
2009 {
2010 case wxJOIN_BEVEL: cairo_set_line_join (m_cairo, CAIRO_LINE_JOIN_BEVEL); break;
2011 case wxJOIN_MITER: cairo_set_line_join (m_cairo, CAIRO_LINE_JOIN_MITER); break;
2012 case wxJOIN_ROUND:
2013 default: cairo_set_line_join (m_cairo, CAIRO_LINE_JOIN_ROUND); break;
2014 }
2015
2016 unsigned char red = m_pen.GetColour().Red();
2017 unsigned char blue = m_pen.GetColour().Blue();
2018 unsigned char green = m_pen.GetColour().Green();
2019 unsigned char alpha = m_pen.GetColour().Alpha();
2020
2021 if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue && alpha == m_currentAlpha))
2022 {
2023 double redPS = (double)(red) / 255.0;
2024 double bluePS = (double)(blue) / 255.0;
2025 double greenPS = (double)(green) / 255.0;
2026 double alphaPS = (double)(alpha) / 255.0;
2027
2028 cairo_set_source_rgba( m_cairo, redPS, greenPS, bluePS, alphaPS );
2029
2030 m_currentRed = red;
2031 m_currentBlue = blue;
2032 m_currentGreen = green;
2033 m_currentAlpha = alpha;
2034 }
2035 }
2036
2037 void wxGtkPrintDC::SetBrush( const wxBrush& brush )
2038 {
2039 if (!brush.Ok()) return;
2040
2041 m_brush = brush;
2042
2043 // Brush colour.
2044 unsigned char red = m_brush.GetColour().Red();
2045 unsigned char blue = m_brush.GetColour().Blue();
2046 unsigned char green = m_brush.GetColour().Green();
2047 unsigned char alpha = m_brush.GetColour().Alpha();
2048
2049 double redPS = (double)(red) / 255.0;
2050 double bluePS = (double)(blue) / 255.0;
2051 double greenPS = (double)(green) / 255.0;
2052 double alphaPS = (double)(alpha) / 255.0;
2053
2054 if (!(red == m_currentRed && green == m_currentGreen && blue == m_currentBlue && alpha == m_currentAlpha))
2055 {
2056 cairo_set_source_rgba( m_cairo, redPS, greenPS, bluePS, alphaPS );
2057
2058 m_currentRed = red;
2059 m_currentBlue = blue;
2060 m_currentGreen = green;
2061 m_currentAlpha = alpha;
2062 }
2063
2064 if (m_brush.IsHatch())
2065 {
2066 cairo_t * cr;
2067 cairo_surface_t *surface;
2068 surface = cairo_surface_create_similar(cairo_get_target(m_cairo),CAIRO_CONTENT_COLOR_ALPHA,10,10);
2069 cr = cairo_create(surface);
2070 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
2071 cairo_set_line_width(cr, 1);
2072 cairo_set_line_join(cr,CAIRO_LINE_JOIN_MITER);
2073
2074 switch (m_brush.GetStyle())
2075 {
2076 case wxCROSS_HATCH:
2077 cairo_move_to(cr, 5, 0);
2078 cairo_line_to(cr, 5, 10);
2079 cairo_move_to(cr, 0, 5);
2080 cairo_line_to(cr, 10, 5);
2081 break;
2082 case wxBDIAGONAL_HATCH:
2083 cairo_move_to(cr, 0, 10);
2084 cairo_line_to(cr, 10, 0);
2085 break;
2086 case wxFDIAGONAL_HATCH:
2087 cairo_move_to(cr, 0, 0);
2088 cairo_line_to(cr, 10, 10);
2089 break;
2090 case wxCROSSDIAG_HATCH:
2091 cairo_move_to(cr, 0, 0);
2092 cairo_line_to(cr, 10, 10);
2093 cairo_move_to(cr, 10, 0);
2094 cairo_line_to(cr, 0, 10);
2095 break;
2096 case wxHORIZONTAL_HATCH:
2097 cairo_move_to(cr, 0, 5);
2098 cairo_line_to(cr, 10, 5);
2099 break;
2100 case wxVERTICAL_HATCH:
2101 cairo_move_to(cr, 5, 0);
2102 cairo_line_to(cr, 5, 10);
2103 break;
2104 default:
2105 wxFAIL_MSG(_("Couldn't get hatch style from wxBrush."));
2106 }
2107
2108 cairo_set_source_rgba(cr, redPS, greenPS, bluePS, alphaPS);
2109 cairo_stroke (cr);
2110
2111 cairo_destroy(cr);
2112 cairo_pattern_t * pattern = cairo_pattern_create_for_surface (surface);
2113 cairo_surface_destroy(surface);
2114 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
2115 cairo_set_source(m_cairo, pattern);
2116 cairo_pattern_destroy(pattern);
2117 }
2118 }
2119
2120 void wxGtkPrintDC::SetLogicalFunction( int function )
2121 {
2122 if (function == wxCLEAR)
2123 cairo_set_operator (m_cairo, CAIRO_OPERATOR_CLEAR);
2124 else if (function == wxOR)
2125 cairo_set_operator (m_cairo, CAIRO_OPERATOR_OUT);
2126 else if (function == wxNO_OP)
2127 cairo_set_operator (m_cairo, CAIRO_OPERATOR_DEST);
2128 else if (function == wxAND)
2129 cairo_set_operator (m_cairo, CAIRO_OPERATOR_ADD);
2130 else if (function == wxSET)
2131 cairo_set_operator (m_cairo, CAIRO_OPERATOR_SATURATE);
2132 else if (function == wxXOR)
2133 cairo_set_operator (m_cairo, CAIRO_OPERATOR_XOR);
2134 else // wxCOPY or anything else.
2135 cairo_set_operator (m_cairo, CAIRO_OPERATOR_SOURCE);
2136 }
2137
2138 void wxGtkPrintDC::SetBackground( const wxBrush& brush )
2139 {
2140 m_backgroundBrush = brush;
2141 cairo_save(m_cairo);
2142 cairo_set_operator (m_cairo, CAIRO_OPERATOR_DEST_OVER);
2143
2144 SetBrush(m_backgroundBrush);
2145 cairo_paint(m_cairo);
2146 cairo_restore(m_cairo);
2147 }
2148
2149 void wxGtkPrintDC::SetBackgroundMode(int mode)
2150 {
2151 if (mode == wxSOLID) m_backgroundMode = wxSOLID;
2152 else m_backgroundMode = wxTRANSPARENT;
2153 }
2154
2155 void wxGtkPrintDC::DoSetClippingRegion(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
2156 {
2157 cairo_rectangle ( m_cairo, LogicalToDeviceX(x), LogicalToDeviceY(y), LogicalToDeviceXRel(width), LogicalToDeviceYRel(height));
2158 cairo_clip(m_cairo);
2159 }
2160
2161 void wxGtkPrintDC::DestroyClippingRegion()
2162 {
2163 cairo_reset_clip(m_cairo);
2164 }
2165
2166 bool wxGtkPrintDC::StartDoc(const wxString& message)
2167 {
2168 return true;
2169 }
2170
2171 void wxGtkPrintDC::EndDoc()
2172 {
2173 return;
2174 }
2175
2176 void wxGtkPrintDC::StartPage()
2177 {
2178 return;
2179 }
2180
2181 void wxGtkPrintDC::EndPage()
2182 {
2183 return;
2184 }
2185
2186 wxCoord wxGtkPrintDC::GetCharHeight() const
2187 {
2188 pango_layout_set_text( m_layout, "H", 1 );
2189
2190 int w,h;
2191 pango_layout_get_pixel_size( m_layout, &w, &h );
2192
2193 return DeviceToLogicalYRel(h);
2194 }
2195
2196 wxCoord wxGtkPrintDC::GetCharWidth() const
2197 {
2198 pango_layout_set_text( m_layout, "H", 1 );
2199
2200 int w,h;
2201 pango_layout_get_pixel_size( m_layout, &w, &h );
2202
2203 return DeviceToLogicalXRel(w);
2204 }
2205
2206 void wxGtkPrintDC::DoGetTextExtent(const wxString& string, wxCoord *width, wxCoord *height,
2207 wxCoord *descent,
2208 wxCoord *externalLeading,
2209 const wxFont *theFont ) const
2210 {
2211 if ( width )
2212 *width = 0;
2213 if ( height )
2214 *height = 0;
2215 if ( descent )
2216 *descent = 0;
2217 if ( externalLeading )
2218 *externalLeading = 0;
2219
2220 if (string.empty())
2221 {
2222 return;
2223 }
2224
2225 // Set layout's text
2226 // FIXME-UTF8: wouldn't be needed if utf8_str() always returned a buffer
2227 #if wxUSE_UNICODE_UTF8
2228 const char *dataUTF8 = string.utf8_str();
2229 #else
2230 const wxCharBuffer dataUTF8 = string.utf8_str();
2231 #endif
2232
2233 PangoFontDescription *desc = m_fontdesc;
2234 if (theFont) desc = theFont->GetNativeFontInfo()->description;
2235
2236 gint oldSize = pango_font_description_get_size( desc );
2237 double size = oldSize;
2238 size = size * m_scaleY;
2239 pango_font_description_set_size( desc, (gint)size );
2240
2241 // apply scaled font
2242 pango_layout_set_font_description( m_layout, desc );
2243
2244 pango_layout_set_text( m_layout, dataUTF8, strlen(dataUTF8) );
2245
2246 int w, h;
2247 pango_layout_get_pixel_size( m_layout, &w, &h );
2248
2249 if (width)
2250 *width = (wxCoord)(w / m_scaleX);
2251 if (height)
2252 *height = (wxCoord)(h / m_scaleY);
2253 if (descent)
2254 {
2255 PangoLayoutIter *iter = pango_layout_get_iter(m_layout);
2256 int baseline = pango_layout_iter_get_baseline(iter);
2257 pango_layout_iter_free(iter);
2258 *descent = h - PANGO_PIXELS(baseline);
2259 }
2260
2261 // Reset unscaled size.
2262 pango_font_description_set_size( desc, oldSize );
2263
2264 // Reset unscaled font.
2265 pango_layout_set_font_description( m_layout, m_fontdesc );
2266 }
2267
2268 void wxGtkPrintDC::DoGetSize(int* width, int* height) const
2269 {
2270 if (width)
2271 *width = (int) (gtk_print_context_get_width( m_gpc ) + 0.5);
2272 if (height)
2273 *height = (int) (gtk_print_context_get_height( m_gpc ) + 0.5);
2274 }
2275
2276 void wxGtkPrintDC::DoGetSizeMM(int *width, int *height) const
2277 {
2278 // This function takes margins into consideration.
2279 gdouble w = gtk_page_setup_get_page_width( gtk_print_context_get_page_setup( m_gpc ), GTK_UNIT_MM);
2280 gdouble h = gtk_page_setup_get_page_height( gtk_print_context_get_page_setup( m_gpc ), GTK_UNIT_MM);
2281
2282 if (width)
2283 *width = (int) (w + 0.5);
2284 if (height)
2285 *height = (int) (h + 0.5);
2286 }
2287
2288 wxSize wxGtkPrintDC::GetPPI() const
2289 {
2290 gdouble xDpi = gtk_print_context_get_dpi_x( m_gpc );
2291 gdouble yDpi = gtk_print_context_get_dpi_y( m_gpc );
2292 return wxSize((int) xDpi,(int) yDpi);
2293 }
2294
2295 void wxGtkPrintDC::SetLogicalOrigin( wxCoord x, wxCoord y )
2296 {
2297 wxDC::SetLogicalOrigin( x, y );
2298 }
2299
2300 void wxGtkPrintDC::SetDeviceOrigin( wxCoord x, wxCoord y )
2301 {
2302 wxDC::SetDeviceOrigin( x, y );
2303 }
2304
2305 void wxGtkPrintDC::SetPrintData(const wxPrintData& data)
2306 {
2307 m_printData = data;
2308
2309 if (m_printData.GetOrientation() == wxPORTRAIT)
2310 GetSize( &m_deviceOffsetX, &m_deviceOffsetY );
2311 else
2312 GetSize( &m_deviceOffsetY, &m_deviceOffsetX );
2313 }
2314
2315 void wxGtkPrintDC::SetResolution(int ppi)
2316 {
2317 // We can't change ppi of the GtkPrintContext.
2318 ms_resolution = ppi;
2319 }
2320
2321 int wxGtkPrintDC::GetResolution()
2322 {
2323 return ms_resolution;
2324 }
2325
2326 // ----------------------------------------------------------------------------
2327 // Print preview
2328 // ----------------------------------------------------------------------------
2329
2330 IMPLEMENT_CLASS(wxGtkPrintPreview, wxPrintPreviewBase)
2331
2332 void wxGtkPrintPreview::Init(wxPrintout * WXUNUSED(printout),
2333 wxPrintout * WXUNUSED(printoutForPrinting))
2334 {
2335 DetermineScaling();
2336 }
2337
2338 wxGtkPrintPreview::wxGtkPrintPreview(wxPrintout *printout,
2339 wxPrintout *printoutForPrinting,
2340 wxPrintDialogData *data)
2341 : wxPrintPreviewBase(printout, printoutForPrinting, data)
2342 {
2343 Init(printout, printoutForPrinting);
2344 }
2345
2346 wxGtkPrintPreview::wxGtkPrintPreview(wxPrintout *printout,
2347 wxPrintout *printoutForPrinting,
2348 wxPrintData *data)
2349 : wxPrintPreviewBase(printout, printoutForPrinting, data)
2350 {
2351 Init(printout, printoutForPrinting);
2352 }
2353
2354 wxGtkPrintPreview::~wxGtkPrintPreview()
2355 {
2356 }
2357
2358 bool wxGtkPrintPreview::Print(bool interactive)
2359 {
2360 if (!m_printPrintout)
2361 return false;
2362
2363 wxPrinter printer(& m_printDialogData);
2364 return printer.Print(m_previewFrame, m_printPrintout, interactive);
2365 }
2366
2367 void wxGtkPrintPreview::DetermineScaling()
2368 {
2369 wxPaperSize paperType = m_printDialogData.GetPrintData().GetPaperId();
2370
2371 wxPrintPaperType *paper = wxThePrintPaperDatabase->FindPaperType(paperType);
2372 if (!paper)
2373 paper = wxThePrintPaperDatabase->FindPaperType(wxPAPER_A4);
2374
2375 if (paper)
2376 {
2377 wxSize ScreenPixels = wxGetDisplaySize();
2378 wxSize ScreenMM = wxGetDisplaySizeMM();
2379
2380 m_previewPrintout->SetPPIScreen( (int) ((ScreenPixels.GetWidth() * 25.4) / ScreenMM.GetWidth()),
2381 (int) ((ScreenPixels.GetHeight() * 25.4) / ScreenMM.GetHeight()) );
2382 m_previewPrintout->SetPPIPrinter(wxGtkPrintDC::GetResolution(), wxGtkPrintDC::GetResolution());
2383 // Get width and height in points (1/72th of an inch)
2384 wxSize sizeDevUnits(paper->GetSizeDeviceUnits());
2385
2386 sizeDevUnits.x = (wxCoord)((float)sizeDevUnits.x * wxGtkPrintDC::GetResolution() / 72.0);
2387 sizeDevUnits.y = (wxCoord)((float)sizeDevUnits.y * wxGtkPrintDC::GetResolution() / 72.0);
2388 wxSize sizeTenthsMM(paper->GetSize());
2389 wxSize sizeMM(sizeTenthsMM.x / 10, sizeTenthsMM.y / 10);
2390
2391 // If in landscape mode, we need to swap the width and height.
2392 if ( m_printDialogData.GetPrintData().GetOrientation() == wxLANDSCAPE )
2393 {
2394 m_pageWidth = sizeDevUnits.y;
2395 m_pageHeight = sizeDevUnits.x;
2396 m_previewPrintout->SetPageSizeMM(sizeMM.y, sizeMM.x);
2397 }
2398 else
2399 {
2400 m_pageWidth = sizeDevUnits.x;
2401 m_pageHeight = sizeDevUnits.y;
2402 m_previewPrintout->SetPageSizeMM(sizeMM.x, sizeMM.y);
2403 }
2404 m_previewPrintout->SetPageSizePixels(m_pageWidth, m_pageHeight);
2405 m_previewPrintout->SetPaperRectPixels(wxRect(0, 0, m_pageWidth, m_pageHeight));
2406
2407 // At 100%, the page should look about page-size on the screen.
2408 m_previewScaleX = (float)0.8 * 72.0 / (float)wxGtkPrintDC::GetResolution();
2409 m_previewScaleY = m_previewScaleX;
2410 }
2411 }
2412
2413 #endif
2414 // wxUSE_GTKPRINT