diff --git a/cef_paths2.gypi b/cef_paths2.gypi index 2431a4b0a..1043dc8bf 100644 --- a/cef_paths2.gypi +++ b/cef_paths2.gypi @@ -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', diff --git a/include/wrapper/cef_helpers.h b/include/wrapper/cef_helpers.h index 3624c74db..642313969 100644 --- a/include/wrapper/cef_helpers.h +++ b/include/wrapper/cef_helpers.h @@ -41,6 +41,7 @@ #include #include +#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 { +// public: +// Foo(); +// void DoSomething(); +// +// private: +// // Allow deletion via scoped_refptr only. +// friend struct CefDeleteOnThread; +// friend class base::RefCountedThreadSafe; +// +// virtual ~Foo() {} +// }; +// +// base::scoped_refptr foo = new Foo(); +// foo->DoSomething(); +// foo = NULL; // Deletion of |foo| will occur on the UI thread. +// +template +struct CefDeleteOnThread { + template + static void Destruct(const T* x) { + if (CefCurrentlyOn(thread)) { + delete x; + } else { + CefPostTask(thread, + base::Bind(&CefDeleteOnThread::Destruct, x)); + } + } +}; + +struct CefDeleteOnUIThread : public CefDeleteOnThread { }; +struct CefDeleteOnIOThread : public CefDeleteOnThread { }; +struct CefDeleteOnFileThread : public CefDeleteOnThread { }; +struct CefDeleteOnRendererThread : public CefDeleteOnThread { }; + + /// // Helper class to manage a scoped copy of |argv|. /// diff --git a/tests/cefclient/browser_window_osr_win.cc b/tests/cefclient/browser_window_osr_win.cc new file mode 100644 index 000000000..e1f4c070a --- /dev/null +++ b/tests/cefclient/browser_window_osr_win.cc @@ -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& 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 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 diff --git a/tests/cefclient/browser_window_osr_win.h b/tests/cefclient/browser_window_osr_win.h new file mode 100644 index 000000000..e49220165 --- /dev/null +++ b/tests/cefclient/browser_window_osr_win.h @@ -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& 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 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 osr_window_; + HWND osr_hwnd_; + + DISALLOW_COPY_AND_ASSIGN(BrowserWindowOsrWin); +}; + +} // namespace client + +#endif // CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_OSR_WIN_H_ diff --git a/tests/cefclient/browser_window_std_win.cc b/tests/cefclient/browser_window_std_win.cc new file mode 100644 index 000000000..fc88fa97c --- /dev/null +++ b/tests/cefclient/browser_window_std_win.cc @@ -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& 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 diff --git a/tests/cefclient/browser_window_std_win.h b/tests/cefclient/browser_window_std_win.h new file mode 100644 index 000000000..3672c6b00 --- /dev/null +++ b/tests/cefclient/browser_window_std_win.h @@ -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& 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_ diff --git a/tests/cefclient/browser_window_win.cc b/tests/cefclient/browser_window_win.cc new file mode 100644 index 000000000..9eda0967a --- /dev/null +++ b/tests/cefclient/browser_window_win.cc @@ -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 BrowserWindowWin::GetBrowser() const { + REQUIRE_MAIN_THREAD(); + return browser_; +} + +bool BrowserWindowWin::IsClosing() const { + REQUIRE_MAIN_THREAD(); + return is_closing_; +} + +void BrowserWindowWin::OnBrowserCreated(CefRefPtr browser) { + REQUIRE_MAIN_THREAD(); + DCHECK(!browser_); + browser_ = browser; + + delegate_->OnBrowserCreated(browser); +} + +void BrowserWindowWin::OnBrowserClosing(CefRefPtr browser) { + REQUIRE_MAIN_THREAD(); + DCHECK_EQ(browser->GetIdentifier(), browser_->GetIdentifier()); + is_closing_ = true; +} + +void BrowserWindowWin::OnBrowserClosed(CefRefPtr 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 diff --git a/tests/cefclient/browser_window_win.h b/tests/cefclient/browser_window_win.h new file mode 100644 index 000000000..9d935dba7 --- /dev/null +++ b/tests/cefclient/browser_window_win.h @@ -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 + +#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 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& 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 GetBrowser() const; + + // Returns true if the browser is closing. + bool IsClosing() const; + + protected: + // Allow deletion via scoped_ptr only. + friend struct base::DefaultDeleter; + + // 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 browser) OVERRIDE; + void OnBrowserClosing(CefRefPtr browser) OVERRIDE; + void OnBrowserClosed(CefRefPtr 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 browser_; + CefRefPtr client_handler_; + bool is_closing_; + + DISALLOW_COPY_AND_ASSIGN(BrowserWindowWin); +}; + +} // namespace client + +#endif // CEF_TESTS_CEFCLIENT_BROWSER_WINDOW_WIN_H_ diff --git a/tests/cefclient/cefclient_win.cc b/tests/cefclient/cefclient_win.cc index 3524ddd98..a52694a35 100644 --- a/tests/cefclient/cefclient_win.cc +++ b/tests/cefclient/cefclient_win.cc @@ -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 -#include -#include -#include -#include -#include -#include -#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 g_handler; - -// Used by off-screen rendering to find the associated CefBrowser. -class MainBrowserProvider : public OSRBrowserProvider { - virtual CefRefPtr 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 context(new MainContextImpl(0, NULL)); + scoped_ptr 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 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 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 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(GetWindowLongPtr(editWnd, GWLP_WNDPROC)); - SetWindowLongPtr(editWnd, GWLP_WNDPROC, - reinterpret_cast(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 command_line = - CefCommandLine::GetGlobalCommandLine(); - const bool transparent = - command_line->HasSwitch(switches::kTransparentPaintingEnabled); - const bool show_update_rect = - command_line->HasSwitch(switches::kShowUpdateRect); - - CefRefPtr 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 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 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 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 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(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 diff --git a/tests/cefclient/client_handler.cc b/tests/cefclient/client_handler.cc index ffeb8421e..6a0f657e7 100644 --- a/tests/cefclient/client_handler.cc +++ b/tests/cefclient/client_handler.cc @@ -264,7 +264,8 @@ bool ClientHandler::OnBeforePopup(CefRefPtr 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 browser) { @@ -464,7 +465,7 @@ void ClientHandler::ShowDevTools(CefRefPtr browser, CefRefPtr 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); diff --git a/tests/cefclient/client_handler.h b/tests/cefclient/client_handler.h index aa99bd233..630889dd9 100644 --- a/tests/cefclient/client_handler.h +++ b/tests/cefclient/client_handler.h @@ -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 browser, bool is_devtools, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, diff --git a/tests/cefclient/client_handler_osr.cc b/tests/cefclient/client_handler_osr.cc new file mode 100644 index 000000000..ada29b169 --- /dev/null +++ b/tests/cefclient/client_handler_osr.cc @@ -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 browser) { + CEF_REQUIRE_UI_THREAD(); + if (osr_delegate_) + osr_delegate_->OnAfterCreated(browser); + ClientHandlerSingle::OnAfterCreated(browser); +} + +void ClientHandlerOsr::OnBeforeClose(CefRefPtr browser) { + CEF_REQUIRE_UI_THREAD(); + if (osr_delegate_) + osr_delegate_->OnBeforeClose(browser); + ClientHandlerSingle::OnBeforeClose(browser); +} + +bool ClientHandlerOsr::GetRootScreenRect(CefRefPtr browser, + CefRect& rect) { + CEF_REQUIRE_UI_THREAD(); + if (!osr_delegate_) + return false; + return osr_delegate_->GetRootScreenRect(browser, rect); +} + +bool ClientHandlerOsr::GetViewRect(CefRefPtr browser, + CefRect& rect) { + CEF_REQUIRE_UI_THREAD(); + if (!osr_delegate_) + return false; + return osr_delegate_->GetViewRect(browser, rect); +} + +bool ClientHandlerOsr::GetScreenPoint(CefRefPtr 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 browser, + CefScreenInfo& screen_info) { + CEF_REQUIRE_UI_THREAD(); + if (!osr_delegate_) + return false; + return osr_delegate_->GetScreenInfo(browser, screen_info); +} + +void ClientHandlerOsr::OnPopupShow(CefRefPtr browser, + bool show) { + CEF_REQUIRE_UI_THREAD(); + if (!osr_delegate_) + return; + return osr_delegate_->OnPopupShow(browser, show); +} + +void ClientHandlerOsr::OnPopupSize(CefRefPtr browser, + const CefRect& rect) { + CEF_REQUIRE_UI_THREAD(); + if (!osr_delegate_) + return; + return osr_delegate_->OnPopupSize(browser, rect); +} + +void ClientHandlerOsr::OnPaint(CefRefPtr 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 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 browser, + CefRefPtr 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 browser, + CefRenderHandler::DragOperation operation) { + CEF_REQUIRE_UI_THREAD(); + if (!osr_delegate_) + return; + osr_delegate_->UpdateDragCursor(browser, operation); +} + +} // namespace client diff --git a/tests/cefclient/client_handler_osr.h b/tests/cefclient/client_handler_osr.h new file mode 100644 index 000000000..5b80c15c3 --- /dev/null +++ b/tests/cefclient/client_handler_osr.h @@ -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 browser) = 0; + virtual void OnBeforeClose(CefRefPtr browser) = 0; + + // These methods match the CefRenderHandler interface. + virtual bool GetRootScreenRect(CefRefPtr browser, + CefRect& rect) = 0; + virtual bool GetViewRect(CefRefPtr browser, + CefRect& rect) = 0; + virtual bool GetScreenPoint(CefRefPtr browser, + int viewX, + int viewY, + int& screenX, + int& screenY) = 0; + virtual bool GetScreenInfo(CefRefPtr browser, + CefScreenInfo& screen_info) = 0; + virtual void OnPopupShow(CefRefPtr browser, bool show) = 0; + virtual void OnPopupSize(CefRefPtr browser, + const CefRect& rect) = 0; + virtual void OnPaint(CefRefPtr browser, + PaintElementType type, + const RectList& dirtyRects, + const void* buffer, + int width, + int height) = 0; + virtual void OnCursorChange( + CefRefPtr browser, + CefCursorHandle cursor, + CefRenderHandler::CursorType type, + const CefCursorInfo& custom_cursor_info) = 0; + virtual bool StartDragging(CefRefPtr browser, + CefRefPtr drag_data, + CefRenderHandler::DragOperationsMask allowed_ops, + int x, int y) = 0; + virtual void UpdateDragCursor( + CefRefPtr 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 GetRenderHandler() OVERRIDE { + return this; + } + + // CefLifeSpanHandler methods. + void OnAfterCreated(CefRefPtr browser) OVERRIDE; + void OnBeforeClose(CefRefPtr browser) OVERRIDE; + + // CefRenderHandler methods. + bool GetRootScreenRect(CefRefPtr browser, + CefRect& rect) OVERRIDE; + bool GetViewRect(CefRefPtr browser, + CefRect& rect) OVERRIDE; + bool GetScreenPoint(CefRefPtr browser, + int viewX, + int viewY, + int& screenX, + int& screenY) OVERRIDE; + bool GetScreenInfo(CefRefPtr browser, + CefScreenInfo& screen_info) OVERRIDE; + void OnPopupShow(CefRefPtr browser, bool show) OVERRIDE; + void OnPopupSize(CefRefPtr browser, + const CefRect& rect) OVERRIDE; + void OnPaint(CefRefPtr browser, + CefRenderHandler::PaintElementType type, + const CefRenderHandler::RectList& dirtyRects, + const void* buffer, + int width, + int height) OVERRIDE; + void OnCursorChange(CefRefPtr browser, + CefCursorHandle cursor, + CursorType type, + const CefCursorInfo& custom_cursor_info) OVERRIDE; + bool StartDragging(CefRefPtr browser, + CefRefPtr drag_data, + CefRenderHandler::DragOperationsMask allowed_ops, + int x, int y) OVERRIDE; + void UpdateDragCursor(CefRefPtr 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_ diff --git a/tests/cefclient/client_handler_shared.cc b/tests/cefclient/client_handler_shared.cc index 0c9358520..b6735a79f 100644 --- a/tests/cefclient/client_handler_shared.cc +++ b/tests/cefclient/client_handler_shared.cc @@ -40,12 +40,7 @@ void ClientHandlerShared::BrowserCreated(CefRefPtr 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 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 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 browser) { } bool ClientHandlerShared::CreatePopupWindow( + CefRefPtr 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::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 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 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 diff --git a/tests/cefclient/client_handler_shared.h b/tests/cefclient/client_handler_shared.h index 6714dbeee..93a32abbc 100644 --- a/tests/cefclient/client_handler_shared.h +++ b/tests/cefclient/client_handler_shared.h @@ -9,12 +9,12 @@ #include #include -#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 browser, bool is_devtools, const CefPopupFeatures& popupFeatures, CefWindowInfo& windowInfo, @@ -59,12 +60,11 @@ class ClientHandlerShared : public ClientHandler { CefRefPtr GetOSRHandler() const; void SetOSRHandler(CefRefPtr 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 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 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_; diff --git a/tests/cefclient/client_handler_shared_win.cc b/tests/cefclient/client_handler_shared_win.cc deleted file mode 100644 index 23fff1464..000000000 --- a/tests/cefclient/client_handler_shared_win.cc +++ /dev/null @@ -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 -#include - -#include "include/cef_browser.h" -#include "cefclient/resource.h" - -namespace client { - -void ClientHandlerShared::SetAddress(CefRefPtr 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 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 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 diff --git a/tests/cefclient/client_handler_single.cc b/tests/cefclient/client_handler_single.cc new file mode 100644 index 000000000..77a54faf7 --- /dev/null +++ b/tests/cefclient/client_handler_single.cc @@ -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 +#include +#include + +#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 browser) { + CEF_REQUIRE_UI_THREAD(); + NotifyBrowserCreated(browser); +} + +void ClientHandlerSingle::BrowserClosing(CefRefPtr browser) { + CEF_REQUIRE_UI_THREAD(); + NotifyBrowserClosing(browser); +} + +void ClientHandlerSingle::BrowserClosed(CefRefPtr browser) { + CEF_REQUIRE_UI_THREAD(); + NotifyBrowserClosed(browser); +} + +void ClientHandlerSingle::SetAddress(CefRefPtr browser, + const CefString& url) { + CEF_REQUIRE_UI_THREAD(); + NotifyAddress(url); +} + +void ClientHandlerSingle::SetTitle(CefRefPtr browser, + const CefString& title) { + CEF_REQUIRE_UI_THREAD(); + NotifyTitle(title); +} + +void ClientHandlerSingle::SetLoadingState(CefRefPtr browser, + bool isLoading, + bool canGoBack, + bool canGoForward) { + CEF_REQUIRE_UI_THREAD(); + NotifyLoadingState(isLoading, canGoBack, canGoForward); +} + +bool ClientHandlerSingle::CreatePopupWindow( + CefRefPtr browser, + bool is_devtools, + const CefPopupFeatures& popupFeatures, + CefWindowInfo& windowInfo, + CefRefPtr& 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 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 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 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 diff --git a/tests/cefclient/client_handler_single.h b/tests/cefclient/client_handler_single.h new file mode 100644 index 000000000..1d37ed9af --- /dev/null +++ b/tests/cefclient/client_handler_single.h @@ -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 +#include + +#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 browser) = 0; + + // Called when the browser is closing. + virtual void OnBrowserClosing(CefRefPtr browser) = 0; + + // Called when the browser has been closed. + virtual void OnBrowserClosed(CefRefPtr 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 browser) OVERRIDE; + void BrowserClosing(CefRefPtr browser) OVERRIDE; + void BrowserClosed(CefRefPtr browser) OVERRIDE; + void SetAddress(CefRefPtr browser, + const CefString& url) OVERRIDE; + void SetTitle(CefRefPtr browser, + const CefString& title) OVERRIDE; + void SetLoadingState(CefRefPtr browser, + bool isLoading, + bool canGoBack, + bool canGoForward) OVERRIDE; + bool CreatePopupWindow( + CefRefPtr browser, + bool is_devtools, + const CefPopupFeatures& popupFeatures, + CefWindowInfo& windowInfo, + CefRefPtr& client, + CefBrowserSettings& settings) OVERRIDE; + + private: + void NotifyBrowserCreated(CefRefPtr browser); + void NotifyBrowserClosing(CefRefPtr browser); + void NotifyBrowserClosed(CefRefPtr 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_ diff --git a/tests/cefclient/client_handler_std.cc b/tests/cefclient/client_handler_std.cc new file mode 100644 index 000000000..983db5083 --- /dev/null +++ b/tests/cefclient/client_handler_std.cc @@ -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 diff --git a/tests/cefclient/client_handler_std.h b/tests/cefclient/client_handler_std.h new file mode 100644 index 000000000..f8bc7696f --- /dev/null +++ b/tests/cefclient/client_handler_std.h @@ -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_ diff --git a/tests/cefclient/main_context.h b/tests/cefclient/main_context.h index c158eebee..e5114a39e 100644 --- a/tests/cefclient/main_context.h +++ b/tests/cefclient/main_context.h @@ -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(); diff --git a/tests/cefclient/main_context_impl.cc b/tests/cefclient/main_context_impl.cc index 783ab2d7b..f643475bb 100644 --- a/tests/cefclient/main_context_impl.cc +++ b/tests/cefclient/main_context_impl.cc @@ -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 diff --git a/tests/cefclient/main_context_impl.h b/tests/cefclient/main_context_impl.h index dd2619c04..84f3878c2 100644 --- a/tests/cefclient/main_context_impl.h +++ b/tests/cefclient/main_context_impl.h @@ -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 command_line_; std::string main_url_; +#if defined(OS_WIN) + scoped_ptr root_window_manager_; +#endif + DISALLOW_COPY_AND_ASSIGN(MainContextImpl); }; diff --git a/tests/cefclient/main_context_impl_win.cc b/tests/cefclient/main_context_impl_win.cc index b4501c6bb..eb3e67761 100644 --- a/tests/cefclient/main_context_impl_win.cc +++ b/tests/cefclient/main_context_impl_win.cc @@ -7,6 +7,8 @@ #include #include +#include "cefclient/root_window_manager.h" + namespace client { std::string MainContextImpl::GetDownloadPath(const std::string& file_name) { diff --git a/tests/cefclient/main_message_loop.h b/tests/cefclient/main_message_loop.h index 803a3c524..d97e52f68 100644 --- a/tests/cefclient/main_message_loop.h +++ b/tests/cefclient/main_message_loop.h @@ -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 - 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; @@ -64,12 +56,6 @@ class MainMessageLoop { virtual ~MainMessageLoop(); private: - // Helper for deleting |object|. - template - 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, x)); } } }; diff --git a/tests/cefclient/osr_widget_win.cc b/tests/cefclient/osr_widget_win.cc deleted file mode 100644 index cbb39168b..000000000 --- a/tests/cefclient/osr_widget_win.cc +++ /dev/null @@ -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 - -#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::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::From( - CefRefPtr renderHandler) { - return static_cast(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(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 browser) { -#if defined(CEF_USE_ATL) - RevokeDragDrop(hWnd_); - drop_target_ = NULL; -#endif - - DisableGL(); - ::DestroyWindow(hWnd_); -} - -bool OSRWindow::GetRootScreenRect(CefRefPtr 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 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 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 browser, - bool show) { - if (!show) { - renderer_.ClearPopupRects(); - browser->GetHost()->Invalidate(PET_VIEW); - } - renderer_.OnPopupShow(browser, show); -} - -void OSRWindow::OnPopupSize(CefRefPtr browser, - const CefRect& rect) { - renderer_.OnPopupSize(browser, rect); -} - -void OSRWindow::OnPaint(CefRefPtr 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 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(reinterpret_cast(cursor))); - SetCursor(cursor); -} - -bool OSRWindow::StartDragging(CefRefPtr browser, - CefRefPtr 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 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 browser = browser_provider_->GetBrowser(); - if (!browser) - return; - browser->GetHost()->WasHidden(hidden); - hidden_ = hidden; -} - -#if defined(CEF_USE_ATL) - -CefBrowserHost::DragOperationsMask - OSRWindow::OnDragEnter(CefRefPtr 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(GetWindowLongPtr(hWnd, GWLP_USERDATA)); - CefRefPtr 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 diff --git a/tests/cefclient/osr_widget_win.h b/tests/cefclient/osr_widget_win.h deleted file mode 100644 index 6c36cf8aa..000000000 --- a/tests/cefclient/osr_widget_win.h +++ /dev/null @@ -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 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 Create(OSRBrowserProvider* browser_provider, - bool transparent, - bool show_update_rect); - - static CefRefPtr From( - CefRefPtr 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 browser) OVERRIDE; - - // CefRenderHandler methods - bool GetRootScreenRect(CefRefPtr browser, - CefRect& rect) OVERRIDE; - bool GetViewRect(CefRefPtr browser, - CefRect& rect) OVERRIDE; - bool GetScreenPoint(CefRefPtr browser, - int viewX, - int viewY, - int& screenX, - int& screenY) OVERRIDE; - void OnPopupShow(CefRefPtr browser, - bool show) OVERRIDE; - void OnPopupSize(CefRefPtr browser, - const CefRect& rect) OVERRIDE; - void OnPaint(CefRefPtr browser, - PaintElementType type, - const RectList& dirtyRects, - const void* buffer, - int width, - int height) OVERRIDE; - void OnCursorChange(CefRefPtr browser, - CefCursorHandle cursor, - CursorType type, - const CefCursorInfo& custom_cursor_info) OVERRIDE; - bool StartDragging(CefRefPtr browser, - CefRefPtr drag_data, - CefRenderHandler::DragOperationsMask allowed_ops, - int x, int y) OVERRIDE; - void UpdateDragCursor( - CefRefPtr browser, - CefRenderHandler::DragOperation operation) OVERRIDE; - -#if defined(CEF_USE_ATL) - // OsrDragEvents methods - CefBrowserHost::DragOperationsMask OnDragEnter( - CefRefPtr 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 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_ diff --git a/tests/cefclient/osr_window_win.cc b/tests/cefclient/osr_window_win.cc new file mode 100644 index 000000000..bd2ebc900 --- /dev/null +++ b/tests/cefclient/osr_window_win.cc @@ -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 + +#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 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(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 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 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 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 browser) { + CEF_REQUIRE_UI_THREAD(); + // Detach |this| from the ClientHandler. + static_cast(browser_->GetHost()->GetClient().get())-> + DetachOsrDelegate(); + browser_ = NULL; + Destroy(); +} + +bool OsrWindowWin::GetRootScreenRect(CefRefPtr 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 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 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 browser, + CefScreenInfo& screen_info) { + CEF_REQUIRE_UI_THREAD(); + + return false; +} + +void OsrWindowWin::OnPopupShow(CefRefPtr browser, + bool show) { + CEF_REQUIRE_UI_THREAD(); + + if (!show) { + renderer_.ClearPopupRects(); + browser->GetHost()->Invalidate(PET_VIEW); + } + renderer_.OnPopupShow(browser, show); +} + +void OsrWindowWin::OnPopupSize(CefRefPtr browser, + const CefRect& rect) { + CEF_REQUIRE_UI_THREAD(); + + renderer_.OnPopupSize(browser, rect); +} + +void OsrWindowWin::OnPaint(CefRefPtr 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 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(reinterpret_cast(cursor))); + SetCursor(cursor); +} + +bool OsrWindowWin::StartDragging( + CefRefPtr browser, + CefRefPtr 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 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 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 diff --git a/tests/cefclient/osr_window_win.h b/tests/cefclient/osr_window_win.h new file mode 100644 index 000000000..1e2fdb6b6 --- /dev/null +++ b/tests/cefclient/osr_window_win.h @@ -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, + 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 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; + friend class base::RefCountedThreadSafe; + + ~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 browser) OVERRIDE; + void OnBeforeClose(CefRefPtr browser) OVERRIDE; + bool GetRootScreenRect(CefRefPtr browser, + CefRect& rect) OVERRIDE; + bool GetViewRect(CefRefPtr browser, + CefRect& rect) OVERRIDE; + bool GetScreenPoint(CefRefPtr browser, + int viewX, + int viewY, + int& screenX, + int& screenY) OVERRIDE; + bool GetScreenInfo(CefRefPtr browser, + CefScreenInfo& screen_info) OVERRIDE; + void OnPopupShow(CefRefPtr browser, bool show) OVERRIDE; + void OnPopupSize(CefRefPtr browser, + const CefRect& rect) OVERRIDE; + void OnPaint(CefRefPtr browser, + CefRenderHandler::PaintElementType type, + const CefRenderHandler::RectList& dirtyRects, + const void* buffer, + int width, + int height) OVERRIDE; + void OnCursorChange(CefRefPtr browser, + CefCursorHandle cursor, + CefRenderHandler::CursorType type, + const CefCursorInfo& custom_cursor_info) OVERRIDE; + bool StartDragging(CefRefPtr browser, + CefRefPtr drag_data, + CefRenderHandler::DragOperationsMask allowed_ops, + int x, int y) OVERRIDE; + void UpdateDragCursor(CefRefPtr browser, + CefRenderHandler::DragOperation operation) OVERRIDE; + +#if defined(CEF_USE_ATL) + // OsrDragEvents methods. + CefBrowserHost::DragOperationsMask OnDragEnter( + CefRefPtr 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 browser_; + +#if defined(CEF_USE_ATL) + CComPtr 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_ diff --git a/tests/cefclient/root_window.h b/tests/cefclient/root_window.h new file mode 100644 index 000000000..0e55fd0ed --- /dev/null +++ b/tests/cefclient/root_window.h @@ -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 + +#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 { + 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 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& 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 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; + + virtual ~RootWindow() {} +}; + +} // namespace client + +#endif // CEF_TESTS_CEFCLIENT_ROOT_WINDOW_H_ diff --git a/tests/cefclient/root_window_manager.cc b/tests/cefclient/root_window_manager.cc new file mode 100644 index 000000000..9e8acfeec --- /dev/null +++ b/tests/cefclient/root_window_manager.cc @@ -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 RootWindowManager::CreateRootWindow( + bool with_controls, + bool with_osr, + const CefRect& bounds, + const std::string& url) { + CefBrowserSettings settings; + MainContext::Get()->PopulateBrowserSettings(&settings); + + scoped_refptr 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 RootWindowManager::CreateRootWindowAsPopup( + bool with_controls, + bool with_osr, + const CefPopupFeatures& popupFeatures, + CefWindowInfo& windowInfo, + CefRefPtr& client, + CefBrowserSettings& settings) { + MainContext::Get()->PopulateBrowserSettings(&settings); + + scoped_refptr 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 RootWindowManager::GetWindowForBrowser( + int browser_id) { + REQUIRE_MAIN_THREAD(); + + RootWindowSet::const_iterator it = root_windows_.begin(); + for (; it != root_windows_.end(); ++it) { + CefRefPtr 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 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 diff --git a/tests/cefclient/root_window_manager.h b/tests/cefclient/root_window_manager.h new file mode 100644 index 000000000..9bc6d7e81 --- /dev/null +++ b/tests/cefclient/root_window_manager.h @@ -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 + +#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 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 CreateRootWindowAsPopup( + bool with_controls, + bool with_osr, + const CefPopupFeatures& popupFeatures, + CefWindowInfo& windowInfo, + CefRefPtr& client, + CefBrowserSettings& settings); + + // Returns the RootWindow associated with the specified browser ID. Must be + // called on the main thread. + scoped_refptr 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(); + + void OnRootWindowCreated(scoped_refptr 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 > 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_ diff --git a/tests/cefclient/root_window_win.cc b/tests/cefclient/root_window_win.cc new file mode 100644 index 000000000..4dc5052ab --- /dev/null +++ b/tests/cefclient/root_window_win.cc @@ -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& 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 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 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(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(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(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(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(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 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(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(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(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 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 browser = GetBrowser()) + browser->GoBack(); + return true; + case IDC_NAV_FORWARD: // Forward button + if (CefRefPtr browser = GetBrowser()) + browser->GoForward(); + return true; + case IDC_NAV_RELOAD: // Reload button + if (CefRefPtr browser = GetBrowser()) + browser->Reload(); + return true; + case IDC_NAV_STOP: // Stop button + if (CefRefPtr 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 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 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 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::Create() { + return new RootWindowWin(); +} + +} // namespace client diff --git a/tests/cefclient/root_window_win.h b/tests/cefclient/root_window_win.h new file mode 100644 index 000000000..0bafcff8f --- /dev/null +++ b/tests/cefclient/root_window_win.h @@ -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 +#include + +#include + +#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& 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 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 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 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_ diff --git a/tests/cefclient/temp_window_win.cc b/tests/cefclient/temp_window_win.cc new file mode 100644 index 000000000..d40bdb1d7 --- /dev/null +++ b/tests/cefclient/temp_window_win.cc @@ -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 diff --git a/tests/cefclient/temp_window_win.h b/tests/cefclient/temp_window_win.h new file mode 100644 index 000000000..5ea056b37 --- /dev/null +++ b/tests/cefclient/temp_window_win.h @@ -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 + +#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_ diff --git a/tests/cefclient/util_win.cc b/tests/cefclient/util_win.cc index aa0d49af7..00407b726 100644 --- a/tests/cefclient/util_win.cc +++ b/tests/cefclient/util_win.cc @@ -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) diff --git a/tests/cefclient/util_win.h b/tests/cefclient/util_win.h index 0ae37e79b..986a1e3f5 100644 --- a/tests/cefclient/util_win.h +++ b/tests/cefclient/util_win.h @@ -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);