1// Copyright (c) 2012 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 5#include "chrome/browser/printing/printer_query.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/message_loop/message_loop.h" 10#include "base/threading/thread_restrictions.h" 11#include "base/values.h" 12#include "chrome/browser/printing/print_job_worker.h" 13 14namespace printing { 15 16PrinterQuery::PrinterQuery() 17 : io_message_loop_(base::MessageLoop::current()), 18 worker_(new PrintJobWorker(this)), 19 is_print_dialog_box_shown_(false), 20 cookie_(PrintSettings::NewCookie()), 21 last_status_(PrintingContext::FAILED) { 22 DCHECK_EQ(io_message_loop_->type(), base::MessageLoop::TYPE_IO); 23} 24 25PrinterQuery::~PrinterQuery() { 26 // The job should be finished (or at least canceled) when it is destroyed. 27 DCHECK(!is_print_dialog_box_shown_); 28 // If this fires, it is that this pending printer context has leaked. 29 DCHECK(!worker_.get()); 30} 31 32void PrinterQuery::GetSettingsDone(const PrintSettings& new_settings, 33 PrintingContext::Result result) { 34 is_print_dialog_box_shown_ = false; 35 last_status_ = result; 36 if (result != PrintingContext::FAILED) { 37 settings_ = new_settings; 38 cookie_ = PrintSettings::NewCookie(); 39 } else { 40 // Failure. 41 cookie_ = 0; 42 } 43 44 if (!callback_.is_null()) { 45 // This may cause reentrancy like to call StopWorker(). 46 callback_.Run(); 47 callback_.Reset(); 48 } 49} 50 51PrintJobWorker* PrinterQuery::DetachWorker(PrintJobWorkerOwner* new_owner) { 52 DCHECK(callback_.is_null()); 53 DCHECK(worker_.get()); 54 55 worker_->SetNewOwner(new_owner); 56 return worker_.release(); 57} 58 59base::MessageLoop* PrinterQuery::message_loop() { 60 return io_message_loop_; 61} 62 63const PrintSettings& PrinterQuery::settings() const { 64 return settings_; 65} 66 67int PrinterQuery::cookie() const { 68 return cookie_; 69} 70 71void PrinterQuery::GetSettings(GetSettingsAskParam ask_user_for_settings, 72 gfx::NativeView parent_view, 73 int expected_page_count, 74 bool has_selection, 75 MarginType margin_type, 76 const base::Closure& callback) { 77 DCHECK_EQ(io_message_loop_, base::MessageLoop::current()); 78 DCHECK(!is_print_dialog_box_shown_); 79 80 StartWorker(callback); 81 82 // Real work is done in PrintJobWorker::Init(). 83 is_print_dialog_box_shown_ = ask_user_for_settings == ASK_USER; 84 worker_->message_loop()->PostTask( 85 FROM_HERE, 86 base::Bind(&PrintJobWorker::GetSettings, 87 base::Unretained(worker_.get()), 88 is_print_dialog_box_shown_, parent_view, 89 expected_page_count, has_selection, margin_type)); 90} 91 92void PrinterQuery::SetSettings(const DictionaryValue& new_settings, 93 const base::Closure& callback) { 94 StartWorker(callback); 95 96 worker_->message_loop()->PostTask( 97 FROM_HERE, 98 base::Bind(&PrintJobWorker::SetSettings, 99 base::Unretained(worker_.get()), 100 new_settings.DeepCopy())); 101} 102 103void PrinterQuery::SetWorkerDestination( 104 PrintDestinationInterface* destination) { 105 worker_->SetPrintDestination(destination); 106} 107 108void PrinterQuery::StartWorker(const base::Closure& callback) { 109 DCHECK(callback_.is_null()); 110 DCHECK(worker_.get()); 111 112 // Lazily create the worker thread. There is one worker thread per print job. 113 if (!worker_->message_loop()) 114 worker_->Start(); 115 116 callback_ = callback; 117} 118 119void PrinterQuery::StopWorker() { 120 if (worker_.get()) { 121 // http://crbug.com/66082: We're blocking on the PrinterQuery's worker 122 // thread. It's not clear to me if this may result in blocking the current 123 // thread for an unacceptable time. We should probably fix it. 124 base::ThreadRestrictions::ScopedAllowIO allow_io; 125 worker_->Stop(); 126 worker_.reset(); 127 } 128} 129 130bool PrinterQuery::is_callback_pending() const { 131 return !callback_.is_null(); 132} 133 134bool PrinterQuery::is_valid() const { 135 return worker_.get() != NULL; 136} 137 138} // namespace printing 139