- Allow execution of CEF using the current application's message loop.
tests/cefclient:
- Support running of the cefclient application using a single message loop via the TEST_SINGLE_THREADED_MESSAGE_LOOP define.

Issue #1, Suggested implementation by: vridosh

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@13 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2009-01-29 18:53:17 +00:00
parent 9d3cd36b4b
commit 15f6c270fa
4 changed files with 150 additions and 63 deletions

View File

@ -39,14 +39,21 @@
// This function should only be called once when the application is started.
// Create the thread to host the UI message loop. A return value of true
// indicates that it succeeded and false indicates that it failed.
bool CefInitialize();
// indicates that it succeeded and false indicates that it failed. Set
// |multi_threaded_message_loop| to true to have the message loop run in
// a separate thread. If |multi_threaded_message_loop| is false than
// the CefDoMessageLoopWork() function must be called from your message loop.
bool CefInitialize(bool multi_threaded_message_loop);
// This function should only be called once before the application exits.
// Shut down the thread hosting the UI message loop and destroy any created
// windows.
void CefShutdown();
// Perform message loop processing. Has no affect if the browser UI loop is
// running in a separate thread.
void CefDoMessageLoopWork();
// Interface defining the the reference count implementation methods. All
// framework classes must implement the CefBase class.

View File

