diff options
Diffstat (limited to 'content')
29 files changed, 345 insertions, 565 deletions
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc index 9d4e707..1309eac 100644 --- a/content/browser/devtools/devtools_agent_host_impl.cc +++ b/content/browser/devtools/devtools_agent_host_impl.cc @@ -5,6 +5,7 @@ #include "content/browser/devtools/devtools_agent_host_impl.h" #include <map> +#include <vector> #include "base/basictypes.h" #include "base/guid.h" @@ -12,17 +13,23 @@ #include "content/browser/devtools/devtools_manager_impl.h" #include "content/browser/devtools/forwarding_agent_host.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/devtools_manager_delegate.h" namespace content { namespace { typedef std::map<std::string, DevToolsAgentHostImpl*> Instances; base::LazyInstance<Instances>::Leaky g_instances = LAZY_INSTANCE_INITIALIZER; + +typedef std::vector<const DevToolsAgentHost::AgentStateCallback*> + AgentStateCallbacks; +base::LazyInstance<AgentStateCallbacks>::Leaky g_callbacks = + LAZY_INSTANCE_INITIALIZER; } // namespace DevToolsAgentHostImpl::DevToolsAgentHostImpl() - : close_listener_(NULL), - id_(base::GenerateGUID()) { + : id_(base::GenerateGUID()), + client_(NULL) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); g_instances.Get()[id_] = this; } @@ -49,8 +56,30 @@ scoped_refptr<DevToolsAgentHost> DevToolsAgentHost::Create( return new ForwardingAgentHost(delegate); } +void DevToolsAgentHostImpl::AttachClient(DevToolsAgentHostClient* client) { + scoped_refptr<DevToolsAgentHostImpl> protect(this); + if (client_) { + client_->AgentHostClosed(this, true); + Detach(); + } else { + DevToolsManagerImpl::GetInstance()->OnClientAttached(); + } + client_ = client; + Attach(); +} + +void DevToolsAgentHostImpl::DetachClient() { + if (!client_) + return; + + scoped_refptr<DevToolsAgentHostImpl> protect(this); + client_ = NULL; + Detach(); + DevToolsManagerImpl::GetInstance()->OnClientDetached(); +} + bool DevToolsAgentHostImpl::IsAttached() { - return !!DevToolsManagerImpl::GetInstance()->GetDevToolsClientHostFor(this); + return !!client_; } void DevToolsAgentHostImpl::InspectElement(int x, int y) { @@ -74,12 +103,76 @@ bool DevToolsAgentHostImpl::IsWorker() const { return false; } -void DevToolsAgentHostImpl::NotifyCloseListener() { - if (close_listener_) { - scoped_refptr<DevToolsAgentHostImpl> protect(this); - close_listener_->AgentHostClosing(this); - close_listener_ = NULL; +void DevToolsAgentHostImpl::HostClosed() { + if (!client_) + return; + + scoped_refptr<DevToolsAgentHostImpl> protect(this); + client_->AgentHostClosed(this, false); + client_ = NULL; + DevToolsManagerImpl::GetInstance()->OnClientDetached(); +} + +void DevToolsAgentHostImpl::SendMessageToClient(const std::string& message) { + if (!client_) + return; + client_->DispatchProtocolMessage(this, message); +} + +// static +void DevToolsAgentHost::DetachAllClients() { + if (g_instances == NULL) + return; + + // Make a copy, since detaching may lead to agent destruction, which + // removes it from the instances. + Instances copy = g_instances.Get(); + for (Instances::iterator it(copy.begin()); it != copy.end(); ++it) { + DevToolsAgentHostImpl* agent_host = it->second; + if (agent_host->client_) { + scoped_refptr<DevToolsAgentHostImpl> protect(agent_host); + agent_host->client_->AgentHostClosed(agent_host, true); + agent_host->client_ = NULL; + agent_host->Detach(); + DevToolsManagerImpl::GetInstance()->OnClientDetached(); + } } } +// static +void DevToolsAgentHost::AddAgentStateCallback( + const AgentStateCallback& callback) { + g_callbacks.Get().push_back(&callback); +} + +// static +void DevToolsAgentHost::RemoveAgentStateCallback( + const AgentStateCallback& callback) { + if (g_callbacks == NULL) + return; + + AgentStateCallbacks* callbacks_ = g_callbacks.Pointer(); + AgentStateCallbacks::iterator it = + std::find(callbacks_->begin(), callbacks_->end(), &callback); + DCHECK(it != callbacks_->end()); + callbacks_->erase(it); +} + +// static +void DevToolsAgentHostImpl::NotifyCallbacks( + DevToolsAgentHostImpl* agent_host, bool attached) { + AgentStateCallbacks copy(g_callbacks.Get()); + DevToolsManagerImpl* manager = DevToolsManagerImpl::GetInstance(); + if (manager->delegate()) + manager->delegate()->DevToolsAgentStateChanged(agent_host, attached); + for (AgentStateCallbacks::iterator it = copy.begin(); it != copy.end(); ++it) + (*it)->Run(agent_host, attached); +} + +void DevToolsAgentHostImpl::Inspect(BrowserContext* browser_context) { + DevToolsManagerImpl* manager = DevToolsManagerImpl::GetInstance(); + if (manager->delegate()) + manager->delegate()->Inspect(browser_context, this); +} + } // namespace content diff --git a/content/browser/devtools/devtools_agent_host_impl.h b/content/browser/devtools/devtools_agent_host_impl.h index d20a8b7..5afc0df 100644 --- a/content/browser/devtools/devtools_agent_host_impl.h +++ b/content/browser/devtools/devtools_agent_host_impl.h @@ -17,53 +17,47 @@ class Message; namespace content { +class BrowserContext; + // Describes interface for managing devtools agents from the browser process. class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost { public: - class CONTENT_EXPORT CloseListener { - public: - virtual void AgentHostClosing(DevToolsAgentHostImpl*) = 0; - protected: - virtual ~CloseListener() {} - }; - // Informs the hosted agent that a client host has attached. virtual void Attach() = 0; // Informs the hosted agent that a client host has detached. virtual void Detach() = 0; - // Sends a message to the agent hosted by this object. - virtual void DispatchOnInspectorBackend(const std::string& message) = 0; + // Sends a message to the agent. + virtual void DispatchProtocolMessage(const std::string& message) = 0; - void set_close_listener(CloseListener* listener) { - close_listener_ = listener; - } + // Opens the inspector for this host. + void Inspect(BrowserContext* browser_context); // DevToolsAgentHost implementation. + virtual void AttachClient(DevToolsAgentHostClient* client) OVERRIDE; + virtual void DetachClient() OVERRIDE; virtual bool IsAttached() OVERRIDE; - virtual void InspectElement(int x, int y) OVERRIDE; - virtual std::string GetId() OVERRIDE; - virtual WebContents* GetWebContents() OVERRIDE; - virtual void DisconnectWebContents() OVERRIDE; - - virtual void ConnectWebContents(WebContents* rvh) OVERRIDE; - + virtual void ConnectWebContents(WebContents* wc) OVERRIDE; virtual bool IsWorker() const OVERRIDE; protected: DevToolsAgentHostImpl(); virtual ~DevToolsAgentHostImpl(); - void NotifyCloseListener(); + void HostClosed(); + void SendMessageToClient(const std::string& message); + static void NotifyCallbacks(DevToolsAgentHostImpl* agent_host, bool attached); private: - CloseListener* close_listener_; + friend class DevToolsAgentHost; // for static methods + const std::string id_; + DevToolsAgentHostClient* client_; }; } // namespace content diff --git a/content/browser/devtools/devtools_http_handler_impl.cc b/content/browser/devtools/devtools_http_handler_impl.cc index d1b5b1e..72fe254 100644 --- a/content/browser/devtools/devtools_http_handler_impl.cc +++ b/content/browser/devtools/devtools_http_handler_impl.cc @@ -26,9 +26,7 @@ #include "content/common/devtools_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/devtools_agent_host.h" -#include "content/public/browser/devtools_client_host.h" #include "content/public/browser/devtools_http_handler_delegate.h" -#include "content/public/browser/devtools_manager.h" #include "content/public/browser/devtools_target.h" #include "content/public/common/content_client.h" #include "content/public/common/url_constants.h" @@ -69,30 +67,37 @@ const char kTargetFaviconUrlField[] = "faviconUrl"; const char kTargetWebSocketDebuggerUrlField[] = "webSocketDebuggerUrl"; const char kTargetDevtoolsFrontendUrlField[] = "devtoolsFrontendUrl"; -// An internal implementation of DevToolsClientHost that delegates -// messages sent for DevToolsClient to a DebuggerShell instance. -class DevToolsClientHostImpl : public DevToolsClientHost { +// An internal implementation of DevToolsAgentHostClient that delegates +// messages sent to a DebuggerShell instance. +class DevToolsAgentHostClientImpl : public DevToolsAgentHostClient { public: - DevToolsClientHostImpl(base::MessageLoop* message_loop, - net::HttpServer* server, - int connection_id) + DevToolsAgentHostClientImpl(base::MessageLoop* message_loop, + net::HttpServer* server, + int connection_id, + DevToolsAgentHost* agent_host) : message_loop_(message_loop), server_(server), connection_id_(connection_id), - is_closed_(false), - detach_reason_("target_closed") {} + agent_host_(agent_host) { + agent_host_->AttachClient(this); + } - virtual ~DevToolsClientHostImpl() {} + virtual ~DevToolsAgentHostClientImpl() { + if (agent_host_) + agent_host_->DetachClient(); + } - // DevToolsClientHost interface - virtual void InspectedContentsClosing() OVERRIDE { - if (is_closed_) - return; - is_closed_ = true; + virtual void AgentHostClosed( + DevToolsAgentHost* agent_host, + bool replaced_with_another_client) OVERRIDE { + DCHECK(agent_host == agent_host_.get()); + agent_host_ = NULL; base::DictionaryValue notification; notification.SetString( - devtools::Inspector::detached::kParamReason, detach_reason_); + devtools::Inspector::detached::kParamReason, + replaced_with_another_client ? + "replaced_with_devtools" : "target_closed"); std::string response = DevToolsProtocol::CreateNotification( devtools::Inspector::detached::kName, notification.DeepCopy())->Serialize(); @@ -108,25 +113,27 @@ class DevToolsClientHostImpl : public DevToolsClientHost { base::Bind(&net::HttpServer::Close, server_, connection_id_)); } - virtual void DispatchOnInspectorFrontend(const std::string& data) OVERRIDE { + virtual void DispatchProtocolMessage( + DevToolsAgentHost* agent_host, const std::string& message) OVERRIDE { + DCHECK(agent_host == agent_host_.get()); message_loop_->PostTask( FROM_HERE, base::Bind(&net::HttpServer::SendOverWebSocket, server_, connection_id_, - data)); + message)); } - virtual void ReplacedWithAnotherClient() OVERRIDE { - detach_reason_ = "replaced_with_devtools"; + void OnMessage(const std::string& message) { + if (agent_host_) + agent_host_->DispatchProtocolMessage(message); } private: base::MessageLoop* message_loop_; net::HttpServer* server_; int connection_id_; - bool is_closed_; - std::string detach_reason_; + scoped_refptr<DevToolsAgentHost> agent_host_; }; static bool TimeComparator(const DevToolsTarget* target1, @@ -612,12 +619,9 @@ void DevToolsHttpHandlerImpl::OnWebSocketRequestUI( return; } - DevToolsClientHostImpl* client_host = new DevToolsClientHostImpl( - thread_->message_loop(), server_.get(), connection_id); - connection_to_client_host_ui_[connection_id] = client_host; - - DevToolsManager::GetInstance()-> - RegisterDevToolsClientHostFor(agent, client_host); + DevToolsAgentHostClientImpl * client_host = new DevToolsAgentHostClientImpl( + thread_->message_loop(), server_.get(), connection_id, agent); + connection_to_client_ui_[connection_id] = client_host; AcceptWebSocket(connection_id, request); } @@ -625,24 +629,24 @@ void DevToolsHttpHandlerImpl::OnWebSocketRequestUI( void DevToolsHttpHandlerImpl::OnWebSocketMessageUI( int connection_id, const std::string& data) { - ConnectionToClientHostMap::iterator it = - connection_to_client_host_ui_.find(connection_id); - if (it == connection_to_client_host_ui_.end()) + ConnectionToClientMap::iterator it = + connection_to_client_ui_.find(connection_id); + if (it == connection_to_client_ui_.end()) return; - DevToolsManager* manager = DevToolsManager::GetInstance(); - manager->DispatchOnInspectorBackend(it->second, data); + DevToolsAgentHostClientImpl* client = + static_cast<DevToolsAgentHostClientImpl*>(it->second); + client->OnMessage(data); } void DevToolsHttpHandlerImpl::OnCloseUI(int connection_id) { - ConnectionToClientHostMap::iterator it = - connection_to_client_host_ui_.find(connection_id); - if (it != connection_to_client_host_ui_.end()) { - DevToolsClientHostImpl* client_host = - static_cast<DevToolsClientHostImpl*>(it->second); - DevToolsManager::GetInstance()->ClientHostClosing(client_host); - delete client_host; - connection_to_client_host_ui_.erase(connection_id); + ConnectionToClientMap::iterator it = + connection_to_client_ui_.find(connection_id); + if (it != connection_to_client_ui_.end()) { + DevToolsAgentHostClientImpl* client = + static_cast<DevToolsAgentHostClientImpl*>(it->second); + delete client; + connection_to_client_ui_.erase(connection_id); } } diff --git a/content/browser/devtools/devtools_http_handler_impl.h b/content/browser/devtools/devtools_http_handler_impl.h index 0d08d98..e9cee0b 100644 --- a/content/browser/devtools/devtools_http_handler_impl.h +++ b/content/browser/devtools/devtools_http_handler_impl.h @@ -13,6 +13,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "content/common/content_export.h" +#include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_http_handler.h" #include "content/public/browser/devtools_http_handler_delegate.h" #include "net/http/http_status_code.h" @@ -33,7 +34,6 @@ class URLRequestContextGetter; namespace content { class DevToolsBrowserTarget; -class DevToolsClientHost; class DevToolsHttpHandlerImpl : public DevToolsHttpHandler, @@ -119,8 +119,8 @@ class DevToolsHttpHandlerImpl std::string frontend_url_; scoped_ptr<const net::StreamListenSocketFactory> socket_factory_; scoped_refptr<net::HttpServer> server_; - typedef std::map<int, DevToolsClientHost*> ConnectionToClientHostMap; - ConnectionToClientHostMap connection_to_client_host_ui_; + typedef std::map<int, DevToolsAgentHostClient*> ConnectionToClientMap; + ConnectionToClientMap connection_to_client_ui_; scoped_ptr<DevToolsHttpHandlerDelegate> delegate_; base::FilePath active_port_output_directory_; typedef std::map<std::string, DevToolsTarget*> TargetMap; diff --git a/content/browser/devtools/devtools_manager_impl.cc b/content/browser/devtools/devtools_manager_impl.cc index 3aafd1c..4f40e80ba 100644 --- a/content/browser/devtools/devtools_manager_impl.cc +++ b/content/browser/devtools/devtools_manager_impl.cc @@ -4,199 +4,48 @@ #include "content/browser/devtools/devtools_manager_impl.h" -#include <vector> - #include "base/bind.h" #include "base/message_loop/message_loop.h" #include "content/browser/devtools/devtools_netlog_observer.h" -#include "content/browser/devtools/render_view_devtools_agent_host.h" -#include "content/browser/renderer_host/render_view_host_impl.h" -#include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/content_browser_client.h" -#include "content/public/browser/devtools_client_host.h" +#include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_manager_delegate.h" namespace content { // static -DevToolsManager* DevToolsManager::GetInstance() { - return DevToolsManagerImpl::GetInstance(); -} - -// static DevToolsManagerImpl* DevToolsManagerImpl::GetInstance() { return Singleton<DevToolsManagerImpl>::get(); } DevToolsManagerImpl::DevToolsManagerImpl() - : delegate_(GetContentClient()->browser()->GetDevToolsManagerDelegate()) { + : delegate_(GetContentClient()->browser()->GetDevToolsManagerDelegate()), + client_count_(0) { } DevToolsManagerImpl::~DevToolsManagerImpl() { - DCHECK(agent_to_client_host_.empty()); - DCHECK(client_to_agent_host_.empty()); -} - -void DevToolsManagerImpl::Inspect(BrowserContext* browser_context, - DevToolsAgentHost* agent_host) { - if (delegate_) - delegate_->Inspect(browser_context, agent_host); -} - -DevToolsClientHost* DevToolsManagerImpl::GetDevToolsClientHostFor( - DevToolsAgentHostImpl* agent_host_impl) { - AgentToClientHostMap::iterator it = - agent_to_client_host_.find(agent_host_impl); - if (it != agent_to_client_host_.end()) - return it->second; - return NULL; -} - -DevToolsAgentHost* DevToolsManagerImpl::GetDevToolsAgentHostFor( - DevToolsClientHost* client_host) { - ClientToAgentHostMap::iterator it = client_to_agent_host_.find(client_host); - if (it != client_to_agent_host_.end()) - return it->second.get(); - return NULL; + DCHECK(!client_count_); } -void DevToolsManagerImpl::RegisterDevToolsClientHostFor( - DevToolsAgentHost* agent_host, - DevToolsClientHost* client_host) { - DevToolsAgentHostImpl* agent_host_impl = - static_cast<DevToolsAgentHostImpl*>(agent_host); - DevToolsClientHost* old_client_host = - GetDevToolsClientHostFor(agent_host_impl); - if (old_client_host) { - old_client_host->ReplacedWithAnotherClient(); - UnregisterDevToolsClientHostFor(agent_host_impl); - } - BindClientHost(agent_host_impl, client_host); - agent_host_impl->Attach(); -} - -bool DevToolsManagerImpl::DispatchOnInspectorBackend( - DevToolsClientHost* from, - const std::string& message) { - DevToolsAgentHost* agent_host = GetDevToolsAgentHostFor(from); - if (!agent_host) - return false; - DevToolsAgentHostImpl* agent_host_impl = - static_cast<DevToolsAgentHostImpl*>(agent_host); - agent_host_impl->DispatchOnInspectorBackend(message); - return true; -} - -void DevToolsManagerImpl::DispatchOnInspectorFrontend( - DevToolsAgentHost* agent_host, - const std::string& message) { - DevToolsAgentHostImpl* agent_host_impl = - static_cast<DevToolsAgentHostImpl*>(agent_host); - DevToolsClientHost* client_host = GetDevToolsClientHostFor(agent_host_impl); - if (!client_host) { - // Client window was closed while there were messages - // being sent to it. - return; - } - client_host->DispatchOnInspectorFrontend(message); -} - -void DevToolsManagerImpl::ClientHostClosing(DevToolsClientHost* client_host) { - DevToolsAgentHost* agent_host = GetDevToolsAgentHostFor(client_host); - if (!agent_host) - return; - DevToolsAgentHostImpl* agent_host_impl = - static_cast<DevToolsAgentHostImpl*>(agent_host); - UnbindClientHost(agent_host_impl, client_host); -} - -void DevToolsManagerImpl::AgentHostClosing(DevToolsAgentHostImpl* agent_host) { - UnregisterDevToolsClientHostFor(agent_host); -} - -void DevToolsManagerImpl::UnregisterDevToolsClientHostFor( - DevToolsAgentHostImpl* agent_host_impl) { - DevToolsClientHost* client_host = GetDevToolsClientHostFor(agent_host_impl); - if (!client_host) - return; - UnbindClientHost(agent_host_impl, client_host); - client_host->InspectedContentsClosing(); -} - -void DevToolsManagerImpl::BindClientHost( - DevToolsAgentHostImpl* agent_host, - DevToolsClientHost* client_host) { - DCHECK(agent_to_client_host_.find(agent_host) == - agent_to_client_host_.end()); - DCHECK(client_to_agent_host_.find(client_host) == - client_to_agent_host_.end()); - - if (client_to_agent_host_.empty()) { +void DevToolsManagerImpl::OnClientAttached() { + if (!client_count_) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&DevToolsNetLogObserver::Attach)); } - agent_to_client_host_[agent_host] = client_host; - client_to_agent_host_[client_host] = agent_host; - agent_host->set_close_listener(this); + client_count_++; } -void DevToolsManagerImpl::UnbindClientHost(DevToolsAgentHostImpl* agent_host, - DevToolsClientHost* client_host) { - DCHECK(agent_host); - scoped_refptr<DevToolsAgentHostImpl> protect(agent_host); - DCHECK(agent_to_client_host_.find(agent_host)->second == - client_host); - DCHECK(client_to_agent_host_.find(client_host)->second.get() == agent_host); - agent_host->set_close_listener(NULL); - - agent_to_client_host_.erase(agent_host); - client_to_agent_host_.erase(client_host); - - if (client_to_agent_host_.empty()) { +void DevToolsManagerImpl::OnClientDetached() { + client_count_--; + if (!client_count_) { BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&DevToolsNetLogObserver::Detach)); } - // Lazy agent hosts can be deleted from within detach. - // Do not access agent_host below this line. - agent_host->Detach(); -} - -void DevToolsManagerImpl::CloseAllClientHosts() { - std::vector<DevToolsAgentHostImpl*> agents; - for (AgentToClientHostMap::iterator it = - agent_to_client_host_.begin(); - it != agent_to_client_host_.end(); ++it) { - agents.push_back(it->first); - } - for (std::vector<DevToolsAgentHostImpl*>::iterator it = agents.begin(); - it != agents.end(); ++it) { - UnregisterDevToolsClientHostFor(*it); - } -} - -void DevToolsManagerImpl::AddAgentStateCallback(const Callback& callback) { - callbacks_.push_back(&callback); -} - -void DevToolsManagerImpl::RemoveAgentStateCallback(const Callback& callback) { - CallbackContainer::iterator it = - std::find(callbacks_.begin(), callbacks_.end(), &callback); - DCHECK(it != callbacks_.end()); - callbacks_.erase(it); -} - -void DevToolsManagerImpl::NotifyObservers(DevToolsAgentHost* agent_host, - bool attached) { - CallbackContainer copy(callbacks_); - if (delegate_) - delegate_->DevToolsAgentStateChanged(agent_host, attached); - for (CallbackContainer::iterator it = copy.begin(); it != copy.end(); ++it) - (*it)->Run(agent_host, attached); } } // namespace content diff --git a/content/browser/devtools/devtools_manager_impl.h b/content/browser/devtools/devtools_manager_impl.h index 19b6918..c5ceb2a 100644 --- a/content/browser/devtools/devtools_manager_impl.h +++ b/content/browser/devtools/devtools_manager_impl.h @@ -11,32 +11,14 @@ #include "base/compiler_specific.h" #include "base/memory/singleton.h" -#include "content/browser/devtools/devtools_agent_host_impl.h" -#include "content/common/content_export.h" -#include "content/public/browser/devtools_client_host.h" -#include "content/public/browser/devtools_manager.h" - -class GURL; - -namespace IPC { -class Message; -} namespace content { -class BrowserContext; class DevToolsManagerDelegate; -class RenderViewHost; -// This class is a singleton that manages DevToolsClientHost instances and -// routes messages between developer tools clients and agents. -// -// Methods below that accept inspected RenderViewHost as a parameter are -// just convenience methods that call corresponding methods accepting -// DevToolAgentHost. -class CONTENT_EXPORT DevToolsManagerImpl - : public DevToolsAgentHostImpl::CloseListener, - public DevToolsManager { +// This class is a singleton that manage global DevTools state for the whole +// browser. +class DevToolsManagerImpl { public: // Returns single instance of this class. The instance is destroyed on the // browser main loop exit so this method MUST NOT be called after that point. @@ -45,65 +27,15 @@ class CONTENT_EXPORT DevToolsManagerImpl DevToolsManagerImpl(); virtual ~DevToolsManagerImpl(); - // Opens the inspector for |agent_host|. - void Inspect(BrowserContext* browser_context, DevToolsAgentHost* agent_host); - - void DispatchOnInspectorFrontend(DevToolsAgentHost* agent_host, - const std::string& message); - DevToolsManagerDelegate* delegate() const { return delegate_.get(); } - - // DevToolsManager implementation - virtual bool DispatchOnInspectorBackend(DevToolsClientHost* from, - const std::string& message) OVERRIDE; - virtual void CloseAllClientHosts() OVERRIDE; - virtual DevToolsAgentHost* GetDevToolsAgentHostFor( - DevToolsClientHost* client_host) OVERRIDE; - virtual void RegisterDevToolsClientHostFor( - DevToolsAgentHost* agent_host, - DevToolsClientHost* client_host) OVERRIDE; - virtual void ClientHostClosing(DevToolsClientHost* host) OVERRIDE; - virtual void AddAgentStateCallback(const Callback& callback) OVERRIDE; - virtual void RemoveAgentStateCallback(const Callback& callback) OVERRIDE; + void OnClientAttached(); + void OnClientDetached(); private: - friend class DevToolsAgentHostImpl; - friend class RenderViewDevToolsAgentHost; friend struct DefaultSingletonTraits<DevToolsManagerImpl>; - // DevToolsAgentHost::CloseListener implementation. - virtual void AgentHostClosing(DevToolsAgentHostImpl* host) OVERRIDE; - - void BindClientHost(DevToolsAgentHostImpl* agent_host, - DevToolsClientHost* client_host); - void UnbindClientHost(DevToolsAgentHostImpl* agent_host, - DevToolsClientHost* client_host); - - DevToolsClientHost* GetDevToolsClientHostFor( - DevToolsAgentHostImpl* agent_host); - - void UnregisterDevToolsClientHostFor(DevToolsAgentHostImpl* agent_host); - - void NotifyObservers(DevToolsAgentHost* agent_host, bool attached); - - // These two maps are for tracking dependencies between inspected contents and - // their DevToolsClientHosts. They are useful for routing devtools messages - // and allow us to have at most one devtools client host per contents. - // - // DevToolsManagerImpl starts listening to DevToolsClientHosts when they are - // put into these maps and removes them when they are closing. - typedef std::map<DevToolsAgentHostImpl*, DevToolsClientHost*> - AgentToClientHostMap; - AgentToClientHostMap agent_to_client_host_; - - typedef std::map<DevToolsClientHost*, scoped_refptr<DevToolsAgentHostImpl> > - ClientToAgentHostMap; - ClientToAgentHostMap client_to_agent_host_; - - typedef std::vector<const Callback*> CallbackContainer; - CallbackContainer callbacks_; - scoped_ptr<DevToolsManagerDelegate> delegate_; + int client_count_; DISALLOW_COPY_AND_ASSIGN(DevToolsManagerImpl); }; diff --git a/content/browser/devtools/devtools_manager_unittest.cc b/content/browser/devtools/devtools_manager_unittest.cc index 79b7654..588e530 100644 --- a/content/browser/devtools/devtools_manager_unittest.cc +++ b/content/browser/devtools/devtools_manager_unittest.cc @@ -10,7 +10,6 @@ #include "content/common/view_messages.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/devtools_agent_host.h" -#include "content/public/browser/devtools_client_host.h" #include "content/public/browser/devtools_external_agent_proxy.h" #include "content/public/browser/devtools_external_agent_proxy_delegate.h" #include "content/public/browser/web_contents_delegate.h" @@ -24,7 +23,7 @@ using base::TimeDelta; namespace content { namespace { -class TestDevToolsClientHost : public DevToolsClientHost { +class TestDevToolsClientHost : public DevToolsAgentHostClient { public: TestDevToolsClientHost() : last_sent_message(NULL), @@ -35,24 +34,30 @@ class TestDevToolsClientHost : public DevToolsClientHost { EXPECT_TRUE(closed_); } - virtual void Close(DevToolsManager* manager) { + void Close() { EXPECT_FALSE(closed_); close_counter++; - manager->ClientHostClosing(this); + agent_host_->DetachClient(); closed_ = true; } - virtual void InspectedContentsClosing() OVERRIDE { + + virtual void AgentHostClosed( + DevToolsAgentHost* agent_host, bool replaced) OVERRIDE { FAIL(); } - virtual void DispatchOnInspectorFrontend( - const std::string& message) OVERRIDE { + virtual void DispatchProtocolMessage( + DevToolsAgentHost* agent_host, const std::string& message) OVERRIDE { last_sent_message = &message; } - virtual void ReplacedWithAnotherClient() OVERRIDE { + void InspectAgentHost(DevToolsAgentHost* agent_host) { + agent_host_ = agent_host; + agent_host_->AttachClient(this); } + DevToolsAgentHost* agent_host() { return agent_host_.get(); } + static void ResetCounters() { close_counter = 0; } @@ -63,6 +68,7 @@ class TestDevToolsClientHost : public DevToolsClientHost { private: bool closed_; + scoped_refptr<DevToolsAgentHost> agent_host_; DISALLOW_COPY_AND_ASSIGN(TestDevToolsClientHost); }; @@ -98,42 +104,21 @@ class DevToolsManagerTest : public RenderViewHostImplTestHarness { }; TEST_F(DevToolsManagerTest, OpenAndManuallyCloseDevToolsClientHost) { - DevToolsManager* manager = DevToolsManager::GetInstance(); - scoped_refptr<DevToolsAgentHost> agent( DevToolsAgentHost::GetOrCreateFor(web_contents())); EXPECT_FALSE(agent->IsAttached()); TestDevToolsClientHost client_host; - manager->RegisterDevToolsClientHostFor(agent.get(), &client_host); + client_host.InspectAgentHost(agent.get()); // Test that the connection is established. EXPECT_TRUE(agent->IsAttached()); - EXPECT_EQ(agent, manager->GetDevToolsAgentHostFor(&client_host)); EXPECT_EQ(0, TestDevToolsClientHost::close_counter); - client_host.Close(manager); + client_host.Close(); EXPECT_EQ(1, TestDevToolsClientHost::close_counter); EXPECT_FALSE(agent->IsAttached()); } -TEST_F(DevToolsManagerTest, ForwardMessageToClient) { - DevToolsManagerImpl* manager = DevToolsManagerImpl::GetInstance(); - - TestDevToolsClientHost client_host; - scoped_refptr<DevToolsAgentHost> agent_host( - DevToolsAgentHost::GetOrCreateFor(web_contents())); - manager->RegisterDevToolsClientHostFor(agent_host.get(), &client_host); - EXPECT_EQ(0, TestDevToolsClientHost::close_counter); - - std::string m = "test message"; - agent_host = DevToolsAgentHost::GetOrCreateFor(web_contents()); - manager->DispatchOnInspectorFrontend(agent_host.get(), m); - EXPECT_TRUE(&m == client_host.last_sent_message); - - client_host.Close(manager); - EXPECT_EQ(1, TestDevToolsClientHost::close_counter); -} - TEST_F(DevToolsManagerTest, NoUnresponsiveDialogInInspectedContents) { TestRenderViewHost* inspected_rvh = test_rvh(); inspected_rvh->set_render_view_created(true); @@ -144,8 +129,7 @@ TEST_F(DevToolsManagerTest, NoUnresponsiveDialogInInspectedContents) { TestDevToolsClientHost client_host; scoped_refptr<DevToolsAgentHost> agent_host(DevToolsAgentHost::GetOrCreateFor( WebContents::FromRenderViewHost(inspected_rvh))); - DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor( - agent_host.get(), &client_host); + client_host.InspectAgentHost(agent_host.get()); // Start with a short timeout. inspected_rvh->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10)); @@ -158,7 +142,7 @@ TEST_F(DevToolsManagerTest, NoUnresponsiveDialogInInspectedContents) { EXPECT_FALSE(delegate.renderer_unresponsive_received()); // Now close devtools and check that the notification is delivered. - client_host.Close(DevToolsManager::GetInstance()); + client_host.Close(); // Start with a short timeout. inspected_rvh->StartHangMonitorTimeout(TimeDelta::FromMilliseconds(10)); // Wait long enough for first timeout and see if it fired. @@ -181,26 +165,25 @@ TEST_F(DevToolsManagerTest, ReattachOnCancelPendingNavigation) { EXPECT_FALSE(contents()->cross_navigation_pending()); TestDevToolsClientHost client_host; - DevToolsManager* devtools_manager = DevToolsManager::GetInstance(); - devtools_manager->RegisterDevToolsClientHostFor( - DevToolsAgentHost::GetOrCreateFor(web_contents()).get(), &client_host); + client_host.InspectAgentHost( + DevToolsAgentHost::GetOrCreateFor(web_contents()).get()); // Navigate to new site which should get a new RenderViewHost. const GURL url2("http://www.yahoo.com"); controller().LoadURL( url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); EXPECT_TRUE(contents()->cross_navigation_pending()); - EXPECT_EQ(devtools_manager->GetDevToolsAgentHostFor(&client_host), - DevToolsAgentHost::GetOrCreateFor(web_contents())); + EXPECT_EQ(client_host.agent_host(), + DevToolsAgentHost::GetOrCreateFor(web_contents())); // Interrupt pending navigation and navigate back to the original site. controller().LoadURL( url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); contents()->TestDidNavigate(rvh(), 1, url, PAGE_TRANSITION_TYPED); EXPECT_FALSE(contents()->cross_navigation_pending()); - EXPECT_EQ(devtools_manager->GetDevToolsAgentHostFor(&client_host), + EXPECT_EQ(client_host.agent_host(), DevToolsAgentHost::GetOrCreateFor(web_contents())); - client_host.Close(DevToolsManager::GetInstance()); + client_host.Close(); } class TestExternalAgentDelegate: public DevToolsExternalAgentProxyDelegate { @@ -245,16 +228,13 @@ TEST_F(DevToolsManagerTest, TestExternalProxy) { DevToolsAgentHost::Create(delegate); EXPECT_EQ(agent_host, DevToolsAgentHost::GetForId(agent_host->GetId())); - DevToolsManager* manager = DevToolsManager::GetInstance(); - TestDevToolsClientHost client_host; - manager->RegisterDevToolsClientHostFor(agent_host.get(), &client_host); - - manager->DispatchOnInspectorBackend(&client_host, "message1"); - manager->DispatchOnInspectorBackend(&client_host, "message2"); - manager->DispatchOnInspectorBackend(&client_host, "message2"); + client_host.InspectAgentHost(agent_host.get()); + agent_host->DispatchProtocolMessage("message1"); + agent_host->DispatchProtocolMessage("message2"); + agent_host->DispatchProtocolMessage("message2"); - client_host.Close(manager); + client_host.Close(); } } // namespace content diff --git a/content/browser/devtools/embedded_worker_devtools_agent_host.cc b/content/browser/devtools/embedded_worker_devtools_agent_host.cc index 9f60400..8a7a948 100644 --- a/content/browser/devtools/embedded_worker_devtools_agent_host.cc +++ b/content/browser/devtools/embedded_worker_devtools_agent_host.cc @@ -83,7 +83,7 @@ bool EmbeddedWorkerDevToolsAgentHost::OnMessageReceived( void EmbeddedWorkerDevToolsAgentHost::WorkerContextStarted() { if (state_ == WORKER_PAUSED_FOR_DEBUG_ON_START) { RenderProcessHost* rph = RenderProcessHost::FromID(worker_id_.first); - DevToolsManagerImpl::GetInstance()->Inspect(rph->GetBrowserContext(), this); + Inspect(rph->GetBrowserContext()); } else if (state_ == WORKER_PAUSED_FOR_REATTACH) { DCHECK(IsAttached()); state_ = WORKER_INSPECTED; @@ -107,8 +107,7 @@ void EmbeddedWorkerDevToolsAgentHost::WorkerDestroyed() { std::string notification = DevToolsProtocol::CreateNotification( devtools::Worker::disconnectedFromWorker::kName, NULL)->Serialize(); - DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend( - this, notification); + SendMessageToClient(notification); DetachFromWorker(); } state_ = WORKER_TERMINATED; @@ -147,8 +146,7 @@ void EmbeddedWorkerDevToolsAgentHost::WorkerCreated() { void EmbeddedWorkerDevToolsAgentHost::OnDispatchOnInspectorFrontend( const std::string& message) { - DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend( - this, message); + SendMessageToClient(message); } void EmbeddedWorkerDevToolsAgentHost::OnSaveAgentRuntimeState( diff --git a/content/browser/devtools/embedded_worker_devtools_manager.cc b/content/browser/devtools/embedded_worker_devtools_manager.cc index cf4c831..2ba644f 100644 --- a/content/browser/devtools/embedded_worker_devtools_manager.cc +++ b/content/browser/devtools/embedded_worker_devtools_manager.cc @@ -52,7 +52,8 @@ EmbeddedWorkerDevToolsManager* EmbeddedWorkerDevToolsManager::GetInstance() { return Singleton<EmbeddedWorkerDevToolsManager>::get(); } -DevToolsAgentHost* EmbeddedWorkerDevToolsManager::GetDevToolsAgentHostForWorker( +DevToolsAgentHostImpl* +EmbeddedWorkerDevToolsManager::GetDevToolsAgentHostForWorker( int worker_process_id, int worker_route_id) { AgentHostMap::iterator it = workers_.find( @@ -60,7 +61,7 @@ DevToolsAgentHost* EmbeddedWorkerDevToolsManager::GetDevToolsAgentHostForWorker( return it == workers_.end() ? NULL : it->second; } -DevToolsAgentHost* +DevToolsAgentHostImpl* EmbeddedWorkerDevToolsManager::GetDevToolsAgentHostForServiceWorker( const ServiceWorkerIdentifier& service_worker_id) { AgentHostMap::iterator it = diff --git a/content/browser/devtools/embedded_worker_devtools_manager.h b/content/browser/devtools/embedded_worker_devtools_manager.h index 4fcfb9b..0e00499 100644 --- a/content/browser/devtools/embedded_worker_devtools_manager.h +++ b/content/browser/devtools/embedded_worker_devtools_manager.h @@ -17,7 +17,7 @@ namespace content { -class DevToolsAgentHost; +class DevToolsAgentHostImpl; class EmbeddedWorkerDevToolsAgentHost; class ServiceWorkerContextCore; @@ -46,9 +46,9 @@ class CONTENT_EXPORT EmbeddedWorkerDevToolsManager { // Returns the EmbeddedWorkerDevToolsManager singleton. static EmbeddedWorkerDevToolsManager* GetInstance(); - DevToolsAgentHost* GetDevToolsAgentHostForWorker(int worker_process_id, + DevToolsAgentHostImpl* GetDevToolsAgentHostForWorker(int worker_process_id, int worker_route_id); - DevToolsAgentHost* GetDevToolsAgentHostForServiceWorker( + DevToolsAgentHostImpl* GetDevToolsAgentHostForServiceWorker( const ServiceWorkerIdentifier& service_worker_id); // Returns true when the worker must be paused on start because a DevTool diff --git a/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc b/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc index 347b6f3..5910b05 100644 --- a/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc +++ b/content/browser/devtools/embedded_worker_devtools_manager_unittest.cc @@ -8,28 +8,34 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "content/browser/browser_thread_impl.h" -#include "content/browser/devtools/devtools_manager_impl.h" +#include "content/browser/devtools/devtools_agent_host_impl.h" #include "content/browser/devtools/embedded_worker_devtools_agent_host.h" #include "content/browser/shared_worker/shared_worker_instance.h" #include "content/browser/shared_worker/worker_storage_partition.h" -#include "content/public/browser/devtools_agent_host.h" -#include "content/public/browser/devtools_client_host.h" #include "content/public/test/test_browser_context.h" #include "testing/gtest/include/gtest/gtest.h" namespace content { namespace { -class TestDevToolsClientHost : public DevToolsClientHost { +class TestDevToolsClientHost : public DevToolsAgentHostClient { public: TestDevToolsClientHost() {} virtual ~TestDevToolsClientHost() {} - virtual void DispatchOnInspectorFrontend( - const std::string& message) OVERRIDE {} - virtual void InspectedContentsClosing() OVERRIDE {} - virtual void ReplacedWithAnotherClient() OVERRIDE {} - + virtual void DispatchProtocolMessage( + DevToolsAgentHost* agent_host, const std::string& message) OVERRIDE {} + virtual void AgentHostClosed( + DevToolsAgentHost* agent_host, bool replaced) OVERRIDE {} + + void InspectAgentHost(DevToolsAgentHost* agent_host) { + if (agent_host_) + agent_host_->DetachClient(); + agent_host_ = agent_host; + if (agent_host_) + agent_host_->AttachClient(this); + } private: + scoped_refptr<DevToolsAgentHost> agent_host_; DISALLOW_COPY_AND_ASSIGN(TestDevToolsClientHost); }; } @@ -81,16 +87,6 @@ class EmbeddedWorkerDevToolsManagerTest : public testing::Test { EXPECT_EQ(size, manager_->workers_.size()); } - void RegisterDevToolsClientHostFor(DevToolsAgentHost* agent_host, - DevToolsClientHost* client_host) { - DevToolsManagerImpl::GetInstance()->RegisterDevToolsClientHostFor( - agent_host, client_host); - } - - void ClientHostClosing(DevToolsClientHost* client_host) { - DevToolsManagerImpl::GetInstance()->ClientHostClosing(client_host); - } - base::MessageLoopForIO message_loop_; BrowserThreadImpl ui_thread_; scoped_ptr<TestBrowserContext> browser_context_; @@ -100,7 +96,7 @@ class EmbeddedWorkerDevToolsManagerTest : public testing::Test { }; TEST_F(EmbeddedWorkerDevToolsManagerTest, BasicTest) { - scoped_refptr<DevToolsAgentHost> agent_host; + scoped_refptr<DevToolsAgentHostImpl> agent_host; SharedWorkerInstance instance1(GURL("http://example.com/w.js"), base::string16(), @@ -182,8 +178,8 @@ TEST_F(EmbeddedWorkerDevToolsManagerTest, BasicTest) { } TEST_F(EmbeddedWorkerDevToolsManagerTest, AttachTest) { - scoped_refptr<DevToolsAgentHost> agent_host1; - scoped_refptr<DevToolsAgentHost> agent_host2; + scoped_refptr<DevToolsAgentHostImpl> agent_host1; + scoped_refptr<DevToolsAgentHostImpl> agent_host2; SharedWorkerInstance instance1(GURL("http://example.com/w1.js"), base::string16(), @@ -207,7 +203,7 @@ TEST_F(EmbeddedWorkerDevToolsManagerTest, AttachTest) { EXPECT_TRUE(agent_host1.get()); CheckWorkerState(2, 1, WorkerState::WORKER_UNINSPECTED); EXPECT_EQ(agent_host1.get(), manager_->GetDevToolsAgentHostForWorker(2, 1)); - RegisterDevToolsClientHostFor(agent_host1.get(), client_host1.get()); + client_host1->InspectAgentHost(agent_host1.get()); CheckWorkerState(2, 1, WorkerState::WORKER_INSPECTED); manager_->WorkerContextStarted(2, 1); CheckWorkerState(2, 1, WorkerState::WORKER_INSPECTED); @@ -226,7 +222,7 @@ TEST_F(EmbeddedWorkerDevToolsManagerTest, AttachTest) { EXPECT_NE(agent_host1.get(), agent_host2.get()); EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 2)); CheckWorkerState(2, 2, WorkerState::WORKER_UNINSPECTED); - RegisterDevToolsClientHostFor(agent_host2.get(), client_host2.get()); + client_host2->InspectAgentHost(agent_host2); CheckWorkerState(2, 2, WorkerState::WORKER_INSPECTED); manager_->WorkerDestroyed(2, 2); CheckWorkerState(2, 2, WorkerState::WORKER_TERMINATED); @@ -240,7 +236,7 @@ TEST_F(EmbeddedWorkerDevToolsManagerTest, AttachTest) { EXPECT_EQ(agent_host1.get(), manager_->GetDevToolsAgentHostForWorker(2, 3)); manager_->WorkerContextStarted(2, 3); CheckWorkerState(2, 3, WorkerState::WORKER_INSPECTED); - ClientHostClosing(client_host1.get()); + client_host1->InspectAgentHost(NULL); manager_->WorkerDestroyed(2, 3); CheckWorkerState(2, 3, WorkerState::WORKER_TERMINATED); agent_host1 = NULL; @@ -261,7 +257,7 @@ TEST_F(EmbeddedWorkerDevToolsManagerTest, AttachTest) { CheckWorkerNotExist(2, 2); CheckWorkerState(2, 5, WorkerState::WORKER_PAUSED_FOR_REATTACH); EXPECT_EQ(agent_host2.get(), manager_->GetDevToolsAgentHostForWorker(2, 5)); - ClientHostClosing(client_host2.get()); + client_host2->InspectAgentHost(NULL); CheckWorkerCount(1); agent_host2 = NULL; CheckWorkerCount(1); @@ -284,12 +280,12 @@ TEST_F(EmbeddedWorkerDevToolsManagerTest, ReattachTest) { manager_->GetDevToolsAgentHostForWorker(3, 1)); EXPECT_TRUE(agent_host.get()); CheckWorkerState(3, 1, WorkerState::WORKER_UNINSPECTED); - RegisterDevToolsClientHostFor(agent_host.get(), client_host.get()); + client_host->InspectAgentHost(agent_host.get()); CheckWorkerState(3, 1, WorkerState::WORKER_INSPECTED); manager_->WorkerDestroyed(3, 1); CheckWorkerState(3, 1, WorkerState::WORKER_TERMINATED); // ClientHostClosing -> Re-created -> release agent_host -> Destroyed - ClientHostClosing(client_host.get()); + client_host->InspectAgentHost(NULL); CheckWorkerState(3, 1, WorkerState::WORKER_TERMINATED); manager_->SharedWorkerCreated(3, 2, instance); CheckWorkerState(3, 2, WorkerState::WORKER_UNINSPECTED); diff --git a/content/browser/devtools/forwarding_agent_host.cc b/content/browser/devtools/forwarding_agent_host.cc index f1524e1..5267ae1 100644 --- a/content/browser/devtools/forwarding_agent_host.cc +++ b/content/browser/devtools/forwarding_agent_host.cc @@ -17,12 +17,11 @@ ForwardingAgentHost::~ForwardingAgentHost() { } void ForwardingAgentHost::DispatchOnClientHost(const std::string& message) { - DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend( - this, message); + SendMessageToClient(message); } void ForwardingAgentHost::ConnectionClosed() { - NotifyCloseListener(); + HostClosed(); } void ForwardingAgentHost::Attach() { @@ -33,7 +32,7 @@ void ForwardingAgentHost::Detach() { delegate_->Detach(); } -void ForwardingAgentHost::DispatchOnInspectorBackend( +void ForwardingAgentHost::DispatchProtocolMessage( const std::string& message) { delegate_->SendMessageToBackend(message); } diff --git a/content/browser/devtools/forwarding_agent_host.h b/content/browser/devtools/forwarding_agent_host.h index 81e4aed..93dabb4 100644 --- a/content/browser/devtools/forwarding_agent_host.h +++ b/content/browser/devtools/forwarding_agent_host.h @@ -29,7 +29,7 @@ class ForwardingAgentHost // DevToolsAgentHostImpl implementation. virtual void Attach() OVERRIDE; virtual void Detach() OVERRIDE; - virtual void DispatchOnInspectorBackend(const std::string& message) OVERRIDE; + virtual void DispatchProtocolMessage(const std::string& message) OVERRIDE; scoped_ptr<DevToolsExternalAgentProxyDelegate> delegate_; }; diff --git a/content/browser/devtools/ipc_devtools_agent_host.cc b/content/browser/devtools/ipc_devtools_agent_host.cc index 294a679..18c362e 100644 --- a/content/browser/devtools/ipc_devtools_agent_host.cc +++ b/content/browser/devtools/ipc_devtools_agent_host.cc @@ -18,7 +18,7 @@ void IPCDevToolsAgentHost::Detach() { OnClientDetached(); } -void IPCDevToolsAgentHost::DispatchOnInspectorBackend( +void IPCDevToolsAgentHost::DispatchProtocolMessage( const std::string& message) { SendMessageToAgent(new DevToolsAgentMsg_DispatchOnInspectorBackend( MSG_ROUTING_NONE, message)); diff --git a/content/browser/devtools/ipc_devtools_agent_host.h b/content/browser/devtools/ipc_devtools_agent_host.h index 98c2794..496c2d9 100644 --- a/content/browser/devtools/ipc_devtools_agent_host.h +++ b/content/browser/devtools/ipc_devtools_agent_host.h @@ -18,7 +18,7 @@ class CONTENT_EXPORT IPCDevToolsAgentHost : public DevToolsAgentHostImpl { // DevToolsAgentHostImpl implementation. virtual void Attach() OVERRIDE; virtual void Detach() OVERRIDE; - virtual void DispatchOnInspectorBackend(const std::string& message) OVERRIDE; + virtual void DispatchProtocolMessage(const std::string& message) OVERRIDE; virtual void InspectElement(int x, int y) OVERRIDE; protected: diff --git a/content/browser/devtools/render_view_devtools_agent_host.cc b/content/browser/devtools/render_view_devtools_agent_host.cc index f0c9c8f..b16c2dc 100644 --- a/content/browser/devtools/render_view_devtools_agent_host.cc +++ b/content/browser/devtools/render_view_devtools_agent_host.cc @@ -127,7 +127,7 @@ WebContents* RenderViewDevToolsAgentHost::GetWebContents() { return web_contents(); } -void RenderViewDevToolsAgentHost::DispatchOnInspectorBackend( +void RenderViewDevToolsAgentHost::DispatchProtocolMessage( const std::string& message) { std::string error_message; @@ -161,7 +161,7 @@ void RenderViewDevToolsAgentHost::DispatchOnInspectorBackend( } } - IPCDevToolsAgentHost::DispatchOnInspectorBackend(message); + IPCDevToolsAgentHost::DispatchProtocolMessage(message); } void RenderViewDevToolsAgentHost::SendMessageToAgent(IPC::Message* msg) { @@ -180,7 +180,7 @@ void RenderViewDevToolsAgentHost::OnClientAttached() { // TODO(kaznacheev): Move this call back to DevToolsManagerImpl when // extensions::ProcessManager no longer relies on this notification. if (!reattaching_) - DevToolsManagerImpl::GetInstance()->NotifyObservers(this, true); + DevToolsAgentHostImpl::NotifyCallbacks(this, true); } void RenderViewDevToolsAgentHost::InnerOnClientAttached() { @@ -212,7 +212,7 @@ void RenderViewDevToolsAgentHost::OnClientDetached() { // TODO(kaznacheev): Move this call back to DevToolsManagerImpl when // extensions::ProcessManager no longer relies on this notification. if (!reattaching_) - DevToolsManagerImpl::GetInstance()->NotifyObservers(this, false); + DevToolsAgentHostImpl::NotifyCallbacks(this, false); } void RenderViewDevToolsAgentHost::ClientDetachedFromRenderer() { @@ -286,7 +286,7 @@ void RenderViewDevToolsAgentHost::RenderViewDeleted(RenderViewHost* rvh) { DCHECK(render_view_host_); scoped_refptr<RenderViewDevToolsAgentHost> protect(this); - NotifyCloseListener(); + HostClosed(); ClearRenderViewHost(); Release(); } @@ -385,8 +385,7 @@ void RenderViewDevToolsAgentHost::RenderViewCrashed() { scoped_refptr<DevToolsProtocol::Notification> notification = DevToolsProtocol::CreateNotification( devtools::Inspector::targetCrashed::kName, NULL); - DevToolsManagerImpl::GetInstance()-> - DispatchOnInspectorFrontend(this, notification->Serialize()); + SendMessageToClient(notification->Serialize()); } bool RenderViewDevToolsAgentHost::DispatchIPCMessage( @@ -447,8 +446,7 @@ void RenderViewDevToolsAgentHost::OnDispatchOnInspectorFrontend( if (notification) { tracing_handler_->HandleNotification(notification); } - DevToolsManagerImpl::GetInstance()->DispatchOnInspectorFrontend( - this, message); + SendMessageToClient(message); } } // namespace content diff --git a/content/browser/devtools/render_view_devtools_agent_host.h b/content/browser/devtools/render_view_devtools_agent_host.h index b1f3e07..7de31fd 100644 --- a/content/browser/devtools/render_view_devtools_agent_host.h +++ b/content/browser/devtools/render_view_devtools_agent_host.h @@ -54,7 +54,7 @@ class CONTENT_EXPORT RenderViewDevToolsAgentHost virtual ~RenderViewDevToolsAgentHost(); // IPCDevToolsAgentHost overrides. - virtual void DispatchOnInspectorBackend(const std::string& message) OVERRIDE; + virtual void DispatchProtocolMessage(const std::string& message) OVERRIDE; virtual void SendMessageToAgent(IPC::Message* msg) OVERRIDE; virtual void OnClientAttached() OVERRIDE; virtual void OnClientDetached() OVERRIDE; diff --git a/content/browser/devtools/renderer_overrides_handler_browsertest.cc b/content/browser/devtools/renderer_overrides_handler_browsertest.cc index a6cd973..48ae7c6 100644 --- a/content/browser/devtools/renderer_overrides_handler_browsertest.cc +++ b/content/browser/devtools/renderer_overrides_handler_browsertest.cc @@ -7,8 +7,6 @@ #include "base/json/json_reader.h" #include "content/browser/devtools/devtools_protocol.h" #include "content/public/browser/devtools_agent_host.h" -#include "content/public/browser/devtools_client_host.h" -#include "content/public/browser/devtools_manager.h" #include "content/public/browser/web_contents.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" @@ -20,12 +18,12 @@ namespace content { class RendererOverridesHandlerTest : public ContentBrowserTest, - public DevToolsClientHost { + public DevToolsAgentHostClient { protected: void SendCommand(const std::string& method, base::DictionaryValue* params) { - EXPECT_TRUE(DevToolsManager::GetInstance()->DispatchOnInspectorBackend(this, - DevToolsProtocol::CreateCommand(1, method, params)->Serialize())); + agent_host_->DispatchProtocolMessage( + DevToolsProtocol::CreateCommand(1, method, params)->Serialize()); base::MessageLoop::current()->Run(); } @@ -55,19 +53,21 @@ class RendererOverridesHandlerTest : public ContentBrowserTest, } scoped_ptr<base::DictionaryValue> result_; + scoped_refptr<DevToolsAgentHost> agent_host_; private: virtual void SetUpOnMainThread() OVERRIDE { - DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor( - DevToolsAgentHost::GetOrCreateFor(shell()->web_contents()).get(), this); + agent_host_ = DevToolsAgentHost::GetOrCreateFor(shell()->web_contents()); + agent_host_->AttachClient(this); } virtual void TearDownOnMainThread() OVERRIDE { - DevToolsManager::GetInstance()->ClientHostClosing(this); + agent_host_->DetachClient(); + agent_host_ = NULL; } - virtual void DispatchOnInspectorFrontend( - const std::string& message) OVERRIDE { + virtual void DispatchProtocolMessage( + DevToolsAgentHost* agent_host, const std::string& message) OVERRIDE { scoped_ptr<base::DictionaryValue> root( static_cast<base::DictionaryValue*>(base::JSONReader::Read(message))); base::DictionaryValue* result; @@ -76,11 +76,8 @@ class RendererOverridesHandlerTest : public ContentBrowserTest, base::MessageLoop::current()->QuitNow(); } - virtual void InspectedContentsClosing() OVERRIDE { - EXPECT_TRUE(false); - } - - virtual void ReplacedWithAnotherClient() OVERRIDE { + virtual void AgentHostClosed( + DevToolsAgentHost* agent_host, bool replaced) OVERRIDE { EXPECT_TRUE(false); } }; diff --git a/content/browser/devtools/tethering_handler.cc b/content/browser/devtools/tethering_handler.cc index 9b3b7fa..261338a 100644 --- a/content/browser/devtools/tethering_handler.cc +++ b/content/browser/devtools/tethering_handler.cc @@ -9,7 +9,6 @@ #include "base/stl_util.h" #include "base/values.h" #include "content/browser/devtools/devtools_http_handler_impl.h" -#include "content/public/browser/devtools_client_host.h" #include "content/public/browser/devtools_http_handler_delegate.h" #include "net/base/io_buffer.h" #include "net/base/ip_endpoint.h" diff --git a/content/browser/service_worker/service_worker_internals_ui.cc b/content/browser/service_worker/service_worker_internals_ui.cc index 1421fe4..a36cb66 100644 --- a/content/browser/service_worker/service_worker_internals_ui.cc +++ b/content/browser/service_worker/service_worker_internals_ui.cc @@ -11,6 +11,7 @@ #include "base/memory/scoped_vector.h" #include "base/strings/string_number_conversions.h" #include "base/values.h" +#include "content/browser/devtools/devtools_agent_host_impl.h" #include "content/browser/devtools/devtools_manager_impl.h" #include "content/browser/devtools/embedded_worker_devtools_manager.h" #include "content/browser/service_worker/service_worker_context_observer.h" @@ -621,15 +622,14 @@ void ServiceWorkerInternalsUI::InspectWorker(const ListValue* args) { } base::Callback<void(ServiceWorkerStatusCode)> callback = base::Bind(OperationCompleteCallback, AsWeakPtr(), callback_id); - scoped_refptr<DevToolsAgentHost> agent_host( + scoped_refptr<DevToolsAgentHostImpl> agent_host( EmbeddedWorkerDevToolsManager::GetInstance() ->GetDevToolsAgentHostForWorker(process_id, devtools_agent_route_id)); if (!agent_host) { callback.Run(SERVICE_WORKER_ERROR_NOT_FOUND); return; } - DevToolsManagerImpl::GetInstance()->Inspect( - web_ui()->GetWebContents()->GetBrowserContext(), agent_host.get()); + agent_host->Inspect(web_ui()->GetWebContents()->GetBrowserContext()); callback.Run(SERVICE_WORKER_OK); } diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 2fc2c8e3..bce96fb 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -96,14 +96,13 @@ 'public/browser/desktop_media_id.h', 'public/browser/desktop_notification_delegate.h', 'public/browser/devtools_agent_host.h', - 'public/browser/devtools_client_host.h', + 'public/browser/devtools_agent_host_client.h', 'public/browser/devtools_external_agent_proxy.h', 'public/browser/devtools_external_agent_proxy_delegate.h', 'public/browser/download_danger_type.h', 'public/browser/devtools_frontend_host.h', 'public/browser/devtools_http_handler.h', 'public/browser/devtools_http_handler_delegate.h', - 'public/browser/devtools_manager.h', 'public/browser/devtools_manager_delegate.h', 'public/browser/devtools_target.h', 'public/browser/dom_operation_notification_details.h', diff --git a/content/public/browser/devtools_agent_host.h b/content/public/browser/devtools_agent_host.h index be02843..c424650 100644 --- a/content/public/browser/devtools_agent_host.h +++ b/content/public/browser/devtools_agent_host.h @@ -9,8 +9,10 @@ #include <vector> #include "base/basictypes.h" +#include "base/callback.h" #include "base/memory/ref_counted.h" #include "content/common/content_export.h" +#include "content/public/browser/devtools_agent_host_client.h" namespace content { @@ -49,9 +51,18 @@ class CONTENT_EXPORT DevToolsAgentHost // Returns a list of all existing WebContents that can be debugged. static std::vector<WebContents*> GetInspectableWebContents(); + // Client attaches to this agent host to start debugging it. + virtual void AttachClient(DevToolsAgentHostClient* client) = 0; + + // Already attached client detaches from this agent host to stop debugging it. + virtual void DetachClient() = 0; + // Returns true if there is a client attached. virtual bool IsAttached() = 0; + // Sends a message to the agent. + virtual void DispatchProtocolMessage(const std::string& message) = 0; + // Starts inspecting element at position (|x|, |y|) in the specified page. virtual void InspectElement(int x, int y) = 0; @@ -71,6 +82,15 @@ class CONTENT_EXPORT DevToolsAgentHost // Returns true if DevToolsAgentHost is for worker. virtual bool IsWorker() const = 0; + // Terminates all debugging sessions and detaches all clients. + static void DetachAllClients(); + + typedef base::Callback<void(DevToolsAgentHost*, bool attached)> + AgentStateCallback; + + static void AddAgentStateCallback(const AgentStateCallback& callback); + static void RemoveAgentStateCallback(const AgentStateCallback& callback); + protected: friend class base::RefCounted<DevToolsAgentHost>; virtual ~DevToolsAgentHost() {} diff --git a/content/public/browser/devtools_agent_host_client.h b/content/public/browser/devtools_agent_host_client.h new file mode 100644 index 0000000..90d7a73 --- /dev/null +++ b/content/public/browser/devtools_agent_host_client.h @@ -0,0 +1,34 @@ +// 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 CONTENT_PUBLIC_BROWSER_DEVTOOLS_AGENT_HOST_CLIENT_H_ +#define CONTENT_PUBLIC_BROWSER_DEVTOOLS_AGENT_HOST_CLIENT_H_ + +#include <string> + +#include "base/basictypes.h" +#include "content/common/content_export.h" + +namespace content { + +class DevToolsAgentHost; + +// DevToolsAgentHostClient can attach to a DevToolsAgentHost and start +// debugging it. +class CONTENT_EXPORT DevToolsAgentHostClient { + public: + virtual ~DevToolsAgentHostClient() {} + + // Dispatches given protocol message on the client. + virtual void DispatchProtocolMessage(DevToolsAgentHost* agent_host, + const std::string& message) = 0; + + // This method is called when attached agent host is closed. + virtual void AgentHostClosed(DevToolsAgentHost* agent_host, + bool replaced_with_another_client) = 0; +}; + +} // namespace content + +#endif // CONTENT_PUBLIC_BROWSER_DEVTOOLS_AGENT_HOST_CLIENT_H_ diff --git a/content/public/browser/devtools_client_host.h b/content/public/browser/devtools_client_host.h deleted file mode 100644 index 67b7003..0000000 --- a/content/public/browser/devtools_client_host.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_PUBLIC_BROWSER_DEVTOOLS_CLIENT_HOST_H_ -#define CONTENT_PUBLIC_BROWSER_DEVTOOLS_CLIENT_HOST_H_ - -#include <string> - -#include "base/basictypes.h" -#include "content/common/content_export.h" - -namespace IPC { -class Message; -} - -namespace content { - -class RenderViewHost; -class WebContents; - -class DevToolsFrontendHostDelegate; - -// Describes interface for managing devtools clients from browser process. There -// are currently two types of clients: devtools windows and TCP socket -// debuggers. -class CONTENT_EXPORT DevToolsClientHost { - public: - virtual ~DevToolsClientHost() {} - - // Dispatches given message on the front-end. - virtual void DispatchOnInspectorFrontend(const std::string& message) = 0; - - // This method is called when the contents inspected by this devtools client - // is closing. - virtual void InspectedContentsClosing() = 0; - - // Called to notify client that it has been kicked out by some other client - // with greater priority. - virtual void ReplacedWithAnotherClient() = 0; -}; - -} // namespace content - -#endif // CONTENT_PUBLIC_BROWSER_DEVTOOLS_CLIENT_HOST_H_ diff --git a/content/public/browser/devtools_manager.h b/content/public/browser/devtools_manager.h deleted file mode 100644 index 32082ea..0000000 --- a/content/public/browser/devtools_manager.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) 2012 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 CONTENT_PUBLIC_BROWSER_DEVTOOLS_MANAGER_H_ -#define CONTENT_PUBLIC_BROWSER_DEVTOOLS_MANAGER_H_ - -#include <string> - -#include "base/callback.h" -#include "content/common/content_export.h" - -namespace IPC { -class Message; -} - -namespace content { - -class DevToolsAgentHost; -class DevToolsClientHost; - -// DevToolsManager connects a devtools client to inspected agent and routes -// devtools messages between the inspected instance represented by the agent -// and devtools front-end represented by the client. If inspected agent -// gets terminated DevToolsManager will notify corresponding client and -// remove it from the map. -class CONTENT_EXPORT DevToolsManager { - public: - static DevToolsManager* GetInstance(); - - virtual ~DevToolsManager() {} - - // Routes devtools message from |from| client to corresponding - // DevToolsAgentHost. - virtual bool DispatchOnInspectorBackend(DevToolsClientHost* from, - const std::string& message) = 0; - - // Disconnects all client hostst. - virtual void CloseAllClientHosts() = 0; - - // Returns agent that has |client_host| attached to it if there is one. - virtual DevToolsAgentHost* GetDevToolsAgentHostFor( - DevToolsClientHost* client_host) = 0; - - // Registers new DevToolsClientHost for inspected |agent_host|. If there is - // another DevToolsClientHost registered for the |agent_host| at the moment - // it is disconnected. - virtual void RegisterDevToolsClientHostFor( - DevToolsAgentHost* agent_host, - DevToolsClientHost* client_host) = 0; - - // This method will remove all references from the manager to the - // DevToolsClientHost and unregister all listeners related to the - // DevToolsClientHost. Called by closing client. - virtual void ClientHostClosing(DevToolsClientHost* client_host) = 0; - - typedef base::Callback<void(DevToolsAgentHost*, bool attached)> Callback; - - virtual void AddAgentStateCallback(const Callback& callback) = 0; - virtual void RemoveAgentStateCallback(const Callback& callback) = 0; -}; - -} // namespace content - -#endif // CONTENT_PUBLIC_BROWSER_DEVTOOLS_MANAGER_H_ diff --git a/content/shell/browser/shell.cc b/content/shell/browser/shell.cc index c63ff15..b10943d 100644 --- a/content/shell/browser/shell.cc +++ b/content/shell/browser/shell.cc @@ -12,7 +12,7 @@ #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "content/public/browser/devtools_manager.h" +#include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/render_view_host.h" @@ -114,7 +114,7 @@ Shell* Shell::CreateShell(WebContents* web_contents, void Shell::CloseAllWindows() { base::AutoReset<bool> auto_reset(&quit_message_loop_, false); - DevToolsManager::GetInstance()->CloseAllClientHosts(); + DevToolsAgentHost::DetachAllClients(); std::vector<Shell*> open_windows(windows_); for (size_t i = 0; i < open_windows.size(); ++i) open_windows[i]->Close(); diff --git a/content/shell/browser/shell_devtools_frontend.cc b/content/shell/browser/shell_devtools_frontend.cc index a426020..b4abeef 100644 --- a/content/shell/browser/shell_devtools_frontend.cc +++ b/content/shell/browser/shell_devtools_frontend.cc @@ -11,7 +11,6 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "content/public/browser/devtools_http_handler.h" -#include "content/public/browser/devtools_manager.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" @@ -116,8 +115,7 @@ void ShellDevToolsFrontend::RenderViewCreated( RenderViewHost* render_view_host) { if (!frontend_host_) { frontend_host_.reset(DevToolsFrontendHost::Create(render_view_host, this)); - DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor( - agent_host_.get(), this); + agent_host_->AttachClient(this); } } @@ -127,7 +125,7 @@ void ShellDevToolsFrontend::DocumentOnLoadCompletedInMainFrame() { } void ShellDevToolsFrontend::WebContentsDestroyed() { - DevToolsManager::GetInstance()->ClientHostClosing(this); + agent_host_->DetachClient(); delete this; } @@ -159,8 +157,7 @@ void ShellDevToolsFrontend::HandleMessageFromDevToolsFrontend( } dict->GetInteger("id", &id); - DevToolsManager::GetInstance()->DispatchOnInspectorBackend( - this, browser_message); + agent_host_->DispatchProtocolMessage(browser_message); if (id) { std::string code = "InspectorFrontendAPI.embedderMessageAck(" + @@ -172,18 +169,18 @@ void ShellDevToolsFrontend::HandleMessageFromDevToolsFrontend( void ShellDevToolsFrontend::HandleMessageFromDevToolsFrontendToBackend( const std::string& message) { - DevToolsManager::GetInstance()->DispatchOnInspectorBackend( - this, message); + agent_host_->DispatchProtocolMessage(message); } -void ShellDevToolsFrontend::DispatchOnInspectorFrontend( - const std::string& message) { +void ShellDevToolsFrontend::DispatchProtocolMessage( + DevToolsAgentHost* agent_host, const std::string& message) { std::string code = "InspectorFrontendAPI.dispatchMessage(" + message + ");"; base::string16 javascript = base::UTF8ToUTF16(code); web_contents()->GetMainFrame()->ExecuteJavaScript(javascript); } -void ShellDevToolsFrontend::InspectedContentsClosing() { +void ShellDevToolsFrontend::AgentHostClosed( + DevToolsAgentHost* agent_host, bool replaced) { frontend_shell_->Close(); } diff --git a/content/shell/browser/shell_devtools_frontend.h b/content/shell/browser/shell_devtools_frontend.h index 0c7f259..2d2eba6 100644 --- a/content/shell/browser/shell_devtools_frontend.h +++ b/content/shell/browser/shell_devtools_frontend.h @@ -10,7 +10,6 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "content/public/browser/devtools_agent_host.h" -#include "content/public/browser/devtools_client_host.h" #include "content/public/browser/devtools_frontend_host.h" #include "content/public/browser/web_contents_observer.h" @@ -25,7 +24,7 @@ class WebContents; class ShellDevToolsFrontend : public WebContentsObserver, public DevToolsFrontendHost::Delegate, - public DevToolsClientHost { + public DevToolsAgentHostClient { public: static ShellDevToolsFrontend* Show(WebContents* inspected_contents); static ShellDevToolsFrontend* Show(WebContents* inspected_contents, @@ -54,10 +53,11 @@ class ShellDevToolsFrontend : public WebContentsObserver, virtual void HandleMessageFromDevToolsFrontendToBackend( const std::string& message) OVERRIDE; - // content::DevToolsClientHost implementation. - virtual void DispatchOnInspectorFrontend(const std::string& message) OVERRIDE; - virtual void InspectedContentsClosing() OVERRIDE; - virtual void ReplacedWithAnotherClient() OVERRIDE {} + // content::DevToolsAgentHostClient implementation. + virtual void DispatchProtocolMessage( + DevToolsAgentHost* agent_host, const std::string& message) OVERRIDE; + virtual void AgentHostClosed( + DevToolsAgentHost* agent_host, bool replaced) OVERRIDE; Shell* frontend_shell_; scoped_refptr<DevToolsAgentHost> agent_host_; diff --git a/content/shell/browser/webkit_test_controller.cc b/content/shell/browser/webkit_test_controller.cc index 960f6a6..8fc8225 100644 --- a/content/shell/browser/webkit_test_controller.cc +++ b/content/shell/browser/webkit_test_controller.cc @@ -12,7 +12,7 @@ #include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" -#include "content/public/browser/devtools_manager.h" +#include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/dom_storage_context.h" #include "content/public/browser/gpu_data_manager.h" #include "content/public/browser/navigation_controller.h" @@ -653,7 +653,7 @@ void WebKitTestController::OnCaptureSessionHistory() { } void WebKitTestController::OnCloseRemainingWindows() { - DevToolsManager::GetInstance()->CloseAllClientHosts(); + DevToolsAgentHost::DetachAllClients(); std::vector<Shell*> open_windows(Shell::windows()); for (size_t i = 0; i < open_windows.size(); ++i) { if (open_windows[i] != main_window_) |