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