ipc/chromium/src/base/message_pump_qt.cc

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:80c9bee9eaa2
1 // Copyright (c) 2010 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 <qabstracteventdispatcher.h>
6 #include <qevent.h>
7 #include <QCoreApplication>
8 #include <QThread>
9 #include <qtimer.h>
10
11 #include "base/message_pump_qt.h"
12
13 #include <fcntl.h>
14 #include <limits>
15 #include <math.h>
16
17 #include "base/eintr_wrapper.h"
18 #include "base/lazy_instance.h"
19 #include "base/logging.h"
20 #include "base/platform_thread.h"
21
22 namespace {
23 // Cached QEvent user type, registered for our event system
24 static int sPokeEvent;
25 } // namespace
26
27 namespace base {
28
29 MessagePumpForUI::MessagePumpForUI()
30 : state_(NULL),
31 qt_pump(*this)
32 {
33 }
34
35 MessagePumpForUI::~MessagePumpForUI() {
36 }
37
38 MessagePumpQt::MessagePumpQt(MessagePumpForUI &aPump)
39 : pump(aPump), mTimer(new QTimer(this))
40 {
41 // Register our custom event type, to use in qApp event loop
42 sPokeEvent = QEvent::registerEventType();
43 connect(mTimer, SIGNAL(timeout()), this, SLOT(dispatchDelayed()));
44 mTimer->setSingleShot(true);
45 }
46
47 MessagePumpQt::~MessagePumpQt()
48 {
49 mTimer->stop();
50 delete mTimer;
51 }
52
53 bool
54 MessagePumpQt::event(QEvent *e)
55 {
56 if (e->type() == sPokeEvent) {
57 pump.HandleDispatch();
58 return true;
59 }
60 return false;
61 }
62
63 void
64 MessagePumpQt::scheduleDelayedIfNeeded(const TimeTicks& delayed_work_time)
65 {
66 if (delayed_work_time.is_null()) {
67 return;
68 }
69
70 if (mTimer->isActive()) {
71 mTimer->stop();
72 }
73
74 TimeDelta later = delayed_work_time - TimeTicks::Now();
75 // later.InMilliseconds() returns an int64_t, QTimer only accepts int's for start(),
76 // std::min only works on exact same types.
77 int laterMsecs = later.InMilliseconds() > std::numeric_limits<int>::max() ?
78 std::numeric_limits<int>::max() : later.InMilliseconds();
79 mTimer->start(laterMsecs > 0 ? laterMsecs : 0);
80 }
81
82 void
83 MessagePumpQt::dispatchDelayed()
84 {
85 pump.HandleDispatch();
86 }
87
88 void MessagePumpForUI::Run(Delegate* delegate) {
89 RunState state;
90 state.delegate = delegate;
91 state.should_quit = false;
92 state.run_depth = state_ ? state_->run_depth + 1 : 1;
93 // We really only do a single task for each iteration of the loop. If we
94 // have done something, assume there is likely something more to do. This
95 // will mean that we don't block on the message pump until there was nothing
96 // more to do. We also set this to true to make sure not to block on the
97 // first iteration of the loop, so RunAllPending() works correctly.
98 bool more_work_is_plausible = true;
99
100 RunState* previous_state = state_;
101 state_ = &state;
102
103 for(;;) {
104 QEventLoop::ProcessEventsFlags block = QEventLoop::AllEvents;
105 if (!more_work_is_plausible) {
106 block |= QEventLoop::WaitForMoreEvents;
107 }
108
109 QAbstractEventDispatcher* dispatcher =
110 QAbstractEventDispatcher::instance(QThread::currentThread());
111 // An assertion seems too much here, as during startup,
112 // the dispatcher might not be ready yet.
113 if (!dispatcher) {
114 return;
115 }
116
117 // processEvent's returns true if an event has been processed.
118 more_work_is_plausible = dispatcher->processEvents(block);
119
120 if (state_->should_quit) {
121 break;
122 }
123
124 more_work_is_plausible |= state_->delegate->DoWork();
125 if (state_->should_quit) {
126 break;
127 }
128
129 more_work_is_plausible |=
130 state_->delegate->DoDelayedWork(&delayed_work_time_);
131 if (state_->should_quit) {
132 break;
133 }
134
135 qt_pump.scheduleDelayedIfNeeded(delayed_work_time_);
136
137 if (more_work_is_plausible) {
138 continue;
139 }
140
141 more_work_is_plausible = state_->delegate->DoIdleWork();
142 if (state_->should_quit) {
143 break;
144 }
145 }
146
147 state_ = previous_state;
148 }
149
150 void MessagePumpForUI::HandleDispatch() {
151 if (state_->should_quit) {
152 return;
153 }
154
155 if (state_->delegate->DoWork()) {
156 // there might be more, see more_work_is_plausible
157 // variable above, that's why we ScheduleWork() to keep going.
158 ScheduleWork();
159 }
160
161 if (state_->should_quit) {
162 return;
163 }
164
165 state_->delegate->DoDelayedWork(&delayed_work_time_);
166 qt_pump.scheduleDelayedIfNeeded(delayed_work_time_);
167 }
168
169 void MessagePumpForUI::Quit() {
170 if (state_) {
171 state_->should_quit = true;
172 } else {
173 NOTREACHED() << "Quit called outside Run!";
174 }
175 }
176
177 void MessagePumpForUI::ScheduleWork() {
178 QCoreApplication::postEvent(&qt_pump,
179 new QEvent((QEvent::Type) sPokeEvent));
180 }
181
182 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) {
183 // On GLib implementation, a work source is defined which explicitly checks the
184 // time that has passed. Here, on Qt we can use a QTimer that enqueues our
185 // event signal in an event queue.
186 delayed_work_time_ = delayed_work_time;
187 qt_pump.scheduleDelayedIfNeeded(delayed_work_time_);
188 }
189
190 } // namespace base

mercurial