- cefclient: Windows: Introduce RootWindow concept and associated window/client object hierarchy (issue #1500).

- cefclient: Remove locking from ClientHandlerShared that was only required for the Windows implementation (issue #1500).
- Add CefDeleteOnThread helper for deleting ref-counted types on a named CEF thread.

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@2001 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2015-01-27 00:03:25 +00:00
parent bcab7e0ebd
commit fd5ededb27
38 changed files with 3601 additions and 1513 deletions

View File

@ -156,8 +156,6 @@
'tests/cefclient/client_app_delegates.cc',
'tests/cefclient/client_handler.cc',
'tests/cefclient/client_handler.h',
'tests/cefclient/client_handler_shared.cc',
'tests/cefclient/client_handler_shared.h',
'tests/cefclient/client_renderer.cc',
'tests/cefclient/client_renderer.h',
'tests/cefclient/client_switches.cc',
@ -189,27 +187,47 @@
'<@(cefclient_bundle_resources_common)',
],
'cefclient_sources_win': [
'tests/cefclient/browser_window_osr_win.cc',
'tests/cefclient/browser_window_osr_win.h',
'tests/cefclient/browser_window_std_win.cc',
'tests/cefclient/browser_window_std_win.h',
'tests/cefclient/browser_window_win.cc',
'tests/cefclient/browser_window_win.h',
'tests/cefclient/cefclient.exe.manifest',
'tests/cefclient/cefclient.rc',
'tests/cefclient/cefclient_win.cc',
'tests/cefclient/client_handler_shared_win.cc',
'tests/cefclient/client_handler_osr.cc',
'tests/cefclient/client_handler_osr.h',
'tests/cefclient/client_handler_single.cc',
'tests/cefclient/client_handler_single.h',
'tests/cefclient/client_handler_std.cc',
'tests/cefclient/client_handler_std.h',
'tests/cefclient/main_context_impl_win.cc',
'tests/cefclient/main_message_loop_multithreaded_win.h',
'tests/cefclient/main_message_loop_multithreaded_win.cc',
'tests/cefclient/osr_dragdrop_win.h',
'tests/cefclient/main_message_loop_multithreaded_win.h',
'tests/cefclient/osr_dragdrop_win.cc',
'tests/cefclient/osr_widget_win.h',
'tests/cefclient/osr_widget_win.cc',
'tests/cefclient/osr_dragdrop_win.h',
'tests/cefclient/osr_window_win.cc',
'tests/cefclient/osr_window_win.h',
'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/root_window.h',
'tests/cefclient/root_window_manager.cc',
'tests/cefclient/root_window_manager.h',
'tests/cefclient/root_window_win.cc',
'tests/cefclient/root_window_win.h',
'tests/cefclient/temp_window_win.cc',
'tests/cefclient/temp_window_win.h',
'tests/cefclient/util_win.cc',
'tests/cefclient/util_win.h',
'tests/cefclient/window_test_win.cc',
],
'cefclient_sources_mac': [
'tests/cefclient/cefclient_mac.mm',
'tests/cefclient/client_handler_shared.cc',
'tests/cefclient/client_handler_shared.h',
'tests/cefclient/client_handler_shared_mac.mm',
'tests/cefclient/main_context_impl_posix.cc',
'tests/cefclient/osr_widget_mac.h',
@ -261,6 +279,8 @@
],
'cefclient_sources_linux': [
'tests/cefclient/cefclient_gtk.cc',
'tests/cefclient/client_handler_shared.cc',
'tests/cefclient/client_handler_shared.h',
'tests/cefclient/client_handler_shared_gtk.cc',
'tests/cefclient/dialog_handler_gtk.cc',
'tests/cefclient/dialog_handler_gtk.h',

View File

@ -41,6 +41,7 @@
#include <string>
#include <vector>
#include "include/base/cef_bind.h"
#include "include/base/cef_logging.h"
#include "include/base/cef_macros.h"
#include "include/cef_task.h"
@ -50,6 +51,46 @@
#define CEF_REQUIRE_FILE_THREAD() DCHECK(CefCurrentlyOn(TID_FILE));
#define CEF_REQUIRE_RENDERER_THREAD() DCHECK(CefCurrentlyOn(TID_RENDERER));
// Use this struct in conjuction with refcounted types to ensure that an
// object is deleted on the specified thread. For example:
//
// class Foo : public base::RefCountedThreadSafe<Foo, CefDeleteOnUIThread> {
// public:
// Foo();
// void DoSomething();
//
// private:
// // Allow deletion via scoped_refptr only.
// friend struct CefDeleteOnThread<TID_UI>;
// friend class base::RefCountedThreadSafe<Foo, CefDeleteOnUIThread>;
//
// virtual ~Foo() {}
// };
//
// base::scoped_refptr<Foo> foo = new Foo();
// foo->DoSomething();
// foo = NULL; // Deletion of |foo| will occur on the UI thread.
//
template<CefThreadId thread>
struct CefDeleteOnThread {
template<typename T>
static void Destruct(const T* x) {
if (CefCurrentlyOn(thread)) {
delete x;
} else {
CefPostTask(thread,
base::Bind(&CefDeleteOnThread<thread>::Destruct<T>, x));
}
}
};
struct CefDeleteOnUIThread : public CefDeleteOnThread<TID_UI> { };
struct CefDeleteOnIOThread : public CefDeleteOnThread<TID_IO> { };
struct CefDeleteOnFileThread : public CefDeleteOnThread<TID_FILE> { };
struct CefDeleteOnRendererThread : public CefDeleteOnThread<TID_RENDERER> { };
///
// Helper class to manage a scoped copy of |argv|.
///

View File

@ -0,0 +1,92 @@
// 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/browser_window_osr_win.h"
#include "cefclient/main_message_loop.h"
namespace client {
BrowserWindowOsrWin::BrowserWindowOsrWin(BrowserWindowWin::Delegate* delegate,
const std::string& startup_url,
bool transparent,
bool show_update_rect)
: BrowserWindowWin(delegate),
transparent_(transparent),
osr_hwnd_(NULL) {
osr_window_ = new OsrWindowWin(this, transparent, show_update_rect);
client_handler_ = new ClientHandlerOsr(this, osr_window_.get(), startup_url);
}
void BrowserWindowOsrWin::CreateBrowser(HWND parent_hwnd,
const RECT& rect,
const CefBrowserSettings& settings) {
REQUIRE_MAIN_THREAD();
// Create the new browser and native window on the UI thread.
osr_window_->CreateBrowser(parent_hwnd, rect, client_handler_, settings,
client_handler_->startup_url());
}
void BrowserWindowOsrWin::GetPopupConfig(HWND temp_hwnd,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) {
// Note: This method may be called on any thread.
windowInfo.SetAsWindowless(temp_hwnd, transparent_);
client = client_handler_;
}
void BrowserWindowOsrWin::ShowPopup(HWND parent_hwnd,
int x, int y, size_t width, size_t height) {
REQUIRE_MAIN_THREAD();
if (osr_window_)
osr_window_->ShowPopup(parent_hwnd, x, y, width, height);
}
void BrowserWindowOsrWin::Show() {
REQUIRE_MAIN_THREAD();
if (osr_window_)
osr_window_->Show();
}
void BrowserWindowOsrWin::Hide() {
REQUIRE_MAIN_THREAD();
if (osr_window_)
osr_window_->Hide();
}
void BrowserWindowOsrWin::SetBounds(int x, int y, size_t width, size_t height) {
REQUIRE_MAIN_THREAD();
if (osr_window_)
osr_window_->SetBounds(x, y, width, height);
}
void BrowserWindowOsrWin::SetFocus() {
REQUIRE_MAIN_THREAD();
if (osr_window_)
osr_window_->SetFocus();
}
HWND BrowserWindowOsrWin::GetHWND() const {
REQUIRE_MAIN_THREAD();
return osr_hwnd_;
}
void BrowserWindowOsrWin::OnBrowserClosed(CefRefPtr<CefBrowser> browser) {
REQUIRE_MAIN_THREAD();
// Release the OSR window reference. It will be deleted on the UI thread.
osr_window_ = NULL;
BrowserWindowWin::OnBrowserClosed(browser);
}
void BrowserWindowOsrWin::OnOsrNativeWindowCreated(HWND hwnd) {
REQUIRE_MAIN_THREAD();
DCHECK(!osr_hwnd_);
osr_hwnd_ = hwnd;
}
} // 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_BROWSER_WINDOW_OSR_WIN_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_OSR_WIN_H_
#include "cefclient/browser_window_win.h"
#include "cefclient/osr_window_win.h"
namespace client {
// Represents a native child window hosting a single off-screen browser
// instance. The methods of this class must be called on the main thread unless
// otherwise indicated.
class BrowserWindowOsrWin : public BrowserWindowWin,
OsrWindowWin::Delegate {
public:
// Constructor may be called on any thread.
// |delegate| must outlive this object.
BrowserWindowOsrWin(BrowserWindowWin::Delegate* delegate,
const std::string& startup_url,
bool transparent,
bool show_update_rect);
// BrowserWindowWin methods.
void CreateBrowser(HWND parent_hwnd,
const RECT& rect,
const CefBrowserSettings& settings) OVERRIDE;
void GetPopupConfig(HWND temp_hwnd,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) OVERRIDE;
void ShowPopup(HWND parent_hwnd,
int x, int y, size_t width, size_t height) OVERRIDE;
void Show() OVERRIDE;
void Hide() OVERRIDE;
void SetBounds(int x, int y, size_t width, size_t height) OVERRIDE;
void SetFocus() OVERRIDE;
HWND GetHWND() const OVERRIDE;
private:
// ClientHandler::Delegate methods.
void OnBrowserClosed(CefRefPtr<CefBrowser> browser) OVERRIDE;
// OsrWindowWin::Delegate methods.
void OnOsrNativeWindowCreated(HWND hwnd) OVERRIDE;
const bool transparent_;
// The below members are only accessed on the main thread.
scoped_refptr<OsrWindowWin> osr_window_;
HWND osr_hwnd_;
DISALLOW_COPY_AND_ASSIGN(BrowserWindowOsrWin);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_OSR_WIN_H_

View File

@ -0,0 +1,101 @@
// 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/browser_window_std_win.h"
#include "cefclient/client_handler_std.h"
#include "cefclient/main_message_loop.h"
namespace client {
BrowserWindowStdWin::BrowserWindowStdWin(Delegate* delegate,
const std::string& startup_url)
: BrowserWindowWin(delegate) {
client_handler_ = new ClientHandlerStd(this, startup_url);
}
void BrowserWindowStdWin::CreateBrowser(HWND parent_hwnd,
const RECT& rect,
const CefBrowserSettings& settings) {
REQUIRE_MAIN_THREAD();
CefWindowInfo window_info;
window_info.SetAsChild(parent_hwnd, rect);
CefBrowserHost::CreateBrowser(window_info, client_handler_,
client_handler_->startup_url(),
settings, NULL);
}
void BrowserWindowStdWin::GetPopupConfig(HWND temp_hwnd,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) {
// Note: This method may be called on any thread.
// The window will be properly sized after the browser is created.
windowInfo.SetAsChild(temp_hwnd, RECT());
client = client_handler_;
}
void BrowserWindowStdWin::ShowPopup(HWND parent_hwnd,
int x, int y, size_t width, size_t height) {
REQUIRE_MAIN_THREAD();
HWND hwnd = GetHWND();
if (hwnd) {
SetParent(hwnd, parent_hwnd);
SetWindowPos(hwnd, NULL, x, y, width, height, SWP_NOZORDER);
ShowWindow(hwnd, SW_SHOW);
}
}
void BrowserWindowStdWin::Show() {
REQUIRE_MAIN_THREAD();
HWND hwnd = GetHWND();
if (hwnd && !::IsWindowVisible(hwnd))
ShowWindow(hwnd, SW_SHOW);
}
void BrowserWindowStdWin::Hide() {
REQUIRE_MAIN_THREAD();
HWND hwnd = GetHWND();
if (hwnd) {
// When the frame window is minimized set the browser window size to 0x0 to
// reduce resource usage.
SetWindowPos(hwnd, NULL,
0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
}
}
void BrowserWindowStdWin::SetBounds(int x, int y, size_t width, size_t height) {
REQUIRE_MAIN_THREAD();
HWND hwnd = GetHWND();
if (hwnd) {
// Set the browser window bounds.
SetWindowPos(hwnd, NULL, x, y, width, height, SWP_NOZORDER);
}
}
void BrowserWindowStdWin::SetFocus() {
REQUIRE_MAIN_THREAD();
if (browser_) {
// Give focus to the browser window.
browser_->GetHost()->SetFocus(true);
}
}
HWND BrowserWindowStdWin::GetHWND() const {
REQUIRE_MAIN_THREAD();
if (browser_)
return browser_->GetHost()->GetWindowHandle();
return NULL;
}
} // namespace client

View File

@ -0,0 +1,44 @@
// 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_BROWSER_WINDOW_STD_WIN_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_STD_WIN_H_
#include "cefclient/browser_window_win.h"
namespace client {
// Represents a native child window hosting a single windowed browser instance.
// The methods of this class must be called on the main thread unless otherwise
// indicated.
class BrowserWindowStdWin : public BrowserWindowWin {
public:
// Constructor may be called on any thread.
// |delegate| must outlive this object.
BrowserWindowStdWin(Delegate* delegate,
const std::string& startup_url);
// BrowserWindowWin methods.
void CreateBrowser(HWND parent_hwnd,
const RECT& rect,
const CefBrowserSettings& settings) OVERRIDE;
void GetPopupConfig(HWND temp_hwnd,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) OVERRIDE;
void ShowPopup(HWND parent_hwnd,
int x, int y, size_t width, size_t height) OVERRIDE;
void Show() OVERRIDE;
void Hide() OVERRIDE;
void SetBounds(int x, int y, size_t width, size_t height) OVERRIDE;
void SetFocus() OVERRIDE;
HWND GetHWND() const OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(BrowserWindowStdWin);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_STD_WIN_H_

View File

@ -0,0 +1,71 @@
// 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/browser_window_win.h"
#include "include/base/cef_bind.h"
#include "cefclient/main_message_loop.h"
namespace client {
BrowserWindowWin::BrowserWindowWin(Delegate* delegate)
: delegate_(delegate),
is_closing_(false) {
DCHECK(delegate_);
}
CefRefPtr<CefBrowser> BrowserWindowWin::GetBrowser() const {
REQUIRE_MAIN_THREAD();
return browser_;
}
bool BrowserWindowWin::IsClosing() const {
REQUIRE_MAIN_THREAD();
return is_closing_;
}
void BrowserWindowWin::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
REQUIRE_MAIN_THREAD();
DCHECK(!browser_);
browser_ = browser;
delegate_->OnBrowserCreated(browser);
}
void BrowserWindowWin::OnBrowserClosing(CefRefPtr<CefBrowser> browser) {
REQUIRE_MAIN_THREAD();
DCHECK_EQ(browser->GetIdentifier(), browser_->GetIdentifier());
is_closing_ = true;
}
void BrowserWindowWin::OnBrowserClosed(CefRefPtr<CefBrowser> browser) {
REQUIRE_MAIN_THREAD();
DCHECK_EQ(browser->GetIdentifier(), browser_->GetIdentifier());
browser_ = NULL;
client_handler_->DetachDelegate();
client_handler_ = NULL;
// |this| may be deleted.
delegate_->OnBrowserWindowDestroyed();
}
void BrowserWindowWin::OnSetAddress(const std::string& url) {
REQUIRE_MAIN_THREAD();
delegate_->OnSetAddress(url);
}
void BrowserWindowWin::OnSetTitle(const std::string& title) {
REQUIRE_MAIN_THREAD();
delegate_->OnSetTitle(title);
}
void BrowserWindowWin::OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) {
REQUIRE_MAIN_THREAD();
delegate_->OnSetLoadingState(isLoading, canGoBack, canGoForward);
}
} // namespace client

View File

@ -0,0 +1,112 @@
// 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_BROWSER_WINDOW_WIN_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_WIN_H_
#include <windows.h>
#include "include/base/cef_scoped_ptr.h"
#include "include/cef_browser.h"
#include "cefclient/client_handler_single.h"
namespace client {
// Represents a native child window hosting a single browser instance. The
// methods of this class must be called on the main thread unless otherwise
// indicated.
class BrowserWindowWin : public ClientHandlerSingle::Delegate {
public:
// This interface is implemented by the owner of the BrowserWindowWin. The
// methods of this class will be called on the main thread.
class Delegate {
public:
// Called when the browser has been created.
virtual void OnBrowserCreated(CefRefPtr<CefBrowser> browser) = 0;
// Called when the BrowserWindowWin has been destroyed.
virtual void OnBrowserWindowDestroyed() = 0;
// Set the window URL address.
virtual void OnSetAddress(const std::string& url) = 0;
// Set the window title.
virtual void OnSetTitle(const std::string& title) = 0;
// Set the loading state.
virtual void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) = 0;
protected:
virtual ~Delegate() {}
};
// Create a new browser and native window.
virtual void CreateBrowser(HWND parent_hwnd,
const RECT& rect,
const CefBrowserSettings& settings) = 0;
// Retrieve the configuration that will be used when creating a popup window.
// The native window will be created later after the browser has been created.
// This method may be called on any thread.
virtual void GetPopupConfig(HWND temp_hwnd,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) = 0;
// Show the popup window with correct parent and bounds in parent coordinates.
virtual void ShowPopup(HWND parent_hwnd,
int x, int y, size_t width, size_t height) = 0;
// Show the window.
virtual void Show() = 0;
// Hide the window.
virtual void Hide() = 0;
// Set the window bounds in parent coordinates.
virtual void SetBounds(int x, int y, size_t width, size_t height) = 0;
// Set focus to the window.
virtual void SetFocus() = 0;
// Returns the window handle.
virtual HWND GetHWND() const = 0;
// Returns the browser owned by the window.
CefRefPtr<CefBrowser> GetBrowser() const;
// Returns true if the browser is closing.
bool IsClosing() const;
protected:
// Allow deletion via scoped_ptr only.
friend struct base::DefaultDeleter<BrowserWindowWin>;
// Constructor may be called on any thread.
// |root_window| and |delegate| must outlive this object.
explicit BrowserWindowWin(Delegate* delegate);
// ClientHandlerSingle::Delegate methods.
void OnBrowserCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
void OnBrowserClosing(CefRefPtr<CefBrowser> browser) OVERRIDE;
void OnBrowserClosed(CefRefPtr<CefBrowser> browser) OVERRIDE;
void OnSetAddress(const std::string& url) OVERRIDE;
void OnSetTitle(const std::string& title) OVERRIDE;
void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) OVERRIDE;
Delegate* delegate_;
CefRefPtr<CefBrowser> browser_;
CefRefPtr<ClientHandlerSingle> client_handler_;
bool is_closing_;
DISALLOW_COPY_AND_ASSIGN(BrowserWindowWin);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_WIN_H_

View File

@ -1,32 +1,17 @@
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// 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 <commdlg.h>
#include <shellapi.h>
#include <direct.h>
#include <shlobj.h>
#include <sstream>
#include <string>
#include "include/base/cef_bind.h"
#include "include/cef_app.h"
#include "include/cef_browser.h"
#include "include/cef_frame.h"
#include "include/base/cef_scoped_ptr.h"
#include "include/cef_sandbox_win.h"
#include "include/wrapper/cef_closure_task.h"
#include "cefclient/client_app.h"
#include "cefclient/client_handler_shared.h"
#include "cefclient/client_switches.h"
#include "cefclient/main_context_impl.h"
#include "cefclient/main_message_loop_multithreaded_win.h"
#include "cefclient/main_message_loop_std.h"
#include "cefclient/osr_widget_win.h"
#include "cefclient/resource.h"
#include "cefclient/root_window_manager.h"
#include "cefclient/test_runner.h"
#include "cefclient/util_win.h"
// When generating projects with CMake the CEF_USE_SANDBOX value will be defined
// automatically if using the required compiler version. Pass -DUSE_SANDBOX=OFF
@ -43,40 +28,6 @@
namespace client {
namespace {
#define MAX_LOADSTRING 100
#define MAX_URL_LENGTH 255
#define BUTTON_WIDTH 72
#define URLBAR_HEIGHT 24
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
TCHAR szOSRWindowClass[MAX_LOADSTRING]; // the OSR window class name
UINT uFindMsg; // Message identifier for find events.
HWND hFindDlg = NULL; // Handle for the find dialog.
// Forward declarations of functions included in this code module.
ATOM RegisterMainClass(HINSTANCE hInstance);
BOOL CreateMainWindow(HINSTANCE, int);
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK FindWndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK AboutWndProc(HWND, UINT, WPARAM, LPARAM);
// The global ClientHandlerShared reference.
CefRefPtr<ClientHandlerShared> g_handler;
// Used by off-screen rendering to find the associated CefBrowser.
class MainBrowserProvider : public OSRBrowserProvider {
virtual CefRefPtr<CefBrowser> GetBrowser() {
if (g_handler.get())
return g_handler->GetBrowser();
return NULL;
}
} g_main_browser_provider;
int RunMain(HINSTANCE hInstance, int nCmdShow) {
void* sandbox_info = NULL;
@ -96,7 +47,7 @@ int RunMain(HINSTANCE hInstance, int nCmdShow) {
return exit_code;
// Create the main context object.
scoped_ptr<MainContextImpl> context(new MainContextImpl(0, NULL));
scoped_ptr<MainContextImpl> context(new MainContextImpl(0, NULL, true));
CefSettings settings;
@ -120,20 +71,15 @@ int RunMain(HINSTANCE hInstance, int nCmdShow) {
// Register scheme handlers.
test_runner::RegisterSchemeHandlers();
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_CEFCLIENT, szWindowClass, MAX_LOADSTRING);
LoadString(hInstance, IDS_OSR_WIDGET_CLASS, szOSRWindowClass, MAX_LOADSTRING);
RegisterMainClass(hInstance);
// Create the first window.
context->GetRootWindowManager()->CreateRootWindow(
true, // Show controls.
settings.windowless_rendering_enabled ? true : false,
CefRect(), // Use default system size.
std::string()); // Use default URL.
// Perform application initialization
if (!CreateMainWindow(hInstance, nCmdShow))
return FALSE;
// Register the find event message.
uFindMsg = RegisterWindowMessage(FINDMSGSTRING);
// Run the message loop. This will block until Quit() is called.
// Run the message loop. This will block until Quit() is called by the
// RootWindowManager after all windows have been destroyed.
int result = message_loop->Run();
// Shut down CEF.
@ -146,462 +92,6 @@ int RunMain(HINSTANCE hInstance, int nCmdShow) {
return result;
}
// Register the main window class.
ATOM RegisterMainClass(HINSTANCE hInstance) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = MainWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CEFCLIENT));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CEFCLIENT);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
// Create and show the main window.
BOOL CreateMainWindow(HINSTANCE hInstance, int nCmdShow) {
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, CW_USEDEFAULT, 0,
CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
// Set focus to |browser| on the UI thread.
static void SetFocusToBrowser(CefRefPtr<CefBrowser> browser) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute on the UI thread.
CefPostTask(TID_UI, base::Bind(&SetFocusToBrowser, browser));
return;
}
if (!g_handler)
return;
if (g_handler->is_osr()) {
// Give focus to the OSR window.
CefRefPtr<OSRWindow> osr_window =
OSRWindow::From(g_handler->GetOSRHandler());
if (osr_window)
::SetFocus(osr_window->hwnd());
} else {
// Give focus to the browser.
browser->GetHost()->SetFocus(true);
}
}
// Window procedure for the main window.
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam) {
static HWND backWnd = NULL, forwardWnd = NULL, reloadWnd = NULL,
stopWnd = NULL, editWnd = NULL;
static WNDPROC editWndOldProc = NULL;
// Static members used for the find dialog.
static FINDREPLACE fr;
static WCHAR szFindWhat[80] = {0};
static WCHAR szLastFindWhat[80] = {0};
static bool findNext = false;
static bool lastMatchCase = false;
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
if (hWnd == editWnd) {
// Callback for the edit window
switch (message) {
case WM_CHAR:
if (wParam == VK_RETURN && g_handler.get()) {
// When the user hits the enter key load the URL
CefRefPtr<CefBrowser> browser = g_handler->GetBrowser();
wchar_t strPtr[MAX_URL_LENGTH+1] = {0};
*((LPWORD)strPtr) = MAX_URL_LENGTH;
LRESULT strLen = SendMessage(hWnd, EM_GETLINE, 0, (LPARAM)strPtr);
if (strLen > 0) {
strPtr[strLen] = 0;
browser->GetMainFrame()->LoadURL(strPtr);
}
return 0;
}
}
return (LRESULT)CallWindowProc(editWndOldProc, hWnd, message, wParam,
lParam);
} else if (message == uFindMsg) {
// Find event.
LPFINDREPLACE lpfr = (LPFINDREPLACE)lParam;
if (lpfr->Flags & FR_DIALOGTERM) {
// The find dialog box has been dismissed so invalidate the handle and
// reset the search results.
hFindDlg = NULL;
if (g_handler.get()) {
g_handler->GetBrowser()->GetHost()->StopFinding(true);
szLastFindWhat[0] = 0;
findNext = false;
}
return 0;
}
if ((lpfr->Flags & FR_FINDNEXT) && g_handler.get()) {
// Search for the requested string.
bool matchCase = (lpfr->Flags & FR_MATCHCASE?true:false);
if (matchCase != lastMatchCase ||
(matchCase && wcsncmp(szFindWhat, szLastFindWhat,
sizeof(szLastFindWhat)/sizeof(WCHAR)) != 0) ||
(!matchCase && _wcsnicmp(szFindWhat, szLastFindWhat,
sizeof(szLastFindWhat)/sizeof(WCHAR)) != 0)) {
// The search string has changed, so reset the search results.
if (szLastFindWhat[0] != 0) {
g_handler->GetBrowser()->GetHost()->StopFinding(true);
findNext = false;
}
lastMatchCase = matchCase;
wcscpy_s(szLastFindWhat, sizeof(szLastFindWhat)/sizeof(WCHAR),
szFindWhat);
}
g_handler->GetBrowser()->GetHost()->Find(0, lpfr->lpstrFindWhat,
(lpfr->Flags & FR_DOWN)?true:false, matchCase, findNext);
if (!findNext)
findNext = true;
}
return 0;
} else {
// Callback for the main window
switch (message) {
case WM_CREATE: {
// Create the single static handler class instance
g_handler = new ClientHandlerShared();
g_handler->SetMainWindowHandle(hWnd);
// Create the child windows used for navigation
RECT rect;
int x = 0;
GetClientRect(hWnd, &rect);
backWnd = CreateWindow(L"BUTTON", L"Back",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON
| WS_DISABLED, x, 0, BUTTON_WIDTH, URLBAR_HEIGHT,
hWnd, (HMENU) IDC_NAV_BACK, hInst, 0);
x += BUTTON_WIDTH;
forwardWnd = CreateWindow(L"BUTTON", L"Forward",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON
| WS_DISABLED, x, 0, BUTTON_WIDTH,
URLBAR_HEIGHT, hWnd, (HMENU) IDC_NAV_FORWARD,
hInst, 0);
x += BUTTON_WIDTH;
reloadWnd = CreateWindow(L"BUTTON", L"Reload",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON
| WS_DISABLED, x, 0, BUTTON_WIDTH,
URLBAR_HEIGHT, hWnd, (HMENU) IDC_NAV_RELOAD,
hInst, 0);
x += BUTTON_WIDTH;
stopWnd = CreateWindow(L"BUTTON", L"Stop",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON
| WS_DISABLED, x, 0, BUTTON_WIDTH, URLBAR_HEIGHT,
hWnd, (HMENU) IDC_NAV_STOP, hInst, 0);
x += BUTTON_WIDTH;
editWnd = CreateWindow(L"EDIT", 0,
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT |
ES_AUTOVSCROLL | ES_AUTOHSCROLL| WS_DISABLED,
x, 0, rect.right - BUTTON_WIDTH * 4,
URLBAR_HEIGHT, hWnd, 0, hInst, 0);
// Assign the edit window's WNDPROC to this function so that we can
// capture the enter key
editWndOldProc =
reinterpret_cast<WNDPROC>(GetWindowLongPtr(editWnd, GWLP_WNDPROC));
SetWindowLongPtr(editWnd, GWLP_WNDPROC,
reinterpret_cast<LONG_PTR>(MainWndProc));
g_handler->SetUXWindowHandles(
editWnd, backWnd, forwardWnd, reloadWnd, stopWnd);
rect.top += URLBAR_HEIGHT;
CefWindowInfo info;
CefBrowserSettings settings;
// Populate the browser settings based on command line arguments.
MainContext::Get()->PopulateBrowserSettings(&settings);
if (g_handler->is_osr()) {
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
const bool transparent =
command_line->HasSwitch(switches::kTransparentPaintingEnabled);
const bool show_update_rect =
command_line->HasSwitch(switches::kShowUpdateRect);
CefRefPtr<OSRWindow> osr_window =
OSRWindow::Create(&g_main_browser_provider, transparent,
show_update_rect);
osr_window->CreateWidget(hWnd, rect, hInst, szOSRWindowClass);
info.SetAsWindowless(osr_window->hwnd(), transparent);
g_handler->SetOSRHandler(osr_window.get());
} else {
// Initialize window info to the defaults for a child window.
info.SetAsChild(hWnd, rect);
}
// Creat the new child browser window
CefBrowserHost::CreateBrowser(info, g_handler.get(),
g_handler->startup_url(), settings, NULL);
return 0;
}
case WM_COMMAND: {
CefRefPtr<CefBrowser> browser;
if (g_handler.get())
browser = g_handler->GetBrowser();
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
if (wmId >= ID_TESTS_FIRST && wmId <= ID_TESTS_LAST) {
test_runner::RunTest(browser, wmId);
return 0;
}
// Parse the menu selections:
switch (wmId) {
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, AboutWndProc);
return 0;
case IDM_EXIT:
if (g_handler.get())
g_handler->CloseAllBrowsers(false);
return 0;
case ID_FIND:
if (!hFindDlg) {
// Create the find dialog.
ZeroMemory(&fr, sizeof(fr));
fr.lStructSize = sizeof(fr);
fr.hwndOwner = hWnd;
fr.lpstrFindWhat = szFindWhat;
fr.wFindWhatLen = sizeof(szFindWhat);
fr.Flags = FR_HIDEWHOLEWORD | FR_DOWN;
hFindDlg = FindText(&fr);
// Override the dialog's window procedure.
WNDPROC wndproc_old = SetWndProcPtr(hFindDlg, FindWndProc);
// Associate |wndproc_old| with the dialog.
SetUserDataPtr(hFindDlg, wndproc_old);
} else {
// Give focus to the existing find dialog.
::SetFocus(hFindDlg);
}
return 0;
case IDC_NAV_BACK: // Back button
if (browser.get())
browser->GoBack();
return 0;
case IDC_NAV_FORWARD: // Forward button
if (browser.get())
browser->GoForward();
return 0;
case IDC_NAV_RELOAD: // Reload button
if (browser.get())
browser->Reload();
return 0;
case IDC_NAV_STOP: // Stop button
if (browser.get())
browser->StopLoad();
return 0;
}
break;
}
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
return 0;
case WM_SETFOCUS:
if (g_handler.get()) {
CefRefPtr<CefBrowser> browser = g_handler->GetBrowser();
if (browser)
SetFocusToBrowser(browser);
}
return 0;
case WM_SIZE: {
if (!g_handler.get())
break;
// For off-screen browsers when the frame window is minimized set the
// browser as hidden to reduce resource usage.
const bool offscreen = g_handler->is_osr();
if (offscreen) {
CefRefPtr<OSRWindow> osr_window =
OSRWindow::From(g_handler->GetOSRHandler());
if (osr_window)
osr_window->WasHidden(wParam == SIZE_MINIMIZED);
}
if (g_handler->GetBrowser()) {
// Retrieve the window handle (parent window with off-screen rendering).
CefWindowHandle hwnd =
g_handler->GetBrowser()->GetHost()->GetWindowHandle();
if (hwnd) {
if (wParam == SIZE_MINIMIZED) {
// For windowed browsers when the frame window is minimized set the
// browser window size to 0x0 to reduce resource usage.
if (!offscreen) {
SetWindowPos(hwnd, NULL,
0, 0, 0, 0, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
}
} else {
// Resize the window and address bar to match the new frame size.
RECT rect;
GetClientRect(hWnd, &rect);
rect.top += URLBAR_HEIGHT;
int urloffset = rect.left + BUTTON_WIDTH * 4;
HDWP hdwp = BeginDeferWindowPos(1);
hdwp = DeferWindowPos(hdwp, editWnd, NULL, urloffset,
0, rect.right - urloffset, URLBAR_HEIGHT, SWP_NOZORDER);
hdwp = DeferWindowPos(hdwp, hwnd, NULL,
rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, SWP_NOZORDER);
EndDeferWindowPos(hdwp);
}
}
}
} break;
case WM_MOVING:
case WM_MOVE:
// Notify the browser of move events so that popup windows are displayed
// in the correct location and dismissed when the window moves.
if (g_handler.get() && g_handler->GetBrowser())
g_handler->GetBrowser()->GetHost()->NotifyMoveOrResizeStarted();
return 0;
case WM_ERASEBKGND:
if (g_handler.get() && g_handler->GetBrowser()) {
CefWindowHandle hwnd =
g_handler->GetBrowser()->GetHost()->GetWindowHandle();
if (hwnd) {
// Dont erase the background if the browser window has been loaded
// (this avoids flashing)
return 0;
}
}
break;
case WM_ENTERMENULOOP:
if (!wParam) {
// Entering the menu loop for the application menu.
CefSetOSModalLoop(true);
}
break;
case WM_EXITMENULOOP:
if (!wParam) {
// Exiting the menu loop for the application menu.
CefSetOSModalLoop(false);
}
break;
case WM_CLOSE:
if (g_handler.get() && !g_handler->IsClosing()) {
CefRefPtr<CefBrowser> browser = g_handler->GetBrowser();
if (browser.get()) {
// Notify the browser window that we would like to close it. This
// will result in a call to ClientHandler::DoClose() if the
// JavaScript 'onbeforeunload' event handler allows it.
browser->GetHost()->CloseBrowser(false);
// Cancel the close.
return 0;
}
}
// Allow the close.
break;
case WM_DESTROY:
// Quitting CEF is handled in ClientHandler::OnBeforeClose().
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
// Window procedure for the find dialog.
LRESULT CALLBACK FindWndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam) {
REQUIRE_MAIN_THREAD();
WNDPROC old_wndproc = GetUserDataPtr<WNDPROC>(hWnd);
DCHECK(old_wndproc);
switch (message) {
case WM_ACTIVATE:
// Set this dialog as current when activated.
MainMessageLoop::Get()->SetCurrentModelessDialog(
wParam == 0 ? NULL : hWnd);
return FALSE;
case WM_NCDESTROY:
// Clear the reference to |old_wndproc|.
SetUserDataPtr(hWnd, NULL);
break;
}
return CallWindowProc(old_wndproc, hWnd, message, wParam, lParam);
}
// Window procedure for the about dialog.
INT_PTR CALLBACK AboutWndProc(HWND hDlg, UINT message, WPARAM wParam,
LPARAM lParam) {
UNREFERENCED_PARAMETER(lParam);
switch (message) {
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
} // namespace
} // namespace client

View File

@ -264,7 +264,8 @@ bool ClientHandler::OnBeforePopup(CefRefPtr<CefBrowser> browser,
CEF_REQUIRE_IO_THREAD();
// Return true to cancel the popup window.
return !CreatePopupWindow(false, popupFeatures, windowInfo, client, settings);
return !CreatePopupWindow(browser, false, popupFeatures, windowInfo, client,
settings);
}
void ClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
@ -464,7 +465,7 @@ void ClientHandler::ShowDevTools(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefClient> client;
CefBrowserSettings settings;
if (CreatePopupWindow(true, CefPopupFeatures(), windowInfo, client,
if (CreatePopupWindow(browser, true, CefPopupFeatures(), windowInfo, client,
settings)) {
browser->GetHost()->ShowDevTools(windowInfo, client, settings,
inspect_element_at);

View File

@ -235,6 +235,7 @@ class ClientHandler : public CefClient,
// proceed with popup browser creation or false to cancel the popup browser.
// May be called on any thead.
virtual bool CreatePopupWindow(
CefRefPtr<CefBrowser> browser,
bool is_devtools,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,

View File

@ -0,0 +1,138 @@
// 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/client_handler_osr.h"
#include "include/base/cef_bind.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
namespace client {
ClientHandlerOsr::ClientHandlerOsr(Delegate* delegate,
OsrDelegate* osr_delegate,
const std::string& startup_url)
: ClientHandlerSingle(delegate, true, startup_url),
osr_delegate_(osr_delegate) {
DCHECK(osr_delegate_);
}
void ClientHandlerOsr::DetachOsrDelegate() {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI, base::Bind(&ClientHandlerOsr::DetachOsrDelegate, this));
return;
}
DCHECK(osr_delegate_);
osr_delegate_ = NULL;
}
void ClientHandlerOsr::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
if (osr_delegate_)
osr_delegate_->OnAfterCreated(browser);
ClientHandlerSingle::OnAfterCreated(browser);
}
void ClientHandlerOsr::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
if (osr_delegate_)
osr_delegate_->OnBeforeClose(browser);
ClientHandlerSingle::OnBeforeClose(browser);
}
bool ClientHandlerOsr::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return false;
return osr_delegate_->GetRootScreenRect(browser, rect);
}
bool ClientHandlerOsr::GetViewRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return false;
return osr_delegate_->GetViewRect(browser, rect);
}
bool ClientHandlerOsr::GetScreenPoint(CefRefPtr<CefBrowser> browser,
int viewX,
int viewY,
int& screenX,
int& screenY) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return false;
return osr_delegate_->GetScreenPoint(browser, viewX, viewY, screenX, screenY);
}
bool ClientHandlerOsr::GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return false;
return osr_delegate_->GetScreenInfo(browser, screen_info);
}
void ClientHandlerOsr::OnPopupShow(CefRefPtr<CefBrowser> browser,
bool show) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
return osr_delegate_->OnPopupShow(browser, show);
}
void ClientHandlerOsr::OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
return osr_delegate_->OnPopupSize(browser, rect);
}
void ClientHandlerOsr::OnPaint(CefRefPtr<CefBrowser> browser,
PaintElementType type,
const RectList& dirtyRects,
const void* buffer,
int width,
int height) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
osr_delegate_->OnPaint(browser, type, dirtyRects, buffer, width, height);
}
void ClientHandlerOsr::OnCursorChange(
CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
CursorType type,
const CefCursorInfo& custom_cursor_info) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
osr_delegate_->OnCursorChange(browser, cursor, type, custom_cursor_info);
}
bool ClientHandlerOsr::StartDragging(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> drag_data,
CefRenderHandler::DragOperationsMask allowed_ops,
int x, int y) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return false;
return osr_delegate_->StartDragging(browser, drag_data, allowed_ops, x, y);
}
void ClientHandlerOsr::UpdateDragCursor(CefRefPtr<CefBrowser> browser,
CefRenderHandler::DragOperation operation) {
CEF_REQUIRE_UI_THREAD();
if (!osr_delegate_)
return;
osr_delegate_->UpdateDragCursor(browser, operation);
}
} // namespace client

