// 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 "apps/app_window.h" #include "apps/app_window_registry.h" #include "apps/apps_client.h" #include "apps/ui/native_app_window.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_manager.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/extensions_browser_client.h" #include "extensions/common/extension.h" namespace { // Create a key that identifies a AppWindow in a RenderViewHost across App // reloads. If the window was given an id in CreateParams, the key is the // extension id, a colon separator, and the AppWindow's |id|. If there is no // |id|, the chrome-extension://extension-id/page.html URL will be used. If the // RenderViewHost is not for a AppWindow, return an empty string. std::string GetWindowKeyForRenderViewHost( const apps::AppWindowRegistry* registry, content::RenderViewHost* render_view_host) { apps::AppWindow* app_window = registry->GetAppWindowForRenderViewHost(render_view_host); if (!app_window) return std::string(); // Not a AppWindow. if (app_window->window_key().empty()) return app_window->web_contents()->GetURL().possibly_invalid_spec(); std::string key = app_window->extension()->id(); key += ':'; key += app_window->window_key(); return key; } } // namespace namespace apps { AppWindowRegistry::AppWindowRegistry(content::BrowserContext* context) : context_(context), devtools_callback_(base::Bind(&AppWindowRegistry::OnDevToolsStateChanged, base::Unretained(this))) { content::DevToolsManager::GetInstance()->AddAgentStateCallback( devtools_callback_); } AppWindowRegistry::~AppWindowRegistry() { content::DevToolsManager::GetInstance()->RemoveAgentStateCallback( devtools_callback_); } // static AppWindowRegistry* AppWindowRegistry::Get(content::BrowserContext* context) { return Factory::GetForBrowserContext(context, true /* create */); } void AppWindowRegistry::AddAppWindow(AppWindow* app_window) { BringToFront(app_window); FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowAdded(app_window)); } void AppWindowRegistry::AppWindowIconChanged(AppWindow* app_window) { AddAppWindowToList(app_window); FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowIconChanged(app_window)); } void AppWindowRegistry::AppWindowActivated(AppWindow* app_window) { BringToFront(app_window); } void AppWindowRegistry::RemoveAppWindow(AppWindow* app_window) { const AppWindowList::iterator it = std::find(app_windows_.begin(), app_windows_.end(), app_window); if (it != app_windows_.end()) app_windows_.erase(it); FOR_EACH_OBSERVER(Observer, observers_, OnAppWindowRemoved(app_window)); } void AppWindowRegistry::AddObserver(Observer* observer) { observers_.AddObserver(observer); } void AppWindowRegistry::RemoveObserver(Observer* observer) { observers_.RemoveObserver(observer); } AppWindowRegistry::AppWindowList AppWindowRegistry::GetAppWindowsForApp( const std::string& app_id) const { AppWindowList app_windows; for (AppWindowList::const_iterator i = app_windows_.begin(); i != app_windows_.end(); ++i) { if ((*i)->extension_id() == app_id) app_windows.push_back(*i); } return app_windows; } void AppWindowRegistry::CloseAllAppWindowsForApp(const std::string& app_id) { for (AppWindowList::const_iterator i = app_windows_.begin(); i != app_windows_.end();) { AppWindow* app_window = *(i++); if (app_window->extension_id() == app_id) app_window->GetBaseWindow()->Close(); } } AppWindow* AppWindowRegistry::GetAppWindowForRenderViewHost( content::RenderViewHost* render_view_host) const { for (AppWindowList::const_iterator i = app_windows_.begin(); i != app_windows_.end(); ++i) { if ((*i)->web_contents()->GetRenderViewHost() == render_view_host) return *i; } return NULL; } AppWindow* AppWindowRegistry::GetAppWindowForNativeWindow( gfx::NativeWindow window) const { for (AppWindowList::const_iterator i = app_windows_.begin(); i != app_windows_.end(); ++i) { if ((*i)->GetNativeWindow() == window) return *i; } return NULL; } AppWindow* AppWindowRegistry::GetCurrentAppWindowForApp( const std::string& app_id) const { AppWindow* result = NULL; for (AppWindowList::const_iterator i = app_windows_.begin(); i != app_windows_.end(); ++i) { if ((*i)->extension()->id() == app_id) { result = *i; if (result->GetBaseWindow()->IsActive()) return result; } } return result; } AppWindow* AppWindowRegistry::GetAppWindowForAppAndKey( const std::string& app_id, const std::string& window_key) const { AppWindow* result = NULL; for (AppWindowList::const_iterator i = app_windows_.begin(); i != app_windows_.end(); ++i) { if ((*i)->extension()->id() == app_id && (*i)->window_key() == window_key) { result = *i; if (result->GetBaseWindow()->IsActive()) return result; } } return result; } bool AppWindowRegistry::HadDevToolsAttached( content::RenderViewHost* render_view_host) const { std::string key = GetWindowKeyForRenderViewHost(this, render_view_host); return key.empty() ? false : inspected_windows_.count(key) != 0; } // static AppWindow* AppWindowRegistry::GetAppWindowForNativeWindowAnyProfile( gfx::NativeWindow window) { std::vector contexts = AppsClient::Get()->GetLoadedBrowserContexts(); for (std::vector::const_iterator i = contexts.begin(); i != contexts.end(); ++i) { AppWindowRegistry* registry = Factory::GetForBrowserContext(*i, false /* create */); if (!registry) continue; AppWindow* app_window = registry->GetAppWindowForNativeWindow(window); if (app_window) return app_window; } return NULL; } // static bool AppWindowRegistry::IsAppWindowRegisteredInAnyProfile( int window_type_mask) { std::vector contexts = AppsClient::Get()->GetLoadedBrowserContexts(); for (std::vector::const_iterator i = contexts.begin(); i != contexts.end(); ++i) { AppWindowRegistry* registry = Factory::GetForBrowserContext(*i, false /* create */); if (!registry) continue; const AppWindowList& app_windows = registry->app_windows(); if (app_windows.empty()) continue; if (window_type_mask == 0) return true; for (const_iterator j = app_windows.begin(); j != app_windows.end(); ++j) { if ((*j)->window_type() & window_type_mask) return true; } } return false; } void AppWindowRegistry::OnDevToolsStateChanged( content::DevToolsAgentHost* agent_host, bool attached) { content::RenderViewHost* rvh = agent_host->GetRenderViewHost(); // Ignore unrelated notifications. if (!rvh || rvh->GetSiteInstance()->GetProcess()->GetBrowserContext() != context_) return; std::string key = GetWindowKeyForRenderViewHost(this, rvh); if (key.empty()) return; if (attached) inspected_windows_.insert(key); else inspected_windows_.erase(key); } void AppWindowRegistry::AddAppWindowToList(AppWindow* app_window) { const AppWindowList::iterator it = std::find(app_windows_.begin(), app_windows_.end(), app_window); if (it != app_windows_.end()) return; app_windows_.push_back(app_window); } void AppWindowRegistry::BringToFront(AppWindow* app_window) { const AppWindowList::iterator it = std::find(app_windows_.begin(), app_windows_.end(), app_window); if (it != app_windows_.end()) app_windows_.erase(it); app_windows_.push_front(app_window); } /////////////////////////////////////////////////////////////////////////////// // Factory boilerplate // static AppWindowRegistry* AppWindowRegistry::Factory::GetForBrowserContext( content::BrowserContext* context, bool create) { return static_cast( GetInstance()->GetServiceForBrowserContext(context, create)); } AppWindowRegistry::Factory* AppWindowRegistry::Factory::GetInstance() { return Singleton::get(); } AppWindowRegistry::Factory::Factory() : BrowserContextKeyedServiceFactory( "AppWindowRegistry", BrowserContextDependencyManager::GetInstance()) {} AppWindowRegistry::Factory::~Factory() {} KeyedService* AppWindowRegistry::Factory::BuildServiceInstanceFor( content::BrowserContext* context) const { return new AppWindowRegistry(context); } bool AppWindowRegistry::Factory::ServiceIsCreatedWithBrowserContext() const { return true; } bool AppWindowRegistry::Factory::ServiceIsNULLWhileTesting() const { return false; } content::BrowserContext* AppWindowRegistry::Factory::GetBrowserContextToUse( content::BrowserContext* context) const { return extensions::ExtensionsBrowserClient::Get()->GetOriginalContext( context); } } // namespace extensions