summaryrefslogtreecommitdiff
path: root/chromium/ui/gtk/printing
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/gtk/printing')
-rw-r--r--chromium/ui/gtk/printing/OWNERS3
-rw-r--r--chromium/ui/gtk/printing/print_dialog_gtk.cc551
-rw-r--r--chromium/ui/gtk/printing/print_dialog_gtk.h89
-rw-r--r--chromium/ui/gtk/printing/printing_gtk_util.cc96
-rw-r--r--chromium/ui/gtk/printing/printing_gtk_util.h27
5 files changed, 766 insertions, 0 deletions
diff --git a/chromium/ui/gtk/printing/OWNERS b/chromium/ui/gtk/printing/OWNERS
new file mode 100644
index 00000000000..d50bb849014
--- /dev/null
+++ b/chromium/ui/gtk/printing/OWNERS
@@ -0,0 +1,3 @@
+file://printing/OWNERS
+
+# COMPONENT: Internals>Printing
diff --git a/chromium/ui/gtk/printing/print_dialog_gtk.cc b/chromium/ui/gtk/printing/print_dialog_gtk.cc
new file mode 100644
index 00000000000..57900d2854d
--- /dev/null
+++ b/chromium/ui/gtk/printing/print_dialog_gtk.cc
@@ -0,0 +1,551 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gtk/printing/print_dialog_gtk.h"
+
+#include <gtk/gtkunixprint.h>
+
+#include <algorithm>
+#include <cmath>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/no_destructor.h"
+#include "base/sequence_checker.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "base/task/thread_pool.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/values.h"
+#include "printing/metafile.h"
+#include "printing/print_job_constants.h"
+#include "printing/print_settings.h"
+#include "ui/aura/window.h"
+#include "ui/gtk/gtk_ui.h"
+#include "ui/gtk/gtk_ui_delegate.h"
+#include "ui/gtk/gtk_util.h"
+#include "ui/gtk/printing/printing_gtk_util.h"
+
+#if defined(USE_CUPS)
+#include "printing/mojom/print.mojom.h"
+#endif
+
+using printing::PageRanges;
+using printing::PrintSettings;
+
+namespace {
+
+#if defined(USE_CUPS)
+// CUPS Duplex attribute and values.
+const char kCUPSDuplex[] = "cups-Duplex";
+const char kDuplexNone[] = "None";
+const char kDuplexTumble[] = "DuplexTumble";
+const char kDuplexNoTumble[] = "DuplexNoTumble";
+#endif
+
+constexpr int kPaperSizeTresholdMicrons = 100;
+constexpr int kMicronsInMm = 1000;
+
+// Checks whether |gtk_paper_size| can be used to represent user selected media.
+// In fuzzy match mode checks that paper sizes are "close enough" (less than
+// 1mm difference). In the exact mode, looks for the paper with the same PPD
+// name and "close enough" size.
+bool PaperSizeMatch(GtkPaperSize* gtk_paper_size,
+ const PrintSettings::RequestedMedia& media,
+ bool fuzzy_match) {
+ if (!gtk_paper_size)
+ return false;
+
+ gfx::Size paper_size_microns(
+ static_cast<int>(gtk_paper_size_get_width(gtk_paper_size, GTK_UNIT_MM) *
+ kMicronsInMm +
+ 0.5),
+ static_cast<int>(gtk_paper_size_get_height(gtk_paper_size, GTK_UNIT_MM) *
+ kMicronsInMm +
+ 0.5));
+ int diff = std::max(
+ std::abs(paper_size_microns.width() - media.size_microns.width()),
+ std::abs(paper_size_microns.height() - media.size_microns.height()));
+ bool close_enough = diff <= kPaperSizeTresholdMicrons;
+ if (fuzzy_match)
+ return close_enough;
+
+ return close_enough && !media.vendor_id.empty() &&
+ media.vendor_id == gtk_paper_size_get_ppd_name(gtk_paper_size);
+}
+
+// Looks up a paper size matching (in terms of PaperSizeMatch) the user selected
+// media in the paper size list reported by GTK. Returns nullptr if there's no
+// match found.
+GtkPaperSize* FindPaperSizeMatch(GList* gtk_paper_sizes,
+ const PrintSettings::RequestedMedia& media) {
+ GtkPaperSize* first_fuzzy_match = nullptr;
+ for (GList* p = gtk_paper_sizes; p && p->data; p = g_list_next(p)) {
+ GtkPaperSize* gtk_paper_size = static_cast<GtkPaperSize*>(p->data);
+ if (PaperSizeMatch(gtk_paper_size, media, false))
+ return gtk_paper_size;
+
+ if (!first_fuzzy_match && PaperSizeMatch(gtk_paper_size, media, true))
+ first_fuzzy_match = gtk_paper_size;
+ }
+ return first_fuzzy_match;
+}
+
+class StickyPrintSettingGtk {
+ public:
+ StickyPrintSettingGtk() : last_used_settings_(gtk_print_settings_new()) {}
+ ~StickyPrintSettingGtk() {
+ NOTREACHED(); // Intended to be used with base::NoDestructor.
+ }
+
+ GtkPrintSettings* settings() { return last_used_settings_; }
+
+ void SetLastUsedSettings(GtkPrintSettings* settings) {
+ DCHECK(last_used_settings_);
+ g_object_unref(last_used_settings_);
+ last_used_settings_ = gtk_print_settings_copy(settings);
+ }
+
+ private:
+ GtkPrintSettings* last_used_settings_;
+
+ DISALLOW_COPY_AND_ASSIGN(StickyPrintSettingGtk);
+};
+
+StickyPrintSettingGtk& GetLastUsedSettings() {
+ static base::NoDestructor<StickyPrintSettingGtk> settings;
+ return *settings;
+}
+
+// Helper class to track GTK printers.
+class GtkPrinterList {
+ public:
+ GtkPrinterList() { gtk_enumerate_printers(SetPrinter, this, nullptr, TRUE); }
+
+ ~GtkPrinterList() {
+ for (GtkPrinter* printer : printers_)
+ g_object_unref(printer);
+ }
+
+ // Can return nullptr if there's no default printer. E.g. Printer on a laptop
+ // is "home_printer", but the laptop is at work.
+ GtkPrinter* default_printer() { return default_printer_; }
+
+ // Can return nullptr if the printer cannot be found due to:
+ // - Printer list out of sync with printer dialog UI.
+ // - Querying for non-existant printers like 'Print to PDF'.
+ GtkPrinter* GetPrinterWithName(const std::string& name) {
+ if (name.empty())
+ return nullptr;
+
+ for (GtkPrinter* printer : printers_) {
+ if (gtk_printer_get_name(printer) == name)
+ return printer;
+ }
+
+ return nullptr;
+ }
+
+ private:
+ // Callback function used by gtk_enumerate_printers() to get all printer.
+ static gboolean SetPrinter(GtkPrinter* printer, gpointer data) {
+ GtkPrinterList* printer_list = reinterpret_cast<GtkPrinterList*>(data);
+ if (gtk_printer_is_default(printer))
+ printer_list->default_printer_ = printer;
+
+ g_object_ref(printer);
+ printer_list->printers_.push_back(printer);
+
+ return FALSE;
+ }
+
+ std::vector<GtkPrinter*> printers_;
+ GtkPrinter* default_printer_ = nullptr;
+};
+
+} // namespace
+
+// static
+printing::PrintDialogGtkInterface* PrintDialogGtk::CreatePrintDialog(
+ PrintingContextLinux* context) {
+ return new PrintDialogGtk(context);
+}
+
+PrintDialogGtk::PrintDialogGtk(PrintingContextLinux* context)
+ : base::RefCountedDeleteOnSequence<PrintDialogGtk>(
+ base::SequencedTaskRunnerHandle::Get()),
+ context_(context) {}
+
+PrintDialogGtk::~PrintDialogGtk() {
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
+
+ if (dialog_) {
+ aura::Window* parent = gtk::GetAuraTransientParent(dialog_);
+ if (parent) {
+ parent->RemoveObserver(this);
+ gtk::ClearAuraTransientParent(dialog_);
+ }
+ gtk_widget_destroy(dialog_);
+ dialog_ = nullptr;
+ }
+ if (gtk_settings_) {
+ g_object_unref(gtk_settings_);
+ gtk_settings_ = nullptr;
+ }
+ if (page_setup_) {
+ g_object_unref(page_setup_);
+ page_setup_ = nullptr;
+ }
+ if (printer_) {
+ g_object_unref(printer_);
+ printer_ = nullptr;
+ }
+}
+
+void PrintDialogGtk::UseDefaultSettings() {
+ DCHECK(!page_setup_);
+ DCHECK(!printer_);
+
+ // |gtk_settings_| is a new copy.
+ gtk_settings_ = gtk_print_settings_copy(GetLastUsedSettings().settings());
+ page_setup_ = gtk_page_setup_new();
+
+ InitPrintSettings(std::make_unique<PrintSettings>());
+}
+
+void PrintDialogGtk::UpdateSettings(
+ std::unique_ptr<printing::PrintSettings> settings) {
+ if (!gtk_settings_)
+ gtk_settings_ = gtk_print_settings_copy(GetLastUsedSettings().settings());
+
+ auto printer_list = std::make_unique<GtkPrinterList>();
+ printer_ = printer_list->GetPrinterWithName(
+ base::UTF16ToUTF8(settings->device_name()));
+ if (printer_) {
+ g_object_ref(printer_);
+ gtk_print_settings_set_printer(gtk_settings_,
+ gtk_printer_get_name(printer_));
+ if (!page_setup_) {
+ page_setup_ = gtk_printer_get_default_page_size(printer_);
+ }
+ }
+
+ gtk_print_settings_set_n_copies(gtk_settings_, settings->copies());
+ gtk_print_settings_set_collate(gtk_settings_, settings->collate());
+
+#if defined(USE_CUPS)
+ // Set advanced settings first so they can be overridden by user applied
+ // settings.
+ for (const auto& pair : settings->advanced_settings()) {
+ if (!pair.second.is_string())
+ continue;
+ static constexpr char kSettingNamePrefix[] = "cups-";
+ const std::string setting_name = kSettingNamePrefix + pair.first;
+ gtk_print_settings_set(gtk_settings_, setting_name.c_str(),
+ pair.second.GetString().c_str());
+ }
+
+ std::string color_value;
+ std::string color_setting_name;
+ printing::GetColorModelForMode(settings->color(), &color_setting_name,
+ &color_value);
+ gtk_print_settings_set(gtk_settings_, color_setting_name.c_str(),
+ color_value.c_str());
+
+ if (settings->duplex_mode() !=
+ printing::mojom::DuplexMode::kUnknownDuplexMode) {
+ const char* cups_duplex_mode = nullptr;
+ switch (settings->duplex_mode()) {
+ case printing::mojom::DuplexMode::kLongEdge:
+ cups_duplex_mode = kDuplexNoTumble;
+ break;
+ case printing::mojom::DuplexMode::kShortEdge:
+ cups_duplex_mode = kDuplexTumble;
+ break;
+ case printing::mojom::DuplexMode::kSimplex:
+ cups_duplex_mode = kDuplexNone;
+ break;
+ default: // kUnknownDuplexMode
+ NOTREACHED();
+ break;
+ }
+ gtk_print_settings_set(gtk_settings_, kCUPSDuplex, cups_duplex_mode);
+ }
+#endif
+
+ if (!page_setup_)
+ page_setup_ = gtk_page_setup_new();
+
+ if (page_setup_ && !settings->requested_media().IsDefault()) {
+ const PrintSettings::RequestedMedia& requested_media =
+ settings->requested_media();
+ GtkPaperSize* gtk_current_paper_size =
+ gtk_page_setup_get_paper_size(page_setup_);
+ if (!PaperSizeMatch(gtk_current_paper_size, requested_media,
+ true /*fuzzy_match*/)) {
+ GList* gtk_paper_sizes =
+ gtk_paper_size_get_paper_sizes(false /*include_custom*/);
+ if (gtk_paper_sizes) {
+ GtkPaperSize* matching_gtk_paper_size =
+ FindPaperSizeMatch(gtk_paper_sizes, requested_media);
+ if (matching_gtk_paper_size) {
+ VLOG(1) << "Using listed paper size";
+ gtk_page_setup_set_paper_size(page_setup_, matching_gtk_paper_size);
+ } else {
+ VLOG(1) << "Using custom paper size";
+ GtkPaperSize* custom_size = gtk_paper_size_new_custom(
+ requested_media.vendor_id.c_str(),
+ requested_media.vendor_id.c_str(),
+ requested_media.size_microns.width() / kMicronsInMm,
+ requested_media.size_microns.height() / kMicronsInMm,
+ GTK_UNIT_MM);
+ gtk_page_setup_set_paper_size(page_setup_, custom_size);
+ gtk_paper_size_free(custom_size);
+ }
+ g_list_free_full(gtk_paper_sizes,
+ reinterpret_cast<GDestroyNotify>(gtk_paper_size_free));
+ }
+ } else {
+ VLOG(1) << "Using default paper size";
+ }
+ }
+
+ gtk_print_settings_set_orientation(
+ gtk_settings_, settings->landscape() ? GTK_PAGE_ORIENTATION_LANDSCAPE
+ : GTK_PAGE_ORIENTATION_PORTRAIT);
+
+ InitPrintSettings(std::move(settings));
+}
+
+void PrintDialogGtk::ShowDialog(
+ gfx::NativeView parent_view,
+ bool has_selection,
+ PrintingContextLinux::PrintSettingsCallback callback) {
+ callback_ = std::move(callback);
+ DCHECK(callback_);
+
+ dialog_ = gtk_print_unix_dialog_new(nullptr, nullptr);
+ gtk::SetGtkTransientForAura(dialog_, parent_view);
+ if (parent_view)
+ parent_view->AddObserver(this);
+ g_signal_connect(dialog_, "delete-event",
+ G_CALLBACK(gtk_widget_hide_on_delete), nullptr);
+
+ // Handle the case when the existing |gtk_settings_| has "selection" selected
+ // as the page range, but |has_selection| is false.
+ if (!has_selection) {
+ GtkPrintPages range = gtk_print_settings_get_print_pages(gtk_settings_);
+ if (range == GTK_PRINT_PAGES_SELECTION)
+ gtk_print_settings_set_print_pages(gtk_settings_, GTK_PRINT_PAGES_ALL);
+ }
+
+ // Set modal so user cannot focus the same tab and press print again.
+ gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);
+
+ // Since we only generate PDF, only show printers that support PDF.
+ // TODO(thestig) Add more capabilities to support?
+ GtkPrintCapabilities cap = static_cast<GtkPrintCapabilities>(
+ GTK_PRINT_CAPABILITY_GENERATE_PDF | GTK_PRINT_CAPABILITY_PAGE_SET |
+ GTK_PRINT_CAPABILITY_COPIES | GTK_PRINT_CAPABILITY_COLLATE |
+ GTK_PRINT_CAPABILITY_REVERSE);
+ gtk_print_unix_dialog_set_manual_capabilities(GTK_PRINT_UNIX_DIALOG(dialog_),
+ cap);
+ gtk_print_unix_dialog_set_embed_page_setup(GTK_PRINT_UNIX_DIALOG(dialog_),
+ TRUE);
+ gtk_print_unix_dialog_set_support_selection(GTK_PRINT_UNIX_DIALOG(dialog_),
+ TRUE);
+ gtk_print_unix_dialog_set_has_selection(GTK_PRINT_UNIX_DIALOG(dialog_),
+ has_selection);
+ gtk_print_unix_dialog_set_settings(GTK_PRINT_UNIX_DIALOG(dialog_),
+ gtk_settings_);
+ g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
+ gtk_widget_show(dialog_);
+
+ gtk::GtkUi::GetDelegate()->ShowGtkWindow(GTK_WINDOW(dialog_));
+}
+
+void PrintDialogGtk::PrintDocument(const printing::MetafilePlayer& metafile,
+ const base::string16& document_name) {
+ // This runs on the print worker thread, does not block the UI thread.
+ DCHECK(!owning_task_runner()->RunsTasksInCurrentSequence());
+
+ // The document printing tasks can outlive the PrintingContext that created
+ // this dialog.
+ AddRef();
+
+ bool success = base::CreateTemporaryFile(&path_to_pdf_);
+
+ if (success) {
+ base::File file;
+ file.Initialize(path_to_pdf_,
+ base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+ success = metafile.SaveTo(&file);
+ file.Close();
+ if (!success)
+ base::DeleteFile(path_to_pdf_, false);
+ }
+
+ if (!success) {
+ LOG(ERROR) << "Saving metafile failed";
+ // Matches AddRef() above.
+ Release();
+ return;
+ }
+
+ // No errors, continue printing.
+ owning_task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&PrintDialogGtk::SendDocumentToPrinter, this,
+ document_name));
+}
+
+void PrintDialogGtk::AddRefToDialog() {
+ AddRef();
+}
+
+void PrintDialogGtk::ReleaseDialog() {
+ Release();
+}
+
+void PrintDialogGtk::OnResponse(GtkWidget* dialog, int response_id) {
+ int num_matched_handlers = g_signal_handlers_disconnect_by_func(
+ dialog_, reinterpret_cast<gpointer>(&OnResponseThunk), this);
+ CHECK_EQ(1, num_matched_handlers);
+
+ gtk_widget_hide(dialog_);
+
+ switch (response_id) {
+ case GTK_RESPONSE_OK: {
+ if (gtk_settings_)
+ g_object_unref(gtk_settings_);
+ gtk_settings_ =
+ gtk_print_unix_dialog_get_settings(GTK_PRINT_UNIX_DIALOG(dialog_));
+
+ if (printer_)
+ g_object_unref(printer_);
+ printer_ = gtk_print_unix_dialog_get_selected_printer(
+ GTK_PRINT_UNIX_DIALOG(dialog_));
+ g_object_ref(printer_);
+
+ if (page_setup_)
+ g_object_unref(page_setup_);
+ page_setup_ =
+ gtk_print_unix_dialog_get_page_setup(GTK_PRINT_UNIX_DIALOG(dialog_));
+ g_object_ref(page_setup_);
+
+ // Handle page ranges.
+ PageRanges ranges_vector;
+ gint num_ranges;
+ bool print_selection_only = false;
+ switch (gtk_print_settings_get_print_pages(gtk_settings_)) {
+ case GTK_PRINT_PAGES_RANGES: {
+ GtkPageRange* gtk_range =
+ gtk_print_settings_get_page_ranges(gtk_settings_, &num_ranges);
+ if (gtk_range) {
+ for (int i = 0; i < num_ranges; ++i) {
+ printing::PageRange range;
+ range.from = gtk_range[i].start;
+ range.to = gtk_range[i].end;
+ ranges_vector.push_back(range);
+ }
+ g_free(gtk_range);
+ }
+ break;
+ }
+ case GTK_PRINT_PAGES_SELECTION:
+ print_selection_only = true;
+ break;
+ case GTK_PRINT_PAGES_ALL:
+ // Leave |ranges_vector| empty to indicate print all pages.
+ break;
+ case GTK_PRINT_PAGES_CURRENT:
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ auto settings = std::make_unique<PrintSettings>();
+ settings->set_is_modifiable(context_->settings().is_modifiable());
+ settings->set_ranges(ranges_vector);
+ settings->set_selection_only(print_selection_only);
+ InitPrintSettingsGtk(gtk_settings_, page_setup_, settings.get());
+ context_->InitWithSettings(std::move(settings));
+ std::move(callback_).Run(PrintingContextLinux::OK);
+ return;
+ }
+ case GTK_RESPONSE_DELETE_EVENT: // Fall through.
+ case GTK_RESPONSE_CANCEL: {
+ std::move(callback_).Run(PrintingContextLinux::CANCEL);
+ return;
+ }
+ case GTK_RESPONSE_APPLY:
+ default: {
+ NOTREACHED();
+ }
+ }
+}
+
+static void OnJobCompletedThunk(GtkPrintJob* print_job,
+ gpointer user_data,
+ const GError* error) {
+ static_cast<PrintDialogGtk*>(user_data)->OnJobCompleted(print_job, error);
+}
+void PrintDialogGtk::SendDocumentToPrinter(
+ const base::string16& document_name) {
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
+
+ // If |printer_| is nullptr then somehow the GTK printer list changed out
+ // under us. In which case, just bail out.
+ if (!printer_) {
+ // Matches AddRef() in PrintDocument();
+ Release();
+ return;
+ }
+
+ // Save the settings for next time.
+ GetLastUsedSettings().SetLastUsedSettings(gtk_settings_);
+
+ GtkPrintJob* print_job =
+ gtk_print_job_new(base::UTF16ToUTF8(document_name).c_str(), printer_,
+ gtk_settings_, page_setup_);
+ gtk_print_job_set_source_file(print_job, path_to_pdf_.value().c_str(),
+ nullptr);
+ gtk_print_job_send(print_job, OnJobCompletedThunk, this, nullptr);
+}
+
+void PrintDialogGtk::OnJobCompleted(GtkPrintJob* print_job,
+ const GError* error) {
+ if (error)
+ LOG(ERROR) << "Printing failed: " << error->message;
+ if (print_job)
+ g_object_unref(print_job);
+
+ base::ThreadPool::PostTask(
+ FROM_HERE,
+ {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
+ base::BindOnce(base::GetDeleteFileCallback(), path_to_pdf_));
+ // Printing finished. Matches AddRef() in PrintDocument();
+ Release();
+}
+
+void PrintDialogGtk::InitPrintSettings(
+ std::unique_ptr<PrintSettings> settings) {
+ InitPrintSettingsGtk(gtk_settings_, page_setup_, settings.get());
+ context_->InitWithSettings(std::move(settings));
+}
+
+void PrintDialogGtk::OnWindowDestroying(aura::Window* window) {
+ DCHECK_EQ(gtk::GetAuraTransientParent(dialog_), window);
+
+ gtk::ClearAuraTransientParent(dialog_);
+ window->RemoveObserver(this);
+ if (callback_)
+ std::move(callback_).Run(PrintingContextLinux::CANCEL);
+}
diff --git a/chromium/ui/gtk/printing/print_dialog_gtk.h b/chromium/ui/gtk/printing/print_dialog_gtk.h
new file mode 100644
index 00000000000..f065848a163
--- /dev/null
+++ b/chromium/ui/gtk/printing/print_dialog_gtk.h
@@ -0,0 +1,89 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GTK_PRINTING_PRINT_DIALOG_GTK_H_
+#define UI_GTK_PRINTING_PRINT_DIALOG_GTK_H_
+
+#include <gtk/gtk.h>
+#include <gtk/gtkunixprint.h>
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted_delete_on_sequence.h"
+#include "printing/print_dialog_gtk_interface.h"
+#include "printing/printing_context_linux.h"
+#include "ui/aura/window_observer.h"
+#include "ui/base/glib/glib_signal.h"
+
+namespace printing {
+class MetafilePlayer;
+class PrintSettings;
+} // namespace printing
+
+using printing::PrintingContextLinux;
+
+// Needs to be freed on the UI thread to clean up its GTK members variables.
+class PrintDialogGtk : public printing::PrintDialogGtkInterface,
+ public base::RefCountedDeleteOnSequence<PrintDialogGtk>,
+ public aura::WindowObserver {
+ public:
+ // Creates and returns a print dialog.
+ static printing::PrintDialogGtkInterface* CreatePrintDialog(
+ PrintingContextLinux* context);
+
+ // printing::PrintDialogGtkInterface implementation.
+ void UseDefaultSettings() override;
+ void UpdateSettings(
+ std::unique_ptr<printing::PrintSettings> settings) override;
+ void ShowDialog(
+ gfx::NativeView parent_view,
+ bool has_selection,
+ PrintingContextLinux::PrintSettingsCallback callback) override;
+ void PrintDocument(const printing::MetafilePlayer& metafile,
+ const base::string16& document_name) override;
+ void AddRefToDialog() override;
+ void ReleaseDialog() override;
+
+ // Handles print job response.
+ void OnJobCompleted(GtkPrintJob* print_job, const GError* error);
+
+ private:
+ friend class base::RefCountedDeleteOnSequence<PrintDialogGtk>;
+ friend class base::DeleteHelper<PrintDialogGtk>;
+
+ explicit PrintDialogGtk(PrintingContextLinux* context);
+ ~PrintDialogGtk() override;
+
+ // Handles dialog response.
+ CHROMEG_CALLBACK_1(PrintDialogGtk, void, OnResponse, GtkWidget*, int);
+
+ // Prints document named |document_name|.
+ void SendDocumentToPrinter(const base::string16& document_name);
+
+ // Helper function for initializing |context_|'s PrintSettings with a given
+ // |settings|.
+ void InitPrintSettings(std::unique_ptr<printing::PrintSettings> settings);
+
+ // aura::WindowObserver implementation.
+ void OnWindowDestroying(aura::Window* window) override;
+
+ // Printing dialog callback.
+ PrintingContextLinux::PrintSettingsCallback callback_;
+ PrintingContextLinux* const context_;
+
+ // Print dialog settings. PrintDialogGtk owns |dialog_| and holds references
+ // to the other objects.
+ GtkWidget* dialog_ = nullptr;
+ GtkPrintSettings* gtk_settings_ = nullptr;
+ GtkPageSetup* page_setup_ = nullptr;
+ GtkPrinter* printer_ = nullptr;
+
+ base::FilePath path_to_pdf_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrintDialogGtk);
+};
+
+#endif // UI_GTK_PRINTING_PRINT_DIALOG_GTK_H_
diff --git a/chromium/ui/gtk/printing/printing_gtk_util.cc b/chromium/ui/gtk/printing/printing_gtk_util.cc
new file mode 100644
index 00000000000..fe3771f808b
--- /dev/null
+++ b/chromium/ui/gtk/printing/printing_gtk_util.cc
@@ -0,0 +1,96 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gtk/printing/printing_gtk_util.h"
+
+#include <gtk/gtk.h>
+#include <gtk/gtkunixprint.h>
+
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "printing/print_settings.h"
+#include "printing/printing_context_linux.h"
+#include "printing/units.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_f.h"
+
+namespace {
+
+const double kTopMarginInInch = 0.25;
+const double kBottomMarginInInch = 0.56;
+const double kLeftMarginInInch = 0.25;
+const double kRightMarginInInch = 0.25;
+
+} // namespace
+
+gfx::Size GetPdfPaperSizeDeviceUnitsGtk(
+ printing::PrintingContextLinux* context) {
+ GtkPageSetup* page_setup = gtk_page_setup_new();
+
+ gfx::SizeF paper_size(
+ gtk_page_setup_get_paper_width(page_setup, GTK_UNIT_INCH),
+ gtk_page_setup_get_paper_height(page_setup, GTK_UNIT_INCH));
+
+ g_object_unref(page_setup);
+
+ const printing::PrintSettings& settings = context->settings();
+
+ return gfx::Size(paper_size.width() * settings.device_units_per_inch(),
+ paper_size.height() * settings.device_units_per_inch());
+}
+
+void InitPrintSettingsGtk(GtkPrintSettings* settings,
+ GtkPageSetup* page_setup,
+ printing::PrintSettings* print_settings) {
+ DCHECK(settings);
+ DCHECK(page_setup);
+ DCHECK(print_settings);
+
+ base::string16 name(base::UTF8ToUTF16(
+ static_cast<const char*>(gtk_print_settings_get_printer(settings))));
+ print_settings->set_device_name(name);
+
+ gfx::Size physical_size_device_units;
+ gfx::Rect printable_area_device_units;
+ int dpi = gtk_print_settings_get_resolution(settings);
+ if (dpi) {
+ // Initialize page_setup_device_units_.
+ physical_size_device_units.SetSize(
+ gtk_page_setup_get_paper_width(page_setup, GTK_UNIT_INCH) * dpi,
+ gtk_page_setup_get_paper_height(page_setup, GTK_UNIT_INCH) * dpi);
+ printable_area_device_units.SetRect(
+ gtk_page_setup_get_left_margin(page_setup, GTK_UNIT_INCH) * dpi,
+ gtk_page_setup_get_top_margin(page_setup, GTK_UNIT_INCH) * dpi,
+ gtk_page_setup_get_page_width(page_setup, GTK_UNIT_INCH) * dpi,
+ gtk_page_setup_get_page_height(page_setup, GTK_UNIT_INCH) * dpi);
+ } else {
+ // Use default values if we cannot get valid values from the print dialog.
+ dpi = printing::kPixelsPerInch;
+ double page_width_in_pixel = printing::kLetterWidthInch * dpi;
+ double page_height_in_pixel = printing::kLetterHeightInch * dpi;
+ physical_size_device_units.SetSize(static_cast<int>(page_width_in_pixel),
+ static_cast<int>(page_height_in_pixel));
+ printable_area_device_units.SetRect(
+ static_cast<int>(kLeftMarginInInch * dpi),
+ static_cast<int>(kTopMarginInInch * dpi),
+ page_width_in_pixel - (kLeftMarginInInch + kRightMarginInInch) * dpi,
+ page_height_in_pixel - (kTopMarginInInch + kBottomMarginInInch) * dpi);
+ }
+
+ print_settings->set_dpi(dpi);
+
+ // Note: With the normal GTK print dialog, when the user selects the landscape
+ // orientation, all that does is change the paper size. Which seems to be
+ // enough to render the right output and send it to the printer.
+ // The orientation value stays as portrait and does not actually affect
+ // printing.
+ // Thus this is only useful in print preview mode, where we manually set the
+ // orientation and change the paper size ourselves.
+ GtkPageOrientation orientation = gtk_print_settings_get_orientation(settings);
+ // Set before SetPrinterPrintableArea to make it flip area if necessary.
+ print_settings->SetOrientation(orientation == GTK_PAGE_ORIENTATION_LANDSCAPE);
+ DCHECK_EQ(print_settings->device_units_per_inch(), dpi);
+ print_settings->SetPrinterPrintableArea(physical_size_device_units,
+ printable_area_device_units, true);
+}
diff --git a/chromium/ui/gtk/printing/printing_gtk_util.h b/chromium/ui/gtk/printing/printing_gtk_util.h
new file mode 100644
index 00000000000..7b41010d94a
--- /dev/null
+++ b/chromium/ui/gtk/printing/printing_gtk_util.h
@@ -0,0 +1,27 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GTK_PRINTING_PRINTING_GTK_UTIL_H_
+#define UI_GTK_PRINTING_PRINTING_GTK_UTIL_H_
+
+#include "ui/gfx/geometry/size.h"
+
+namespace printing {
+class PrintingContextLinux;
+class PrintSettings;
+} // namespace printing
+
+typedef struct _GtkPrintSettings GtkPrintSettings;
+typedef struct _GtkPageSetup GtkPageSetup;
+
+// Obtains the paper size through Gtk.
+gfx::Size GetPdfPaperSizeDeviceUnitsGtk(
+ printing::PrintingContextLinux* context);
+
+// Initializes a PrintSettings object from the provided Gtk printer objects.
+void InitPrintSettingsGtk(GtkPrintSettings* settings,
+ GtkPageSetup* page_setup,
+ printing::PrintSettings* print_settings);
+
+#endif // UI_GTK_PRINTING_PRINTING_GTK_UTIL_H_