| // 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_bind.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_(NULL), |
| message_hwnd_(NULL) {} |
| |
| MainMessageLoopMultithreadedWin::~MainMessageLoopMultithreadedWin() { |
| DCHECK(RunsTasksOnCurrentThread()); |
| DCHECK(!message_hwnd_); |
| DCHECK(queued_tasks_.empty()); |
| } |
| |
| int MainMessageLoopMultithreadedWin::Run() { |
| DCHECK(RunsTasksOnCurrentThread()); |
| |
| HINSTANCE hInstance = ::GetModuleHandle(NULL); |
| |
| { |
| 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, NULL, 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_ = NULL; |
| } |
| |
| return static_cast<int>(msg.wParam); |
| } |
| |
| void MainMessageLoopMultithreadedWin::Quit() { |
| // Execute PostQuitMessage(0) on the main thread. |
| PostClosure(base::Bind(::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, NULL); |
| 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 |