1 // Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4
5 #include "tests/shared/browser/main_message_loop_external_pump.h"
6
7 #include <CommCtrl.h>
8
9 #include <memory>
10
11 #include "include/cef_app.h"
12 #include "tests/shared/browser/util_win.h"
13
14 namespace client {
15
16 namespace {
17
18 // Message sent to get an additional time slice for pumping (processing) another
19 // task (a series of such messages creates a continuous task pump).
20 static const int kMsgHaveWork = WM_USER + 1;
21
22 class MainMessageLoopExternalPumpWin : public MainMessageLoopExternalPump {
23 public:
24 MainMessageLoopExternalPumpWin();
25 ~MainMessageLoopExternalPumpWin();
26
27 // MainMessageLoopStd methods:
28 void Quit() override;
29 int Run() override;
30
31 // MainMessageLoopExternalPump methods:
32 void OnScheduleMessagePumpWork(int64 delay_ms) override;
33
34 protected:
35 // MainMessageLoopExternalPump methods:
36 void SetTimer(int64 delay_ms) override;
37 void KillTimer() override;
IsTimerPending()38 bool IsTimerPending() override { return timer_pending_; }
39
40 private:
41 static LRESULT CALLBACK WndProc(HWND hwnd,
42 UINT msg,
43 WPARAM wparam,
44 LPARAM lparam);
45
46 // True if a timer event is currently pending.
47 bool timer_pending_;
48
49 // HWND owned by the thread that CefDoMessageLoopWork should be invoked on.
50 HWND main_thread_target_;
51 };
52
MainMessageLoopExternalPumpWin()53 MainMessageLoopExternalPumpWin::MainMessageLoopExternalPumpWin()
54 : timer_pending_(false), main_thread_target_(nullptr) {
55 HINSTANCE hInstance = GetModuleHandle(nullptr);
56 const wchar_t* const kClassName = L"CEFMainTargetHWND";
57
58 WNDCLASSEX wcex = {};
59 wcex.cbSize = sizeof(WNDCLASSEX);
60 wcex.lpfnWndProc = WndProc;
61 wcex.hInstance = hInstance;
62 wcex.lpszClassName = kClassName;
63 RegisterClassEx(&wcex);
64
65 // Create the message handling window.
66 main_thread_target_ =
67 CreateWindowW(kClassName, nullptr, WS_OVERLAPPEDWINDOW, 0, 0, 0, 0,
68 HWND_MESSAGE, nullptr, hInstance, nullptr);
69 DCHECK(main_thread_target_);
70 SetUserDataPtr(main_thread_target_, this);
71 }
72
~MainMessageLoopExternalPumpWin()73 MainMessageLoopExternalPumpWin::~MainMessageLoopExternalPumpWin() {
74 KillTimer();
75 if (main_thread_target_)
76 DestroyWindow(main_thread_target_);
77 }
78
Quit()79 void MainMessageLoopExternalPumpWin::Quit() {
80 PostMessage(nullptr, WM_QUIT, 0, 0);
81 }
82
Run()83 int MainMessageLoopExternalPumpWin::Run() {
84 // Run the message loop.
85 MSG msg;
86 while (GetMessage(&msg, nullptr, 0, 0)) {
87 TranslateMessage(&msg);
88 DispatchMessage(&msg);
89 }
90
91 KillTimer();
92
93 // We need to run the message pump until it is idle. However we don't have
94 // that information here so we run the message loop "for a while".
95 for (int i = 0; i < 10; ++i) {
96 // Do some work.
97 CefDoMessageLoopWork();
98
99 // Sleep to allow the CEF proc to do work.
100 Sleep(50);
101 }
102
103 return 0;
104 }
105
OnScheduleMessagePumpWork(int64 delay_ms)106 void MainMessageLoopExternalPumpWin::OnScheduleMessagePumpWork(int64 delay_ms) {
107 // This method may be called on any thread.
108 PostMessage(main_thread_target_, kMsgHaveWork, 0,
109 static_cast<LPARAM>(delay_ms));
110 }
111
SetTimer(int64 delay_ms)112 void MainMessageLoopExternalPumpWin::SetTimer(int64 delay_ms) {
113 DCHECK(!timer_pending_);
114 DCHECK_GT(delay_ms, 0);
115 timer_pending_ = true;
116 ::SetTimer(main_thread_target_, 1, static_cast<UINT>(delay_ms), nullptr);
117 }
118
KillTimer()119 void MainMessageLoopExternalPumpWin::KillTimer() {
120 if (timer_pending_) {
121 ::KillTimer(main_thread_target_, 1);
122 timer_pending_ = false;
123 }
124 }
125
126 // static
WndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)127 LRESULT CALLBACK MainMessageLoopExternalPumpWin::WndProc(HWND hwnd,
128 UINT msg,
129 WPARAM wparam,
130 LPARAM lparam) {
131 if (msg == WM_TIMER || msg == kMsgHaveWork) {
132 MainMessageLoopExternalPumpWin* message_loop =
133 GetUserDataPtr<MainMessageLoopExternalPumpWin*>(hwnd);
134 if (msg == kMsgHaveWork) {
135 // OnScheduleMessagePumpWork() request.
136 const int64 delay_ms = static_cast<int64>(lparam);
137 message_loop->OnScheduleWork(delay_ms);
138 } else {
139 // Timer timed out.
140 message_loop->OnTimerTimeout();
141 }
142 }
143 return DefWindowProc(hwnd, msg, wparam, lparam);
144 }
145
146 } // namespace
147
148 // static
149 std::unique_ptr<MainMessageLoopExternalPump>
Create()150 MainMessageLoopExternalPump::Create() {
151 return std::make_unique<MainMessageLoopExternalPumpWin>();
152 }
153
154 } // namespace client
155