1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/ipc/chromium/src/base/message_pump_qt.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,190 @@ 1.4 +// Copyright (c) 2010 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#include <qabstracteventdispatcher.h> 1.9 +#include <qevent.h> 1.10 +#include <QCoreApplication> 1.11 +#include <QThread> 1.12 +#include <qtimer.h> 1.13 + 1.14 +#include "base/message_pump_qt.h" 1.15 + 1.16 +#include <fcntl.h> 1.17 +#include <limits> 1.18 +#include <math.h> 1.19 + 1.20 +#include "base/eintr_wrapper.h" 1.21 +#include "base/lazy_instance.h" 1.22 +#include "base/logging.h" 1.23 +#include "base/platform_thread.h" 1.24 + 1.25 +namespace { 1.26 +// Cached QEvent user type, registered for our event system 1.27 +static int sPokeEvent; 1.28 +} // namespace 1.29 + 1.30 +namespace base { 1.31 + 1.32 +MessagePumpForUI::MessagePumpForUI() 1.33 + : state_(NULL), 1.34 + qt_pump(*this) 1.35 +{ 1.36 +} 1.37 + 1.38 +MessagePumpForUI::~MessagePumpForUI() { 1.39 +} 1.40 + 1.41 +MessagePumpQt::MessagePumpQt(MessagePumpForUI &aPump) 1.42 + : pump(aPump), mTimer(new QTimer(this)) 1.43 +{ 1.44 + // Register our custom event type, to use in qApp event loop 1.45 + sPokeEvent = QEvent::registerEventType(); 1.46 + connect(mTimer, SIGNAL(timeout()), this, SLOT(dispatchDelayed())); 1.47 + mTimer->setSingleShot(true); 1.48 +} 1.49 + 1.50 +MessagePumpQt::~MessagePumpQt() 1.51 +{ 1.52 + mTimer->stop(); 1.53 + delete mTimer; 1.54 +} 1.55 + 1.56 +bool 1.57 +MessagePumpQt::event(QEvent *e) 1.58 +{ 1.59 + if (e->type() == sPokeEvent) { 1.60 + pump.HandleDispatch(); 1.61 + return true; 1.62 + } 1.63 + return false; 1.64 +} 1.65 + 1.66 +void 1.67 +MessagePumpQt::scheduleDelayedIfNeeded(const TimeTicks& delayed_work_time) 1.68 +{ 1.69 + if (delayed_work_time.is_null()) { 1.70 + return; 1.71 + } 1.72 + 1.73 + if (mTimer->isActive()) { 1.74 + mTimer->stop(); 1.75 + } 1.76 + 1.77 + TimeDelta later = delayed_work_time - TimeTicks::Now(); 1.78 + // later.InMilliseconds() returns an int64_t, QTimer only accepts int's for start(), 1.79 + // std::min only works on exact same types. 1.80 + int laterMsecs = later.InMilliseconds() > std::numeric_limits<int>::max() ? 1.81 + std::numeric_limits<int>::max() : later.InMilliseconds(); 1.82 + mTimer->start(laterMsecs > 0 ? laterMsecs : 0); 1.83 +} 1.84 + 1.85 +void 1.86 +MessagePumpQt::dispatchDelayed() 1.87 +{ 1.88 + pump.HandleDispatch(); 1.89 +} 1.90 + 1.91 +void MessagePumpForUI::Run(Delegate* delegate) { 1.92 + RunState state; 1.93 + state.delegate = delegate; 1.94 + state.should_quit = false; 1.95 + state.run_depth = state_ ? state_->run_depth + 1 : 1; 1.96 + // We really only do a single task for each iteration of the loop. If we 1.97 + // have done something, assume there is likely something more to do. This 1.98 + // will mean that we don't block on the message pump until there was nothing 1.99 + // more to do. We also set this to true to make sure not to block on the 1.100 + // first iteration of the loop, so RunAllPending() works correctly. 1.101 + bool more_work_is_plausible = true; 1.102 + 1.103 + RunState* previous_state = state_; 1.104 + state_ = &state; 1.105 + 1.106 + for(;;) { 1.107 + QEventLoop::ProcessEventsFlags block = QEventLoop::AllEvents; 1.108 + if (!more_work_is_plausible) { 1.109 + block |= QEventLoop::WaitForMoreEvents; 1.110 + } 1.111 + 1.112 + QAbstractEventDispatcher* dispatcher = 1.113 + QAbstractEventDispatcher::instance(QThread::currentThread()); 1.114 + // An assertion seems too much here, as during startup, 1.115 + // the dispatcher might not be ready yet. 1.116 + if (!dispatcher) { 1.117 + return; 1.118 + } 1.119 + 1.120 + // processEvent's returns true if an event has been processed. 1.121 + more_work_is_plausible = dispatcher->processEvents(block); 1.122 + 1.123 + if (state_->should_quit) { 1.124 + break; 1.125 + } 1.126 + 1.127 + more_work_is_plausible |= state_->delegate->DoWork(); 1.128 + if (state_->should_quit) { 1.129 + break; 1.130 + } 1.131 + 1.132 + more_work_is_plausible |= 1.133 + state_->delegate->DoDelayedWork(&delayed_work_time_); 1.134 + if (state_->should_quit) { 1.135 + break; 1.136 + } 1.137 + 1.138 + qt_pump.scheduleDelayedIfNeeded(delayed_work_time_); 1.139 + 1.140 + if (more_work_is_plausible) { 1.141 + continue; 1.142 + } 1.143 + 1.144 + more_work_is_plausible = state_->delegate->DoIdleWork(); 1.145 + if (state_->should_quit) { 1.146 + break; 1.147 + } 1.148 + } 1.149 + 1.150 + state_ = previous_state; 1.151 +} 1.152 + 1.153 +void MessagePumpForUI::HandleDispatch() { 1.154 + if (state_->should_quit) { 1.155 + return; 1.156 + } 1.157 + 1.158 + if (state_->delegate->DoWork()) { 1.159 + // there might be more, see more_work_is_plausible 1.160 + // variable above, that's why we ScheduleWork() to keep going. 1.161 + ScheduleWork(); 1.162 + } 1.163 + 1.164 + if (state_->should_quit) { 1.165 + return; 1.166 + } 1.167 + 1.168 + state_->delegate->DoDelayedWork(&delayed_work_time_); 1.169 + qt_pump.scheduleDelayedIfNeeded(delayed_work_time_); 1.170 +} 1.171 + 1.172 +void MessagePumpForUI::Quit() { 1.173 + if (state_) { 1.174 + state_->should_quit = true; 1.175 + } else { 1.176 + NOTREACHED() << "Quit called outside Run!"; 1.177 + } 1.178 +} 1.179 + 1.180 +void MessagePumpForUI::ScheduleWork() { 1.181 + QCoreApplication::postEvent(&qt_pump, 1.182 + new QEvent((QEvent::Type) sPokeEvent)); 1.183 +} 1.184 + 1.185 +void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { 1.186 + // On GLib implementation, a work source is defined which explicitly checks the 1.187 + // time that has passed. Here, on Qt we can use a QTimer that enqueues our 1.188 + // event signal in an event queue. 1.189 + delayed_work_time_ = delayed_work_time; 1.190 + qt_pump.scheduleDelayedIfNeeded(delayed_work_time_); 1.191 +} 1.192 + 1.193 +} // namespace base