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 |