libcef:
- 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:
parent
9d3cd36b4b
commit
15f6c270fa
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue