diff options
Diffstat (limited to 'chromium/ui/gtk/printing')
-rw-r--r-- | chromium/ui/gtk/printing/OWNERS | 3 | ||||
-rw-r--r-- | chromium/ui/gtk/printing/print_dialog_gtk.cc | 551 | ||||
-rw-r--r-- | chromium/ui/gtk/printing/print_dialog_gtk.h | 89 | ||||
-rw-r--r-- | chromium/ui/gtk/printing/printing_gtk_util.cc | 96 | ||||
-rw-r--r-- | chromium/ui/gtk/printing/printing_gtk_util.h | 27 |
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_ |