View File

@ -0,0 +1,123 @@
// 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_CLIENT_HANDLER_OSR_H_
#define CEF_TESTS_CEFCLIENT_CLIENT_HANDLER_OSR_H_
#include "cefclient/client_handler_single.h"
namespace client {
// Client handler implementation for windowless browsers. There will only ever
// be one browser per handler instance.
class ClientHandlerOsr : public ClientHandlerSingle,
public CefRenderHandler {
public:
// Implement this interface to receive notification of ClientHandlerOsr
// events. The methods of this class will be called on the CEF UI thread.
class OsrDelegate {
public:
// These methods match the CefLifeSpanHandler interface.
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) = 0;
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) = 0;
// These methods match the CefRenderHandler interface.
virtual bool GetRootScreenRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) = 0;
virtual bool GetViewRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) = 0;
virtual bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
int viewX,
int viewY,
int& screenX,
int& screenY) = 0;
virtual bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) = 0;
virtual void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) = 0;
virtual void OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) = 0;
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
PaintElementType type,
const RectList& dirtyRects,
const void* buffer,
int width,
int height) = 0;
virtual void OnCursorChange(
CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
CefRenderHandler::CursorType type,
const CefCursorInfo& custom_cursor_info) = 0;
virtual bool StartDragging(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> drag_data,
CefRenderHandler::DragOperationsMask allowed_ops,
int x, int y) = 0;
virtual void UpdateDragCursor(
CefRefPtr<CefBrowser> browser,
CefRenderHandler::DragOperation operation) = 0;
protected:
virtual ~OsrDelegate() {}
};
ClientHandlerOsr(Delegate* delegate,
OsrDelegate* osr_delegate,
const std::string& startup_url);
// This object may outlive the OsrDelegate object so it's necessary for the
// OsrDelegate to detach itself before destruction.
void DetachOsrDelegate();
// CefClient methods.
CefRefPtr<CefRenderHandler> GetRenderHandler() OVERRIDE {
return this;
}
// CefLifeSpanHandler methods.
void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
// CefRenderHandler methods.
bool GetRootScreenRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) OVERRIDE;
bool GetViewRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) OVERRIDE;
bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
int viewX,
int viewY,
int& screenX,
int& screenY) OVERRIDE;
bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) OVERRIDE;
void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) OVERRIDE;
void OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) OVERRIDE;
void OnPaint(CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList& dirtyRects,
const void* buffer,
int width,
int height) OVERRIDE;
void OnCursorChange(CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
CursorType type,
const CefCursorInfo& custom_cursor_info) OVERRIDE;
bool StartDragging(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> drag_data,
CefRenderHandler::DragOperationsMask allowed_ops,
int x, int y) OVERRIDE;
void UpdateDragCursor(CefRefPtr<CefBrowser> browser,
CefRenderHandler::DragOperation operation) OVERRIDE;
private:
// Only accessed on the UI thread.
OsrDelegate* osr_delegate_;
// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(ClientHandlerOsr);
DISALLOW_COPY_AND_ASSIGN(ClientHandlerOsr);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_CLIENT_HANDLER_OSR_H_

