print_dialog_gtk.cc 21 KB

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