ipc/chromium/src/base/message_pump_qt.cc

changeset 0
6474c204b198
     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

mercurial