View File

@ -40,12 +40,7 @@ void ClientHandlerShared::BrowserCreated(CefRefPtr<CefBrowser> browser) {
if (browser_id_ == 0) {
// Keep references to the browser hosted in the main window.
browser_id_ = browser->GetIdentifier();
{
// Protect modification of |browser_| with a lock because it may be
// accessed from different threads.
base::AutoLock lock_scope(lock_);
browser_ = browser;
}
browser_ = browser;
} else if (browser->IsPopup()) {
// Add to the list of popup browsers.
popup_browsers_.push_back(browser);
@ -64,9 +59,6 @@ void ClientHandlerShared::BrowserClosing(CefRefPtr<CefBrowser> browser) {
// documentation in the CEF header for a detailed destription of this
// process.
if (browser_id_ == browser->GetIdentifier()) {
// Protect modification of |is_closing_| with a lock because it may be
// accessed from different threads.
base::AutoLock lock_scope(lock_);
// Set a flag to indicate that the window close should be allowed.
is_closing_ = true;
}
@ -76,20 +68,11 @@ void ClientHandlerShared::BrowserClosed(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
if (browser_id_ == browser->GetIdentifier()) {
{
// Protect modification of |browser_| with a lock because it may be
// accessed from different threads.
base::AutoLock lock_scope(lock_);
// Free the browser pointer so that the browser can be destroyed.
browser_ = NULL;
}
// Free the browser pointer so that the browser can be destroyed.
browser_ = NULL;
if (osr_handler_.get()) {
osr_handler_->OnBeforeClose(browser);
// Protect modification of |osr_handler_| with a lock because it may be
// accessed from different threads.
base::AutoLock lock_scope(lock_);
osr_handler_ = NULL;
}
@ -112,6 +95,7 @@ void ClientHandlerShared::BrowserClosed(CefRefPtr<CefBrowser> browser) {
}
bool ClientHandlerShared::CreatePopupWindow(
CefRefPtr<CefBrowser> browser,
bool is_devtools,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
@ -120,6 +104,8 @@ bool ClientHandlerShared::CreatePopupWindow(
// Note: This method will be called on multiple threads.
if (is_devtools) {
CEF_REQUIRE_UI_THREAD();
// Create DevTools as a windowed popup browser using the same client.
#if defined(OS_WIN)
windowInfo.SetAsPopup(GetMainWindowHandle(), "DevTools");
@ -127,7 +113,7 @@ bool ClientHandlerShared::CreatePopupWindow(
client = this;
} else if (is_osr()) {
CefPostTask(TID_UI,
base::Bind(test_runner::Alert, GetBrowser(),
base::Bind(test_runner::Alert, browser,
"Popup windows are disabled with off-screen rendering."));
// Cancel popups in off-screen rendering mode.
@ -143,14 +129,7 @@ void ClientHandlerShared::SetUXWindowHandles(
ClientWindowHandle forwardHandle,
ClientWindowHandle reloadHandle,
ClientWindowHandle stopHandle) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute on the UI thread.
CefPostTask(TID_UI,
base::Bind(&ClientHandlerShared::SetUXWindowHandles, this,
editHandle, backHandle, forwardHandle, reloadHandle,
stopHandle));
return;
}
CEF_REQUIRE_UI_THREAD();
edit_handle_ = editHandle;
back_handle_ = backHandle;
@ -161,50 +140,31 @@ void ClientHandlerShared::SetUXWindowHandles(
CefRefPtr<ClientHandlerShared::RenderHandler>
ClientHandlerShared::GetOSRHandler() const {
if (CefCurrentlyOn(TID_UI)) {
// No need for locking because |osr_handler_| will only be modified on this
// thread.
return osr_handler_;
} else {
// Use a lock to protect |osr_handler_| from being modified while we're
// accessing it from a different thread.
base::AutoLock lock_scope(lock_);
return osr_handler_;
}
CEF_REQUIRE_UI_THREAD();
return osr_handler_;
}
void ClientHandlerShared::SetOSRHandler(CefRefPtr<RenderHandler> handler) {
// Protect modification of |osr_handler_| with a lock because it may be
// accessed from different threads.
base::AutoLock lock_scope(lock_);
CEF_REQUIRE_UI_THREAD();
osr_handler_ = handler;
}
CefRefPtr<CefBrowser> ClientHandlerShared::GetBrowser() const {
if (CefCurrentlyOn(TID_UI)) {
// No need for locking because |browser_| will only be modified on this
// thread.
return browser_;
} else {
// Use a lock to protect |browser_| from being modified while we're
// accessing it from a different thread.
base::AutoLock lock_scope(lock_);
return browser_;
}
CEF_REQUIRE_UI_THREAD();
return browser_;
}
int ClientHandlerShared::GetBrowserId() const {
CEF_REQUIRE_UI_THREAD();
return browser_id_;
}
void ClientHandlerShared::CloseAllBrowsers(bool force_close) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute on the UI thread.
CefPostTask(TID_UI,
base::Bind(&ClientHandlerShared::CloseAllBrowsers, this, force_close));
return;
}
CEF_REQUIRE_UI_THREAD();
if (!popup_browsers_.empty()) {
// Request that any popup browsers close.
@ -220,16 +180,9 @@ void ClientHandlerShared::CloseAllBrowsers(bool force_close) {
}
bool ClientHandlerShared::IsClosing() const {
if (CefCurrentlyOn(TID_UI)) {
// No need for locking because |is_closing_| will only be modified on this
// thread.
return is_closing_;
} else {
// Use a lock to protect |is_closing_| from being modified while we're
// accessing it from a different thread.
base::AutoLock lock_scope(lock_);
return is_closing_;
}
CEF_REQUIRE_UI_THREAD();
return is_closing_;
}
} // namespace client

View File

@ -9,12 +9,12 @@
#include <list>
#include <string>
#include "include/base/cef_lock.h"
#include "cefclient/client_handler.h"
namespace client {
// Client handler implementation that is shared by all existing browsers.
// Client handler implementation that is shared by all existing browsers. All
// methods must be called on the CEF UI thread unless otherwise indicated.
class ClientHandlerShared : public ClientHandler {
public:
// Interface implemented to handle off-screen rendering.
@ -44,6 +44,7 @@ class ClientHandlerShared : public ClientHandler {
bool canGoBack,
bool canGoForward) OVERRIDE;
bool CreatePopupWindow(
CefRefPtr<CefBrowser> browser,
bool is_devtools,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
@ -59,12 +60,11 @@ class ClientHandlerShared : public ClientHandler {
CefRefPtr<RenderHandler> GetOSRHandler() const;
void SetOSRHandler(CefRefPtr<RenderHandler> handler);
// Get the main (non-popup) browser associated with this client. Safe to call
// on any thread.
// Get the main (non-popup) browser associated with this client.
CefRefPtr<CefBrowser> GetBrowser() const;
// Get the main (non-popup) browser ID. Will return non-0 if the main browser
// currently exists. Should only be called on the CEF UI thread.
// currently exists.
int GetBrowserId() const;
// Request that all existing browser windows close.
@ -72,21 +72,11 @@ class ClientHandlerShared : public ClientHandler {
// Returns true if the main browser window is currently closing. Used in
// combination with DoClose() and the OS close notification to properly handle
// 'onbeforeunload' JavaScript events during window close. Safe to call on any
// thread.
// 'onbeforeunload' JavaScript events during window close.
bool IsClosing() const;
private:
// Lock used to protect members accessed on multiple threads. Make it mutable
// so that it can be used from const methods.
mutable base::Lock lock_;
// LOCK PROTECTED MEMBERS
// Setting the following members or accessing them from a thread other than
// the CEF UI thread must be protected by |lock_|. Most platforms will only
// access them from the UI thread but on Windows they will be accessed from
// the main application thread when using using multi-threaded message loop
// mode.
// The following members will only be accessed on the CEF UI thread.
// The handler for off-screen rendering, if any.
CefRefPtr<RenderHandler> osr_handler_;
@ -97,9 +87,6 @@ class ClientHandlerShared : public ClientHandler {
// True if the main browser window is currently closing.
bool is_closing_;
// UI THREAD MEMBERS
// The following members will only be accessed on the CEF UI thread.
// The child browser id.
int browser_id_;

View File

@ -1,55 +0,0 @@
// Copyright (c) 2011 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/client_handler_shared.h"
#include <string>
#include <windows.h>
#include "include/cef_browser.h"
#include "cefclient/resource.h"
namespace client {
void ClientHandlerShared::SetAddress(CefRefPtr<CefBrowser> browser,
const CefString& url) {
CEF_REQUIRE_UI_THREAD();
if (browser_id_ == browser->GetIdentifier()) {
// Set the edit window text for the main (top-level) browser.
SetWindowText(edit_handle_, std::wstring(url).c_str());
}
}
void ClientHandlerShared::SetTitle(CefRefPtr<CefBrowser> browser,
const CefString& title) {
CEF_REQUIRE_UI_THREAD();
// Set the frame window title bar.
CefWindowHandle hwnd = browser->GetHost()->GetWindowHandle();
if (browser_id_ == browser->GetIdentifier()) {
// For the main (top-level) browser the frame window will be the parent of
// the browser window.
hwnd = GetParent(hwnd);
}
SetWindowText(hwnd, std::wstring(title).c_str());
}
void ClientHandlerShared::SetLoadingState(CefRefPtr<CefBrowser> browser,
bool isLoading,
bool canGoBack,
bool canGoForward) {
CEF_REQUIRE_UI_THREAD();
if (browser_id_ == browser->GetIdentifier()) {
// Set UX control state for the main (top-level) browser.
EnableWindow(edit_handle_, TRUE);
EnableWindow(reload_handle_, !isLoading);
EnableWindow(stop_handle_, isLoading);
EnableWindow(back_handle_, canGoBack);
EnableWindow(forward_handle_, canGoForward);
}
}
} // namespace client

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/client_handler_single.h"
#include <stdio.h>
#include <algorithm>
#include <string>
#include "include/base/cef_bind.h"
#include "include/cef_command_line.h"
#include "include/wrapper/cef_closure_task.h"
#include "cefclient/main_context.h"
#include "cefclient/main_message_loop.h"
#include "cefclient/root_window_manager.h"
namespace client {
ClientHandlerSingle::ClientHandlerSingle(Delegate* delegate,
bool is_osr,
const std::string& startup_url)
: ClientHandler(startup_url, is_osr),
delegate_(delegate) {
DCHECK(delegate_);
}
void ClientHandlerSingle::DetachDelegate() {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(base::Bind(&ClientHandlerSingle::DetachDelegate, this));
return;
}
DCHECK(delegate_);
delegate_ = NULL;
}
void ClientHandlerSingle::BrowserCreated(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
NotifyBrowserCreated(browser);
}
void ClientHandlerSingle::BrowserClosing(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
NotifyBrowserClosing(browser);
}
void ClientHandlerSingle::BrowserClosed(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
NotifyBrowserClosed(browser);
}
void ClientHandlerSingle::SetAddress(CefRefPtr<CefBrowser> browser,
const CefString& url) {
CEF_REQUIRE_UI_THREAD();
NotifyAddress(url);
}
void ClientHandlerSingle::SetTitle(CefRefPtr<CefBrowser> browser,
const CefString& title) {
CEF_REQUIRE_UI_THREAD();
NotifyTitle(title);
}
void ClientHandlerSingle::SetLoadingState(CefRefPtr<CefBrowser> browser,
bool isLoading,
bool canGoBack,
bool canGoForward) {
CEF_REQUIRE_UI_THREAD();
NotifyLoadingState(isLoading, canGoBack, canGoForward);
}
bool ClientHandlerSingle::CreatePopupWindow(
CefRefPtr<CefBrowser> browser,
bool is_devtools,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) {
// Note: This method will be called on multiple threads.
// The popup browser will be parented to a new native window.
// Don't show URL bar and navigation buttons on DevTools windows.
MainContext::Get()->GetRootWindowManager()->CreateRootWindowAsPopup(
!is_devtools, is_osr(), popupFeatures, windowInfo, client, settings);
return true;
}
void ClientHandlerSingle::NotifyBrowserCreated(CefRefPtr<CefBrowser> browser) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(
base::Bind(&ClientHandlerSingle::NotifyBrowserCreated, this, browser));
return;
}
if (delegate_)
delegate_->OnBrowserCreated(browser);
}
void ClientHandlerSingle::NotifyBrowserClosing(CefRefPtr<CefBrowser> browser) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(
base::Bind(&ClientHandlerSingle::NotifyBrowserClosing, this, browser));
return;
}
if (delegate_)
delegate_->OnBrowserClosing(browser);
}
void ClientHandlerSingle::NotifyBrowserClosed(CefRefPtr<CefBrowser> browser) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(
base::Bind(&ClientHandlerSingle::NotifyBrowserClosed, this, browser));
return;
}
if (delegate_)
delegate_->OnBrowserClosed(browser);
}
void ClientHandlerSingle::NotifyAddress(const CefString& url) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(
base::Bind(&ClientHandlerSingle::NotifyAddress, this, url));
return;
}
if (delegate_)
delegate_->OnSetAddress(url);
}
void ClientHandlerSingle::NotifyTitle(const CefString& title) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(
base::Bind(&ClientHandlerSingle::NotifyTitle, this, title));
return;
}
if (delegate_)
delegate_->OnSetTitle(title);
}
void ClientHandlerSingle::NotifyLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(
base::Bind(&ClientHandlerSingle::NotifyLoadingState, this,
isLoading, canGoBack, canGoForward));
return;
}
if (delegate_)
delegate_->OnSetLoadingState(isLoading, canGoBack, canGoForward);
}
} // namespace client

View File

@ -0,0 +1,97 @@
// 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_CLIENT_HANDLER_SINGLE_H_
#define CEF_TESTS_CEFCLIENT_CLIENT_HANDLER_SINGLE_H_
#pragma once
#include <list>
#include <string>
#include "include/base/cef_lock.h"
#include "cefclient/client_handler.h"
namespace client {
// Client handler implementation that is used by a single browser.
class ClientHandlerSingle : public ClientHandler {
public:
// Implement this interface to receive notification of ClientHandlerSingle
// events. The methods of this class will be called on the main thread.
class Delegate {
public:
// Called when the browser is created.
virtual void OnBrowserCreated(CefRefPtr<CefBrowser> browser) = 0;
// Called when the browser is closing.
virtual void OnBrowserClosing(CefRefPtr<CefBrowser> browser) = 0;
// Called when the browser has been closed.
virtual void OnBrowserClosed(CefRefPtr<CefBrowser> browser) = 0;
// Set the window URL address.
virtual void OnSetAddress(const std::string& url) = 0;
// Set the window title.
virtual void OnSetTitle(const std::string& title) = 0;
// Set the loading state.
virtual void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) = 0;
protected:
virtual ~Delegate() {}
};
// This object may outlive the Delegate object so it's necessary for the
// Delegate to detach itself before destruction.
void DetachDelegate();
protected:
// Constructor may be called on any thread.
// |delegate| must outlive this object or DetachDelegate() must be called.
ClientHandlerSingle(Delegate* delegate,
bool is_osr,
const std::string& startup_url);
// ClientHandler methods
void BrowserCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
void BrowserClosing(CefRefPtr<CefBrowser> browser) OVERRIDE;
void BrowserClosed(CefRefPtr<CefBrowser> browser) OVERRIDE;
void SetAddress(CefRefPtr<CefBrowser> browser,
const CefString& url) OVERRIDE;
void SetTitle(CefRefPtr<CefBrowser> browser,
const CefString& title) OVERRIDE;
void SetLoadingState(CefRefPtr<CefBrowser> browser,
bool isLoading,
bool canGoBack,
bool canGoForward) OVERRIDE;
bool CreatePopupWindow(
CefRefPtr<CefBrowser> browser,
bool is_devtools,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) OVERRIDE;
private:
void NotifyBrowserCreated(CefRefPtr<CefBrowser> browser);
void NotifyBrowserClosing(CefRefPtr<CefBrowser> browser);
void NotifyBrowserClosed(CefRefPtr<CefBrowser> browser);
void NotifyAddress(const CefString& url);
void NotifyTitle(const CefString& title);
void NotifyLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward);
// Only accessed on the main thread.
Delegate* delegate_;
DISALLOW_COPY_AND_ASSIGN(ClientHandlerSingle);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_CLIENT_HANDLER_SINGLE_H_

View File

@ -0,0 +1,14 @@
// 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/client_handler_std.h"
namespace client {
ClientHandlerStd::ClientHandlerStd(Delegate* delegate,
const std::string& startup_url)
: ClientHandlerSingle(delegate, false, startup_url) {
}
} // namespace client

View File

@ -0,0 +1,27 @@
// 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_CLIENT_HANDLER_STD_H_
#define CEF_TESTS_CEFCLIENT_CLIENT_HANDLER_STD_H_
#include "cefclient/client_handler_single.h"
namespace client {
// Client handler implementation for windowed browsers. There will only ever be
// one browser per handler instance.
class ClientHandlerStd : public ClientHandlerSingle {
public:
ClientHandlerStd(Delegate* delegate,
const std::string& startup_url);
private:
// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(ClientHandlerStd);
DISALLOW_COPY_AND_ASSIGN(ClientHandlerStd);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_CLIENT_HANDLER_STD_H_

View File

@ -12,6 +12,10 @@
namespace client {
#if defined(OS_WIN)
class RootWindowManager;
#endif
// Used to store global context in the browser process. The methods of this
// class are thread-safe unless otherwise indicated.
class MainContext {
@ -35,6 +39,11 @@ class MainContext {
virtual void PopulateSettings(CefSettings* settings) = 0;
virtual void PopulateBrowserSettings(CefBrowserSettings* settings) = 0;
#if defined(OS_WIN)
// Returns the object used to create/manage RootWindow instances.
virtual RootWindowManager* GetRootWindowManager() = 0;
#endif
protected:
MainContext();
virtual ~MainContext();

View File

@ -6,6 +6,9 @@
#include "cefclient/client_switches.h"
#if defined(OS_WIN)
#include "cefclient/root_window_manager.h"
#endif
namespace client {
namespace {
@ -16,7 +19,11 @@ const char kDefaultUrl[] = "http://www.google.com";
} // namespace
MainContextImpl::MainContextImpl(int argc,
const char* const* argv) {
const char* const* argv
#if defined(OS_WIN)
, bool terminate_when_all_windows_closed
#endif
) {
// Parse the command line.
command_line_ = CefCommandLine::CreateCommandLine();
#if defined(OS_WIN)
@ -30,6 +37,11 @@ MainContextImpl::MainContextImpl(int argc,
main_url_ = command_line_->GetSwitchValue(switches::kUrl);
if (main_url_.empty())
main_url_ = kDefaultUrl;
#if defined(OS_WIN)
root_window_manager_.reset(
new RootWindowManager(terminate_when_all_windows_closed));
#endif
}
std::string MainContextImpl::GetConsoleLogPath() {
@ -60,4 +72,10 @@ void MainContextImpl::PopulateBrowserSettings(CefBrowserSettings* settings) {
}
}
#if defined(OS_WIN)
RootWindowManager* MainContextImpl::GetRootWindowManager() {
return root_window_manager_.get();
}
#endif
} // namespace client

View File

@ -15,7 +15,11 @@ namespace client {
class MainContextImpl : public MainContext {
public:
MainContextImpl(int argc,
const char* const* argv);
const char* const* argv
#if defined(OS_WIN)
, bool terminate_when_all_windows_closed
#endif
);
// MainContext members.
std::string GetConsoleLogPath() OVERRIDE;
@ -24,6 +28,9 @@ class MainContextImpl : public MainContext {
std::string GetMainURL() OVERRIDE;
void PopulateSettings(CefSettings* settings) OVERRIDE;
void PopulateBrowserSettings(CefBrowserSettings* settings) OVERRIDE;
#if defined(OS_WIN)
RootWindowManager* GetRootWindowManager() OVERRIDE;
#endif
private:
// Allow deletion via scoped_ptr only.
@ -34,6 +41,10 @@ class MainContextImpl : public MainContext {
CefRefPtr<CefCommandLine> command_line_;
std::string main_url_;
#if defined(OS_WIN)
scoped_ptr<RootWindowManager> root_window_manager_;
#endif
DISALLOW_COPY_AND_ASSIGN(MainContextImpl);
};

View File

@ -7,6 +7,8 @@
#include <direct.h>
#include <shlobj.h>
#include "cefclient/root_window_manager.h"
namespace client {
std::string MainContextImpl::GetDownloadPath(const std::string& file_name) {

View File

@ -48,14 +48,6 @@ class MainMessageLoop {
// 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>;
@ -64,12 +56,6 @@ class MainMessageLoop {
virtual ~MainMessageLoop();
private:
// Helper for deleting |object|.
template<class T>
static void DeleteHelper(const T* object) {
delete object;
}
DISALLOW_COPY_AND_ASSIGN(MainMessageLoop);
};
@ -110,7 +96,8 @@ struct DeleteOnMainThread {
if (CURRENTLY_ON_MAIN_THREAD()) {
delete x;
} else {
client::MainMessageLoop::Get()->DeleteSoon(x);
client::MainMessageLoop::Get()->PostClosure(
base::Bind(&DeleteOnMainThread::Destruct<T>, x));
}
}
};

View File

@ -1,681 +0,0 @@
// Copyright (c) 2011 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/osr_widget_win.h"
#include <windowsx.h>
#include "include/base/cef_bind.h"
#include "include/base/cef_build.h"
#include "include/wrapper/cef_closure_task.h"
#include "cefclient/resource.h"
#include "cefclient/util_win.h"
namespace client {
namespace {
class ScopedGLContext {
public:
ScopedGLContext(HDC hdc, HGLRC hglrc, bool swap_buffers)
: hdc_(hdc),
swap_buffers_(swap_buffers) {
BOOL result = wglMakeCurrent(hdc, hglrc);
ALLOW_UNUSED_LOCAL(result);
DCHECK(result);
}
~ScopedGLContext() {
BOOL result = wglMakeCurrent(NULL, NULL);
DCHECK(result);
if (swap_buffers_) {
result = SwapBuffers(hdc_);
DCHECK(result);
}
}
private:
const HDC hdc_;
const bool swap_buffers_;
};
} // namespace
// static
CefRefPtr<OSRWindow> OSRWindow::Create(
OSRBrowserProvider* browser_provider,
bool transparent,
bool show_update_rect) {
DCHECK(browser_provider);
if (!browser_provider)
return NULL;
return new OSRWindow(browser_provider, transparent, show_update_rect);
}
// static
CefRefPtr<OSRWindow> OSRWindow::From(
CefRefPtr<ClientHandlerShared::RenderHandler> renderHandler) {
return static_cast<OSRWindow*>(renderHandler.get());
}
bool OSRWindow::CreateWidget(HWND hWndParent, const RECT& rect,
HINSTANCE hInst, LPCTSTR className) {
DCHECK(hWnd_ == NULL && hDC_ == NULL && hRC_ == NULL);
RegisterOSRClass(hInst, className);
hWnd_ = ::CreateWindow(className, 0,
WS_BORDER | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
hWndParent, 0, hInst, 0);
if (!hWnd_)
return false;
SetWindowLongPtr(hWnd_, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
// Reference released in OnDestroyed().
AddRef();
#if defined(CEF_USE_ATL)
drop_target_ = DropTargetWin::Create(this, hWnd_);
HRESULT register_res = RegisterDragDrop(hWnd_, drop_target_);
DCHECK_EQ(register_res, S_OK);
#endif
return true;
}
void OSRWindow::DestroyWidget() {
if (IsWindow(hWnd_))
DestroyWindow(hWnd_);
}
void OSRWindow::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
#if defined(CEF_USE_ATL)
RevokeDragDrop(hWnd_);
drop_target_ = NULL;
#endif
DisableGL();
::DestroyWindow(hWnd_);
}
bool OSRWindow::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) {
RECT window_rect = {0};
HWND root_window = GetAncestor(hWnd_, GA_ROOT);
if (::GetWindowRect(root_window, &window_rect)) {
rect = CefRect(window_rect.left,
window_rect.top,
window_rect.right - window_rect.left,
window_rect.bottom - window_rect.top);
return true;
}
return false;
}
bool OSRWindow::GetViewRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) {
RECT clientRect;
if (!::GetClientRect(hWnd_, &clientRect))
return false;
rect.x = rect.y = 0;
rect.width = clientRect.right;
rect.height = clientRect.bottom;
return true;
}
bool OSRWindow::GetScreenPoint(CefRefPtr<CefBrowser> browser,
int viewX,
int viewY,
int& screenX,
int& screenY) {
if (!::IsWindow(hWnd_))
return false;
// Convert the point from view coordinates to actual screen coordinates.
POINT screen_pt = {viewX, viewY};
ClientToScreen(hWnd_, &screen_pt);
screenX = screen_pt.x;
screenY = screen_pt.y;
return true;
}
void OSRWindow::OnPopupShow(CefRefPtr<CefBrowser> browser,
bool show) {
if (!show) {
renderer_.ClearPopupRects();
browser->GetHost()->Invalidate(PET_VIEW);
}
renderer_.OnPopupShow(browser, show);
}
void OSRWindow::OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) {
renderer_.OnPopupSize(browser, rect);
}
void OSRWindow::OnPaint(CefRefPtr<CefBrowser> browser,
PaintElementType type,
const RectList& dirtyRects,
const void* buffer,
int width, int height) {
if (painting_popup_) {
renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
return;
}
if (!hDC_)
EnableGL();
{
ScopedGLContext scoped_gl_context(hDC_, hRC_, true);
renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) {
painting_popup_ = true;
browser->GetHost()->Invalidate(PET_POPUP);
painting_popup_ = false;
}
renderer_.Render();
}
}
void OSRWindow::OnCursorChange(CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
CursorType type,
const CefCursorInfo& custom_cursor_info) {
if (!::IsWindow(hWnd_))
return;
// Change the plugin window's cursor.
SetClassLongPtr(hWnd_, GCLP_HCURSOR,
static_cast<LONG>(reinterpret_cast<LONG_PTR>(cursor)));
SetCursor(cursor);
}
bool OSRWindow::StartDragging(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> drag_data,
CefRenderHandler::DragOperationsMask allowed_ops,
int x, int y) {
#if defined(CEF_USE_ATL)
if (!drop_target_)
return false;
current_drag_op_ = DRAG_OPERATION_NONE;
CefBrowserHost::DragOperationsMask result =
drop_target_->StartDragging(browser, drag_data, allowed_ops, x, y);
current_drag_op_ = DRAG_OPERATION_NONE;
POINT pt = {};
GetCursorPos(&pt);
ScreenToClient(hWnd_, &pt);
browser->GetHost()->DragSourceEndedAt(pt.x, pt.y, result);
browser->GetHost()->DragSourceSystemDragEnded();
return true;
#else
// Cancel the drag. The dragging implementation requires ATL support.
return false;
#endif
}
void OSRWindow::UpdateDragCursor(CefRefPtr<CefBrowser> browser,
CefRenderHandler::DragOperation operation) {
#if defined(CEF_USE_ATL)
current_drag_op_ = operation;
#endif
}
void OSRWindow::Invalidate() {
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::Bind(&OSRWindow::Invalidate, this));
return;
}
// Don't post another task if the previous task is still pending.
if (render_task_pending_)
return;
render_task_pending_ = true;
// Render at 30fps.
static const int kRenderDelay = 1000 / 30;
CefPostDelayedTask(TID_UI, base::Bind(&OSRWindow::Render, this),
kRenderDelay);
}
void OSRWindow::WasHidden(bool hidden) {
if (hidden == hidden_)
return;
CefRefPtr<CefBrowser> browser = browser_provider_->GetBrowser();
if (!browser)
return;
browser->GetHost()->WasHidden(hidden);
hidden_ = hidden;
}
#if defined(CEF_USE_ATL)
CefBrowserHost::DragOperationsMask
OSRWindow::OnDragEnter(CefRefPtr<CefDragData> drag_data,
CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) {
browser_provider_->GetBrowser()->GetHost()->DragTargetDragEnter(
drag_data, ev, effect);
browser_provider_->GetBrowser()->GetHost()->DragTargetDragOver(ev, effect);
return current_drag_op_;
}
CefBrowserHost::DragOperationsMask OSRWindow::OnDragOver(CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) {
browser_provider_->GetBrowser()->GetHost()->DragTargetDragOver(ev, effect);
return current_drag_op_;
}
void OSRWindow::OnDragLeave() {
browser_provider_->GetBrowser()->GetHost()->DragTargetDragLeave();
}
CefBrowserHost::DragOperationsMask
OSRWindow::OnDrop(CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) {
browser_provider_->GetBrowser()->GetHost()->DragTargetDragOver(ev, effect);
browser_provider_->GetBrowser()->GetHost()->DragTargetDrop(ev);
return current_drag_op_;
}
#endif // defined(CEF_USE_ATL)
OSRWindow::OSRWindow(OSRBrowserProvider* browser_provider,
bool transparent,
bool show_update_rect)
: renderer_(transparent, show_update_rect),
browser_provider_(browser_provider),
hWnd_(NULL),
hDC_(NULL),
hRC_(NULL),
#if defined(CEF_USE_ATL)
current_drag_op_(DRAG_OPERATION_NONE),
#endif
painting_popup_(false),
render_task_pending_(false),
hidden_(false) {
}
OSRWindow::~OSRWindow() {
DestroyWidget();
}
void OSRWindow::Render() {
CEF_REQUIRE_UI_THREAD();
if (render_task_pending_)
render_task_pending_ = false;
if (!hDC_)
EnableGL();
ScopedGLContext scoped_gl_context(hDC_, hRC_, true);
renderer_.Render();
}
void OSRWindow::EnableGL() {
CEF_REQUIRE_UI_THREAD();
PIXELFORMATDESCRIPTOR pfd;
int format;
// Get the device context.
hDC_ = GetDC(hWnd_);
// Set the pixel format for the DC.
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
format = ChoosePixelFormat(hDC_, &pfd);
SetPixelFormat(hDC_, format, &pfd);
// Create and enable the render context.
hRC_ = wglCreateContext(hDC_);
ScopedGLContext scoped_gl_context(hDC_, hRC_, false);
renderer_.Initialize();
}
void OSRWindow::DisableGL() {
CEF_REQUIRE_UI_THREAD();
if (!hDC_)
return;
{
ScopedGLContext scoped_gl_context(hDC_, hRC_, false);
renderer_.Cleanup();
}
if (IsWindow(hWnd_)) {
// wglDeleteContext will make the context not current before deleting it.
BOOL result = wglDeleteContext(hRC_);
ALLOW_UNUSED_LOCAL(result);
DCHECK(result);
ReleaseDC(hWnd_, hDC_);
}
hDC_ = NULL;
hRC_ = NULL;
}
void OSRWindow::OnDestroyed() {
SetWindowLongPtr(hWnd_, GWLP_USERDATA, 0L);
hWnd_ = NULL;
Release();
}
ATOM OSRWindow::RegisterOSRClass(HINSTANCE hInstance, LPCTSTR className) {
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_OWNDC;
wcex.lpfnWndProc = &OSRWindow::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = className;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
bool OSRWindow::IsOverPopupWidget(int x, int y) const {
const CefRect& rc = renderer_.popup_rect();
int popup_right = rc.x + rc.width;
int popup_bottom = rc.y + rc.height;
return (x >= rc.x) && (x < popup_right) &&
(y >= rc.y) && (y < popup_bottom);
}
int OSRWindow::GetPopupXOffset() const {
return renderer_.original_popup_rect().x - renderer_.popup_rect().x;
}
int OSRWindow::GetPopupYOffset() const {
return renderer_.original_popup_rect().y - renderer_.popup_rect().y;
}
void OSRWindow::ApplyPopupOffset(int& x, int& y) const {
if (IsOverPopupWidget(x, y)) {
x += GetPopupXOffset();
y += GetPopupYOffset();
}
}
// Plugin window procedure.
// static
LRESULT CALLBACK OSRWindow::WndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam) {
static POINT lastMousePos, curMousePos;
static bool mouseRotation = false;
static bool mouseTracking = false;
static int lastClickX = 0;
static int lastClickY = 0;
static CefBrowserHost::MouseButtonType lastClickButton = MBT_LEFT;
static int gLastClickCount = 0;
static double gLastClickTime = 0;
static bool gLastMouseDownOnView = false;
OSRWindow* window =
reinterpret_cast<OSRWindow*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
CefRefPtr<CefBrowserHost> browser;
if (window && window->browser_provider_->GetBrowser().get())
browser = window->browser_provider_->GetBrowser()->GetHost();
LONG currentTime = 0;
bool cancelPreviousClick = false;
if (message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN ||
message == WM_MBUTTONDOWN || message == WM_MOUSEMOVE ||
message == WM_MOUSELEAVE) {
currentTime = GetMessageTime();
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
cancelPreviousClick =
(abs(lastClickX - x) > (GetSystemMetrics(SM_CXDOUBLECLK) / 2))
|| (abs(lastClickY - y) > (GetSystemMetrics(SM_CYDOUBLECLK) / 2))
|| ((currentTime - gLastClickTime) > GetDoubleClickTime());
if (cancelPreviousClick &&
(message == WM_MOUSEMOVE || message == WM_MOUSELEAVE)) {
gLastClickCount = 0;
lastClickX = 0;
lastClickY = 0;
gLastClickTime = 0;
}
}
switch (message) {
case WM_DESTROY:
if (window)
window->OnDestroyed();
return 0;
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN: {
SetCapture(hWnd);
SetFocus(hWnd);
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
if (wParam & MK_SHIFT) {
// Start rotation effect.
lastMousePos.x = curMousePos.x = x;
lastMousePos.y = curMousePos.y = y;
mouseRotation = true;
} else {
CefBrowserHost::MouseButtonType btnType =
(message == WM_LBUTTONDOWN ? MBT_LEFT : (
message == WM_RBUTTONDOWN ? MBT_RIGHT : MBT_MIDDLE));
if (!cancelPreviousClick && (btnType == lastClickButton)) {
++gLastClickCount;
} else {
gLastClickCount = 1;
lastClickX = x;
lastClickY = y;
}
gLastClickTime = currentTime;
lastClickButton = btnType;
if (browser.get()) {
CefMouseEvent mouse_event;
mouse_event.x = x;
mouse_event.y = y;
gLastMouseDownOnView = !window->IsOverPopupWidget(x, y);
window->ApplyPopupOffset(mouse_event.x, mouse_event.y);
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser->SendMouseClickEvent(mouse_event, btnType, false,
gLastClickCount);
}
}
break;
}
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
if (GetCapture() == hWnd)
ReleaseCapture();
if (mouseRotation) {
// End rotation effect.
mouseRotation = false;
window->renderer_.SetSpin(0, 0);
window->Invalidate();
} else {
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
CefBrowserHost::MouseButtonType btnType =
(message == WM_LBUTTONUP ? MBT_LEFT : (
message == WM_RBUTTONUP ? MBT_RIGHT : MBT_MIDDLE));
if (browser.get()) {
CefMouseEvent mouse_event;
mouse_event.x = x;
mouse_event.y = y;
if (gLastMouseDownOnView &&
window->IsOverPopupWidget(x, y) &&
(window->GetPopupXOffset() || window->GetPopupYOffset())) {
break;
}
window->ApplyPopupOffset(mouse_event.x, mouse_event.y);
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser->SendMouseClickEvent(mouse_event, btnType, true,
gLastClickCount);
}
}
break;
case WM_MOUSEMOVE: {
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
if (mouseRotation) {
// Apply rotation effect.
curMousePos.x = x;
curMousePos.y = y;
window->renderer_.IncrementSpin((curMousePos.x - lastMousePos.x),
(curMousePos.y - lastMousePos.y));
lastMousePos.x = curMousePos.x;
lastMousePos.y = curMousePos.y;
window->Invalidate();
} else {
if (!mouseTracking) {
// Start tracking mouse leave. Required for the WM_MOUSELEAVE event to
// be generated.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hWnd;
TrackMouseEvent(&tme);
mouseTracking = true;
}
if (browser.get()) {
CefMouseEvent mouse_event;
mouse_event.x = x;
mouse_event.y = y;
window->ApplyPopupOffset(mouse_event.x, mouse_event.y);
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser->SendMouseMoveEvent(mouse_event, false);
}
}
break;
}
case WM_MOUSELEAVE:
if (mouseTracking) {
// Stop tracking mouse leave.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE & TME_CANCEL;
tme.hwndTrack = hWnd;
TrackMouseEvent(&tme);
mouseTracking = false;
}
if (browser.get()) {
// Determine the cursor position in screen coordinates.
POINT p;
::GetCursorPos(&p);
::ScreenToClient(hWnd, &p);
CefMouseEvent mouse_event;
mouse_event.x = p.x;
mouse_event.y = p.y;
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser->SendMouseMoveEvent(mouse_event, true);
}
break;
case WM_MOUSEWHEEL:
if (browser.get()) {
POINT screen_point = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
HWND scrolled_wnd = ::WindowFromPoint(screen_point);
if (scrolled_wnd != hWnd) {
break;
}
ScreenToClient(hWnd, &screen_point);
int delta = GET_WHEEL_DELTA_WPARAM(wParam);
CefMouseEvent mouse_event;
mouse_event.x = screen_point.x;
mouse_event.y = screen_point.y;
window->ApplyPopupOffset(mouse_event.x, mouse_event.y);
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser->SendMouseWheelEvent(mouse_event,
IsKeyDown(VK_SHIFT) ? delta : 0,
!IsKeyDown(VK_SHIFT) ? delta : 0);
}
break;
case WM_SIZE:
if (browser.get())
browser->WasResized();
break;
case WM_SETFOCUS:
case WM_KILLFOCUS:
if (browser.get())
browser->SendFocusEvent(message == WM_SETFOCUS);
break;
case WM_CAPTURECHANGED:
case WM_CANCELMODE:
if (!mouseRotation) {
if (browser.get())
browser->SendCaptureLostEvent();
}
break;
case WM_SYSCHAR:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:
case WM_CHAR: {
CefKeyEvent event;
event.windows_key_code = wParam;
event.native_key_code = lParam;
event.is_system_key = message == WM_SYSCHAR ||
message == WM_SYSKEYDOWN ||
message == WM_SYSKEYUP;
if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
event.type = KEYEVENT_RAWKEYDOWN;
else if (message == WM_KEYUP || message == WM_SYSKEYUP)
event.type = KEYEVENT_KEYUP;
else
event.type = KEYEVENT_CHAR;
event.modifiers = GetCefKeyboardModifiers(wParam, lParam);
if (browser.get())
browser->SendKeyEvent(event);
break;
}
case WM_PAINT: {
PAINTSTRUCT ps;
RECT rc;
BeginPaint(hWnd, &ps);
rc = ps.rcPaint;
EndPaint(hWnd, &ps);
if (browser.get())
browser->Invalidate(PET_VIEW);
return 0;
}
case WM_ERASEBKGND:
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
} // namespace client

View File

@ -1,140 +0,0 @@
// Copyright (c) 2011 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_OSR_WIDGET_WIN_H_
#define CEF_TESTS_CEFCLIENT_OSR_WIDGET_WIN_H_
#pragma once
#include "include/cef_render_handler.h"
#include "cefclient/client_handler_shared.h"
#include "cefclient/osr_dragdrop_win.h"
#include "cefclient/osr_renderer.h"
namespace client {
class OSRBrowserProvider {
public:
virtual CefRefPtr<CefBrowser> GetBrowser() =0;
protected:
virtual ~OSRBrowserProvider() {}
};
class OSRWindow : public ClientHandlerShared::RenderHandler
#if defined(CEF_USE_ATL)
, public OsrDragEvents
#endif
{
public:
// Create a new OSRWindow instance. |browser_provider| must outlive this
// object.
static CefRefPtr<OSRWindow> Create(OSRBrowserProvider* browser_provider,
bool transparent,
bool show_update_rect);
static CefRefPtr<OSRWindow> From(
CefRefPtr<ClientHandlerShared::RenderHandler> renderHandler);
// Create the underlying window.
bool CreateWidget(HWND hWndParent, const RECT& rect,
HINSTANCE hInst, LPCTSTR className);
// Destroy the underlying window.
void DestroyWidget();
HWND hwnd() const {
return hWnd_;
}
// ClientHandlerShared::RenderHandler methods
void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
// CefRenderHandler methods
bool GetRootScreenRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) OVERRIDE;
bool GetViewRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) OVERRIDE;
bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
int viewX,
int viewY,
int& screenX,
int& screenY) OVERRIDE;
void OnPopupShow(CefRefPtr<CefBrowser> browser,
bool show) OVERRIDE;
void OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) OVERRIDE;
void OnPaint(CefRefPtr<CefBrowser> browser,
PaintElementType type,
const RectList& dirtyRects,
const void* buffer,
int width,
int height) OVERRIDE;
void OnCursorChange(CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
CursorType type,
const CefCursorInfo& custom_cursor_info) OVERRIDE;
bool StartDragging(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> drag_data,
CefRenderHandler::DragOperationsMask allowed_ops,
int x, int y) OVERRIDE;
void UpdateDragCursor(
CefRefPtr<CefBrowser> browser,
CefRenderHandler::DragOperation operation) OVERRIDE;
#if defined(CEF_USE_ATL)
// OsrDragEvents methods
CefBrowserHost::DragOperationsMask OnDragEnter(
CefRefPtr<CefDragData> drag_data,
CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) OVERRIDE;
CefBrowserHost::DragOperationsMask OnDragOver(CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) OVERRIDE;
void OnDragLeave() OVERRIDE;
CefBrowserHost::DragOperationsMask OnDrop(CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) OVERRIDE;
#endif // defined(CEF_USE_ATL)
void Invalidate();
void WasHidden(bool hidden);
private:
OSRWindow(OSRBrowserProvider* browser_provider,
bool transparent,
bool show_update_rect);
~OSRWindow();
void Render();
void EnableGL();
void DisableGL();
void OnDestroyed();
static ATOM RegisterOSRClass(HINSTANCE hInstance, LPCTSTR className);
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam);
bool IsOverPopupWidget(int x, int y) const;
int GetPopupXOffset() const;
int GetPopupYOffset() const;
void ApplyPopupOffset(int& x, int& y) const;
OsrRenderer renderer_;
OSRBrowserProvider* browser_provider_;
HWND hWnd_;
HDC hDC_;
HGLRC hRC_;
#if defined(CEF_USE_ATL)
CComPtr<DropTargetWin> drop_target_;
CefRenderHandler::DragOperation current_drag_op_;
#endif
bool painting_popup_;
bool render_task_pending_;
bool hidden_;
IMPLEMENT_REFCOUNTING(OSRWindow);
DISALLOW_COPY_AND_ASSIGN(OSRWindow);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_OSR_WIDGET_WIN_H_

View File

@ -0,0 +1,903 @@
// 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/osr_window_win.h"
#include <windowsx.h>
#include "include/base/cef_build.h"
#include "cefclient/main_message_loop.h"
#include "cefclient/resource.h"
#include "cefclient/util_win.h"
namespace client {
namespace {
const wchar_t kWndClass[] = L"Client_OsrWindow";
// Render at 30fps during rotation.
const int kRenderDelay = 1000 / 30;
// Helper that calls wglMakeCurrent.
class ScopedGLContext {
public:
ScopedGLContext(HDC hdc, HGLRC hglrc, bool swap_buffers)
: hdc_(hdc),
swap_buffers_(swap_buffers) {
BOOL result = wglMakeCurrent(hdc, hglrc);
ALLOW_UNUSED_LOCAL(result);
DCHECK(result);
}
~ScopedGLContext() {
BOOL result = wglMakeCurrent(NULL, NULL);
DCHECK(result);
if (swap_buffers_) {
result = SwapBuffers(hdc_);
DCHECK(result);
}
}
private:
const HDC hdc_;
const bool swap_buffers_;
};
} // namespace
OsrWindowWin::OsrWindowWin(Delegate* delegate,
bool transparent,
bool show_update_rect)
: delegate_(delegate),
renderer_(transparent, show_update_rect),
hwnd_(NULL),
hdc_(NULL),
hrc_(NULL),
client_rect_(),
painting_popup_(false),
render_task_pending_(false),
hidden_(false),
last_mouse_pos_(),
current_mouse_pos_(),
mouse_rotation_(false),
mouse_tracking_(false),
last_click_x_(0),
last_click_y_(0),
last_click_button_(MBT_LEFT),
last_click_count_(0),
last_click_time_(0),
last_mouse_down_on_view_(false) {
DCHECK(delegate_);
}
OsrWindowWin::~OsrWindowWin() {
CEF_REQUIRE_UI_THREAD();
// The native window should have already been destroyed.
DCHECK(!hwnd_);
}
void OsrWindowWin::CreateBrowser(HWND parent_hwnd,
const RECT& rect,
CefRefPtr<CefClient> handler,
const CefBrowserSettings& settings,
const std::string& startup_url) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI, base::Bind(&OsrWindowWin::CreateBrowser, this,
parent_hwnd, rect, handler, settings,
startup_url));
return;
}
// Create the native window.
Create(parent_hwnd, rect);
CefWindowInfo window_info;
window_info.SetAsWindowless(hwnd_, renderer_.IsTransparent());
// Create the browser asynchronously.
CefBrowserHost::CreateBrowser(window_info, handler, startup_url, settings,
NULL);
}
void OsrWindowWin::ShowPopup(HWND parent_hwnd,
int x, int y, size_t width, size_t height) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI, base::Bind(&OsrWindowWin::ShowPopup, this,
parent_hwnd, x, y, width, height));
return;
}
DCHECK(browser_.get());
// Create the native window.
const RECT rect = {x, y, x + width, y + height};
Create(parent_hwnd, rect);
// Send resize notification so the compositor is assigned the correct
// viewport size and begins rendering.
browser_->GetHost()->WasResized();
Show();
}
void OsrWindowWin::Show() {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI, base::Bind(&OsrWindowWin::Show, this));
return;
}
if (!browser_)
return;
// Show the native window if not currently visible.
if (hwnd_ && !::IsWindowVisible(hwnd_))
ShowWindow(hwnd_, SW_SHOW);
if (hidden_) {
// Set the browser as visible.
browser_->GetHost()->WasHidden(false);
hidden_ = false;
}
// Give focus to the browser.
browser_->GetHost()->SendFocusEvent(true);
}
void OsrWindowWin::Hide() {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI, base::Bind(&OsrWindowWin::Hide, this));
return;
}
if (!browser_)
return;
// Remove focus from the browser.
browser_->GetHost()->SendFocusEvent(false);
if (!hidden_) {
// Set the browser as hidden.
browser_->GetHost()->WasHidden(true);
hidden_ = true;
}
}
void OsrWindowWin::SetBounds(int x, int y, size_t width, size_t height) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI, base::Bind(&OsrWindowWin::SetBounds, this, x, y, width,
height));
return;
}
if (hwnd_) {
// Set the browser window bounds.
::SetWindowPos(hwnd_, NULL, x, y, width, height, SWP_NOZORDER);
}
}
void OsrWindowWin::SetFocus() {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI, base::Bind(&OsrWindowWin::SetFocus, this));
return;
}
if (hwnd_) {
// Give focus to the native window.
::SetFocus(hwnd_);
}
}
void OsrWindowWin::Create(HWND parent_hwnd, const RECT& rect) {
CEF_REQUIRE_UI_THREAD();
DCHECK(!hwnd_ && !hdc_ && !hrc_);
DCHECK(parent_hwnd);
DCHECK(!::IsRectEmpty(&rect));
HINSTANCE hInst = ::GetModuleHandle(NULL);
RegisterOsrClass(hInst);
// Create the native window with a border so it's easier to visually identify
// OSR windows.
hwnd_ = ::CreateWindow(kWndClass, 0,
WS_BORDER | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE,
rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top,
parent_hwnd, 0, hInst, 0);
CHECK(hwnd_);
client_rect_ = rect;
// Associate |this| with the window.
SetUserDataPtr(hwnd_, this);
#if defined(CEF_USE_ATL)
// Create/register the drag&drop handler.
drop_target_ = DropTargetWin::Create(this, hwnd_);
HRESULT register_res = RegisterDragDrop(hwnd_, drop_target_);
DCHECK_EQ(register_res, S_OK);
#endif
// Notify the window owner.
NotifyNativeWindowCreated(hwnd_);
}
void OsrWindowWin::Destroy() {
CEF_REQUIRE_UI_THREAD();
DCHECK(hwnd_ != NULL);
#if defined(CEF_USE_ATL)
// Revoke/delete the drag&drop handler.
RevokeDragDrop(hwnd_);
drop_target_ = NULL;
#endif
DisableGL();
// Destroy the native window.
::DestroyWindow(hwnd_);
hwnd_ = NULL;
}
void OsrWindowWin::EnableGL() {
CEF_REQUIRE_UI_THREAD();
PIXELFORMATDESCRIPTOR pfd;
int format;
// Get the device context.
hdc_ = GetDC(hwnd_);
// Set the pixel format for the DC.
ZeroMemory(&pfd, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
format = ChoosePixelFormat(hdc_, &pfd);
SetPixelFormat(hdc_, format, &pfd);
// Create and enable the render context.
hrc_ = wglCreateContext(hdc_);
ScopedGLContext scoped_gl_context(hdc_, hrc_, false);
renderer_.Initialize();
}
void OsrWindowWin::DisableGL() {
CEF_REQUIRE_UI_THREAD();
if (!hdc_)
return;
{
ScopedGLContext scoped_gl_context(hdc_, hrc_, false);
renderer_.Cleanup();
}
if (IsWindow(hwnd_)) {
// wglDeleteContext will make the context not current before deleting it.
BOOL result = wglDeleteContext(hrc_);
ALLOW_UNUSED_LOCAL(result);
DCHECK(result);
ReleaseDC(hwnd_, hdc_);
}
hdc_ = NULL;
hrc_ = NULL;
}
void OsrWindowWin::Invalidate() {
CEF_REQUIRE_UI_THREAD();
// Don't post another task if the previous task is still pending.
if (render_task_pending_)
return;
render_task_pending_ = true;
CefPostDelayedTask(TID_UI, base::Bind(&OsrWindowWin::Render, this),
kRenderDelay);
}
void OsrWindowWin::Render() {
CEF_REQUIRE_UI_THREAD();
if (render_task_pending_)
render_task_pending_ = false;
if (!hdc_)
EnableGL();
ScopedGLContext scoped_gl_context(hdc_, hrc_, true);
renderer_.Render();
}
void OsrWindowWin::NotifyNativeWindowCreated(HWND hwnd) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(
base::Bind(&OsrWindowWin::NotifyNativeWindowCreated, this, hwnd));
return;
}
delegate_->OnOsrNativeWindowCreated(hwnd);
}
// static
void OsrWindowWin::RegisterOsrClass(HINSTANCE hInstance) {
// Only register the class one time.
static bool class_registered = false;
if (class_registered)
return;
class_registered = true;
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_OWNDC;
wcex.lpfnWndProc = OsrWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = kWndClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassEx(&wcex);
}
// static
LRESULT CALLBACK OsrWindowWin::OsrWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam) {
CEF_REQUIRE_UI_THREAD();
OsrWindowWin* self = GetUserDataPtr<OsrWindowWin*>(hWnd);
if (!self)
return DefWindowProc(hWnd, message, wParam, lParam);
switch (message) {
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
case WM_MOUSEMOVE:
case WM_MOUSELEAVE:
case WM_MOUSEWHEEL:
if (self)
self->OnMouseEvent(message, wParam, lParam);
break;
case WM_SIZE:
if (self)
self->OnSize();
break;
case WM_SETFOCUS:
case WM_KILLFOCUS:
if (self)
self->OnFocus(message == WM_SETFOCUS);
break;
case WM_CAPTURECHANGED:
case WM_CANCELMODE:
if (self)
self->OnCaptureLost();
break;
case WM_SYSCHAR:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
case WM_KEYDOWN:
case WM_KEYUP:
case WM_CHAR:
if (self)
self->OnKeyEvent(message, wParam, lParam);
break;
case WM_PAINT:
if (self)
self->OnPaint();
return 0;
case WM_ERASEBKGND:
// Never erase the background.
return 0;
case WM_NCDESTROY:
// Clear the reference to |self|.
SetUserDataPtr(hWnd, NULL);
self->hwnd_ = NULL;
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
void OsrWindowWin::OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam) {
CefRefPtr<CefBrowserHost> browser_host;
if (browser_)
browser_host = browser_->GetHost();
LONG currentTime = 0;
bool cancelPreviousClick = false;
if (message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN ||
message == WM_MBUTTONDOWN || message == WM_MOUSEMOVE ||
message == WM_MOUSELEAVE) {
currentTime = GetMessageTime();
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
cancelPreviousClick =
(abs(last_click_x_ - x) > (GetSystemMetrics(SM_CXDOUBLECLK) / 2))
|| (abs(last_click_y_ - y) > (GetSystemMetrics(SM_CYDOUBLECLK) / 2))
|| ((currentTime - last_click_time_) > GetDoubleClickTime());
if (cancelPreviousClick &&
(message == WM_MOUSEMOVE || message == WM_MOUSELEAVE)) {
last_click_count_ = 0;
last_click_x_ = 0;
last_click_y_ = 0;
last_click_time_ = 0;
}
}
switch(message) {
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN: {
::SetCapture(hwnd_);
::SetFocus(hwnd_);
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
if (wParam & MK_SHIFT) {
// Start rotation effect.
last_mouse_pos_.x = current_mouse_pos_.x = x;
last_mouse_pos_.y = current_mouse_pos_.y = y;
mouse_rotation_ = true;
} else {
CefBrowserHost::MouseButtonType btnType =
(message == WM_LBUTTONDOWN ? MBT_LEFT : (
message == WM_RBUTTONDOWN ? MBT_RIGHT : MBT_MIDDLE));
if (!cancelPreviousClick && (btnType == last_click_button_)) {
++last_click_count_;
} else {
last_click_count_ = 1;
last_click_x_ = x;
last_click_y_ = y;
}
last_click_time_ = currentTime;
last_click_button_ = btnType;
CefRefPtr<CefBrowserHost> browser_host = browser_->GetHost();
if (browser_host) {
CefMouseEvent mouse_event;
mouse_event.x = x;
mouse_event.y = y;
last_mouse_down_on_view_ = !IsOverPopupWidget(x, y);
ApplyPopupOffset(mouse_event.x, mouse_event.y);
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser_host->SendMouseClickEvent(mouse_event, btnType, false,
last_click_count_);
}
}
} break;
case WM_LBUTTONUP:
case WM_RBUTTONUP:
case WM_MBUTTONUP:
if (GetCapture() == hwnd_)
ReleaseCapture();
if (mouse_rotation_) {
// End rotation effect.
mouse_rotation_ = false;
renderer_.SetSpin(0, 0);
Invalidate();
} else {
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
CefBrowserHost::MouseButtonType btnType =
(message == WM_LBUTTONUP ? MBT_LEFT : (
message == WM_RBUTTONUP ? MBT_RIGHT : MBT_MIDDLE));
if (browser_host) {
CefMouseEvent mouse_event;
mouse_event.x = x;
mouse_event.y = y;
if (last_mouse_down_on_view_ &&
IsOverPopupWidget(x, y) &&
(GetPopupXOffset() || GetPopupYOffset())) {
break;
}
ApplyPopupOffset(mouse_event.x, mouse_event.y);
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser_host->SendMouseClickEvent(mouse_event, btnType, true,
last_click_count_);
}
}
break;
case WM_MOUSEMOVE: {
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
if (mouse_rotation_) {
// Apply rotation effect.
current_mouse_pos_.x = x;
current_mouse_pos_.y = y;
renderer_.IncrementSpin(
current_mouse_pos_.x - last_mouse_pos_.x,
current_mouse_pos_.y - last_mouse_pos_.y);
last_mouse_pos_.x = current_mouse_pos_.x;
last_mouse_pos_.y = current_mouse_pos_.y;
Invalidate();
} else {
if (!mouse_tracking_) {
// Start tracking mouse leave. Required for the WM_MOUSELEAVE event to
// be generated.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = hwnd_;
TrackMouseEvent(&tme);
mouse_tracking_ = true;
}
if (browser_host) {
CefMouseEvent mouse_event;
mouse_event.x = x;
mouse_event.y = y;
ApplyPopupOffset(mouse_event.x, mouse_event.y);
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser_host->SendMouseMoveEvent(mouse_event, false);
}
}
break;
}
case WM_MOUSELEAVE: {
if (mouse_tracking_) {
// Stop tracking mouse leave.
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE & TME_CANCEL;
tme.hwndTrack = hwnd_;
TrackMouseEvent(&tme);
mouse_tracking_ = false;
}
if (browser_host) {
// Determine the cursor position in screen coordinates.
POINT p;
::GetCursorPos(&p);
::ScreenToClient(hwnd_, &p);
CefMouseEvent mouse_event;
mouse_event.x = p.x;
mouse_event.y = p.y;
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser_host->SendMouseMoveEvent(mouse_event, true);
}
} break;
case WM_MOUSEWHEEL:
if (browser_host) {
POINT screen_point = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
HWND scrolled_wnd = ::WindowFromPoint(screen_point);
if (scrolled_wnd != hwnd_)
break;
ScreenToClient(hwnd_, &screen_point);
int delta = GET_WHEEL_DELTA_WPARAM(wParam);
CefMouseEvent mouse_event;
mouse_event.x = screen_point.x;
mouse_event.y = screen_point.y;
ApplyPopupOffset(mouse_event.x, mouse_event.y);
mouse_event.modifiers = GetCefMouseModifiers(wParam);
browser_host->SendMouseWheelEvent(mouse_event,
IsKeyDown(VK_SHIFT) ? delta : 0,
!IsKeyDown(VK_SHIFT) ? delta : 0);
}
break;
}
}
void OsrWindowWin::OnSize() {
// Keep |client_rect_| up to date.
::GetClientRect(hwnd_, &client_rect_);
if (browser_)
browser_->GetHost()->WasResized();
}
void OsrWindowWin::OnFocus(bool setFocus) {
if (browser_)
browser_->GetHost()->SendFocusEvent(setFocus);
}
void OsrWindowWin::OnCaptureLost() {
if (mouse_rotation_)
return;
if (browser_)
browser_->GetHost()->SendCaptureLostEvent();
}
void OsrWindowWin::OnKeyEvent(UINT message, WPARAM wParam, LPARAM lParam) {
if (!browser_)
return;
CefKeyEvent event;
event.windows_key_code = wParam;
event.native_key_code = lParam;
event.is_system_key = message == WM_SYSCHAR ||
message == WM_SYSKEYDOWN ||
message == WM_SYSKEYUP;
if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
event.type = KEYEVENT_RAWKEYDOWN;
else if (message == WM_KEYUP || message == WM_SYSKEYUP)
event.type = KEYEVENT_KEYUP;
else
event.type = KEYEVENT_CHAR;
event.modifiers = GetCefKeyboardModifiers(wParam, lParam);
browser_->GetHost()->SendKeyEvent(event);
}
void OsrWindowWin::OnPaint() {
// Paint nothing here. Invalidate will cause OnPaint to be called for the
// render handler.
PAINTSTRUCT ps;
BeginPaint(hwnd_, &ps);
EndPaint(hwnd_, &ps);
if (browser_)
browser_->GetHost()->Invalidate(PET_VIEW);
}
bool OsrWindowWin::IsOverPopupWidget(int x, int y) const {
CEF_REQUIRE_UI_THREAD();
const CefRect& rc = renderer_.popup_rect();
int popup_right = rc.x + rc.width;
int popup_bottom = rc.y + rc.height;
return (x >= rc.x) && (x < popup_right) &&
(y >= rc.y) && (y < popup_bottom);
}
int OsrWindowWin::GetPopupXOffset() const {
CEF_REQUIRE_UI_THREAD();
return renderer_.original_popup_rect().x - renderer_.popup_rect().x;
}
int OsrWindowWin::GetPopupYOffset() const {
CEF_REQUIRE_UI_THREAD();
return renderer_.original_popup_rect().y - renderer_.popup_rect().y;
}
void OsrWindowWin::ApplyPopupOffset(int& x, int& y) const {
if (IsOverPopupWidget(x, y)) {
x += GetPopupXOffset();
y += GetPopupYOffset();
}
}
void OsrWindowWin::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
DCHECK(!browser_);
browser_ = browser;
if (hwnd_) {
// Show the browser window. Called asynchronously so that the browser has
// time to create associated internal objects.
CefPostTask(TID_UI, base::Bind(&OsrWindowWin::Show, this));
}
}
void OsrWindowWin::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
// Detach |this| from the ClientHandler.
static_cast<ClientHandlerOsr*>(browser_->GetHost()->GetClient().get())->
DetachOsrDelegate();
browser_ = NULL;
Destroy();
}
bool OsrWindowWin::GetRootScreenRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) {
CEF_REQUIRE_UI_THREAD();
RECT window_rect = {0};
HWND root_window = GetAncestor(hwnd_, GA_ROOT);
if (::GetWindowRect(root_window, &window_rect)) {
rect = CefRect(window_rect.left,
window_rect.top,
window_rect.right - window_rect.left,
window_rect.bottom - window_rect.top);
return true;
}
return false;
}
bool OsrWindowWin::GetViewRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) {
CEF_REQUIRE_UI_THREAD();
rect.x = rect.y = 0;
rect.width = client_rect_.right - client_rect_.left;
rect.height = client_rect_.bottom - client_rect_.top;
return true;
}
bool OsrWindowWin::GetScreenPoint(CefRefPtr<CefBrowser> browser,
int viewX,
int viewY,
int& screenX,
int& screenY) {
CEF_REQUIRE_UI_THREAD();
if (!::IsWindow(hwnd_))
return false;
// Convert the point from view coordinates to actual screen coordinates.
POINT screen_pt = {viewX, viewY};
ClientToScreen(hwnd_, &screen_pt);
screenX = screen_pt.x;
screenY = screen_pt.y;
return true;
}
bool OsrWindowWin::GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) {
CEF_REQUIRE_UI_THREAD();
return false;
}
void OsrWindowWin::OnPopupShow(CefRefPtr<CefBrowser> browser,
bool show) {
CEF_REQUIRE_UI_THREAD();
if (!show) {
renderer_.ClearPopupRects();
browser->GetHost()->Invalidate(PET_VIEW);
}
renderer_.OnPopupShow(browser, show);
}
void OsrWindowWin::OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) {
CEF_REQUIRE_UI_THREAD();
renderer_.OnPopupSize(browser, rect);
}
void OsrWindowWin::OnPaint(CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList& dirtyRects,
const void* buffer,
int width,
int height) {
CEF_REQUIRE_UI_THREAD();
if (painting_popup_) {
renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
return;
}
if (!hdc_)
EnableGL();
ScopedGLContext scoped_gl_context(hdc_, hrc_, true);
renderer_.OnPaint(browser, type, dirtyRects, buffer, width, height);
if (type == PET_VIEW && !renderer_.popup_rect().IsEmpty()) {
painting_popup_ = true;
browser->GetHost()->Invalidate(PET_POPUP);
painting_popup_ = false;
}
renderer_.Render();
}
void OsrWindowWin::OnCursorChange(
CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
CefRenderHandler::CursorType type,
const CefCursorInfo& custom_cursor_info) {
CEF_REQUIRE_UI_THREAD();
if (!::IsWindow(hwnd_))
return;
// Change the plugin window's cursor.
SetClassLongPtr(hwnd_, GCLP_HCURSOR,
static_cast<LONG>(reinterpret_cast<LONG_PTR>(cursor)));
SetCursor(cursor);
}
bool OsrWindowWin::StartDragging(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> drag_data,
CefRenderHandler::DragOperationsMask allowed_ops,
int x, int y) {
CEF_REQUIRE_UI_THREAD();
#if defined(CEF_USE_ATL)
if (!drop_target_)
return false;
current_drag_op_ = DRAG_OPERATION_NONE;
CefBrowserHost::DragOperationsMask result =
drop_target_->StartDragging(browser, drag_data, allowed_ops, x, y);
current_drag_op_ = DRAG_OPERATION_NONE;
POINT pt = {};
GetCursorPos(&pt);
ScreenToClient(hwnd_, &pt);
browser->GetHost()->DragSourceEndedAt(pt.x, pt.y, result);
browser->GetHost()->DragSourceSystemDragEnded();
return true;
#else
// Cancel the drag. The dragging implementation requires ATL support.
return false;
#endif
}
void OsrWindowWin::UpdateDragCursor(
CefRefPtr<CefBrowser> browser,
CefRenderHandler::DragOperation operation) {
CEF_REQUIRE_UI_THREAD();
#if defined(CEF_USE_ATL)
current_drag_op_ = operation;
#endif
}
#if defined(CEF_USE_ATL)
CefBrowserHost::DragOperationsMask
OsrWindowWin::OnDragEnter(CefRefPtr<CefDragData> drag_data,
CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) {
if (browser_) {
browser_->GetHost()->DragTargetDragEnter(drag_data, ev, effect);
browser_->GetHost()->DragTargetDragOver(ev, effect);
}
return current_drag_op_;
}
CefBrowserHost::DragOperationsMask
OsrWindowWin::OnDragOver(CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) {
if (browser_)
browser_->GetHost()->DragTargetDragOver(ev, effect);
return current_drag_op_;
}
void OsrWindowWin::OnDragLeave() {
if (browser_)
browser_->GetHost()->DragTargetDragLeave();
}
CefBrowserHost::DragOperationsMask
OsrWindowWin::OnDrop(CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) {
if (browser_) {
browser_->GetHost()->DragTargetDragOver(ev, effect);
browser_->GetHost()->DragTargetDrop(ev);
}
return current_drag_op_;
}
#endif // defined(CEF_USE_ATL)
} // namespace client

