mirror of
https://bitbucket.org/chromiumembedded/cef
synced 2025-06-05 21:39:12 +02: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:
@@ -165,6 +165,10 @@
|
|||||||
'tests/cefclient/dialog_test.cc',
|
'tests/cefclient/dialog_test.cc',
|
||||||
'tests/cefclient/dialog_test.h',
|
'tests/cefclient/dialog_test.h',
|
||||||
'tests/cefclient/dragdrop_events.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.h',
|
||||||
'tests/cefclient/osrenderer.cc',
|
'tests/cefclient/osrenderer.cc',
|
||||||
'tests/cefclient/performance_test.cc',
|
'tests/cefclient/performance_test.cc',
|
||||||
@@ -189,10 +193,14 @@
|
|||||||
'tests/cefclient/cefclient_osr_widget_win.cc',
|
'tests/cefclient/cefclient_osr_widget_win.cc',
|
||||||
'tests/cefclient/cefclient_win.cc',
|
'tests/cefclient/cefclient_win.cc',
|
||||||
'tests/cefclient/client_handler_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/resource.h',
|
||||||
'tests/cefclient/res/cefclient.ico',
|
'tests/cefclient/res/cefclient.ico',
|
||||||
'tests/cefclient/res/small.ico',
|
'tests/cefclient/res/small.ico',
|
||||||
'tests/cefclient/resource_util_win.cc',
|
'tests/cefclient/resource_util_win.cc',
|
||||||
|
'tests/cefclient/util_win.h',
|
||||||
|
'tests/cefclient/util_win.cc',
|
||||||
'tests/cefclient/window_test_win.cc',
|
'tests/cefclient/window_test_win.cc',
|
||||||
],
|
],
|
||||||
'cefclient_sources_mac': [
|
'cefclient_sources_mac': [
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
#include "cefclient/cefclient_osr_widget_gtk.h"
|
#include "cefclient/cefclient_osr_widget_gtk.h"
|
||||||
#include "cefclient/client_handler.h"
|
#include "cefclient/client_handler.h"
|
||||||
#include "cefclient/client_switches.h"
|
#include "cefclient/client_switches.h"
|
||||||
|
#include "cefclient/main_message_loop_std.h"
|
||||||
#include "cefclient/scheme_test.h"
|
#include "cefclient/scheme_test.h"
|
||||||
#include "cefclient/string_util.h"
|
#include "cefclient/string_util.h"
|
||||||
|
|
||||||
@@ -453,6 +454,10 @@ int main(int argc, char* argv[]) {
|
|||||||
XSetErrorHandler(XErrorHandlerImpl);
|
XSetErrorHandler(XErrorHandlerImpl);
|
||||||
XSetIOErrorHandler(XIOErrorHandlerImpl);
|
XSetIOErrorHandler(XIOErrorHandlerImpl);
|
||||||
|
|
||||||
|
// Create the main message loop object.
|
||||||
|
scoped_ptr<client::MainMessageLoop> message_loop(
|
||||||
|
new client::MainMessageLoopStd);
|
||||||
|
|
||||||
// Initialize CEF.
|
// Initialize CEF.
|
||||||
CefInitialize(main_args, settings, app.get(), NULL);
|
CefInitialize(main_args, settings, app.get(), NULL);
|
||||||
|
|
||||||
@@ -582,11 +587,16 @@ int main(int argc, char* argv[]) {
|
|||||||
signal(SIGINT, TerminationSignalHandler);
|
signal(SIGINT, TerminationSignalHandler);
|
||||||
signal(SIGTERM, 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();
|
CefShutdown();
|
||||||
|
|
||||||
return 0;
|
// Release the |message_loop| object.
|
||||||
|
message_loop.reset();
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Global functions
|
// Global functions
|
||||||
@@ -596,5 +606,5 @@ std::string AppGetWorkingDirectory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AppQuitMessageLoop() {
|
void AppQuitMessageLoop() {
|
||||||
CefQuitMessageLoop();
|
client::MainMessageLoop::Get()->Quit();
|
||||||
}
|
}
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include "cefclient/cefclient_osr_widget_mac.h"
|
#include "cefclient/cefclient_osr_widget_mac.h"
|
||||||
#include "cefclient/client_handler.h"
|
#include "cefclient/client_handler.h"
|
||||||
#include "cefclient/client_switches.h"
|
#include "cefclient/client_switches.h"
|
||||||
|
#include "cefclient/main_message_loop_std.h"
|
||||||
#include "cefclient/resource_util.h"
|
#include "cefclient/resource_util.h"
|
||||||
#include "cefclient/scheme_test.h"
|
#include "cefclient/scheme_test.h"
|
||||||
#include "cefclient/string_util.h"
|
#include "cefclient/string_util.h"
|
||||||
@@ -622,6 +623,10 @@ int main(int argc, char* argv[]) {
|
|||||||
// Populate the settings based on command line arguments.
|
// Populate the settings based on command line arguments.
|
||||||
AppGetSettings(settings);
|
AppGetSettings(settings);
|
||||||
|
|
||||||
|
// Create the main message loop object.
|
||||||
|
scoped_ptr<client::MainMessageLoop> message_loop(
|
||||||
|
new client::MainMessageLoopStd);
|
||||||
|
|
||||||
// Initialize CEF.
|
// Initialize CEF.
|
||||||
CefInitialize(main_args, settings, app.get(), NULL);
|
CefInitialize(main_args, settings, app.get(), NULL);
|
||||||
|
|
||||||
@@ -634,8 +639,8 @@ int main(int argc, char* argv[]) {
|
|||||||
withObject:nil
|
withObject:nil
|
||||||
waitUntilDone:NO];
|
waitUntilDone:NO];
|
||||||
|
|
||||||
// Run the application message loop.
|
// Run the message loop. This will block until Quit() is called.
|
||||||
CefRunMessageLoop();
|
int result = message_loop->Run();
|
||||||
|
|
||||||
// Shut down CEF.
|
// Shut down CEF.
|
||||||
CefShutdown();
|
CefShutdown();
|
||||||
@@ -649,7 +654,10 @@ int main(int argc, char* argv[]) {
|
|||||||
// Release the AutoRelease pool.
|
// Release the AutoRelease pool.
|
||||||
[autopool release];
|
[autopool release];
|
||||||
|
|
||||||
return 0;
|
// Release the |message_loop| object.
|
||||||
|
message_loop.reset();
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -660,5 +668,5 @@ std::string AppGetWorkingDirectory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AppQuitMessageLoop() {
|
void AppQuitMessageLoop() {
|
||||||
CefQuitMessageLoop();
|
client::MainMessageLoop::Get()->Quit();
|
||||||
}
|
}
|
||||||
|
@@ -20,9 +20,12 @@
|
|||||||
#include "cefclient/cefclient_osr_widget_win.h"
|
#include "cefclient/cefclient_osr_widget_win.h"
|
||||||
#include "cefclient/client_handler.h"
|
#include "cefclient/client_handler.h"
|
||||||
#include "cefclient/client_switches.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/resource.h"
|
||||||
#include "cefclient/scheme_test.h"
|
#include "cefclient/scheme_test.h"
|
||||||
#include "cefclient/string_util.h"
|
#include "cefclient/string_util.h"
|
||||||
|
#include "cefclient/util_win.h"
|
||||||
|
|
||||||
|
|
||||||
// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
|
// 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);
|
ATOM MyRegisterClass(HINSTANCE hInstance);
|
||||||
BOOL InitInstance(HINSTANCE, int);
|
BOOL InitInstance(HINSTANCE, int);
|
||||||
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
||||||
|
LRESULT CALLBACK FindProc(HWND, UINT, WPARAM, LPARAM);
|
||||||
INT_PTR CALLBACK About(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.
|
// The global ClientHandler reference.
|
||||||
extern CefRefPtr<ClientHandler> g_handler;
|
extern CefRefPtr<ClientHandler> g_handler;
|
||||||
|
|
||||||
@@ -117,14 +115,19 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
|
|||||||
// Populate the settings based on command line arguments.
|
// Populate the settings based on command line arguments.
|
||||||
AppGetSettings(settings);
|
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.
|
// Initialize CEF.
|
||||||
CefInitialize(main_args, settings, app.get(), sandbox_info);
|
CefInitialize(main_args, settings, app.get(), sandbox_info);
|
||||||
|
|
||||||
// Register the scheme handler.
|
// Register the scheme handler.
|
||||||
scheme_test::InitTest();
|
scheme_test::InitTest();
|
||||||
|
|
||||||
HACCEL hAccelTable;
|
|
||||||
|
|
||||||
// Initialize global strings
|
// Initialize global strings
|
||||||
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
|
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
|
||||||
LoadString(hInstance, IDC_CEFCLIENT, szWindowClass, MAX_LOADSTRING);
|
LoadString(hInstance, IDC_CEFCLIENT, szWindowClass, MAX_LOADSTRING);
|
||||||
@@ -135,45 +138,18 @@ int APIENTRY wWinMain(HINSTANCE hInstance,
|
|||||||
if (!InitInstance (hInstance, nCmdShow))
|
if (!InitInstance (hInstance, nCmdShow))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_CEFCLIENT));
|
|
||||||
|
|
||||||
// Register the find event message.
|
// Register the find event message.
|
||||||
uFindMsg = RegisterWindowMessage(FINDMSGSTRING);
|
uFindMsg = RegisterWindowMessage(FINDMSGSTRING);
|
||||||
|
|
||||||
int result = 0;
|
// Run the message loop. This will block until Quit() is called.
|
||||||
|
int result = message_loop->Run();
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shut down CEF.
|
// Shut down CEF.
|
||||||
CefShutdown();
|
CefShutdown();
|
||||||
|
|
||||||
|
// Release the |message_loop| object.
|
||||||
|
message_loop.reset();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,6 +494,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
|
|||||||
fr.Flags = FR_HIDEWHOLEWORD | FR_DOWN;
|
fr.Flags = FR_HIDEWHOLEWORD | FR_DOWN;
|
||||||
|
|
||||||
hFindDlg = FindText(&fr);
|
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 {
|
} else {
|
||||||
// Give focus to the existing find dialog.
|
// Give focus to the existing find dialog.
|
||||||
::SetFocus(hFindDlg);
|
::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.
|
// Message handler for about box.
|
||||||
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||||
UNREFERENCED_PARAMETER(lParam);
|
UNREFERENCED_PARAMETER(lParam);
|
||||||
@@ -725,35 +730,6 @@ INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) {
|
|||||||
return (INT_PTR)FALSE;
|
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
|
// Global functions
|
||||||
|
|
||||||
@@ -762,13 +738,5 @@ std::string AppGetWorkingDirectory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AppQuitMessageLoop() {
|
void AppQuitMessageLoop() {
|
||||||
CefRefPtr<CefCommandLine> command_line = AppGetCommandLine();
|
client::MainMessageLoop::Get()->Quit();
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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
|
Reference in New Issue
Block a user