Merge pull request #60 from brightray/new-mac-devtools

Rewrite the devtools view for Chromium's new devtools architecture
This commit is contained in:
Cheng Zhao 2014-07-11 23:36:49 +08:00
commit 14235a65a9
33 changed files with 1082 additions and 1059 deletions

View file

@ -40,6 +40,8 @@
'browser/default_web_contents_delegate.cc',
'browser/default_web_contents_delegate.h',
'browser/default_web_contents_delegate_mac.mm',
'browser/devtools_contents_resizing_strategy.cc',
'browser/devtools_contents_resizing_strategy.h',
'browser/devtools_embedder_message_dispatcher.cc',
'browser/devtools_embedder_message_dispatcher.h',
'browser/devtools_ui.cc',
@ -54,13 +56,10 @@
'browser/inspectable_web_contents_view.h',
'browser/inspectable_web_contents_view_mac.h',
'browser/inspectable_web_contents_view_mac.mm',
'browser/linux/inspectable_web_contents_view_linux.h',
'browser/linux/inspectable_web_contents_view_linux.cc',
'browser/mac/bry_application.h',
'browser/mac/bry_application.mm',
'browser/mac/bry_inspectable_web_contents_view.h',
'browser/mac/bry_inspectable_web_contents_view.mm',
'browser/mac/bry_inspectable_web_contents_view_private.h',
'browser/media/media_capture_devices_dispatcher.cc',
'browser/media/media_capture_devices_dispatcher.h',
'browser/media/media_stream_devices_controller.cc',
@ -74,10 +73,10 @@
'browser/linux/notification_presenter_linux.cc',
'browser/url_request_context_getter.cc',
'browser/url_request_context_getter.h',
'browser/win/devtools_window.cc',
'browser/win/devtools_window.h',
'browser/win/inspectable_web_contents_view_win.cc',
'browser/win/inspectable_web_contents_view_win.h',
'browser/views/inspectable_web_contents_view_views.h',
'browser/views/inspectable_web_contents_view_views.cc',
'browser/views/views_delegate.cc',
'browser/views/views_delegate.h',
'browser/web_ui_controller_factory.cc',
'browser/web_ui_controller_factory.h',
'common/application_info.h',
@ -100,6 +99,7 @@
'link_settings': {
'libraries': [
'<(brightray_source_root)/<(libchromiumcontent_library_dir)/libchromiumcontent.so',
'<(brightray_source_root)/<(libchromiumcontent_library_dir)/libchromiumviews.a',
'-lpthread',
'<!@(pkg-config --libs gtk+-2.0 libnotify)',
],
@ -117,8 +117,8 @@
'link_settings': {
'libraries': [
'<(brightray_source_root)/<(libchromiumcontent_library_dir)/base_static.lib',
'<(brightray_source_root)/<(libchromiumcontent_library_dir)/chromiumviews.lib',
'<(brightray_source_root)/<(libchromiumcontent_library_dir)/chromiumcontent.dll.lib',
'<(brightray_source_root)/<(libchromiumcontent_library_dir)/chromiumviews.lib',
'<(brightray_source_root)/<(libchromiumcontent_library_dir)/sandbox_static.lib',
],
},

View file

@ -80,8 +80,9 @@
},
},
'conditions': [
['OS=="win"', {
['OS!="mac"', {
'defines': [
'TOOLKIT_VIEWS',
'USE_AURA',
'VIEWS_IMPLEMENTATION',
'WEBVIEW_IMPLEMENTATION',
@ -180,6 +181,11 @@
['exclude', '/mac/'],
['exclude', '_mac\.(mm|h)$'],
],
}, {
'sources/': [
['exclude', '/views/'],
['exclude', '_views\.(cc|h)$'],
],
}],
['OS!="win"', {
'sources/': [
@ -262,6 +268,7 @@
4481, # nonstandard extension used: override specifier 'override'
4512, # assignment operator could not be generated
4702, # unreachable code
4819, # The file contains a character that cannot be represented in the current code page
],
},
}],

View file

@ -9,6 +9,8 @@
#include "browser/media/media_capture_devices_dispatcher.h"
#include "browser/notification_presenter.h"
#include "content/public/common/url_constants.h"
namespace brightray {
namespace {
@ -88,4 +90,10 @@ content::MediaObserver* BrowserClient::GetMediaObserver() {
return MediaCaptureDevicesDispatcher::GetInstance();
}
void BrowserClient::GetAdditionalAllowedSchemesForFileSystem(
std::vector<std::string>* additional_schemes) {
additional_schemes->push_back(content::kChromeDevToolsScheme);
additional_schemes->push_back(content::kChromeUIScheme);
}
} // namespace brightray

View file

@ -51,6 +51,8 @@ class BrowserClient : public content::ContentBrowserClient {
int render_view_id,
int notification_id) OVERRIDE;
virtual content::MediaObserver* GetMediaObserver() OVERRIDE;
virtual void GetAdditionalAllowedSchemesForFileSystem(
std::vector<std::string>* additional_schemes) OVERRIDE;
BrowserMainParts* browser_main_parts_;
scoped_ptr<NotificationPresenter> notification_presenter_;

View file

@ -7,8 +7,22 @@
#include "browser/browser_context.h"
#include "browser/web_ui_controller_factory.h"
#include "net/proxy/proxy_resolver_v8.h"
#if defined(USE_AURA)
#include "ui/aura/env.h"
#include "ui/gfx/screen.h"
#include "ui/views/widget/desktop_aura/desktop_screen.h"
#endif
#if defined(USE_AURA) && defined(USE_X11)
#include "chrome/browser/ui/libgtk2ui/gtk2_ui.h"
#include "ui/views/linux_ui/linux_ui.h"
#include "ui/wm/core/wm_state.h"
#endif
#if defined(TOOLKIT_VIEWS)
#include "browser/views/views_delegate.h"
#endif
namespace brightray {
@ -18,6 +32,33 @@ BrowserMainParts::BrowserMainParts() {
BrowserMainParts::~BrowserMainParts() {
}
void BrowserMainParts::PreEarlyInitialization() {
#if defined(OS_MACOSX)
IncreaseFileDescriptorLimit();
#endif
#if defined(USE_AURA) && defined(USE_X11)
views::LinuxUI::SetInstance(BuildGtk2UI());
#endif
}
void BrowserMainParts::ToolkitInitialized() {
#if defined(USE_AURA) && defined(USE_X11)
views::LinuxUI::instance()->Initialize();
wm_state_.reset(new wm::WMState);
#endif
#if defined(TOOLKIT_VIEWS)
views_delegate_.reset(new ViewsDelegate);
#endif
}
void BrowserMainParts::PreMainMessageLoopStart() {
#if defined(OS_MACOSX)
InitializeMainNib();
#endif
}
void BrowserMainParts::PreMainMessageLoopRun() {
browser_context_.reset(CreateBrowserContext());
browser_context_->Initialize();
@ -26,22 +67,23 @@ void BrowserMainParts::PreMainMessageLoopRun() {
new WebUIControllerFactory(browser_context_.get()));
content::WebUIControllerFactory::RegisterFactory(
web_ui_controller_factory_.get());
#if defined(OS_WIN)
gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen());
#endif
}
void BrowserMainParts::PostMainMessageLoopRun() {
browser_context_.reset();
#if defined(USE_AURA)
aura::Env::DeleteInstance();
#endif
}
int BrowserMainParts::PreCreateThreads() {
#if defined(OS_WIN)
net::ProxyResolverV8::CreateIsolate();
#else
net::ProxyResolverV8::RememberDefaultIsolate();
#if defined(USE_AURA)
aura::Env::CreateInstance();
gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE,
views::CreateDesktopScreen());
#endif
InitProxyResolverV8();
return 0;
}
@ -49,4 +91,12 @@ BrowserContext* BrowserMainParts::CreateBrowserContext() {
return new BrowserContext;
}
void BrowserMainParts::InitProxyResolverV8() {
#if defined(OS_WIN)
net::ProxyResolverV8::CreateIsolate();
#else
net::ProxyResolverV8::RememberDefaultIsolate();
#endif
}
} // namespace brightray

View file

@ -9,6 +9,18 @@
#include "base/memory/scoped_ptr.h"
#include "content/public/browser/browser_main_parts.h"
#if defined(TOOLKIT_VIEWS)
namespace brightray {
class ViewsDelegate;
}
#endif
#if defined(USE_AURA) && defined(USE_X11)
namespace wm {
class WMState;
}
#endif
namespace brightray {
class BrowserContext;
@ -22,23 +34,38 @@ class BrowserMainParts : public content::BrowserMainParts {
BrowserContext* browser_context() { return browser_context_.get(); }
protected:
// Subclasses should override this to provide their own BrowserContxt
// implementation. The caller takes ownership of the returned object.
virtual BrowserContext* CreateBrowserContext();
#if defined(OS_MACOSX)
// content::BrowserMainParts:
virtual void PreEarlyInitialization() OVERRIDE;
virtual void ToolkitInitialized() OVERRIDE;
virtual void PreMainMessageLoopStart() OVERRIDE;
#endif
virtual void PreMainMessageLoopRun() OVERRIDE;
virtual void PostMainMessageLoopRun() OVERRIDE;
virtual int PreCreateThreads() OVERRIDE;
// Subclasses should override this to provide their own BrowserContxt
// implementation. The caller takes ownership of the returned object.
virtual BrowserContext* CreateBrowserContext();
// Override this to change how ProxyResolverV8 is initialized.
virtual void InitProxyResolverV8();
private:
#if defined(OS_MACOSX)
void IncreaseFileDescriptorLimit();
void InitializeMainNib();
#endif
scoped_ptr<BrowserContext> browser_context_;
scoped_ptr<WebUIControllerFactory> web_ui_controller_factory_;
#if defined(TOOLKIT_VIEWS)
scoped_ptr<ViewsDelegate> views_delegate_;
#endif
#if defined(USE_AURA) && defined(USE_X11)
scoped_ptr<wm::WMState> wm_state_;
#endif
DISALLOW_COPY_AND_ASSIGN(BrowserMainParts);
};

View file

@ -27,7 +27,7 @@ void SetFileDescriptorLimit(rlim_t max_descriptors) {
} // namespace
void BrowserMainParts::PreEarlyInitialization() {
void BrowserMainParts::IncreaseFileDescriptorLimit() {
// We use quite a few file descriptors for our IPC, and the default limit on the Mac is low (256),
// so bump it up.
// See http://src.chromium.org/viewvc/chrome/trunk/src/chrome/browser/chrome_browser_main_posix.cc?revision=244734#l295
@ -36,7 +36,7 @@ void BrowserMainParts::PreEarlyInitialization() {
}
// Replicates NSApplicationMain, but doesn't start a run loop.
void BrowserMainParts::PreMainMessageLoopStart() {
void BrowserMainParts::InitializeMainNib() {
auto infoDictionary = base::mac::OuterBundle().infoDictionary;
auto principalClass = NSClassFromString([infoDictionary objectForKey:@"NSPrincipalClass"]);

View file

@ -0,0 +1,85 @@
// Copyright 2014 The Chromium 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 "browser/devtools_contents_resizing_strategy.h"
#include <algorithm>
DevToolsContentsResizingStrategy::DevToolsContentsResizingStrategy() {
}
DevToolsContentsResizingStrategy::DevToolsContentsResizingStrategy(
const gfx::Insets& insets, const gfx::Size& min_size)
: insets_(insets),
min_size_(min_size) {
}
DevToolsContentsResizingStrategy::DevToolsContentsResizingStrategy(
const gfx::Rect& bounds)
: bounds_(bounds) {
}
void DevToolsContentsResizingStrategy::CopyFrom(
const DevToolsContentsResizingStrategy& strategy) {
insets_ = strategy.insets();
min_size_ = strategy.min_size();
bounds_ = strategy.bounds();
}
bool DevToolsContentsResizingStrategy::Equals(
const DevToolsContentsResizingStrategy& strategy) {
return insets_ == strategy.insets() && min_size_ == strategy.min_size() &&
bounds_ == strategy.bounds();
}
void ApplyDevToolsContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy,
const gfx::Size& container_size,
const gfx::Rect& old_devtools_bounds,
const gfx::Rect& old_contents_bounds,
gfx::Rect* new_devtools_bounds,
gfx::Rect* new_contents_bounds) {
new_devtools_bounds->SetRect(
0, 0, container_size.width(), container_size.height());
const gfx::Insets& insets = strategy.insets();
const gfx::Size& min_size = strategy.min_size();
const gfx::Rect& bounds = strategy.bounds();
if (!bounds.size().IsEmpty()) {
int left = std::min(bounds.x(), container_size.width());
int top = std::min(bounds.y(), container_size.height());
int width = std::min(bounds.width(), container_size.width() - left);
int height = std::min(bounds.height(), container_size.height() - top);
new_contents_bounds->SetRect(left, top, width, height);
return;
}
int width = std::max(0, container_size.width() - insets.width());
int left = insets.left();
if (width < min_size.width() && insets.width() > 0) {
int min_width = std::min(min_size.width(), container_size.width());
int insets_width = container_size.width() - min_width;
int insets_decrease = insets.width() - insets_width;
// Decrease both left and right insets proportionally.
left -= insets_decrease * insets.left() / insets.width();
width = min_width;
}
left = std::max(0, std::min(container_size.width(), left));
int height = std::max(0, container_size.height() - insets.height());
int top = insets.top();
if (height < min_size.height() && insets.height() > 0) {
int min_height = std::min(min_size.height(), container_size.height());
int insets_height = container_size.height() - min_height;
int insets_decrease = insets.height() - insets_height;
// Decrease both top and bottom insets proportionally.
top -= insets_decrease * insets.top() / insets.height();
height = min_height;
}
top = std::max(0, std::min(container_size.height(), top));
new_contents_bounds->SetRect(left, top, width, height);
}

View file

@ -0,0 +1,56 @@
// Copyright 2014 The Chromium 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 BRIGHTRAY_BROWSER_DEVTOOLS_CONTENTS_RESIZING_STRATEGY_H_
#define BRIGHTRAY_BROWSER_DEVTOOLS_CONTENTS_RESIZING_STRATEGY_H_
#include "base/basictypes.h"
#include "ui/gfx/insets.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
// This class knows how to resize both DevTools and inspected WebContents
// inside a browser window hierarchy.
class DevToolsContentsResizingStrategy {
public:
DevToolsContentsResizingStrategy();
DevToolsContentsResizingStrategy(
const gfx::Insets& insets,
const gfx::Size& min_size);
explicit DevToolsContentsResizingStrategy(const gfx::Rect& bounds);
void CopyFrom(const DevToolsContentsResizingStrategy& strategy);
bool Equals(const DevToolsContentsResizingStrategy& strategy);
const gfx::Insets& insets() const { return insets_; }
const gfx::Size& min_size() const { return min_size_; }
const gfx::Rect& bounds() const { return bounds_; }
private:
// Insets of contents inside DevTools.
gfx::Insets insets_;
// Minimum size of contents.
gfx::Size min_size_;
// Contents bounds. When non-empty, used instead of insets.
gfx::Rect bounds_;
DISALLOW_COPY_AND_ASSIGN(DevToolsContentsResizingStrategy);
};
// Applies contents resizing strategy, producing bounds for devtools and
// page contents views. Generally, page contents view is placed atop of devtools
// inside a common parent view, which size should be passed in |container_size|.
// When unknown, providing empty rect as previous devtools and contents bounds
// is allowed.
void ApplyDevToolsContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy,
const gfx::Size& container_size,
const gfx::Rect& old_devtools_bounds,
const gfx::Rect& old_contents_bounds,
gfx::Rect* new_devtools_bounds,
gfx::Rect* new_contents_bounds);
#endif // BRIGHTRAY_BROWSER_DEVTOOLS_CONTENTS_RESIZING_STRATEGY_H_

View file

@ -5,16 +5,12 @@
#include "browser/devtools_embedder_message_dispatcher.h"
#include "base/bind.h"
#include "base/json/json_reader.h"
#include "base/values.h"
namespace brightray {
namespace {
static const char kFrontendHostMethod[] = "method";
static const char kFrontendHostParams[] = "params";
bool GetValue(const base::ListValue& list, int pos, std::string& value) {
return list.GetString(pos, &value);
}
@ -27,6 +23,36 @@ bool GetValue(const base::ListValue& list, int pos, bool& value) {
return list.GetBoolean(pos, &value);
}
bool GetValue(const base::ListValue& list, int pos, gfx::Insets& insets) {
const base::DictionaryValue* dict;
if (!list.GetDictionary(pos, &dict))
return false;
int top = 0;
int left = 0;
int bottom = 0;
int right = 0;
if (!dict->GetInteger("top", &top) ||
!dict->GetInteger("left", &left) ||
!dict->GetInteger("bottom", &bottom) ||
!dict->GetInteger("right", &right))
return false;
insets.Set(top, left, bottom, right);
return true;
}
bool GetValue(const base::ListValue& list, int pos, gfx::Size& size) {
const base::DictionaryValue* dict;
if (!list.GetDictionary(pos, &dict))
return false;
int width = 0;
int height = 0;
if (!dict->GetInteger("width", &width) ||
!dict->GetInteger("height", &height))
return false;
size.SetSize(width, height);
return true;
}
template <typename T>
struct StorageTraits {
typedef T StorageType;
@ -105,6 +131,28 @@ bool ParseAndHandle3(const base::Callback<void(A1, A2, A3)>& handler,
return true;
}
template <class A1, class A2, class A3, class A4>
bool ParseAndHandle3(const base::Callback<void(A1, A2, A3, A4)>& handler,
const base::ListValue& list) {
if (list.GetSize() != 3)
return false;
Argument<A1> arg1(list, 0);
if (!arg1.valid())
return false;
Argument<A2> arg2(list, 1);
if (!arg2.valid())
return false;
Argument<A3> arg3(list, 2);
if (!arg3.valid())
return false;
Argument<A4> arg4(list, 3);
if (!arg4.valid())
return false;
handler.Run(arg1.value(), arg2.value(), arg3.value(), arg4.value());
return true;
}
typedef base::Callback<bool (const base::ListValue&)> ListValueParser;
ListValueParser BindToListParser(const base::Callback<void()>& handler) {
@ -127,6 +175,12 @@ ListValueParser BindToListParser(
return base::Bind(&ParseAndHandle3<A1, A2, A3>, handler);
}
template <class A1, class A2, class A3, class A4>
ListValueParser BindToListParser(
const base::Callback<void(A1, A2, A3, A4)>& handler) {
return base::Bind(&ParseAndHandle3<A1, A2, A3, A4>, handler);
}
} // namespace
DevToolsEmbedderMessageDispatcher::DevToolsEmbedderMessageDispatcher(
@ -137,11 +191,17 @@ DevToolsEmbedderMessageDispatcher::DevToolsEmbedderMessageDispatcher(
RegisterHandler("closeWindow",
BindToListParser(base::Bind(&Delegate::CloseWindow,
base::Unretained(delegate))));
RegisterHandler("setContentsResizingStrategy",
BindToListParser(base::Bind(&Delegate::SetContentsResizingStrategy,
base::Unretained(delegate))));
RegisterHandler("inspectElementCompleted",
BindToListParser(base::Bind(&Delegate::InspectElementCompleted,
base::Unretained(delegate))));
RegisterHandler("moveWindowBy",
BindToListParser(base::Bind(&Delegate::MoveWindow,
base::Unretained(delegate))));
RegisterHandler("requestSetDockSide",
BindToListParser(base::Bind(&Delegate::SetDockSide,
RegisterHandler("setIsDocked",
BindToListParser(base::Bind(&Delegate::SetIsDocked,
base::Unretained(delegate))));
RegisterHandler("openInNewTab",
BindToListParser(base::Bind(&Delegate::OpenInNewTab,
@ -161,6 +221,9 @@ DevToolsEmbedderMessageDispatcher::DevToolsEmbedderMessageDispatcher(
RegisterHandler("removeFileSystem",
BindToListParser(base::Bind(&Delegate::RemoveFileSystem,
base::Unretained(delegate))));
RegisterHandler("upgradeDraggedFileSystemPermissions",
BindToListParser(base::Bind(&Delegate::UpgradeDraggedFileSystemPermissions,
base::Unretained(delegate))));
RegisterHandler("indexPath",
BindToListParser(base::Bind(&Delegate::IndexPath,
base::Unretained(delegate))));
@ -170,34 +233,28 @@ DevToolsEmbedderMessageDispatcher::DevToolsEmbedderMessageDispatcher(
RegisterHandler("searchInPath",
BindToListParser(base::Bind(&Delegate::SearchInPath,
base::Unretained(delegate))));
RegisterHandler("zoomIn",
BindToListParser(base::Bind(&Delegate::ZoomIn,
base::Unretained(delegate))));
RegisterHandler("zoomOut",
BindToListParser(base::Bind(&Delegate::ZoomOut,
base::Unretained(delegate))));
RegisterHandler("resetZoom",
BindToListParser(base::Bind(&Delegate::ResetZoom,
base::Unretained(delegate))));
}
DevToolsEmbedderMessageDispatcher::~DevToolsEmbedderMessageDispatcher() {}
void DevToolsEmbedderMessageDispatcher::Dispatch(const std::string& message) {
std::string method;
base::ListValue empty_params;
base::ListValue* params = &empty_params;
base::DictionaryValue* dict;
scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
if (!parsed_message ||
!parsed_message->GetAsDictionary(&dict) ||
!dict->GetString(kFrontendHostMethod, &method) ||
(dict->HasKey(kFrontendHostParams) &&
!dict->GetList(kFrontendHostParams, &params))) {
LOG(ERROR) << "Cannot parse frontend host message: " << message;
return;
}
std::string DevToolsEmbedderMessageDispatcher::Dispatch(
const std::string& method, base::ListValue* params) {
HandlerMap::iterator it = handlers_.find(method);
if (it == handlers_.end()) {
LOG(ERROR) << "Unsupported frontend host method: " << message;
return;
}
if (it == handlers_.end())
return "Unsupported frontend host method: " + method;
if (!it->second.Run(*params))
LOG(ERROR) << "Invalid frontend host message parameters: " << message;
return "Invalid frontend host message parameters: " + method;
return "";
}
void DevToolsEmbedderMessageDispatcher::RegisterHandler(

View file

@ -9,6 +9,8 @@
#include <string>
#include "base/callback.h"
#include "ui/gfx/insets.h"
#include "ui/gfx/size.h"
namespace base {
class ListValue;
@ -30,8 +32,11 @@ class DevToolsEmbedderMessageDispatcher {
virtual void ActivateWindow() = 0;
virtual void CloseWindow() = 0;
virtual void SetContentsResizingStrategy(
const gfx::Insets& insets, const gfx::Size& min_size) = 0;
virtual void InspectElementCompleted() = 0;
virtual void MoveWindow(int x, int y) = 0;
virtual void SetDockSide(const std::string& side) = 0;
virtual void SetIsDocked(bool docked) = 0;
virtual void OpenInNewTab(const std::string& url) = 0;
virtual void SaveToFile(const std::string& url,
const std::string& content,
@ -41,19 +46,24 @@ class DevToolsEmbedderMessageDispatcher {
virtual void RequestFileSystems() = 0;
virtual void AddFileSystem() = 0;
virtual void RemoveFileSystem(const std::string& file_system_path) = 0;
virtual void UpgradeDraggedFileSystemPermissions(
const std::string& file_system_url) = 0;
virtual void IndexPath(int request_id,
const std::string& file_system_path) = 0;
virtual void StopIndexing(int request_id) = 0;
virtual void SearchInPath(int request_id,
const std::string& file_system_path,
const std::string& query) = 0;
virtual void ZoomIn() = 0;
virtual void ZoomOut() = 0;
virtual void ResetZoom() = 0;
};
explicit DevToolsEmbedderMessageDispatcher(Delegate* delegate);
~DevToolsEmbedderMessageDispatcher();
void Dispatch(const std::string& message);
std::string Dispatch(const std::string& method, base::ListValue* params);
private:
typedef base::Callback<bool (const base::ListValue&)> Handler;

View file

@ -9,18 +9,6 @@ class InspectableWebContentsDelegate {
public:
virtual ~InspectableWebContentsDelegate() {}
// Called when the devtools is going to change the dock side, returning true
// to override the default behavior.
// Receiver should set |succeed| to |false| if it failed to handle this.
virtual bool DevToolsSetDockSide(const std::string& side, bool* succeed) {
return false;
}
// Called when the devtools is going to be showed, returning true to override
// the default behavior.
// Receiver is given the chance to change the |dock_side|.
virtual bool DevToolsShow(std::string* dock_side) { return false; }
// Requested by WebContents of devtools.
virtual void DevToolsSaveToFile(
const std::string& url, const std::string& content, bool save_as) {}

View file

@ -11,41 +11,95 @@
#include "browser/inspectable_web_contents_delegate.h"
#include "browser/inspectable_web_contents_view.h"
#include "base/json/json_reader.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/prefs/pref_service.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_client_host.h"
#include "content/public/browser/devtools_http_handler.h"
#include "content/public/browser/devtools_manager.h"
#include "content/public/browser/web_contents_view.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
namespace brightray {
namespace {
const char kChromeUIDevToolsURL[] = "chrome-devtools://devtools/devtools.html";
const char kDockSidePref[] = "brightray.devtools.dockside";
const char kChromeUIDevToolsURL[] = "chrome-devtools://devtools/devtools.html?can_dock=true";
const char kDevToolsBoundsPref[] = "brightray.devtools.bounds";
const char kFrontendHostId[] = "id";
const char kFrontendHostMethod[] = "method";
const char kFrontendHostParams[] = "params";
void RectToDictionary(const gfx::Rect& bounds, base::DictionaryValue* dict) {
dict->SetInteger("x", bounds.x());
dict->SetInteger("y", bounds.y());
dict->SetInteger("width", bounds.width());
dict->SetInteger("height", bounds.height());
}
void DictionaryToRect(const base::DictionaryValue& dict, gfx::Rect* bounds) {
int x = 0, y = 0, width = 800, height = 600;
dict.GetInteger("x", &x);
dict.GetInteger("y", &y);
dict.GetInteger("width", &width);
dict.GetInteger("height", &height);
*bounds = gfx::Rect(x, y, width, height);
}
bool ParseMessage(const std::string& message,
std::string* method,
base::ListValue* params,
int* id) {
scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
if (!parsed_message)
return false;
base::DictionaryValue* dict = NULL;
if (!parsed_message->GetAsDictionary(&dict))
return false;
if (!dict->GetString(kFrontendHostMethod, method))
return false;
// "params" is optional.
if (dict->HasKey(kFrontendHostParams)) {
base::ListValue* internal_params;
if (dict->GetList(kFrontendHostParams, &internal_params))
params->Swap(internal_params);
else
return false;
}
*id = 0;
dict->GetInteger(kFrontendHostId, id);
return true;
}
} // namespace
// Implemented separately on each platform.
InspectableWebContentsView* CreateInspectableContentsView(
InspectableWebContentsImpl* inspectable_web_contents_impl);
void InspectableWebContentsImpl::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterStringPref(kDockSidePref, "bottom");
auto bounds_dict = make_scoped_ptr(new base::DictionaryValue);
RectToDictionary(gfx::Rect(0, 0, 800, 600), bounds_dict.get());
registry->RegisterDictionaryPref(kDevToolsBoundsPref, bounds_dict.release());
}
InspectableWebContentsImpl::InspectableWebContentsImpl(
content::WebContents* web_contents)
: web_contents_(web_contents),
delegate_(nullptr) {
auto context = static_cast<BrowserContext*>(
web_contents_->GetBrowserContext());
dock_side_ = context->prefs()->GetString(kDockSidePref);
auto context = static_cast<BrowserContext*>(web_contents_->GetBrowserContext());
auto bounds_dict = context->prefs()->GetDictionary(kDevToolsBoundsPref);
if (bounds_dict)
DictionaryToRect(*bounds_dict, &devtools_bounds_);
view_.reset(CreateInspectableContentsView(this));
}
@ -62,6 +116,8 @@ content::WebContents* InspectableWebContentsImpl::GetWebContents() const {
}
void InspectableWebContentsImpl::ShowDevTools() {
// Show devtools only after it has done loading, this is to make sure the
// SetIsDocked is called *BEFORE* ShowDevTools.
if (!devtools_web_contents_) {
embedder_message_dispatcher_.reset(
new DevToolsEmbedderMessageDispatcher(this));
@ -70,11 +126,6 @@ void InspectableWebContentsImpl::ShowDevTools() {
web_contents_->GetBrowserContext());
devtools_web_contents_.reset(content::WebContents::Create(create_params));
#if defined(OS_MACOSX)
// Work around http://crbug.com/279472.
devtools_web_contents_->GetView()->SetAllowOverlappingViews(true);
#endif
Observe(devtools_web_contents_.get());
devtools_web_contents_->SetDelegate(this);
@ -92,17 +143,13 @@ void InspectableWebContentsImpl::ShowDevTools() {
content::Referrer(),
content::PAGE_TRANSITION_AUTO_TOPLEVEL,
std::string());
} else {
view_->ShowDevTools();
}
if (delegate_ && delegate_->DevToolsShow(&dock_side_))
return;
view_->SetDockSide(dock_side_);
view_->ShowDevTools();
}
void InspectableWebContentsImpl::CloseDevTools() {
if (IsDevToolsViewShowing()) {
if (devtools_web_contents_) {
view_->CloseDevTools();
devtools_web_contents_.reset();
web_contents_->GetView()->Focus();
@ -113,11 +160,16 @@ bool InspectableWebContentsImpl::IsDevToolsViewShowing() {
return devtools_web_contents_ && view_->IsDevToolsViewShowing();
}
void InspectableWebContentsImpl::UpdateFrontendDockSide() {
auto javascript = base::StringPrintf(
"InspectorFrontendAPI.setDockSide(\"%s\")", dock_side_.c_str());
devtools_web_contents_->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
base::string16(), base::ASCIIToUTF16(javascript));
gfx::Rect InspectableWebContentsImpl::GetDevToolsBounds() const {
return devtools_bounds_;
}
void InspectableWebContentsImpl::SaveDevToolsBounds(const gfx::Rect& bounds) {
auto context = static_cast<BrowserContext*>(web_contents_->GetBrowserContext());
base::DictionaryValue bounds_dict;
RectToDictionary(bounds, &bounds_dict);
context->prefs()->Set(kDevToolsBoundsPref, bounds_dict);
devtools_bounds_ = bounds;
}
void InspectableWebContentsImpl::ActivateWindow() {
@ -127,25 +179,24 @@ void InspectableWebContentsImpl::CloseWindow() {
CloseDevTools();
}
void InspectableWebContentsImpl::SetContentsResizingStrategy(
const gfx::Insets& insets, const gfx::Size& min_size) {
DevToolsContentsResizingStrategy strategy(insets, min_size);
if (contents_resizing_strategy_.Equals(strategy))
return;
contents_resizing_strategy_.CopyFrom(strategy);
view_->SetContentsResizingStrategy(contents_resizing_strategy_);
}
void InspectableWebContentsImpl::InspectElementCompleted() {
}
void InspectableWebContentsImpl::MoveWindow(int x, int y) {
}
void InspectableWebContentsImpl::SetDockSide(const std::string& side) {
bool succeed = true;
if (delegate_ && delegate_->DevToolsSetDockSide(side, &succeed)) {
if (!succeed) // delegate failed to set dock side.
return;
} else if (!view_->SetDockSide(side)) {
return;
}
dock_side_ = side;
auto context = static_cast<BrowserContext*>(
web_contents_->GetBrowserContext());
context->prefs()->SetString(kDockSidePref, side);
UpdateFrontendDockSide();
void InspectableWebContentsImpl::SetIsDocked(bool docked) {
view_->SetIsDocked(docked);
}
void InspectableWebContentsImpl::OpenInNewTab(const std::string& url) {
@ -164,6 +215,8 @@ void InspectableWebContentsImpl::AppendToFile(
}
void InspectableWebContentsImpl::RequestFileSystems() {
devtools_web_contents()->GetMainFrame()->ExecuteJavaScript(
base::ASCIIToUTF16("InspectorFrontendAPI.fileSystemsLoaded([])"));
}
void InspectableWebContentsImpl::AddFileSystem() {
@ -173,6 +226,10 @@ void InspectableWebContentsImpl::RemoveFileSystem(
const std::string& file_system_path) {
}
void InspectableWebContentsImpl::UpgradeDraggedFileSystemPermissions(
const std::string& file_system_url) {
}
void InspectableWebContentsImpl::IndexPath(
int request_id, const std::string& file_system_path) {
}
@ -186,9 +243,31 @@ void InspectableWebContentsImpl::SearchInPath(
const std::string& query) {
}
void InspectableWebContentsImpl::ZoomIn() {
}
void InspectableWebContentsImpl::ZoomOut() {
}
void InspectableWebContentsImpl::ResetZoom() {
}
void InspectableWebContentsImpl::DispatchOnEmbedder(
const std::string& message) {
embedder_message_dispatcher_->Dispatch(message);
std::string method;
base::ListValue params;
int id;
if (!ParseMessage(message, &method, &params, &id)) {
LOG(ERROR) << "Invalid message was sent to embedder: " << message;
return;
}
std::string error = embedder_message_dispatcher_->Dispatch(method, &params);
if (id) {
std::string ack = base::StringPrintf(
"InspectorFrontendAPI.embedderMessageAck(%d, \"%s\");", id, error.c_str());
devtools_web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(ack));
}
}
void InspectableWebContentsImpl::InspectedContentsClosing() {
@ -207,7 +286,7 @@ void InspectableWebContentsImpl::DidFinishLoad(int64 frame_id,
if (!is_main_frame)
return;
UpdateFrontendDockSide();
view_->ShowDevTools();
}
void InspectableWebContentsImpl::WebContentsDestroyed(content::WebContents*) {

View file

@ -8,11 +8,13 @@
#include "browser/inspectable_web_contents.h"
#include "browser/devtools_contents_resizing_strategy.h"
#include "browser/devtools_embedder_message_dispatcher.h"
#include "content/public/browser/devtools_frontend_host_delegate.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "ui/gfx/rect.h"
class PrefRegistrySimple;
@ -45,6 +47,10 @@ class InspectableWebContentsImpl :
virtual void CloseDevTools() OVERRIDE;
virtual bool IsDevToolsViewShowing() OVERRIDE;
// Return the last position and size of devtools window.
gfx::Rect GetDevToolsBounds() const;
void SaveDevToolsBounds(const gfx::Rect& bounds);
virtual void SetDelegate(InspectableWebContentsDelegate* delegate) {
delegate_ = delegate;
}
@ -54,14 +60,15 @@ class InspectableWebContentsImpl :
}
private:
void UpdateFrontendDockSide();
// DevToolsEmbedderMessageDispacher::Delegate
virtual void ActivateWindow() OVERRIDE;
virtual void CloseWindow() OVERRIDE;
virtual void SetContentsResizingStrategy(
const gfx::Insets& insets, const gfx::Size& min_size) OVERRIDE;
virtual void InspectElementCompleted() OVERRIDE;
virtual void MoveWindow(int x, int y) OVERRIDE;
virtual void SetDockSide(const std::string& side) OVERRIDE;
virtual void SetIsDocked(bool docked) OVERRIDE;
virtual void OpenInNewTab(const std::string& url) OVERRIDE;
virtual void SaveToFile(const std::string& url,
const std::string& content,
@ -71,12 +78,17 @@ class InspectableWebContentsImpl :
virtual void RequestFileSystems() OVERRIDE;
virtual void AddFileSystem() OVERRIDE;
virtual void RemoveFileSystem(const std::string& file_system_path) OVERRIDE;
virtual void UpgradeDraggedFileSystemPermissions(
const std::string& file_system_url) OVERRIDE;
virtual void IndexPath(int request_id,
const std::string& file_system_path) OVERRIDE;
virtual void StopIndexing(int request_id) OVERRIDE;
virtual void SearchInPath(int request_id,
const std::string& file_system_path,
const std::string& query) OVERRIDE;
virtual void ZoomIn() OVERRIDE;
virtual void ZoomOut() OVERRIDE;
virtual void ResetZoom() OVERRIDE;
// content::DevToolsFrontendHostDelegate
@ -103,7 +115,9 @@ class InspectableWebContentsImpl :
scoped_ptr<content::WebContents> devtools_web_contents_;
scoped_ptr<InspectableWebContentsView> view_;
scoped_refptr<content::DevToolsAgentHost> agent_host_;
std::string dock_side_;
DevToolsContentsResizingStrategy contents_resizing_strategy_;
gfx::Rect devtools_bounds_;
scoped_ptr<DevToolsEmbedderMessageDispatcher> embedder_message_dispatcher_;

View file

@ -3,19 +3,38 @@
#include "ui/gfx/native_widget_types.h"
class DevToolsContentsResizingStrategy;
#if defined(TOOLKIT_VIEWS)
namespace views {
class View;
}
#endif
namespace brightray {
class InspectableWebContentsView {
public:
virtual ~InspectableWebContentsView() {}
#if defined(TOOLKIT_VIEWS)
// Returns the container control, which has devtools view attached.
virtual views::View* GetView() = 0;
// Returns the web view control, which can be used by the
// GetInitiallyFocusedView() to set initial focus to web view.
virtual views::View* GetWebView() = 0;
#else
virtual gfx::NativeView GetNativeView() const = 0;
#endif
virtual void ShowDevTools() = 0;
// Hide the DevTools view.
virtual void CloseDevTools() = 0;
virtual bool IsDevToolsViewShowing() = 0;
virtual bool SetDockSide(const std::string& side) = 0;
virtual void SetIsDocked(bool docked) = 0;
virtual void SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) = 0;
};
} // namespace brightray

View file

@ -21,7 +21,9 @@ class InspectableWebContentsViewMac : public InspectableWebContentsView {
virtual void ShowDevTools() OVERRIDE;
virtual void CloseDevTools() OVERRIDE;
virtual bool IsDevToolsViewShowing() OVERRIDE;
virtual bool SetDockSide(const std::string& side) OVERRIDE;
virtual void SetIsDocked(bool docked) OVERRIDE;
virtual void SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) OVERRIDE;
InspectableWebContentsImpl* inspectable_web_contents() {
return inspectable_web_contents_;

View file

@ -1,13 +1,14 @@
#import "browser/inspectable_web_contents_view_mac.h"
#include "browser/inspectable_web_contents_view_mac.h"
#import "browser/inspectable_web_contents.h"
#import "browser/mac/bry_inspectable_web_contents_view_private.h"
#import "content/public/browser/web_contents_view.h"
#import <AppKit/AppKit.h>
#include "browser/inspectable_web_contents.h"
#import "browser/mac/bry_inspectable_web_contents_view.h"
#include "content/public/browser/web_contents_view.h"
namespace brightray {
InspectableWebContentsView* CreateInspectableContentsView(InspectableWebContentsImpl* inspectable_web_contents) {
return new InspectableWebContentsViewMac(inspectable_web_contents);
}
@ -18,7 +19,6 @@ InspectableWebContentsViewMac::InspectableWebContentsViewMac(InspectableWebConte
}
InspectableWebContentsViewMac::~InspectableWebContentsViewMac() {
[view_ removeFromNotificationCenter];
}
gfx::NativeView InspectableWebContentsViewMac::GetNativeView() const {
@ -37,8 +37,13 @@ bool InspectableWebContentsViewMac::IsDevToolsViewShowing() {
return [view_ isDevToolsVisible];
}
bool InspectableWebContentsViewMac::SetDockSide(const std::string& side) {
return [view_ setDockSide:side];
void InspectableWebContentsViewMac::SetIsDocked(bool docked) {
[view_ setIsDocked:docked];
}
void InspectableWebContentsViewMac::SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) {
[view_ setContentsResizingStrategy:strategy];
}
}

View file

@ -1,286 +0,0 @@
#include "browser/linux/inspectable_web_contents_view_linux.h"
#include <glib-object.h>
#include <gtk/gtk.h>
#include "base/strings/stringprintf.h"
#include "browser/browser_client.h"
#include "browser/inspectable_web_contents_impl.h"
#include "content/public/browser/web_contents_view.h"
namespace brightray {
namespace {
bool IsWidgetAncestryVisible(GtkWidget* widget) {
GtkWidget* parent = widget;
while (parent && gtk_widget_get_visible(parent))
parent = gtk_widget_get_parent(parent);
return !parent;
}
}
InspectableWebContentsView* CreateInspectableContentsView(
InspectableWebContentsImpl* inspectable_web_contents) {
return new InspectableWebContentsViewLinux(inspectable_web_contents);
}
InspectableWebContentsViewLinux::InspectableWebContentsViewLinux(
InspectableWebContentsImpl* inspectable_web_contents)
: inspectable_web_contents_(inspectable_web_contents),
devtools_window_(NULL) {
}
InspectableWebContentsViewLinux::~InspectableWebContentsViewLinux() {
if (devtools_window_) gtk_widget_destroy(devtools_window_);
}
#if 0 // some utility functions to debug GTK window hierarchies
static void dump_one(GtkWidget *wat, int indent) {
GtkAllocation alloc;
gtk_widget_get_allocation(wat, &alloc);
fprintf(stderr, "%*s[%p] %s @%d,%d %dx%d",
indent, "", wat,
g_type_name_from_instance(reinterpret_cast<GTypeInstance*>(wat)),
alloc.x, alloc.y, alloc.width, alloc.height);
if (GTK_IS_WINDOW(wat)) {
fprintf(stderr, " - \"%s\"", gtk_window_get_title(GTK_WINDOW(wat)));
}
fputc('\n', stderr);
}
static void dump_the_whole_tree(GtkWidget *wat, int indent) {
if (!wat) {
fprintf(stderr, "(nil)\n");
return;
}
dump_one(wat, indent);
GList *kids = gtk_container_get_children(GTK_CONTAINER(wat));
for (GList *p = kids; p; p = p->next) {
dump_the_whole_tree(GTK_WIDGET(p->data), indent+2);
}
}
static void dump_parents(GtkWidget *wat) {
fprintf(stderr, "Parents:\n");
for (GtkWidget *p = gtk_widget_get_parent(wat);
p;
p = gtk_widget_get_parent(p)) {
dump_one(p, 2);
}
}
#endif
gfx::NativeView InspectableWebContentsViewLinux::GetNativeView() const {
auto web_contents = inspectable_web_contents_->GetWebContents();
return web_contents->GetView()->GetNativeView();
}
/* This code is a little bit hairy.
The dev tools can be in any one of five places:
1. Unassigned and invisible. This is the default state until someone asks
to 'inspect element' for the first time. In this case, devtools->parent is
NULL.
2. In an onscreen window, visible.
3. In the bottom half of a GtkVPaned.
4. In the right half of a GtkHPaned.
5. In an offscreen window, invisible. This is where they go once they have
been displayed and the user asks to "close" them. They can't be put back
into the unassigned state.
ShowDevTools() and is responsible for transitioning from any one of these
states to the three visible states, 2-4, as indicated by the contents of the
'dockside_' variable. The helper functions ShowDevToolsInWindow and
ShowDevToolsInPane focus on transitioning to states 2 and 3+4, respectively.
These helper functions are responsible for the entire transition, including
cleaning up any extraneous containers from the old state.
Hiding the dev tools is taken care of by CloseDevTools (from paned states
3+4 to invisible state 5) or by the "delete-event" signal on the
devtools_window_ (from window state 2 to 5).
Remember that GTK does reference counting, so a view with no refs and no
parent will be freed. Views that have a ref but no parents will lose their
dimensions. So it's best to move the devtools view from place to place with
gtk_widget_reparent whenever possible. Unfortunately, one cannot reparent
things into a GtkPaned, so fairly brittle use of g_object_[un]ref and
gtk_container_remove happens.
*/
void InspectableWebContentsViewLinux::ShowDevTools() {
auto devtools_web_contents =
inspectable_web_contents()->devtools_web_contents();
GtkWidget *devtools = devtools_web_contents->GetView()->GetNativeView();
GtkWidget *parent = gtk_widget_get_parent(devtools);
DLOG(INFO) << base::StringPrintf(
"InspectableWebContentsViewLinux::ShowDevTools - " \
"parent=%s@%p window=%p dockside=\"%s\"",
g_type_name_from_instance(reinterpret_cast<GTypeInstance*>(parent)),
parent,
devtools_window_,
dockside_.c_str());
if (!parent || GTK_IS_PANED(parent)) {
if (dockside_ == "undocked") ShowDevToolsInWindow();
else if (dockside_ == "bottom") ShowDevToolsInPane(true);
else if (dockside_ == "right") ShowDevToolsInPane(false);
} else {
DCHECK(parent == devtools_window_);
if (dockside_ == "undocked") gtk_widget_show_all(parent);
else if (dockside_ == "bottom") ShowDevToolsInPane(true);
else if (dockside_ == "right") ShowDevToolsInPane(false);
}
}
void InspectableWebContentsViewLinux::CloseDevTools() {
auto devtools_web_contents =
inspectable_web_contents()->devtools_web_contents();
GtkWidget *devtools = devtools_web_contents->GetView()->GetNativeView();
GtkWidget *parent = gtk_widget_get_parent(devtools);
DLOG(INFO) << base::StringPrintf(
"InspectableWebContentsViewLinux::CloseDevTools - " \
"parent=%s@%p window=%p dockside=\"%s\"",
g_type_name_from_instance(reinterpret_cast<GTypeInstance*>(parent)),
parent,
devtools_window_,
dockside_.c_str());
if (!parent) {
return; // Not visible -> nothing to do
} else if (GTK_IS_PANED(parent)) {
GtkWidget *browser = GetBrowserWindow();
GtkWidget *view = GetNativeView();
if (!devtools_window_) MakeDevToolsWindow();
gtk_widget_reparent(devtools, devtools_window_);
g_object_ref(parent);
gtk_container_remove(GTK_CONTAINER(browser), parent);
gtk_widget_reparent(view, browser);
g_object_unref(parent);
} else {
DCHECK(parent == devtools_window_);
gtk_widget_hide(parent);
}
}
bool InspectableWebContentsViewLinux::IsDevToolsViewShowing() {
auto devtools_web_contents =
inspectable_web_contents()->devtools_web_contents();
GtkWidget* devtools = devtools_web_contents->GetView()->GetNativeView();
return IsWidgetAncestryVisible(devtools);
}
bool InspectableWebContentsViewLinux::SetDockSide(const std::string& side) {
DLOG(INFO) <<
"InspectableWebContentsViewLinux::SetDockSide: \"" << side << "\"";
if (side != "undocked" && side != "bottom" && side != "right")
return false; // unsupported display location
if (dockside_ == side)
return true; // no change from current location
dockside_ = side;
// If devtools already has a parent, then we're being asked to move it.
auto devtools_web_contents =
inspectable_web_contents()->devtools_web_contents();
GtkWidget *devtools = devtools_web_contents->GetView()->GetNativeView();
if (gtk_widget_get_parent(devtools)) {
ShowDevTools();
}
return true;
}
void InspectableWebContentsViewLinux::ShowDevToolsInWindow() {
auto devtools_web_contents =
inspectable_web_contents()->devtools_web_contents();
GtkWidget *devtools = devtools_web_contents->GetView()->GetNativeView();
GtkWidget *parent = gtk_widget_get_parent(devtools);
if (!devtools_window_)
MakeDevToolsWindow();
if (!parent) {
gtk_container_add(GTK_CONTAINER(devtools_window_), devtools);
} else if (parent != devtools_window_) {
DCHECK(GTK_IS_PANED(parent));
gtk_widget_reparent(devtools, devtools_window_);
// Remove the pane.
GtkWidget *view = GetNativeView();
GtkWidget *browser = GetBrowserWindow();
g_object_ref(view);
gtk_container_remove(GTK_CONTAINER(parent), view);
gtk_container_remove(GTK_CONTAINER(browser), parent);
gtk_container_add(GTK_CONTAINER(browser), view);
g_object_unref(view);
}
gtk_widget_show_all(devtools_window_);
}
void InspectableWebContentsViewLinux::MakeDevToolsWindow() {
DCHECK(!devtools_window_);
devtools_window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(devtools_window_), "Developer Tools");
gtk_window_set_default_size(GTK_WINDOW(devtools_window_), 800, 600);
g_signal_connect(GTK_OBJECT(devtools_window_),
"delete-event",
G_CALLBACK(gtk_widget_hide_on_delete),
this);
}
void InspectableWebContentsViewLinux::ShowDevToolsInPane(bool on_bottom) {
auto devtools_web_contents =
inspectable_web_contents()->devtools_web_contents();
GtkWidget *devtools = devtools_web_contents->GetView()->GetNativeView();
GtkWidget *parent = gtk_widget_get_parent(devtools);
GtkWidget *pane = on_bottom ? gtk_vpaned_new() : gtk_hpaned_new();
GtkWidget *view = GetNativeView();
GtkWidget *browser = GetBrowserWindow();
GtkAllocation alloc;
gtk_widget_get_allocation(browser, &alloc);
gtk_paned_set_position(GTK_PANED(pane),
on_bottom ? alloc.height * 2 / 3 : alloc.width / 2);
if (!parent) {
g_object_ref(view);
gtk_container_remove(GTK_CONTAINER(browser), view);
gtk_paned_add1(GTK_PANED(pane), view);
gtk_paned_add2(GTK_PANED(pane), devtools);
g_object_unref(view);
} else if (GTK_IS_PANED(parent)) {
g_object_ref(view);
g_object_ref(devtools);
gtk_container_remove(GTK_CONTAINER(parent), view);
gtk_container_remove(GTK_CONTAINER(parent), devtools);
gtk_paned_add1(GTK_PANED(pane), view);
gtk_paned_add2(GTK_PANED(pane), devtools);
g_object_unref(view);
g_object_unref(devtools);
gtk_container_remove(GTK_CONTAINER(browser), parent);
} else {
DCHECK(parent == devtools_window_);
g_object_ref(view);
gtk_container_remove(GTK_CONTAINER(devtools_window_), devtools);
gtk_container_remove(GTK_CONTAINER(browser), view);
gtk_paned_add1(GTK_PANED(pane), view);
gtk_paned_add2(GTK_PANED(pane), devtools);
g_object_unref(view);
gtk_widget_hide(devtools_window_);
}
gtk_container_add(GTK_CONTAINER(browser), pane);
gtk_widget_show_all(pane);
}
GtkWidget *InspectableWebContentsViewLinux::GetBrowserWindow() {
GtkWidget *view = GetNativeView();
GtkWidget *parent = gtk_widget_get_parent(view);
GtkWidget *browser =
GTK_IS_PANED(parent) ? gtk_widget_get_parent(parent) : parent;
DCHECK(GTK_IS_WINDOW(browser));
return browser;
}
} // namespace brightray

View file

@ -1,58 +0,0 @@
#ifndef BRIGHTRAY_BROWSER_LINUX_INSPECTABLE_WEB_CONTENTS_VIEW_LINUX_H_
#define BRIGHTRAY_BROWSER_LINUX_INSPECTABLE_WEB_CONTENTS_VIEW_LINUX_H_
#include "browser/inspectable_web_contents_view.h"
#include "base/compiler_specific.h"
namespace brightray {
class InspectableWebContentsImpl;
class InspectableWebContentsViewLinux : public InspectableWebContentsView {
public:
explicit InspectableWebContentsViewLinux(
InspectableWebContentsImpl* inspectable_web_contents_impl);
~InspectableWebContentsViewLinux();
virtual gfx::NativeView GetNativeView() const OVERRIDE;
virtual void ShowDevTools() OVERRIDE;
virtual void CloseDevTools() OVERRIDE;
virtual bool IsDevToolsViewShowing() OVERRIDE;
virtual bool SetDockSide(const std::string& side) OVERRIDE;
InspectableWebContentsImpl* inspectable_web_contents() {
return inspectable_web_contents_;
}
private:
// Show the dev tools in their own window. If they're already shown
// somewhere else, remove them cleanly and take any GtkPaned out of the
// window.
void ShowDevToolsInWindow();
// Show the dev tools in a vpaned (on the bottom) or hpaned (on the
// right). If they're already shown in a pane, move them and remove the
// old pane. If they're already shown in a window, hide (don't delete)
// that window.
void ShowDevToolsInPane(bool on_bottom);
// Create a new window for dev tools. This function doesn't actually
// put the dev tools in the window or show the window.
void MakeDevToolsWindow();
// Get the GtkWindow* that contains this object.
GtkWidget *GetBrowserWindow();
// Owns us.
InspectableWebContentsImpl* inspectable_web_contents_;
std::string dockside_;
GtkWidget *devtools_window_;
DISALLOW_COPY_AND_ASSIGN(InspectableWebContentsViewLinux);
};
} // namespace brightray
#endif

View file

@ -1,14 +1,34 @@
#import <AppKit/AppKit.h>
@class BRYInspectableWebContentsViewPrivate;
#include "browser/devtools_contents_resizing_strategy.h"
@interface BRYInspectableWebContentsView
: NSView<NSWindowDelegate, NSSplitViewDelegate> {
@private
BRYInspectableWebContentsViewPrivate *_private;
#include "base/mac/scoped_nsobject.h"
#include "ui/base/cocoa/base_view.h"
namespace brightray {
class InspectableWebContentsViewMac;
}
- (void)removeFromNotificationCenter;
- (IBAction)showDevTools:(id)sender;
using brightray::InspectableWebContentsViewMac;
@interface BRYInspectableWebContentsView : BaseView<NSWindowDelegate> {
@private
brightray::InspectableWebContentsViewMac* inspectableWebContentsView_;
base::scoped_nsobject<NSWindow> devtools_window_;
BOOL devtools_visible_;
BOOL devtools_docked_;
DevToolsContentsResizingStrategy strategy_;
}
- (instancetype)initWithInspectableWebContentsViewMac:(InspectableWebContentsViewMac*)view;
- (void)setDevToolsVisible:(BOOL)visible;
- (BOOL)isDevToolsVisible;
- (void)setIsDocked:(BOOL)docked;
- (void)setContentsResizingStrategy:(const DevToolsContentsResizingStrategy&)strategy;
// Adjust docked devtools to the contents resizing strategy.
- (void)update;
@end

View file

@ -1,252 +1,161 @@
#import "browser/mac/bry_inspectable_web_contents_view.h"
#include "browser/mac/bry_inspectable_web_contents_view.h"
#import "browser/inspectable_web_contents_impl.h"
#import "browser/inspectable_web_contents_view_mac.h"
#import "browser/mac/bry_inspectable_web_contents_view_private.h"
#include "browser/inspectable_web_contents_impl.h"
#include "browser/inspectable_web_contents_view_mac.h"
#import "content/public/browser/render_widget_host_view.h"
#import "content/public/browser/web_contents_view.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents_view.h"
#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
#include "ui/gfx/mac/scoped_ns_disable_screen_updates.h"
using namespace brightray;
@interface GraySplitView : NSSplitView
- (NSColor*)dividerColor;
@end
@implementation GraySplitView
- (NSColor*)dividerColor {
return [NSColor darkGrayColor];
}
@end
@interface BRYInspectableWebContentsViewPrivate : NSObject {
@public
InspectableWebContentsViewMac *inspectableWebContentsView;
GraySplitView *splitView;
NSWindow *window;
BOOL visible;
}
@end
namespace {
NSRect devtoolsWindowFrame(NSView *referenceView) {
auto screenFrame = [referenceView.window convertRectToScreen:[referenceView convertRect:referenceView.bounds toView:nil]];
return NSInsetRect(screenFrame, NSWidth(screenFrame) / 6, NSHeight(screenFrame) / 6);
}
void SetActive(content::WebContents* web_contents, bool active) {
auto render_widget_host_view = web_contents->GetRenderWidgetHostView();
if (!render_widget_host_view)
return;
render_widget_host_view->SetActive(active);
}
}
@implementation BRYInspectableWebContentsView
- (instancetype)initWithInspectableWebContentsViewMac:(InspectableWebContentsViewMac *)inspectableWebContentsView {
- (instancetype)initWithInspectableWebContentsViewMac:(InspectableWebContentsViewMac*)view {
self = [super init];
if (!self)
return nil;
_private = [[BRYInspectableWebContentsViewPrivate alloc] init];
_private->inspectableWebContentsView = inspectableWebContentsView;
_private->splitView = [[GraySplitView alloc] init];
_private->splitView.delegate = self;
inspectableWebContentsView_ = view;
devtools_visible_ = NO;
devtools_docked_ = NO;
[self addSubview:_private->splitView];
_private->splitView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
_private->splitView.dividerStyle = NSSplitViewDividerStyleThin;
[_private->splitView addSubview:inspectableWebContentsView->inspectable_web_contents()->GetWebContents()->GetView()->GetNativeView()];
auto contents = inspectableWebContentsView_->inspectable_web_contents()->GetWebContents();
auto contentsView = contents->GetView()->GetNativeView();
[contentsView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[self addSubview:contentsView];
return self;
}
- (void)dealloc {
[_private->window release];
[_private->splitView release];
[_private release];
_private = nil;
[super dealloc];
}
- (void)removeFromNotificationCenter {
[NSNotificationCenter.defaultCenter removeObserver:self];
- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize {
[self adjustSubviews];
}
- (IBAction)showDevTools:(id)sender {
_private->inspectableWebContentsView->inspectable_web_contents()->ShowDevTools();
inspectableWebContentsView_->inspectable_web_contents()->ShowDevTools();
}
- (void)setDevToolsVisible:(BOOL)visible {
if (_private->visible == visible)
if (visible == devtools_visible_)
return;
_private->visible = visible;
if ([self isDocked]) {
if (visible) {
[_private->window makeKeyAndOrderFront:nil];
} else {
[_private->window orderOut:nil];
}
return;
}
auto devToolsWebContents = _private->inspectableWebContentsView->inspectable_web_contents()->devtools_web_contents();
auto devToolsWebContents = inspectableWebContentsView_->inspectable_web_contents()->devtools_web_contents();
auto devToolsView = devToolsWebContents->GetView()->GetNativeView();
if (visible) {
auto inspectedView = _private->inspectableWebContentsView->inspectable_web_contents()->GetWebContents()->GetView()->GetNativeView();
CGRect frame = NSRectToCGRect(inspectedView.frame);
CGRect inspectedViewFrame;
CGRect devToolsFrame;
CGFloat amount;
CGRectEdge edge;
if ([_private->splitView isVertical]) {
amount = CGRectGetWidth(frame) * 2 / 3;
edge = CGRectMaxXEdge;
devtools_visible_ = visible;
if (devtools_docked_) {
if (visible) {
// Place the devToolsView under contentsView, notice that we didn't set
// sizes for them until the setContentsResizingStrategy message.
[self addSubview:devToolsView positioned:NSWindowBelow relativeTo:nil];
[self update];
} else {
amount = CGRectGetHeight(frame) * 2 / 3;
edge = CGRectMaxYEdge;
gfx::ScopedNSDisableScreenUpdates disabler;
devToolsWebContents->GetView()->RemoveOverlayView();
[devToolsView removeFromSuperview];
[self adjustSubviews];
}
CGRectDivide(frame, &inspectedViewFrame, &devToolsFrame, amount, edge);
inspectedView.frame = NSRectFromCGRect(inspectedViewFrame);
devToolsView.frame = NSRectFromCGRect(devToolsFrame);
[_private->splitView addSubview:devToolsView];
} else {
[devToolsView removeFromSuperview];
if (visible) {
[devtools_window_ makeKeyAndOrderFront:nil];
} else {
[[self window] makeKeyAndOrderFront:nil];
devtools_window_.reset();
}
}
[_private->splitView adjustSubviews];
}
- (BOOL)isDevToolsVisible {
return _private->visible;
return devtools_visible_;
}
- (BOOL)setDockSide:(const std::string&)side {
if (side == "right") {
_private->splitView.vertical = YES;
[self moveToSplitView];
} else if (side == "bottom") {
_private->splitView.vertical = NO;
[self moveToSplitView];
} else if (side == "undocked") {
[self moveToWindow];
} else {
return NO;
- (void)setIsDocked:(BOOL)docked {
// Revert to no-devtools state.
[self setDevToolsVisible:NO];
// Switch to new state.
devtools_docked_ = docked;
if (!docked) {
auto devToolsWebContents = inspectableWebContentsView_->inspectable_web_contents()->devtools_web_contents();
auto devToolsView = devToolsWebContents->GetView()->GetNativeView();
auto styleMask = NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask |
NSTexturedBackgroundWindowMask |
NSUnifiedTitleAndToolbarWindowMask;
devtools_window_.reset([[UnderlayOpenGLHostingWindow alloc]
initWithContentRect:NSMakeRect(0, 0, 800, 600)
styleMask:styleMask
backing:NSBackingStoreBuffered
defer:YES]);
[devtools_window_ setDelegate:self];
[devtools_window_ setFrameAutosaveName:@"brightray.devtools"];
[devtools_window_ setTitle:@"Developer Tools"];
[devtools_window_ setReleasedWhenClosed:NO];
[devtools_window_ setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
[devtools_window_ setContentBorderThickness:24 forEdge:NSMaxYEdge];
NSView* contentView = [devtools_window_ contentView];
devToolsView.frame = contentView.bounds;
devToolsView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[contentView addSubview:devToolsView];
}
return YES;
[self setDevToolsVisible:YES];
}
- (void)moveToWindow {
if (!_private->window) {
auto styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask | NSTexturedBackgroundWindowMask | NSUnifiedTitleAndToolbarWindowMask;
auto contentRect = [UnderlayOpenGLHostingWindow contentRectForFrameRect:devtoolsWindowFrame(_private->splitView) styleMask:styleMask];
_private->window = [[UnderlayOpenGLHostingWindow alloc] initWithContentRect:contentRect styleMask:styleMask backing:NSBackingStoreBuffered defer:YES];
_private->window.delegate = self;
_private->window.releasedWhenClosed = NO;
_private->window.title = @"Developer Tools";
_private->window.frameAutosaveName = @"brightray.developer.tools";
[_private->window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
[_private->window setContentBorderThickness:24 forEdge:NSMaxYEdge];
}
auto devToolsWebContents = _private->inspectableWebContentsView->inspectable_web_contents()->devtools_web_contents();
auto devToolsView = devToolsWebContents->GetView()->GetNativeView();
NSView *contentView = _private->window.contentView;
devToolsView.frame = contentView.bounds;
devToolsView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
[contentView addSubview:devToolsView];
[_private->window makeKeyAndOrderFront:nil];
[_private->splitView adjustSubviews];
- (void)setContentsResizingStrategy:(const DevToolsContentsResizingStrategy&)strategy {
strategy_.CopyFrom(strategy);
[self update];
}
- (void)moveToSplitView {
[_private->window orderOut:nil];
auto devToolsWebContents = _private->inspectableWebContentsView->inspectable_web_contents()->devtools_web_contents();
auto devToolsView = devToolsWebContents->GetView()->GetNativeView();
[_private->splitView addSubview:devToolsView];
[_private->splitView adjustSubviews];
}
- (BOOL)isDocked {
auto devToolsWebContents = _private->inspectableWebContentsView->inspectable_web_contents()->devtools_web_contents();
if (!devToolsWebContents)
return NO;
auto devToolsView = devToolsWebContents->GetView()->GetNativeView();
return _private->window && devToolsView.window == _private->window;
}
- (void)window:(NSWindow *)window didBecomeActive:(BOOL)active {
auto inspectable_contents = _private->inspectableWebContentsView->inspectable_web_contents();
// Changes to the active state of the window we create only affects the dev tools contents.
if (window == _private->window) {
SetActive(inspectable_contents->devtools_web_contents(), active);
return;
}
// Changes the window that hosts us always affect our main web contents. If the dev tools are also
// hosted in this window, they are affected too.
SetActive(inspectable_contents->GetWebContents(), active);
if (![self isDocked])
return;
SetActive(inspectable_contents->devtools_web_contents(), active);
}
#pragma mark - NSView
- (void)viewWillMoveToWindow:(NSWindow *)newWindow {
if (self.window) {
[NSNotificationCenter.defaultCenter removeObserver:self name:NSWindowDidBecomeKeyNotification object:self.window];
[NSNotificationCenter.defaultCenter removeObserver:self name:NSWindowDidResignKeyNotification object:self.window];
}
if (!newWindow)
- (void)update {
if (!devtools_docked_)
return;
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(windowDidBecomeKey:) name:NSWindowDidBecomeKeyNotification object:newWindow];
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(windowDidResignKey:) name:NSWindowDidResignKeyNotification object:newWindow];
auto contents = inspectableWebContentsView_->inspectable_web_contents()->GetWebContents();
auto devToolsWebContents = inspectableWebContentsView_->inspectable_web_contents()->devtools_web_contents();
gfx::ScopedNSDisableScreenUpdates disabler;
devToolsWebContents->GetView()->SetOverlayView(
contents->GetView(),
gfx::Point(strategy_.insets().left(), strategy_.insets().top()));
[self adjustSubviews];
}
#pragma mark - NSSplitViewDelegate
- (void)adjustSubviews {
if (![[self subviews] count])
return;
-(void)splitViewWillResizeSubviews:(NSNotification *)notification {
[[_private->splitView window] disableScreenUpdatesUntilFlush];
if (![self isDevToolsVisible] || devtools_window_) {
DCHECK_EQ(1u, [[self subviews] count]);
NSView* contents = [[self subviews] objectAtIndex:0];
[contents setFrame:[self bounds]];
return;
}
NSView* devToolsView = [[self subviews] objectAtIndex:0];
NSView* contentsView = [[self subviews] objectAtIndex:1];
DCHECK_EQ(2u, [[self subviews] count]);
gfx::Rect new_devtools_bounds;
gfx::Rect new_contents_bounds;
ApplyDevToolsContentsResizingStrategy(
strategy_, gfx::Size(NSSizeToCGSize([self bounds].size)),
[self flipNSRectToRect:[devToolsView bounds]],
[self flipNSRectToRect:[contentsView bounds]],
&new_devtools_bounds, &new_contents_bounds);
[devToolsView setFrame:[self flipRectToNSRect:new_devtools_bounds]];
[contentsView setFrame:[self flipRectToNSRect:new_contents_bounds]];
}
#pragma mark - NSWindowDelegate
- (BOOL)windowShouldClose:(id)sender {
_private->visible = NO;
[_private->window orderOut:nil];
return NO;
}
- (void)windowDidBecomeKey:(NSNotification *)notification {
[self window:notification.object didBecomeActive:YES];
}
- (void)windowDidResignKey:(NSNotification *)notification {
[self window:notification.object didBecomeActive:NO];
- (void)windowWillClose:(NSNotification*)notification {
inspectableWebContentsView_->inspectable_web_contents()->CloseDevTools();
}
@end
@implementation BRYInspectableWebContentsViewPrivate
@end

View file

@ -1,14 +0,0 @@
#import "browser/mac/bry_inspectable_web_contents_view.h"
namespace brightray {
class InspectableWebContentsViewMac;
}
@interface BRYInspectableWebContentsView (Private)
- (instancetype)initWithInspectableWebContentsViewMac:(brightray::InspectableWebContentsViewMac *)inspectableWebContentsView;
- (void)setDevToolsVisible:(BOOL)visible;
- (BOOL)isDevToolsVisible;
- (BOOL)setDockSide:(const std::string&)side;
@end

View file

@ -0,0 +1,180 @@
#include "browser/views/inspectable_web_contents_view_views.h"
#include "browser/inspectable_web_contents_impl.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/web_contents_view.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/widget/widget.h"
#include "ui/views/widget/widget_delegate.h"
#include "ui/views/window/client_view.h"
namespace brightray {
namespace {
class DevToolsWindowDelegate : public views::ClientView,
public views::WidgetDelegate {
public:
DevToolsWindowDelegate(InspectableWebContentsViewViews* shell,
views::View* view,
views::Widget* widget)
: views::ClientView(widget_, view),
shell_(shell),
view_(view),
widget_(widget),
title_(base::ASCIIToUTF16("Developer Tools")) {
// A WidgetDelegate should be deleted on DeleteDelegate.
set_owned_by_client();
}
virtual ~DevToolsWindowDelegate() {}
// views::WidgetDelegate:
virtual void DeleteDelegate() OVERRIDE { delete this; }
virtual views::View* GetInitiallyFocusedView() OVERRIDE { return view_; }
virtual bool CanResize() const OVERRIDE { return true; }
virtual bool CanMaximize() const OVERRIDE { return false; }
virtual base::string16 GetWindowTitle() const OVERRIDE { return title_; }
virtual views::Widget* GetWidget() OVERRIDE { return widget_; }
virtual const views::Widget* GetWidget() const OVERRIDE { return widget_; }
virtual views::View* GetContentsView() OVERRIDE { return view_; }
virtual views::ClientView* CreateClientView(views::Widget* widget) { return this; }
// views::ClientView:
virtual bool CanClose() OVERRIDE {
shell_->inspectable_web_contents()->CloseDevTools();
return false;
}
private:
InspectableWebContentsViewViews* shell_;
views::View* view_;
views::Widget* widget_;
base::string16 title_;
DISALLOW_COPY_AND_ASSIGN(DevToolsWindowDelegate);
};
} // namespace
InspectableWebContentsView* CreateInspectableContentsView(
InspectableWebContentsImpl* inspectable_web_contents) {
return new InspectableWebContentsViewViews(inspectable_web_contents);
}
InspectableWebContentsViewViews::InspectableWebContentsViewViews(
InspectableWebContentsImpl* inspectable_web_contents)
: inspectable_web_contents_(inspectable_web_contents),
devtools_window_web_view_(NULL),
contents_web_view_(new views::WebView(NULL)),
devtools_web_view_(new views::WebView(NULL)),
devtools_visible_(false) {
set_owned_by_client();
devtools_web_view_->SetVisible(false);
contents_web_view_->SetWebContents(inspectable_web_contents_->GetWebContents());
AddChildView(devtools_web_view_);
AddChildView(contents_web_view_);
}
InspectableWebContentsViewViews::~InspectableWebContentsViewViews() {
if (devtools_window_)
inspectable_web_contents()->SaveDevToolsBounds(devtools_window_->GetWindowBoundsInScreen());
}
views::View* InspectableWebContentsViewViews::GetView() {
return this;
}
views::View* InspectableWebContentsViewViews::GetWebView() {
return contents_web_view_;
}
void InspectableWebContentsViewViews::ShowDevTools() {
if (devtools_visible_)
return;
devtools_visible_ = true;
if (devtools_window_) {
devtools_window_web_view_->SetWebContents(inspectable_web_contents_->devtools_web_contents());
devtools_window_->SetBounds(inspectable_web_contents()->GetDevToolsBounds());
devtools_window_->Show();
} else {
devtools_web_view_->SetVisible(true);
devtools_web_view_->SetWebContents(inspectable_web_contents_->devtools_web_contents());
devtools_web_view_->RequestFocus();
Layout();
}
}
void InspectableWebContentsViewViews::CloseDevTools() {
if (!devtools_visible_)
return;
devtools_visible_ = false;
if (devtools_window_) {
inspectable_web_contents()->SaveDevToolsBounds(devtools_window_->GetWindowBoundsInScreen());
devtools_window_.reset();
devtools_window_web_view_ = NULL;
} else {
devtools_web_view_->SetVisible(false);
devtools_web_view_->SetWebContents(NULL);
Layout();
}
}
bool InspectableWebContentsViewViews::IsDevToolsViewShowing() {
return devtools_visible_;
}
void InspectableWebContentsViewViews::SetIsDocked(bool docked) {
CloseDevTools();
if (!docked) {
devtools_window_.reset(new views::Widget);
devtools_window_web_view_ = new views::WebView(NULL);
views::Widget::InitParams params;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.delegate = new DevToolsWindowDelegate(this,
devtools_window_web_view_,
devtools_window_.get());
params.top_level = true;
params.remove_standard_frame = true;
devtools_window_->Init(params);
}
ShowDevTools();
}
void InspectableWebContentsViewViews::SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) {
strategy_.CopyFrom(strategy);
Layout();
}
void InspectableWebContentsViewViews::Layout() {
if (!devtools_web_view_->visible()) {
contents_web_view_->SetBoundsRect(GetContentsBounds());
return;
}
gfx::Size container_size(width(), height());
gfx::Rect old_devtools_bounds(devtools_web_view_->bounds());
gfx::Rect old_contents_bounds(contents_web_view_->bounds());
gfx::Rect new_devtools_bounds;
gfx::Rect new_contents_bounds;
ApplyDevToolsContentsResizingStrategy(strategy_, container_size,
old_devtools_bounds, old_contents_bounds,
&new_devtools_bounds, &new_contents_bounds);
// DevTools cares about the specific position, so we have to compensate RTL
// layout here.
new_devtools_bounds.set_x(GetMirroredXForRect(new_devtools_bounds));
new_contents_bounds.set_x(GetMirroredXForRect(new_contents_bounds));
devtools_web_view_->SetBoundsRect(new_devtools_bounds);
contents_web_view_->SetBoundsRect(new_contents_bounds);
}
} // namespace brightray

View file

@ -0,0 +1,60 @@
#ifndef BROWSER_VIEWS_INSPECTABLE_WEB_CONTENTS_VIEW_VIEWS_H_
#define BROWSER_VIEWS_INSPECTABLE_WEB_CONTENTS_VIEW_VIEWS_H_
#include "browser/devtools_contents_resizing_strategy.h"
#include "browser/inspectable_web_contents_view.h"
#include "base/compiler_specific.h"
#include "ui/views/view.h"
namespace views {
class WebView;
class Widget;
}
namespace brightray {
class InspectableWebContentsImpl;
class InspectableWebContentsViewViews : public InspectableWebContentsView,
public views::View {
public:
explicit InspectableWebContentsViewViews(
InspectableWebContentsImpl* inspectable_web_contents_impl);
~InspectableWebContentsViewViews();
// InspectableWebContentsView:
virtual views::View* GetView() OVERRIDE;
virtual views::View* GetWebView() OVERRIDE;
virtual void ShowDevTools() OVERRIDE;
virtual void CloseDevTools() OVERRIDE;
virtual bool IsDevToolsViewShowing() OVERRIDE;
virtual void SetIsDocked(bool docked) OVERRIDE;
virtual void SetContentsResizingStrategy(
const DevToolsContentsResizingStrategy& strategy) OVERRIDE;
InspectableWebContentsImpl* inspectable_web_contents() {
return inspectable_web_contents_;
}
private:
// views::View:
virtual void Layout() OVERRIDE;
// Owns us.
InspectableWebContentsImpl* inspectable_web_contents_;
scoped_ptr<views::Widget> devtools_window_;
views::WebView* devtools_window_web_view_;
views::WebView* contents_web_view_;
views::WebView* devtools_web_view_;
DevToolsContentsResizingStrategy strategy_;
bool devtools_visible_;
DISALLOW_COPY_AND_ASSIGN(InspectableWebContentsViewViews);
};
} // namespace brightray
#endif // BROWSER_VIEWS_INSPECTABLE_WEB_CONTENTS_VIEW_VIEWS_H_

View file

@ -0,0 +1,101 @@
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#include "browser/views/views_delegate.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
namespace brightray {
ViewsDelegate::ViewsDelegate() {
DCHECK(!views::ViewsDelegate::views_delegate);
views::ViewsDelegate::views_delegate = this;
}
ViewsDelegate::~ViewsDelegate() {
DCHECK_EQ(views::ViewsDelegate::views_delegate, this);
views::ViewsDelegate::views_delegate = NULL;
}
void ViewsDelegate::SaveWindowPlacement(const views::Widget* window,
const std::string& window_name,
const gfx::Rect& bounds,
ui::WindowShowState show_state) {
}
bool ViewsDelegate::GetSavedWindowPlacement(
const views::Widget* widget,
const std::string& window_name,
gfx::Rect* bounds,
ui::WindowShowState* show_state) const {
return false;
}
void ViewsDelegate::NotifyAccessibilityEvent(
views::View* view, ui::AXEvent event_type) {
}
void ViewsDelegate::NotifyMenuItemFocused(
const base::string16& menu_name,
const base::string16& menu_item_name,
int item_index,
int item_count,
bool has_submenu) {
}
#if defined(OS_WIN)
HICON ViewsDelegate::GetDefaultWindowIcon() const {
return NULL;
}
bool ViewsDelegate::IsWindowInMetro(gfx::NativeWindow window) const {
return false;
}
#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
gfx::ImageSkia* ViewsDelegate::GetDefaultWindowIcon() const {
return NULL;
}
#endif
views::NonClientFrameView* ViewsDelegate::CreateDefaultNonClientFrameView(
views::Widget* widget) {
return NULL;
}
void ViewsDelegate::AddRef() {
}
void ViewsDelegate::ReleaseRef() {
}
content::WebContents* ViewsDelegate::CreateWebContents(
content::BrowserContext* browser_context,
content::SiteInstance* site_instance) {
return NULL;
}
void ViewsDelegate::OnBeforeWidgetInit(
views::Widget::InitParams* params,
views::internal::NativeWidgetDelegate* delegate) {
// If we already have a native_widget, we don't have to try to come
// up with one.
if (params->native_widget)
return;
// The native_widget is required when using aura.
if (params->parent == NULL && params->context == NULL && !params->child)
params->native_widget = new views::DesktopNativeWidgetAura(delegate);
}
base::TimeDelta ViewsDelegate::GetDefaultTextfieldObscuredRevealDuration() {
return base::TimeDelta();
}
bool ViewsDelegate::WindowManagerProvidesTitleBar(bool maximized) {
return maximized;
}
} // namespace brightray

View file

@ -0,0 +1,64 @@
// Copyright (c) 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#ifndef BRIGHTRAY_BROWSER_VIEWS_VIEWS_DELEGATE_H_
#define BRIGHTRAY_BROWSER_VIEWS_VIEWS_DELEGATE_H_
#include "base/compiler_specific.h"
#include "ui/views/views_delegate.h"
namespace brightray {
class ViewsDelegate : public views::ViewsDelegate {
public:
ViewsDelegate();
virtual ~ViewsDelegate();
protected:
// views::ViewsDelegate:
virtual void SaveWindowPlacement(const views::Widget* window,
const std::string& window_name,
const gfx::Rect& bounds,
ui::WindowShowState show_state) OVERRIDE;
virtual bool GetSavedWindowPlacement(
const views::Widget* widget,
const std::string& window_name,
gfx::Rect* bounds,
ui::WindowShowState* show_state) const OVERRIDE;
virtual void NotifyAccessibilityEvent(
views::View* view, ui::AXEvent event_type) OVERRIDE;
virtual void NotifyMenuItemFocused(const base::string16& menu_name,
const base::string16& menu_item_name,
int item_index,
int item_count,
bool has_submenu) OVERRIDE;
#if defined(OS_WIN)
virtual HICON GetDefaultWindowIcon() const OVERRIDE;
virtual bool IsWindowInMetro(gfx::NativeWindow window) const OVERRIDE;
#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
virtual gfx::ImageSkia* GetDefaultWindowIcon() const OVERRIDE;
#endif
virtual views::NonClientFrameView* CreateDefaultNonClientFrameView(
views::Widget* widget) OVERRIDE;
virtual void AddRef() OVERRIDE;
virtual void ReleaseRef() OVERRIDE;
virtual content::WebContents* CreateWebContents(
content::BrowserContext* browser_context,
content::SiteInstance* site_instance) OVERRIDE;
virtual void OnBeforeWidgetInit(
views::Widget::InitParams* params,
views::internal::NativeWidgetDelegate* delegate) OVERRIDE;
virtual base::TimeDelta GetDefaultTextfieldObscuredRevealDuration() OVERRIDE;
virtual bool WindowManagerProvidesTitleBar(bool maximized) OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(ViewsDelegate);
};
} // namespace brightray
#endif // BRIGHTRAY_BROWSER_VIEWS_VIEWS_DELEGATE_H_

View file

@ -1,66 +0,0 @@
#include "browser/win/devtools_window.h"
#include "browser/inspectable_web_contents_impl.h"
#include "browser/win/inspectable_web_contents_view_win.h"
#include "content/public/browser/web_contents_view.h"
#include "ui/views/layout/fill_layout.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#include "ui/views/widget/widget_delegate.h"
namespace brightray {
namespace {
class WidgetDelegateView : public views::WidgetDelegateView {
public:
WidgetDelegateView() {
SetLayoutManager(new views::FillLayout);
}
virtual void DeleteDelegate() OVERRIDE { delete this; }
virtual views::View* GetContentsView() OVERRIDE { return this; }
virtual bool CanResize() const OVERRIDE { return true; }
virtual bool CanMaximize() const OVERRIDE { return true; }
virtual base::string16 GetWindowTitle() const OVERRIDE { return L"Developer Tools"; }
virtual gfx::Size GetPreferredSize() OVERRIDE { return gfx::Size(800, 600); }
virtual gfx::Size GetMinimumSize() OVERRIDE { return gfx::Size(100, 100); }
};
} // namespace
DevToolsWindow* DevToolsWindow::Create(
InspectableWebContentsViewWin* controller) {
return new DevToolsWindow(controller);
}
DevToolsWindow::DevToolsWindow(InspectableWebContentsViewWin* controller)
: controller_(controller),
widget_(new views::Widget) {
auto delegate_view = new WidgetDelegateView;
views::Widget::InitParams params;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.top_level = true;
params.native_widget = new views::DesktopNativeWidgetAura(widget_.get());
params.delegate = delegate_view;
widget_->Init(params);
delegate_view->AddChildView(controller->GetView());
delegate_view->Layout();
}
DevToolsWindow::~DevToolsWindow() {
}
void DevToolsWindow::Show() {
widget_->Show();
}
void DevToolsWindow::Close() {
widget_->Hide();
}
void DevToolsWindow::Destroy() {
delete this;
}
} // namespace brightray

View file

@ -1,37 +0,0 @@
#ifndef BRIGHTRAY_BROWSER_WIN_DEVTOOLS_WINDOW_H_
#define BRIGHTRAY_BROWSER_WIN_DEVTOOLS_WINDOW_H_
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
namespace views {
class Widget;
}
namespace brightray {
class InspectableWebContentsViewWin;
class DevToolsWindow : public base::SupportsWeakPtr<DevToolsWindow> {
public:
static DevToolsWindow* Create(
InspectableWebContentsViewWin* inspectable_web_contents_view_win);
void Show();
void Close();
void Destroy();
private:
explicit DevToolsWindow(
InspectableWebContentsViewWin* inspectable_web_contents_view_win);
~DevToolsWindow();
InspectableWebContentsViewWin* controller_;
scoped_ptr<views::Widget> widget_;
DISALLOW_COPY_AND_ASSIGN(DevToolsWindow);
};
} // namespace brightray
#endif

View file

@ -1,201 +0,0 @@
#include "browser/win/inspectable_web_contents_view_win.h"
#include "browser/browser_client.h"
#include "browser/inspectable_web_contents_impl.h"
#include "browser/win/devtools_window.h"
#include "content/public/browser/web_contents_view.h"
#include "ui/gfx/win/hwnd_util.h"
#include "ui/views/controls/single_split_view.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/view.h"
namespace brightray {
namespace {
const int kWindowInset = 100;
}
class ContainerView : public views::View {
public:
explicit ContainerView(InspectableWebContentsViewWin* web_contents_view)
: container_view_created_(false),
dockside_("none"), // "none" is treated as "bottom".
web_view_(new views::WebView(NULL)),
web_contents_view_(web_contents_view) {
set_owned_by_client();
web_view_->set_owned_by_client();
web_view_->SetWebContents(
web_contents_view_->inspectable_web_contents()->GetWebContents());
}
views::View* GetWebView() const {
return web_view_.get();
}
void ShowDevTools() {
if (IsDevToolsViewShowing())
return;
RemoveChildView(web_view_.get());
devtools_view_ = new views::WebView(NULL);
devtools_view_->SetWebContents(web_contents_view_->
inspectable_web_contents()->devtools_web_contents());
split_view_.reset(new views::SingleSplitView(
web_view_.get(),
devtools_view_,
GetSplitViewOrientation(),
NULL));
split_view_->set_divider_offset(GetSplitVievDividerOffset());
AddChildView(split_view_.get());
Layout();
devtools_view_->RequestFocus();
}
void CloseDevTools() {
if (!IsDevToolsViewShowing())
return;
RemoveChildView(split_view_.get());
split_view_.reset();
AddChildView(web_view_.get());
Layout();
}
bool IsDevToolsViewShowing() {
return split_view_;
}
void SetDockSide(const std::string& side) {
if (dockside_ == side)
return; // no change from current location
dockside_ = side;
if (!IsDevToolsViewShowing())
return;
split_view_->set_orientation(GetSplitViewOrientation());
split_view_->set_divider_offset(GetSplitVievDividerOffset());
split_view_->Layout();
return;
}
private:
// views::View:
virtual void Layout() OVERRIDE {
if (split_view_)
split_view_->SetBounds(0, 0, width(), height());
else
web_view_->SetBounds(0, 0, width(), height());
}
virtual void ViewHierarchyChanged(
const ViewHierarchyChangedDetails& details) OVERRIDE {
View::ViewHierarchyChanged(details);
// We're not using child == this because a Widget may not be
// available when this is added to the hierarchy.
if (details.is_add && GetWidget() && !container_view_created_) {
container_view_created_ = true;
AddChildView(web_view_.get());
}
}
views::SingleSplitView::Orientation GetSplitViewOrientation() const {
if (dockside_ == "right")
return views::SingleSplitView::HORIZONTAL_SPLIT;
else
return views::SingleSplitView::VERTICAL_SPLIT;
}
int GetSplitVievDividerOffset() const {
if (dockside_ == "right")
return width() * 2 / 3;
else
return height() * 2 / 3;
}
// True if the container view has already been created, or false otherwise.
bool container_view_created_;
std::string dockside_;
scoped_ptr<views::WebView> web_view_;
scoped_ptr<views::SingleSplitView> split_view_;
views::WebView* devtools_view_; // Owned by split_view_.
InspectableWebContentsViewWin* web_contents_view_;
};
InspectableWebContentsView* CreateInspectableContentsView(
InspectableWebContentsImpl* inspectable_web_contents) {
return new InspectableWebContentsViewWin(inspectable_web_contents);
}
InspectableWebContentsViewWin::InspectableWebContentsViewWin(
InspectableWebContentsImpl* inspectable_web_contents)
: inspectable_web_contents_(inspectable_web_contents),
undocked_(false),
container_(new ContainerView(this)) {
}
InspectableWebContentsViewWin::~InspectableWebContentsViewWin() {
if (devtools_window_)
devtools_window_->Destroy();
}
views::View* InspectableWebContentsViewWin::GetView() const {
return container_.get();
}
views::View* InspectableWebContentsViewWin::GetWebView() const {
return container_->GetWebView();
}
gfx::NativeView InspectableWebContentsViewWin::GetNativeView() const {
auto web_contents = inspectable_web_contents_->GetWebContents();
return web_contents->GetView()->GetNativeView();
}
void InspectableWebContentsViewWin::ShowDevTools() {
if (undocked_) {
if (!devtools_window_)
devtools_window_ = DevToolsWindow::Create(this)->AsWeakPtr();
devtools_window_->Show();
} else {
container_->ShowDevTools();
}
}
void InspectableWebContentsViewWin::CloseDevTools() {
if (undocked_)
devtools_window_->Close();
else
container_->CloseDevTools();
}
bool InspectableWebContentsViewWin::IsDevToolsViewShowing() {
return container_->IsDevToolsViewShowing() || devtools_window_;
}
bool InspectableWebContentsViewWin::SetDockSide(const std::string& side) {
if (side == "undocked") {
undocked_ = true;
container_->CloseDevTools();
} else if (side == "right" || side == "bottom") {
undocked_ = false;
if (devtools_window_)
devtools_window_->Close();
container_->SetDockSide(side);
} else {
return false;
}
ShowDevTools();
return true;
}
} // namespace brightray

View file

@ -1,61 +0,0 @@
#ifndef BRIGHTRAY_BROWSER_WIN_INSPECTABLE_WEB_CONTENTS_VIEW_WIN_H_
#define BRIGHTRAY_BROWSER_WIN_INSPECTABLE_WEB_CONTENTS_VIEW_WIN_H_
#include "browser/inspectable_web_contents_view.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
namespace views {
class View;
}
namespace brightray {
class ContainerView;
class DevToolsWindow;
class InspectableWebContentsImpl;
class InspectableWebContentsViewWin : public InspectableWebContentsView {
public:
explicit InspectableWebContentsViewWin(
InspectableWebContentsImpl* inspectable_web_contents_impl);
~InspectableWebContentsViewWin();
// Returns the container control, which has devtools view attached. Unlike
// GetNativeView(), this returns a views::View instead of HWND, and can only
// be used by applications that use the views library, if you don't use the
// views library, you probably want to set dock side to "undocked" before
// showing the devtools, because devtools is showed attached by default and
// attached devtools is currently only supported when using views library.
views::View* GetView() const;
// Returns the web view control, which can be used by the
// GetInitiallyFocusedView() to set initial focus to web view.
views::View* GetWebView() const;
virtual gfx::NativeView GetNativeView() const OVERRIDE;
virtual void ShowDevTools() OVERRIDE;
virtual void CloseDevTools() OVERRIDE;
virtual bool IsDevToolsViewShowing() OVERRIDE;
virtual bool SetDockSide(const std::string& side) OVERRIDE;
InspectableWebContentsImpl* inspectable_web_contents() {
return inspectable_web_contents_;
}
private:
// Owns us.
InspectableWebContentsImpl* inspectable_web_contents_;
bool undocked_;
scoped_ptr<ContainerView> container_;
base::WeakPtr<DevToolsWindow> devtools_window_;
DISALLOW_COPY_AND_ASSIGN(InspectableWebContentsViewWin);
};
} // namespace brightray
#endif

View file

@ -38,6 +38,14 @@ class MainDelegate : public content::ContentMainDelegate {
// included in the ui::ResourceBundle.
virtual void AddPakPaths(std::vector<base::FilePath>* pak_paths) {}
#if defined(OS_MACOSX)
// Subclasses can override this to custom the paths of child process and
// framework bundle.
virtual base::FilePath GetResourcesPakFilePath();
virtual void OverrideChildProcessPath();
virtual void OverrideFrameworkBundlePath();
#endif
virtual bool BasicStartupComplete(int* exit_code) OVERRIDE;
virtual void PreSandboxStartup() OVERRIDE;
@ -45,11 +53,6 @@ class MainDelegate : public content::ContentMainDelegate {
virtual content::ContentBrowserClient* CreateContentBrowserClient() OVERRIDE;
void InitializeResourceBundle();
#if defined(OS_MACOSX)
static base::FilePath GetResourcesPakFilePath();
static void OverrideChildProcessPath();
static void OverrideFrameworkBundlePath();
#endif
scoped_ptr<ContentClient> content_client_;
scoped_ptr<BrowserClient> browser_client_;

View file

@ -11,7 +11,7 @@ CPPLINT = os.path.join(SOURCE_ROOT, 'vendor', 'google-styleguide', 'trunk', 'cpp
LINE_LENGTH = 100
IGNORED_FILES = [
os.path.join('browser', 'mac', 'bry_inspectable_web_contents_view_private.h'),
os.path.join('browser', 'mac', 'bry_inspectable_web_contents_view.h'),
]
FILTERS = [

@ -1 +1 @@
Subproject commit 331dbed44676c534faf21f7db1985e796260649a
Subproject commit 4b4bcec11a02d1c7981562cf0b8a4670c338992b