1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #include "nsPrintSettingsGTK.h"
7 #include "nsIFile.h"
8 #include "nsNetUtil.h"
9 #include <stdlib.h>
10 #include <algorithm>
11 
12 static
ref_printer(GtkPrinter * aPrinter,gpointer aData)13 gboolean ref_printer(GtkPrinter *aPrinter, gpointer aData)
14 {
15   ((nsPrintSettingsGTK*) aData)->SetGtkPrinter(aPrinter);
16   return TRUE;
17 }
18 
19 static
printer_enumerator(GtkPrinter * aPrinter,gpointer aData)20 gboolean printer_enumerator(GtkPrinter *aPrinter, gpointer aData)
21 {
22   if (gtk_printer_is_default(aPrinter))
23     return ref_printer(aPrinter, aData);
24 
25   return FALSE; // Keep 'em coming...
26 }
27 
28 static
moz_gtk_paper_size_copy_to_new_custom(GtkPaperSize * oldPaperSize)29 GtkPaperSize* moz_gtk_paper_size_copy_to_new_custom(GtkPaperSize* oldPaperSize)
30 {
31   // We make a "custom-ified" copy of the paper size so it can be changed later.
32   return gtk_paper_size_new_custom(gtk_paper_size_get_name(oldPaperSize),
33                                    gtk_paper_size_get_display_name(oldPaperSize),
34                                    gtk_paper_size_get_width(oldPaperSize, GTK_UNIT_INCH),
35                                    gtk_paper_size_get_height(oldPaperSize, GTK_UNIT_INCH),
36                                    GTK_UNIT_INCH);
37 }
38 
NS_IMPL_ISUPPORTS_INHERITED(nsPrintSettingsGTK,nsPrintSettings,nsPrintSettingsGTK)39 NS_IMPL_ISUPPORTS_INHERITED(nsPrintSettingsGTK,
40                             nsPrintSettings,
41                             nsPrintSettingsGTK)
42 
43 /** ---------------------------------------------------
44  */
45 nsPrintSettingsGTK::nsPrintSettingsGTK() :
46   mPageSetup(nullptr),
47   mPrintSettings(nullptr),
48   mGTKPrinter(nullptr),
49   mPrintSelectionOnly(false)
50 {
51   // The aim here is to set up the objects enough that silent printing works well.
52   // These will be replaced anyway if the print dialog is used.
53   mPrintSettings = gtk_print_settings_new();
54   GtkPageSetup* pageSetup = gtk_page_setup_new();
55   SetGtkPageSetup(pageSetup);
56   g_object_unref(pageSetup);
57 
58   SetOutputFormat(nsIPrintSettings::kOutputFormatNative);
59 }
60 
61 /** ---------------------------------------------------
62  */
~nsPrintSettingsGTK()63 nsPrintSettingsGTK::~nsPrintSettingsGTK()
64 {
65   if (mPageSetup) {
66     g_object_unref(mPageSetup);
67     mPageSetup = nullptr;
68   }
69   if (mPrintSettings) {
70     g_object_unref(mPrintSettings);
71     mPrintSettings = nullptr;
72   }
73   if (mGTKPrinter) {
74     g_object_unref(mGTKPrinter);
75     mGTKPrinter = nullptr;
76   }
77 }
78 
79 /** ---------------------------------------------------
80  */
nsPrintSettingsGTK(const nsPrintSettingsGTK & aPS)81 nsPrintSettingsGTK::nsPrintSettingsGTK(const nsPrintSettingsGTK& aPS) :
82   mPageSetup(nullptr),
83   mPrintSettings(nullptr),
84   mGTKPrinter(nullptr),
85   mPrintSelectionOnly(false)
86 {
87   *this = aPS;
88 }
89 
90 /** ---------------------------------------------------
91  */
operator =(const nsPrintSettingsGTK & rhs)92 nsPrintSettingsGTK& nsPrintSettingsGTK::operator=(const nsPrintSettingsGTK& rhs)
93 {
94   if (this == &rhs) {
95     return *this;
96   }
97 
98   nsPrintSettings::operator=(rhs);
99 
100   if (mPageSetup)
101     g_object_unref(mPageSetup);
102   mPageSetup = gtk_page_setup_copy(rhs.mPageSetup);
103   // NOTE: No need to re-initialize mUnwriteableMargin here (even
104   // though mPageSetup is changing). It'll be copied correctly by
105   // nsPrintSettings::operator=.
106 
107   if (mPrintSettings)
108     g_object_unref(mPrintSettings);
109   mPrintSettings = gtk_print_settings_copy(rhs.mPrintSettings);
110 
111   if (mGTKPrinter)
112     g_object_unref(mGTKPrinter);
113   mGTKPrinter = (GtkPrinter*) g_object_ref(rhs.mGTKPrinter);
114 
115   mPrintSelectionOnly = rhs.mPrintSelectionOnly;
116 
117   return *this;
118 }
119 
120 /** -------------------------------------------
121  */
_Clone(nsIPrintSettings ** _retval)122 nsresult nsPrintSettingsGTK::_Clone(nsIPrintSettings **_retval)
123 {
124   NS_ENSURE_ARG_POINTER(_retval);
125   *_retval = nullptr;
126 
127   nsPrintSettingsGTK *newSettings = new nsPrintSettingsGTK(*this);
128   if (!newSettings)
129     return NS_ERROR_FAILURE;
130   *_retval = newSettings;
131   NS_ADDREF(*_retval);
132   return NS_OK;
133 }
134 
135 
136 /** -------------------------------------------
137  */
138 NS_IMETHODIMP
_Assign(nsIPrintSettings * aPS)139 nsPrintSettingsGTK::_Assign(nsIPrintSettings *aPS)
140 {
141   nsPrintSettingsGTK *printSettingsGTK = static_cast<nsPrintSettingsGTK*>(aPS);
142   if (!printSettingsGTK)
143     return NS_ERROR_UNEXPECTED;
144   *this = *printSettingsGTK;
145   return NS_OK;
146 }
147 
148 /** ---------------------------------------------------
149  */
150 void
SetGtkPageSetup(GtkPageSetup * aPageSetup)151 nsPrintSettingsGTK::SetGtkPageSetup(GtkPageSetup *aPageSetup)
152 {
153   if (mPageSetup)
154     g_object_unref(mPageSetup);
155 
156   mPageSetup = (GtkPageSetup*) g_object_ref(aPageSetup);
157   InitUnwriteableMargin();
158 
159   // If the paper size is not custom, then we make a custom copy of the
160   // GtkPaperSize, so it can be mutable. If a GtkPaperSize wasn't made as
161   // custom, its properties are immutable.
162   GtkPaperSize* paperSize = gtk_page_setup_get_paper_size(aPageSetup);
163   if (!gtk_paper_size_is_custom(paperSize)) {
164     GtkPaperSize* customPaperSize =
165       moz_gtk_paper_size_copy_to_new_custom(paperSize);
166     gtk_page_setup_set_paper_size(mPageSetup, customPaperSize);
167     gtk_paper_size_free(customPaperSize);
168   }
169   SaveNewPageSize();
170 }
171 
172 /** ---------------------------------------------------
173  */
174 void
SetGtkPrintSettings(GtkPrintSettings * aPrintSettings)175 nsPrintSettingsGTK::SetGtkPrintSettings(GtkPrintSettings *aPrintSettings)
176 {
177   if (mPrintSettings)
178     g_object_unref(mPrintSettings);
179 
180   mPrintSettings = (GtkPrintSettings*) g_object_ref(aPrintSettings);
181 
182   GtkPaperSize* paperSize = gtk_print_settings_get_paper_size(aPrintSettings);
183   if (paperSize) {
184     GtkPaperSize* customPaperSize =
185       moz_gtk_paper_size_copy_to_new_custom(paperSize);
186     gtk_paper_size_free(paperSize);
187     gtk_page_setup_set_paper_size(mPageSetup, customPaperSize);
188     gtk_paper_size_free(customPaperSize);
189   } else {
190     // paperSize was null, and so we add the paper size in the GtkPageSetup to
191     // the settings.
192     SaveNewPageSize();
193   }
194 }
195 
196 /** ---------------------------------------------------
197  */
198 void
SetGtkPrinter(GtkPrinter * aPrinter)199 nsPrintSettingsGTK::SetGtkPrinter(GtkPrinter *aPrinter)
200 {
201   if (mGTKPrinter)
202     g_object_unref(mGTKPrinter);
203 
204   mGTKPrinter = (GtkPrinter*) g_object_ref(aPrinter);
205 }
206 
GetOutputFormat(int16_t * aOutputFormat)207 NS_IMETHODIMP nsPrintSettingsGTK::GetOutputFormat(int16_t *aOutputFormat)
208 {
209   NS_ENSURE_ARG_POINTER(aOutputFormat);
210 
211   int16_t format;
212   nsresult rv = nsPrintSettings::GetOutputFormat(&format);
213   if (NS_FAILED(rv)) {
214     return rv;
215   }
216 
217   if (format == nsIPrintSettings::kOutputFormatNative) {
218     const gchar* fmtGTK =
219       gtk_print_settings_get(mPrintSettings,
220                              GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT);
221     if (fmtGTK) {
222       if (nsDependentCString(fmtGTK).EqualsIgnoreCase("pdf")) {
223         format = nsIPrintSettings::kOutputFormatPDF;
224       } else {
225         format = nsIPrintSettings::kOutputFormatPS;
226       }
227     } else if (GTK_IS_PRINTER(mGTKPrinter)) {
228       // Prior to gtk 2.24, gtk_printer_accepts_pdf() and
229       // gtk_printer_accepts_ps() always returned true regardless of the
230       // printer's capability.
231       bool shouldTrustGTK =
232         (gtk_major_version > 2 ||
233          (gtk_major_version == 2 && gtk_minor_version >= 24));
234       bool acceptsPDF = shouldTrustGTK && gtk_printer_accepts_pdf(mGTKPrinter);
235 
236       format = acceptsPDF ? nsIPrintSettings::kOutputFormatPDF
237                           : nsIPrintSettings::kOutputFormatPS;
238     }
239   }
240 
241   *aOutputFormat = format;
242   return NS_OK;
243 }
244 
245 /**
246  * Reimplementation of nsPrintSettings functions so that we get the values
247  * from the GTK objects rather than our own variables.
248  */
249 
GetPrintRange(int16_t * aPrintRange)250 NS_IMETHODIMP nsPrintSettingsGTK::GetPrintRange(int16_t *aPrintRange)
251 {
252   NS_ENSURE_ARG_POINTER(aPrintRange);
253   if (mPrintSelectionOnly) {
254     *aPrintRange = kRangeSelection;
255     return NS_OK;
256   }
257 
258   GtkPrintPages gtkRange = gtk_print_settings_get_print_pages(mPrintSettings);
259   if (gtkRange == GTK_PRINT_PAGES_RANGES)
260     *aPrintRange = kRangeSpecifiedPageRange;
261   else
262     *aPrintRange = kRangeAllPages;
263 
264   return NS_OK;
265 }
SetPrintRange(int16_t aPrintRange)266 NS_IMETHODIMP nsPrintSettingsGTK::SetPrintRange(int16_t aPrintRange)
267 {
268   if (aPrintRange == kRangeSelection) {
269     mPrintSelectionOnly = true;
270     return NS_OK;
271   }
272 
273   mPrintSelectionOnly = false;
274   if (aPrintRange == kRangeSpecifiedPageRange)
275     gtk_print_settings_set_print_pages(mPrintSettings, GTK_PRINT_PAGES_RANGES);
276   else
277     gtk_print_settings_set_print_pages(mPrintSettings, GTK_PRINT_PAGES_ALL);
278   return NS_OK;
279 }
280 
281 NS_IMETHODIMP
GetStartPageRange(int32_t * aStartPageRange)282 nsPrintSettingsGTK::GetStartPageRange(int32_t *aStartPageRange)
283 {
284   gint ctRanges;
285   GtkPageRange* lstRanges = gtk_print_settings_get_page_ranges(mPrintSettings, &ctRanges);
286 
287   // Make sure we got a range.
288   if (ctRanges < 1) {
289     *aStartPageRange = 1;
290   } else {
291     // GTK supports multiple page ranges; gecko only supports 1. So find
292     // the lowest start page.
293     int32_t start(lstRanges[0].start);
294     for (gint ii = 1; ii < ctRanges; ii++) {
295       start = std::min(lstRanges[ii].start, start);
296     }
297     *aStartPageRange = start + 1;
298   }
299 
300   g_free(lstRanges);
301   return NS_OK;
302 }
303 NS_IMETHODIMP
SetStartPageRange(int32_t aStartPageRange)304 nsPrintSettingsGTK::SetStartPageRange(int32_t aStartPageRange)
305 {
306   int32_t endRange;
307   GetEndPageRange(&endRange);
308 
309   GtkPageRange gtkRange;
310   gtkRange.start = aStartPageRange - 1;
311   gtkRange.end = endRange - 1;
312 
313   gtk_print_settings_set_page_ranges(mPrintSettings, &gtkRange, 1);
314 
315   return NS_OK;
316 }
317 
318 NS_IMETHODIMP
GetEndPageRange(int32_t * aEndPageRange)319 nsPrintSettingsGTK::GetEndPageRange(int32_t *aEndPageRange)
320 {
321   gint ctRanges;
322   GtkPageRange* lstRanges = gtk_print_settings_get_page_ranges(mPrintSettings, &ctRanges);
323 
324   if (ctRanges < 1) {
325     *aEndPageRange = 1;
326   } else {
327     int32_t end(lstRanges[0].end);
328     for (gint ii = 1; ii < ctRanges; ii++) {
329       end = std::max(lstRanges[ii].end, end);
330     }
331     *aEndPageRange = end + 1;
332   }
333 
334   g_free(lstRanges);
335   return NS_OK;
336 }
337 NS_IMETHODIMP
SetEndPageRange(int32_t aEndPageRange)338 nsPrintSettingsGTK::SetEndPageRange(int32_t aEndPageRange)
339 {
340   int32_t startRange;
341   GetStartPageRange(&startRange);
342 
343   GtkPageRange gtkRange;
344   gtkRange.start = startRange - 1;
345   gtkRange.end = aEndPageRange - 1;
346 
347   gtk_print_settings_set_page_ranges(mPrintSettings, &gtkRange, 1);
348 
349   return NS_OK;
350 }
351 
352 NS_IMETHODIMP
GetPrintReversed(bool * aPrintReversed)353 nsPrintSettingsGTK::GetPrintReversed(bool *aPrintReversed)
354 {
355   *aPrintReversed = gtk_print_settings_get_reverse(mPrintSettings);
356   return NS_OK;
357 }
358 NS_IMETHODIMP
SetPrintReversed(bool aPrintReversed)359 nsPrintSettingsGTK::SetPrintReversed(bool aPrintReversed)
360 {
361   gtk_print_settings_set_reverse(mPrintSettings, aPrintReversed);
362   return NS_OK;
363 }
364 
365 NS_IMETHODIMP
GetPrintInColor(bool * aPrintInColor)366 nsPrintSettingsGTK::GetPrintInColor(bool *aPrintInColor)
367 {
368   *aPrintInColor = gtk_print_settings_get_use_color(mPrintSettings);
369   return NS_OK;
370 }
371 NS_IMETHODIMP
SetPrintInColor(bool aPrintInColor)372 nsPrintSettingsGTK::SetPrintInColor(bool aPrintInColor)
373 {
374   gtk_print_settings_set_use_color(mPrintSettings, aPrintInColor);
375   return NS_OK;
376 }
377 
378 NS_IMETHODIMP
GetOrientation(int32_t * aOrientation)379 nsPrintSettingsGTK::GetOrientation(int32_t *aOrientation)
380 {
381   NS_ENSURE_ARG_POINTER(aOrientation);
382 
383   GtkPageOrientation gtkOrient = gtk_page_setup_get_orientation(mPageSetup);
384   switch (gtkOrient) {
385     case GTK_PAGE_ORIENTATION_LANDSCAPE:
386     case GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE:
387       *aOrientation = kLandscapeOrientation;
388       break;
389 
390     case GTK_PAGE_ORIENTATION_PORTRAIT:
391     case GTK_PAGE_ORIENTATION_REVERSE_PORTRAIT:
392     default:
393       *aOrientation = kPortraitOrientation;
394   }
395   return NS_OK;
396 }
397 NS_IMETHODIMP
SetOrientation(int32_t aOrientation)398 nsPrintSettingsGTK::SetOrientation(int32_t aOrientation)
399 {
400   GtkPageOrientation gtkOrient;
401   if (aOrientation == kLandscapeOrientation)
402     gtkOrient = GTK_PAGE_ORIENTATION_LANDSCAPE;
403   else
404     gtkOrient = GTK_PAGE_ORIENTATION_PORTRAIT;
405 
406   gtk_print_settings_set_orientation(mPrintSettings, gtkOrient);
407   gtk_page_setup_set_orientation(mPageSetup, gtkOrient);
408   return NS_OK;
409 }
410 
411 NS_IMETHODIMP
GetToFileName(char16_t ** aToFileName)412 nsPrintSettingsGTK::GetToFileName(char16_t * *aToFileName)
413 {
414   // Get the gtk output filename
415   const char* gtk_output_uri = gtk_print_settings_get(mPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_URI);
416   if (!gtk_output_uri) {
417     *aToFileName = ToNewUnicode(mToFileName);
418     return NS_OK;
419   }
420 
421   // Convert to an nsIFile
422   nsCOMPtr<nsIFile> file;
423   nsresult rv = NS_GetFileFromURLSpec(nsDependentCString(gtk_output_uri),
424                                       getter_AddRefs(file));
425   if (NS_FAILED(rv))
426     return rv;
427 
428   // Extract the path
429   nsAutoString path;
430   rv = file->GetPath(path);
431   NS_ENSURE_SUCCESS(rv, rv);
432 
433   *aToFileName = ToNewUnicode(path);
434   return NS_OK;
435 }
436 
437 NS_IMETHODIMP
SetToFileName(const char16_t * aToFileName)438 nsPrintSettingsGTK::SetToFileName(const char16_t * aToFileName)
439 {
440   if (aToFileName[0] == 0) {
441     mToFileName.SetLength(0);
442     gtk_print_settings_set(mPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_URI,
443                            nullptr);
444     return NS_OK;
445   }
446 
447   if (StringEndsWith(nsDependentString(aToFileName), NS_LITERAL_STRING(".ps"))) {
448     gtk_print_settings_set(mPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT, "ps");
449   } else {
450     gtk_print_settings_set(mPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_FILE_FORMAT, "pdf");
451   }
452 
453   nsCOMPtr<nsIFile> file;
454   nsresult rv = NS_NewLocalFile(nsDependentString(aToFileName), true,
455                                 getter_AddRefs(file));
456   NS_ENSURE_SUCCESS(rv, rv);
457 
458   // Convert the nsIFile to a URL
459   nsAutoCString url;
460   rv = NS_GetURLSpecFromFile(file, url);
461   NS_ENSURE_SUCCESS(rv, rv);
462 
463   gtk_print_settings_set(mPrintSettings, GTK_PRINT_SETTINGS_OUTPUT_URI, url.get());
464   mToFileName = aToFileName;
465 
466   return NS_OK;
467 }
468 
469 NS_IMETHODIMP
GetPrinterName(char16_t ** aPrinter)470 nsPrintSettingsGTK::GetPrinterName(char16_t * *aPrinter)
471 {
472   const char* gtkPrintName = gtk_print_settings_get_printer(mPrintSettings);
473   if (!gtkPrintName) {
474     if (GTK_IS_PRINTER(mGTKPrinter)) {
475       gtkPrintName = gtk_printer_get_name(mGTKPrinter);
476     } else {
477       // This mimics what nsPrintSettingsImpl does when we try to Get before we Set
478       nsXPIDLString nullPrintName;
479       *aPrinter = ToNewUnicode(nullPrintName);
480       return NS_OK;
481     }
482   }
483   *aPrinter = UTF8ToNewUnicode(nsDependentCString(gtkPrintName));
484   return NS_OK;
485 }
486 
487 NS_IMETHODIMP
SetPrinterName(const char16_t * aPrinter)488 nsPrintSettingsGTK::SetPrinterName(const char16_t * aPrinter)
489 {
490   NS_ConvertUTF16toUTF8 gtkPrinter(aPrinter);
491 
492   if (StringBeginsWith(gtkPrinter, NS_LITERAL_CSTRING("CUPS/"))) {
493     // Strip off "CUPS/"; GTK might recognize the rest
494     gtkPrinter.Cut(0, strlen("CUPS/"));
495   }
496 
497   // Give mPrintSettings the passed-in printer name if either...
498   // - it has no printer name stored yet
499   // - it has an existing printer name that's different from
500   //   the name passed to this function.
501   const char* oldPrinterName = gtk_print_settings_get_printer(mPrintSettings);
502   if (!oldPrinterName || !gtkPrinter.Equals(oldPrinterName)) {
503     mIsInitedFromPrinter = false;
504     mIsInitedFromPrefs = false;
505     gtk_print_settings_set_printer(mPrintSettings, gtkPrinter.get());
506   }
507 
508   return NS_OK;
509 }
510 
511 NS_IMETHODIMP
GetNumCopies(int32_t * aNumCopies)512 nsPrintSettingsGTK::GetNumCopies(int32_t *aNumCopies)
513 {
514   NS_ENSURE_ARG_POINTER(aNumCopies);
515   *aNumCopies = gtk_print_settings_get_n_copies(mPrintSettings);
516   return NS_OK;
517 }
518 NS_IMETHODIMP
SetNumCopies(int32_t aNumCopies)519 nsPrintSettingsGTK::SetNumCopies(int32_t aNumCopies)
520 {
521   gtk_print_settings_set_n_copies(mPrintSettings, aNumCopies);
522   return NS_OK;
523 }
524 
525 NS_IMETHODIMP
GetScaling(double * aScaling)526 nsPrintSettingsGTK::GetScaling(double *aScaling)
527 {
528   *aScaling = gtk_print_settings_get_scale(mPrintSettings) / 100.0;
529   return NS_OK;
530 }
531 
532 NS_IMETHODIMP
SetScaling(double aScaling)533 nsPrintSettingsGTK::SetScaling(double aScaling)
534 {
535   gtk_print_settings_set_scale(mPrintSettings, aScaling * 100.0);
536   return NS_OK;
537 }
538 
539 NS_IMETHODIMP
GetPaperName(char16_t ** aPaperName)540 nsPrintSettingsGTK::GetPaperName(char16_t * *aPaperName)
541 {
542   NS_ENSURE_ARG_POINTER(aPaperName);
543   const gchar* name =
544     gtk_paper_size_get_name(gtk_page_setup_get_paper_size(mPageSetup));
545   *aPaperName = ToNewUnicode(NS_ConvertUTF8toUTF16(name));
546   return NS_OK;
547 }
548 NS_IMETHODIMP
SetPaperName(const char16_t * aPaperName)549 nsPrintSettingsGTK::SetPaperName(const char16_t * aPaperName)
550 {
551   NS_ConvertUTF16toUTF8 gtkPaperName(aPaperName);
552 
553   // Convert these Gecko names to GTK names
554   if (gtkPaperName.EqualsIgnoreCase("letter"))
555     gtkPaperName.AssignLiteral(GTK_PAPER_NAME_LETTER);
556   else if (gtkPaperName.EqualsIgnoreCase("legal"))
557     gtkPaperName.AssignLiteral(GTK_PAPER_NAME_LEGAL);
558 
559   GtkPaperSize* oldPaperSize = gtk_page_setup_get_paper_size(mPageSetup);
560   gdouble width = gtk_paper_size_get_width(oldPaperSize, GTK_UNIT_INCH);
561   gdouble height = gtk_paper_size_get_height(oldPaperSize, GTK_UNIT_INCH);
562 
563   // Try to get the display name from the name so our paper size fits in the Page Setup dialog.
564   GtkPaperSize* paperSize = gtk_paper_size_new(gtkPaperName.get());
565   GtkPaperSize* customPaperSize =
566     gtk_paper_size_new_custom(gtkPaperName.get(),
567                               gtk_paper_size_get_display_name(paperSize),
568                               width, height, GTK_UNIT_INCH);
569   gtk_paper_size_free(paperSize);
570 
571   gtk_page_setup_set_paper_size(mPageSetup, customPaperSize);
572   gtk_paper_size_free(customPaperSize);
573   SaveNewPageSize();
574   return NS_OK;
575 }
576 
577 GtkUnit
GetGTKUnit(int16_t aGeckoUnit)578 nsPrintSettingsGTK::GetGTKUnit(int16_t aGeckoUnit)
579 {
580   if (aGeckoUnit == kPaperSizeMillimeters)
581     return GTK_UNIT_MM;
582   else
583     return GTK_UNIT_INCH;
584 }
585 
586 void
SaveNewPageSize()587 nsPrintSettingsGTK::SaveNewPageSize()
588 {
589   gtk_print_settings_set_paper_size(mPrintSettings,
590                                     gtk_page_setup_get_paper_size(mPageSetup));
591 }
592 
593 void
InitUnwriteableMargin()594 nsPrintSettingsGTK::InitUnwriteableMargin()
595 {
596   mUnwriteableMargin.SizeTo(
597    NS_INCHES_TO_INT_TWIPS(gtk_page_setup_get_top_margin(mPageSetup, GTK_UNIT_INCH)),
598    NS_INCHES_TO_INT_TWIPS(gtk_page_setup_get_right_margin(mPageSetup, GTK_UNIT_INCH)),
599    NS_INCHES_TO_INT_TWIPS(gtk_page_setup_get_bottom_margin(mPageSetup, GTK_UNIT_INCH)),
600    NS_INCHES_TO_INT_TWIPS(gtk_page_setup_get_left_margin(mPageSetup, GTK_UNIT_INCH))
601   );
602 }
603 
604 /**
605  * NOTE: Need a custom set of SetUnwriteableMargin functions, because
606  * whenever we change mUnwriteableMargin, we must pass the change
607  * down to our GTKPageSetup object.  (This is needed in order for us
608  * to give the correct default values in nsPrintDialogGTK.)
609  *
610  * It's important that the following functions pass
611  * mUnwriteableMargin values rather than aUnwriteableMargin values
612  * to gtk_page_setup_set_[blank]_margin, because the two may not be
613  * the same.  (Specifically, negative values of aUnwriteableMargin
614  * are ignored by the nsPrintSettings::SetUnwriteableMargin functions.)
615  */
616 NS_IMETHODIMP
SetUnwriteableMarginInTwips(nsIntMargin & aUnwriteableMargin)617 nsPrintSettingsGTK::SetUnwriteableMarginInTwips(nsIntMargin& aUnwriteableMargin)
618 {
619   nsPrintSettings::SetUnwriteableMarginInTwips(aUnwriteableMargin);
620   gtk_page_setup_set_top_margin(mPageSetup,
621            NS_TWIPS_TO_INCHES(mUnwriteableMargin.top), GTK_UNIT_INCH);
622   gtk_page_setup_set_left_margin(mPageSetup,
623            NS_TWIPS_TO_INCHES(mUnwriteableMargin.left), GTK_UNIT_INCH);
624   gtk_page_setup_set_bottom_margin(mPageSetup,
625            NS_TWIPS_TO_INCHES(mUnwriteableMargin.bottom), GTK_UNIT_INCH);
626   gtk_page_setup_set_right_margin(mPageSetup,
627            NS_TWIPS_TO_INCHES(mUnwriteableMargin.right), GTK_UNIT_INCH);
628   return NS_OK;
629 }
630 
631 NS_IMETHODIMP
SetUnwriteableMarginTop(double aUnwriteableMarginTop)632 nsPrintSettingsGTK::SetUnwriteableMarginTop(double aUnwriteableMarginTop)
633 {
634   nsPrintSettings::SetUnwriteableMarginTop(aUnwriteableMarginTop);
635   gtk_page_setup_set_top_margin(mPageSetup,
636            NS_TWIPS_TO_INCHES(mUnwriteableMargin.top), GTK_UNIT_INCH);
637   return NS_OK;
638 }
639 
640 NS_IMETHODIMP
SetUnwriteableMarginLeft(double aUnwriteableMarginLeft)641 nsPrintSettingsGTK::SetUnwriteableMarginLeft(double aUnwriteableMarginLeft)
642 {
643   nsPrintSettings::SetUnwriteableMarginLeft(aUnwriteableMarginLeft);
644   gtk_page_setup_set_left_margin(mPageSetup,
645            NS_TWIPS_TO_INCHES(mUnwriteableMargin.left), GTK_UNIT_INCH);
646   return NS_OK;
647 }
648 
649 NS_IMETHODIMP
SetUnwriteableMarginBottom(double aUnwriteableMarginBottom)650 nsPrintSettingsGTK::SetUnwriteableMarginBottom(double aUnwriteableMarginBottom)
651 {
652   nsPrintSettings::SetUnwriteableMarginBottom(aUnwriteableMarginBottom);
653   gtk_page_setup_set_bottom_margin(mPageSetup,
654            NS_TWIPS_TO_INCHES(mUnwriteableMargin.bottom), GTK_UNIT_INCH);
655   return NS_OK;
656 }
657 
658 NS_IMETHODIMP
SetUnwriteableMarginRight(double aUnwriteableMarginRight)659 nsPrintSettingsGTK::SetUnwriteableMarginRight(double aUnwriteableMarginRight)
660 {
661   nsPrintSettings::SetUnwriteableMarginRight(aUnwriteableMarginRight);
662   gtk_page_setup_set_right_margin(mPageSetup,
663            NS_TWIPS_TO_INCHES(mUnwriteableMargin.right), GTK_UNIT_INCH);
664   return NS_OK;
665 }
666 
667 NS_IMETHODIMP
GetPaperWidth(double * aPaperWidth)668 nsPrintSettingsGTK::GetPaperWidth(double *aPaperWidth)
669 {
670   NS_ENSURE_ARG_POINTER(aPaperWidth);
671   GtkPaperSize* paperSize = gtk_page_setup_get_paper_size(mPageSetup);
672   *aPaperWidth =
673     gtk_paper_size_get_width(paperSize, GetGTKUnit(mPaperSizeUnit));
674   return NS_OK;
675 }
676 NS_IMETHODIMP
SetPaperWidth(double aPaperWidth)677 nsPrintSettingsGTK::SetPaperWidth(double aPaperWidth)
678 {
679   GtkPaperSize* paperSize = gtk_page_setup_get_paper_size(mPageSetup);
680   gtk_paper_size_set_size(paperSize,
681                           aPaperWidth,
682                           gtk_paper_size_get_height(paperSize, GetGTKUnit(mPaperSizeUnit)),
683                           GetGTKUnit(mPaperSizeUnit));
684   SaveNewPageSize();
685   return NS_OK;
686 }
687 
688 NS_IMETHODIMP
GetPaperHeight(double * aPaperHeight)689 nsPrintSettingsGTK::GetPaperHeight(double *aPaperHeight)
690 {
691   NS_ENSURE_ARG_POINTER(aPaperHeight);
692   GtkPaperSize* paperSize = gtk_page_setup_get_paper_size(mPageSetup);
693   *aPaperHeight =
694     gtk_paper_size_get_height(paperSize, GetGTKUnit(mPaperSizeUnit));
695   return NS_OK;
696 }
697 NS_IMETHODIMP
SetPaperHeight(double aPaperHeight)698 nsPrintSettingsGTK::SetPaperHeight(double aPaperHeight)
699 {
700   GtkPaperSize* paperSize = gtk_page_setup_get_paper_size(mPageSetup);
701   gtk_paper_size_set_size(paperSize,
702                           gtk_paper_size_get_width(paperSize, GetGTKUnit(mPaperSizeUnit)),
703                           aPaperHeight,
704                           GetGTKUnit(mPaperSizeUnit));
705   SaveNewPageSize();
706   return NS_OK;
707 }
708 
709 NS_IMETHODIMP
SetPaperSizeUnit(int16_t aPaperSizeUnit)710 nsPrintSettingsGTK::SetPaperSizeUnit(int16_t aPaperSizeUnit)
711 {
712   // Convert units internally. e.g. they might have set the values while we're still in mm but
713   // they change to inch just afterwards, expecting that their sizes are in inches.
714   GtkPaperSize* paperSize = gtk_page_setup_get_paper_size(mPageSetup);
715   gtk_paper_size_set_size(paperSize,
716                           gtk_paper_size_get_width(paperSize, GetGTKUnit(mPaperSizeUnit)),
717                           gtk_paper_size_get_height(paperSize, GetGTKUnit(mPaperSizeUnit)),
718                           GetGTKUnit(aPaperSizeUnit));
719   SaveNewPageSize();
720 
721   mPaperSizeUnit = aPaperSizeUnit;
722   return NS_OK;
723 }
724 
725 NS_IMETHODIMP
GetEffectivePageSize(double * aWidth,double * aHeight)726 nsPrintSettingsGTK::GetEffectivePageSize(double *aWidth, double *aHeight)
727 {
728   GtkPaperSize* paperSize = gtk_page_setup_get_paper_size(mPageSetup);
729   *aWidth  = NS_INCHES_TO_INT_TWIPS(gtk_paper_size_get_width(paperSize, GTK_UNIT_INCH));
730   *aHeight = NS_INCHES_TO_INT_TWIPS(gtk_paper_size_get_height(paperSize, GTK_UNIT_INCH));
731 
732   GtkPageOrientation gtkOrient = gtk_page_setup_get_orientation(mPageSetup);
733 
734   if (gtkOrient == GTK_PAGE_ORIENTATION_LANDSCAPE ||
735       gtkOrient == GTK_PAGE_ORIENTATION_REVERSE_LANDSCAPE) {
736     double temp = *aWidth;
737     *aWidth = *aHeight;
738     *aHeight = temp;
739   }
740   return NS_OK;
741 }
742 
743 NS_IMETHODIMP
SetupSilentPrinting()744 nsPrintSettingsGTK::SetupSilentPrinting()
745 {
746   // We have to get a printer here, rather than when the print settings are constructed.
747   // This is because when we request sync, GTK makes us wait in the *event loop* while waiting
748   // for the enumeration to finish. We must do this when event loop runs are expected.
749   gtk_enumerate_printers(printer_enumerator, this, nullptr, TRUE);
750 
751   // XXX If no default printer set, get the first one.
752   if (!GTK_IS_PRINTER(mGTKPrinter))
753     gtk_enumerate_printers(ref_printer, this, nullptr, TRUE);
754 
755   return NS_OK;
756 }
757 
758 NS_IMETHODIMP
GetPageRanges(nsTArray<int32_t> & aPages)759 nsPrintSettingsGTK::GetPageRanges(nsTArray<int32_t> &aPages)
760 {
761   gint ctRanges;
762   GtkPageRange* lstRanges = gtk_print_settings_get_page_ranges(mPrintSettings, &ctRanges);
763 
764   aPages.Clear();
765 
766   if (ctRanges > 1) {
767     for (gint i = 0; i < ctRanges; i++) {
768       aPages.AppendElement(lstRanges[i].start+1);
769       aPages.AppendElement(lstRanges[i].end+1);
770     }
771   }
772 
773   g_free(lstRanges);
774   return NS_OK;
775 }
776 
777 NS_IMETHODIMP
GetResolution(int32_t * aResolution)778 nsPrintSettingsGTK::GetResolution(int32_t *aResolution)
779 {
780   if (!gtk_print_settings_has_key(mPrintSettings, GTK_PRINT_SETTINGS_RESOLUTION))
781     return NS_ERROR_FAILURE;
782   *aResolution = gtk_print_settings_get_resolution(mPrintSettings);
783   return NS_OK;
784 }
785 
786 NS_IMETHODIMP
SetResolution(int32_t aResolution)787 nsPrintSettingsGTK::SetResolution(int32_t aResolution)
788 {
789   gtk_print_settings_set_resolution(mPrintSettings, aResolution);
790   return NS_OK;
791 }
792 
793 NS_IMETHODIMP
GetDuplex(int32_t * aDuplex)794 nsPrintSettingsGTK::GetDuplex(int32_t *aDuplex)
795 {
796   if (!gtk_print_settings_has_key(mPrintSettings, GTK_PRINT_SETTINGS_DUPLEX)) {
797     *aDuplex = GTK_PRINT_DUPLEX_SIMPLEX;
798   } else {
799     *aDuplex = gtk_print_settings_get_duplex(mPrintSettings);
800   }
801   return NS_OK;
802 }
803 
804 NS_IMETHODIMP
SetDuplex(int32_t aDuplex)805 nsPrintSettingsGTK::SetDuplex(int32_t aDuplex)
806 {
807   MOZ_ASSERT(aDuplex >= GTK_PRINT_DUPLEX_SIMPLEX &&
808              aDuplex <= GTK_PRINT_DUPLEX_VERTICAL,
809              "value is out of bounds for GtkPrintDuplex enum");
810   gtk_print_settings_set_duplex(mPrintSettings, static_cast<GtkPrintDuplex>(aDuplex));
811   return NS_OK;
812 }
813 
814