Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_win.h" | 5 #include "base/message_pump_win.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
| 10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
| 11 #include "base/process_util.h" | |
| 12 #include "base/stringprintf.h" | |
| 11 #include "base/win/wrapped_window_proc.h" | 13 #include "base/win/wrapped_window_proc.h" |
| 12 | 14 |
| 15 namespace { | |
| 16 | |
| 17 // The ID of the timer used by the UI message pump. | |
| 18 const int kMessagePumpTimerId = 0; | |
| 19 | |
| 20 } // namespace | |
| 21 | |
| 13 namespace base { | 22 namespace base { |
| 14 | 23 |
| 15 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow"; | 24 static const wchar_t kWndClassFormat[] = L"Chrome_MessagePumpWindow%p"; |
| 16 | 25 |
| 17 // Message sent to get an additional time slice for pumping (processing) another | 26 // Message sent to get an additional time slice for pumping (processing) another |
| 18 // task (a series of such messages creates a continuous task pump). | 27 // task (a series of such messages creates a continuous task pump). |
| 19 static const int kMsgHaveWork = WM_USER + 1; | 28 static const int kMsgHaveWork = WM_USER + 1; |
| 20 | 29 |
| 21 //----------------------------------------------------------------------------- | 30 //----------------------------------------------------------------------------- |
| 22 // MessagePumpWin public: | 31 // MessagePumpWin public: |
| 23 | 32 |
| 24 void MessagePumpWin::AddObserver(MessagePumpObserver* observer) { | 33 void MessagePumpWin::AddObserver(MessagePumpObserver* observer) { |
| 25 observers_.AddObserver(observer); | 34 observers_.AddObserver(observer); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 75 int delay = static_cast<int>(timeout); | 84 int delay = static_cast<int>(timeout); |
| 76 if (delay < 0) | 85 if (delay < 0) |
| 77 delay = 0; | 86 delay = 0; |
| 78 | 87 |
| 79 return delay; | 88 return delay; |
| 80 } | 89 } |
| 81 | 90 |
| 82 //----------------------------------------------------------------------------- | 91 //----------------------------------------------------------------------------- |
| 83 // MessagePumpForUI public: | 92 // MessagePumpForUI public: |
| 84 | 93 |
| 85 MessagePumpForUI::MessagePumpForUI() { | 94 MessagePumpForUI::MessagePumpForUI() |
| 95 : atom_(0), | |
| 96 instance_(NULL), | |
| 97 message_hwnd_(NULL) { | |
| 86 InitMessageWnd(); | 98 InitMessageWnd(); |
| 87 } | 99 } |
| 88 | 100 |
| 89 MessagePumpForUI::~MessagePumpForUI() { | 101 MessagePumpForUI::~MessagePumpForUI() { |
| 90 DestroyWindow(message_hwnd_); | 102 if (message_hwnd_ != NULL) |
| 91 UnregisterClass(kWndClass, GetModuleHandle(NULL)); | 103 DestroyWindow(message_hwnd_); |
| 104 | |
| 105 if (atom_ != 0) | |
| 106 UnregisterClass(reinterpret_cast<const char16*>(atom_), instance_); | |
| 92 } | 107 } |
| 93 | 108 |
| 94 void MessagePumpForUI::ScheduleWork() { | 109 void MessagePumpForUI::ScheduleWork() { |
| 95 if (InterlockedExchange(&have_work_, 1)) | 110 if (InterlockedExchange(&have_work_, 1)) |
| 96 return; // Someone else continued the pumping. | 111 return; // Someone else continued the pumping. |
| 97 | 112 |
| 98 // Make sure the MessagePump does some work for us. | 113 // Make sure the MessagePump does some work for us. |
| 99 PostMessage(message_hwnd_, kMsgHaveWork, reinterpret_cast<WPARAM>(this), 0); | 114 PostMessage(message_hwnd_, kMsgHaveWork, 0, 0); |
| 100 } | 115 } |
| 101 | 116 |
| 102 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { | 117 void MessagePumpForUI::ScheduleDelayedWork(const TimeTicks& delayed_work_time) { |
| 103 // | 118 // |
| 104 // We would *like* to provide high resolution timers. Windows timers using | 119 // We would *like* to provide high resolution timers. Windows timers using |
| 105 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup | 120 // SetTimer() have a 10ms granularity. We have to use WM_TIMER as a wakeup |
| 106 // mechanism because the application can enter modal windows loops where it | 121 // mechanism because the application can enter modal windows loops where it |
| 107 // is not running our MessageLoop; the only way to have our timers fire in | 122 // is not running our MessageLoop; the only way to have our timers fire in |
| 108 // these cases is to post messages there. | 123 // these cases is to post messages there. |
| 109 // | 124 // |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 122 // | 137 // |
| 123 delayed_work_time_ = delayed_work_time; | 138 delayed_work_time_ = delayed_work_time; |
| 124 | 139 |
| 125 int delay_msec = GetCurrentDelay(); | 140 int delay_msec = GetCurrentDelay(); |
| 126 DCHECK_GE(delay_msec, 0); | 141 DCHECK_GE(delay_msec, 0); |
| 127 if (delay_msec < USER_TIMER_MINIMUM) | 142 if (delay_msec < USER_TIMER_MINIMUM) |
| 128 delay_msec = USER_TIMER_MINIMUM; | 143 delay_msec = USER_TIMER_MINIMUM; |
| 129 | 144 |
| 130 // Create a WM_TIMER event that will wake us up to check for any pending | 145 // Create a WM_TIMER event that will wake us up to check for any pending |
| 131 // timers (in case we are running within a nested, external sub-pump). | 146 // timers (in case we are running within a nested, external sub-pump). |
| 132 SetTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this), delay_msec, NULL); | 147 SetTimer(message_hwnd_, kMessagePumpTimerId, delay_msec, NULL); |
| 133 } | 148 } |
| 134 | 149 |
| 135 void MessagePumpForUI::PumpOutPendingPaintMessages() { | 150 void MessagePumpForUI::PumpOutPendingPaintMessages() { |
| 136 // If we are being called outside of the context of Run, then don't try to do | 151 // If we are being called outside of the context of Run, then don't try to do |
| 137 // any work. | 152 // any work. |
| 138 if (!state_) | 153 if (!state_) |
| 139 return; | 154 return; |
| 140 | 155 |
| 141 // Create a mini-message-pump to force immediate processing of only Windows | 156 // Create a mini-message-pump to force immediate processing of only Windows |
| 142 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking | 157 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 155 // Histogram what was really being used, to help to adjust kMaxPeekCount. | 170 // Histogram what was really being used, to help to adjust kMaxPeekCount. |
| 156 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count); | 171 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count); |
| 157 } | 172 } |
| 158 | 173 |
| 159 //----------------------------------------------------------------------------- | 174 //----------------------------------------------------------------------------- |
| 160 // MessagePumpForUI private: | 175 // MessagePumpForUI private: |
| 161 | 176 |
| 162 // static | 177 // static |
| 163 LRESULT CALLBACK MessagePumpForUI::WndProcThunk( | 178 LRESULT CALLBACK MessagePumpForUI::WndProcThunk( |
| 164 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { | 179 HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { |
| 165 switch (message) { | 180 // Retrieve |this| from the user data, associated with the window. |
| 166 case kMsgHaveWork: | 181 MessagePumpForUI* self = reinterpret_cast<MessagePumpForUI*>( |
| 167 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleWorkMessage(); | 182 GetWindowLongPtr(hwnd, GWLP_USERDATA)); |
| 168 break; | 183 if (self != NULL) { |
|
jar (doing other things)
2012/05/15 21:39:42
Perchance we should not check the value of |self|,
alexeypa (please no reviews)
2012/05/15 22:10:27
|self| should never be NULL except for WM_CREATE m
| |
| 169 case WM_TIMER: | 184 switch (message) { |
| 170 reinterpret_cast<MessagePumpForUI*>(wparam)->HandleTimerMessage(); | 185 case kMsgHaveWork: |
| 171 break; | 186 self->HandleWorkMessage(); |
| 187 break; | |
| 188 case WM_TIMER: | |
| 189 DCHECK(wparam == kMessagePumpTimerId); | |
| 190 self->HandleTimerMessage(); | |
| 191 break; | |
| 192 } | |
| 172 } | 193 } |
| 173 return DefWindowProc(hwnd, message, wparam, lparam); | 194 return DefWindowProc(hwnd, message, wparam, lparam); |
| 174 } | 195 } |
| 175 | 196 |
| 176 void MessagePumpForUI::DoRunLoop() { | 197 void MessagePumpForUI::DoRunLoop() { |
| 177 // IF this was just a simple PeekMessage() loop (servicing all possible work | 198 // IF this was just a simple PeekMessage() loop (servicing all possible work |
| 178 // queues), then Windows would try to achieve the following order according | 199 // queues), then Windows would try to achieve the following order according |
| 179 // to MSDN documentation about PeekMessage with no filter): | 200 // to MSDN documentation about PeekMessage with no filter): |
| 180 // * Sent messages | 201 // * Sent messages |
| 181 // * Posted messages | 202 // * Posted messages |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 204 if (state_->should_quit) | 225 if (state_->should_quit) |
| 205 break; | 226 break; |
| 206 | 227 |
| 207 more_work_is_plausible |= | 228 more_work_is_plausible |= |
| 208 state_->delegate->DoDelayedWork(&delayed_work_time_); | 229 state_->delegate->DoDelayedWork(&delayed_work_time_); |
| 209 // If we did not process any delayed work, then we can assume that our | 230 // If we did not process any delayed work, then we can assume that our |
| 210 // existing WM_TIMER if any will fire when delayed work should run. We | 231 // existing WM_TIMER if any will fire when delayed work should run. We |
| 211 // don't want to disturb that timer if it is already in flight. However, | 232 // don't want to disturb that timer if it is already in flight. However, |
| 212 // if we did do all remaining delayed work, then lets kill the WM_TIMER. | 233 // if we did do all remaining delayed work, then lets kill the WM_TIMER. |
| 213 if (more_work_is_plausible && delayed_work_time_.is_null()) | 234 if (more_work_is_plausible && delayed_work_time_.is_null()) |
| 214 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); | 235 KillTimer(message_hwnd_, kMessagePumpTimerId); |
| 215 if (state_->should_quit) | 236 if (state_->should_quit) |
| 216 break; | 237 break; |
| 217 | 238 |
| 218 if (more_work_is_plausible) | 239 if (more_work_is_plausible) |
| 219 continue; | 240 continue; |
| 220 | 241 |
| 221 more_work_is_plausible = state_->delegate->DoIdleWork(); | 242 more_work_is_plausible = state_->delegate->DoIdleWork(); |
| 222 if (state_->should_quit) | 243 if (state_->should_quit) |
| 223 break; | 244 break; |
| 224 | 245 |
| 225 if (more_work_is_plausible) | 246 if (more_work_is_plausible) |
| 226 continue; | 247 continue; |
| 227 | 248 |
| 228 WaitForWork(); // Wait (sleep) until we have work to do again. | 249 WaitForWork(); // Wait (sleep) until we have work to do again. |
| 229 } | 250 } |
| 230 } | 251 } |
| 231 | 252 |
| 232 void MessagePumpForUI::InitMessageWnd() { | 253 void MessagePumpForUI::InitMessageWnd() { |
| 233 HINSTANCE hinst = GetModuleHandle(NULL); | 254 // Register a unique window class for each instance of UI pump. |
| 255 string16 class_name = base::StringPrintf(kWndClassFormat, this); | |
| 256 WNDPROC window_procedure = &base::win::WrappedWindowProc<WndProcThunk>; | |
| 234 | 257 |
| 235 WNDCLASSEX wc = {0}; | 258 // RegisterClassEx uses a handle of the module containing the window procedure |
| 259 // to distinguish identically named classes registered in different modules. | |
| 260 instance_ = GetModuleFromAddress(window_procedure); | |
| 261 | |
| 262 WNDCLASSEXW wc = {0}; | |
| 236 wc.cbSize = sizeof(wc); | 263 wc.cbSize = sizeof(wc); |
| 237 wc.lpfnWndProc = base::win::WrappedWindowProc<WndProcThunk>; | 264 wc.lpfnWndProc = window_procedure; |
| 238 wc.hInstance = hinst; | 265 wc.hInstance = instance_; |
| 239 wc.lpszClassName = kWndClass; | 266 wc.lpszClassName = class_name.c_str(); |
| 240 RegisterClassEx(&wc); | 267 atom_ = RegisterClassEx(&wc); |
| 268 if (atom_ == 0) { | |
| 269 DCHECK(atom_); | |
|
alexeypa (please no reviews)
2012/05/15 22:10:27
We should also CHECK here.
| |
| 270 return; | |
| 271 } | |
| 241 | 272 |
| 242 message_hwnd_ = | 273 // Create the message-only window. |
| 243 CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hinst, 0); | 274 message_hwnd_ = CreateWindow( |
| 244 DCHECK(message_hwnd_); | 275 reinterpret_cast<const char16*>(atom_), 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, |
| 276 instance_, 0); | |
| 277 if (message_hwnd_ == NULL) { | |
| 278 DCHECK(message_hwnd_); | |
| 279 return; | |
|
jar (doing other things)
2012/05/15 21:39:42
These return on error condition appear to mask a s
alexeypa (please no reviews)
2012/05/15 22:10:27
Those DCHECKs migrated from the previous version o
| |
| 280 } | |
| 281 | |
| 282 // Store |this| so that the window procedure could retrieve it later. | |
| 283 SetWindowLongPtr(message_hwnd_, | |
|
alexeypa (please no reviews)
2012/05/15 22:10:27
The return value of SetWindowLongPtr should be che
| |
| 284 GWLP_USERDATA, | |
| 285 reinterpret_cast<LONG_PTR>(this)); | |
| 245 } | 286 } |
| 246 | 287 |
| 247 void MessagePumpForUI::WaitForWork() { | 288 void MessagePumpForUI::WaitForWork() { |
| 248 // Wait until a message is available, up to the time needed by the timer | 289 // Wait until a message is available, up to the time needed by the timer |
| 249 // manager to fire the next set of timers. | 290 // manager to fire the next set of timers. |
| 250 int delay = GetCurrentDelay(); | 291 int delay = GetCurrentDelay(); |
| 251 if (delay < 0) // Negative value means no timers waiting. | 292 if (delay < 0) // Negative value means no timers waiting. |
| 252 delay = INFINITE; | 293 delay = INFINITE; |
| 253 | 294 |
| 254 DWORD result; | 295 DWORD result; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 293 // messages that may be in the Windows message queue. | 334 // messages that may be in the Windows message queue. |
| 294 ProcessPumpReplacementMessage(); | 335 ProcessPumpReplacementMessage(); |
| 295 | 336 |
| 296 // Now give the delegate a chance to do some work. He'll let us know if he | 337 // Now give the delegate a chance to do some work. He'll let us know if he |
| 297 // needs to do more work. | 338 // needs to do more work. |
| 298 if (state_->delegate->DoWork()) | 339 if (state_->delegate->DoWork()) |
| 299 ScheduleWork(); | 340 ScheduleWork(); |
| 300 } | 341 } |
| 301 | 342 |
| 302 void MessagePumpForUI::HandleTimerMessage() { | 343 void MessagePumpForUI::HandleTimerMessage() { |
| 303 KillTimer(message_hwnd_, reinterpret_cast<UINT_PTR>(this)); | 344 KillTimer(message_hwnd_, kMessagePumpTimerId); |
| 304 | 345 |
| 305 // If we are being called outside of the context of Run, then don't do | 346 // If we are being called outside of the context of Run, then don't do |
| 306 // anything. This could correspond to a MessageBox call or something of | 347 // anything. This could correspond to a MessageBox call or something of |
| 307 // that sort. | 348 // that sort. |
| 308 if (!state_) | 349 if (!state_) |
| 309 return; | 350 return; |
| 310 | 351 |
| 311 state_->delegate->DoDelayedWork(&delayed_work_time_); | 352 state_->delegate->DoDelayedWork(&delayed_work_time_); |
| 312 if (!delayed_work_time_.is_null()) { | 353 if (!delayed_work_time_.is_null()) { |
| 313 // A bit gratuitous to set delayed_work_time_ again, but oh well. | 354 // A bit gratuitous to set delayed_work_time_ again, but oh well. |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 574 | 615 |
| 575 void MessagePumpForIO::WillProcessIOEvent() { | 616 void MessagePumpForIO::WillProcessIOEvent() { |
| 576 FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent()); | 617 FOR_EACH_OBSERVER(IOObserver, io_observers_, WillProcessIOEvent()); |
| 577 } | 618 } |
| 578 | 619 |
| 579 void MessagePumpForIO::DidProcessIOEvent() { | 620 void MessagePumpForIO::DidProcessIOEvent() { |
| 580 FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent()); | 621 FOR_EACH_OBSERVER(IOObserver, io_observers_, DidProcessIOEvent()); |
| 581 } | 622 } |
| 582 | 623 |
| 583 } // namespace base | 624 } // namespace base |
| OLD | NEW |