View File

@ -0,0 +1,185 @@
// 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_OSR_WINDOW_WIN_H_
#define CEF_TESTS_CEFCLIENT_OSR_WINDOW_WIN_H_
#include "include/base/cef_bind.h"
#include "include/base/cef_ref_counted.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
#include "cefclient/client_handler_osr.h"
#include "cefclient/osr_dragdrop_win.h"
#include "cefclient/osr_renderer.h"
namespace client {
// Represents the native parent window for an off-screen browser. This object
// must live on the CEF UI thread in order to handle CefRenderHandler callbacks.
// The methods of this class are thread-safe unless otherwise indicated.
class OsrWindowWin :
public base::RefCountedThreadSafe<OsrWindowWin, CefDeleteOnUIThread>,
public ClientHandlerOsr::OsrDelegate
#if defined(CEF_USE_ATL)
, public OsrDragEvents
#endif
{
public:
// This interface is implemented by the owner of the OsrWindowWin. The
// methods of this class will be called on the main thread.
class Delegate {
public:
// Called after the native window has been created.
virtual void OnOsrNativeWindowCreated(HWND hwnd) = 0;
protected:
virtual ~Delegate() {}
};
// |delegate| must outlive this object.
OsrWindowWin(Delegate* delegate,
bool transparent,
bool show_update_rect);
// Create a new browser and native window.
void CreateBrowser(HWND parent_hwnd,
const RECT& rect,
CefRefPtr<CefClient> handler,
const CefBrowserSettings& settings,
const std::string& startup_url);
// Show the popup window with correct parent and bounds in parent coordinates.
void ShowPopup(HWND parent_hwnd, int x, int y, size_t width, size_t height);
void Show();
void Hide();
void SetBounds(int x, int y, size_t width, size_t height);
void SetFocus();
private:
// Only allow deletion via scoped_refptr.
friend struct CefDeleteOnThread<TID_UI>;
friend class base::RefCountedThreadSafe<OsrWindowWin, CefDeleteOnUIThread>;
~OsrWindowWin();
// Manage native window lifespan.
void Create(HWND parent_hwnd, const RECT& rect);
void Destroy();
// Manage GL context lifespan.
void EnableGL();
void DisableGL();
// Redraw what is currently in the texture.
void Invalidate();
void Render();
void NotifyNativeWindowCreated(HWND hwnd);
static void RegisterOsrClass(HINSTANCE hInstance);
static LRESULT CALLBACK OsrWndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam);
// WndProc message handlers.
void OnMouseEvent(UINT message, WPARAM wParam, LPARAM lParam);
void OnSize();
void OnFocus(bool setFocus);
void OnCaptureLost();
void OnKeyEvent(UINT message, WPARAM wParam, LPARAM lParam);
void OnPaint();
// Manage popup bounds.
bool IsOverPopupWidget(int x, int y) const;
int GetPopupXOffset() const;
int GetPopupYOffset() const;
void ApplyPopupOffset(int& x, int& y) const;
// ClientHandlerOsr::Delegate methods.
void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
bool GetRootScreenRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) OVERRIDE;
bool GetViewRect(CefRefPtr<CefBrowser> browser,
CefRect& rect) OVERRIDE;
bool GetScreenPoint(CefRefPtr<CefBrowser> browser,
int viewX,
int viewY,
int& screenX,
int& screenY) OVERRIDE;
bool GetScreenInfo(CefRefPtr<CefBrowser> browser,
CefScreenInfo& screen_info) OVERRIDE;
void OnPopupShow(CefRefPtr<CefBrowser> browser, bool show) OVERRIDE;
void OnPopupSize(CefRefPtr<CefBrowser> browser,
const CefRect& rect) OVERRIDE;
void OnPaint(CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList& dirtyRects,
const void* buffer,
int width,
int height) OVERRIDE;
void OnCursorChange(CefRefPtr<CefBrowser> browser,
CefCursorHandle cursor,
CefRenderHandler::CursorType type,
const CefCursorInfo& custom_cursor_info) OVERRIDE;
bool StartDragging(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> drag_data,
CefRenderHandler::DragOperationsMask allowed_ops,
int x, int y) OVERRIDE;
void UpdateDragCursor(CefRefPtr<CefBrowser> browser,
CefRenderHandler::DragOperation operation) OVERRIDE;
#if defined(CEF_USE_ATL)
// OsrDragEvents methods.
CefBrowserHost::DragOperationsMask OnDragEnter(
CefRefPtr<CefDragData> drag_data,
CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) OVERRIDE;
CefBrowserHost::DragOperationsMask OnDragOver(CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) OVERRIDE;
void OnDragLeave() OVERRIDE;
CefBrowserHost::DragOperationsMask OnDrop(CefMouseEvent ev,
CefBrowserHost::DragOperationsMask effect) OVERRIDE;
#endif // defined(CEF_USE_ATL)
// Only accessed on the main thread.
Delegate* delegate_;
// The below members are only accessed on the UI thread.
OsrRenderer renderer_;
HWND hwnd_;
HDC hdc_;
HGLRC hrc_;
RECT client_rect_;
CefRefPtr<CefBrowser> browser_;
#if defined(CEF_USE_ATL)
CComPtr<DropTargetWin> drop_target_;
CefRenderHandler::DragOperation current_drag_op_;
#endif
bool painting_popup_;
bool render_task_pending_;
bool hidden_;
// Mouse state tracking.
POINT last_mouse_pos_;
POINT current_mouse_pos_;
bool mouse_rotation_;
bool mouse_tracking_;
int last_click_x_;
int last_click_y_;
CefBrowserHost::MouseButtonType last_click_button_;
int last_click_count_;
double last_click_time_;
bool last_mouse_down_on_view_;
DISALLOW_COPY_AND_ASSIGN(OsrWindowWin);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_OSR_WINDOW_WIN_H_

