OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/message_pump_glib.h" | 5 #include "base/message_pump_glib.h" |
6 | 6 |
7 #include <fcntl.h> | 7 #include <fcntl.h> |
8 #include <math.h> | 8 #include <math.h> |
9 | 9 |
10 #include <gtk/gtk.h> | |
11 #include <glib.h> | 10 #include <glib.h> |
12 | 11 |
13 #include "base/eintr_wrapper.h" | 12 #include "base/eintr_wrapper.h" |
14 #include "base/logging.h" | 13 #include "base/logging.h" |
15 #include "base/threading/platform_thread.h" | 14 #include "base/threading/platform_thread.h" |
16 | 15 |
17 namespace { | 16 namespace { |
18 | 17 |
19 // We send a byte across a pipe to wakeup the event loop. | 18 // We send a byte across a pipe to wakeup the event loop. |
20 const char kWorkScheduled = '\0'; | 19 const char kWorkScheduled = '\0'; |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
78 // after, from gtk_main_iteration. | 77 // after, from gtk_main_iteration. |
79 // | 78 // |
80 // For the GLib pump we try to follow the Windows UI pump model: | 79 // For the GLib pump we try to follow the Windows UI pump model: |
81 // - Whenever we receive a wakeup event or the timer for delayed work expires, | 80 // - Whenever we receive a wakeup event or the timer for delayed work expires, |
82 // we run DoWork and/or DoDelayedWork. That part will also run in the other | 81 // we run DoWork and/or DoDelayedWork. That part will also run in the other |
83 // event pumps. | 82 // event pumps. |
84 // - We also run DoWork, DoDelayedWork, and possibly DoIdleWork in the main | 83 // - We also run DoWork, DoDelayedWork, and possibly DoIdleWork in the main |
85 // loop, around event handling. | 84 // loop, around event handling. |
86 | 85 |
87 struct WorkSource : public GSource { | 86 struct WorkSource : public GSource { |
88 base::MessagePumpForUI* pump; | 87 base::MessagePumpGlib* pump; |
89 }; | 88 }; |
90 | 89 |
91 gboolean WorkSourcePrepare(GSource* source, | 90 gboolean WorkSourcePrepare(GSource* source, |
92 gint* timeout_ms) { | 91 gint* timeout_ms) { |
93 *timeout_ms = static_cast<WorkSource*>(source)->pump->HandlePrepare(); | 92 *timeout_ms = static_cast<WorkSource*>(source)->pump->HandlePrepare(); |
94 // We always return FALSE, so that our timeout is honored. If we were | 93 // We always return FALSE, so that our timeout is honored. If we were |
95 // to return TRUE, the timeout would be considered to be 0 and the poll | 94 // to return TRUE, the timeout would be considered to be 0 and the poll |
96 // would never block. Once the poll is finished, Check will be called. | 95 // would never block. Once the poll is finished, Check will be called. |
97 return FALSE; | 96 return FALSE; |
98 } | 97 } |
(...skipping 18 matching lines...) Expand all Loading... |
117 WorkSourceCheck, | 116 WorkSourceCheck, |
118 WorkSourceDispatch, | 117 WorkSourceDispatch, |
119 NULL | 118 NULL |
120 }; | 119 }; |
121 | 120 |
122 } // namespace | 121 } // namespace |
123 | 122 |
124 | 123 |
125 namespace base { | 124 namespace base { |
126 | 125 |
127 struct MessagePumpForUI::RunState { | 126 struct MessagePumpGlib::RunState { |
128 Delegate* delegate; | 127 Delegate* delegate; |
129 Dispatcher* dispatcher; | 128 MessagePumpDispatcher* dispatcher; |
130 | 129 |
131 // Used to flag that the current Run() invocation should return ASAP. | 130 // Used to flag that the current Run() invocation should return ASAP. |
132 bool should_quit; | 131 bool should_quit; |
133 | 132 |
134 // Used to count how many Run() invocations are on the stack. | 133 // Used to count how many Run() invocations are on the stack. |
135 int run_depth; | 134 int run_depth; |
136 | 135 |
137 // This keeps the state of whether the pump got signaled that there was new | 136 // This keeps the state of whether the pump got signaled that there was new |
138 // work to be done. Since we eat the message on the wake up pipe as soon as | 137 // work to be done. Since we eat the message on the wake up pipe as soon as |
139 // we get it, we keep that state here to stay consistent. | 138 // we get it, we keep that state here to stay consistent. |
140 bool has_work; | 139 bool has_work; |
141 }; | 140 }; |
142 | 141 |
143 MessagePumpForUI::MessagePumpForUI() | 142 MessagePumpGlib::MessagePumpGlib() |
144 : state_(NULL), | 143 : state_(NULL), |
145 context_(g_main_context_default()), | 144 context_(g_main_context_default()), |
146 wakeup_gpollfd_(new GPollFD) { | 145 wakeup_gpollfd_(new GPollFD) { |
147 // Create our wakeup pipe, which is used to flag when work was scheduled. | 146 // Create our wakeup pipe, which is used to flag when work was scheduled. |
148 int fds[2]; | 147 int fds[2]; |
149 CHECK_EQ(pipe(fds), 0); | 148 CHECK_EQ(pipe(fds), 0); |
150 wakeup_pipe_read_ = fds[0]; | 149 wakeup_pipe_read_ = fds[0]; |
151 wakeup_pipe_write_ = fds[1]; | 150 wakeup_pipe_write_ = fds[1]; |
152 wakeup_gpollfd_->fd = wakeup_pipe_read_; | 151 wakeup_gpollfd_->fd = wakeup_pipe_read_; |
153 wakeup_gpollfd_->events = G_IO_IN; | 152 wakeup_gpollfd_->events = G_IO_IN; |
154 | 153 |
155 work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource)); | 154 work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource)); |
156 static_cast<WorkSource*>(work_source_)->pump = this; | 155 static_cast<WorkSource*>(work_source_)->pump = this; |
157 g_source_add_poll(work_source_, wakeup_gpollfd_.get()); | 156 g_source_add_poll(work_source_, wakeup_gpollfd_.get()); |
158 // Use a low priority so that we let other events in the queue go first. | 157 // Use a low priority so that we let other events in the queue go first. |
159 g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE); | 158 g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE); |
160 // This is needed to allow Run calls inside Dispatch. | 159 // This is needed to allow Run calls inside Dispatch. |
161 g_source_set_can_recurse(work_source_, TRUE); | 160 g_source_set_can_recurse(work_source_, TRUE); |
162 g_source_attach(work_source_, context_); | 161 g_source_attach(work_source_, context_); |
163 gdk_event_handler_set(&EventDispatcher, this, NULL); | |
164 } | 162 } |
165 | 163 |
166 MessagePumpForUI::~MessagePumpForUI() { | 164 MessagePumpGlib::~MessagePumpGlib() { |
167 gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event), | |
168 this, NULL); | |
169 g_source_destroy(work_source_); | 165 g_source_destroy(work_source_); |
170 g_source_unref(work_source_); | 166 g_source_unref(work_source_); |
171 close(wakeup_pipe_read_); | 167 close(wakeup_pipe_read_); |
172 close(wakeup_pipe_write_); | 168 close(wakeup_pipe_write_); |
173 } | 169 } |
174 | 170 |
175 void MessagePumpForUI::RunWithDispatcher(Delegate* delegate, | 171 void MessagePumpGlib::RunWithDispatcher(Delegate* delegate, |
176 Dispatcher* dispatcher) { | 172 MessagePumpDispatcher* dispatcher) { |
177 #ifndef NDEBUG | 173 #ifndef NDEBUG |
178 // Make sure we only run this on one thread. GTK only has one message pump | 174 // Make sure we only run this on one thread. X/GTK only has one message pump |
179 // so we can only have one UI loop per process. | 175 // so we can only have one UI loop per process. |
180 static base::PlatformThreadId thread_id = base::PlatformThread::CurrentId(); | 176 static base::PlatformThreadId thread_id = base::PlatformThread::CurrentId(); |
181 DCHECK(thread_id == base::PlatformThread::CurrentId()) << | 177 DCHECK(thread_id == base::PlatformThread::CurrentId()) << |
182 "Running MessagePumpForUI on two different threads; " | 178 "Running MessagePumpGlib on two different threads; " |
183 "this is unsupported by GLib!"; | 179 "this is unsupported by GLib!"; |
184 #endif | 180 #endif |
185 | 181 |
186 RunState state; | 182 RunState state; |
187 state.delegate = delegate; | 183 state.delegate = delegate; |
188 state.dispatcher = dispatcher; | 184 state.dispatcher = dispatcher; |
189 state.should_quit = false; | 185 state.should_quit = false; |
190 state.run_depth = state_ ? state_->run_depth + 1 : 1; | 186 state.run_depth = state_ ? state_->run_depth + 1 : 1; |
191 state.has_work = false; | 187 state.has_work = false; |
192 | 188 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 continue; | 220 continue; |
225 | 221 |
226 more_work_is_plausible = state_->delegate->DoIdleWork(); | 222 more_work_is_plausible = state_->delegate->DoIdleWork(); |
227 if (state_->should_quit) | 223 if (state_->should_quit) |
228 break; | 224 break; |
229 } | 225 } |
230 | 226 |
231 state_ = previous_state; | 227 state_ = previous_state; |
232 } | 228 } |
233 | 229 |
234 bool MessagePumpForUI::RunOnce(GMainContext* context, bool block) { | |
235 // g_main_context_iteration returns true if events have been dispatched. | |
236 return g_main_context_iteration(context, block); | |
237 } | |
238 | |
239 // Return the timeout we want passed to poll. | 230 // Return the timeout we want passed to poll. |
240 int MessagePumpForUI::HandlePrepare() { | 231 int MessagePumpGlib::HandlePrepare() { |
241 // We know we have work, but we haven't called HandleDispatch yet. Don't let | 232 // We know we have work, but we haven't called HandleDispatch yet. Don't let |
242 // the pump block so that we can do some processing. | 233 // the pump block so that we can do some processing. |
243 if (state_ && // state_ may be null during tests. | 234 if (state_ && // state_ may be null during tests. |
244 state_->has_work) | 235 state_->has_work) |
245 return 0; | 236 return 0; |
246 | 237 |
247 // We don't think we have work to do, but make sure not to block | 238 // We don't think we have work to do, but make sure not to block |
248 // longer than the next time we need to run delayed work. | 239 // longer than the next time we need to run delayed work. |
249 return GetTimeIntervalMilliseconds(delayed_work_time_); | 240 return GetTimeIntervalMilliseconds(delayed_work_time_); |
250 } | 241 } |
251 | 242 |
252 bool MessagePumpForUI::HandleCheck() { | 243 bool MessagePumpGlib::HandleCheck() { |
253 if (!state_) // state_ may be null during tests. | 244 if (!state_) // state_ may be null during tests. |
254 return false; | 245 return false; |
255 | 246 |
256 // We should only ever have a single message on the wakeup pipe, since we | 247 // We should only ever have a single message on the wakeup pipe, since we |
257 // are only signaled when the queue went from empty to non-empty. The glib | 248 // are only signaled when the queue went from empty to non-empty. The glib |
258 // poll will tell us whether there was data, so this read shouldn't block. | 249 // poll will tell us whether there was data, so this read shouldn't block. |
259 if (wakeup_gpollfd_->revents & G_IO_IN) { | 250 if (wakeup_gpollfd_->revents & G_IO_IN) { |
260 char msg; | 251 char msg; |
261 if (HANDLE_EINTR(read(wakeup_pipe_read_, &msg, 1)) != 1 || msg != '!') { | 252 if (HANDLE_EINTR(read(wakeup_pipe_read_, &msg, 1)) != 1 || msg != '!') { |
262 NOTREACHED() << "Error reading from the wakeup pipe."; | 253 NOTREACHED() << "Error reading from the wakeup pipe."; |
263 } | 254 } |
264 // Since we ate the message, we need to record that we have more work, | 255 // Since we ate the message, we need to record that we have more work, |
265 // because HandleCheck() may be called without HandleDispatch being called | 256 // because HandleCheck() may be called without HandleDispatch being called |
266 // afterwards. | 257 // afterwards. |
267 state_->has_work = true; | 258 state_->has_work = true; |
268 } | 259 } |
269 | 260 |
270 if (state_->has_work) | 261 if (state_->has_work) |
271 return true; | 262 return true; |
272 | 263 |
273 if (GetTimeIntervalMilliseconds(delayed_work_time_) == 0) { | 264 if (GetTimeIntervalMilliseconds(delayed_work_time_) == 0) { |
274 // The timer has expired. That condition will stay true until we process | 265 // The timer has expired. That condition will stay true until we process |
275 // that delayed work, so we don't need to record this differently. | 266 // that delayed work, so we don't need to record this differently. |
276 return true; | 267 return true; |
277 } | 268 } |
278 | 269 |
279 return false; | 270 return false; |
280 } | 271 } |
281 | 272 |
282 void MessagePumpForUI::HandleDispatch() { | 273 void MessagePumpGlib::HandleDispatch() { |
283 state_->has_work = false; | 274 state_->has_work = false; |
284 if (state_->delegate->DoWork()) { | 275 if (state_->delegate->DoWork()) { |
285 // NOTE: on Windows at this point we would call ScheduleWork (see | 276 // NOTE: on Windows at this point we would call ScheduleWork (see |
286 // MessagePumpForUI::HandleWorkMessage in message_pump_win.cc). But here, | 277 // MessagePumpGlib::HandleWorkMessage in message_pump_win.cc). But here, |
287 // instead of posting a message on the wakeup pipe, we can avoid the | 278 // instead of posting a message on the wakeup pipe, we can avoid the |
288 // syscalls and just signal that we have more work. | 279 // syscalls and just signal that we have more work. |
289 state_->has_work = true; | 280 state_->has_work = true; |
290 } | 281 } |
291 | 282 |
292 if (state_->should_quit) | 283 if (state_->should_quit) |
293 return; | 284 return; |
294 | 285 |
295 state_->delegate->DoDelayedWork(&delayed_work_time_); | 286 state_->delegate->DoDelayedWork(&delayed_work_time_); |
296 } | 287 } |
297 | 288 |
298 void MessagePumpForUI::AddObserver(Observer* observer) { | 289 void MessagePumpGlib::AddObserver(MessagePumpObserver* observer) { |
299 observers_.AddObserver(observer); | 290 observers_.AddObserver(observer); |
300 } | 291 } |
301 | 292 |
302 void MessagePumpForUI::RemoveObserver(Observer* observer) { | 293 void MessagePumpGlib::RemoveObserver(MessagePumpObserver* observer) { |
303 observers_.RemoveObserver(observer); | 294 observers_.RemoveObserver(observer); |
304 } | 295 } |
305 | 296 |
306 void MessagePumpForUI::DispatchEvents(GdkEvent* event) { | 297 void MessagePumpGlib::Run(Delegate* delegate) { |
307 WillProcessEvent(event); | |
308 if (state_ && state_->dispatcher) { // state_ may be null during tests. | |
309 if (!state_->dispatcher->Dispatch(event)) | |
310 state_->should_quit = true; | |
311 } else { | |
312 gtk_main_do_event(event); | |
313 } | |
314 DidProcessEvent(event); | |
315 } | |
316 | |
317 void MessagePumpForUI::Run(Delegate* delegate) { | |
318 RunWithDispatcher(delegate, NULL); | 298 RunWithDispatcher(delegate, NULL); |
319 } | 299 } |
320 | 300 |
321 void MessagePumpForUI::Quit() { | 301 void MessagePumpGlib::Quit() { |
322 if (state_) { | 302 if (state_) { |
323 state_->should_quit = true; | 303 state_->should_quit = true; |
324 } else { | 304 } else { |
325 NOTREACHED() << "Quit called outside Run!"; | 305 NOTREACHED() << "Quit called outside Run!"; |
326 } | 306 } |
327 } | 307 } |
328 | 308 |
329 void MessagePumpForUI::ScheduleWork() { | 309 void MessagePumpGlib::ScheduleWork() { |
330 // This can be called on any thread, so we don't want to touch any state | 310 // This can be called on any thread, so we don't want to touch any state |
331 // variables as we would then need locks all over. This ensures that if | 311 // variables as we would then need locks all over. This ensures that if |
332 // we are sleeping in a poll that we will wake up. | 312 // we are sleeping in a poll that we will wake up. |
333 char msg = '!'; | 313 char msg = '!'; |
334 if (HANDLE_EINTR(write(wakeup_pipe_write_, &msg, 1)) != 1) { | 314 if (HANDLE_EINTR(write(wakeup_pipe_write_, &msg, 1)) != 1) { |
335 NOTREACHED() << "Could not write to the UI message loop wakeup pipe!"; | 315 NOTREACHED() << "Could not write to the UI message loop wakeup pipe!"; |
336 } | 316 } |
337 } | 317 } |
338 | 318 |
339 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { | 319 void MessagePumpGlib::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
340 // We need to wake up the loop in case the poll timeout needs to be | 320 // We need to wake up the loop in case the poll timeout needs to be |
341 // adjusted. This will cause us to try to do work, but that's ok. | 321 // adjusted. This will cause us to try to do work, but that's ok. |
342 delayed_work_time_ = delayed_work_time; | 322 delayed_work_time_ = delayed_work_time; |
343 ScheduleWork(); | 323 ScheduleWork(); |
344 } | 324 } |
345 | 325 |
346 MessagePumpForUI::Dispatcher* MessagePumpForUI::GetDispatcher() { | 326 MessagePumpDispatcher* MessagePumpGlib::GetDispatcher() { |
347 return state_ ? state_->dispatcher : NULL; | 327 return state_ ? state_->dispatcher : NULL; |
348 } | 328 } |
349 | 329 |
350 void MessagePumpForUI::WillProcessEvent(GdkEvent* event) { | |
351 FOR_EACH_OBSERVER(Observer, observers_, WillProcessEvent(event)); | |
352 } | |
353 | |
354 void MessagePumpForUI::DidProcessEvent(GdkEvent* event) { | |
355 FOR_EACH_OBSERVER(Observer, observers_, DidProcessEvent(event)); | |
356 } | |
357 | |
358 // static | |
359 void MessagePumpForUI::EventDispatcher(GdkEvent* event, gpointer data) { | |
360 MessagePumpForUI* message_pump = reinterpret_cast<MessagePumpForUI*>(data); | |
361 message_pump->DispatchEvents(event); | |
362 } | |
363 | |
364 } // namespace base | 330 } // namespace base |
OLD | NEW |