mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-02-16 20:20:51 +01:00
cefclient: Use an abstraction for message loop functionality (Run/Quit/PostTask) instead of implementing the same logic multiple times in platform-specific files (issue #1500).
git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1982 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
parent
4bf08b70d6
commit
249ad7f6e4
@ -165,6 +165,10 @@
|
||||
'tests/cefclient/dialog_test.cc',
|
||||
'tests/cefclient/dialog_test.h',
|
||||
'tests/cefclient/dragdrop_events.h',
|
||||
'tests/cefclient/main_message_loop.h',
|
||||
'tests/cefclient/main_message_loop.cc',
|
||||
'tests/cefclient/main_message_loop_std.h',
|
||||
'tests/cefclient/main_message_loop_std.cc',
|
||||
'tests/cefclient/osrenderer.h',
|
||||
'tests/cefclient/osrenderer.cc',
|
||||
'tests/cefclient/performance_test.cc',
|
||||
@ -189,10 +193,14 @@
|
||||
'tests/cefclient/cefclient_osr_widget_win.cc',
|
||||
'tests/cefclient/cefclient_win.cc',
|
||||
'tests/cefclient/client_handler_win.cc',
|
||||
'tests/cefclient/main_message_loop_multithreaded_win.h',
|
||||
'tests/cefclient/main_message_loop_multithreaded_win.cc',
|
||||
'tests/cefclient/resource.h',
|
||||
'tests/cefclient/res/cefclient.ico',
|
||||
'tests/cefclient/res/small.ico',
|
||||
'tests/cefclient/resource_util_win.cc',
|
||||
'tests/cefclient/util_win.h',
|
||||
'tests/cefclient/util_win.cc',
|
||||
'tests/cefclient/window_test_win.cc',
|
||||
],
|
||||
'cefclient_sources_mac': [
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "cefclient/cefclient_osr_widget_gtk.h"
|
||||
#include "cefclient/client_handler.h"
|
||||
#include "cefclient/client_switches.h"
|
||||
#include "cefclient/main_message_loop_std.h"
|
||||
#include "cefclient/scheme_test.h"
|
||||
#include "cefclient/string_util.h"
|
||||
|
||||
@ -453,6 +454,10 @@ int main(int argc, char* argv[]) {
|
||||
XSetErrorHandler(XErrorHandlerImpl);
|
||||
XSetIOErrorHandler(XIOErrorHandlerImpl);
|
||||
|
||||
// Create the main message loop object.
|
||||
scoped_ptr<client::MainMessageLoop> message_loop(
|
||||
new client::MainMessageLoopStd);
|
||||
|
||||
// Initialize CEF.
|
||||
CefInitialize(main_args, settings, app.get(), NULL);
|
||||
|
||||
@ -582,11 +587,16 @@ int main(int argc, char* argv[]) {
|
||||
signal(SIGINT, TerminationSignalHandler);
|
||||
signal(SIGTERM, TerminationSignalHandler);
|
||||
|
||||
CefRunMessageLoop();
|
||||
// Run the message loop. This will block until Quit() is called.
|
||||
int result = message_loop->Run();
|
||||
|
||||
// Shut down CEF.
|
||||
CefShutdown();
|
||||
|
||||
return 0;
|
||||
// Release the |message_loop| object.
|
||||
message_loop.reset();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Global functions
|
||||
@ -596,5 +606,5 @@ std::string AppGetWorkingDirectory() {
|
||||
}
|
||||
|
||||
void AppQuitMessageLoop() {
|
||||
CefQuitMessageLoop();
|
||||
client::MainMessageLoop::Get()->Quit();
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "cefclient/cefclient_osr_widget_mac.h"
|
||||
#include "cefclient/client_handler.h"
|
||||
#include "cefclient/client_switches.h"
|
||||
#include "cefclient/main_message_loop_std.h"
|
||||
#include "cefclient/resource_util.h"
|
||||
#include "cefclient/scheme_test.h"
|
||||
#include "cefclient/string_util.h"
|
||||
@ -622,6 +623,10 @@ int main(int argc, char* argv[]) {
|
||||
// Populate the settings based on command line arguments.
|
||||
AppGetSettings(settings);
|
||||
|
||||
// Create the main message loop object.
|
||||
scoped_ptr<client::MainMessageLoop> message_loop(
|
||||
new client::MainMessageLoopStd);
|
||||
|
||||
// Initialize CEF.
|
||||
CefInitialize(main_args, settings, app.get(), NULL);
|
||||
|
||||
@ -634,8 +639,8 @@ int main(int argc, char* argv[]) {
|
||||
withObject:nil
|
||||
waitUntilDone:NO];
|
||||
|
||||
// Run the application message loop.
|
||||
CefRunMessageLoop();
|
||||
// Run the message loop. This will block until Quit() is called.
|
||||
int result = message_loop->Run();
|
||||
|
||||
// Shut down CEF.
|
||||
CefShutdown();
|
||||
@ -649,7 +654,10 @@ int main(int argc, char* argv[]) {
|
||||
// Release the AutoRelease pool.
|
||||
[autopool release];
|
||||
|
||||
return 0;
|
||||
// Release the |message_loop| object.
|
||||
message_loop.reset();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -660,5 +668,5 @@ std::string AppGetWorkingDirectory() {
|
||||
}
|
||||
|
||||
void AppQuitMessageLoop() {
|
||||
CefQuitMessageLoop();
|
||||
client::MainMessageLoop::Get()->Quit();
|
||||
}
|
||||
|
@ -20,9 +20,12 @@
|
||||
#include "cefclient/cefclient_osr_widget_win.h"
|
||||
#include "cefclient/client_handler.h"
|
||||
#include "cefclient/client_switches.h"
|
||||
#include "cefclient/main_message_loop_multithreaded_win.h"
|
||||
#include "cefclient/main_message_loop_std.h"
|
||||
#include "cefclient/resource.h"
|
||||
#include "cefclient/scheme_test.h"
|
||||
#include "cefclient/string_util.h"
|
||||
#include "cefclient/util_win.h"
|
||||
|
||||
|
||||
// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
|
||||
@ -56,14 +59,9 @@ HWND hFindDlg = NULL; // Handle for the find dialog.
|
||||
ATOM MyRegisterClass(HINSTANCE hInstance);
|
||||
BOOL InitInstance(HINSTANCE, int);
|
||||
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
LRESULT CALLBACK FindProc(HWND, UINT, WPARAM, LPARAM);
|
||||
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
// Used for processing messages on the main application thread while running
|
||||
// in multi-threaded message loop mode.
|
||||
HWND hMessageWnd = NULL;
|
||||
HWND CreateMessageWindow(HINSTANCE hInstance);
|
||||
LRESULT CALLBACK MessageWndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
// The global ClientHandler reference.
|
||||
extern CefRefPtr<ClientHandler> g_handler;
|
||||
|
||||
@ -116,15 +114,20 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
|
||||
|
||||
// Populate the settings based on command line arguments.
|
||||
AppGetSettings(settings);
|
||||
|
||||
|
||||
// Create the main message loop object.
|
||||
scoped_ptr<client::MainMessageLoop> message_loop;
|
||||
if (settings.multi_threaded_message_loop)
|
||||
message_loop.reset(new client::MainMessageLoopMultithreadedWin);
|
||||
else
|
||||
message_loop.reset(new client::MainMessageLoopStd);
|
||||
|
||||
// Initialize CEF.
|
||||
CefInitialize(main_args, settings, app.get(), sandbox_info);
|
||||
|
||||
// Register the scheme handler.
|
||||
scheme_test::InitTest();
|
||||
|
||||
HACCEL hAccelTable;
|
||||
|
||||
// Initialize global strings
|
||||
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
|
||||
LoadString(hInstance, IDC_CEFCLIENT, szWindowClass, MAX_LOADSTRING);
|
||||
@ -135,45 +138,18 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
|
||||
if (!InitInstance (hInstance, nCmdShow))
|
||||
return FALSE;
|
||||
|
||||
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CEFCLIENT));
|
||||
|
||||
// Register the find event message.
|
||||
uFindMsg = RegisterWindowMessage(FINDMSGSTRING);
|
||||
|
||||
int result = 0;
|
||||
|
||||
if (!settings.multi_threaded_message_loop) {
|
||||
// Run the CEF message loop. This function will block until the application
|
||||
// recieves a WM_QUIT message.
|
||||
CefRunMessageLoop();
|
||||
} else {
|
||||
// Create a hidden window for message processing.
|
||||
hMessageWnd = CreateMessageWindow(hInstance);
|
||||
DCHECK(hMessageWnd);
|
||||
|
||||
MSG msg;
|
||||
|
||||
// Run the application message loop.
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
// Allow processing of find dialog messages.
|
||||
if (hFindDlg && IsDialogMessage(hFindDlg, &msg))
|
||||
continue;
|
||||
|
||||
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
DestroyWindow(hMessageWnd);
|
||||
hMessageWnd = NULL;
|
||||
|
||||
result = static_cast<int>(msg.wParam);
|
||||
}
|
||||
// Run the message loop. This will block until Quit() is called.
|
||||
int result = message_loop->Run();
|
||||
|
||||
// Shut down CEF.
|
||||
CefShutdown();
|
||||
|
||||
// Release the |message_loop| object.
|
||||
message_loop.reset();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -518,6 +494,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
fr.Flags = FR_HIDEWHOLEWORD | FR_DOWN;
|
||||
|
||||
hFindDlg = FindText(&fr);
|
||||
|
||||
// Override the dialog's window procedure.
|
||||
WNDPROC wndproc_old = client::SetWndProcPtr(hFindDlg, FindProc);
|
||||
|
||||
// Associate |wndproc_old| with the dialog.
|
||||
client::SetUserDataPtr(hFindDlg, wndproc_old);
|
||||
} else {
|
||||
// Give focus to the existing find dialog.
|
||||
::SetFocus(hFindDlg);
|
||||
@ -708,6 +690,29 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
}
|
||||
}
|
||||
|
||||
// Message handler for the find dialog.
|
||||
LRESULT CALLBACK FindProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
REQUIRE_MAIN_THREAD();
|
||||
|
||||
WNDPROC old_wndproc = client::GetUserDataPtr<WNDPROC>(hWnd);
|
||||
DCHECK(old_wndproc);
|
||||
|
||||
switch (message) {
|
||||
case WM_ACTIVATE:
|
||||
// Set this dialog as current when activated.
|
||||
client::MainMessageLoop::Get()->SetCurrentModelessDialog(
|
||||
wParam == 0 ? NULL : hWnd);
|
||||
return FALSE;
|
||||
case WM_NCDESTROY:
|
||||
// Clear the reference to |old_wndproc|.
|
||||
client::SetUserDataPtr(hWnd, NULL);
|
||||
break;
|
||||
}
|
||||
|
||||
return CallWindowProc(old_wndproc, hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
// Message handler for about box.
|
||||
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
UNREFERENCED_PARAMETER(lParam);
|
||||
@ -725,35 +730,6 @@ INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
return (INT_PTR)FALSE;
|
||||
}
|
||||
|
||||
HWND CreateMessageWindow(HINSTANCE hInstance) {
|
||||
static const wchar_t kWndClass[] = L"ClientMessageWindow";
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK MessageWndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
switch (message) {
|
||||
case WM_COMMAND: {
|
||||
int wmId = LOWORD(wParam);
|
||||
switch (wmId) {
|
||||
case ID_QUIT:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
// Global functions
|
||||
|
||||
@ -762,13 +738,5 @@ std::string AppGetWorkingDirectory() {
|
||||
}
|
||||
|
||||
void AppQuitMessageLoop() {
|
||||
CefRefPtr<CefCommandLine> command_line = AppGetCommandLine();
|
||||
if (command_line->HasSwitch(cefclient::kMultiThreadedMessageLoop)) {
|
||||
// Running in multi-threaded message loop mode. Need to execute
|
||||
// PostQuitMessage on the main application thread.
|
||||
DCHECK(hMessageWnd);
|
||||
PostMessage(hMessageWnd, WM_COMMAND, ID_QUIT, 0);
|
||||
} else {
|
||||
CefQuitMessageLoop();
|
||||
}
|
||||
client::MainMessageLoop::Get()->Quit();
|
||||
}
|
||||
|
37
tests/cefclient/main_message_loop.cc
Normal file
37
tests/cefclient/main_message_loop.cc
Normal file
@ -0,0 +1,37 @@
|
||||
// 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 "cefclient/main_message_loop.h"
|
||||
|
||||
#include "include/cef_task.h"
|
||||
#include "include/wrapper/cef_closure_task.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
namespace {
|
||||
|
||||
MainMessageLoop* g_main_message_loop = NULL;
|
||||
|
||||
} // namespace
|
||||
|
||||
MainMessageLoop::MainMessageLoop() {
|
||||
DCHECK(!g_main_message_loop);
|
||||
g_main_message_loop = this;
|
||||
}
|
||||
|
||||
MainMessageLoop::~MainMessageLoop() {
|
||||
g_main_message_loop = NULL;
|
||||
}
|
||||
|
||||
// static
|
||||
MainMessageLoop* MainMessageLoop::Get() {
|
||||
DCHECK(g_main_message_loop);
|
||||
return g_main_message_loop;
|
||||
}
|
||||
|
||||
void MainMessageLoop::PostClosure(const base::Closure& closure) {
|
||||
PostTask(CefCreateClosureTask(closure));
|
||||
}
|
||||
|
||||
} // namespace client
|
120
tests/cefclient/main_message_loop.h
Normal file
120
tests/cefclient/main_message_loop.h
Normal file
@ -0,0 +1,120 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CEF_TESTS_CEFCLIENT_MAIN_MESSAGE_LOOP_H_
|
||||
#define CEF_TESTS_CEFCLIENT_MAIN_MESSAGE_LOOP_H_
|
||||
|
||||
#include "include/base/cef_bind.h"
|
||||
#include "include/base/cef_scoped_ptr.h"
|
||||
#include "include/cef_task.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
namespace client {
|
||||
|
||||
// Represents the message loop running on the main application thread in the
|
||||
// browser process. This will be the same as the CEF UI thread on Linux, OS X
|
||||
// and Windows when not using multi-threaded message loop mode. The methods of
|
||||
// this class are thread-safe unless otherwise indicated.
|
||||
class MainMessageLoop {
|
||||
public:
|
||||
// Returns the singleton instance of this object.
|
||||
static MainMessageLoop* Get();
|
||||
|
||||
// Run the message loop. The thread that this method is called on will be
|
||||
// considered the main thread. This blocks until Quit() is called.
|
||||
virtual int Run() = 0;
|
||||
|
||||
// Quit the message loop.
|
||||
virtual void Quit() = 0;
|
||||
|
||||
// Post a task for execution on the main message loop.
|
||||
virtual void PostTask(CefRefPtr<CefTask> task) = 0;
|
||||
|
||||
// Returns true if this message loop runs tasks on the current thread.
|
||||
virtual bool RunsTasksOnCurrentThread() const = 0;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// Set the current modeless dialog on Windows for proper delivery of dialog
|
||||
// messages when using multi-threaded message loop mode. This method must be
|
||||
// called from the main thread. See http://support.microsoft.com/kb/71450 for
|
||||
// background.
|
||||
virtual void SetCurrentModelessDialog(HWND hWndDialog) = 0;
|
||||
#endif
|
||||
|
||||
// Post a closure for execution on the main message loop.
|
||||
void PostClosure(const base::Closure& closure);
|
||||
|
||||
// Used in combination with DeleteOnMainThread to delete |object| on the
|
||||
// correct thread.
|
||||
template<class T>
|
||||
void DeleteSoon(const T* object) {
|
||||
// Execute DeleteHelper on the main thread.
|
||||
PostClosure(base::Bind(&MainMessageLoop::DeleteHelper, object));
|
||||
}
|
||||
|
||||
protected:
|
||||
// Only allow deletion via scoped_ptr.
|
||||
friend struct base::DefaultDeleter<MainMessageLoop>;
|
||||
|
||||
MainMessageLoop();
|
||||
virtual ~MainMessageLoop();
|
||||
|
||||
private:
|
||||
// Helper for deleting |object|.
|
||||
template<class T>
|
||||
static void DeleteHelper(const T* object) {
|
||||
delete object;
|
||||
}
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MainMessageLoop);
|
||||
};
|
||||
|
||||
#define CURRENTLY_ON_MAIN_THREAD() \
|
||||
client::MainMessageLoop::Get()->RunsTasksOnCurrentThread()
|
||||
|
||||
#define REQUIRE_MAIN_THREAD() DCHECK(CURRENTLY_ON_MAIN_THREAD())
|
||||
|
||||
#define MAIN_POST_TASK(task) \
|
||||
client::MainMessageLoop::Get()->PostTask(task)
|
||||
|
||||
#define MAIN_POST_CLOSURE(closure) \
|
||||
client::MainMessageLoop::Get()->PostClosure(closure)
|
||||
|
||||
// Use this struct in conjuction with RefCountedThreadSafe to ensure that an
|
||||
// object is deleted on the main thread. For example:
|
||||
//
|
||||
// class Foo : public base::RefCountedThreadSafe<Foo, DeleteOnMainThread> {
|
||||
// public:
|
||||
// Foo();
|
||||
// void DoSomething();
|
||||
//
|
||||
// private:
|
||||
// // Allow deletion via scoped_refptr only.
|
||||
// friend struct DeleteOnMainThread;
|
||||
// friend class base::RefCountedThreadSafe<Foo, DeleteOnMainThread>;
|
||||
//
|
||||
// virtual ~Foo() {}
|
||||
// };
|
||||
//
|
||||
// base::scoped_refptr<Foo> foo = new Foo();
|
||||
// foo->DoSomething();
|
||||
// foo = NULL; // Deletion of |foo| will occur on the main thread.
|
||||
//
|
||||
struct DeleteOnMainThread {
|
||||
template<typename T>
|
||||
static void Destruct(const T* x) {
|
||||
if (CURRENTLY_ON_MAIN_THREAD()) {
|
||||
delete x;
|
||||
} else {
|
||||
client::MainMessageLoop::Get()->DeleteSoon(x);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_MAIN_MESSAGE_LOOP_H_
|
166
tests/cefclient/main_message_loop_multithreaded_win.cc
Normal file
166
tests/cefclient/main_message_loop_multithreaded_win.cc
Normal file
@ -0,0 +1,166 @@
|
||||
// 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 "cefclient/main_message_loop_multithreaded_win.h"
|
||||
|
||||
#include "include/base/cef_bind.h"
|
||||
#include "include/cef_app.h"
|
||||
#include "cefclient/resource.h"
|
||||
#include "cefclient/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());
|
||||
|
||||
#ifndef NDEBUG
|
||||
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_DESTROY:
|
||||
// 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
|
60
tests/cefclient/main_message_loop_multithreaded_win.h
Normal file
60
tests/cefclient/main_message_loop_multithreaded_win.h
Normal file
@ -0,0 +1,60 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CEF_TESTS_CEFCLIENT_MAIN_MESSAGE_LOOP_MULTITHREADED_WIN_H_
|
||||
#define CEF_TESTS_CEFCLIENT_MAIN_MESSAGE_LOOP_MULTITHREADED_WIN_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <queue>
|
||||
|
||||
#include "include/base/cef_lock.h"
|
||||
#include "include/base/cef_platform_thread.h"
|
||||
#include "cefclient/main_message_loop.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
// Represents the main message loop in the browser process when using multi-
|
||||
// threaded message loop mode on Windows. In this mode there is no Chromium
|
||||
// message loop running on the main application thread. Instead, this
|
||||
// implementation utilizes a hidden message window for running tasks.
|
||||
class MainMessageLoopMultithreadedWin : public MainMessageLoop {
|
||||
public:
|
||||
MainMessageLoopMultithreadedWin();
|
||||
~MainMessageLoopMultithreadedWin();
|
||||
|
||||
// MainMessageLoop methods.
|
||||
int Run() OVERRIDE;
|
||||
void Quit() OVERRIDE;
|
||||
void PostTask(CefRefPtr<CefTask> task) OVERRIDE;
|
||||
bool RunsTasksOnCurrentThread() const OVERRIDE;
|
||||
void SetCurrentModelessDialog(HWND hWndDialog) OVERRIDE;
|
||||
|
||||
private:
|
||||
// Create the message window.
|
||||
static HWND CreateMessageWindow(HINSTANCE hInstance);
|
||||
|
||||
// Window procedure for the message window.
|
||||
static LRESULT CALLBACK MessageWndProc(HWND hWnd, UINT message, WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
void PostTaskInternal(CefRefPtr<CefTask> task);
|
||||
|
||||
base::PlatformThreadId thread_id_;
|
||||
UINT task_message_id_;
|
||||
|
||||
// Only accessed on the main thread.
|
||||
HWND dialog_hwnd_;
|
||||
|
||||
base::Lock lock_;
|
||||
|
||||
// Must be protected by |lock_|.
|
||||
HWND message_hwnd_;
|
||||
std::queue<CefRefPtr<CefTask> > queued_tasks_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MainMessageLoopMultithreadedWin);
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_MAIN_MESSAGE_LOOP_MULTITHREADED_WIN_H_
|
38
tests/cefclient/main_message_loop_std.cc
Normal file
38
tests/cefclient/main_message_loop_std.cc
Normal file
@ -0,0 +1,38 @@
|
||||
// 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 "cefclient/main_message_loop_std.h"
|
||||
|
||||
#include "include/cef_app.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
MainMessageLoopStd::MainMessageLoopStd() {
|
||||
}
|
||||
|
||||
int MainMessageLoopStd::Run() {
|
||||
CefRunMessageLoop();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MainMessageLoopStd::Quit() {
|
||||
CefQuitMessageLoop();
|
||||
}
|
||||
|
||||
void MainMessageLoopStd::PostTask(CefRefPtr<CefTask> task) {
|
||||
CefPostTask(TID_UI, task);
|
||||
}
|
||||
|
||||
bool MainMessageLoopStd::RunsTasksOnCurrentThread() const {
|
||||
return CefCurrentlyOn(TID_UI);
|
||||
}
|
||||
|
||||
#if defined(OS_WIN)
|
||||
void MainMessageLoopStd::SetCurrentModelessDialog(HWND hWndDialog) {
|
||||
// Nothing to do here. The Chromium message loop implementation will
|
||||
// internally route dialog messages.
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace client
|
34
tests/cefclient/main_message_loop_std.h
Normal file
34
tests/cefclient/main_message_loop_std.h
Normal file
@ -0,0 +1,34 @@
|
||||
// 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.
|
||||
|
||||
#ifndef CEF_TESTS_CEFCLIENT_MAIN_MESSAGE_LOOP_STD_H_
|
||||
#define CEF_TESTS_CEFCLIENT_MAIN_MESSAGE_LOOP_STD_H_
|
||||
|
||||
#include "cefclient/main_message_loop.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
// Represents the main message loop in the browser process. This implementation
|
||||
// is a light-weight wrapper around the Chromium UI thread.
|
||||
class MainMessageLoopStd : public MainMessageLoop {
|
||||
public:
|
||||
MainMessageLoopStd();
|
||||
|
||||
// MainMessageLoop methods.
|
||||
int Run() OVERRIDE;
|
||||
void Quit() OVERRIDE;
|
||||
void PostTask(CefRefPtr<CefTask> task) OVERRIDE;
|
||||
bool RunsTasksOnCurrentThread() const OVERRIDE;
|
||||
|
||||
#if defined(OS_WIN)
|
||||
void SetCurrentModelessDialog(HWND hWndDialog) OVERRIDE;
|
||||
#endif
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MainMessageLoopStd);
|
||||
};
|
||||
|
||||
} // namespace client
|
||||
|
||||
#endif // CEF_TESTS_CEFCLIENT_MAIN_MESSAGE_LOOP_STD_H_
|
29
tests/cefclient/util_win.cc
Normal file
29
tests/cefclient/util_win.cc
Normal file
@ -0,0 +1,29 @@
|
||||
// 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 "cefclient/util_win.h"
|
||||
|
||||
#include "include/base/cef_logging.h"
|
||||
#include "include/internal/cef_types.h"
|
||||
|
||||
namespace client {
|
||||
|
||||
void SetUserDataPtr(HWND hWnd, void* ptr) {
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
LONG_PTR result = ::SetWindowLongPtr(
|
||||
hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(ptr));
|
||||
CHECK(result != 0 || GetLastError() == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
WNDPROC SetWndProcPtr(HWND hWnd, WNDPROC wndProc) {
|
||||
WNDPROC old =
|
||||
reinterpret_cast<WNDPROC>(::GetWindowLongPtr(hWnd, GWLP_WNDPROC));
|
||||
CHECK(old != NULL);
|
||||
LONG_PTR result = ::SetWindowLongPtr(
|
||||
hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(wndProc));
|
||||
CHECK(result != 0 || GetLastError() == ERROR_SUCCESS);
|
||||
return old;
|
||||
}
|
||||
|
||||
} // namespace client
|
22
tests/cefclient/util_win.h
Normal file
22
tests/cefclient/util_win.h
Normal file
@ -0,0 +1,22 @@
|
||||
// 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 <windows.h>
|
||||
#include <string>
|
||||
|
||||
namespace client {
|
||||
|
||||
// Set the window's user data pointer.
|
||||
void SetUserDataPtr(HWND hWnd, void* ptr);
|
||||
|
||||
// Return the window's user data pointer.
|
||||
template <typename T>
|
||||
T GetUserDataPtr(HWND hWnd) {
|
||||
return reinterpret_cast<T>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
|
||||
}
|
||||
|
||||
// Set the window's window procedure pointer and return the old value.
|
||||
WNDPROC SetWndProcPtr(HWND hWnd, WNDPROC wndProc);
|
||||
|
||||
} // namespace client
|
Loading…
x
Reference in New Issue
Block a user