View File

@ -0,0 +1,105 @@
// 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_ROOT_WINDOW_H_
#define CEF_TESTS_CEFCLIENT_ROOT_WINDOW_H_
#include <string>
#include "include/base/cef_ref_counted.h"
#include "include/cef_browser.h"
#include "cefclient/main_message_loop.h"
namespace client {
// Represents a top-level native window in the browser process. While references
// to this object are thread-safe the methods must be called on the main thread
// unless otherwise indicated.
class RootWindow :
public base::RefCountedThreadSafe<RootWindow, DeleteOnMainThread> {
public:
// This interface is implemented by the owner of the RootWindow. The methods
// of this class will be called on the main thread.
class Delegate {
public:
// Called to execute a test. See resource.h for |test_id| values.
virtual void OnTest(RootWindow* root_window, int test_id) = 0;
// Called to exit the application.
virtual void OnExit(RootWindow* root_window) = 0;
// Called when the RootWindow has been destroyed.
virtual void OnRootWindowDestroyed(RootWindow* root_window) = 0;
protected:
virtual ~Delegate() {}
};
// Create a new RootWindow object. This method may be called on any thread.
// Use RootWindowManager::CreateRootWindow() or CreateRootWindowAsPopup()
// instead of calling this method directly.
static scoped_refptr<RootWindow> Create();
// Initialize as a normal window. This will create and show a browser window.
// This method may be called on any thread.
// |delegate| must be non-NULL and outlive this object.
// Use RootWindowManager::CreateRootWindow() instead of calling this method
// directly.
virtual void Init(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefRect& bounds,
const CefBrowserSettings& settings,
const std::string& url) = 0;
// Initialize as a popup window. This is used to attach a browser window that
// will be created later. The window will be shown once the browser is
// available. This method may be called on any thread.
// |delegate| must be non-NULL and outlive this object.
// Use RootWindowManager::CreateRootWindowAsPopup() instead of calling this
// method directly.
virtual void InitAsPopup(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) = 0;
enum ShowMode {
ShowNormal,
ShowMinimized,
ShowMaximized,
};
// Show the window.
virtual void Show(ShowMode mode) = 0;
// Hide the window.
virtual void Hide() = 0;
// Set the window bounds in screen coordinates.
virtual void SetBounds(int x, int y, size_t width, size_t height) = 0;
// Close the window. If |force| is true onunload handlers will not be
// executed.
virtual void Close(bool force) = 0;
// Returns the browser that this window contains, if any.
virtual CefRefPtr<CefBrowser> GetBrowser() const = 0;
// Returns the handle for this window, if any.
virtual CefWindowHandle GetWindowHandle() const = 0;
protected:
// Allow deletion via scoped_refptr only.
friend struct DeleteOnMainThread;
friend class base::RefCountedThreadSafe<RootWindow, DeleteOnMainThread>;
virtual ~RootWindow() {}
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_ROOT_WINDOW_H_

View File

@ -0,0 +1,129 @@
// 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/root_window_manager.h"
#include "include/base/cef_bind.h"
#include "include/wrapper/cef_helpers.h"
#include "cefclient/main_context.h"
#include "cefclient/test_runner.h"
namespace client {
RootWindowManager::RootWindowManager(bool terminate_when_all_windows_closed)
: terminate_when_all_windows_closed_(terminate_when_all_windows_closed) {
}
RootWindowManager::~RootWindowManager() {
// All root windows should already have been destroyed.
DCHECK(root_windows_.empty());
}
scoped_refptr<RootWindow> RootWindowManager::CreateRootWindow(
bool with_controls,
bool with_osr,
const CefRect& bounds,
const std::string& url) {
CefBrowserSettings settings;
MainContext::Get()->PopulateBrowserSettings(&settings);
scoped_refptr<RootWindow> root_window = RootWindow::Create();
root_window->Init(this, with_controls, with_osr, bounds, settings,
url.empty() ? MainContext::Get()->GetMainURL() : url);
// Store a reference to the root window on the main thread.
OnRootWindowCreated(root_window);
return root_window;
}
scoped_refptr<RootWindow> RootWindowManager::CreateRootWindowAsPopup(
bool with_controls,
bool with_osr,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) {
MainContext::Get()->PopulateBrowserSettings(&settings);
scoped_refptr<RootWindow> root_window = RootWindow::Create();
root_window->InitAsPopup(this, with_controls, with_osr,
popupFeatures, windowInfo, client, settings);
// Store a reference to the root window on the main thread.
OnRootWindowCreated(root_window);
return root_window;
}
scoped_refptr<RootWindow> RootWindowManager::GetWindowForBrowser(
int browser_id) {
REQUIRE_MAIN_THREAD();
RootWindowSet::const_iterator it = root_windows_.begin();
for (; it != root_windows_.end(); ++it) {
CefRefPtr<CefBrowser> browser = (*it)->GetBrowser();
if (browser.get() && browser->GetIdentifier() == browser_id)
return *it;
}
return NULL;
}
void RootWindowManager::CloseAllWindows(bool force) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(
base::Bind(&RootWindowManager::CloseAllWindows, base::Unretained(this),
force));
return;
}
if (root_windows_.empty())
return;
RootWindowSet::const_iterator it = root_windows_.begin();
for (; it != root_windows_.end(); ++it)
(*it)->Close(force);
}
void RootWindowManager::OnRootWindowCreated(
scoped_refptr<RootWindow> root_window) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(
base::Bind(&RootWindowManager::OnRootWindowCreated,
base::Unretained(this), root_window));
return;
}
root_windows_.insert(root_window);
}
void RootWindowManager::OnTest(RootWindow* root_window, int test_id) {
REQUIRE_MAIN_THREAD();
test_runner::RunTest(root_window->GetBrowser(), test_id);
}
void RootWindowManager::OnExit(RootWindow* root_window) {
REQUIRE_MAIN_THREAD();
CloseAllWindows(false);
}
void RootWindowManager::OnRootWindowDestroyed(RootWindow* root_window) {
REQUIRE_MAIN_THREAD();
RootWindowSet::iterator it = root_windows_.find(root_window);
DCHECK(it != root_windows_.end());
if (it != root_windows_.end())
root_windows_.erase(it);
if (terminate_when_all_windows_closed_ && root_windows_.empty()) {
// Quit the main message loop after all windows have closed.
MainMessageLoop::Get()->Quit();
}
}
} // namespace client

View File

@ -0,0 +1,89 @@
// 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_ROOT_WINDOW_MANAGER_H_
#define CEF_TESTS_CEFCLIENT_ROOT_WINDOW_MANAGER_H_
#include <set>
#include "include/base/cef_scoped_ptr.h"
#include "include/cef_command_line.h"
#include "cefclient/root_window.h"
#if defined(OS_WIN)
#include "cefclient/temp_window_win.h"
#endif
namespace client {
// Used to create/manage RootWindow instances. The methods of this class can be
// called from any browser process thread unless otherwise indicated.
class RootWindowManager : public RootWindow::Delegate {
public:
// If |terminate_when_all_windows_closed| is true quit the main message loop
// after all windows have closed.
explicit RootWindowManager(bool terminate_when_all_windows_closed);
// Create a new top-level native window that loads |url|.
// If |with_controls| is true the window will show controls.
// If |with_osr| is true the window will use off-screen rendering.
// If |bounds| is empty the default window size will be used.
// This method can be called from anywhere to create a new top-level window.
scoped_refptr<RootWindow> CreateRootWindow(
bool with_controls,
bool with_osr,
const CefRect& bounds,
const std::string& url);
// Create a new native popup window.
// If |with_controls| is true the window will show controls.
// If |with_osr| is true the window will use off-screen rendering.
// This method is called from ClientHandlerSingle::CreatePopupWindow() to
// create a new popup or DevTools window.
scoped_refptr<RootWindow> CreateRootWindowAsPopup(
bool with_controls,
bool with_osr,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings);
// Returns the RootWindow associated with the specified browser ID. Must be
// called on the main thread.
scoped_refptr<RootWindow> GetWindowForBrowser(int browser_id);
// Close all existing windows. If |force| is true onunload handlers will not
// be executed.
void CloseAllWindows(bool force);
private:
// Allow deletion via scoped_ptr only.
friend struct base::DefaultDeleter<RootWindowManager>;
~RootWindowManager();
void OnRootWindowCreated(scoped_refptr<RootWindow> root_window);
// RootWindow::Delegate methods.
void OnTest(RootWindow* root_window, int test_id) OVERRIDE;
void OnExit(RootWindow* root_window) OVERRIDE;
void OnRootWindowDestroyed(RootWindow* root_window) OVERRIDE;
const bool terminate_when_all_windows_closed_;
// Existing root windows. Only accessed on the main thread.
typedef std::set<scoped_refptr<RootWindow> > RootWindowSet;
RootWindowSet root_windows_;
#if defined(OS_WIN)
// Singleton window used as the temporary parent for popup browsers.
TempWindowWin temp_window_win_;
#endif
DISALLOW_COPY_AND_ASSIGN(RootWindowManager);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_ROOT_WINDOW_MANAGER_H_

View File

@ -0,0 +1,750 @@
// 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/root_window_win.h"
#include "include/base/cef_bind.h"
#include "include/cef_app.h"
#include "cefclient/browser_window_osr_win.h"
#include "cefclient/browser_window_std_win.h"
#include "cefclient/client_switches.h"
#include "cefclient/main_message_loop.h"
#include "cefclient/resource.h"
#include "cefclient/temp_window_win.h"
#include "cefclient/util_win.h"
#define MAX_URL_LENGTH 255
#define BUTTON_WIDTH 72
#define URLBAR_HEIGHT 24
namespace client {
namespace {
// Message handler for the About box.
INT_PTR CALLBACK AboutWndProc(HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam) {
UNREFERENCED_PARAMETER(lParam);
switch (message) {
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
} // namespace
RootWindowWin::RootWindowWin()
: delegate_(NULL),
with_controls_(false),
is_popup_(false),
start_rect_(),
initialized_(false),
hwnd_(NULL),
back_hwnd_(NULL),
forward_hwnd_(NULL),
reload_hwnd_(NULL),
stop_hwnd_(NULL),
edit_hwnd_(NULL),
edit_wndproc_old_(NULL),
find_hwnd_(NULL),
find_message_id_(0),
find_wndproc_old_(NULL),
find_state_(),
find_buff_(),
find_next_(false),
find_match_case_last_(false),
window_destroyed_(false),
browser_destroyed_(false) {
}
RootWindowWin::~RootWindowWin() {
REQUIRE_MAIN_THREAD();
// The window and browser should already have been destroyed.
DCHECK(window_destroyed_);
DCHECK(browser_destroyed_);
}
void RootWindowWin::Init(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefRect& bounds,
const CefBrowserSettings& settings,
const std::string& url) {
DCHECK(delegate);
DCHECK(!initialized_);
delegate_ = delegate;
with_controls_ = with_controls;
start_rect_.left = bounds.x;
start_rect_.top = bounds.y;
start_rect_.right = bounds.x + bounds.width;
start_rect_.bottom = bounds.y + bounds.height;
CreateBrowserWindow(with_osr, url);
initialized_ = true;
// Create the native root window on the main thread.
if (CURRENTLY_ON_MAIN_THREAD()) {
CreateRootWindow(settings);
} else {
MAIN_POST_CLOSURE(
base::Bind(&RootWindowWin::CreateRootWindow, this, settings));
}
}
void RootWindowWin::InitAsPopup(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) {
DCHECK(delegate);
DCHECK(!initialized_);
delegate_ = delegate;
with_controls_ = with_controls;
is_popup_ = true;
if (popupFeatures.xSet)
start_rect_.left = popupFeatures.x;
if (popupFeatures.ySet)
start_rect_.top = popupFeatures.y;
if (popupFeatures.widthSet)
start_rect_.right = start_rect_.left + popupFeatures.width;
if (popupFeatures.heightSet)
start_rect_.bottom = start_rect_.top + popupFeatures.height;
CreateBrowserWindow(with_osr, std::string());
initialized_ = true;
// The new popup is initially parented to a temporary window. The native root
// window will be created after the browser is created and the popup window
// will be re-parented to it at that time.
browser_window_->GetPopupConfig(TempWindowWin::GetHWND(),
windowInfo, client, settings);
}
void RootWindowWin::Show(ShowMode mode) {
REQUIRE_MAIN_THREAD();
if (!hwnd_)
return;
int nCmdShow = SW_SHOWNORMAL;
switch (mode) {
case ShowMinimized:
nCmdShow = SW_SHOWNORMAL;
break;
case ShowMaximized:
nCmdShow = SW_SHOWNORMAL;
break;
default:
break;
}
ShowWindow(hwnd_, nCmdShow);
UpdateWindow(hwnd_);
}
void RootWindowWin::Hide() {
REQUIRE_MAIN_THREAD();
if (hwnd_)
ShowWindow(hwnd_, SW_HIDE);
}
void RootWindowWin::SetBounds(int x, int y, size_t width, size_t height) {
REQUIRE_MAIN_THREAD();
if (hwnd_)
SetWindowPos(hwnd_, NULL, 0, 0, 0, 0, SWP_NOZORDER);
}
void RootWindowWin::Close(bool force) {
REQUIRE_MAIN_THREAD();
if (hwnd_) {
if (force)
DestroyWindow(hwnd_);
else
PostMessage(hwnd_, WM_CLOSE, 0, 0);
}
}
CefRefPtr<CefBrowser> RootWindowWin::GetBrowser() const {
REQUIRE_MAIN_THREAD();
if (browser_window_)
return browser_window_->GetBrowser();
return NULL;
}
CefWindowHandle RootWindowWin::GetWindowHandle() const {
REQUIRE_MAIN_THREAD();
return hwnd_;
}
void RootWindowWin::CreateBrowserWindow(bool with_osr,
const std::string& startup_url) {
if (with_osr) {
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
const bool transparent =
command_line->HasSwitch(switches::kTransparentPaintingEnabled);
const bool show_update_rect =
command_line->HasSwitch(switches::kShowUpdateRect);
browser_window_.reset(new BrowserWindowOsrWin(this, startup_url,
transparent,
show_update_rect));
} else {
browser_window_.reset(new BrowserWindowStdWin(this, startup_url));
}
}
void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings) {
REQUIRE_MAIN_THREAD();
DCHECK(!hwnd_);
HINSTANCE hInstance = GetModuleHandle(NULL);
// Load strings from the resource file.
const std::wstring& window_title = GetResourceString(IDS_APP_TITLE);
const std::wstring& window_class = GetResourceString(IDC_CEFCLIENT);
// Register the window class.
RegisterRootClass(hInstance, window_class);
// Register the message used with the find dialog.
find_message_id_ = RegisterWindowMessage(FINDMSGSTRING);
CHECK(find_message_id_);
const DWORD dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
int x, y, width, height;
if (::IsRectEmpty(&start_rect_)) {
// Use the default window position/size.
x = y = width = height = CW_USEDEFAULT;
} else {
// Adjust the window size to account for window frame and controls.
RECT window_rect = start_rect_;
::AdjustWindowRectEx(&window_rect, dwStyle, with_controls_, 0);
if (with_controls_)
window_rect.bottom += URLBAR_HEIGHT;
x = start_rect_.left;
y = start_rect_.top;
width = window_rect.right - window_rect.left;
height = window_rect.bottom - window_rect.top;
}
// Create the main window initially hidden.
hwnd_ = CreateWindow(window_class.c_str(), window_title.c_str(),
dwStyle,
x, y, width, height,
NULL, NULL, hInstance, NULL);
CHECK(hwnd_);
// Associate |this| with the main window.
SetUserDataPtr(hwnd_, this);
RECT rect;
GetClientRect(hwnd_, &rect);
if (with_controls_) {
// Create the child controls.
int x = 0;
back_hwnd_ = CreateWindow(
L"BUTTON", L"Back",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
x, 0, BUTTON_WIDTH, URLBAR_HEIGHT,
hwnd_, reinterpret_cast<HMENU>(IDC_NAV_BACK), hInstance, 0);
CHECK(back_hwnd_);
x += BUTTON_WIDTH;
forward_hwnd_ = CreateWindow(
L"BUTTON", L"Forward",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
x, 0, BUTTON_WIDTH, URLBAR_HEIGHT,
hwnd_, reinterpret_cast<HMENU>(IDC_NAV_FORWARD), hInstance, 0);
CHECK(forward_hwnd_);
x += BUTTON_WIDTH;
reload_hwnd_ = CreateWindow(
L"BUTTON", L"Reload",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON| WS_DISABLED,
x, 0, BUTTON_WIDTH, URLBAR_HEIGHT,
hwnd_, reinterpret_cast<HMENU>(IDC_NAV_RELOAD), hInstance, 0);
CHECK(reload_hwnd_);
x += BUTTON_WIDTH;
stop_hwnd_ = CreateWindow(
L"BUTTON", L"Stop",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | WS_DISABLED,
x, 0, BUTTON_WIDTH, URLBAR_HEIGHT,
hwnd_, reinterpret_cast<HMENU>(IDC_NAV_STOP), hInstance, 0);
CHECK(stop_hwnd_);
x += BUTTON_WIDTH;
edit_hwnd_ = CreateWindow(
L"EDIT", 0,
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL |
ES_AUTOHSCROLL| WS_DISABLED,
x, 0, rect.right - BUTTON_WIDTH * 4, URLBAR_HEIGHT,
hwnd_, 0, hInstance, 0);
CHECK(edit_hwnd_);
// Override the edit control's window procedure.
edit_wndproc_old_ = SetWndProcPtr(edit_hwnd_, EditWndProc);
// Associate |this| with the edit window.
SetUserDataPtr(edit_hwnd_, this);
rect.top += URLBAR_HEIGHT;
} else {
// No controls so also remove the default menu.
::SetMenu(hwnd_, NULL);
}
if (!is_popup_) {
// Create the browser window.
browser_window_->CreateBrowser(hwnd_, rect, settings);
} else {
// With popups we already have a browser window. Parent the browser window
// to the root window and show it in the correct location.
browser_window_->ShowPopup(hwnd_,
rect.left, rect.top,
rect.right - rect.left,
rect.bottom - rect.top);
}
// Show this window.
Show(ShowNormal);
}
// static
void RootWindowWin::RegisterRootClass(HINSTANCE hInstance,
const std::wstring& window_class) {
// Only register the class one time.
static bool class_registered = false;
if (class_registered)
return;
class_registered = true;
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = RootWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CEFCLIENT));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_CEFCLIENT);
wcex.lpszClassName = window_class.c_str();
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
RegisterClassEx(&wcex);
}
// static
LRESULT CALLBACK RootWindowWin::EditWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam) {
REQUIRE_MAIN_THREAD();
RootWindowWin* self = GetUserDataPtr<RootWindowWin*>(hWnd);
DCHECK(self);
DCHECK(hWnd == self->edit_hwnd_);
switch (message) {
case WM_CHAR:
if (wParam == VK_RETURN) {
// When the user hits the enter key load the URL.
CefRefPtr<CefBrowser> browser = self->GetBrowser();
if (browser) {
wchar_t strPtr[MAX_URL_LENGTH+1] = {0};
*((LPWORD)strPtr) = MAX_URL_LENGTH;
LRESULT strLen = SendMessage(hWnd, EM_GETLINE, 0, (LPARAM)strPtr);
if (strLen > 0) {
strPtr[strLen] = 0;
browser->GetMainFrame()->LoadURL(strPtr);
}
}
return 0;
}
break;
case WM_NCDESTROY:
// Clear the reference to |self|.
SetUserDataPtr(hWnd, NULL);
self->edit_hwnd_ = NULL;
break;
}
return CallWindowProc(self->edit_wndproc_old_, hWnd, message, wParam, lParam);
}
// static
LRESULT CALLBACK RootWindowWin::FindWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam) {
REQUIRE_MAIN_THREAD();
RootWindowWin* self = GetUserDataPtr<RootWindowWin*>(hWnd);
DCHECK(self);
DCHECK(hWnd == self->find_hwnd_);
switch (message) {
case WM_ACTIVATE:
// Set this dialog as current when activated.
MainMessageLoop::Get()->SetCurrentModelessDialog(
wParam == 0 ? NULL : hWnd);
return FALSE;
case WM_NCDESTROY:
// Clear the reference to |self|.
SetUserDataPtr(hWnd, NULL);
self->find_hwnd_ = NULL;
break;
}
return CallWindowProc(self->find_wndproc_old_, hWnd, message, wParam, lParam);
}
// static
LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam) {
REQUIRE_MAIN_THREAD();
RootWindowWin* self = GetUserDataPtr<RootWindowWin*>(hWnd);
if (!self)
return DefWindowProc(hWnd, message, wParam, lParam);
DCHECK(hWnd == self->hwnd_);
if (message == self->find_message_id_) {
// Message targeting the find dialog.
LPFINDREPLACE lpfr = reinterpret_cast<LPFINDREPLACE>(lParam);
CHECK(lpfr == &self->find_state_);
self->OnFindEvent();
return 0;
}
// Callback for the main window
switch (message) {
case WM_COMMAND:
if (self->OnCommand(LOWORD(wParam)))
return 0;
break;
case WM_PAINT:
self->OnPaint();
return 0;
case WM_SETFOCUS:
self->OnFocus();
return 0;
case WM_SIZE:
self->OnSize(wParam == SIZE_MINIMIZED);
break;
case WM_MOVING:
case WM_MOVE:
self->OnMove();
return 0;
case WM_ERASEBKGND:
// Never erase the background.
return 0;
case WM_ENTERMENULOOP:
if (!wParam) {
// Entering the menu loop for the application menu.
CefSetOSModalLoop(true);
}
break;
case WM_EXITMENULOOP:
if (!wParam) {
// Exiting the menu loop for the application menu.
CefSetOSModalLoop(false);
}
break;
case WM_CLOSE:
if (self->OnClose())
return 0; // Cancel the close.
break;
case WM_NCDESTROY:
// Clear the reference to |self|.
SetUserDataPtr(hWnd, NULL);
self->hwnd_ = NULL;
self->OnDestroyed();
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
void RootWindowWin::OnPaint() {
PAINTSTRUCT ps;
BeginPaint(hwnd_, &ps);
EndPaint(hwnd_, &ps);
}
void RootWindowWin::OnFocus() {
if (browser_window_)
browser_window_->SetFocus();
}
void RootWindowWin::OnSize(bool minimized) {
if (minimized) {
// Notify the browser window that it was hidden and do nothing further.
if (browser_window_)
browser_window_->Hide();
return;
}
if (browser_window_)
browser_window_->Show();
RECT rect;
GetClientRect(hwnd_, &rect);
if (with_controls_) {
// Resize the window and address bar to match the new frame size.
rect.top += URLBAR_HEIGHT;
int urloffset = rect.left + BUTTON_WIDTH * 4;
if (browser_window_) {
HWND browser_hwnd = browser_window_->GetHWND();
HDWP hdwp = BeginDeferWindowPos(1);
hdwp = DeferWindowPos(hdwp, edit_hwnd_, NULL, urloffset,
0, rect.right - urloffset, URLBAR_HEIGHT, SWP_NOZORDER);
hdwp = DeferWindowPos(hdwp, browser_hwnd, NULL,
rect.left, rect.top, rect.right - rect.left,
rect.bottom - rect.top, SWP_NOZORDER);
EndDeferWindowPos(hdwp);
} else {
SetWindowPos(edit_hwnd_, NULL, urloffset,
0, rect.right - urloffset, URLBAR_HEIGHT, SWP_NOZORDER);
}
} else if (browser_window_) {
// Size the browser window to the whole client area.
browser_window_->SetBounds(0, 0, rect.right, rect.bottom);
}
}
void RootWindowWin::OnMove() {
// Notify the browser of move events so that popup windows are displayed
// in the correct location and dismissed when the window moves.
CefRefPtr<CefBrowser> browser = GetBrowser();
if (browser)
browser->GetHost()->NotifyMoveOrResizeStarted();
}
bool RootWindowWin::OnCommand(UINT id) {
if (id >= ID_TESTS_FIRST && id <= ID_TESTS_LAST) {
delegate_->OnTest(this, id);
return true;
}
switch (id) {
case IDM_ABOUT:
OnAbout();
return true;
case IDM_EXIT:
delegate_->OnExit(this);
return true;
case ID_FIND:
OnFind();
return true;
case IDC_NAV_BACK: // Back button
if (CefRefPtr<CefBrowser> browser = GetBrowser())
browser->GoBack();
return true;
case IDC_NAV_FORWARD: // Forward button
if (CefRefPtr<CefBrowser> browser = GetBrowser())
browser->GoForward();
return true;
case IDC_NAV_RELOAD: // Reload button
if (CefRefPtr<CefBrowser> browser = GetBrowser())
browser->Reload();
return true;
case IDC_NAV_STOP: // Stop button
if (CefRefPtr<CefBrowser> browser = GetBrowser())
browser->StopLoad();
return true;
}
return false;
}
void RootWindowWin::OnFind() {
if (find_hwnd_) {
// Give focus to the existing find dialog.
::SetFocus(find_hwnd_);
return;
}
// Configure dialog state.
ZeroMemory(&find_state_, sizeof(find_state_));
find_state_.lStructSize = sizeof(find_state_);
find_state_.hwndOwner = hwnd_;
find_state_.lpstrFindWhat = find_buff_;
find_state_.wFindWhatLen = sizeof(find_buff_);
find_state_.Flags = FR_HIDEWHOLEWORD | FR_DOWN;
// Create the dialog.
find_hwnd_ = FindText(&find_state_);
// Override the dialog's window procedure.
find_wndproc_old_ = SetWndProcPtr(find_hwnd_, FindWndProc);
// Associate |self| with the dialog.
SetUserDataPtr(find_hwnd_, this);
}
void RootWindowWin::OnFindEvent() {
CefRefPtr<CefBrowser> browser = GetBrowser();
if (find_state_.Flags & FR_DIALOGTERM) {
// The find dialog box has been dismissed so invalidate the handle and
// reset the search results.
if (browser) {
browser->GetHost()->StopFinding(true);
find_what_last_.clear();
find_next_ = false;
}
} else if ((find_state_.Flags & FR_FINDNEXT) && browser) {
// Search for the requested string.
bool match_case = ((find_state_.Flags & FR_MATCHCASE) ? true : false);
const std::wstring& find_what = find_buff_;
if (match_case != find_match_case_last_ || find_what != find_what_last_) {
// The search string has changed, so reset the search results.
if (!find_what.empty()) {
browser->GetHost()->StopFinding(true);
find_next_ = false;
}
find_match_case_last_ = match_case;
find_what_last_ = find_buff_;
}
browser->GetHost()->Find(0, find_what,
(find_state_.Flags & FR_DOWN) ? true : false,
match_case, find_next_);
if (!find_next_)
find_next_ = true;
}
}
void RootWindowWin::OnAbout() {
// Show the about box.
DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd_,
AboutWndProc);
}
bool RootWindowWin::OnClose() {
if (browser_window_ && !browser_window_->IsClosing()) {
CefRefPtr<CefBrowser> browser = GetBrowser();
if (browser) {
// Notify the browser window that we would like to close it. This
// will result in a call to ClientHandler::DoClose() if the
// JavaScript 'onbeforeunload' event handler allows it.
browser->GetHost()->CloseBrowser(false);
// Cancel the close.
return true;
}
}
// Allow the close.
return false;
}
void RootWindowWin::OnDestroyed() {
window_destroyed_ = true;
NotifyDestroyedIfDone();
}
void RootWindowWin::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
REQUIRE_MAIN_THREAD();
// For popup browsers create the root window once the browser has been
// created.
if (is_popup_)
CreateRootWindow(CefBrowserSettings());
}
void RootWindowWin::OnBrowserWindowDestroyed() {
REQUIRE_MAIN_THREAD();
browser_window_.reset();
browser_destroyed_ = true;
if (!window_destroyed_) {
// The browser was destroyed first. This could be due to the use of
// off-screen rendering or execution of JavaScript window.close().
// Close the RootWindow asynchronously.
Close(false);
}
NotifyDestroyedIfDone();
}
void RootWindowWin::OnSetAddress(const std::string& url) {
REQUIRE_MAIN_THREAD();
if (edit_hwnd_)
SetWindowText(edit_hwnd_, CefString(url).ToWString().c_str());
}
void RootWindowWin::OnSetTitle(const std::string& title) {
REQUIRE_MAIN_THREAD();
if (hwnd_)
SetWindowText(hwnd_, CefString(title).ToWString().c_str());
}
void RootWindowWin::OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) {
REQUIRE_MAIN_THREAD();
if (with_controls_) {
EnableWindow(back_hwnd_, canGoBack);
EnableWindow(forward_hwnd_, canGoForward);
EnableWindow(reload_hwnd_, !isLoading);
EnableWindow(stop_hwnd_, isLoading);
EnableWindow(edit_hwnd_, TRUE);
}
}
void RootWindowWin::NotifyDestroyedIfDone() {
// Notify once both the window and the browser have been destroyed.
if (window_destroyed_ && browser_destroyed_)
delegate_->OnRootWindowDestroyed(this);
}
// static
scoped_refptr<RootWindow> RootWindow::Create() {
return new RootWindowWin();
}
} // namespace client

