From 2efeaa268fd2f0fe8a0bd36ccf78bba52860f019 Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Wed, 2 Jul 2014 16:21:47 +0800 Subject: [PATCH] Place DevTools WebContents underneath inspected WebContents. This commit has this strategy implemented on Mac. See https://code.google.com/p/chromium/issues/detail?id=318751. --- brightray/brightray.gyp | 2 + .../devtools_contents_resizing_strategy.cc | 85 +++++++++++++ .../devtools_contents_resizing_strategy.h | 56 +++++++++ .../devtools_embedder_message_dispatcher.cc | 65 +++++++++- .../devtools_embedder_message_dispatcher.h | 6 +- .../inspectable_web_contents_delegate.h | 12 -- .../browser/inspectable_web_contents_impl.cc | 61 ++++----- .../browser/inspectable_web_contents_impl.h | 11 +- .../browser/inspectable_web_contents_view.h | 6 +- .../inspectable_web_contents_view_mac.h | 4 +- .../inspectable_web_contents_view_mac.mm | 18 ++- .../mac/bry_inspectable_web_contents_view.h | 17 ++- .../mac/bry_inspectable_web_contents_view.mm | 118 ++++++++++++++---- 13 files changed, 370 insertions(+), 91 deletions(-) create mode 100644 brightray/browser/devtools_contents_resizing_strategy.cc create mode 100644 brightray/browser/devtools_contents_resizing_strategy.h diff --git a/brightray/brightray.gyp b/brightray/brightray.gyp index 1c37fe83c2..aae368994d 100644 --- a/brightray/brightray.gyp +++ b/brightray/brightray.gyp @@ -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', diff --git a/brightray/browser/devtools_contents_resizing_strategy.cc b/brightray/browser/devtools_contents_resizing_strategy.cc new file mode 100644 index 0000000000..15d7a5253f --- /dev/null +++ b/brightray/browser/devtools_contents_resizing_strategy.cc @@ -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 + +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); +} diff --git a/brightray/browser/devtools_contents_resizing_strategy.h b/brightray/browser/devtools_contents_resizing_strategy.h new file mode 100644 index 0000000000..86ea260c71 --- /dev/null +++ b/brightray/browser/devtools_contents_resizing_strategy.h @@ -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_ diff --git a/brightray/browser/devtools_embedder_message_dispatcher.cc b/brightray/browser/devtools_embedder_message_dispatcher.cc index 2d6c61ec1c..98e4732208 100644 --- a/brightray/browser/devtools_embedder_message_dispatcher.cc +++ b/brightray/browser/devtools_embedder_message_dispatcher.cc @@ -27,6 +27,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 struct StorageTraits { typedef T StorageType; @@ -105,6 +135,28 @@ bool ParseAndHandle3(const base::Callback& handler, return true; } +template +bool ParseAndHandle3(const base::Callback& handler, + const base::ListValue& list) { + if (list.GetSize() != 3) + return false; + Argument arg1(list, 0); + if (!arg1.valid()) + return false; + Argument arg2(list, 1); + if (!arg2.valid()) + return false; + Argument arg3(list, 2); + if (!arg3.valid()) + return false; + Argument arg4(list, 3); + if (!arg4.valid()) + return false; + handler.Run(arg1.value(), arg2.value(), arg3.value(), arg4.value()); + return true; +} + + typedef base::Callback ListValueParser; ListValueParser BindToListParser(const base::Callback& handler) { @@ -127,6 +179,12 @@ ListValueParser BindToListParser( return base::Bind(&ParseAndHandle3, handler); } +template +ListValueParser BindToListParser( + const base::Callback& handler) { + return base::Bind(&ParseAndHandle3, handler); +} + } // namespace DevToolsEmbedderMessageDispatcher::DevToolsEmbedderMessageDispatcher( @@ -137,11 +195,14 @@ DevToolsEmbedderMessageDispatcher::DevToolsEmbedderMessageDispatcher( RegisterHandler("closeWindow", BindToListParser(base::Bind(&Delegate::CloseWindow, base::Unretained(delegate)))); + RegisterHandler("setContentsResizingStrategy", + BindToListParser(base::Bind(&Delegate::SetContentsResizingStrategy, + 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, diff --git a/brightray/browser/devtools_embedder_message_dispatcher.h b/brightray/browser/devtools_embedder_message_dispatcher.h index df21050320..1f4a6e5d00 100644 --- a/brightray/browser/devtools_embedder_message_dispatcher.h +++ b/brightray/browser/devtools_embedder_message_dispatcher.h @@ -9,6 +9,8 @@ #include #include "base/callback.h" +#include "ui/gfx/insets.h" +#include "ui/gfx/size.h" namespace base { class ListValue; @@ -30,8 +32,10 @@ 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 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, diff --git a/brightray/browser/inspectable_web_contents_delegate.h b/brightray/browser/inspectable_web_contents_delegate.h index d86285789e..a6dc5e1c78 100644 --- a/brightray/browser/inspectable_web_contents_delegate.h +++ b/brightray/browser/inspectable_web_contents_delegate.h @@ -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) {} diff --git a/brightray/browser/inspectable_web_contents_impl.cc b/brightray/browser/inspectable_web_contents_impl.cc index 739acf44ec..fa9b792976 100644 --- a/brightray/browser/inspectable_web_contents_impl.cc +++ b/brightray/browser/inspectable_web_contents_impl.cc @@ -26,8 +26,8 @@ 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 kIsDockedPref[] = "brightray.devtools.isDocked"; } @@ -36,7 +36,7 @@ InspectableWebContentsView* CreateInspectableContentsView( InspectableWebContentsImpl* inspectable_web_contents_impl); void InspectableWebContentsImpl::RegisterPrefs(PrefRegistrySimple* registry) { - registry->RegisterStringPref(kDockSidePref, "bottom"); + registry->RegisterBooleanPref(kIsDockedPref, true); } InspectableWebContentsImpl::InspectableWebContentsImpl( @@ -45,7 +45,7 @@ InspectableWebContentsImpl::InspectableWebContentsImpl( delegate_(nullptr) { auto context = static_cast( web_contents_->GetBrowserContext()); - dock_side_ = context->prefs()->GetString(kDockSidePref); + is_docked_ = context->prefs()->GetBoolean(kIsDockedPref); view_.reset(CreateInspectableContentsView(this)); } @@ -62,6 +62,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 +72,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 +89,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,13 +106,6 @@ 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)); -} - void InspectableWebContentsImpl::ActivateWindow() { } @@ -127,25 +113,26 @@ 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::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; +void InspectableWebContentsImpl::SetIsDocked(bool docked) { + view_->SetIsDocked(docked); + is_docked_ = docked; auto context = static_cast( web_contents_->GetBrowserContext()); - context->prefs()->SetString(kDockSidePref, side); - - UpdateFrontendDockSide(); + context->prefs()->SetBoolean(kIsDockedPref, docked); } void InspectableWebContentsImpl::OpenInNewTab(const std::string& url) { @@ -207,7 +194,7 @@ void InspectableWebContentsImpl::DidFinishLoad(int64 frame_id, if (!is_main_frame) return; - UpdateFrontendDockSide(); + view_->ShowDevTools(); } void InspectableWebContentsImpl::WebContentsDestroyed(content::WebContents*) { diff --git a/brightray/browser/inspectable_web_contents_impl.h b/brightray/browser/inspectable_web_contents_impl.h index 8581b24ec4..913c59323c 100644 --- a/brightray/browser/inspectable_web_contents_impl.h +++ b/brightray/browser/inspectable_web_contents_impl.h @@ -8,6 +8,7 @@ #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" @@ -54,14 +55,14 @@ 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 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, @@ -103,7 +104,9 @@ class InspectableWebContentsImpl : scoped_ptr devtools_web_contents_; scoped_ptr view_; scoped_refptr agent_host_; - std::string dock_side_; + + bool is_docked_; + DevToolsContentsResizingStrategy contents_resizing_strategy_; scoped_ptr embedder_message_dispatcher_; diff --git a/brightray/browser/inspectable_web_contents_view.h b/brightray/browser/inspectable_web_contents_view.h index 18fd192a67..251d4337a4 100644 --- a/brightray/browser/inspectable_web_contents_view.h +++ b/brightray/browser/inspectable_web_contents_view.h @@ -3,6 +3,8 @@ #include "ui/gfx/native_widget_types.h" +class DevToolsContentsResizingStrategy; + namespace brightray { class InspectableWebContentsView { @@ -15,7 +17,9 @@ class InspectableWebContentsView { // 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 diff --git a/brightray/browser/inspectable_web_contents_view_mac.h b/brightray/browser/inspectable_web_contents_view_mac.h index 927a91a362..29a55bdd08 100644 --- a/brightray/browser/inspectable_web_contents_view_mac.h +++ b/brightray/browser/inspectable_web_contents_view_mac.h @@ -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_; diff --git a/brightray/browser/inspectable_web_contents_view_mac.mm b/brightray/browser/inspectable_web_contents_view_mac.mm index 6ab9711727..89eb8ec074 100644 --- a/brightray/browser/inspectable_web_contents_view_mac.mm +++ b/brightray/browser/inspectable_web_contents_view_mac.mm @@ -1,10 +1,11 @@ -#import "browser/inspectable_web_contents_view_mac.h" +#include "browser/inspectable_web_contents_view_mac.h" -#import "browser/inspectable_web_contents.h" +#import + +#include "browser/inspectable_web_contents.h" #import "browser/mac/bry_inspectable_web_contents_view.h" -#import "content/public/browser/web_contents_view.h" -#import +#include "content/public/browser/web_contents_view.h" namespace brightray { @@ -36,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]; } } diff --git a/brightray/browser/mac/bry_inspectable_web_contents_view.h b/brightray/browser/mac/bry_inspectable_web_contents_view.h index f689f1f38c..d5761bb5ee 100644 --- a/brightray/browser/mac/bry_inspectable_web_contents_view.h +++ b/brightray/browser/mac/bry_inspectable_web_contents_view.h @@ -1,24 +1,33 @@ #import -#include +#include "browser/devtools_contents_resizing_strategy.h" #include "base/mac/scoped_nsobject.h" +#include "ui/base/cocoa/base_view.h" +#include "ui/gfx/insets.h" namespace brightray { class InspectableWebContentsViewMac; } -@interface BRYInspectableWebContentsView : NSView { +@interface BRYInspectableWebContentsView : BaseView { @private brightray::InspectableWebContentsViewMac* inspectableWebContentsView_; + base::scoped_nsobject devtools_window_; BOOL devtools_visible_; + BOOL devtools_docked_; + + DevToolsContentsResizingStrategy strategy_; } - (instancetype)initWithInspectableWebContentsViewMac:(brightray::InspectableWebContentsViewMac*)inspectableWebContentsView; -- (IBAction)showDevTools:(id)sender; - (void)setDevToolsVisible:(BOOL)visible; - (BOOL)isDevToolsVisible; -- (BOOL)setDockSide:(const std::string&)side ; +- (void)setIsDocked:(BOOL)docked; +- (void)setContentsResizingStrategy:(const DevToolsContentsResizingStrategy&)strategy; + +// Adjust docked devtools to the contents resizing strategy. +- (void)update; @end diff --git a/brightray/browser/mac/bry_inspectable_web_contents_view.mm b/brightray/browser/mac/bry_inspectable_web_contents_view.mm index 8c463dd325..22a0d02d40 100644 --- a/brightray/browser/mac/bry_inspectable_web_contents_view.mm +++ b/brightray/browser/mac/bry_inspectable_web_contents_view.mm @@ -1,11 +1,12 @@ -#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" +#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; @@ -18,10 +19,12 @@ using namespace brightray; inspectableWebContentsView_ = inspectableWebContentsView; devtools_visible_ = NO; + devtools_docked_ = NO; - auto webView = inspectableWebContentsView->inspectable_web_contents()->GetWebContents()->GetView()->GetNativeView(); - webView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; - [self addSubview:webView]; + auto contents = inspectableWebContentsView->inspectable_web_contents()->GetWebContents(); + auto contentsView = contents->GetView()->GetNativeView(); + [contentsView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [self addSubview:contentsView]; return self; } @@ -30,16 +33,53 @@ using namespace brightray; [super dealloc]; } +- (void)resizeSubviewsWithOldSize:(NSSize)oldBoundsSize { + [self adjustSubviews]; +} + - (IBAction)showDevTools:(id)sender { inspectableWebContentsView_->inspectable_web_contents()->ShowDevTools(); } - (void)setDevToolsVisible:(BOOL)visible { - if (devtools_visible_ == visible) + if (visible == devtools_visible_) return; - devtools_visible_ = visible; - if (!devtools_window_) { + auto devToolsWebContents = inspectableWebContentsView_->inspectable_web_contents()->devtools_web_contents(); + auto devToolsView = devToolsWebContents->GetView()->GetNativeView(); + + 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 { + gfx::ScopedNSDisableScreenUpdates disabler; + devToolsWebContents->GetView()->RemoveOverlayView(); + [devToolsView removeFromSuperview]; + [self adjustSubviews]; + } + } else { + if (visible) + [devtools_window_ makeKeyAndOrderFront:nil]; + else + devtools_window_.reset(); + } +} + +- (BOOL)isDevToolsVisible { + return devtools_visible_; +} + +- (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(); @@ -65,27 +105,59 @@ using namespace brightray; [contentView addSubview:devToolsView]; } + [self setDevToolsVisible:YES]; +} - if (visible) { - [devtools_window_ makeKeyAndOrderFront:nil]; - } else { - [devtools_window_ performClose:nil]; +- (void)setContentsResizingStrategy:(const DevToolsContentsResizingStrategy&)strategy { + strategy_.CopyFrom(strategy); + [self update]; +} + +- (void)update { + if (!devtools_docked_) + return; + + 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]; +} + +- (void)adjustSubviews { + if (![[self subviews] count]) + return; + + if (![self isDevToolsVisible] || devtools_window_) { + DCHECK_EQ(1u, [[self subviews] count]); + NSView* contents = [[self subviews] objectAtIndex:0]; + [contents setFrame:[self bounds]]; + return; } -} -- (BOOL)isDevToolsVisible { - return devtools_visible_; -} + NSView* devToolsView = [[self subviews] objectAtIndex:0]; + NSView* contentsView = [[self subviews] objectAtIndex:1]; -- (BOOL)setDockSide:(const std::string&)side { - return NO; + 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 - (void)windowWillClose:(NSNotification*)notification { - devtools_visible_ = NO; - devtools_window_.reset(); + inspectableWebContentsView_->inspectable_web_contents()->CloseDevTools(); } @end