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:
Marshall Greenblatt 2015-01-22 17:55:55 +00:00
parent 4bf08b70d6
commit 249ad7f6e4
12 changed files with 586 additions and 86 deletions

View File

@ -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': [

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View 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

View 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_

View 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

View 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_

View 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

View 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_

View 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

View 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