Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(369)

Side by Side Diff: chrome/browser/printing/print_dialog_gtk.cc

Issue 6516022: Linux: Refactor printing to be more like Windows/Mac.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/printing/print_dialog_gtk.h ('k') | chrome/browser/printing/print_job_worker.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/printing/print_dialog_gtk.h" 5 #include "chrome/browser/printing/print_dialog_gtk.h"
6 6
7 #include <fcntl.h>
8 #include <gtk/gtkpagesetupunixdialog.h>
7 #include <gtk/gtkprintjob.h> 9 #include <gtk/gtkprintjob.h>
8 #include <gtk/gtkprintunixdialog.h> 10 #include <sys/stat.h>
9 #include <gtk/gtkpagesetupunixdialog.h> 11 #include <sys/types.h>
10 12
11 #include "base/file_util.h" 13 #include "base/file_util.h"
12 #include "base/file_util_proxy.h" 14 #include "base/file_util_proxy.h"
13 #include "base/lazy_instance.h"
14 #include "base/logging.h" 15 #include "base/logging.h"
15 #include "base/synchronization/lock.h" 16 #include "base/synchronization/waitable_event.h"
16 #include "base/threading/thread_restrictions.h" 17 #include "base/string_util.h"
17 #include "base/utf_string_conversions.h"
18 #include "chrome/browser/browser_list.h" 18 #include "chrome/browser/browser_list.h"
19 #include "chrome/browser/browser_thread.h" 19 #include "chrome/browser/browser_thread.h"
20 #include "chrome/browser/browser_window.h" 20 #include "chrome/browser/browser_window.h"
21 #include "chrome/browser/tab_contents/infobar_delegate.h" 21 #include "printing/print_settings_initializer_gtk.h"
22 #include "chrome/browser/tab_contents/tab_contents.h"
23
24 namespace {
25
26 PrintDialogGtk* g_print_dialog = NULL;
27
28 // Used to make accesses to the above thread safe.
29 base::Lock& DialogLock() {
30 static base::LazyInstance<base::Lock> dialog_lock(base::LINKER_INITIALIZED);
31 return dialog_lock.Get();
32 }
33
34 // This is a temporary infobar designed to help gauge how many users are trying
35 // to print to printers that don't support PDF.
36 class PdfUnsupportedInfoBarDelegate : public LinkInfoBarDelegate {
37 public:
38 explicit PdfUnsupportedInfoBarDelegate(Browser* browser)
39 : LinkInfoBarDelegate(NULL),
40 browser_(browser) {
41 }
42
43 virtual ~PdfUnsupportedInfoBarDelegate() {}
44
45 virtual string16 GetMessageTextWithOffset(size_t* link_offset) const {
46 string16 message = UTF8ToUTF16("Oops! Your printer does not support PDF. "
47 "Please report this to us.");
48 *link_offset = message.length() - 1;
49 return message;
50 }
51
52 virtual string16 GetLinkText() const {
53 return UTF8ToUTF16("here");
54 }
55
56 virtual Type GetInfoBarType() const { return WARNING_TYPE; }
57
58 virtual bool LinkClicked(WindowOpenDisposition disposition) {
59 browser_->OpenURL(
60 GURL("http://code.google.com/p/chromium/issues/detail?id=22027"),
61 GURL(), NEW_FOREGROUND_TAB, PageTransition::TYPED);
62 return true;
63 }
64
65 private:
66 Browser* browser_;
67 };
68
69 } // namespace
70 22
71 // static 23 // static
72 void PrintDialogGtk::CreatePrintDialogForPdf(const FilePath& path) { 24 void* PrintDialogGtk::CreatePrintDialog(
73 BrowserThread::PostTask( 25 PrintingContextCairo::PrintSettingsCallback* callback,
74 BrowserThread::UI, FROM_HERE, 26 PrintingContextCairo* context) {
75 NewRunnableFunction(&PrintDialogGtk::CreateDialogImpl, path)); 27 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
28
29 PrintDialogGtk* dialog = new PrintDialogGtk(callback, context);
30 dialog->AddRef(); // Manual AddRef since PrintingContextCairo is not suppose
Evan Stade 2011/02/14 23:30:54 nit: supposed nit: comment above the code, rather
Lei Zhang 2011/02/14 23:47:31 Done.
31 // to know about PrintDialogGtk. Thus it cannot put this
32 // ref-counted class in a scoped_refptr.
33 return dialog;
76 } 34 }
77 35
78 // static 36 // static
79 bool PrintDialogGtk::DialogShowing() { 37 void PrintDialogGtk::PrintDocument(void* print_dialog,
80 base::AutoLock lock(DialogLock()); 38 const NativeMetafile* metafile,
81 return !!g_print_dialog; 39 const string16& document_name) {
40 PrintDialogGtk* dialog = static_cast<PrintDialogGtk*>(print_dialog);
41
42 scoped_ptr<base::WaitableEvent> event;
43 event.reset(new base::WaitableEvent(false, false));
44 dialog->set_save_document_event(event.get());
45 BrowserThread::PostTask(
46 BrowserThread::FILE, FROM_HERE,
47 NewRunnableMethod(dialog,
48 &PrintDialogGtk::SaveDocumentToDisk,
49 metafile,
50 document_name));
51 event->Wait(); // Wait for SaveDocumentToDisk() to finish.
82 } 52 }
83 53
84 // static 54 PrintDialogGtk::PrintDialogGtk(
85 void PrintDialogGtk::CreateDialogImpl(const FilePath& path) { 55 PrintingContextCairo::PrintSettingsCallback* callback,
86 // Only show one print dialog at once. This is to prevent a page from 56 PrintingContextCairo* context)
87 // locking up the system with 57 : callback_(callback),
88 // 58 context_(context),
89 // while(true){print();} 59 dialog_(NULL),
90 base::AutoLock lock(DialogLock()); 60 page_setup_(NULL),
91 if (g_print_dialog) { 61 printer_(NULL),
92 // Clean up the temporary file. 62 gtk_settings_(NULL),
93 base::FileUtilProxy::Delete( 63 save_document_event_(NULL) {
94 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), 64 GtkWindow* parent = BrowserList::GetLastActive()->window()->GetNativeHandle();
95 path, false, NULL);
96 return;
97 }
98
99 g_print_dialog = new PrintDialogGtk(path);
100 }
101
102 PrintDialogGtk::PrintDialogGtk(const FilePath& path_to_pdf)
103 : path_to_pdf_(path_to_pdf),
104 browser_(BrowserList::GetLastActive()) {
105 GtkWindow* parent = browser_->window()->GetNativeHandle();
106 65
107 // TODO(estade): We need a window title here. 66 // TODO(estade): We need a window title here.
108 dialog_ = gtk_print_unix_dialog_new(NULL, parent); 67 dialog_ = gtk_print_unix_dialog_new(NULL, parent);
68 // Set modal so user cannot focus the same tab and press print again.
69 gtk_window_set_modal(GTK_WINDOW(dialog_), TRUE);
70
71 // Since we only generate PDF, only show printers that support PDF.
72 // TODO(thestig) Add more capabilities to support?
73 GtkPrintCapabilities cap = static_cast<GtkPrintCapabilities>(
74 GTK_PRINT_CAPABILITY_GENERATE_PDF |
75 GTK_PRINT_CAPABILITY_PAGE_SET |
76 GTK_PRINT_CAPABILITY_COPIES |
77 GTK_PRINT_CAPABILITY_COLLATE |
78 GTK_PRINT_CAPABILITY_REVERSE);
79 gtk_print_unix_dialog_set_manual_capabilities(GTK_PRINT_UNIX_DIALOG(dialog_),
80 cap);
81 gtk_print_unix_dialog_set_embed_page_setup(GTK_PRINT_UNIX_DIALOG(dialog_),
Lei Zhang 2011/02/14 23:47:31 This is GTK 2.18+. Does that mean I need to remove
82 TRUE);
109 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this); 83 g_signal_connect(dialog_, "response", G_CALLBACK(OnResponseThunk), this);
110 84
111 gtk_widget_show(dialog_); 85 gtk_widget_show(dialog_);
112 } 86 }
113 87
114 PrintDialogGtk::~PrintDialogGtk() { 88 PrintDialogGtk::~PrintDialogGtk() {
115 base::AutoLock lock(DialogLock()); 89 gtk_widget_destroy(dialog_);
116 DCHECK_EQ(this, g_print_dialog); 90 dialog_ = NULL;
117 g_print_dialog = NULL; 91 page_setup_ = NULL;
92 printer_ = NULL;
93 if (gtk_settings_) {
94 g_object_unref(gtk_settings_);
95 gtk_settings_ = NULL;
96 }
118 } 97 }
119 98
120 void PrintDialogGtk::OnResponse(GtkWidget* dialog, gint response_id) { 99 void PrintDialogGtk::OnResponse(GtkWidget* dialog, gint response_id) {
121 gtk_widget_hide(dialog_); 100 gtk_widget_hide(dialog_);
122 101
123 switch (response_id) { 102 switch (response_id) {
124 case GTK_RESPONSE_OK: { 103 case GTK_RESPONSE_OK: {
125 GtkPrinter* printer = 104 // |gtk_settings_| is a new object.
126 gtk_print_unix_dialog_get_selected_printer( 105 gtk_settings_ = gtk_print_unix_dialog_get_settings(
127 GTK_PRINT_UNIX_DIALOG(dialog_)); 106 GTK_PRINT_UNIX_DIALOG(dialog_));
128 // Attempt to track down bug 70166. 107 // |printer_| and |page_setup_| are owned by |dialog_|.
129 CHECK(printer != NULL); 108 page_setup_ = gtk_print_unix_dialog_get_page_setup(
130 if (!gtk_printer_accepts_pdf(printer)) { 109 GTK_PRINT_UNIX_DIALOG(dialog_));
131 browser_->GetSelectedTabContents()->AddInfoBar( 110 printer_ = gtk_print_unix_dialog_get_selected_printer(
132 new PdfUnsupportedInfoBarDelegate(browser_)); 111 GTK_PRINT_UNIX_DIALOG(dialog_));
133 break; 112
113 printing::PageRanges ranges_vector;
114 gint num_ranges;
115 GtkPageRange* gtk_range =
116 gtk_print_settings_get_page_ranges(gtk_settings_, &num_ranges);
117 if (gtk_range) {
118 for (int i = 0; i < num_ranges; ++i) {
119 printing::PageRange* range = new printing::PageRange;
120 range->from = gtk_range[i].start;
121 range->to = gtk_range[i].end;
122 ranges_vector.push_back(*range);
123 }
124 g_free(gtk_range);
134 } 125 }
135 126
136 GtkPrintSettings* settings = 127 printing::PrintSettings settings;
137 gtk_print_unix_dialog_get_settings( 128 printing::PrintSettingsInitializerGtk::InitPrintSettings(
138 GTK_PRINT_UNIX_DIALOG(dialog_)); 129 gtk_settings_, page_setup_, ranges_vector, false, &settings);
139 GtkPageSetup* setup = gtk_print_unix_dialog_get_page_setup( 130 context_->InitWithSettings(settings);
140 GTK_PRINT_UNIX_DIALOG(dialog_)); 131 callback_->Run(PrintingContextCairo::OK);
141
142 GtkPrintJob* job =
143 gtk_print_job_new(path_to_pdf_.value().c_str(), printer,
144 settings, setup);
145 gtk_print_job_set_source_file(job, path_to_pdf_.value().c_str(), NULL);
146 gtk_print_job_send(job, OnJobCompletedThunk, this, NULL);
147 g_object_unref(settings);
148 // Success; return early.
149 return; 132 return;
150 } 133 }
151 case GTK_RESPONSE_DELETE_EVENT: // Fall through. 134 case GTK_RESPONSE_DELETE_EVENT: // Fall through.
152 case GTK_RESPONSE_CANCEL: { 135 case GTK_RESPONSE_CANCEL: {
153 break; 136 callback_->Run(PrintingContextCairo::CANCEL);
137 // Fall through.
Evan Stade 2011/02/14 23:30:54 why is it unexpected to get a cancel?
Lei Zhang 2011/02/14 23:47:31 Whoops, meant to put a break there.
154 } 138 }
155 case GTK_RESPONSE_APPLY: 139 case GTK_RESPONSE_APPLY:
156 default: { 140 default: {
157 NOTREACHED(); 141 NOTREACHED();
158 } 142 }
159 } 143 }
160 144 Release(); // Printing cancelled.
Evan Stade 2011/02/14 23:30:54 from the comment, it seems like this would make mo
Lei Zhang 2011/02/14 23:47:31 Done.
161 // Delete this dialog.
162 OnJobCompleted(NULL, NULL);
163 } 145 }
164 146
147 void PrintDialogGtk::SaveDocumentToDisk(const NativeMetafile* metafile,
148 const string16& document_name) {
149 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
150
151 bool error = false;
152 if (!file_util::CreateTemporaryFile(&path_to_pdf_)) {
153 LOG(ERROR) << "Creating temporary file failed";
154 error = true;
155 }
156
157 base::FileDescriptor temp_file_fd;
158 temp_file_fd.fd = open(path_to_pdf_.value().c_str(), O_WRONLY);
Evan Stade 2011/02/14 23:30:54 seems odd to do this stuff if error is true
Lei Zhang 2011/02/14 23:47:31 Done.
159 temp_file_fd.auto_close = true;
160 if (!metafile->SaveTo(temp_file_fd)) {
161 LOG(ERROR) << "Saving metafile failed";
162 file_util::Delete(path_to_pdf_, false);
163 error = true;
164 }
165
166 // Done saving, let PrintDialogGtk::PrintDocument() continue.
167 save_document_event_->Signal();
168
169 if (error) {
170 Release(); // Error encountered, bail out.
Evan Stade 2011/02/14 23:30:54 comment a little obvious imo
Lei Zhang 2011/02/14 23:47:31 Removed.
171 } else {
172 // No errors, continue printing.
173 BrowserThread::PostTask(
174 BrowserThread::UI, FROM_HERE,
175 NewRunnableMethod(this,
176 &PrintDialogGtk::SendDocumentToPrinter,
177 document_name));
178 }
179 }
180
181 void PrintDialogGtk::SendDocumentToPrinter(const string16& document_name) {
182 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
183 GtkPrintJob* print_job = gtk_print_job_new(
184 UTF16ToASCII(document_name).c_str(),
185 printer_,
186 gtk_settings_,
187 page_setup_);
188 gtk_print_job_set_source_file(print_job, path_to_pdf_.value().c_str(), NULL);
189 gtk_print_job_send(print_job, OnJobCompletedThunk, this, NULL);
190 }
191
192 // static
165 void PrintDialogGtk::OnJobCompletedThunk(GtkPrintJob* print_job, 193 void PrintDialogGtk::OnJobCompletedThunk(GtkPrintJob* print_job,
166 gpointer user_data, 194 gpointer user_data,
167 GError* error) { 195 GError* error) {
168 reinterpret_cast<PrintDialogGtk*>(user_data)->OnJobCompleted(print_job, 196 static_cast<PrintDialogGtk*>(user_data)->OnJobCompleted(print_job, error);
169 error);
170 } 197 }
171 198
172 void PrintDialogGtk::OnJobCompleted(GtkPrintJob* job, GError* error) { 199 void PrintDialogGtk::OnJobCompleted(GtkPrintJob* print_job, GError* error) {
173 gtk_widget_destroy(dialog_);
174
175 if (error) 200 if (error)
176 LOG(ERROR) << "Printing failed: " << error->message; 201 LOG(ERROR) << "Printing failed: " << error->message;
177 202 if (print_job)
178 if (job) 203 g_object_unref(print_job);
179 g_object_unref(job);
180
181 base::FileUtilProxy::Delete( 204 base::FileUtilProxy::Delete(
182 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), 205 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
183 path_to_pdf_, 206 path_to_pdf_,
184 false, 207 false,
185 NULL); 208 NULL);
209 Release(); // Printing finished.
210 }
186 211
187 delete this; 212 void PrintDialogGtk::set_save_document_event(base::WaitableEvent* event) {
213 DCHECK(event);
214 DCHECK(!save_document_event_);
215 save_document_event_ = event;
188 } 216 }
OLDNEW
« no previous file with comments | « chrome/browser/printing/print_dialog_gtk.h ('k') | chrome/browser/printing/print_job_worker.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698