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