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