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