@ -10,7 +10,6 @@
#include "browser_request_context.h"
#include "../include/cef_nplugin.h"
#include "base/at_exit.h"
#include "base/command_line.h"
#include "base/icu_util.h"
#include "base/path_service.h"
@ -33,7 +32,30 @@ static const char* kStatsFilePrefix = "libcef_";
static int kStatsFileThreads = 20;
static int kStatsFileCounters = 200;
bool CefInitialize()
// Class used to process events on the current message loop.
class CefMessageLoopForUI : public MessageLoopForUI
{
typedef MessageLoopForUI inherited;
public:
CefMessageLoopForUI()
{
}
virtual bool DoIdleWork() {
bool valueToRet = inherited::DoIdleWork();
pump_->Quit();
return valueToRet;
}
void DoMessageLoopIteration() {
Run(NULL);
}
};
bool CefInitialize(bool multi_threaded_message_loop)
{
// Return true if the context is already initialized
if(_Context.get())
@ -42,7 +64,7 @@ bool CefInitialize()
// Create the new global context object
_Context = new CefContext();
// Initialize the glboal context
return _Context->Initialize();
return _Context->Initialize(multi_threaded_message_loop);
}
void CefShutdown()
@ -57,6 +79,13 @@ void CefShutdown()
_Context = NULL;
}
void CefDoMessageLoopWork()
{
if(!_Context->RunningOnUIThread())
return;
((CefMessageLoopForUI*)CefMessageLoopForUI::current())->DoMessageLoopIteration();
}
bool CefRegisterPlugin(const struct CefPluginInfo& plugin_info)
{
if(!_Context.get())
@ -124,10 +153,8 @@ StringPiece NetResourceProvider(int key) {
return GetRawDataResource(::GetModuleHandle(NULL), key);
}
DWORD WINAPI ThreadHandlerUI(LPVOID lpParam)
bool CefContext::DoInitialize()
{
CefContext *pContext = static_cast<CefContext*>(lpParam);
HRESULT res;
// Initialize common controls
@ -142,16 +169,9 @@ DWORD WINAPI ThreadHandlerUI(LPVOID lpParam)
res = OleInitialize(NULL);
DCHECK(SUCCEEDED(res));
// Instantiate the AtExitManager to avoid asserts and possible memory leaks.
base::AtExitManager at_exit_manager;
// Initialize the global CommandLine object.
CommandLine::Init(0, NULL);
// Instantiate the message loop for this thread.
MessageLoopForUI main_message_loop;
pContext->SetMessageLoopForUI(&main_message_loop);
// Initializing with a default context, which means no on-disk cookie DB,
// and no support for directory listings.
// TODO(cef): Either disable caching or send the cache files to a reasonable
@ -166,7 +186,7 @@ DWORD WINAPI ThreadHandlerUI(LPVOID lpParam)
if(!ret) {
MessageBox(NULL, L"Failed to load the required icudt38 library",
L"CEF Initialization Error", MB_ICONERROR | MB_OK);
return 1;
return false;
}
// Config the network module so it has access to a limited set of resources.
@ -174,19 +194,17 @@ DWORD WINAPI ThreadHandlerUI(LPVOID lpParam)
// Load and initialize the stats table. Attempt to construct a somewhat
// unique name to isolate separate instances from each other.
StatsTable *table = new StatsTable(
statstable_ = new StatsTable(
kStatsFilePrefix + Uint64ToString(base::RandUint64()),
kStatsFileThreads,
kStatsFileCounters);
StatsTable::set_current(table);
StatsTable::set_current(statstable_);
// Notify the context that initialization is complete so that the
// Initialize() function can return.
pContext->NotifyEvent();
// Execute the message loop that will run until a quit task is received.
MessageLoop::current()->Run();
return true;
}
void CefContext::DoUninitialize()
{
// Flush any remaining messages. This ensures that any accumulated
// Task objects get destroyed before we exit, which avoids noise in
// purify leak-test results.
@ -196,13 +214,35 @@ DWORD WINAPI ThreadHandlerUI(LPVOID lpParam)
// Tear down shared StatsTable; prevents unit_tests from leaking it.
StatsTable::set_current(NULL);
delete table;
delete statstable_;
statstable_ = NULL;
// Uninitialize COM stuff
OleUninitialize();
// Uninitialize common controls
CoUninitialize();
}
DWORD WINAPI ThreadHandlerUI(LPVOID lpParam)
{
CefContext *pContext = static_cast<CefContext*>(lpParam);
if (!pContext->DoInitialize())
return 1;
// Instantiate the message loop for this thread.
MessageLoopForUI main_message_loop;
pContext->SetMessageLoopForUI(&main_message_loop);
// Notify the context that initialization is complete so that the
// Initialize() function can return.
pContext->NotifyEvent();
// Execute the message loop that will run until a quit task is received.
MessageLoop::current()->Run();
pContext->DoUninitialize();
return 0;
}
@ -222,9 +262,11 @@ CefContext::~CefContext()
{
// Just in case CefShutdown() isn't called
Shutdown();
DoUninitialize();
}
bool CefContext::Initialize()
bool CefContext::Initialize(bool multi_threaded_message_loop)
{
bool initialized = false, intransition = false;
@ -294,15 +336,24 @@ bool CefContext::Initialize()
webprefs_->java_enabled = true;
webprefs_->allow_scripts_to_close_windows = false;
// Event that will be used to signal thread setup completion. Start
// in non-signaled mode so that the event will block.
heventui_ = CreateEvent(NULL, TRUE, FALSE, NULL);
DCHECK(heventui_ != NULL);
// Thread that hosts the UI loop
hthreadui_ = CreateThread(
NULL, 0, ThreadHandlerUI, this, 0, &idthreadui_);
DCHECK(hthreadui_ != NULL);
if (multi_threaded_message_loop) {
// Event that will be used to signal thread setup completion. Start
// in non-signaled mode so that the event will block.
heventui_ = CreateEvent(NULL, TRUE, FALSE, NULL);
DCHECK(heventui_ != NULL);
// Thread that hosts the UI loop
hthreadui_ = CreateThread(
NULL, 0, ThreadHandlerUI, this, 0, &idthreadui_);
DCHECK(hthreadui_ != NULL);
} else {
if (!DoInitialize()) {
// TODO: Process initialization errors
}
// Create our own message loop there
SetMessageLoopForUI(new CefMessageLoopForUI());
idthreadui_ = GetCurrentThreadId();
}
initialized = true;
}
@ -311,8 +362,10 @@ bool CefContext::Initialize()
Unlock();
if(initialized) {
// Wait for initial UI thread setup to complete
WaitForSingleObject(heventui_, INFINITE);
if (multi_threaded_message_loop) {
// Wait for initial UI thread setup to complete
WaitForSingleObject(heventui_, INFINITE);
}
Lock();

View File

@ -7,6 +7,7 @@
#define _CONTEXT_H
#include "../include/cef.h"
#include "base/at_exit.h"
#include "base/message_loop.h"
#include "base/gfx/native_widget_types.h"
#include "webkit/glue/webpreferences.h"
@ -21,7 +22,7 @@ public:
CefContext();
~CefContext();
bool Initialize();
bool Initialize(bool multi_threaded_message_loop);
void Shutdown();
MessageLoopForUI* GetMessageLoopForUI() { return messageloopui_; }
@ -45,10 +46,17 @@ public:
void UIT_RegisterPlugin(struct CefPluginInfo* plugin_info);
void UIT_UnregisterPlugin(struct CefPluginInfo* plugin_info);
bool DoWork();
bool DoDelayedWork();
bool DoIdleWork();
private:
void SetMessageLoopForUI(MessageLoopForUI* loop);
void NotifyEvent();
bool DoInitialize();
void DoUninitialize();
protected:
HMODULE hinstance_;
DWORD idthreadui_;
@ -58,6 +66,10 @@ protected:
bool in_transition_;
BrowserList browserlist_;
WebPreferences* webprefs_;
StatsTable* statstable_;
// Instantiate the AtExitManager to avoid asserts and possible memory leaks.
base::AtExitManager at_exit_manager_;
friend DWORD WINAPI ThreadHandlerUI(LPVOID lpParam);
};

View File

@ -15,6 +15,10 @@
#define BUTTON_WIDTH 72
#define URLBAR_HEIGHT 24
// Define this value to run CEF with messages processed using the current
// application's message loop.
//#define TEST_SINGLE_THREADED_MESSAGE_LOOP
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
@ -31,11 +35,17 @@ int APIENTRY _tWinMain(HINSTANCE hInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// Initialize the CEF
CefInitialize();
#ifdef TEST_SINGLE_THREADED_MESSAGE_LOOP
// Initialize the CEF with messages processed using the current application's
// message loop.
CefInitialize(false);
#else
// Initialize the CEF with messages processed using a separate UI thread.
CefInitialize(true);
#endif
// Structure providing information about the client plugin.
CefPluginInfo plugin_info;
@ -56,31 +66,36 @@ int APIENTRY _tWinMain(HINSTANCE hInstance,
// Register the internal client plugin
CefRegisterPlugin(plugin_info);
MSG msg;
HACCEL hAccelTable;
MSG msg;
HACCEL hAccelTable;
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_CEFCLIENT, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_CEFCLIENT, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
// Perform application initialization
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CEFCLIENT));
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CEFCLIENT));
// Main message loop
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Main message loop
while (GetMessage(&msg, NULL, 0, 0))
{
#ifdef TEST_SINGLE_THREADED_MESSAGE_LOOP
// Allow the CEF to do its message loop processing.
CefDoMessageLoopWork();
#endif
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Shut down the CEF
CefShutdown();