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