blob: 585daf4132f9afeb7f170a082df5a094e839689d [file] [log] [blame]
// Copyright (c) 2009 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 "chrome/browser/printing/print_dialog_gtk.h"
#include <gtk/gtkprintjob.h>
#include <gtk/gtkprintunixdialog.h>
#include <gtk/gtkpagesetupunixdialog.h>
#include "base/file_util.h"
#include "base/file_util_proxy.h"
#include "base/lazy_instance.h"
#include "base/lock.h"
#include "base/logging.h"
#include "base/thread_restrictions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_thread.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/tab_contents/infobar_delegate.h"
#include "chrome/browser/tab_contents/tab_contents.h"
namespace {
PrintDialogGtk* g_print_dialog = NULL;
// Used to make accesses to the above thread safe.
Lock& DialogLock() {
static base::LazyInstance<Lock> dialog_lock(base::LINKER_INITIALIZED);
return dialog_lock.Get();
}
// This is a temporary infobar designed to help gauge how many users are trying
// to print to printers that don't support PDF.
class PdfUnsupportedInfoBarDelegate : public LinkInfoBarDelegate {
public:
explicit PdfUnsupportedInfoBarDelegate(Browser* browser)
: LinkInfoBarDelegate(NULL),
browser_(browser) {
}
virtual ~PdfUnsupportedInfoBarDelegate() {}
virtual string16 GetMessageTextWithOffset(size_t* link_offset) const {
string16 message = UTF8ToUTF16("Oops! Your printer does not support PDF. "
"Please report this to us.");
*link_offset = message.length() - 1;
return message;
}
virtual string16 GetLinkText() const {
return UTF8ToUTF16("here");
}
virtual Type GetInfoBarType() { return WARNING_TYPE; }
virtual bool LinkClicked(WindowOpenDisposition disposition) {
browser_->OpenURL(
GURL("http://code.google.com/p/chromium/issues/detail?id=22027"),
GURL(), NEW_FOREGROUND_TAB, PageTransition::TYPED);
return true;
}
private:
Browser* browser_;
};
} // namespace
// static
void PrintDialogGtk::CreatePrintDialogForPdf(const FilePath& path) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
NewRunnableFunction(&PrintDialogGtk::CreateDialogImpl, path));
}
// static
bool PrintDialogGtk::DialogShowing() {
AutoLock lock(DialogLock());
return !!g_print_dialog;
}
// static
void PrintDialogGtk::CreateDialogImpl(const FilePath& path) {
// Only show one print dialog at once. This is to prevent a page from
// locking up the system with
//
// while(true){print();}
AutoLock lock(DialogLock());
if (g_print_dialog)
return;
g_print_dialog = new PrintDialogGtk(path);
}
PrintDialogGtk::PrintDialogGtk(const FilePath& path_to_pdf)
: path_to_pdf_(path_to_pdf),
browser_(BrowserList::GetLastActive()) {
GtkWindow* parent = browser_->window()->GetNativeHandle();
// TODO(estade): We need a window title here.
dialog_ = gtk_print_unix_dialog_new(NULL, parent);
g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
gtk_widget_show(dialog_);
}
PrintDialogGtk::~PrintDialogGtk() {
AutoLock lock(DialogLock());
DCHECK_EQ(this, g_print_dialog);
g_print_dialog = NULL;
}
void PrintDialogGtk::OnResponse(GtkWidget* dialog, gint response_id) {
gtk_widget_hide(dialog_);
switch (response_id) {
case GTK_RESPONSE_OK: {
GtkPrinter* printer =
gtk_print_unix_dialog_get_selected_printer(
GTK_PRINT_UNIX_DIALOG(dialog_));
if (!gtk_printer_accepts_pdf(printer)) {
browser_->GetSelectedTabContents()->AddInfoBar(
new PdfUnsupportedInfoBarDelegate(browser_));
break;
}
GtkPrintSettings* settings =
gtk_print_unix_dialog_get_settings(
GTK_PRINT_UNIX_DIALOG(dialog_));
GtkPageSetup* setup = gtk_print_unix_dialog_get_page_setup(
GTK_PRINT_UNIX_DIALOG(dialog_));
GtkPrintJob* job =
gtk_print_job_new(path_to_pdf_.value().c_str(), printer,
settings, setup);
gtk_print_job_set_source_file(job, path_to_pdf_.value().c_str(), NULL);
gtk_print_job_send(job, OnJobCompletedThunk, this, NULL);
g_object_unref(settings);
// Success; return early.
return;
}
case GTK_RESPONSE_DELETE_EVENT: // Fall through.
case GTK_RESPONSE_CANCEL: {
break;
}
case GTK_RESPONSE_APPLY:
default: {
NOTREACHED();
}
}
// Delete this dialog.
OnJobCompleted(NULL, NULL);
}
void PrintDialogGtk::OnJobCompletedThunk(GtkPrintJob* print_job,
gpointer user_data,
GError* error) {
reinterpret_cast<PrintDialogGtk*>(user_data)->OnJobCompleted(print_job,
error);
}
void PrintDialogGtk::OnJobCompleted(GtkPrintJob* job, GError* error) {
gtk_widget_destroy(dialog_);
if (error)
LOG(ERROR) << "Printing failed: " << error->message;
if (job)
g_object_unref(job);
base::FileUtilProxy::Delete(
BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
path_to_pdf_,
false,
NULL);
delete this;
}