Chromium Code Reviews| Index: base/message_pump_glib.cc |
| diff --git a/base/message_pump_glib.cc b/base/message_pump_glib.cc |
| index ae6d88e05e1c7fac78997797a677862a3e4158dd..ac33e531c653143b555e1ca09df77d5ea0c7209a 100644 |
| --- a/base/message_pump_glib.cc |
| +++ b/base/message_pump_glib.cc |
| @@ -51,23 +51,29 @@ int GetTimeIntervalMilliseconds(base::Time from) { |
| // Finalize is called when the source is destroyed. |
| struct WorkSource : public GSource { |
| - int timeout_ms; |
| + base::MessagePumpForUI* pump; |
| }; |
| gboolean WorkSourcePrepare(GSource* source, |
| gint* timeout_ms) { |
| - *timeout_ms = static_cast<WorkSource*>(source)->timeout_ms; |
| + *timeout_ms = static_cast<WorkSource*>(source)->pump->HandlePrepare(); |
| + // We always return FALSE, so that our timeout is honored. If we were |
| + // to return TRUE, the timeout would be considered to be 0 and the poll |
| + // would never block. Once the poll is finished, Check will be called. |
| return FALSE; |
| } |
| gboolean WorkSourceCheck(GSource* source) { |
| - return FALSE; |
| + // Always return TRUE, and Dispatch will be called. |
| + return TRUE; |
| } |
| gboolean WorkSourceDispatch(GSource* source, |
| GSourceFunc unused_func, |
| gpointer unused_data) { |
| - NOTREACHED(); |
| + |
| + static_cast<WorkSource*>(source)->pump->HandleDispatch(); |
| + // Always return TRUE so our source stays registered. |
| return TRUE; |
| } |
| @@ -88,6 +94,9 @@ MessagePumpForUI::MessagePumpForUI() |
| : state_(NULL), |
| context_(g_main_context_default()) { |
| work_source_ = g_source_new(&WorkSourceFuncs, sizeof(WorkSource)); |
| + static_cast<WorkSource*>(work_source_)->pump = this; |
| + // Use a low priority so that we let other events in the queue go first. |
| + g_source_set_priority(work_source_, G_PRIORITY_DEFAULT_IDLE); |
| // This is needed to allow Run calls inside Dispatch. |
| g_source_set_can_recurse(work_source_, TRUE); |
| g_source_attach(work_source_, context_); |
| @@ -112,53 +121,73 @@ void MessagePumpForUI::Run(Delegate* delegate) { |
| state.delegate = delegate; |
| state.should_quit = false; |
| state.run_depth = state_ ? state_->run_depth + 1 : 1; |
| - |
| - RunState* previous_state = state_; |
| - state_ = &state; |
| - |
| // We really only do a single task for each iteration of the loop. If we |
| // have done something, assume there is likely something more to do. This |
| // will mean that we don't block on the message pump until there was nothing |
| // more to do. We also set this to true to make sure not to block on the |
| // first iteration of the loop, so RunAllPending() works correctly. |
| - bool more_work_is_plausible = true; |
| - for (;;) { |
| - // Set up our timeout for any delayed work. |
| - static_cast<WorkSource*>(work_source_)->timeout_ms = |
| - GetTimeIntervalMilliseconds(delayed_work_time_); |
| - |
| - // Process a single iteration of the event loop. |
| - g_main_context_iteration(context_, !more_work_is_plausible); |
| - if (state_->should_quit) |
| - break; |
| - |
| - more_work_is_plausible = false; |
| - |
| - if (state_->delegate->DoWork()) |
| - more_work_is_plausible = true; |
| - |
| - if (state_->should_quit) |
| - break; |
| - |
| - if (state_->delegate->DoDelayedWork(&delayed_work_time_)) |
| - more_work_is_plausible = true; |
| - if (state_->should_quit) |
| - break; |
| - |
| - // Don't do idle work if we think there are more important things |
| - // that we could be doing. |
| - if (more_work_is_plausible) |
| - continue; |
| - |
| - if (state_->delegate->DoIdleWork()) |
| - more_work_is_plausible = true; |
| - if (state_->should_quit) |
| - break; |
| - } |
| + state.more_work_is_plausible = true; |
| + |
| + RunState* previous_state = state_; |
| + state_ = &state; |
| + |
| + // We run our own loop instead of using g_main_loop_quit in one of the |
| + // callbacks. This is so we only quit our own loops, and we don't quit |
| + // nested loops run by others. TODO(deanm): Is this what we want? |
| + while (!state_->should_quit) |
| + g_main_context_iteration(context_, true); |
| state_ = previous_state; |
| } |
| +// Return the timeout we want passed to poll. |
| +int MessagePumpForUI::HandlePrepare() { |
| + // If it's likely that we have more work, don't let the pump |
| + // block so that we can do some processing. |
| + if (state_->more_work_is_plausible) |
| + return 0; |
| + |
| + // Work wasn't plausible, so we'll block. In the case where glib fires |
| + // our Dispatch(), |more_work_is_plausible| will be reset to whatever it |
| + // should be. However, so we don't get starved by more important work, |
| + // we set |more_work_is_plausible| to true. This means if we come back |
| + // here without having been through Dispatch(), will get a chance to be |
|
dsh
2008/11/12 23:48:39
Should this have a "we" before "will"?
|
| + // fired and properly do our work in Dispatch(). |
| + state_->more_work_is_plausible = true; |
| + |
| + // We don't think we have work to do, but make sure not to block |
| + // longer than the next time we need to run delayed work. |
| + return GetTimeIntervalMilliseconds(delayed_work_time_); |
| +} |
| + |
| +void MessagePumpForUI::HandleDispatch() { |
| + if (state_->should_quit) |
| + return; |
| + |
| + state_->more_work_is_plausible = false; |
| + |
| + if (state_->delegate->DoWork()) |
| + state_->more_work_is_plausible = true; |
| + |
| + if (state_->should_quit) |
| + return; |
| + |
| + if (state_->delegate->DoDelayedWork(&delayed_work_time_)) |
| + state_->more_work_is_plausible = true; |
| + if (state_->should_quit) |
| + return; |
| + |
| + // Don't do idle work if we think there are more important things |
| + // that we could be doing. |
| + if (state_->more_work_is_plausible) |
| + return; |
| + |
| + if (state_->delegate->DoIdleWork()) |
| + state_->more_work_is_plausible = true; |
| + if (state_->should_quit) |
| + return; |
| +} |
| + |
| void MessagePumpForUI::Quit() { |
| if (state_) { |
| state_->should_quit = true; |