1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/gtk/printing/print_dialog_gtk.h"
6
7 #include <gtk/gtkunixprint.h>
8
9 #include <algorithm>
10 #include <cmath>
11 #include <memory>
12 #include <string>
13 #include <utility>
14 #include <vector>
15
16 #include "base/bind.h"
17 #include "base/files/file_util.h"
18 #include "base/logging.h"
19 #include "base/macros.h"
20 #include "base/no_destructor.h"
21 #include "base/sequence_checker.h"
22 #include "base/strings/utf_string_conversions.h"
23 #include "base/task/post_task.h"
24 #include "base/task/thread_pool.h"
25 #include "base/threading/sequenced_task_runner_handle.h"
26 #include "base/values.h"
27 #include "printing/metafile.h"
28 #include "printing/print_job_constants.h"
29 #include "printing/print_settings.h"
30 #include "ui/aura/window.h"
31 #include "ui/gtk/gtk_ui.h"
32 #include "ui/gtk/gtk_ui_delegate.h"
33 #include "ui/gtk/gtk_util.h"
34 #include "ui/gtk/printing/printing_gtk_util.h"
35
36 #if defined(USE_CUPS)
37 #include "printing/mojom/print.mojom.h"
38 #endif
39
40 using printing::PageRanges;
41 using printing::PrintSettings;
42
43 namespace {
44
45 #if defined(USE_CUPS)
46 // CUPS Duplex attribute and values.
47 const char kCUPSDuplex[] = "cups-Duplex";
48 const char kDuplexNone[] = "None";
49 const char kDuplexTumble[] = "DuplexTumble";
50 const char kDuplexNoTumble[] = "DuplexNoTumble";
51 #endif
52
53 constexpr int kPaperSizeTresholdMicrons = 100;
54 constexpr int kMicronsInMm = 1000;
55
56 // Checks whether |gtk_paper_size| can be used to represent user selected media.
57 // In fuzzy match mode checks that paper sizes are "close enough" (less than
58 // 1mm difference). In the exact mode, looks for the paper with the same PPD
59 // name and "close enough" size.
PaperSizeMatch(GtkPaperSize * gtk_paper_size,const PrintSettings::RequestedMedia & media,bool fuzzy_match)60 bool PaperSizeMatch(GtkPaperSize* gtk_paper_size,
61 const PrintSettings::RequestedMedia& media,
62 bool fuzzy_match) {
63 if (!gtk_paper_size)
64 return false;
65
66 gfx::Size paper_size_microns(
67 static_cast<int>(gtk_paper_size_get_width(gtk_paper_size, GTK_UNIT_MM) *
68 kMicronsInMm +
69 0.5),
70 static_cast<int>(gtk_paper_size_get_height(gtk_paper_size, GTK_UNIT_MM) *
71 kMicronsInMm +
72 0.5));
73 int diff = std::max(
74 std::abs(paper_size_microns.width() - media.size_microns.width()),
75 std::abs(paper_size_microns.height() - media.size_microns.height()));
76 bool close_enough = diff <= kPaperSizeTresholdMicrons;
77 if (fuzzy_match)
78 return close_enough;
79
80 return close_enough && !media.vendor_id.empty() &&
81 media.vendor_id == gtk_paper_size_get_ppd_name(gtk_paper_size);
82 }
83
84 // Looks up a paper size matching (in terms of PaperSizeMatch) the user selected
85 // media in the paper size list reported by GTK. Returns nullptr if there's no
86 // match found.
FindPaperSizeMatch(GList * gtk_paper_sizes,const PrintSettings::RequestedMedia & media)87 GtkPaperSize* FindPaperSizeMatch(GList* gtk_paper_sizes,
88 const PrintSettings::RequestedMedia& media) {
89 GtkPaperSize* first_fuzzy_match = nullptr;
90 for (GList* p = gtk_paper_sizes; p && p->data; p = g_list_next(p)) {
91 GtkPaperSize* gtk_paper_size = static_cast<GtkPaperSize*>(p->data);
92 if (PaperSizeMatch(gtk_paper_size, media, false))
93 return gtk_paper_size;
94
95 if (!first_fuzzy_match && PaperSizeMatch(gtk_paper_size, media, true))
96 first_fuzzy_match = gtk_paper_size;
97 }
98 return first_fuzzy_match;
99 }
100
101 class StickyPrintSettingGtk {
102 public:
StickyPrintSettingGtk()103 StickyPrintSettingGtk() : last_used_settings_(gtk_print_settings_new()) {}
~StickyPrintSettingGtk()104 ~StickyPrintSettingGtk() {
105 NOTREACHED(); // Intended to be used with base::NoDestructor.
106 }
107
settings()108 GtkPrintSettings* settings() { return last_used_settings_; }
109
SetLastUsedSettings(GtkPrintSettings * settings)110 void SetLastUsedSettings(GtkPrintSettings* settings) {
111 DCHECK(last_used_settings_);
112 g_object_unref(last_used_settings_);
113 last_used_settings_ = gtk_print_settings_copy(settings);
114 }
115
116 private:
117 GtkPrintSettings* last_used_settings_;
118
119 DISALLOW_COPY_AND_ASSIGN(StickyPrintSettingGtk);
120 };
121
GetLastUsedSettings()122 StickyPrintSettingGtk& GetLastUsedSettings() {
123 static base::NoDestructor<StickyPrintSettingGtk> settings;
124 return *settings;
125 }
126
127 // Helper class to track GTK printers.
128 class GtkPrinterList {
129 public:
GtkPrinterList()130 GtkPrinterList() { gtk_enumerate_printers(SetPrinter, this, nullptr, TRUE); }
131
~GtkPrinterList()132 ~GtkPrinterList() {
133 for (GtkPrinter* printer : printers_)
134 g_object_unref(printer);
135 }
136
137 // Can return nullptr if there's no default printer. E.g. Printer on a laptop
138 // is "home_printer", but the laptop is at work.
default_printer()139 GtkPrinter* default_printer() { return default_printer_; }
140
141 // Can return nullptr if the printer cannot be found due to:
142 // - Printer list out of sync with printer dialog UI.
143 // - Querying for non-existant printers like 'Print to PDF'.
GetPrinterWithName(const std::string & name)144 GtkPrinter* GetPrinterWithName(const std::string& name) {
145 if (name.empty())
146 return nullptr;
147
148 for (GtkPrinter* printer : printers_) {
149 if (gtk_printer_get_name(printer) == name)
150 return printer;
151 }
152
153 return nullptr;
154 }
155
156 private:
157 // Callback function used by gtk_enumerate_printers() to get all printer.
SetPrinter(GtkPrinter * printer,gpointer data)158 static gboolean SetPrinter(GtkPrinter* printer, gpointer data) {
159 GtkPrinterList* printer_list = reinterpret_cast<GtkPrinterList*>(data);
160 if (gtk_printer_is_default(printer))
161 printer_list->default_printer_ = printer;
162
163 g_object_ref(printer);
164 printer_list->printers_.push_back(printer);
165
166 return FALSE;
167 }
168
169 std::vector<GtkPrinter*> printers_;
170 GtkPrinter* default_printer_ = nullptr;
171 };
172
173 } // namespace
174
175 // static
CreatePrintDialog(PrintingContextLinux * context)176 printing::PrintDialogGtkInterface* PrintDialogGtk::CreatePrintDialog(
177 PrintingContextLinux* context) {
178 return new PrintDialogGtk(context);
179 }
180
PrintDialogGtk(PrintingContextLinux * context)181 PrintDialogGtk::PrintDialogGtk(PrintingContextLinux* context)
182 : base::RefCountedDeleteOnSequence<PrintDialogGtk>(
183 base::SequencedTaskRunnerHandle::Get()),
184 context_(context) {}
185
~PrintDialogGtk()186 PrintDialogGtk::~PrintDialogGtk() {
187 DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
188
189 if (dialog_) {
190 aura::Window* parent = gtk::GetAuraTransientParent(dialog_);
191 if (parent) {
192 parent->RemoveObserver(this);
193 gtk::ClearAuraTransientParent(dialog_, parent);
194 }
195 gtk_widget_destroy(dialog_);
196 dialog_ = nullptr;
197 }
198 if (gtk_settings_) {
199 g_object_unref(gtk_settings_);
200 gtk_settings_ = nullptr;
201 }
202 if (page_setup_) {
203 g_object_unref(page_setup_);
204 page_setup_ = nullptr;
205 }
206 if (printer_) {
207 g_object_unref(printer_);
208 printer_ = nullptr;
209 }
210 }
211
UseDefaultSettings()212 void PrintDialogGtk::UseDefaultSettings() {
213 DCHECK(!page_setup_);
214 DCHECK(!printer_);
215
216 // |gtk_settings_| is a new copy.
217 gtk_settings_ = gtk_print_settings_copy(GetLastUsedSettings().settings());
218 page_setup_ = gtk_page_setup_new();
219
220 InitPrintSettings(std::make_unique<PrintSettings>());
221 }
222
UpdateSettings(std::unique_ptr<printing::PrintSettings> settings)223 void PrintDialogGtk::UpdateSettings(
224 std::unique_ptr<printing::PrintSettings> settings) {
225 if (!gtk_settings_)
226 gtk_settings_ = gtk_print_settings_copy(GetLastUsedSettings().settings());
227
228 auto printer_list = std::make_unique<GtkPrinterList>();
229 printer_ = printer_list->GetPrinterWithName(
230 base::UTF16ToUTF8(settings->device_name()));
231 if (printer_) {
232 g_object_ref(printer_);
233 gtk_print_settings_set_printer(gtk_settings_,
234 gtk_printer_get_name(printer_));
235 if (!page_setup_) {
236 page_setup_ = gtk_printer_get_default_page_size(printer_);
237 }
238 }
239
240 gtk_print_settings_set_n_copies(gtk_settings_, settings->copies());
241 gtk_print_settings_set_collate(gtk_settings_, settings->collate());
242 if (settings->dpi_horizontal() > 0 && settings->dpi_vertical() > 0) {
243 gtk_print_settings_set_resolution_xy(
244 gtk_settings_, settings->dpi_horizontal(), settings->dpi_vertical());
245 #if defined(USE_CUPS)
246 std::string dpi = base::NumberToString(settings->dpi_horizontal());
247 if (settings->dpi_horizontal() != settings->dpi_vertical())
248 dpi += "x" + base::NumberToString(settings->dpi_vertical());
249 dpi += "dpi";
250
251 // The resolution attribute (case-insensitive) has decent coverage
252 // in the CUPS PPD API (Resolution, SetResolution, JCLResolution,
253 // CNRes_PGP). See
254 // https://chromium.googlesource.com/chromiumos/third_party/cups/+/49a182a4c42d/cups/mark.c#266
255 // for more information.
256 //
257 // Many PPDs use pdftopdf directly to generate the print data and pdftopdf
258 // uses the CUPS PPD API internally to handle resolution selection.
259 //
260 // Many third-party filters such as the Brother print filter that
261 // do not use the CUPS PPD API are case sensitive and tend to support
262 // the Resolution PPD attribute. For this reason "cups-Resolution"
263 // makes the most sense here.
264 //
265 // TODO(crbug.com/1119956): Since PrintBackendCUPS parses the PPD file in
266 // Chromium, it should be possible to store the resolution attribute name
267 // as well as a map from the gfx::Size resolution to the std::string
268 // serialized value (in case a non-standard value such as 500x500dpi is
269 // present) in the PrinterCapsAndDefaults object. This object then needs to
270 // be passed over here (there are a couple ways this can be done) where it
271 // can be used to lookup the CUPS PPD resolution name and serialized DPI
272 // value to use. The main benefit of the approach would be full support
273 // for the HPPrintQuality and LXResolution PPD attributes which some PPD
274 // files use.
275 gtk_print_settings_set(gtk_settings_, "cups-Resolution", dpi.c_str());
276 #endif
277 }
278
279 #if defined(USE_CUPS)
280 // Set advanced settings first so they can be overridden by user applied
281 // settings.
282 for (const auto& pair : settings->advanced_settings()) {
283 if (!pair.second.is_string())
284 continue;
285 static constexpr char kSettingNamePrefix[] = "cups-";
286 const std::string setting_name = kSettingNamePrefix + pair.first;
287 gtk_print_settings_set(gtk_settings_, setting_name.c_str(),
288 pair.second.GetString().c_str());
289 }
290
291 std::string color_value;
292 std::string color_setting_name;
293 printing::GetColorModelForModel(settings->color(), &color_setting_name,
294 &color_value);
295 gtk_print_settings_set(gtk_settings_, color_setting_name.c_str(),
296 color_value.c_str());
297
298 if (settings->duplex_mode() !=
299 printing::mojom::DuplexMode::kUnknownDuplexMode) {
300 const char* cups_duplex_mode = nullptr;
301 switch (settings->duplex_mode()) {
302 case printing::mojom::DuplexMode::kLongEdge:
303 cups_duplex_mode = kDuplexNoTumble;
304 break;
305 case printing::mojom::DuplexMode::kShortEdge:
306 cups_duplex_mode = kDuplexTumble;
307 break;
308 case printing::mojom::DuplexMode::kSimplex:
309 cups_duplex_mode = kDuplexNone;
310 break;
311 default: // kUnknownDuplexMode
312 NOTREACHED();
313 break;
314 }
315 gtk_print_settings_set(gtk_settings_, kCUPSDuplex, cups_duplex_mode);
316 }
317 #endif
318
319 if (!page_setup_)
320 page_setup_ = gtk_page_setup_new();
321
322 if (page_setup_ && !settings->requested_media().IsDefault()) {
323 const PrintSettings::RequestedMedia& requested_media =
324 settings->requested_media();
325 GtkPaperSize* gtk_current_paper_size =
326 gtk_page_setup_get_paper_size(page_setup_);
327 if (!PaperSizeMatch(gtk_current_paper_size, requested_media,
328 true /*fuzzy_match*/)) {
329 GList* gtk_paper_sizes =
330 gtk_paper_size_get_paper_sizes(false /*include_custom*/);
331 if (gtk_paper_sizes) {
332 GtkPaperSize* matching_gtk_paper_size =
333 FindPaperSizeMatch(gtk_paper_sizes, requested_media);
334 if (matching_gtk_paper_size) {
335 VLOG(1) << "Using listed paper size";
336 gtk_page_setup_set_paper_size(page_setup_, matching_gtk_paper_size);
337 } else {
338 VLOG(1) << "Using custom paper size";
339 GtkPaperSize* custom_size = gtk_paper_size_new_custom(
340 requested_media.vendor_id.c_str(),
341 requested_media.vendor_id.c_str(),
342 requested_media.size_microns.width() / kMicronsInMm,
343 requested_media.size_microns.height() / kMicronsInMm,
344 GTK_UNIT_MM);
345 gtk_page_setup_set_paper_size(page_setup_, custom_size);
346 gtk_paper_size_free(custom_size);
347 }
348 g_list_free_full(gtk_paper_sizes,
349 reinterpret_cast<GDestroyNotify>(gtk_paper_size_free));
350 }
351 } else {
352 VLOG(1) << "Using default paper size";
353 }
354 }
355
356 gtk_print_settings_set_orientation(
357 gtk_settings_, settings->landscape() ? GTK_PAGE_ORIENTATION_LANDSCAPE
358 : GTK_PAGE_ORIENTATION_PORTRAIT);
359
360 InitPrintSettings(std::move(settings));
361 }
362
ShowDialog(gfx::NativeView parent_view,bool has_selection,PrintingContextLinux::PrintSettingsCallback callback)363 void PrintDialogGtk::ShowDialog(
364 gfx::NativeView parent_view,
365 bool has_selection,
366 PrintingContextLinux::PrintSettingsCallback callback) {
367 callback_ = std::move(callback);
368 DCHECK(callback_);
369
370 dialog_ = gtk_print_unix_dialog_new(nullptr, nullptr);
371 gtk::SetGtkTransientForAura(dialog_, parent_view);
372 if (parent_view)
373 parent_view->AddObserver(this);
374 g_signal_connect(dialog_, "delete-event",
375 G_CALLBACK(gtk_widget_hide_on_delete), nullptr);
376
377 // Handle the case when the existing |gtk_settings_| has "selection" selected
378 // as the page range, but |has_selection| is false.
379 if (!has_selection) {
380 GtkPrintPages range = gtk_print_settings_get_print_pages(gtk_settings_);
381 if (range == GTK_PRINT_PAGES_SELECTION)
382 gtk_print_settings_set_print_pages(gtk_settings_, GTK_PRINT_PAGES_ALL);
383 }
384
385 // Set modal so user cannot focus the same tab and press print again.
386 gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);
387
388 // Since we only generate PDF, only show printers that support PDF.
389 // TODO(thestig) Add more capabilities to support?
390 GtkPrintCapabilities cap = static_cast<GtkPrintCapabilities>(
391 GTK_PRINT_CAPABILITY_GENERATE_PS | GTK_PRINT_CAPABILITY_GENERATE_PDF | GTK_PRINT_CAPABILITY_PAGE_SET |
392 GTK_PRINT_CAPABILITY_COPIES | GTK_PRINT_CAPABILITY_COLLATE |
393 GTK_PRINT_CAPABILITY_REVERSE);
394 gtk_print_unix_dialog_set_manual_capabilities(GTK_PRINT_UNIX_DIALOG(dialog_),
395 cap);
396 gtk_print_unix_dialog_set_embed_page_setup(GTK_PRINT_UNIX_DIALOG(dialog_),
397 TRUE);
398 gtk_print_unix_dialog_set_support_selection(GTK_PRINT_UNIX_DIALOG(dialog_),
399 TRUE);
400 gtk_print_unix_dialog_set_has_selection(GTK_PRINT_UNIX_DIALOG(dialog_),
401 has_selection);
402 gtk_print_unix_dialog_set_settings(GTK_PRINT_UNIX_DIALOG(dialog_),
403 gtk_settings_);
404 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
405 gtk_widget_show(dialog_);
406
407 gtk::GtkUi::GetDelegate()->ShowGtkWindow(GTK_WINDOW(dialog_));
408 }
409
PrintDocument(const printing::MetafilePlayer & metafile,const base::string16 & document_name)410 void PrintDialogGtk::PrintDocument(const printing::MetafilePlayer& metafile,
411 const base::string16& document_name) {
412 // This runs on the print worker thread, does not block the UI thread.
413 DCHECK(!owning_task_runner()->RunsTasksInCurrentSequence());
414
415 // The document printing tasks can outlive the PrintingContext that created
416 // this dialog.
417 AddRef();
418
419 bool success = base::CreateTemporaryFile(&path_to_pdf_);
420
421 if (success) {
422 base::File file;
423 file.Initialize(path_to_pdf_,
424 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
425 success = metafile.SaveTo(&file);
426 file.Close();
427 if (!success)
428 base::DeleteFile(path_to_pdf_);
429 }
430
431 if (!success) {
432 LOG(ERROR) << "Saving metafile failed";
433 // Matches AddRef() above.
434 Release();
435 return;
436 }
437
438 // No errors, continue printing.
439 owning_task_runner()->PostTask(
440 FROM_HERE, base::BindOnce(&PrintDialogGtk::SendDocumentToPrinter, this,
441 document_name));
442 }
443
AddRefToDialog()444 void PrintDialogGtk::AddRefToDialog() {
445 AddRef();
446 }
447
ReleaseDialog()448 void PrintDialogGtk::ReleaseDialog() {
449 Release();
450 }
451
OnResponse(GtkWidget * dialog,int response_id)452 void PrintDialogGtk::OnResponse(GtkWidget* dialog, int response_id) {
453 int num_matched_handlers = g_signal_handlers_disconnect_by_func(
454 dialog_, reinterpret_cast<gpointer>(&OnResponseThunk), this);
455 CHECK_EQ(1, num_matched_handlers);
456
457 gtk_widget_hide(dialog_);
458
459 switch (response_id) {
460 case GTK_RESPONSE_OK: {
461 if (gtk_settings_)
462 g_object_unref(gtk_settings_);
463 gtk_settings_ =
464 gtk_print_unix_dialog_get_settings(GTK_PRINT_UNIX_DIALOG(dialog_));
465
466 if (printer_)
467 g_object_unref(printer_);
468 printer_ = gtk_print_unix_dialog_get_selected_printer(
469 GTK_PRINT_UNIX_DIALOG(dialog_));
470 g_object_ref(printer_);
471
472 if (page_setup_)
473 g_object_unref(page_setup_);
474 page_setup_ =
475 gtk_print_unix_dialog_get_page_setup(GTK_PRINT_UNIX_DIALOG(dialog_));
476 g_object_ref(page_setup_);
477
478 // Handle page ranges.
479 PageRanges ranges_vector;
480 gint num_ranges;
481 bool print_selection_only = false;
482 switch (gtk_print_settings_get_print_pages(gtk_settings_)) {
483 case GTK_PRINT_PAGES_RANGES: {
484 GtkPageRange* gtk_range =
485 gtk_print_settings_get_page_ranges(gtk_settings_, &num_ranges);
486 if (gtk_range) {
487 for (int i = 0; i < num_ranges; ++i) {
488 printing::PageRange range;
489 range.from = gtk_range[i].start;
490 range.to = gtk_range[i].end;
491 ranges_vector.push_back(range);
492 }
493 g_free(gtk_range);
494 }
495 break;
496 }
497 case GTK_PRINT_PAGES_SELECTION:
498 print_selection_only = true;
499 break;
500 case GTK_PRINT_PAGES_ALL:
501 // Leave |ranges_vector| empty to indicate print all pages.
502 break;
503 case GTK_PRINT_PAGES_CURRENT:
504 default:
505 NOTREACHED();
506 break;
507 }
508
509 auto settings = std::make_unique<PrintSettings>();
510 settings->set_is_modifiable(context_->settings().is_modifiable());
511 settings->set_ranges(ranges_vector);
512 settings->set_selection_only(print_selection_only);
513 InitPrintSettingsGtk(gtk_settings_, page_setup_, settings.get());
514 context_->InitWithSettings(std::move(settings));
515 std::move(callback_).Run(PrintingContextLinux::OK);
516 return;
517 }
518 case GTK_RESPONSE_DELETE_EVENT: // Fall through.
519 case GTK_RESPONSE_CANCEL: {
520 std::move(callback_).Run(PrintingContextLinux::CANCEL);
521 return;
522 }
523 case GTK_RESPONSE_APPLY:
524 default: {
525 NOTREACHED();
526 }
527 }
528 }
529
OnJobCompletedThunk(GtkPrintJob * print_job,gpointer user_data,const GError * error)530 static void OnJobCompletedThunk(GtkPrintJob* print_job,
531 gpointer user_data,
532 const GError* error) {
533 static_cast<PrintDialogGtk*>(user_data)->OnJobCompleted(print_job, error);
534 }
SendDocumentToPrinter(const base::string16 & document_name)535 void PrintDialogGtk::SendDocumentToPrinter(
536 const base::string16& document_name) {
537 DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
538
539 // If |printer_| is nullptr then somehow the GTK printer list changed out
540 // under us. In which case, just bail out.
541 if (!printer_) {
542 // Matches AddRef() in PrintDocument();
543 Release();
544 return;
545 }
546
547 // Save the settings for next time.
548 GetLastUsedSettings().SetLastUsedSettings(gtk_settings_);
549
550 GtkPrintJob* print_job =
551 gtk_print_job_new(base::UTF16ToUTF8(document_name).c_str(), printer_,
552 gtk_settings_, page_setup_);
553 gtk_print_job_set_source_file(print_job, path_to_pdf_.value().c_str(),
554 nullptr);
555 gtk_print_job_send(print_job, OnJobCompletedThunk, this, nullptr);
556 }
557
OnJobCompleted(GtkPrintJob * print_job,const GError * error)558 void PrintDialogGtk::OnJobCompleted(GtkPrintJob* print_job,
559 const GError* error) {
560 if (error)
561 LOG(ERROR) << "Printing failed: " << error->message;
562 if (print_job)
563 g_object_unref(print_job);
564
565 base::ThreadPool::PostTask(
566 FROM_HERE,
567 {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
568 base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
569 base::BindOnce(base::GetDeleteFileCallback(), path_to_pdf_));
570 // Printing finished. Matches AddRef() in PrintDocument();
571 Release();
572 }
573
InitPrintSettings(std::unique_ptr<PrintSettings> settings)574 void PrintDialogGtk::InitPrintSettings(
575 std::unique_ptr<PrintSettings> settings) {
576 InitPrintSettingsGtk(gtk_settings_, page_setup_, settings.get());
577 context_->InitWithSettings(std::move(settings));
578 }
579
OnWindowDestroying(aura::Window * window)580 void PrintDialogGtk::OnWindowDestroying(aura::Window* window) {
581 DCHECK_EQ(gtk::GetAuraTransientParent(dialog_), window);
582
583 gtk::ClearAuraTransientParent(dialog_, window);
584 window->RemoveObserver(this);
585 if (callback_)
586 std::move(callback_).Run(PrintingContextLinux::CANCEL);
587 }
588