172 lines
4.7 KiB
C++
172 lines
4.7 KiB
C++
// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights
|
|
// reserved. Use of this source code is governed by a BSD-style license that
|
|
// can be found in the LICENSE file.
|
|
|
|
#include "tests/cefclient/browser/main_message_loop_multithreaded_win.h"
|
|
|
|
#include "include/base/cef_callback.h"
|
|
#include "include/base/cef_logging.h"
|
|
#include "include/cef_app.h"
|
|
#include "tests/cefclient/browser/resource.h"
|
|
#include "tests/shared/browser/util_win.h"
|
|
|
|
namespace client {
|
|
|
|
namespace {
|
|
|
|
const wchar_t kWndClass[] = L"Client_MessageWindow";
|
|
const wchar_t kTaskMessageName[] = L"Client_CustomTask";
|
|
|
|
} // namespace
|
|
|
|
MainMessageLoopMultithreadedWin::MainMessageLoopMultithreadedWin()
|
|
: thread_id_(base::PlatformThread::CurrentId()),
|
|
task_message_id_(RegisterWindowMessage(kTaskMessageName)),
|
|
dialog_hwnd_(nullptr),
|
|
message_hwnd_(nullptr) {}
|
|
|
|
MainMessageLoopMultithreadedWin::~MainMessageLoopMultithreadedWin() {
|
|
DCHECK(RunsTasksOnCurrentThread());
|
|
DCHECK(!message_hwnd_);
|
|
DCHECK(queued_tasks_.empty());
|
|
}
|
|
|
|
int MainMessageLoopMultithreadedWin::Run() {
|
|
DCHECK(RunsTasksOnCurrentThread());
|
|
|
|
HINSTANCE hInstance = ::GetModuleHandle(nullptr);
|
|
|
|
{
|
|
base::AutoLock lock_scope(lock_);
|
|
|
|
// Create the hidden window for message processing.
|
|
message_hwnd_ = CreateMessageWindow(hInstance);
|
|
CHECK(message_hwnd_);
|
|
|
|
// Store a pointer to |this| in the window's user data.
|
|
SetUserDataPtr(message_hwnd_, this);
|
|
|
|
// Execute any tasks that are currently queued.
|
|
while (!queued_tasks_.empty()) {
|
|
PostTaskInternal(queued_tasks_.front());
|
|
queued_tasks_.pop();
|
|
}
|
|
}
|
|
|
|
HACCEL hAccelTable =
|
|
LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CEFCLIENT));
|
|
|
|
MSG msg;
|
|
|
|
// Run the application message loop.
|
|
while (GetMessage(&msg, nullptr, 0, 0)) {
|
|
// Allow processing of dialog messages.
|
|
if (dialog_hwnd_ && IsDialogMessage(dialog_hwnd_, &msg))
|
|
continue;
|
|
|
|
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
|
|
{
|
|
base::AutoLock lock_scope(lock_);
|
|
|
|
// Destroy the message window.
|
|
DestroyWindow(message_hwnd_);
|
|
message_hwnd_ = nullptr;
|
|
}
|
|
|
|
return static_cast<int>(msg.wParam);
|
|
}
|
|
|
|
void MainMessageLoopMultithreadedWin::Quit() {
|
|
// Execute PostQuitMessage(0) on the main thread.
|
|
PostClosure(base::BindOnce(::PostQuitMessage, 0));
|
|
}
|
|
|
|
void MainMessageLoopMultithreadedWin::PostTask(CefRefPtr<CefTask> task) {
|
|
base::AutoLock lock_scope(lock_);
|
|
PostTaskInternal(task);
|
|
}
|
|
|
|
bool MainMessageLoopMultithreadedWin::RunsTasksOnCurrentThread() const {
|
|
return (thread_id_ == base::PlatformThread::CurrentId());
|
|
}
|
|
|
|
void MainMessageLoopMultithreadedWin::SetCurrentModelessDialog(
|
|
HWND hWndDialog) {
|
|
DCHECK(RunsTasksOnCurrentThread());
|
|
|
|
#if DCHECK_IS_ON()
|
|
if (hWndDialog) {
|
|
// A new dialog reference should not be set while one is currently set.
|
|
DCHECK(!dialog_hwnd_);
|
|
}
|
|
#endif
|
|
dialog_hwnd_ = hWndDialog;
|
|
}
|
|
|
|
// static
|
|
HWND MainMessageLoopMultithreadedWin::CreateMessageWindow(HINSTANCE hInstance) {
|
|
WNDCLASSEX wc = {0};
|
|
wc.cbSize = sizeof(wc);
|
|
wc.lpfnWndProc = MessageWndProc;
|
|
wc.hInstance = hInstance;
|
|
wc.lpszClassName = kWndClass;
|
|
RegisterClassEx(&wc);
|
|
|
|
return CreateWindow(kWndClass, 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hInstance,
|
|
0);
|
|
}
|
|
|
|
// static
|
|
LRESULT CALLBACK
|
|
MainMessageLoopMultithreadedWin::MessageWndProc(HWND hWnd,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam) {
|
|
MainMessageLoopMultithreadedWin* self =
|
|
GetUserDataPtr<MainMessageLoopMultithreadedWin*>(hWnd);
|
|
|
|
if (self && message == self->task_message_id_) {
|
|
// Execute the task.
|
|
CefTask* task = reinterpret_cast<CefTask*>(wParam);
|
|
task->Execute();
|
|
|
|
// Release the reference added in PostTaskInternal. This will likely result
|
|
// in |task| being deleted.
|
|
task->Release();
|
|
} else {
|
|
switch (message) {
|
|
case WM_NCDESTROY:
|
|
// Clear the reference to |self|.
|
|
SetUserDataPtr(hWnd, nullptr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return DefWindowProc(hWnd, message, wParam, lParam);
|
|
}
|
|
|
|
void MainMessageLoopMultithreadedWin::PostTaskInternal(
|
|
CefRefPtr<CefTask> task) {
|
|
lock_.AssertAcquired();
|
|
|
|
if (!message_hwnd_) {
|
|
// Queue the task until the message loop starts running.
|
|
queued_tasks_.push(task);
|
|
return;
|
|
}
|
|
|
|
// Add a reference that will be released in MessageWndProc.
|
|
task->AddRef();
|
|
|
|
// Post the task for execution by the message window.
|
|
PostMessage(message_hwnd_, task_message_id_,
|
|
reinterpret_cast<WPARAM>(task.get()), 0);
|
|
}
|
|
|
|
} // namespace client
|