View File

@ -0,0 +1,135 @@
// 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_ROOT_WINDOW_WIN_H_
#define CEF_TESTS_CEFCLIENT_ROOT_WINDOW_WIN_H_
#include <windows.h>
#include <commdlg.h>
#include <string>
#include "include/base/cef_scoped_ptr.h"
#include "cefclient/browser_window_win.h"
#include "cefclient/root_window.h"
namespace client {
// Windows implementation of a top-level native window in the browser process.
// The methods of this class must be called on the main thread unless otherwise
// indicated.
class RootWindowWin : public RootWindow,
public BrowserWindowWin::Delegate {
public:
// Constructor may be called on any thread.
RootWindowWin();
~RootWindowWin();
// RootWindow methods.
void Init(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefRect& rect,
const CefBrowserSettings& settings,
const std::string& url) OVERRIDE;
void InitAsPopup(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefPopupFeatures& popupFeatures,
CefWindowInfo& windowInfo,
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings) OVERRIDE;
void Show(ShowMode mode) OVERRIDE;
void Hide() OVERRIDE;
void SetBounds(int x, int y, size_t width, size_t height) OVERRIDE;
void Close(bool force) OVERRIDE;
CefRefPtr<CefBrowser> GetBrowser() const OVERRIDE;
CefWindowHandle GetWindowHandle() const OVERRIDE;
private:
void CreateBrowserWindow(bool with_osr, const std::string& startup_url);
void CreateRootWindow(const CefBrowserSettings& settings);
// Register the root window class.
static void RegisterRootClass(HINSTANCE hInstance,
const std::wstring& window_class);
// Window procedure for the edit field.
static LRESULT CALLBACK EditWndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam);
// Window procedure for the find dialog.
static LRESULT CALLBACK FindWndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam);
// Window procedure for the root window.
static LRESULT CALLBACK RootWndProc(HWND hWnd, UINT message, WPARAM wParam,
LPARAM lParam);
// Event handlers.
void OnPaint();
void OnFocus();
void OnSize(bool minimized);
void OnMove();
bool OnCommand(UINT id);
void OnFind();
void OnFindEvent();
void OnAbout();
bool OnClose();
void OnDestroyed();
// BrowserWindowWin::Delegate methods.
void OnBrowserCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
void OnBrowserWindowDestroyed() OVERRIDE;
void OnSetAddress(const std::string& url) OVERRIDE;
void OnSetTitle(const std::string& title) OVERRIDE;
void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) OVERRIDE;
void NotifyDestroyedIfDone();
// After initialization all members are only accessed on the main thread.
// Members set during initialization.
RootWindow::Delegate* delegate_;
bool with_controls_;
bool is_popup_;
RECT start_rect_;
scoped_ptr<BrowserWindowWin> browser_window_;
bool initialized_;
// Main window.
HWND hwnd_;
// Buttons.
HWND back_hwnd_;
HWND forward_hwnd_;
HWND reload_hwnd_;
HWND stop_hwnd_;
// URL text field.
HWND edit_hwnd_;
WNDPROC edit_wndproc_old_;
// Find dialog.
HWND find_hwnd_;
UINT find_message_id_;
WNDPROC find_wndproc_old_;
// Find dialog state.
FINDREPLACE find_state_;
WCHAR find_buff_[80];
std::wstring find_what_last_;
bool find_next_;
bool find_match_case_last_;
bool window_destroyed_;
bool browser_destroyed_;
DISALLOW_COPY_AND_ASSIGN(RootWindowWin);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_ROOT_WINDOW_WIN_H_

