Add support for loading extensions (issue #1947)

- Add CefRequestContext::LoadExtension, CefExtension, CefExtensionHandler and
  related methods/interfaces.
- Add chrome://extensions-support that lists supported Chrome APIs.
- Add CefBrowserHost::SetAutoResizeEnabled and CefDisplayHandler::OnAutoResize
  to support browser resize based on preferred web contents size.
- views: Add support for custom CefMenuButton popups.
- cefclient: Run with `--load-extension=set_page_color` command-line flag for
  an extension loading example. Add `--use-views` on Windows and Linux for an
  even better example.
This commit is contained in:
Marshall Greenblatt
2017-08-03 18:55:19 -04:00
parent 5b12134a45
commit 9cff99dc4e
178 changed files with 10360 additions and 650 deletions

View File

@@ -73,6 +73,11 @@ void BrowserWindow::OnSetFullscreen(bool fullscreen) {
delegate_->OnSetFullscreen(fullscreen);
}
void BrowserWindow::OnAutoResize(const CefSize& new_size) {
REQUIRE_MAIN_THREAD();
delegate_->OnAutoResize(new_size);
}
void BrowserWindow::OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) {

View File

@@ -37,6 +37,9 @@ class BrowserWindow : public ClientHandler::Delegate {
// Set fullscreen mode.
virtual void OnSetFullscreen(bool fullscreen) = 0;
// Auto-resize contents.
virtual void OnAutoResize(const CefSize& new_size) = 0;
// Set the loading state.
virtual void OnSetLoadingState(bool isLoading,
bool canGoBack,
@@ -117,6 +120,7 @@ class BrowserWindow : public ClientHandler::Delegate {
void OnSetAddress(const std::string& url) OVERRIDE;
void OnSetTitle(const std::string& title) OVERRIDE;
void OnSetFullscreen(bool fullscreen) OVERRIDE;
void OnAutoResize(const CefSize& new_size) OVERRIDE;
void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) OVERRIDE;

View File

@@ -20,6 +20,7 @@
#include "tests/cefclient/browser/main_context.h"
#include "tests/cefclient/browser/root_window_manager.h"
#include "tests/cefclient/browser/test_runner.h"
#include "tests/shared/browser/extension_util.h"
#include "tests/shared/browser/resource_util.h"
#include "tests/shared/common/client_switches.h"
@@ -417,6 +418,14 @@ bool ClientHandler::OnConsoleMessage(CefRefPtr<CefBrowser> browser,
return false;
}
bool ClientHandler::OnAutoResize(CefRefPtr<CefBrowser> browser,
const CefSize& new_size) {
CEF_REQUIRE_UI_THREAD();
NotifyAutoResize(new_size);
return true;
}
void ClientHandler::OnBeforeDownload(
CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
@@ -541,6 +550,19 @@ void ClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
if (mouse_cursor_change_disabled_)
browser->GetHost()->SetMouseCursorChangeDisabled(true);
if (browser->GetHost()->GetExtension()) {
// Browsers hosting extension apps should auto-resize.
browser->GetHost()->SetAutoResizeEnabled(true, CefSize(20, 20),
CefSize(1000, 1000));
CefRefPtr<CefExtension> extension = browser->GetHost()->GetExtension();
if (extension_util::IsInternalExtension(extension->GetPath())) {
// Register the internal handler for extension resources.
extension_util::AddInternalExtensionToResourceManager(extension,
resource_manager_);
}
}
NotifyBrowserCreated(browser);
}
@@ -623,8 +645,11 @@ bool ClientHandler::OnOpenURLFromTab(
target_disposition == WOD_NEW_FOREGROUND_TAB) {
// Handle middle-click and ctrl + left-click by opening the URL in a new
// browser window.
MainContext::Get()->GetRootWindowManager()->CreateRootWindow(
true, is_osr(), CefRect(), target_url);
RootWindowConfig config;
config.with_controls = true;
config.with_osr = is_osr();
config.url = target_url;
MainContext::Get()->GetRootWindowManager()->CreateRootWindow(config);
return true;
}
@@ -867,9 +892,11 @@ void ClientHandler::ShowSSLInformation(CefRefPtr<CefBrowser> browser) {
ss << "</body></html>";
MainContext::Get()->GetRootWindowManager()->CreateRootWindow(
false, is_osr(), CefRect(),
test_runner::GetDataURI(ss.str(), "text/html"));
RootWindowConfig config;
config.with_controls = false;
config.with_osr = is_osr();
config.url = test_runner::GetDataURI(ss.str(), "text/html");
MainContext::Get()->GetRootWindowManager()->CreateRootWindow(config);
}
bool ClientHandler::CreatePopupWindow(CefRefPtr<CefBrowser> browser,
@@ -969,6 +996,18 @@ void ClientHandler::NotifyFullscreen(bool fullscreen) {
delegate_->OnSetFullscreen(fullscreen);
}
void ClientHandler::NotifyAutoResize(const CefSize& new_size) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(
base::Bind(&ClientHandler::NotifyAutoResize, this, new_size));
return;
}
if (delegate_)
delegate_->OnAutoResize(new_size);
}
void ClientHandler::NotifyLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) {

View File

@@ -58,11 +58,14 @@ class ClientHandler : public CefClient,
virtual void OnSetTitle(const std::string& title) = 0;
// Set the Favicon image.
virtual void OnSetFavicon(CefRefPtr<CefImage> image){};
virtual void OnSetFavicon(CefRefPtr<CefImage> image) {}
// Set fullscreen mode.
virtual void OnSetFullscreen(bool fullscreen) = 0;
// Auto-resize contents.
virtual void OnAutoResize(const CefSize& new_size) = 0;
// Set the loading state.
virtual void OnSetLoadingState(bool isLoading,
bool canGoBack,
@@ -147,6 +150,8 @@ class ClientHandler : public CefClient,
const CefString& message,
const CefString& source,
int line) OVERRIDE;
bool OnAutoResize(CefRefPtr<CefBrowser> browser,
const CefSize& new_size) OVERRIDE;
// CefDownloadHandler methods
void OnBeforeDownload(CefRefPtr<CefBrowser> browser,
@@ -311,6 +316,7 @@ class ClientHandler : public CefClient,
void NotifyTitle(const CefString& title);
void NotifyFavicon(CefRefPtr<CefImage> image);
void NotifyFullscreen(bool fullscreen);
void NotifyAutoResize(const CefSize& new_size);
void NotifyLoadingState(bool isLoading, bool canGoBack, bool canGoForward);
void NotifyDraggableRegions(const std::vector<CefDraggableRegion>& regions);
void NotifyTakeFocus(bool next);

View File

@@ -0,0 +1,306 @@
// Copyright (c) 2017 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 "tests/cefclient/browser/image_cache.h"
#include "tests/shared/browser/file_util.h"
#include "tests/shared/browser/resource_util.h"
namespace client {
namespace {
const char kEmptyId[] = "__empty";
} // namespace
ImageCache::ImageCache() {}
ImageCache::~ImageCache() {
CEF_REQUIRE_UI_THREAD();
}
ImageCache::ImageRep::ImageRep(const std::string& path, float scale_factor)
: path_(path), scale_factor_(scale_factor) {
DCHECK(!path_.empty());
DCHECK_GT(scale_factor_, 0.0f);
}
ImageCache::ImageInfo::ImageInfo(const std::string& id,
const ImageRepSet& reps,
bool internal,
bool force_reload)
: id_(id), reps_(reps), internal_(internal), force_reload_(force_reload) {
#ifndef NDEBUG
DCHECK(!id_.empty());
if (id_ != kEmptyId)
DCHECK(!reps_.empty());
#endif
}
// static
ImageCache::ImageInfo ImageCache::ImageInfo::Empty() {
return ImageInfo(kEmptyId, ImageRepSet(), true, false);
}
// static
ImageCache::ImageInfo ImageCache::ImageInfo::Create1x(
const std::string& id,
const std::string& path_1x,
bool internal) {
ImageRepSet reps;
reps.push_back(ImageRep(path_1x, 1.0f));
return ImageInfo(id, reps, internal, false);
}
// static
ImageCache::ImageInfo ImageCache::ImageInfo::Create2x(
const std::string& id,
const std::string& path_1x,
const std::string& path_2x,
bool internal) {
ImageRepSet reps;
reps.push_back(ImageRep(path_1x, 1.0f));
reps.push_back(ImageRep(path_2x, 2.0f));
return ImageInfo(id, reps, internal, false);
}
// static
ImageCache::ImageInfo ImageCache::ImageInfo::Create2x(const std::string& id) {
return Create2x(id, id + ".1x.png", id + ".2x.png", true);
}
struct ImageCache::ImageContent {
ImageContent() {}
struct RepContent {
RepContent(ImageType type, float scale_factor, const std::string& contents)
: type_(type), scale_factor_(scale_factor), contents_(contents) {}
ImageType type_;
float scale_factor_;
std::string contents_;
};
typedef std::vector<RepContent> RepContentSet;
RepContentSet contents_;
CefRefPtr<CefImage> image_;
};
void ImageCache::LoadImages(const ImageInfoSet& image_info,
const LoadImagesCallback& callback) {
DCHECK(!image_info.empty());
DCHECK(!callback.is_null());
if (!CefCurrentlyOn(TID_UI)) {
CefPostTask(TID_UI, base::Bind(&ImageCache::LoadImages, this, image_info,
callback));
return;
}
ImageSet images;
bool missing_images = false;
ImageInfoSet::const_iterator it = image_info.begin();
for (; it != image_info.end(); ++it) {
const ImageInfo& info = *it;
if (info.id_ == kEmptyId) {
// Image intentionally left empty.
images.push_back(NULL);
continue;
}
ImageMap::iterator it2 = image_map_.find(info.id_);
if (it2 != image_map_.end()) {
if (!info.force_reload_) {
// Image already exists.
images.push_back(it2->second);
continue;
}
// Remove the existing image from the map.
image_map_.erase(it2);
}
// Load the image.
images.push_back(NULL);
if (!missing_images)
missing_images = true;
}
if (missing_images) {
CefPostTask(TID_FILE, base::Bind(&ImageCache::LoadMissing, this, image_info,
images, callback));
} else {
callback.Run(images);
}
}
CefRefPtr<CefImage> ImageCache::GetCachedImage(const std::string& image_id) {
CEF_REQUIRE_UI_THREAD();
DCHECK(!image_id.empty());
ImageMap::const_iterator it = image_map_.find(image_id);
if (it != image_map_.end())
return it->second;
return NULL;
}
// static
ImageCache::ImageType ImageCache::GetImageType(const std::string& path) {
std::string ext = file_util::GetFileExtension(path);
if (ext.empty())
return TYPE_NONE;
std::transform(ext.begin(), ext.end(), ext.begin(), tolower);
if (ext == "png")
return TYPE_PNG;
if (ext == "jpg" || ext == "jpeg")
return TYPE_JPEG;
return TYPE_NONE;
}
void ImageCache::LoadMissing(const ImageInfoSet& image_info,
const ImageSet& images,
const LoadImagesCallback& callback) {
CEF_REQUIRE_FILE_THREAD();
DCHECK_EQ(image_info.size(), images.size());
ImageContentSet contents;
ImageInfoSet::const_iterator it1 = image_info.begin();
ImageSet::const_iterator it2 = images.begin();
for (; it1 != image_info.end() && it2 != images.end(); ++it1, ++it2) {
const ImageInfo& info = *it1;
ImageContent content;
if (*it2 || info.id_ == kEmptyId) {
// Image already exists or is intentionally empty.
content.image_ = *it2;
} else {
LoadImageContents(info, &content);
}
contents.push_back(content);
}
CefPostTask(TID_UI, base::Bind(&ImageCache::UpdateCache, this, image_info,
contents, callback));
}
// static
bool ImageCache::LoadImageContents(const ImageInfo& info,
ImageContent* content) {
CEF_REQUIRE_FILE_THREAD();
ImageRepSet::const_iterator it = info.reps_.begin();
for (; it != info.reps_.end(); ++it) {
const ImageRep& rep = *it;
ImageType rep_type;
std::string rep_contents;
if (!LoadImageContents(rep.path_, info.internal_, &rep_type,
&rep_contents)) {
LOG(ERROR) << "Failed to load image " << info.id_ << " from path "
<< rep.path_;
return false;
}
content->contents_.push_back(
ImageContent::RepContent(rep_type, rep.scale_factor_, rep_contents));
}
return true;
}
// static
bool ImageCache::LoadImageContents(const std::string& path,
bool internal,
ImageType* type,
std::string* contents) {
CEF_REQUIRE_FILE_THREAD();
*type = GetImageType(path);
if (*type == TYPE_NONE)
return false;
if (internal) {
if (!LoadBinaryResource(path.c_str(), *contents))
return false;
} else if (!file_util::ReadFileToString(path, contents)) {
return false;
}
return !contents->empty();
}
void ImageCache::UpdateCache(const ImageInfoSet& image_info,
const ImageContentSet& contents,
const LoadImagesCallback& callback) {
CEF_REQUIRE_UI_THREAD();
DCHECK_EQ(image_info.size(), contents.size());
ImageSet images;
ImageInfoSet::const_iterator it1 = image_info.begin();
ImageContentSet::const_iterator it2 = contents.begin();
for (; it1 != image_info.end() && it2 != contents.end(); ++it1, ++it2) {
const ImageInfo& info = *it1;
const ImageContent& content = *it2;
if (content.image_ || info.id_ == kEmptyId) {
// Image already exists or is intentionally empty.
images.push_back(content.image_);
} else {
CefRefPtr<CefImage> image = CreateImage(info.id_, content);
images.push_back(image);
// Add the image to the map.
image_map_.insert(std::make_pair(info.id_, image));
}
}
callback.Run(images);
}
// static
CefRefPtr<CefImage> ImageCache::CreateImage(const std::string& image_id,
const ImageContent& content) {
CEF_REQUIRE_UI_THREAD();
// Shouldn't be creating an image if one already exists.
DCHECK(!content.image_);
if (content.contents_.empty())
return NULL;
CefRefPtr<CefImage> image = CefImage::CreateImage();
ImageContent::RepContentSet::const_iterator it = content.contents_.begin();
for (; it != content.contents_.end(); ++it) {
const ImageContent::RepContent& rep = *it;
if (rep.type_ == TYPE_PNG) {
if (!image->AddPNG(rep.scale_factor_, rep.contents_.c_str(),
rep.contents_.size())) {
LOG(ERROR) << "Failed to create image " << image_id << " for PNG@"
<< rep.scale_factor_;
return NULL;
}
} else if (rep.type_ == TYPE_JPEG) {
if (!image->AddJPEG(rep.scale_factor_, rep.contents_.c_str(),
rep.contents_.size())) {
LOG(ERROR) << "Failed to create image " << image_id << " for JPG@"
<< rep.scale_factor_;
return NULL;
}
} else {
NOTREACHED();
return NULL;
}
}
return image;
}
} // namespace client

View File

@@ -0,0 +1,127 @@
// Copyright (c) 2017 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_IMAGE_CACHE_H_
#define CEF_TESTS_CEFCLIENT_BROWSER_IMAGE_CACHE_H_
#pragma once
#include <map>
#include <vector>
#include "include/base/cef_bind.h"
#include "include/base/cef_ref_counted.h"
#include "include/cef_image.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
namespace client {
// Simple image caching implementation.
class ImageCache
: public base::RefCountedThreadSafe<ImageCache, CefDeleteOnUIThread> {
public:
ImageCache();
// Image representation at a specific scale factor.
struct ImageRep {
ImageRep(const std::string& path, float scale_factor);
// Full file system path.
std::string path_;
// Image scale factor (usually 1.0f or 2.0f).
float scale_factor_;
};
typedef std::vector<ImageRep> ImageRepSet;
// Unique image that may have multiple representations.
struct ImageInfo {
ImageInfo(const std::string& id,
const ImageRepSet& reps,
bool internal,
bool force_reload);
// Helper for returning an empty image.
static ImageInfo Empty();
// Helpers for creating common representations.
static ImageInfo Create1x(const std::string& id,
const std::string& path_1x,
bool internal);
static ImageInfo Create2x(const std::string& id,
const std::string& path_1x,
const std::string& path_2x,
bool internal);
static ImageInfo Create2x(const std::string& id);
// Image unique ID.
std::string id_;
// Image representations to load.
ImageRepSet reps_;
// True if the image is internal (loaded via LoadBinaryResource).
bool internal_;
// True to force reload.
bool force_reload_;
};
typedef std::vector<ImageInfo> ImageInfoSet;
typedef std::vector<CefRefPtr<CefImage>> ImageSet;
typedef base::Callback<void(const ImageSet& /*images*/)> LoadImagesCallback;
// Loads the images represented by |image_info|. Executes |callback|
// either synchronously or asychronously on the UI thread after completion.
void LoadImages(const ImageInfoSet& image_info,
const LoadImagesCallback& callback);
// Returns an image that has already been cached. Must be called on the
// UI thread.
CefRefPtr<CefImage> GetCachedImage(const std::string& image_id);
private:
// Only allow deletion via scoped_refptr.
friend struct CefDeleteOnThread<TID_UI>;
friend class base::RefCountedThreadSafe<ImageCache, CefDeleteOnUIThread>;
~ImageCache();
enum ImageType {
TYPE_NONE,
TYPE_PNG,
TYPE_JPEG,
};
static ImageType GetImageType(const std::string& path);
struct ImageContent;
typedef std::vector<ImageContent> ImageContentSet;
// Load missing image contents on the FILE thread.
void LoadMissing(const ImageInfoSet& image_info,
const ImageSet& images,
const LoadImagesCallback& callback);
static bool LoadImageContents(const ImageInfo& info, ImageContent* content);
static bool LoadImageContents(const std::string& path,
bool internal,
ImageType* type,
std::string* contents);
// Create missing CefImage representations on the UI thread.
void UpdateCache(const ImageInfoSet& image_info,
const ImageContentSet& contents,
const LoadImagesCallback& callback);
static CefRefPtr<CefImage> CreateImage(const std::string& image_id,
const ImageContent& content);
// Map image ID to image representation. Only accessed on the UI thread.
typedef std::map<std::string, CefRefPtr<CefImage>> ImageMap;
ImageMap image_map_;
};
} // namespace client
#endif // CEF_TESTS_CEFCLIENT_BROWSER_IMAGE_CACHE_H_

View File

@@ -65,6 +65,11 @@
#define IDS_WINDOW_ICON_2X_PNG 1020
#define IDS_XMLHTTPREQUEST_HTML 1021
#define IDS_EXTENSIONS_SET_PAGE_COLOR_ICON_PNG 1030
#define IDS_EXTENSIONS_SET_PAGE_COLOR_MANIFEST_JSON 1031
#define IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_HTML 1032
#define IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_JS 1033
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED

View File

@@ -18,6 +18,14 @@ int GetResourceId(const char* resource_name) {
{"dialogs.html", IDS_DIALOGS_HTML},
{"draggable.html", IDS_DRAGGABLE_HTML},
{"drm.html", IDS_DRM_HTML},
{"extensions/set_page_color/icon.png",
IDS_EXTENSIONS_SET_PAGE_COLOR_ICON_PNG},
{"extensions/set_page_color/manifest.json",
IDS_EXTENSIONS_SET_PAGE_COLOR_MANIFEST_JSON},
{"extensions/set_page_color/popup.html",
IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_HTML},
{"extensions/set_page_color/popup.js",
IDS_EXTENSIONS_SET_PAGE_COLOR_POPUP_JS},
{"logo.png", IDS_LOGO_PNG},
{"localstorage.html", IDS_LOCALSTORAGE_HTML},
{"menu_icon.1x.png", IDS_MENU_ICON_1X_PNG},

View File

@@ -9,10 +9,36 @@
namespace client {
RootWindowConfig::RootWindowConfig()
: with_controls(true),
with_osr(false),
with_extension(false),
initially_hidden(false),
url(MainContext::Get()->GetMainURL()) {}
RootWindow::RootWindow() : delegate_(NULL) {}
RootWindow::~RootWindow() {}
// static
scoped_refptr<RootWindow> RootWindow::GetForBrowser(int browser_id) {
return MainContext::Get()->GetRootWindowManager()->GetWindowForBrowser(
browser_id);
}
void RootWindow::OnExtensionsChanged(const ExtensionSet& extensions) {
REQUIRE_MAIN_THREAD();
DCHECK(delegate_);
DCHECK(!WithExtension());
if (extensions.empty())
return;
ExtensionSet::const_iterator it = extensions.begin();
for (; it != extensions.end(); ++it) {
delegate_->CreateExtensionWindow(*it, CefRect(), NULL, base::Closure(),
WithWindowlessRendering());
}
}
} // namespace client

View File

@@ -6,15 +6,58 @@
#define CEF_TESTS_CEFCLIENT_BROWSER_ROOT_WINDOW_H_
#pragma once
#include <set>
#include <string>
#include "include/base/cef_callback_forward.h"
#include "include/base/cef_ref_counted.h"
#include "include/cef_browser.h"
#include "include/views/cef_window.h"
#include "tests/cefclient/browser/client_types.h"
#include "tests/cefclient/browser/image_cache.h"
#include "tests/shared/browser/main_message_loop.h"
namespace client {
// Used to configure how a RootWindow is created.
struct RootWindowConfig {
RootWindowConfig();
// If true the window will show controls.
bool with_controls;
// If true the window will use off-screen rendering.
bool with_osr;
// If true the window is hosting an extension app.
bool with_extension;
// If true the window will be created initially hidden.
bool initially_hidden;
// Requested window position. If |bounds| and |source_bounds| are empty the
// default window size and location will be used.
CefRect bounds;
// Position of the UI element that triggered the window creation. If |bounds|
// is empty and |source_bounds| is non-empty the new window will be positioned
// relative to |source_bounds|. This is currently only implemented for Views-
// based windows when |initially_hidden| is also true.
CefRect source_bounds;
// Parent window. Only used for Views-based windows.
CefRefPtr<CefWindow> parent_window;
// Callback to be executed when the window is closed. Will be executed on the
// main thread. This is currently only implemented for Views-based windows.
base::Closure close_callback;
// Initial URL to load.
std::string url;
};
typedef std::set<CefRefPtr<CefExtension>> ExtensionSet;
// 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.
@@ -30,8 +73,8 @@ class RootWindow
virtual CefRefPtr<CefRequestContext> GetRequestContext(
RootWindow* root_window) = 0;
// Returns the default window icon.
virtual CefRefPtr<CefImage> GetDefaultWindowIcon() = 0;
// Returns the ImageCache.
virtual scoped_refptr<ImageCache> GetImageCache() = 0;
// Called to execute a test. See resource.h for |test_id| values.
virtual void OnTest(RootWindow* root_window, int test_id) = 0;
@@ -42,6 +85,21 @@ class RootWindow
// Called when the RootWindow has been destroyed.
virtual void OnRootWindowDestroyed(RootWindow* root_window) = 0;
// Called when the RootWindow is activated (becomes the foreground window).
virtual void OnRootWindowActivated(RootWindow* root_window) = 0;
// Called when the browser is created for the RootWindow.
virtual void OnBrowserCreated(RootWindow* root_window,
CefRefPtr<CefBrowser> browser) = 0;
// Create a window for |extension|. |source_bounds| are the bounds of the
// UI element, like a button, that triggered the extension.
virtual void CreateExtensionWindow(CefRefPtr<CefExtension> extension,
const CefRect& source_bounds,
CefRefPtr<CefWindow> parent_window,
const base::Closure& close_callback,
bool with_osr) = 0;
protected:
virtual ~Delegate() {}
};
@@ -68,11 +126,8 @@ class RootWindow
// 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;
const RootWindowConfig& config,
const CefBrowserSettings& settings) = 0;
// Initialize as a popup window. This is used to attach a new native window to
// a single browser instance that will be created later. The native window
@@ -121,12 +176,25 @@ class RootWindow
// Returns the native handle for this window, if any.
virtual ClientWindowHandle GetWindowHandle() const = 0;
// Returns true if this window is using windowless rendering (osr).
virtual bool WithWindowlessRendering() const = 0;
// Returns true if this window is hosting an extension app.
virtual bool WithExtension() const = 0;
// Called when the set of loaded extensions changes. The default
// implementation will create a single window instance for each extension.
virtual void OnExtensionsChanged(const ExtensionSet& extensions);
protected:
// Allow deletion via scoped_refptr only.
friend struct DeleteOnMainThread;
friend class base::RefCountedThreadSafe<RootWindow, DeleteOnMainThread>;
virtual ~RootWindow() {}
RootWindow();
virtual ~RootWindow();
Delegate* delegate_;
};
} // namespace client

View File

@@ -49,9 +49,9 @@ void MaximizeWindow(GtkWindow* window) {
} // namespace
RootWindowGtk::RootWindowGtk()
: delegate_(NULL),
with_controls_(false),
: with_controls_(false),
with_osr_(false),
with_extension_(false),
is_popup_(false),
initialized_(false),
window_(NULL),
@@ -75,29 +75,27 @@ RootWindowGtk::~RootWindowGtk() {
}
void RootWindowGtk::Init(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefRect& bounds,
const CefBrowserSettings& settings,
const std::string& url) {
const RootWindowConfig& config,
const CefBrowserSettings& settings) {
DCHECK(delegate);
DCHECK(!initialized_);
delegate_ = delegate;
with_controls_ = with_controls;
with_osr_ = with_osr;
start_rect_ = bounds;
with_controls_ = config.with_controls;
with_osr_ = config.with_osr;
with_extension_ = config.with_extension;
start_rect_ = config.bounds;
CreateBrowserWindow(url);
CreateBrowserWindow(config.url);
initialized_ = true;
// Create the native root window on the main thread.
if (CURRENTLY_ON_MAIN_THREAD()) {
CreateRootWindow(settings);
CreateRootWindow(settings, config.initially_hidden);
} else {
MAIN_POST_CLOSURE(
base::Bind(&RootWindowGtk::CreateRootWindow, this, settings));
MAIN_POST_CLOSURE(base::Bind(&RootWindowGtk::CreateRootWindow, this,
settings, config.initially_hidden));
}
}
@@ -179,13 +177,7 @@ void RootWindowGtk::SetBounds(int x, int y, size_t width, size_t height) {
else
gtk_window_present(window);
// Retrieve information about the display that contains the window.
GdkScreen* screen = gdk_screen_get_default();
const gint monitor = gdk_screen_get_monitor_at_window(screen, gdk_window);
GdkRectangle rect;
gdk_screen_get_monitor_geometry(screen, monitor, &rect);
gdk_window_move_resize(gdk_window, rect.x, rect.y, rect.width, rect.height);
gdk_window_move_resize(gdk_window, x, y, width, height);
}
void RootWindowGtk::Close(bool force) {
@@ -200,16 +192,18 @@ void RootWindowGtk::Close(bool force) {
void RootWindowGtk::SetDeviceScaleFactor(float device_scale_factor) {
REQUIRE_MAIN_THREAD();
if (browser_window_)
if (browser_window_ && with_osr_)
browser_window_->SetDeviceScaleFactor(device_scale_factor);
}
float RootWindowGtk::GetDeviceScaleFactor() const {
REQUIRE_MAIN_THREAD();
if (browser_window_)
if (browser_window_ && with_osr_)
return browser_window_->GetDeviceScaleFactor();
return 1.0f;
NOTREACHED();
return 0.0f;
}
CefRefPtr<CefBrowser> RootWindowGtk::GetBrowser() const {
@@ -225,6 +219,16 @@ ClientWindowHandle RootWindowGtk::GetWindowHandle() const {
return window_;
}
bool RootWindowGtk::WithWindowlessRendering() const {
REQUIRE_MAIN_THREAD();
return with_osr_;
}
bool RootWindowGtk::WithExtension() const {
REQUIRE_MAIN_THREAD();
return with_extension_;
}
void RootWindowGtk::CreateBrowserWindow(const std::string& startup_url) {
if (with_osr_) {
OsrRenderer::Settings settings = {};
@@ -235,7 +239,8 @@ void RootWindowGtk::CreateBrowserWindow(const std::string& startup_url) {
}
}
void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings) {
void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings,
bool initially_hidden) {
REQUIRE_MAIN_THREAD();
DCHECK(!window_);
@@ -358,7 +363,9 @@ void RootWindowGtk::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
// For popup browsers create the root window once the browser has been
// created.
if (is_popup_)
CreateRootWindow(CefBrowserSettings());
CreateRootWindow(CefBrowserSettings(), false);
delegate_->OnBrowserCreated(this, browser);
}
void RootWindowGtk::OnBrowserWindowDestroyed() {
@@ -409,6 +416,24 @@ void RootWindowGtk::OnSetFullscreen(bool fullscreen) {
}
}
void RootWindowGtk::OnAutoResize(const CefSize& new_size) {
REQUIRE_MAIN_THREAD();
if (!window_)
return;
GtkWindow* window = GTK_WINDOW(window_);
GdkWindow* gdk_window = gtk_widget_get_window(window_);
// Make sure the window isn't minimized or maximized.
if (IsWindowMaximized(window))
gtk_window_unmaximize(window);
else
gtk_window_present(window);
gdk_window_resize(gdk_window, new_size.width, new_size.height);
}
void RootWindowGtk::OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) {
@@ -440,6 +465,7 @@ gboolean RootWindowGtk::WindowFocusIn(GtkWidget* widget,
RootWindowGtk* self) {
if (event->in && self->browser_window_.get()) {
self->browser_window_->SetFocus(true);
self->delegate_->OnRootWindowActivated(self);
// Return true for a windowed browser so that focus is not passed to GTK.
return self->with_osr_ ? FALSE : TRUE;
}

View File

@@ -26,11 +26,8 @@ class RootWindowGtk : public RootWindow, public BrowserWindow::Delegate {
// RootWindow methods.
void Init(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefRect& rect,
const CefBrowserSettings& settings,
const std::string& url) OVERRIDE;
const RootWindowConfig& config,
const CefBrowserSettings& settings) OVERRIDE;
void InitAsPopup(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
@@ -46,10 +43,13 @@ class RootWindowGtk : public RootWindow, public BrowserWindow::Delegate {
float GetDeviceScaleFactor() const OVERRIDE;
CefRefPtr<CefBrowser> GetBrowser() const OVERRIDE;
ClientWindowHandle GetWindowHandle() const OVERRIDE;
bool WithWindowlessRendering() const OVERRIDE;
bool WithExtension() const OVERRIDE;
private:
void CreateBrowserWindow(const std::string& startup_url);
void CreateRootWindow(const CefBrowserSettings& settings);
void CreateRootWindow(const CefBrowserSettings& settings,
bool initially_hidden);
// BrowserWindow::Delegate methods.
void OnBrowserCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
@@ -57,6 +57,7 @@ class RootWindowGtk : public RootWindow, public BrowserWindow::Delegate {
void OnSetAddress(const std::string& url) OVERRIDE;
void OnSetTitle(const std::string& title) OVERRIDE;
void OnSetFullscreen(bool fullscreen) OVERRIDE;
void OnAutoResize(const CefSize& new_size) OVERRIDE;
void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) OVERRIDE;
@@ -112,9 +113,9 @@ class RootWindowGtk : public RootWindow, public BrowserWindow::Delegate {
// After initialization all members are only accessed on the main thread.
// Members set during initialization.
RootWindow::Delegate* delegate_;
bool with_controls_;
bool with_osr_;
bool with_extension_;
bool is_popup_;
CefRect start_rect_;
scoped_ptr<BrowserWindow> browser_window_;

View File

@@ -35,11 +35,8 @@ class RootWindowMac : public RootWindow, public BrowserWindow::Delegate {
// RootWindow methods.
void Init(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefRect& rect,
const CefBrowserSettings& settings,
const std::string& url) OVERRIDE;
const RootWindowConfig& config,
const CefBrowserSettings& settings) OVERRIDE;
void InitAsPopup(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
@@ -55,16 +52,20 @@ class RootWindowMac : public RootWindow, public BrowserWindow::Delegate {
float GetDeviceScaleFactor() const OVERRIDE;
CefRefPtr<CefBrowser> GetBrowser() const OVERRIDE;
ClientWindowHandle GetWindowHandle() const OVERRIDE;
bool WithWindowlessRendering() const OVERRIDE;
bool WithExtension() const OVERRIDE;
// Called by RootWindowDelegate after the associated NSWindow has been
// destroyed.
void WindowDestroyed();
BrowserWindow* browser_window() const { return browser_window_.get(); }
RootWindow::Delegate* delegate() const { return delegate_; }
private:
void CreateBrowserWindow(const std::string& startup_url);
void CreateRootWindow(const CefBrowserSettings& settings);
void CreateRootWindow(const CefBrowserSettings& settings,
bool initially_hidden);
// BrowserWindow::Delegate methods.
void OnBrowserCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
@@ -72,6 +73,7 @@ class RootWindowMac : public RootWindow, public BrowserWindow::Delegate {
void OnSetAddress(const std::string& url) OVERRIDE;
void OnSetTitle(const std::string& title) OVERRIDE;
void OnSetFullscreen(bool fullscreen) OVERRIDE;
void OnAutoResize(const CefSize& new_size) OVERRIDE;
void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) OVERRIDE;
@@ -82,9 +84,9 @@ class RootWindowMac : public RootWindow, public BrowserWindow::Delegate {
// After initialization all members are only accessed on the main thread.
// Members set during initialization.
RootWindow::Delegate* delegate_;
bool with_controls_;
bool with_osr_;
bool with_extension_;
bool is_popup_;
CefRect start_rect_;
scoped_ptr<BrowserWindow> browser_window_;

View File

@@ -118,6 +118,7 @@
client::BrowserWindow* browser_window = root_window_->browser_window();
if (browser_window)
browser_window->SetFocus(true);
root_window_->delegate()->OnRootWindowActivated(root_window_);
}
// Called when we are deactivated (when we lose focus).
@@ -236,8 +237,7 @@ NSRect GetScreenRectForWindow(NSWindow* window) {
} // namespace
RootWindowMac::RootWindowMac()
: delegate_(NULL),
with_controls_(false),
: with_controls_(false),
with_osr_(false),
is_popup_(false),
initialized_(false),
@@ -259,29 +259,27 @@ RootWindowMac::~RootWindowMac() {
}
void RootWindowMac::Init(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefRect& bounds,
const CefBrowserSettings& settings,
const std::string& url) {
const RootWindowConfig& config,
const CefBrowserSettings& settings) {
DCHECK(delegate);
DCHECK(!initialized_);
delegate_ = delegate;
with_controls_ = with_controls;
with_osr_ = with_osr;
start_rect_ = bounds;
with_controls_ = config.with_controls;
with_osr_ = config.with_osr;
with_extension_ = config.with_extension;
start_rect_ = config.bounds;
CreateBrowserWindow(url);
CreateBrowserWindow(config.url);
initialized_ = true;
// Create the native root window on the main thread.
if (CURRENTLY_ON_MAIN_THREAD()) {
CreateRootWindow(settings);
CreateRootWindow(settings, config.initially_hidden);
} else {
MAIN_POST_CLOSURE(
base::Bind(&RootWindowMac::CreateRootWindow, this, settings));
MAIN_POST_CLOSURE(base::Bind(&RootWindowMac::CreateRootWindow, this,
settings, config.initially_hidden));
}
}
@@ -402,16 +400,18 @@ void RootWindowMac::Close(bool force) {
void RootWindowMac::SetDeviceScaleFactor(float device_scale_factor) {
REQUIRE_MAIN_THREAD();
if (browser_window_)
if (browser_window_ && with_osr_)
browser_window_->SetDeviceScaleFactor(device_scale_factor);
}
float RootWindowMac::GetDeviceScaleFactor() const {
REQUIRE_MAIN_THREAD();
if (browser_window_)
if (browser_window_ && with_osr_)
return browser_window_->GetDeviceScaleFactor();
return 1.0f;
NOTREACHED();
return 0.0f;
}
CefRefPtr<CefBrowser> RootWindowMac::GetBrowser() const {
@@ -427,6 +427,16 @@ ClientWindowHandle RootWindowMac::GetWindowHandle() const {
return [window_ contentView];
}
bool RootWindowMac::WithWindowlessRendering() const {
REQUIRE_MAIN_THREAD();
return with_osr_;
}
bool RootWindowMac::WithExtension() const {
REQUIRE_MAIN_THREAD();
return with_extension_;
}
void RootWindowMac::WindowDestroyed() {
window_ = nil;
window_destroyed_ = true;
@@ -443,7 +453,8 @@ void RootWindowMac::CreateBrowserWindow(const std::string& startup_url) {
}
}
void RootWindowMac::CreateRootWindow(const CefBrowserSettings& settings) {
void RootWindowMac::CreateRootWindow(const CefBrowserSettings& settings,
bool initially_hidden) {
REQUIRE_MAIN_THREAD();
DCHECK(!window_);
@@ -566,11 +577,13 @@ void RootWindowMac::CreateRootWindow(const CefBrowserSettings& settings) {
contentBounds.size.height);
}
// Show the window.
Show(ShowNormal);
if (!initially_hidden) {
// Show the window.
Show(ShowNormal);
// Size the window.
SetBounds(x, y, width, height);
// Size the window.
SetBounds(x, y, width, height);
}
}
void RootWindowMac::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
@@ -579,7 +592,9 @@ void RootWindowMac::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
// For popup browsers create the root window once the browser has been
// created.
if (is_popup_)
CreateRootWindow(CefBrowserSettings());
CreateRootWindow(CefBrowserSettings(), false);
delegate_->OnBrowserCreated(this, browser);
}
void RootWindowMac::OnBrowserWindowDestroyed() {
@@ -638,6 +653,29 @@ void RootWindowMac::OnSetFullscreen(bool fullscreen) {
}
}
void RootWindowMac::OnAutoResize(const CefSize& new_size) {
REQUIRE_MAIN_THREAD();
if (!window_)
return;
// Desired content rectangle.
NSRect content_rect;
content_rect.size.width = static_cast<int>(new_size.width);
content_rect.size.height =
static_cast<int>(new_size.height) + (with_controls_ ? URLBAR_HEIGHT : 0);
// Convert to a frame rectangle.
NSRect frame_rect = [window_ frameRectForContentRect:content_rect];
// Don't change the origin.
frame_rect.origin = window_.frame.origin;
[window_ setFrame:frame_rect display:YES];
// Make sure the window is visible.
Show(ShowNormal);
}
void RootWindowMac::OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) {

View File

@@ -11,6 +11,7 @@
#include "include/wrapper/cef_helpers.h"
#include "tests/cefclient/browser/main_context.h"
#include "tests/cefclient/browser/test_runner.h"
#include "tests/shared/browser/extension_util.h"
#include "tests/shared/browser/resource_util.h"
#include "tests/shared/common/client_switches.h"
@@ -18,10 +19,12 @@ namespace client {
namespace {
class ClientRequestContextHandler : public CefRequestContextHandler {
class ClientRequestContextHandler : public CefRequestContextHandler,
public CefExtensionHandler {
public:
ClientRequestContextHandler() {}
// CefRequestContextHandler methods:
bool OnBeforePluginLoad(const CefString& mime_type,
const CefString& plugin_url,
bool is_main_frame,
@@ -38,14 +41,73 @@ class ClientRequestContextHandler : public CefRequestContextHandler {
return false;
}
void OnRequestContextInitialized(
CefRefPtr<CefRequestContext> request_context) OVERRIDE {
CEF_REQUIRE_UI_THREAD();
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
if (command_line->HasSwitch(switches::kLoadExtension)) {
if (MainContext::Get()
->GetRootWindowManager()
->request_context_per_browser()) {
// The example extension loading implementation requires all browsers to
// share the same request context.
LOG(ERROR)
<< "Cannot mix --load-extension and --request-context-per-browser";
return;
}
// Load one or more extension paths specified on the command-line and
// delimited with semicolon.
const std::string& extension_path =
command_line->GetSwitchValue(switches::kLoadExtension);
if (!extension_path.empty()) {
std::string part;
std::istringstream f(extension_path);
while (getline(f, part, ';')) {
if (!part.empty())
extension_util::LoadExtension(request_context, part, this);
}
}
}
}
// CefExtensionHandler methods:
void OnExtensionLoaded(CefRefPtr<CefExtension> extension) OVERRIDE {
CEF_REQUIRE_UI_THREAD();
MainContext::Get()->GetRootWindowManager()->AddExtension(extension);
}
CefRefPtr<CefBrowser> GetActiveBrowser(CefRefPtr<CefExtension> extension,
CefRefPtr<CefBrowser> browser,
bool include_incognito) OVERRIDE {
CEF_REQUIRE_UI_THREAD();
// Return the browser for the active/foreground window.
CefRefPtr<CefBrowser> active_browser =
MainContext::Get()->GetRootWindowManager()->GetActiveBrowser();
if (!active_browser) {
LOG(WARNING)
<< "No active browser available for extension "
<< browser->GetHost()->GetExtension()->GetIdentifier().ToString();
} else {
// The active browser should not be hosting an extension.
DCHECK(!active_browser->GetHost()->GetExtension());
}
return active_browser;
}
private:
IMPLEMENT_REFCOUNTING(ClientRequestContextHandler);
DISALLOW_COPY_AND_ASSIGN(ClientRequestContextHandler);
};
} // namespace
RootWindowManager::RootWindowManager(bool terminate_when_all_windows_closed)
: terminate_when_all_windows_closed_(terminate_when_all_windows_closed) {
: terminate_when_all_windows_closed_(terminate_when_all_windows_closed),
image_cache_(new ImageCache) {
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
DCHECK(command_line.get());
@@ -61,17 +123,13 @@ RootWindowManager::~RootWindowManager() {
}
scoped_refptr<RootWindow> RootWindowManager::CreateRootWindow(
bool with_controls,
bool with_osr,
const CefRect& bounds,
const std::string& url) {
const RootWindowConfig& config) {
CefBrowserSettings settings;
MainContext::Get()->PopulateBrowserSettings(&settings);
scoped_refptr<RootWindow> root_window =
RootWindow::Create(MainContext::Get()->UseViews());
root_window->Init(this, with_controls, with_osr, bounds, settings,
url.empty() ? MainContext::Get()->GetMainURL() : url);
root_window->Init(this, config, settings);
// Store a reference to the root window on the main thread.
OnRootWindowCreated(root_window);
@@ -101,8 +159,60 @@ scoped_refptr<RootWindow> RootWindowManager::CreateRootWindowAsPopup(
return root_window;
}
scoped_refptr<RootWindow> RootWindowManager::CreateRootWindowAsExtension(
CefRefPtr<CefExtension> extension,
const CefRect& source_bounds,
CefRefPtr<CefWindow> parent_window,
const base::Closure& close_callback,
bool with_controls,
bool with_osr) {
const std::string& extension_url = extension_util::GetExtensionURL(extension);
if (extension_url.empty()) {
NOTREACHED() << "Extension cannot be loaded directly.";
return NULL;
}
// Create an initially hidden browser window that loads the extension URL.
// We'll show the window when the desired size becomes available via
// ClientHandler::OnAutoResize.
RootWindowConfig config;
config.with_controls = with_controls;
config.with_osr = with_osr;
config.with_extension = true;
config.initially_hidden = true;
config.source_bounds = source_bounds;
config.parent_window = parent_window;
config.close_callback = close_callback;
config.url = extension_url;
return CreateRootWindow(config);
}
bool RootWindowManager::HasRootWindowAsExtension(
CefRefPtr<CefExtension> extension) {
REQUIRE_MAIN_THREAD();
RootWindowSet::const_iterator it = root_windows_.begin();
for (; it != root_windows_.end(); ++it) {
const RootWindow* root_window = (*it);
if (!root_window->WithExtension())
continue;
CefRefPtr<CefBrowser> browser = root_window->GetBrowser();
if (!browser)
continue;
CefRefPtr<CefExtension> browser_extension =
browser->GetHost()->GetExtension();
DCHECK(browser_extension);
if (browser_extension->GetIdentifier() == extension->GetIdentifier())
return true;
}
return false;
}
scoped_refptr<RootWindow> RootWindowManager::GetWindowForBrowser(
int browser_id) {
int browser_id) const {
REQUIRE_MAIN_THREAD();
RootWindowSet::const_iterator it = root_windows_.begin();
@@ -114,6 +224,16 @@ scoped_refptr<RootWindow> RootWindowManager::GetWindowForBrowser(
return NULL;
}
scoped_refptr<RootWindow> RootWindowManager::GetActiveRootWindow() const {
REQUIRE_MAIN_THREAD();
return active_root_window_;
}
CefRefPtr<CefBrowser> RootWindowManager::GetActiveBrowser() const {
base::AutoLock lock_scope(active_browser_lock_);
return active_browser_;
}
void RootWindowManager::CloseAllWindows(bool force) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
@@ -130,6 +250,29 @@ void RootWindowManager::CloseAllWindows(bool force) {
(*it)->Close(force);
}
void RootWindowManager::AddExtension(CefRefPtr<CefExtension> extension) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(base::Bind(&RootWindowManager::AddExtension,
base::Unretained(this), extension));
return;
}
// Don't track extensions that can't be loaded directly.
if (extension_util::GetExtensionURL(extension).empty())
return;
// Don't add the same extension multiple times.
ExtensionSet::const_iterator it = extensions_.begin();
for (; it != extensions_.end(); ++it) {
if ((*it)->GetIdentifier() == extension->GetIdentifier())
return;
}
extensions_.insert(extension);
NotifyExtensionsChanged();
}
void RootWindowManager::OnRootWindowCreated(
scoped_refptr<RootWindow> root_window) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
@@ -140,6 +283,26 @@ void RootWindowManager::OnRootWindowCreated(
}
root_windows_.insert(root_window);
if (!root_window->WithExtension()) {
root_window->OnExtensionsChanged(extensions_);
if (root_windows_.size() == 1U) {
// The first non-extension root window should be considered the active
// window.
OnRootWindowActivated(root_window);
}
}
}
void RootWindowManager::NotifyExtensionsChanged() {
REQUIRE_MAIN_THREAD();
RootWindowSet::const_iterator it = root_windows_.begin();
for (; it != root_windows_.end(); ++it) {
RootWindow* root_window = *it;
if (!root_window->WithExtension())
root_window->OnExtensionsChanged(extensions_);
}
}
CefRefPtr<CefRequestContext> RootWindowManager::GetRequestContext(
@@ -180,14 +343,10 @@ CefRefPtr<CefRequestContext> RootWindowManager::GetRequestContext(
return shared_request_context_;
}
CefRefPtr<CefImage> RootWindowManager::GetDefaultWindowIcon() {
scoped_refptr<ImageCache> RootWindowManager::GetImageCache() {
REQUIRE_MAIN_THREAD();
if (!default_window_icon_) {
// Create the Image and load resources at different scale factors.
default_window_icon_ = LoadImageIcon("window_icon");
}
return default_window_icon_;
return image_cache_;
}
void RootWindowManager::OnTest(RootWindow* root_window, int test_id) {
@@ -210,10 +369,62 @@ void RootWindowManager::OnRootWindowDestroyed(RootWindow* root_window) {
if (it != root_windows_.end())
root_windows_.erase(it);
if (root_window == active_root_window_) {
active_root_window_ = NULL;
base::AutoLock lock_scope(active_browser_lock_);
active_browser_ = NULL;
}
if (terminate_when_all_windows_closed_ && root_windows_.empty()) {
// Quit the main message loop after all windows have closed.
MainMessageLoop::Get()->Quit();
}
}
void RootWindowManager::OnRootWindowActivated(RootWindow* root_window) {
REQUIRE_MAIN_THREAD();
if (root_window->WithExtension()) {
// We don't want extension apps to become the active RootWindow.
return;
}
if (root_window == active_root_window_)
return;
active_root_window_ = root_window;
{
base::AutoLock lock_scope(active_browser_lock_);
// May be NULL at this point, in which case we'll make the association in
// OnBrowserCreated.
active_browser_ = active_root_window_->GetBrowser();
}
}
void RootWindowManager::OnBrowserCreated(RootWindow* root_window,
CefRefPtr<CefBrowser> browser) {
REQUIRE_MAIN_THREAD();
if (root_window == active_root_window_) {
base::AutoLock lock_scope(active_browser_lock_);
active_browser_ = browser;
}
}
void RootWindowManager::CreateExtensionWindow(
CefRefPtr<CefExtension> extension,
const CefRect& source_bounds,
CefRefPtr<CefWindow> parent_window,
const base::Closure& close_callback,
bool with_osr) {
REQUIRE_MAIN_THREAD();
if (!HasRootWindowAsExtension(extension)) {
CreateRootWindowAsExtension(extension, source_bounds, parent_window,
close_callback, false, with_osr);
}
}
} // namespace client

View File

@@ -10,6 +10,7 @@
#include "include/base/cef_scoped_ptr.h"
#include "include/cef_command_line.h"
#include "tests/cefclient/browser/image_cache.h"
#include "tests/cefclient/browser/root_window.h"
#include "tests/cefclient/browser/temp_window.h"
@@ -23,15 +24,9 @@ class RootWindowManager : public RootWindow::Delegate {
// 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 and location will be used.
// This method can be called from anywhere to create a new top-level window.
scoped_refptr<RootWindow> CreateRootWindow(bool with_controls,
bool with_osr,
const CefRect& bounds,
const std::string& url);
// Create a new top-level native window. This method can be called from
// anywhere.
scoped_refptr<RootWindow> CreateRootWindow(const RootWindowConfig& config);
// Create a new native popup window.
// If |with_controls| is true the window will show controls.
@@ -46,14 +41,46 @@ class RootWindowManager : public RootWindow::Delegate {
CefRefPtr<CefClient>& client,
CefBrowserSettings& settings);
// Create a new top-level native window to host |extension|.
// If |with_controls| is true the window will show controls.
// If |with_osr| is true the window will use off-screen rendering.
// This method can be called from anywhere.
scoped_refptr<RootWindow> CreateRootWindowAsExtension(
CefRefPtr<CefExtension> extension,
const CefRect& source_bounds,
CefRefPtr<CefWindow> parent_window,
const base::Closure& close_callback,
bool with_controls,
bool with_osr);
// Returns true if a window hosting |extension| currently exists. Must be
// called on the main thread.
bool HasRootWindowAsExtension(CefRefPtr<CefExtension> extension);
// Returns the RootWindow associated with the specified browser ID. Must be
// called on the main thread.
scoped_refptr<RootWindow> GetWindowForBrowser(int browser_id);
scoped_refptr<RootWindow> GetWindowForBrowser(int browser_id) const;
// Returns the currently active/foreground RootWindow. May return NULL. Must
// be called on the main thread.
scoped_refptr<RootWindow> GetActiveRootWindow() const;
// Returns the currently active/foreground browser. May return NULL. Safe to
// call from any thread.
CefRefPtr<CefBrowser> GetActiveBrowser() const;
// Close all existing windows. If |force| is true onunload handlers will not
// be executed.
void CloseAllWindows(bool force);
// Manage the set of loaded extensions. RootWindows will be notified via the
// OnExtensionsChanged method.
void AddExtension(CefRefPtr<CefExtension> extension);
bool request_context_per_browser() const {
return request_context_per_browser_;
}
private:
// Allow deletion via scoped_ptr only.
friend struct base::DefaultDeleter<RootWindowManager>;
@@ -61,14 +88,23 @@ class RootWindowManager : public RootWindow::Delegate {
~RootWindowManager();
void OnRootWindowCreated(scoped_refptr<RootWindow> root_window);
void NotifyExtensionsChanged();
// RootWindow::Delegate methods.
CefRefPtr<CefRequestContext> GetRequestContext(
RootWindow* root_window) OVERRIDE;
CefRefPtr<CefImage> GetDefaultWindowIcon() OVERRIDE;
scoped_refptr<ImageCache> GetImageCache() OVERRIDE;
void OnTest(RootWindow* root_window, int test_id) OVERRIDE;
void OnExit(RootWindow* root_window) OVERRIDE;
void OnRootWindowDestroyed(RootWindow* root_window) OVERRIDE;
void OnRootWindowActivated(RootWindow* root_window) OVERRIDE;
void OnBrowserCreated(RootWindow* root_window,
CefRefPtr<CefBrowser> browser) OVERRIDE;
void CreateExtensionWindow(CefRefPtr<CefExtension> extension,
const CefRect& source_bounds,
CefRefPtr<CefWindow> parent_window,
const base::Closure& close_callback,
bool with_osr) OVERRIDE;
const bool terminate_when_all_windows_closed_;
bool request_context_per_browser_;
@@ -78,11 +114,24 @@ class RootWindowManager : public RootWindow::Delegate {
typedef std::set<scoped_refptr<RootWindow>> RootWindowSet;
RootWindowSet root_windows_;
// The currently active/foreground RootWindow. Only accessed on the main
// thread.
scoped_refptr<RootWindow> active_root_window_;
// The currently active/foreground browser. Access is protected by
// |active_browser_lock_;
mutable base::Lock active_browser_lock_;
CefRefPtr<CefBrowser> active_browser_;
// Singleton window used as the temporary parent for popup browsers.
TempWindow temp_window_;
CefRefPtr<CefRequestContext> shared_request_context_;
CefRefPtr<CefImage> default_window_icon_;
// Loaded extensions. Only accessed on the main thread.
ExtensionSet extensions_;
scoped_refptr<ImageCache> image_cache_;
DISALLOW_COPY_AND_ASSIGN(RootWindowManager);
};

View File

@@ -12,10 +12,19 @@
namespace client {
namespace {
// Images that are loaded early and cached.
static const char* kDefaultImageCache[] = {"menu_icon", "window_icon"};
} // namespace
RootWindowViews::RootWindowViews()
: delegate_(NULL),
with_controls_(false),
: with_controls_(false),
with_extension_(false),
initially_hidden_(false),
is_popup_(false),
position_on_resize_(false),
initialized_(false),
window_destroyed_(false),
browser_destroyed_(false) {}
@@ -25,23 +34,31 @@ RootWindowViews::~RootWindowViews() {
}
void RootWindowViews::Init(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefRect& bounds,
const CefBrowserSettings& settings,
const std::string& url) {
const RootWindowConfig& config,
const CefBrowserSettings& settings) {
DCHECK(delegate);
DCHECK(!with_osr); // Windowless rendering is not supported.
DCHECK(!config.with_osr); // Windowless rendering is not supported.
DCHECK(!initialized_);
delegate_ = delegate;
with_controls_ = with_controls;
initial_bounds_ = bounds;
CreateClientHandler(url);
with_controls_ = config.with_controls;
with_extension_ = config.with_extension;
initially_hidden_ = config.initially_hidden;
if (initially_hidden_ && !config.source_bounds.IsEmpty()) {
// The window will be sized and positioned in OnAutoResize().
initial_bounds_ = config.source_bounds;
position_on_resize_ = true;
} else {
initial_bounds_ = config.bounds;
}
parent_window_ = config.parent_window;
close_callback_ = config.close_callback;
CreateClientHandler(config.url);
initialized_ = true;
// Continue initialization on the main thread.
InitOnMainThread(settings, url);
InitOnMainThread(settings, config.url);
}
void RootWindowViews::InitAsPopup(RootWindow::Delegate* delegate,
@@ -167,20 +184,66 @@ ClientWindowHandle RootWindowViews::GetWindowHandle() const {
#endif
}
bool RootWindowViews::WithExtension() const {
REQUIRE_MAIN_THREAD();
return with_extension_;
}
bool RootWindowViews::WithControls() {
CEF_REQUIRE_UI_THREAD();
return with_controls_;
}
bool RootWindowViews::WithExtension() {
REQUIRE_MAIN_THREAD();
return with_extension_;
}
void RootWindowViews::OnExtensionsChanged(const ExtensionSet& extensions) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI, base::Bind(&RootWindowViews::OnExtensionsChanged, this,
extensions));
return;
}
if (window_) {
window_->OnExtensionsChanged(extensions);
} else {
// Window may not exist yet for popups.
pending_extensions_ = extensions;
}
}
bool RootWindowViews::InitiallyHidden() {
CEF_REQUIRE_UI_THREAD();
return initially_hidden_;
}
CefRefPtr<CefWindow> RootWindowViews::GetParentWindow() {
CEF_REQUIRE_UI_THREAD();
return parent_window_;
}
CefRect RootWindowViews::GetWindowBounds() {
CEF_REQUIRE_UI_THREAD();
return initial_bounds_;
}
scoped_refptr<ImageCache> RootWindowViews::GetImageCache() {
CEF_REQUIRE_UI_THREAD();
return image_cache_;
}
void RootWindowViews::OnViewsWindowCreated(CefRefPtr<ViewsWindow> window) {
CEF_REQUIRE_UI_THREAD();
DCHECK(!window_);
window_ = window;
if (!pending_extensions_.empty()) {
window_->OnExtensionsChanged(pending_extensions_);
pending_extensions_.clear();
}
}
void RootWindowViews::OnViewsWindowDestroyed(CefRefPtr<ViewsWindow> window) {
@@ -192,6 +255,14 @@ void RootWindowViews::OnViewsWindowDestroyed(CefRefPtr<ViewsWindow> window) {
base::Bind(&RootWindowViews::NotifyViewsWindowDestroyed, this));
}
void RootWindowViews::OnViewsWindowActivated(CefRefPtr<ViewsWindow> window) {
CEF_REQUIRE_UI_THREAD();
// Continue on the main thread.
MAIN_POST_CLOSURE(
base::Bind(&RootWindowViews::NotifyViewsWindowActivated, this));
}
ViewsWindow::Delegate* RootWindowViews::GetDelegateForPopup(
CefRefPtr<CefClient> client) {
CEF_REQUIRE_UI_THREAD();
@@ -199,9 +270,30 @@ ViewsWindow::Delegate* RootWindowViews::GetDelegateForPopup(
ClientHandlerStd* handler = static_cast<ClientHandlerStd*>(client.get());
RootWindowViews* root_window =
static_cast<RootWindowViews*>(handler->delegate());
// Transfer some state to the child RootWindowViews.
root_window->image_cache_ = image_cache_;
return root_window;
}
void RootWindowViews::CreateExtensionWindow(
CefRefPtr<CefExtension> extension,
const CefRect& source_bounds,
CefRefPtr<CefWindow> parent_window,
const base::Closure& close_callback) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(base::Bind(&RootWindowViews::CreateExtensionWindow, this,
extension, source_bounds, parent_window,
close_callback));
return;
}
delegate_->CreateExtensionWindow(extension, source_bounds, parent_window,
close_callback, false);
}
void RootWindowViews::OnTest(int test_id) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
@@ -226,6 +318,7 @@ void RootWindowViews::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
REQUIRE_MAIN_THREAD();
DCHECK(!browser_);
browser_ = browser;
delegate_->OnBrowserCreated(this, browser);
}
void RootWindowViews::OnBrowserClosing(CefRefPtr<CefBrowser> browser) {
@@ -293,6 +386,33 @@ void RootWindowViews::OnSetFullscreen(bool fullscreen) {
window_->SetFullscreen(fullscreen);
}
void RootWindowViews::OnAutoResize(const CefSize& new_size) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI,
base::Bind(&RootWindowViews::OnAutoResize, this, new_size));
return;
}
bool has_position = false;
CefPoint position;
if (position_on_resize_) {
// Position the window centered on and immediately below the source.
const int x_offset = (initial_bounds_.width - new_size.width) / 2;
position.Set(initial_bounds_.x + x_offset,
initial_bounds_.y + initial_bounds_.height);
has_position = true;
// Don't change the window position on future resizes.
position_on_resize_ = false;
}
if (window_) {
window_->SetBrowserSize(new_size, has_position, position);
window_->Show();
}
}
void RootWindowViews::OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) {
@@ -309,7 +429,8 @@ void RootWindowViews::OnSetLoadingState(bool isLoading,
if (isLoading) {
// Reset to the default window icon when loading begins.
window_->SetFavicon(delegate_->GetDefaultWindowIcon());
window_->SetFavicon(
delegate_->GetImageCache()->GetCachedImage("window_icon"));
}
}
}
@@ -360,22 +481,34 @@ void RootWindowViews::InitOnMainThread(const CefBrowserSettings& settings,
return;
}
CreateViewsWindow(settings, startup_url, delegate_->GetRequestContext(this));
image_cache_ = delegate_->GetImageCache();
// Populate the default image cache.
ImageCache::ImageInfoSet image_set;
for (size_t i = 0U; i < arraysize(kDefaultImageCache); ++i)
image_set.push_back(ImageCache::ImageInfo::Create2x(kDefaultImageCache[i]));
image_cache_->LoadImages(
image_set, base::Bind(&RootWindowViews::CreateViewsWindow, this, settings,
startup_url, delegate_->GetRequestContext(this)));
}
void RootWindowViews::CreateViewsWindow(
const CefBrowserSettings& settings,
const std::string& startup_url,
CefRefPtr<CefRequestContext> request_context) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI, base::Bind(&RootWindowViews::CreateViewsWindow, this,
settings, startup_url, request_context));
return;
}
CefRefPtr<CefRequestContext> request_context,
const ImageCache::ImageSet& images) {
CEF_REQUIRE_UI_THREAD();
DCHECK(!window_);
#ifndef NDEBUG
// Make sure the default images loaded successfully.
DCHECK_EQ(images.size(), arraysize(kDefaultImageCache));
for (size_t i = 0U; i < arraysize(kDefaultImageCache); ++i) {
DCHECK(images[i]) << "Default image " << i << " failed to load";
}
#endif
// Create the ViewsWindow. It will show itself after creation.
ViewsWindow::Create(this, client_handler_, startup_url, settings,
request_context);
@@ -387,10 +520,18 @@ void RootWindowViews::NotifyViewsWindowDestroyed() {
NotifyDestroyedIfDone();
}
void RootWindowViews::NotifyViewsWindowActivated() {
REQUIRE_MAIN_THREAD();
delegate_->OnRootWindowActivated(this);
}
void RootWindowViews::NotifyDestroyedIfDone() {
// Notify once both the window and the browser have been destroyed.
if (window_destroyed_ && browser_destroyed_)
if (window_destroyed_ && browser_destroyed_) {
delegate_->OnRootWindowDestroyed(this);
if (!close_callback_.is_null())
close_callback_.Run();
}
}
} // namespace client

View File

@@ -28,11 +28,8 @@ class RootWindowViews : public RootWindow,
// RootWindow methods:
void Init(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefRect& rect,
const CefBrowserSettings& settings,
const std::string& url) OVERRIDE;
const RootWindowConfig& config,
const CefBrowserSettings& settings) OVERRIDE;
void InitAsPopup(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
@@ -48,16 +45,28 @@ class RootWindowViews : public RootWindow,
float GetDeviceScaleFactor() const OVERRIDE;
CefRefPtr<CefBrowser> GetBrowser() const OVERRIDE;
ClientWindowHandle GetWindowHandle() const OVERRIDE;
bool WithWindowlessRendering() const OVERRIDE { return false; }
bool WithExtension() const OVERRIDE;
void OnExtensionsChanged(const ExtensionSet& extensions) OVERRIDE;
// ViewsWindow::Delegate methods:
bool WithControls() OVERRIDE;
bool WithExtension() OVERRIDE;
bool InitiallyHidden() OVERRIDE;
CefRefPtr<CefWindow> GetParentWindow() OVERRIDE;
CefRect GetWindowBounds() OVERRIDE;
scoped_refptr<ImageCache> GetImageCache() OVERRIDE;
void OnViewsWindowCreated(CefRefPtr<ViewsWindow> window) OVERRIDE;
void OnViewsWindowDestroyed(CefRefPtr<ViewsWindow> window) OVERRIDE;
void OnViewsWindowActivated(CefRefPtr<ViewsWindow> window) OVERRIDE;
ViewsWindow::Delegate* GetDelegateForPopup(
CefRefPtr<CefClient> client) OVERRIDE;
virtual void OnTest(int test_id) OVERRIDE;
virtual void OnExit() OVERRIDE;
void CreateExtensionWindow(CefRefPtr<CefExtension> extension,
const CefRect& source_bounds,
CefRefPtr<CefWindow> parent_window,
const base::Closure& close_callback) OVERRIDE;
void OnTest(int test_id) OVERRIDE;
void OnExit() OVERRIDE;
protected:
// ClientHandler::Delegate methods:
@@ -68,6 +77,7 @@ class RootWindowViews : public RootWindow,
void OnSetTitle(const std::string& title) OVERRIDE;
void OnSetFavicon(CefRefPtr<CefImage> image) OVERRIDE;
void OnSetFullscreen(bool fullscreen) OVERRIDE;
void OnAutoResize(const CefSize& new_size) OVERRIDE;
void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) OVERRIDE;
@@ -83,18 +93,24 @@ class RootWindowViews : public RootWindow,
const std::string& startup_url);
void CreateViewsWindow(const CefBrowserSettings& settings,
const std::string& startup_url,
CefRefPtr<CefRequestContext> request_context);
CefRefPtr<CefRequestContext> request_context,
const ImageCache::ImageSet& images);
void NotifyViewsWindowDestroyed();
void NotifyViewsWindowActivated();
void NotifyDestroyedIfDone();
// After initialization all members are only accessed on the main thread
// unless otherwise indicated.
// Members set during initialization.
RootWindow::Delegate* delegate_;
bool with_controls_;
bool with_extension_;
bool initially_hidden_;
CefRefPtr<CefWindow> parent_window_;
bool is_popup_;
CefRect initial_bounds_;
base::Closure close_callback_;
bool position_on_resize_;
CefRefPtr<ClientHandler> client_handler_;
bool initialized_;
@@ -105,6 +121,8 @@ class RootWindowViews : public RootWindow,
// Only accessed on the browser process UI thread.
CefRefPtr<ViewsWindow> window_;
ExtensionSet pending_extensions_;
scoped_refptr<ImageCache> image_cache_;
DISALLOW_COPY_AND_ASSIGN(RootWindowViews);
};

View File

@@ -51,7 +51,8 @@ int GetButtonWidth() {
static bool initialized = false;
if (!initialized) {
button_width = LogicalToDevice(BUTTON_WIDTH, GetDeviceScaleFactor());
button_width =
LogicalToDevice(BUTTON_WIDTH, client::GetDeviceScaleFactor());
initialized = true;
}
@@ -63,7 +64,8 @@ int GetURLBarHeight() {
static bool initialized = false;
if (!initialized) {
urlbar_height = LogicalToDevice(URLBAR_HEIGHT, GetDeviceScaleFactor());
urlbar_height =
LogicalToDevice(URLBAR_HEIGHT, client::GetDeviceScaleFactor());
initialized = true;
}
@@ -73,9 +75,9 @@ int GetURLBarHeight() {
} // namespace
RootWindowWin::RootWindowWin()
: delegate_(NULL),
with_controls_(false),
: with_controls_(false),
with_osr_(false),
with_extension_(false),
is_popup_(false),
start_rect_(),
initialized_(false),
@@ -114,33 +116,31 @@ RootWindowWin::~RootWindowWin() {
}
void RootWindowWin::Init(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefRect& bounds,
const CefBrowserSettings& settings,
const std::string& url) {
const RootWindowConfig& config,
const CefBrowserSettings& settings) {
DCHECK(delegate);
DCHECK(!initialized_);
delegate_ = delegate;
with_controls_ = with_controls;
with_osr_ = with_osr;
with_controls_ = config.with_controls;
with_osr_ = config.with_osr;
with_extension_ = config.with_extension;
start_rect_.left = bounds.x;
start_rect_.top = bounds.y;
start_rect_.right = bounds.x + bounds.width;
start_rect_.bottom = bounds.y + bounds.height;
start_rect_.left = config.bounds.x;
start_rect_.top = config.bounds.y;
start_rect_.right = config.bounds.x + config.bounds.width;
start_rect_.bottom = config.bounds.y + config.bounds.height;
CreateBrowserWindow(url);
CreateBrowserWindow(config.url);
initialized_ = true;
// Create the native root window on the main thread.
if (CURRENTLY_ON_MAIN_THREAD()) {
CreateRootWindow(settings);
CreateRootWindow(settings, config.initially_hidden);
} else {
MAIN_POST_CLOSURE(
base::Bind(&RootWindowWin::CreateRootWindow, this, settings));
MAIN_POST_CLOSURE(base::Bind(&RootWindowWin::CreateRootWindow, this,
settings, config.initially_hidden));
}
}
@@ -233,16 +233,18 @@ void RootWindowWin::Close(bool force) {
void RootWindowWin::SetDeviceScaleFactor(float device_scale_factor) {
REQUIRE_MAIN_THREAD();
if (browser_window_)
if (browser_window_ && with_osr_)
browser_window_->SetDeviceScaleFactor(device_scale_factor);
}
float RootWindowWin::GetDeviceScaleFactor() const {
REQUIRE_MAIN_THREAD();
if (browser_window_)
if (browser_window_ && with_osr_)
return browser_window_->GetDeviceScaleFactor();
return client::GetDeviceScaleFactor();
NOTREACHED();
return 0.0f;
}
CefRefPtr<CefBrowser> RootWindowWin::GetBrowser() const {
@@ -258,6 +260,16 @@ ClientWindowHandle RootWindowWin::GetWindowHandle() const {
return hwnd_;
}
bool RootWindowWin::WithWindowlessRendering() const {
REQUIRE_MAIN_THREAD();
return with_osr_;
}
bool RootWindowWin::WithExtension() const {
REQUIRE_MAIN_THREAD();
return with_extension_;
}
void RootWindowWin::CreateBrowserWindow(const std::string& startup_url) {
if (with_osr_) {
OsrRenderer::Settings settings = {};
@@ -268,7 +280,8 @@ void RootWindowWin::CreateBrowserWindow(const std::string& startup_url) {
}
}
void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings) {
void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings,
bool initially_hidden) {
REQUIRE_MAIN_THREAD();
DCHECK(!hwnd_);
@@ -415,8 +428,10 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings) {
rect.right - rect.left, rect.bottom - rect.top);
}
// Show this window.
Show(ShowNormal);
if (!initially_hidden) {
// Show this window.
Show(ShowNormal);
}
}
// static
@@ -556,6 +571,11 @@ LRESULT CALLBACK RootWindowWin::RootWndProc(HWND hWnd,
self->OnPaint();
return 0;
case WM_ACTIVATE:
self->OnActivate(LOWORD(wParam) != WA_INACTIVE);
// Allow DefWindowProc to set keyboard focus.
break;
case WM_SETFOCUS:
self->OnFocus();
return 0;
@@ -631,6 +651,11 @@ void RootWindowWin::OnFocus() {
browser_window_->SetFocus(true);
}
void RootWindowWin::OnActivate(bool active) {
if (active)
delegate_->OnRootWindowActivated(this);
}
void RootWindowWin::OnSize(bool minimized) {
if (minimized) {
// Notify the browser window that it was hidden and do nothing further.
@@ -825,11 +850,13 @@ void RootWindowWin::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
if (is_popup_) {
// For popup browsers create the root window once the browser has been
// created.
CreateRootWindow(CefBrowserSettings());
CreateRootWindow(CefBrowserSettings(), false);
} else {
// Make sure the browser is sized correctly.
OnSize(false);
}
delegate_->OnBrowserCreated(this, browser);
}
void RootWindowWin::OnBrowserWindowDestroyed() {
@@ -876,6 +903,36 @@ void RootWindowWin::OnSetFullscreen(bool fullscreen) {
}
}
void RootWindowWin::OnAutoResize(const CefSize& new_size) {
REQUIRE_MAIN_THREAD();
if (!hwnd_)
return;
int new_width = new_size.width;
// Make the window wide enough to drag by the top menu bar.
if (new_width < 200)
new_width = 200;
RECT rect = {
0, 0, LogicalToDevice(new_width, client::GetDeviceScaleFactor()),
LogicalToDevice(new_size.height, client::GetDeviceScaleFactor())};
DWORD style = GetWindowLong(hwnd_, GWL_STYLE);
DWORD ex_style = GetWindowLong(hwnd_, GWL_EXSTYLE);
bool has_menu = !(style & WS_CHILD) && (GetMenu(hwnd_) != NULL);
// The size value is for the client area. Calculate the whole window size
// based on the current style.
AdjustWindowRectEx(&rect, style, has_menu, ex_style);
// Size the window. The left/top values may be negative.
// Also show the window if it's not currently visible.
SetWindowPos(hwnd_, NULL, 0, 0, rect.right - rect.left,
rect.bottom - rect.top,
SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
}
void RootWindowWin::OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) {

View File

@@ -29,11 +29,8 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
// RootWindow methods.
void Init(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
const CefRect& rect,
const CefBrowserSettings& settings,
const std::string& url) OVERRIDE;
const RootWindowConfig& config,
const CefBrowserSettings& settings) OVERRIDE;
void InitAsPopup(RootWindow::Delegate* delegate,
bool with_controls,
bool with_osr,
@@ -49,10 +46,13 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
float GetDeviceScaleFactor() const OVERRIDE;
CefRefPtr<CefBrowser> GetBrowser() const OVERRIDE;
ClientWindowHandle GetWindowHandle() const OVERRIDE;
bool WithWindowlessRendering() const OVERRIDE;
bool WithExtension() const OVERRIDE;
private:
void CreateBrowserWindow(const std::string& startup_url);
void CreateRootWindow(const CefBrowserSettings& settings);
void CreateRootWindow(const CefBrowserSettings& settings,
bool initially_hidden);
// Register the root window class.
static void RegisterRootClass(HINSTANCE hInstance,
@@ -80,6 +80,7 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
// Event handlers.
void OnPaint();
void OnFocus();
void OnActivate(bool active);
void OnSize(bool minimized);
void OnMove();
bool OnEraseBkgnd();
@@ -96,6 +97,7 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
void OnSetAddress(const std::string& url) OVERRIDE;
void OnSetTitle(const std::string& title) OVERRIDE;
void OnSetFullscreen(bool fullscreen) OVERRIDE;
void OnAutoResize(const CefSize& new_size) OVERRIDE;
void OnSetLoadingState(bool isLoading,
bool canGoBack,
bool canGoForward) OVERRIDE;
@@ -106,9 +108,9 @@ class RootWindowWin : public RootWindow, public BrowserWindow::Delegate {
// After initialization all members are only accessed on the main thread.
// Members set during initialization.
RootWindow::Delegate* delegate_;
bool with_controls_;
bool with_osr_;
bool with_extension_;
bool is_popup_;
RECT start_rect_;
scoped_ptr<BrowserWindow> browser_window_;

View File

@@ -119,11 +119,10 @@ void RunRequestTest(CefRefPtr<CefBrowser> browser) {
}
void RunNewWindowTest(CefRefPtr<CefBrowser> browser) {
MainContext::Get()->GetRootWindowManager()->CreateRootWindow(
true, // Show controls.
browser->GetHost()->IsWindowRenderingDisabled(),
CefRect(), // Use default system size.
std::string()); // Use default URL.
RootWindowConfig config;
config.with_controls = true;
config.with_osr = browser->GetHost()->IsWindowRenderingDisabled();
MainContext::Get()->GetRootWindowManager()->CreateRootWindow(config);
}
void RunPopupWindowTest(CefRefPtr<CefBrowser> browser) {
@@ -680,8 +679,9 @@ void SetupResourceManager(CefRefPtr<CefResourceManager> resource_manager) {
// Add provider for bundled resource files.
#if defined(OS_WIN)
// Read resources from the binary.
resource_manager->AddProvider(CreateBinaryResourceProvider(test_origin), 100,
std::string());
resource_manager->AddProvider(
CreateBinaryResourceProvider(test_origin, std::string()), 100,
std::string());
#elif defined(OS_POSIX)
// Read resources from a directory on disk.
std::string resource_dir;
@@ -693,6 +693,14 @@ void SetupResourceManager(CefRefPtr<CefResourceManager> resource_manager) {
}
void Alert(CefRefPtr<CefBrowser> browser, const std::string& message) {
if (browser->GetHost()->GetExtension()) {
// Alerts originating from extension hosts should instead be displayed in
// the active browser.
browser = MainContext::Get()->GetRootWindowManager()->GetActiveBrowser();
if (!browser)
return;
}
// Escape special characters in the message.
std::string msg = StringReplace(message, "\\", "\\\\");
msg = StringReplace(msg, "'", "\\'");

View File

@@ -147,8 +147,10 @@ void ViewsMenuBar::Reset() {
id_next_ = id_start_;
}
void ViewsMenuBar::OnMenuButtonPressed(CefRefPtr<CefMenuButton> menu_button,
const CefPoint& screen_point) {
void ViewsMenuBar::OnMenuButtonPressed(
CefRefPtr<CefMenuButton> menu_button,
const CefPoint& screen_point,
CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) {
CefRefPtr<CefMenuModel> menu_model = GetMenuModel(menu_button->GetID());
// Adjust menu position left by button width.

View File

@@ -73,8 +73,10 @@ class ViewsMenuBar : public CefMenuButtonDelegate, public CefMenuModelDelegate {
void OnButtonPressed(CefRefPtr<CefButton> button) OVERRIDE {}
// CefMenuButtonDelegate methods:
void OnMenuButtonPressed(CefRefPtr<CefMenuButton> menu_button,
const CefPoint& screen_point) OVERRIDE;
void OnMenuButtonPressed(
CefRefPtr<CefMenuButton> menu_button,
const CefPoint& screen_point,
CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) OVERRIDE;
// CefMenuModelDelegate methods:
void ExecuteCommand(CefRefPtr<CefMenuModel> menu_model,

View File

@@ -13,10 +13,11 @@
#include "include/wrapper/cef_helpers.h"
#include "tests/cefclient/browser/resource.h"
#include "tests/cefclient/browser/views_style.h"
#include "tests/shared/browser/resource_util.h"
#include "tests/shared/browser/extension_util.h"
#include "tests/shared/common/client_switches.h"
#if !defined(OS_WIN)
#define VK_ESCAPE 0x1B
#define VK_RETURN 0x0D
#define VK_MENU 0x12 // ALT key.
#endif
@@ -25,6 +26,8 @@ namespace client {
namespace {
const char kDefaultExtensionIcon[] = "window_icon";
// Control IDs for Views in the top-level Window.
enum ControlIds {
ID_WINDOW = 1,
@@ -39,6 +42,10 @@ enum ControlIds {
// Reserved range of top menu button IDs.
ID_TOP_MENU_FIRST,
ID_TOP_MENU_LAST = ID_TOP_MENU_FIRST + 10,
// Reserved range of extension button IDs.
ID_EXTENSION_BUTTON_FIRST,
ID_EXTENSION_BUTTON_LAST = ID_EXTENSION_BUTTON_FIRST + 10,
};
typedef std::vector<CefRefPtr<CefLabelButton>> LabelButtons;
@@ -122,6 +129,10 @@ void ViewsWindow::Show() {
CEF_REQUIRE_UI_THREAD();
if (window_)
window_->Show();
if (browser_view_) {
// Give keyboard focus to the BrowserView.
browser_view_->RequestFocus();
}
}
void ViewsWindow::Hide() {
@@ -148,6 +159,19 @@ void ViewsWindow::SetBounds(const CefRect& bounds) {
window_->SetBounds(bounds);
}
void ViewsWindow::SetBrowserSize(const CefSize& size,
bool has_position,
const CefPoint& position) {
CEF_REQUIRE_UI_THREAD();
if (browser_view_)
browser_view_->SetSize(size);
if (window_) {
window_->SizeToPreferredSize();
if (has_position)
window_->SetPosition(position);
}
}
void ViewsWindow::Close(bool force) {
CEF_REQUIRE_UI_THREAD();
if (!browser_view_)
@@ -251,21 +275,75 @@ void ViewsWindow::OnBeforeContextMenu(CefRefPtr<CefMenuModel> model) {
views_style::ApplyTo(model);
}
bool ViewsWindow::OnPopupBrowserViewCreated(
void ViewsWindow::OnExtensionsChanged(const ExtensionSet& extensions) {
CEF_REQUIRE_UI_THREAD();
if (extensions.empty()) {
if (!extensions_.empty()) {
extensions_.clear();
UpdateExtensionControls();
}
return;
}
ImageCache::ImageInfoSet image_set;
ExtensionSet::const_iterator it = extensions.begin();
for (; it != extensions.end(); ++it) {
CefRefPtr<CefExtension> extension = *it;
bool internal = false;
const std::string& icon_path =
extension_util::GetExtensionIconPath(extension, &internal);
if (!icon_path.empty()) {
// Load the extension icon.
image_set.push_back(
ImageCache::ImageInfo::Create1x(icon_path, icon_path, internal));
} else {
// Get a NULL image and use the default icon.
image_set.push_back(ImageCache::ImageInfo::Empty());
}
}
delegate_->GetImageCache()->LoadImages(
image_set,
base::Bind(&ViewsWindow::OnExtensionIconsLoaded, this, extensions));
}
CefRefPtr<CefBrowserViewDelegate> ViewsWindow::GetDelegateForPopupBrowserView(
CefRefPtr<CefBrowserView> browser_view,
CefRefPtr<CefBrowserView> popup_browser_view,
const CefBrowserSettings& settings,
CefRefPtr<CefClient> client,
bool is_devtools) {
CEF_REQUIRE_UI_THREAD();
// The popup browser client is created in CefLifeSpanHandler::OnBeforePopup()
// (e.g. via RootWindowViews::InitAsPopup()). The Delegate (RootWindowViews)
// knows the association between |client| and itself.
Delegate* popup_delegate = delegate_->GetDelegateForPopup(
popup_browser_view->GetBrowser()->GetHost()->GetClient());
Delegate* popup_delegate = delegate_->GetDelegateForPopup(client);
// Should not be the same RootWindowViews that owns |this|.
DCHECK(popup_delegate && popup_delegate != delegate_);
// Create a new ViewsWindow for the popup BrowserView.
return new ViewsWindow(popup_delegate, NULL);
}
bool ViewsWindow::OnPopupBrowserViewCreated(
CefRefPtr<CefBrowserView> browser_view,
CefRefPtr<CefBrowserView> popup_browser_view,
bool is_devtools) {
CEF_REQUIRE_UI_THREAD();
// Retrieve the ViewsWindow created in GetDelegateForPopupBrowserView.
CefRefPtr<ViewsWindow> popup_window =
new ViewsWindow(popup_delegate, popup_browser_view);
static_cast<ViewsWindow*>(static_cast<CefBrowserViewDelegate*>(
popup_browser_view->GetDelegate().get()));
// Should not be the same ViewsWindow as |this|.
DCHECK(popup_window && popup_window != this);
// Associate the ViewsWindow with the new popup browser.
popup_window->SetBrowserView(popup_browser_view);
// Create a new top-level Window for the popup. It will show itself after
// creation.
@@ -307,11 +385,32 @@ void ViewsWindow::OnButtonPressed(CefRefPtr<CefButton> button) {
}
}
void ViewsWindow::OnMenuButtonPressed(CefRefPtr<CefMenuButton> menu_button,
const CefPoint& screen_point) {
void ViewsWindow::OnMenuButtonPressed(
CefRefPtr<CefMenuButton> menu_button,
const CefPoint& screen_point,
CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) {
CEF_REQUIRE_UI_THREAD();
const int id = menu_button->GetID();
if (id >= ID_EXTENSION_BUTTON_FIRST && id <= ID_EXTENSION_BUTTON_LAST) {
const size_t extension_idx = id - ID_EXTENSION_BUTTON_FIRST;
if (extension_idx >= extensions_.size()) {
LOG(ERROR) << "Invalid extension index " << extension_idx;
return;
}
// Keep the button pressed until the extension window is closed.
extension_button_pressed_lock_ = button_pressed_lock;
// Create a window for the extension.
delegate_->CreateExtensionWindow(
extensions_[extension_idx].extension_, menu_button->GetBoundsInScreen(),
window_, base::Bind(&ViewsWindow::OnExtensionWindowClosed, this));
return;
}
DCHECK(with_controls_);
DCHECK_EQ(ID_MENU_BUTTON, menu_button->GetID());
DCHECK_EQ(ID_MENU_BUTTON, id);
menu_button->ShowMenu(button_menu_model_, screen_point,
CEF_MENU_ANCHOR_TOPRIGHT);
@@ -399,15 +498,16 @@ void ViewsWindow::OnWindowCreated(CefRefPtr<CefWindow> window) {
// Add the BrowserView as the only child of the Window.
window_->AddChildView(browser_view_);
// Choose a reasonable minimum window size.
minimum_window_size_ = CefSize(100, 100);
if (!delegate_->WithExtension()) {
// Choose a reasonable minimum window size.
minimum_window_size_ = CefSize(100, 100);
}
}
// Show the Window.
window_->Show();
// Give keyboard focus to the BrowserView.
browser_view_->RequestFocus();
if (!delegate_->InitiallyHidden()) {
// Show the Window.
Show();
}
}
void ViewsWindow::OnWindowDestroyed(CefRefPtr<CefWindow> window) {
@@ -422,6 +522,7 @@ void ViewsWindow::OnWindowDestroyed(CefRefPtr<CefWindow> window) {
top_menu_bar_->Reset();
top_menu_bar_ = NULL;
}
extensions_panel_ = NULL;
window_ = NULL;
}
@@ -435,11 +536,32 @@ bool ViewsWindow::CanClose(CefRefPtr<CefWindow> window) {
return true;
}
CefRefPtr<CefWindow> ViewsWindow::GetParentWindow(CefRefPtr<CefWindow> window,
bool* is_menu,
bool* can_activate_menu) {
CEF_REQUIRE_UI_THREAD();
CefRefPtr<CefWindow> parent_window = delegate_->GetParentWindow();
if (parent_window) {
// Should be an extension window, in which case we want it to behave as a
// menu and allow activation.
DCHECK(delegate_->WithExtension());
*is_menu = true;
*can_activate_menu = true;
}
return parent_window;
}
bool ViewsWindow::IsFrameless(CefRefPtr<CefWindow> window) {
CEF_REQUIRE_UI_THREAD();
return frameless_;
}
bool ViewsWindow::CanResize(CefRefPtr<CefWindow> window) {
CEF_REQUIRE_UI_THREAD();
// Don't allow windows hosting extensions to resize.
return !delegate_->WithExtension();
}
bool ViewsWindow::OnAccelerator(CefRefPtr<CefWindow> window, int command_id) {
CEF_REQUIRE_UI_THREAD();
@@ -455,7 +577,17 @@ bool ViewsWindow::OnKeyEvent(CefRefPtr<CefWindow> window,
const CefKeyEvent& event) {
CEF_REQUIRE_UI_THREAD();
if (!window_ || !with_controls_)
if (!window_)
return false;
if (delegate_->WithExtension() && event.type == KEYEVENT_RAWKEYDOWN &&
event.windows_key_code == VK_ESCAPE) {
// Close the extension window on escape.
Close(false);
return true;
}
if (!with_controls_)
return false;
if (event.type == KEYEVENT_RAWKEYDOWN && event.windows_key_code == VK_MENU) {
@@ -509,6 +641,19 @@ void ViewsWindow::OnFocus(CefRefPtr<CefView> view) {
SetMenuFocusable(false);
}
}
if (view_id == ID_BROWSER_VIEW)
delegate_->OnViewsWindowActivated(this);
}
void ViewsWindow::OnBlur(CefRefPtr<CefView> view) {
CEF_REQUIRE_UI_THREAD();
const int view_id = view->GetID();
if (view_id == ID_BROWSER_VIEW && delegate_->WithExtension()) {
// Close windows hosting extensions when the browser loses focus.
Close(false);
}
}
void ViewsWindow::MenuBarExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
@@ -529,7 +674,8 @@ ViewsWindow::ViewsWindow(Delegate* delegate,
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
frameless_ = command_line->HasSwitch(switches::kHideFrame);
frameless_ = command_line->HasSwitch(switches::kHideFrame) ||
delegate_->WithExtension();
if (!command_line->HasSwitch(switches::kHideTopMenu)) {
top_menu_bar_ = new ViewsMenuBar(this, ID_TOP_MENU_FIRST);
@@ -609,7 +755,9 @@ void ViewsWindow::AddControls() {
CefRefPtr<CefMenuButton> menu_button =
CefMenuButton::CreateMenuButton(this, CefString(), false, false);
menu_button->SetID(ID_MENU_BUTTON);
menu_button->SetImage(CEF_BUTTON_STATE_NORMAL, LoadImageIcon("menu_icon"));
menu_button->SetImage(
CEF_BUTTON_STATE_NORMAL,
delegate_->GetImageCache()->GetCachedImage("menu_icon"));
views_style::ApplyTo(menu_button.get());
menu_button->SetInkDropEnabled(true);
// Override the default minimum size.
@@ -628,6 +776,11 @@ void ViewsWindow::AddControls() {
for (size_t i = 0U; i < browse_buttons.size(); ++i)
top_panel->AddChildView(browse_buttons[i]);
top_panel->AddChildView(url_textfield);
UpdateExtensionControls();
DCHECK(extensions_panel_);
top_panel->AddChildView(extensions_panel_);
top_panel->AddChildView(menu_button);
views_style::ApplyTo(top_panel);
@@ -718,4 +871,84 @@ void ViewsWindow::ShowTopControls(bool show) {
}
}
void ViewsWindow::UpdateExtensionControls() {
CEF_REQUIRE_UI_THREAD();
if (!window_ || !with_controls_)
return;
if (!extensions_panel_) {
extensions_panel_ = CefPanel::CreatePanel(NULL);
// Use a horizontal box layout for |top_panel|.
CefBoxLayoutSettings top_panel_layout_settings;
top_panel_layout_settings.horizontal = true;
CefRefPtr<CefBoxLayout> top_panel_layout =
extensions_panel_->SetToBoxLayout(top_panel_layout_settings);
} else {
extensions_panel_->RemoveAllChildViews();
}
if (extensions_.size() >
ID_EXTENSION_BUTTON_LAST - ID_EXTENSION_BUTTON_FIRST) {
LOG(WARNING) << "Too many extensions loaded. Some will be ignored.";
}
ExtensionInfoSet::const_iterator it = extensions_.begin();
for (int id = ID_EXTENSION_BUTTON_FIRST;
it != extensions_.end() && id <= ID_EXTENSION_BUTTON_LAST; ++id, ++it) {
CefRefPtr<CefMenuButton> button =
CefMenuButton::CreateMenuButton(this, CefString(), false, false);
button->SetID(id);
button->SetImage(CEF_BUTTON_STATE_NORMAL, (*it).image_);
views_style::ApplyTo(button.get());
button->SetInkDropEnabled(true);
// Override the default minimum size.
button->SetMinimumSize(CefSize(0, 0));
extensions_panel_->AddChildView(button);
}
CefRefPtr<CefView> parent_view = extensions_panel_->GetParentView();
if (parent_view)
parent_view->InvalidateLayout();
}
void ViewsWindow::OnExtensionIconsLoaded(const ExtensionSet& extensions,
const ImageCache::ImageSet& images) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI, base::Bind(&ViewsWindow::OnExtensionIconsLoaded, this,
extensions, images));
return;
}
DCHECK_EQ(extensions.size(), images.size());
extensions_.clear();
ExtensionSet::const_iterator it1 = extensions.begin();
ImageCache::ImageSet::const_iterator it2 = images.begin();
for (; it1 != extensions.end() && it2 != images.end(); ++it1, ++it2) {
CefRefPtr<CefImage> icon = *it2;
if (!icon)
icon = delegate_->GetImageCache()->GetCachedImage(kDefaultExtensionIcon);
extensions_.push_back(ExtensionInfo(*it1, icon));
}
UpdateExtensionControls();
}
void ViewsWindow::OnExtensionWindowClosed() {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI,
base::Bind(&ViewsWindow::OnExtensionWindowClosed, this));
return;
}
// Restore the button state.
extension_button_pressed_lock_ = NULL;
}
} // namespace client

View File

@@ -6,8 +6,11 @@
#define CEF_TESTS_CEFCLIENT_BROWSER_VIEWS_WINDOW_H_
#pragma once
#include <set>
#include <string>
#include <vector>
#include "include/base/cef_callback_forward.h"
#include "include/cef_menu_model_delegate.h"
#include "include/views/cef_browser_view.h"
#include "include/views/cef_browser_view_delegate.h"
@@ -19,10 +22,13 @@
#include "include/views/cef_textfield_delegate.h"
#include "include/views/cef_window.h"
#include "include/views/cef_window_delegate.h"
#include "tests/cefclient/browser/image_cache.h"
#include "tests/cefclient/browser/views_menu_bar.h"
namespace client {
typedef std::set<CefRefPtr<CefExtension>> ExtensionSet;
// Implements a CefWindow that hosts a single CefBrowserView and optional
// Views-based controls. All methods must be called on the browser process UI
// thread.
@@ -39,9 +45,21 @@ class ViewsWindow : public CefBrowserViewDelegate,
// Return true if the window should show controls.
virtual bool WithControls() = 0;
// Return true if the window is hosting an extension.
virtual bool WithExtension() = 0;
// Return true if the window should be created initially hidden.
virtual bool InitiallyHidden() = 0;
// Returns the parent for this window.
virtual CefRefPtr<CefWindow> GetParentWindow() = 0;
// Return the initial window bounds.
virtual CefRect GetWindowBounds() = 0;
// Returns the ImageCache.
virtual scoped_refptr<ImageCache> GetImageCache() = 0;
// Called when the ViewsWindow is created.
virtual void OnViewsWindowCreated(CefRefPtr<ViewsWindow> window) = 0;
@@ -49,9 +67,19 @@ class ViewsWindow : public CefBrowserViewDelegate,
// should be released in this callback.
virtual void OnViewsWindowDestroyed(CefRefPtr<ViewsWindow> window) = 0;
// Called when the ViewsWindow is activated (becomes the foreground window).
virtual void OnViewsWindowActivated(CefRefPtr<ViewsWindow> window) = 0;
// Return the Delegate for the popup window controlled by |client|.
virtual Delegate* GetDelegateForPopup(CefRefPtr<CefClient> client) = 0;
// Create a window for |extension|. |source_bounds| are the bounds of the
// UI element, like a button, that triggered the extension.
virtual void CreateExtensionWindow(CefRefPtr<CefExtension> extension,
const CefRect& source_bounds,
CefRefPtr<CefWindow> parent_window,
const base::Closure& close_callback) = 0;
// Called to execute a test. See resource.h for |test_id| values.
virtual void OnTest(int test_id) = 0;
@@ -76,6 +104,9 @@ class ViewsWindow : public CefBrowserViewDelegate,
void Minimize();
void Maximize();
void SetBounds(const CefRect& bounds);
void SetBrowserSize(const CefSize& size,
bool has_position,
const CefPoint& position);
void Close(bool force);
void SetAddress(const std::string& url);
void SetTitle(const std::string& title);
@@ -85,8 +116,14 @@ class ViewsWindow : public CefBrowserViewDelegate,
void SetDraggableRegions(const std::vector<CefDraggableRegion>& regions);
void TakeFocus(bool next);
void OnBeforeContextMenu(CefRefPtr<CefMenuModel> model);
void OnExtensionsChanged(const ExtensionSet& extensions);
// CefBrowserViewDelegate methods:
CefRefPtr<CefBrowserViewDelegate> GetDelegateForPopupBrowserView(
CefRefPtr<CefBrowserView> browser_view,
const CefBrowserSettings& settings,
CefRefPtr<CefClient> client,
bool is_devtools) OVERRIDE;
bool OnPopupBrowserViewCreated(CefRefPtr<CefBrowserView> browser_view,
CefRefPtr<CefBrowserView> popup_browser_view,
bool is_devtools) OVERRIDE;
@@ -95,8 +132,10 @@ class ViewsWindow : public CefBrowserViewDelegate,
void OnButtonPressed(CefRefPtr<CefButton> button) OVERRIDE;
// CefMenuButtonDelegate methods:
void OnMenuButtonPressed(CefRefPtr<CefMenuButton> menu_button,
const CefPoint& screen_point) OVERRIDE;
void OnMenuButtonPressed(
CefRefPtr<CefMenuButton> menu_button,
const CefPoint& screen_point,
CefRefPtr<CefMenuButtonPressedLock> button_pressed_lock) OVERRIDE;
// CefMenuModelDelegate methods:
void ExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
@@ -110,7 +149,11 @@ class ViewsWindow : public CefBrowserViewDelegate,
// CefWindowDelegate methods:
void OnWindowCreated(CefRefPtr<CefWindow> window) OVERRIDE;
void OnWindowDestroyed(CefRefPtr<CefWindow> window) OVERRIDE;
CefRefPtr<CefWindow> GetParentWindow(CefRefPtr<CefWindow> window,
bool* is_menu,
bool* can_activate_menu) OVERRIDE;
bool IsFrameless(CefRefPtr<CefWindow> window) OVERRIDE;
bool CanResize(CefRefPtr<CefWindow> window) OVERRIDE;
bool CanClose(CefRefPtr<CefWindow> window) OVERRIDE;
bool OnAccelerator(CefRefPtr<CefWindow> window, int command_id) OVERRIDE;
bool OnKeyEvent(CefRefPtr<CefWindow> window,
@@ -119,6 +162,7 @@ class ViewsWindow : public CefBrowserViewDelegate,
// CefViewDelegate methods:
CefSize GetMinimumSize(CefRefPtr<CefView> view) OVERRIDE;
void OnFocus(CefRefPtr<CefView> view) OVERRIDE;
void OnBlur(CefRefPtr<CefView> view) OVERRIDE;
// ViewsMenuBar::Delegate methods:
void MenuBarExecuteCommand(CefRefPtr<CefMenuModel> menu_model,
@@ -152,6 +196,13 @@ class ViewsWindow : public CefBrowserViewDelegate,
// Show/hide top controls on the Window.
void ShowTopControls(bool show);
// Update extension controls on the Window.
void UpdateExtensionControls();
void OnExtensionIconsLoaded(const ExtensionSet& extensions,
const ImageCache::ImageSet& images);
void OnExtensionWindowClosed();
Delegate* delegate_; // Not owned by this object.
CefRefPtr<CefBrowserView> browser_view_;
bool frameless_;
@@ -165,6 +216,20 @@ class ViewsWindow : public CefBrowserViewDelegate,
CefSize minimum_window_size_;
// Structure representing an extension.
struct ExtensionInfo {
ExtensionInfo(CefRefPtr<CefExtension> extension, CefRefPtr<CefImage> image)
: extension_(extension), image_(image) {}
CefRefPtr<CefExtension> extension_;
CefRefPtr<CefImage> image_;
};
typedef std::vector<ExtensionInfo> ExtensionInfoSet;
ExtensionInfoSet extensions_;
CefRefPtr<CefPanel> extensions_panel_;
CefRefPtr<CefMenuButtonPressedLock> extension_button_pressed_lock_;
IMPLEMENT_REFCOUNTING(ViewsWindow);
DISALLOW_COPY_AND_ASSIGN(ViewsWindow);
};