Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: base/message_pump_win.cc

Issue 10826223: Replace PeekMessage for TSF awareness (Closed) Base URL: http://git.chromium.org/chromium/src.git@yukawa
Patch Set: change BOOL to bool, rename variables. Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/debug/trace_event.h" 9 #include "base/debug/trace_event.h"
10 #include "base/message_loop.h" 10 #include "base/message_loop.h"
11 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
12 #include "base/process_util.h" 12 #include "base/process_util.h"
13 #include "base/win/text_services_message_filter.h"
13 #include "base/win/wrapped_window_proc.h" 14 #include "base/win/wrapped_window_proc.h"
14 15
15 namespace { 16 namespace {
16 17
17 enum MessageLoopProblems { 18 enum MessageLoopProblems {
18 MESSAGE_POST_ERROR, 19 MESSAGE_POST_ERROR,
19 COMPLETION_POST_ERROR, 20 COMPLETION_POST_ERROR,
20 SET_TIMER_ERROR, 21 SET_TIMER_ERROR,
21 MESSAGE_LOOP_PROBLEM_MAX, 22 MESSAGE_LOOP_PROBLEM_MAX,
22 }; 23 };
23 24
25 class SimpleMessageFilter : public base::MessagePumpForUI::MessageFilter {
26 public:
27 virtual ~SimpleMessageFilter() {}
28 virtual bool Init() OVERRIDE {
29 return true;
30 }
31 virtual bool DoPeekMessage(MSG* message,
32 HWND window,
33 UINT msg_filter_min,
34 UINT msg_filter_max,
35 UINT remove_msg) OVERRIDE {
36 return !!PeekMessage(message, window, msg_filter_min, msg_filter_max,
37 remove_msg);
38 }
39 virtual bool ProcessMessage(const MSG& message) OVERRIDE {
40 return false;
41 }
42 };
43
24 } // namespace 44 } // namespace
25 45
26 namespace base { 46 namespace base {
27 47
28 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow"; 48 static const wchar_t kWndClass[] = L"Chrome_MessagePumpWindow";
29 49
30 // Message sent to get an additional time slice for pumping (processing) another 50 // Message sent to get an additional time slice for pumping (processing) another
31 // task (a series of such messages creates a continuous task pump). 51 // task (a series of such messages creates a continuous task pump).
32 static const int kMsgHaveWork = WM_USER + 1; 52 static const int kMsgHaveWork = WM_USER + 1;
33 53
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 delay = 0; 110 delay = 0;
91 111
92 return delay; 112 return delay;
93 } 113 }
94 114
95 //----------------------------------------------------------------------------- 115 //-----------------------------------------------------------------------------
96 // MessagePumpForUI public: 116 // MessagePumpForUI public:
97 117
98 MessagePumpForUI::MessagePumpForUI() : instance_(NULL) { 118 MessagePumpForUI::MessagePumpForUI() : instance_(NULL) {
99 InitMessageWnd(); 119 InitMessageWnd();
120
121 if (base::win::IsTsfAwareRequired())
122 message_filter_.reset(new win::TextServicesMessageFilter);
123
cpu_(ooo_6.6-7.5) 2012/08/23 23:51:16 I discussed it a bit with others and the COM issue
rvargas (doing something else) 2012/08/24 01:21:06 The first option is actually quite simple. The fil
124 if (!message_filter_.get() || !message_filter_->Init()) {
125 message_filter_.reset(new SimpleMessageFilter);
126 DCHECK(message_filter_->Init());
127 }
100 } 128 }
101 129
102 MessagePumpForUI::~MessagePumpForUI() { 130 MessagePumpForUI::~MessagePumpForUI() {
103 DestroyWindow(message_hwnd_); 131 DestroyWindow(message_hwnd_);
104 UnregisterClass(kWndClass, instance_); 132 UnregisterClass(kWndClass, instance_);
105 } 133 }
106 134
107 void MessagePumpForUI::ScheduleWork() { 135 void MessagePumpForUI::ScheduleWork() {
108 if (InterlockedExchange(&have_work_, 1)) 136 if (InterlockedExchange(&have_work_, 1))
109 return; // Someone else continued the pumping. 137 return; // Someone else continued the pumping.
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 if (!state_) 202 if (!state_)
175 return; 203 return;
176 204
177 // Create a mini-message-pump to force immediate processing of only Windows 205 // Create a mini-message-pump to force immediate processing of only Windows
178 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking 206 // WM_PAINT messages. Don't provide an infinite loop, but do enough peeking
179 // to get the job done. Actual common max is 4 peeks, but we'll be a little 207 // to get the job done. Actual common max is 4 peeks, but we'll be a little
180 // safe here. 208 // safe here.
181 const int kMaxPeekCount = 20; 209 const int kMaxPeekCount = 20;
182 int peek_count; 210 int peek_count;
183 for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) { 211 for (peek_count = 0; peek_count < kMaxPeekCount; ++peek_count) {
184 MSG msg; 212 MSG message;
185 if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_PAINT)) 213 if (!message_filter_->DoPeekMessage(&message, NULL, 0, 0,
214 PM_REMOVE | PM_QS_PAINT))
186 break; 215 break;
187 ProcessMessageHelper(msg); 216 ProcessMessageHelper(message);
188 if (state_->should_quit) // Handle WM_QUIT. 217 if (state_->should_quit) // Handle WM_QUIT.
189 break; 218 break;
190 } 219 }
191 // Histogram what was really being used, to help to adjust kMaxPeekCount. 220 // Histogram what was really being used, to help to adjust kMaxPeekCount.
192 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count); 221 DHISTOGRAM_COUNTS("Loop.PumpOutPendingPaintMessages Peeks", peek_count);
193 } 222 }
194 223
195 //----------------------------------------------------------------------------- 224 //-----------------------------------------------------------------------------
196 // MessagePumpForUI private: 225 // MessagePumpForUI private:
197 226
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 317
289 DWORD result; 318 DWORD result;
290 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, 319 result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT,
291 MWMO_INPUTAVAILABLE); 320 MWMO_INPUTAVAILABLE);
292 321
293 if (WAIT_OBJECT_0 == result) { 322 if (WAIT_OBJECT_0 == result) {
294 // A WM_* message is available. 323 // A WM_* message is available.
295 // If a parent child relationship exists between windows across threads 324 // If a parent child relationship exists between windows across threads
296 // then their thread inputs are implicitly attached. 325 // then their thread inputs are implicitly attached.
297 // This causes the MsgWaitForMultipleObjectsEx API to return indicating 326 // This causes the MsgWaitForMultipleObjectsEx API to return indicating
298 // that messages are ready for processing (specifically mouse messages 327 // that messages are ready for processing (Specifically, mouse messages
299 // intended for the child window. Occurs if the child window has capture) 328 // intended for the child window may appear if the child window has
300 // The subsequent PeekMessages call fails to return any messages thus 329 // capture).
330 // The subsequent PeekMessages call may fail to return any messages thus
301 // causing us to enter a tight loop at times. 331 // causing us to enter a tight loop at times.
302 // The WaitMessage call below is a workaround to give the child window 332 // The WaitMessage call below is a workaround to give the child window
303 // sometime to process its input messages. 333 // some time to process its input messages.
304 MSG msg = {0}; 334 MSG msg = {0};
305 DWORD queue_status = GetQueueStatus(QS_MOUSE); 335 DWORD queue_status = GetQueueStatus(QS_MOUSE);
306 if (HIWORD(queue_status) & QS_MOUSE && 336 if (HIWORD(queue_status) & QS_MOUSE &&
307 !PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_NOREMOVE)) { 337 !message_filter_->DoPeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST,
338 PM_NOREMOVE)) {
308 WaitMessage(); 339 WaitMessage();
309 } 340 }
310 return; 341 return;
311 } 342 }
312 343
313 DCHECK_NE(WAIT_FAILED, result) << GetLastError(); 344 DCHECK_NE(WAIT_FAILED, result) << GetLastError();
314 } 345 }
315 346
316 void MessagePumpForUI::HandleWorkMessage() { 347 void MessagePumpForUI::HandleWorkMessage() {
317 // If we are being called outside of the context of Run, then don't try to do 348 // If we are being called outside of the context of Run, then don't try to do
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 // If there are sent messages in the queue then PeekMessage internally 385 // If there are sent messages in the queue then PeekMessage internally
355 // dispatches the message and returns false. We return true in this 386 // dispatches the message and returns false. We return true in this
356 // case to ensure that the message loop peeks again instead of calling 387 // case to ensure that the message loop peeks again instead of calling
357 // MsgWaitForMultipleObjectsEx again. 388 // MsgWaitForMultipleObjectsEx again.
358 bool sent_messages_in_queue = false; 389 bool sent_messages_in_queue = false;
359 DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE); 390 DWORD queue_status = GetQueueStatus(QS_SENDMESSAGE);
360 if (HIWORD(queue_status) & QS_SENDMESSAGE) 391 if (HIWORD(queue_status) & QS_SENDMESSAGE)
361 sent_messages_in_queue = true; 392 sent_messages_in_queue = true;
362 393
363 MSG msg; 394 MSG msg;
364 if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 395 if (message_filter_->DoPeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
365 return ProcessMessageHelper(msg); 396 return ProcessMessageHelper(msg);
366 397
367 return sent_messages_in_queue; 398 return sent_messages_in_queue;
368 } 399 }
369 400
370 bool MessagePumpForUI::ProcessMessageHelper(const MSG& msg) { 401 bool MessagePumpForUI::ProcessMessageHelper(const MSG& message) {
371 TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper", 402 TRACE_EVENT1("base", "MessagePumpForUI::ProcessMessageHelper",
372 "message", msg.message); 403 "message", message.message);
373 if (WM_QUIT == msg.message) { 404 if (WM_QUIT == message.message) {
374 // Repost the QUIT message so that it will be retrieved by the primary 405 // Repost the QUIT message so that it will be retrieved by the primary
375 // GetMessage() loop. 406 // GetMessage() loop.
376 state_->should_quit = true; 407 state_->should_quit = true;
377 PostQuitMessage(static_cast<int>(msg.wParam)); 408 PostQuitMessage(static_cast<int>(message.wParam));
378 return false; 409 return false;
379 } 410 }
380 411
381 // While running our main message pump, we discard kMsgHaveWork messages. 412 // While running our main message pump, we discard kMsgHaveWork messages.
382 if (msg.message == kMsgHaveWork && msg.hwnd == message_hwnd_) 413 if (message.message == kMsgHaveWork && message.hwnd == message_hwnd_)
383 return ProcessPumpReplacementMessage(); 414 return ProcessPumpReplacementMessage();
384 415
385 if (CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode)) 416 if (CallMsgFilter(const_cast<MSG*>(&message), kMessageFilterCode))
386 return true; 417 return true;
387 418
388 WillProcessMessage(msg); 419 WillProcessMessage(message);
389 420
390 if (state_->dispatcher) { 421 if (!message_filter_->ProcessMessage(message)) {
391 if (!state_->dispatcher->Dispatch(msg)) 422 if (state_->dispatcher) {
392 state_->should_quit = true; 423 if (!state_->dispatcher->Dispatch(message))
393 } else { 424 state_->should_quit = true;
394 TranslateMessage(&msg); 425 } else {
395 DispatchMessage(&msg); 426 TranslateMessage(&message);
427 DispatchMessage(&message);
428 }
396 } 429 }
397 430
398 DidProcessMessage(msg); 431 DidProcessMessage(message);
399 return true; 432 return true;
400 } 433 }
401 434
402 bool MessagePumpForUI::ProcessPumpReplacementMessage() { 435 bool MessagePumpForUI::ProcessPumpReplacementMessage() {
403 // When we encounter a kMsgHaveWork message, this method is called to peek 436 // When we encounter a kMsgHaveWork message, this method is called to peek
404 // and process a replacement message, such as a WM_PAINT or WM_TIMER. The 437 // and process a replacement message, such as a WM_PAINT or WM_TIMER. The
405 // goal is to make the kMsgHaveWork as non-intrusive as possible, even though 438 // goal is to make the kMsgHaveWork as non-intrusive as possible, even though
406 // a continuous stream of such messages are posted. This method carefully 439 // a continuous stream of such messages are posted. This method carefully
407 // peeks a message while there is no chance for a kMsgHaveWork to be pending, 440 // peeks a message while there is no chance for a kMsgHaveWork to be pending,
408 // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to 441 // then resets the have_work_ flag (allowing a replacement kMsgHaveWork to
409 // possibly be posted), and finally dispatches that peeked replacement. Note 442 // possibly be posted), and finally dispatches that peeked replacement. Note
410 // that the re-post of kMsgHaveWork may be asynchronous to this thread!! 443 // that the re-post of kMsgHaveWork may be asynchronous to this thread!!
411 444
412 bool have_message = false; 445 bool have_message = false;
413 MSG msg; 446 MSG message;
414 // We should not process all window messages if we are in the context of an 447 // We should not process all window messages if we are in the context of an
415 // OS modal loop, i.e. in the context of a windows API call like MessageBox. 448 // OS modal loop, i.e. in the context of a windows API call like MessageBox.
416 // This is to ensure that these messages are peeked out by the OS modal loop. 449 // This is to ensure that these messages are peeked out by the OS modal loop.
417 if (MessageLoop::current()->os_modal_loop()) { 450 if (MessageLoop::current()->os_modal_loop()) {
418 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above. 451 // We only peek out WM_PAINT and WM_TIMER here for reasons mentioned above.
419 have_message = PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE) || 452 have_message =
420 PeekMessage(&msg, NULL, WM_TIMER, WM_TIMER, PM_REMOVE); 453 message_filter_->DoPeekMessage(&message, NULL, WM_PAINT, WM_PAINT,
454 PM_REMOVE) ||
455 message_filter_->DoPeekMessage(&message, NULL, WM_TIMER, WM_TIMER,
456 PM_REMOVE);
421 } else { 457 } else {
422 have_message = (0 != PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)); 458 have_message = message_filter_->DoPeekMessage(&message, NULL, 0, 0,
459 PM_REMOVE);
423 } 460 }
424 461
425 DCHECK(!have_message || kMsgHaveWork != msg.message || 462 DCHECK(!have_message || kMsgHaveWork != message.message ||
426 msg.hwnd != message_hwnd_); 463 message.hwnd != message_hwnd_);
427 464
428 // Since we discarded a kMsgHaveWork message, we must update the flag. 465 // Since we discarded a kMsgHaveWork message, we must update the flag.
429 int old_have_work = InterlockedExchange(&have_work_, 0); 466 int old_have_work = InterlockedExchange(&have_work_, 0);
430 DCHECK(old_have_work); 467 DCHECK(old_have_work);
431 468
432 // We don't need a special time slice if we didn't have_message to process. 469 // We don't need a special time slice if we didn't have_message to process.
433 if (!have_message) 470 if (!have_message)
434 return false; 471 return false;
435 472
436 // Guarantee we'll get another time slice in the case where we go into native 473 // Guarantee we'll get another time slice in the case where we go into native
437 // windows code. This ScheduleWork() may hurt performance a tiny bit when 474 // windows code. This ScheduleWork() may hurt performance a tiny bit when
438 // tasks appear very infrequently, but when the event queue is busy, the 475 // tasks appear very infrequently, but when the event queue is busy, the
439 // kMsgHaveWork events get (percentage wise) rarer and rarer. 476 // kMsgHaveWork events get (percentage wise) rarer and rarer.
440 ScheduleWork(); 477 ScheduleWork();
441 return ProcessMessageHelper(msg); 478 return ProcessMessageHelper(message);
442 } 479 }
443 480
444 //----------------------------------------------------------------------------- 481 //-----------------------------------------------------------------------------
445 // MessagePumpForIO public: 482 // MessagePumpForIO public:
446 483
447 MessagePumpForIO::MessagePumpForIO() { 484 MessagePumpForIO::MessagePumpForIO() {
448 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1)); 485 port_.Set(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1));
449 DCHECK(port_.IsValid()); 486 DCHECK(port_.IsValid());
450 } 487 }
451 488
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
660 697
661 // static 698 // static
662 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler( 699 MessagePumpForIO::IOHandler* MessagePumpForIO::KeyToHandler(
663 ULONG_PTR key, 700 ULONG_PTR key,
664 bool* has_valid_io_context) { 701 bool* has_valid_io_context) {
665 *has_valid_io_context = ((key & 1) == 0); 702 *has_valid_io_context = ((key & 1) == 0);
666 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1)); 703 return reinterpret_cast<IOHandler*>(key & ~static_cast<ULONG_PTR>(1));
667 } 704 }
668 705
669 } // namespace base 706 } // namespace base
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698