View File

@ -0,0 +1,58 @@
// 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/temp_window_win.h"
#include "include/base/cef_logging.h"
namespace client {
namespace {
const wchar_t kWndClass[] = L"Client_TempWindow";
// Create the temp window.
HWND CreateTempWindow() {
HINSTANCE hInstance = ::GetModuleHandle(NULL);
WNDCLASSEX wc = {0};
wc.cbSize = sizeof(wc);
wc.lpfnWndProc = DefWindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = kWndClass;
RegisterClassEx(&wc);
// Create a 1x1 pixel hidden window.
return CreateWindow(kWndClass, 0,
WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
0, 0, 1, 1,
NULL, NULL, hInstance, NULL);
}
TempWindowWin* g_temp_window = NULL;
} // namespace
TempWindowWin::TempWindowWin()
: hwnd_(NULL) {
DCHECK(!g_temp_window);
g_temp_window = this;
hwnd_ = CreateTempWindow();
CHECK(hwnd_);
}
TempWindowWin::~TempWindowWin() {
g_temp_window = NULL;
DCHECK(hwnd_);
DestroyWindow(hwnd_);
}
// static
HWND TempWindowWin::GetHWND() {
DCHECK(g_temp_window);
return g_temp_window->hwnd_;
}
} // namespace client

View File

@ -0,0 +1,35 @@
// 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_TEMP_WINDOW_WIN_H_
#define CEF_TESTS_CEFCLIENT_TEMP_WINDOW_WIN_H_
#include <windows.h>
#include "cefclient/main_message_loop.h"
namespace client {
// Represents a singleton hidden window that acts at temporary parent for
// popup browsers.
class TempWindowWin {
public:
// Returns the singleton window HWND.
static HWND GetHWND();
private:
// A single instance will be created/owned by RootWindowManager.
friend class RootWindowManager;
TempWindowWin();
~TempWindowWin();
HWND hwnd_;
DISALLOW_COPY_AND_ASSIGN(TempWindowWin);
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_TEMP_WINDOW_WIN_H_

View File

@ -26,6 +26,13 @@ WNDPROC SetWndProcPtr(HWND hWnd, WNDPROC wndProc) {
return old;
}
std::wstring GetResourceString(UINT id) {
#define MAX_LOADSTRING 100
TCHAR buff[MAX_LOADSTRING] = {0};
LoadString(::GetModuleHandle(NULL), id, buff, MAX_LOADSTRING);
return buff;
}
int GetCefMouseModifiers(WPARAM wparam) {
int modifiers = 0;
if (wparam & MK_CONTROL)

View File

@ -19,6 +19,9 @@ T GetUserDataPtr(HWND hWnd) {
// Set the window's window procedure pointer and return the old value.
WNDPROC SetWndProcPtr(HWND hWnd, WNDPROC wndProc);
// Return the resource string with the specified id.
std::wstring GetResourceString(UINT id);
int GetCefMouseModifiers(WPARAM wparam);
int GetCefKeyboardModifiers(WPARAM wparam, LPARAM lparam);
bool IsKeyDown(WPARAM wparam);