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; |