• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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