diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index b4748d81630a..f59b72bd0c9c 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -896,9 +896,10 @@ void WebContents::DevToolsOpened() { "DevToolsAPI.setInspectedTabId", &tab_id, nullptr, nullptr); // Inherit owner window in devtools. - if (owner_window()) - handle->SetOwnerWindow(managed_web_contents()->GetDevToolsWebContents(), - owner_window()); + auto* devtools = managed_web_contents()->GetDevToolsWebContents(); + if (owner_window() && + !devtools->GetUserData(NativeWindowRelay::UserDataKey())) + handle->SetOwnerWindow(devtools, owner_window()); Emit("devtools-opened"); } @@ -1808,6 +1809,11 @@ void WebContents::SetEmbedder(const WebContents* embedder) { } } +void WebContents::SetDevToolsWebContents(const WebContents* devtools) { + if (managed_web_contents()) + managed_web_contents()->SetDevToolsWebContents(devtools->web_contents()); +} + v8::Local WebContents::GetNativeView() const { gfx::NativeView ptr = web_contents()->GetNativeView(); auto buffer = node::Buffer::Copy( @@ -1929,6 +1935,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate, .SetMethod("copyImageAt", &WebContents::CopyImageAt) .SetMethod("capturePage", &WebContents::CapturePage) .SetMethod("setEmbedder", &WebContents::SetEmbedder) + .SetMethod("setDevToolsWebContents", &WebContents::SetDevToolsWebContents) .SetMethod("getNativeView", &WebContents::GetNativeView) .SetMethod("setWebRTCIPHandlingPolicy", &WebContents::SetWebRTCIPHandlingPolicy) diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 2abdd2accc28..16f23210557c 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -126,6 +126,7 @@ class WebContents : public mate::TrackableObject, void Print(mate::Arguments* args); std::vector GetPrinterList(); void SetEmbedder(const WebContents* embedder); + void SetDevToolsWebContents(const WebContents* devtools); v8::Local GetNativeView() const; // Print current page as PDF. diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 1e02a37fc07d..09780be079f1 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -391,6 +391,10 @@ class NativeWindowRelay : explicit NativeWindowRelay(base::WeakPtr window) : key(UserDataKey()), window(window) {} + static void* UserDataKey() { + return content::WebContentsUserData::UserDataKey(); + } + void* key; base::WeakPtr window; diff --git a/brightray/browser/inspectable_web_contents.h b/brightray/browser/inspectable_web_contents.h index 28c00f6d72df..7b0a010b9e21 100644 --- a/brightray/browser/inspectable_web_contents.h +++ b/brightray/browser/inspectable_web_contents.h @@ -37,6 +37,7 @@ class InspectableWebContents { virtual void SetDelegate(InspectableWebContentsDelegate* delegate) = 0; virtual InspectableWebContentsDelegate* GetDelegate() const = 0; + virtual void SetDevToolsWebContents(content::WebContents* devtools) = 0; virtual void SetDockState(const std::string& state) = 0; virtual void ShowDevTools() = 0; virtual void CloseDevTools() = 0; diff --git a/brightray/browser/inspectable_web_contents_impl.cc b/brightray/browser/inspectable_web_contents_impl.cc index 4d0826990c8c..ad18f69bce50 100644 --- a/brightray/browser/inspectable_web_contents_impl.cc +++ b/brightray/browser/inspectable_web_contents_impl.cc @@ -242,13 +242,14 @@ InspectableWebContentsImpl::InspectableWebContentsImpl( InspectableWebContentsImpl::~InspectableWebContentsImpl() { // Unsubscribe from devtools and Clean up resources. - if (devtools_web_contents_) { - devtools_web_contents_->SetDelegate(nullptr); + if (GetDevToolsWebContents()) { + if (managed_devtools_web_contents_) + managed_devtools_web_contents_->SetDelegate(nullptr); // Calling this also unsubscribes the observer, so WebContentsDestroyed // won't be called again. WebContentsDestroyed(); } - // Let destructor destroy devtools_web_contents_. + // Let destructor destroy managed_devtools_web_contents_. } InspectableWebContentsView* InspectableWebContentsImpl::GetView() const { @@ -261,7 +262,10 @@ content::WebContents* InspectableWebContentsImpl::GetWebContents() const { content::WebContents* InspectableWebContentsImpl::GetDevToolsWebContents() const { - return devtools_web_contents_.get(); + if (external_devtools_web_contents_) + return external_devtools_web_contents_; + else + return managed_devtools_web_contents_.get(); } void InspectableWebContentsImpl::InspectElement(int x, int y) { @@ -288,43 +292,56 @@ void InspectableWebContentsImpl::SetDockState(const std::string& state) { } } +void InspectableWebContentsImpl::SetDevToolsWebContents( + content::WebContents* devtools) { + if (!managed_devtools_web_contents_) + external_devtools_web_contents_ = devtools; +} + void InspectableWebContentsImpl::ShowDevTools() { + if (embedder_message_dispatcher_) { + if (managed_devtools_web_contents_) + view_->ShowDevTools(); + return; + } + // 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( - DevToolsEmbedderMessageDispatcher::CreateForDevToolsFrontend(this)); + embedder_message_dispatcher_.reset( + DevToolsEmbedderMessageDispatcher::CreateForDevToolsFrontend(this)); - content::WebContents::CreateParams create_params( - web_contents_->GetBrowserContext()); - devtools_web_contents_.reset(content::WebContents::Create(create_params)); - - Observe(devtools_web_contents_.get()); - devtools_web_contents_->SetDelegate(this); - - AttachTo(content::DevToolsAgentHost::GetOrCreateFor(web_contents_.get())); - - devtools_web_contents_->GetController().LoadURL( - GetDevToolsURL(can_dock_), - content::Referrer(), - ui::PAGE_TRANSITION_AUTO_TOPLEVEL, - std::string()); - } else { - view_->ShowDevTools(); + if (!external_devtools_web_contents_) { // no external devtools + managed_devtools_web_contents_.reset( + content::WebContents::Create( + content::WebContents::CreateParams( + web_contents_->GetBrowserContext()))); + managed_devtools_web_contents_->SetDelegate(this); } + + Observe(GetDevToolsWebContents()); + AttachTo(content::DevToolsAgentHost::GetOrCreateFor(web_contents_.get())); + + GetDevToolsWebContents()->GetController().LoadURL( + GetDevToolsURL(can_dock_), + content::Referrer(), + ui::PAGE_TRANSITION_AUTO_TOPLEVEL, + std::string()); } void InspectableWebContentsImpl::CloseDevTools() { - if (devtools_web_contents_) { + if (GetDevToolsWebContents()) { frontend_loaded_ = false; - view_->CloseDevTools(); - devtools_web_contents_.reset(); + if (managed_devtools_web_contents_) { + view_->CloseDevTools(); + managed_devtools_web_contents_.reset(); + } + embedder_message_dispatcher_.reset(); web_contents_->Focus(); } } bool InspectableWebContentsImpl::IsDevToolsViewShowing() { - return devtools_web_contents_ && view_->IsDevToolsViewShowing(); + return managed_devtools_web_contents_ && view_->IsDevToolsViewShowing(); } void InspectableWebContentsImpl::AttachTo( @@ -347,7 +364,7 @@ void InspectableWebContentsImpl::CallClientFunction( const base::Value* arg1, const base::Value* arg2, const base::Value* arg3) { - if (!devtools_web_contents_) + if (!GetDevToolsWebContents()) return; std::string javascript = function_name + "("; @@ -365,7 +382,7 @@ void InspectableWebContentsImpl::CallClientFunction( } } javascript.append(");"); - devtools_web_contents_->GetMainFrame()->ExecuteJavaScript( + GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript( base::UTF8ToUTF16(javascript)); } @@ -400,7 +417,8 @@ void InspectableWebContentsImpl::CloseWindow() { void InspectableWebContentsImpl::LoadCompleted() { frontend_loaded_ = true; - view_->ShowDevTools(); + if (managed_devtools_web_contents_) + view_->ShowDevTools(); // If the devtools can dock, "SetIsDocked" will be called by devtools itself. if (!can_dock_) { @@ -415,7 +433,7 @@ void InspectableWebContentsImpl::LoadCompleted() { } base::string16 javascript = base::UTF8ToUTF16( "Components.dockController.setDockSide(\"" + dock_state_ + "\");"); - devtools_web_contents_->GetMainFrame()->ExecuteJavaScript(javascript); + GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript(javascript); } if (view_->GetDelegate()) @@ -428,15 +446,17 @@ void InspectableWebContentsImpl::SetInspectedPageBounds(const gfx::Rect& rect) { return; contents_resizing_strategy_.CopyFrom(strategy); - view_->SetContentsResizingStrategy(contents_resizing_strategy_); + if (managed_devtools_web_contents_) + view_->SetContentsResizingStrategy(contents_resizing_strategy_); } void InspectableWebContentsImpl::InspectElementCompleted() { } void InspectableWebContentsImpl::InspectedURLChanged(const std::string& url) { - view_->SetTitle(base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, - url.c_str()))); + if (managed_devtools_web_contents_) + view_->SetTitle(base::UTF8ToUTF16(base::StringPrintf(kTitleFormat, + url.c_str()))); } void InspectableWebContentsImpl::LoadNetworkResource( @@ -452,8 +472,8 @@ void InspectableWebContentsImpl::LoadNetworkResource( return; } - auto browser_context = - static_cast(devtools_web_contents_->GetBrowserContext()); + auto* browser_context = static_cast( + GetDevToolsWebContents()->GetBrowserContext()); net::URLFetcher* fetcher = (net::URLFetcher::Create(gurl, net::URLFetcher::GET, this)).release(); @@ -468,7 +488,8 @@ void InspectableWebContentsImpl::LoadNetworkResource( void InspectableWebContentsImpl::SetIsDocked(const DispatchCallback& callback, bool docked) { - view_->SetIsDocked(docked); + if (managed_devtools_web_contents_) + view_->SetIsDocked(docked); if (!callback.is_null()) callback.Run(nullptr); } @@ -640,7 +661,7 @@ void InspectableWebContentsImpl::DispatchProtocolMessage( if (message.length() < kMaxMessageChunkSize) { base::string16 javascript = base::UTF8ToUTF16( "DevToolsAPI.dispatchMessage(" + message + ");"); - devtools_web_contents_->GetMainFrame()->ExecuteJavaScript(javascript); + GetDevToolsWebContents()->GetMainFrame()->ExecuteJavaScript(javascript); return; } @@ -664,13 +685,15 @@ void InspectableWebContentsImpl::RenderFrameHostChanged( frontend_host_.reset(content::DevToolsFrontendHost::Create( new_host, base::Bind(&InspectableWebContentsImpl::HandleMessageFromDevToolsFrontend, - base::Unretained(this)))); + weak_factory_.GetWeakPtr()))); } void InspectableWebContentsImpl::WebContentsDestroyed() { frontend_loaded_ = false; + external_devtools_web_contents_ = nullptr; Observe(nullptr); Detach(); + embedder_message_dispatcher_.reset(); for (const auto& pair : pending_requests_) delete pair.first; @@ -758,7 +781,7 @@ void InspectableWebContentsImpl::ReadyToCommitNavigation( content::NavigationHandle* navigation_handle) { if (navigation_handle->IsInMainFrame()) { if (navigation_handle->GetRenderFrameHost() == - devtools_web_contents_->GetMainFrame() && + GetDevToolsWebContents()->GetMainFrame() && frontend_host_) { return; } diff --git a/brightray/browser/inspectable_web_contents_impl.h b/brightray/browser/inspectable_web_contents_impl.h index c2f359bcd297..6c1b34d8635e 100644 --- a/brightray/browser/inspectable_web_contents_impl.h +++ b/brightray/browser/inspectable_web_contents_impl.h @@ -48,6 +48,7 @@ class InspectableWebContentsImpl : void SetDelegate(InspectableWebContentsDelegate* delegate) override; InspectableWebContentsDelegate* GetDelegate() const override; + void SetDevToolsWebContents(content::WebContents* devtools) override; void SetDockState(const std::string& state) override; void ShowDevTools() override; void CloseDevTools() override; @@ -192,7 +193,13 @@ class InspectableWebContentsImpl : PrefService* pref_service_; // weak reference. std::unique_ptr web_contents_; - std::unique_ptr devtools_web_contents_; + + // The default devtools created by this class when we don't have an external + // one assigned by SetDevToolsWebContents. + std::unique_ptr managed_devtools_web_contents_; + // The external devtools assigned by SetDevToolsWebContents. + content::WebContents* external_devtools_web_contents_ = nullptr; + std::unique_ptr view_; using ExtensionsAPIs = std::map;