diff options
21 files changed, 493 insertions, 227 deletions
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index f86d997..113fcbf 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -94,6 +94,16 @@ base::LazyInstance<Static> g_global_io_data = LAZY_INSTANCE_INITIALIZER; } // namespace +ExtensionWindowController* + ExtensionFunctionDispatcher::Delegate::GetExtensionWindowController() + const { + return NULL; +} + +content::WebContents* + ExtensionFunctionDispatcher::Delegate::GetAssociatedWebContents() const { + return NULL; +} void ExtensionFunctionDispatcher::GetAllFunctionNames( std::vector<std::string>* names) { diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h index 4a731d9..5278171 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.h +++ b/chrome/browser/extensions/extension_function_dispatcher.h @@ -55,13 +55,13 @@ class ExtensionFunctionDispatcher public: // Returns the ExtensionWindowController associated with this delegate, // or NULL if no window is associated with the delegate. - virtual ExtensionWindowController* GetExtensionWindowController() const = 0; + virtual ExtensionWindowController* GetExtensionWindowController() const; // Asks the delegate for any relevant WebContents associated with this // context. For example, the WebbContents in which an infobar or // chrome-extension://<id> URL are being shown. Callers must check for a // NULL return value (as in the case of a background page). - virtual content::WebContents* GetAssociatedWebContents() const = 0; + virtual content::WebContents* GetAssociatedWebContents() const; protected: virtual ~Delegate() {} diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc index 71f3281..e7562fc 100644 --- a/chrome/browser/extensions/extension_host.cc +++ b/chrome/browser/extensions/extension_host.cc @@ -179,10 +179,6 @@ void ExtensionHost::CreateView(Browser* browser) { #endif } -void ExtensionHost::CreateViewWithoutBrowser() { - CreateView(NULL); -} - WebContents* ExtensionHost::GetAssociatedWebContents() const { return associated_web_contents_; } @@ -196,7 +192,6 @@ void ExtensionHost::SetAssociatedWebContents( } } - content::RenderProcessHost* ExtensionHost::render_process_host() const { return render_view_host()->GetProcess(); } @@ -211,13 +206,10 @@ bool ExtensionHost::IsRenderViewLive() const { } void ExtensionHost::CreateRenderViewSoon() { - if ((render_process_host() && render_process_host()->HasConnection()) || - extension_host_type_ == chrome::VIEW_TYPE_APP_SHELL) { + if ((render_process_host() && render_process_host()->HasConnection())) { // If the process is already started, go ahead and initialize the RenderView // synchronously. The process creation is the real meaty part that we want // to defer. - // We also skip the ratelimiting in the shell window case. This is a hack - // (see crbug.com/124350 for details). CreateRenderViewNow(); } else { ProcessCreationQueue::GetInstance()->CreateSoon(this); @@ -295,8 +287,8 @@ void ExtensionHost::Observe(int type, void ExtensionHost::ResizeDueToAutoResize(WebContents* source, const gfx::Size& new_size) { - if (view_.get()) - view_->ResizeDueToAutoResize(new_size); + if (view()) + view()->ResizeDueToAutoResize(new_size); } void ExtensionHost::RenderViewGone(base::TerminationStatus status) { @@ -340,11 +332,10 @@ void ExtensionHost::DidStopLoading() { if (extension_host_type_ == chrome::VIEW_TYPE_EXTENSION_POPUP || extension_host_type_ == chrome::VIEW_TYPE_EXTENSION_DIALOG || extension_host_type_ == chrome::VIEW_TYPE_EXTENSION_INFOBAR || - extension_host_type_ == chrome::VIEW_TYPE_APP_SHELL || extension_host_type_ == chrome::VIEW_TYPE_PANEL) { #if defined(TOOLKIT_VIEWS) || defined(OS_MACOSX) - if (view_.get()) - view_->DidStopLoading(); + if (view()) + view()->DidStopLoading(); #endif } if (notify) { @@ -360,8 +351,6 @@ void ExtensionHost::DidStopLoading() { } else if (extension_host_type_ == chrome::VIEW_TYPE_EXTENSION_INFOBAR) { UMA_HISTOGRAM_TIMES("Extensions.InfobarLoadTime", since_created_.Elapsed()); - } else if (extension_host_type_ == chrome::VIEW_TYPE_APP_SHELL) { - UMA_HISTOGRAM_TIMES("Extensions.ShellLoadTime", since_created_.Elapsed()); } else if (extension_host_type_ == chrome::VIEW_TYPE_PANEL) { UMA_HISTOGRAM_TIMES("Extensions.PanelLoadTime", since_created_.Elapsed()); } @@ -401,16 +390,11 @@ void ExtensionHost::CloseContents(WebContents* contents) { extension_host_type_ == chrome::VIEW_TYPE_EXTENSION_DIALOG || extension_host_type_ == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE || extension_host_type_ == chrome::VIEW_TYPE_EXTENSION_INFOBAR || - extension_host_type_ == chrome::VIEW_TYPE_APP_SHELL || extension_host_type_ == chrome::VIEW_TYPE_PANEL) { Close(); } } -bool ExtensionHost::ShouldSuppressDialogs() { - return extension_->is_platform_app(); -} - void ExtensionHost::WillRunJavaScriptDialog() { ExtensionProcessManager* pm = ExtensionSystem::Get(profile_)->process_manager(); @@ -510,8 +494,8 @@ void ExtensionHost::OnDecrementLazyKeepaliveCount() { void ExtensionHost::RenderViewCreated(RenderViewHost* render_view_host) { render_view_host_ = render_view_host; - if (view_.get()) - view_->RenderViewCreated(); + if (view()) + view()->RenderViewCreated(); // If the host is bound to a window, then extract its id. Extensions hosted // in ExternalTabContainer objects may not have an associated window. diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h index 764f05b..96aa74d 100644 --- a/chrome/browser/extensions/extension_host.h +++ b/chrome/browser/extensions/extension_host.h @@ -92,9 +92,6 @@ class ExtensionHost : public content::WebContentsDelegate, // instantiate Browser objects. void CreateView(Browser* browser); - // Helper variant of the above for cases where no Browser is present. - void CreateViewWithoutBrowser(); - const Extension* extension() const { return extension_; } const std::string& extension_id() const { return extension_id_; } content::WebContents* host_contents() const { return host_contents_.get(); } @@ -162,7 +159,6 @@ class ExtensionHost : public content::WebContentsDelegate, const gfx::Rect& initial_pos, bool user_gesture) OVERRIDE; virtual void CloseContents(content::WebContents* contents) OVERRIDE; - virtual bool ShouldSuppressDialogs() OVERRIDE; // content::NotificationObserver virtual void Observe(int type, diff --git a/chrome/browser/extensions/extension_process_manager.cc b/chrome/browser/extensions/extension_process_manager.cc index 8b606e7..9bc68d6 100644 --- a/chrome/browser/extensions/extension_process_manager.cc +++ b/chrome/browser/extensions/extension_process_manager.cc @@ -170,22 +170,6 @@ ExtensionProcessManager::~ExtensionProcessManager() { DCHECK(background_hosts_.empty()); } -ExtensionHost* ExtensionProcessManager::CreateShellHost( - const Extension* extension, - const GURL& url) { - DCHECK(extension); - ExtensionHost* host = new ExtensionHost(extension, - GetSiteInstanceForURL(url), - url, - chrome::VIEW_TYPE_APP_SHELL); - host->CreateViewWithoutBrowser(); - content::WebContents* host_contents = host->host_contents(); - host_contents->GetMutableRendererPrefs()->browser_handles_all_requests = true; - host_contents->GetRenderViewHost()->SyncRendererPrefs(); - OnExtensionHostCreated(host, false /* not a background host */); - return host; -} - void ExtensionProcessManager::EnsureBrowserWhenRequired( Browser* browser, content::ViewType view_type) { @@ -361,6 +345,11 @@ void ExtensionProcessManager::UnregisterRenderViewHost( if (view == all_extension_views_.end()) return; + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED, + content::Source<Profile>(GetProfile()), + content::Details<RenderViewHost>(render_view_host)); + content::ViewType view_type = view->second; all_extension_views_.erase(view); @@ -381,18 +370,17 @@ void ExtensionProcessManager::UpdateRegisteredRenderView( if (view == all_extension_views_.end()) return; + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED, + content::Source<Profile>(GetProfile()), + content::Details<RenderViewHost>(render_view_host)); + view->second = render_view_host->GetDelegate()->GetRenderViewType(); // Keep the lazy background page alive as long as any non-background-page // extension views are visible. Keepalive count balanced in // UnregisterRenderViewHost. - if (view->second != content::VIEW_TYPE_INVALID && - view->second != chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { - const Extension* extension = GetExtensionForRenderViewHost( - render_view_host); - if (extension) - IncrementLazyKeepaliveCount(extension); - } + IncrementLazyKeepaliveCountForView(render_view_host); } SiteInstance* ExtensionProcessManager::GetSiteInstanceForURL(const GURL& url) { @@ -442,6 +430,18 @@ int ExtensionProcessManager::DecrementLazyKeepaliveCount( return count; } +void ExtensionProcessManager::IncrementLazyKeepaliveCountForView( + RenderViewHost* render_view_host) { + content::ViewType view_type = + render_view_host->GetDelegate()->GetRenderViewType(); + if (view_type != content::VIEW_TYPE_INVALID && + view_type != chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE) { + const Extension* extension = GetExtensionForRenderViewHost( + render_view_host); + if (extension) + IncrementLazyKeepaliveCount(extension); + } +} void ExtensionProcessManager::OnLazyBackgroundPageIdle( const std::string& extension_id, int sequence_id) { @@ -552,7 +552,6 @@ void ExtensionProcessManager::Observe( ExtensionHost* host = content::Details<ExtensionHost>(details).ptr(); if (background_hosts_.erase(host)) ClearBackgroundPageData(host->extension()->id()); - platform_app_hosts_.erase(host); break; } @@ -623,8 +622,6 @@ void ExtensionProcessManager::OnExtensionHostCreated(ExtensionHost* host, DCHECK_EQ(site_instance_->GetBrowserContext(), host->profile()); if (is_background) background_hosts_.insert(host); - if (host->extension()->is_platform_app()) - platform_app_hosts_.insert(host); } void ExtensionProcessManager::CloseBackgroundHost(ExtensionHost* host) { @@ -653,7 +650,7 @@ void ExtensionProcessManager::ClearBackgroundPageData( for (ExtensionRenderViews::const_iterator it = all_extension_views_.begin(); it != all_extension_views_.end(); ++it) { if (GetExtensionID(it->first) == extension_id) - UpdateRegisteredRenderView(it->first); + IncrementLazyKeepaliveCountForView(it->first); } } diff --git a/chrome/browser/extensions/extension_process_manager.h b/chrome/browser/extensions/extension_process_manager.h index adaa7fd..33f5820 100644 --- a/chrome/browser/extensions/extension_process_manager.h +++ b/chrome/browser/extensions/extension_process_manager.h @@ -44,10 +44,6 @@ class ExtensionProcessManager : public content::NotificationObserver { return background_hosts_; } - const ExtensionHostSet& platform_app_hosts() const { - return platform_app_hosts_; - } - typedef std::set<content::RenderViewHost*> ViewSet; const ViewSet GetAllViews() const; @@ -71,7 +67,6 @@ class ExtensionProcessManager : public content::NotificationObserver { Browser* browser); ExtensionHost* CreateInfobarHost(const GURL& url, Browser* browser); - ExtensionHost* CreateShellHost(const Extension* extension, const GURL& url); // Open the extension's options page. void OpenOptionsPage(const Extension* extension, Browser* browser); @@ -119,6 +114,9 @@ class ExtensionProcessManager : public content::NotificationObserver { int IncrementLazyKeepaliveCount(const Extension* extension); int DecrementLazyKeepaliveCount(const Extension* extension); + void IncrementLazyKeepaliveCountForView( + content::RenderViewHost* render_view_host); + // Handles a response to the ShouldUnload message, used for lazy background // pages. void OnShouldUnloadAck(const std::string& extension_id, int sequence_id); @@ -154,9 +152,6 @@ class ExtensionProcessManager : public content::NotificationObserver { // The set of ExtensionHosts running viewless background extensions. ExtensionHostSet background_hosts_; - // The set of ExtensionHosts running platform apps. - ExtensionHostSet platform_app_hosts_; - // A SiteInstance related to the SiteInstance for all extensions in // this profile. We create it in such a way that a new // browsing instance is created. This controls process grouping. diff --git a/chrome/browser/extensions/platform_app_browsertest.cc b/chrome/browser/extensions/platform_app_browsertest.cc index a4ade53..44f615a 100644 --- a/chrome/browser/extensions/platform_app_browsertest.cc +++ b/chrome/browser/extensions/platform_app_browsertest.cc @@ -8,15 +8,15 @@ #include "chrome/browser/automation/automation_util.h" #include "chrome/browser/extensions/extension_apitest.h" #include "chrome/browser/extensions/extension_browsertest.h" -#include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_test_message_listener.h" +#include "chrome/browser/extensions/shell_window_registry.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/tab_contents/render_view_context_menu.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" +#include "chrome/browser/ui/extensions/shell_window.h" #include "chrome/common/chrome_switches.h" -#include "chrome/common/chrome_view_type.h" #include "chrome/common/extensions/extension_constants.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/web_contents.h" @@ -57,7 +57,6 @@ class PlatformAppBrowserTest : public ExtensionApiTest { protected: void LoadAndLaunchPlatformApp(const char* name) { - size_t platform_app_count = GetPlatformAppCount(); ui_test_utils::WindowedNotificationObserver app_loaded_observer( content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME, content::NotificationService::AllSources()); @@ -78,41 +77,19 @@ class PlatformAppBrowserTest : public ExtensionApiTest { NEW_WINDOW); app_loaded_observer.Wait(); - - // Now we have a new platform app running. - EXPECT_EQ(platform_app_count + 1, GetPlatformAppCount()); - } - - // Gets the number of platform apps extension hosts that are running. - size_t GetPlatformAppCount() { - int count = 0; - ExtensionProcessManager* process_manager = - browser()->profile()->GetExtensionProcessManager(); - ExtensionProcessManager::const_iterator iter; - ExtensionProcessManager::ExtensionHostSet platform_app_hosts = - process_manager->platform_app_hosts(); - for (iter = platform_app_hosts.begin(); iter != platform_app_hosts.end(); - ++iter) { - if ((*iter)->extension()) - count++; - } - - return count; } - // Gets the WebContents associated with the ExtensionHost of the first - // platform app shell window that is found (most tests only deal with one - // platform app window, so this is good enough). - WebContents* GetFirstPlatformAppShellWindowWebContents() { - ExtensionProcessManager* process_manager = - browser()->profile()->GetExtensionProcessManager(); - ExtensionProcessManager::const_iterator iter; - ExtensionProcessManager::ExtensionHostSet platform_app_hosts = - process_manager->platform_app_hosts(); - for (iter = platform_app_hosts.begin(); iter != platform_app_hosts.end(); - ++iter) { - if ((*iter)->extension_host_type() == chrome::VIEW_TYPE_APP_SHELL) - return (*iter)->host_contents(); + // Gets the WebContents associated with the first shell window that is found + // (most tests only deal with one platform app window, so this is good + // enough). + WebContents* GetFirstShellWindowWebContents() { + ShellWindowRegistry* app_registry = + ShellWindowRegistry::Get(browser()->profile()); + ShellWindowRegistry::const_iterator iter; + ShellWindowRegistry::ShellWindowSet shell_windows = + app_registry->shell_windows(); + for (iter = shell_windows.begin(); iter != shell_windows.end(); ++iter) { + return (*iter)->web_contents(); } return NULL; @@ -132,13 +109,15 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, EmptyContextMenu) { // The empty app doesn't add any context menu items, so its menu should // only include the developer tools. - WebContents* web_contents = GetFirstPlatformAppShellWindowWebContents(); + WebContents* web_contents = GetFirstShellWindowWebContents(); ASSERT_TRUE(web_contents); WebKit::WebContextMenuData data; content::ContextMenuParams params(data); PlatformAppContextMenu* menu = new PlatformAppContextMenu(web_contents, params); menu->Init(); + // TODO(benwells): Remove the constant below. Instead of checking the + // number of menu items check certain item's absense and presence. // 3 including separator ASSERT_EQ(3, menu->menu_model().GetItemCount()); } @@ -153,13 +132,15 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenu) { // The context_menu app has one context menu item. This, along with a // separator and the developer tools, is all that should be in the menu. - WebContents* web_contents = GetFirstPlatformAppShellWindowWebContents(); + WebContents* web_contents = GetFirstShellWindowWebContents(); ASSERT_TRUE(web_contents); WebKit::WebContextMenuData data; content::ContextMenuParams params(data); PlatformAppContextMenu* menu = new PlatformAppContextMenu(web_contents, params); menu->Init(); + // TODO(benwells): Remove the constant below. Instead of checking the + // number of menu items check certain item's absense and presence. ASSERT_EQ(4, menu->menu_model().GetItemCount()); } diff --git a/chrome/browser/extensions/shell_window_registry.cc b/chrome/browser/extensions/shell_window_registry.cc new file mode 100644 index 0000000..375fb9c --- /dev/null +++ b/chrome/browser/extensions/shell_window_registry.cc @@ -0,0 +1,59 @@ +// 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. + +#include "chrome/browser/extensions/shell_window_registry.h" +#include "chrome/browser/profiles/profile_dependency_manager.h" + +ShellWindowRegistry::ShellWindowRegistry() {} + +ShellWindowRegistry::~ShellWindowRegistry() {} + +// static +ShellWindowRegistry* ShellWindowRegistry::Get(Profile* profile) { + return Factory::GetForProfile(profile); +} + +void ShellWindowRegistry::AddShellWindow(ShellWindow* shell_window) { + shell_windows_.insert(shell_window); +} + +void ShellWindowRegistry::RemoveShellWindow(ShellWindow* shell_window) { + shell_windows_.erase(shell_window); +} + + +/////////////////////////////////////////////////////////////////////////////// +// Factory boilerplate + +// static +ShellWindowRegistry* ShellWindowRegistry::Factory::GetForProfile( + Profile* profile) { + return static_cast<ShellWindowRegistry*>( + GetInstance()->GetServiceForProfile(profile, true)); +} + +ShellWindowRegistry::Factory* ShellWindowRegistry::Factory::GetInstance() { + return Singleton<ShellWindowRegistry::Factory>::get(); +} + +ShellWindowRegistry::Factory::Factory() + : ProfileKeyedServiceFactory("ShellWindowRegistry", + ProfileDependencyManager::GetInstance()) { +} + +ShellWindowRegistry::Factory::~Factory() { +} + +ProfileKeyedService* ShellWindowRegistry::Factory::BuildServiceInstanceFor( + Profile* profile) const { + return new ShellWindowRegistry(); +} + +bool ShellWindowRegistry::Factory::ServiceIsCreatedWithProfile() { + return true; +} + +bool ShellWindowRegistry::Factory::ServiceIsNULLWhileTesting() { + return false; +} diff --git a/chrome/browser/extensions/shell_window_registry.h b/chrome/browser/extensions/shell_window_registry.h new file mode 100644 index 0000000..a2c5a4e --- /dev/null +++ b/chrome/browser/extensions/shell_window_registry.h @@ -0,0 +1,65 @@ +// 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 CHROME_BROWSER_EXTENSIONS_SHELL_WINDOW_REGISTRY_H_ +#define CHROME_BROWSER_EXTENSIONS_SHELL_WINDOW_REGISTRY_H_ +#pragma once + +#include <set> + +#include "base/compiler_specific.h" +#include "base/memory/singleton.h" +#include "chrome/browser/profiles/profile_keyed_service.h" +#include "chrome/browser/profiles/profile_keyed_service_factory.h" + +class Profile; +class ShellWindow; + +// The ShellWindowRegistry tracks the ShellWindows for all platform apps for a +// particular profile. +// This class is planned to evolve into tracking all PlatformApps for a +// particular profile, with a PlatformApp encapsulating all views (background +// page, shell windows, tray view, panels etc.) and other app level behaviour +// (e.g. notifications the app is interested in, lifetime of the background +// page). +class ShellWindowRegistry : public ProfileKeyedService { + public: + typedef std::set<ShellWindow*> ShellWindowSet; + typedef ShellWindowSet::const_iterator const_iterator; + + ShellWindowRegistry(); + virtual ~ShellWindowRegistry(); + + // Returns the instance for the given profile, or NULL if none. This is + // a convenience wrapper around ShellWindowRegistryFactory::GetForProfile. + static ShellWindowRegistry* Get(Profile* profile); + + void AddShellWindow(ShellWindow* shell_window); + void RemoveShellWindow(ShellWindow* shell_window); + + const ShellWindowSet& shell_windows() const { return shell_windows_; } + + private: + class Factory : public ProfileKeyedServiceFactory { + public: + static ShellWindowRegistry* GetForProfile(Profile* profile); + + static Factory* GetInstance(); + private: + friend struct DefaultSingletonTraits<Factory>; + + Factory(); + virtual ~Factory(); + + // ProfileKeyedServiceFactory + virtual ProfileKeyedService* BuildServiceInstanceFor( + Profile* profile) const OVERRIDE; + virtual bool ServiceIsCreatedWithProfile() OVERRIDE; + virtual bool ServiceIsNULLWhileTesting() OVERRIDE; + }; + + ShellWindowSet shell_windows_; +}; + +#endif // CHROME_BROWSER_EXTENSIONS_SHELL_WINDOW_REGISTRY_H_ diff --git a/chrome/browser/task_manager/task_manager_resource_providers.cc b/chrome/browser/task_manager/task_manager_resource_providers.cc index 327ea9a..b252812 100644 --- a/chrome/browser/task_manager/task_manager_resource_providers.cc +++ b/chrome/browser/task_manager/task_manager_resource_providers.cc @@ -1259,28 +1259,17 @@ void TaskManagerExtensionProcessResourceProvider::StartUpdating() { if (!rvh->IsRenderViewLive()) continue; - // Don't add WebContents (those are handled by - // TaskManagerTabContentsResourceProvider) or background contents - // (handled by TaskManagerBackgroundResourceProvider). - // TODO(benwells): create specific chrome::VIEW_TYPE_TAB_CONTENTS for - // tab contents, as VIEW_TYPE_WEB_CONTENTS is the default. - content::ViewType view_type = rvh->GetDelegate()->GetRenderViewType(); - if (view_type == content::VIEW_TYPE_WEB_CONTENTS || - view_type == chrome::VIEW_TYPE_BACKGROUND_CONTENTS) { - continue; - } - AddToTaskManager(rvh); } } } // Register for notifications about extension process changes. - registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_CREATED, + registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED, content::NotificationService::AllBrowserContextsAndSources()); registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, content::NotificationService::AllBrowserContextsAndSources()); - registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, + registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED, content::NotificationService::AllBrowserContextsAndSources()); } @@ -1290,13 +1279,13 @@ void TaskManagerExtensionProcessResourceProvider::StopUpdating() { // Unregister for notifications about extension process changes. registrar_.Remove( - this, chrome::NOTIFICATION_EXTENSION_HOST_CREATED, + this, chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED, content::NotificationService::AllBrowserContextsAndSources()); registrar_.Remove( this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, content::NotificationService::AllBrowserContextsAndSources()); registrar_.Remove( - this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED, + this, chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED, content::NotificationService::AllBrowserContextsAndSources()); // Delete all the resources. @@ -1311,23 +1300,42 @@ void TaskManagerExtensionProcessResourceProvider::Observe( const content::NotificationSource& source, const content::NotificationDetails& details) { switch (type) { - case chrome::NOTIFICATION_EXTENSION_HOST_CREATED: + case chrome::NOTIFICATION_EXTENSION_VIEW_REGISTERED: AddToTaskManager( - content::Details<ExtensionHost>(details).ptr()->render_view_host()); + content::Details<content::RenderViewHost>(details).ptr()); break; case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: - case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: RemoveFromTaskManager( content::Details<ExtensionHost>(details).ptr()->render_view_host()); break; + case chrome::NOTIFICATION_EXTENSION_VIEW_UNREGISTERED: + RemoveFromTaskManager( + content::Details<content::RenderViewHost>(details).ptr()); + break; default: NOTREACHED() << "Unexpected notification."; return; } } +bool TaskManagerExtensionProcessResourceProvider:: + IsHandledByThisProvider(content::RenderViewHost* render_view_host) { + // Don't add WebContents (those are handled by + // TaskManagerTabContentsResourceProvider) or background contents (handled + // by TaskManagerBackgroundResourceProvider). + // TODO(benwells): create specific chrome::VIEW_TYPE_TAB_CONTENTS for + // tab contents, as VIEW_TYPE_WEB_CONTENTS is the default. + content::ViewType view_type = + render_view_host->GetDelegate()->GetRenderViewType(); + return (view_type != content::VIEW_TYPE_WEB_CONTENTS && + view_type != chrome::VIEW_TYPE_BACKGROUND_CONTENTS); +} + void TaskManagerExtensionProcessResourceProvider::AddToTaskManager( content::RenderViewHost* render_view_host) { + if (!IsHandledByThisProvider(render_view_host)) + return; + TaskManagerExtensionProcessResource* resource = new TaskManagerExtensionProcessResource(render_view_host); DCHECK(resources_.find(render_view_host) == resources_.end()); diff --git a/chrome/browser/task_manager/task_manager_resource_providers.h b/chrome/browser/task_manager/task_manager_resource_providers.h index e3299e9..721e3ec 100644 --- a/chrome/browser/task_manager/task_manager_resource_providers.h +++ b/chrome/browser/task_manager/task_manager_resource_providers.h @@ -402,6 +402,7 @@ class TaskManagerExtensionProcessResourceProvider private: virtual ~TaskManagerExtensionProcessResourceProvider(); + bool IsHandledByThisProvider(content::RenderViewHost* render_view_host); void AddToTaskManager(content::RenderViewHost* render_view_host); void RemoveFromTaskManager(content::RenderViewHost* render_view_host); diff --git a/chrome/browser/ui/cocoa/extensions/shell_window_cocoa.h b/chrome/browser/ui/cocoa/extensions/shell_window_cocoa.h index d4d0f69..b5020ec 100644 --- a/chrome/browser/ui/cocoa/extensions/shell_window_cocoa.h +++ b/chrome/browser/ui/cocoa/extensions/shell_window_cocoa.h @@ -13,7 +13,7 @@ #include "chrome/browser/ui/extensions/shell_window.h" #include "ui/gfx/rect.h" -class ExtensionHost; +class Profile; class ShellWindowCocoa; // A window controller for a minimal window to host a web app view. Passes @@ -30,7 +30,9 @@ class ShellWindowCocoa; // Cocoa bridge to ShellWindow. class ShellWindowCocoa : public ShellWindow { public: - explicit ShellWindowCocoa(ExtensionHost* host); + ShellWindowCocoa(Profile* profile, + const Extension* extension, + const GURL& url); // BaseWindow implementation. virtual bool IsActive() const OVERRIDE; diff --git a/chrome/browser/ui/cocoa/extensions/shell_window_cocoa.mm b/chrome/browser/ui/cocoa/extensions/shell_window_cocoa.mm index 9487eab..01e41fb 100644 --- a/chrome/browser/ui/cocoa/extensions/shell_window_cocoa.mm +++ b/chrome/browser/ui/cocoa/extensions/shell_window_cocoa.mm @@ -5,10 +5,12 @@ #include "chrome/browser/ui/cocoa/extensions/shell_window_cocoa.h" #include "base/sys_string_conversions.h" -#include "chrome/browser/extensions/extension_host.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/cocoa/browser_window_utils.h" #include "chrome/browser/ui/cocoa/extensions/extension_view_mac.h" #include "chrome/common/extensions/extension.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_view.h" #import "ui/base/cocoa/underlay_opengl_hosting_window.h" @implementation ShellWindowController @@ -22,8 +24,10 @@ @end -ShellWindowCocoa::ShellWindowCocoa(ExtensionHost* host) - : ShellWindow(host), +ShellWindowCocoa::ShellWindowCocoa(Profile* profile, + const Extension* extension, + const GURL& url) + : ShellWindow(profile, extension, url), attention_request_id_(0) { NSRect rect = NSMakeRect(0, 0, kDefaultWidth, kDefaultHeight); NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask | @@ -33,9 +37,9 @@ ShellWindowCocoa::ShellWindowCocoa(ExtensionHost* host) styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]); - [window setTitle:base::SysUTF8ToNSString(host->extension()->name())]; + [window setTitle:base::SysUTF8ToNSString(extension->name())]; - NSView* view = host->view()->native_view(); + NSView* view = web_contents()->GetView()->GetNativeView(); [view setFrame:rect]; [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; [[window contentView] addSubview:view]; @@ -165,6 +169,8 @@ NSWindow* ShellWindowCocoa::window() const { } // static -ShellWindow* ShellWindow::CreateShellWindow(ExtensionHost* host) { - return new ShellWindowCocoa(host); +ShellWindow* ShellWindow::CreateImpl(Profile* profile, + const Extension* extension, + const GURL& url) { + return new ShellWindowCocoa(profile, extension, url); } diff --git a/chrome/browser/ui/extensions/shell_window.cc b/chrome/browser/ui/extensions/shell_window.cc index f624f95..0371ab7 100644 --- a/chrome/browser/ui/extensions/shell_window.cc +++ b/chrome/browser/ui/extensions/shell_window.cc @@ -8,14 +8,24 @@ #include "chrome/browser/extensions/extension_process_manager.h" #include "chrome/browser/extensions/extension_tabs_module_constants.h" #include "chrome/browser/extensions/extension_window_controller.h" +#include "chrome/browser/extensions/shell_window_registry.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/session_id.h" #include "chrome/common/chrome_notification_types.h" +#include "chrome/common/chrome_view_type.h" #include "chrome/common/extensions/extension.h" +#include "chrome/common/extensions/extension_messages.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/notification_types.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/site_instance.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/renderer_preferences.h" + +using content::SiteInstance; +using content::WebContents; namespace internal { @@ -26,7 +36,6 @@ class ShellWindowController : public ExtensionWindowController { // Overriden from ExtensionWindowController virtual int GetWindowId() const OVERRIDE; virtual std::string GetWindowTypeText() const OVERRIDE; - virtual base::DictionaryValue* CreateWindowValue() const OVERRIDE; virtual base::DictionaryValue* CreateWindowValueWithTabs() const OVERRIDE; virtual bool CanClose(Reason* reason) const OVERRIDE; virtual void SetFullscreenMode(bool is_fullscreen, @@ -49,15 +58,8 @@ int ShellWindowController::GetWindowId() const { return static_cast<int>(shell_window_->session_id().id()); } -namespace keys = extension_tabs_module_constants; - std::string ShellWindowController::GetWindowTypeText() const { - return keys::kWindowTypeValueShell; -} - -base::DictionaryValue* ShellWindowController::CreateWindowValue() const { - DictionaryValue* result = ExtensionWindowController::CreateWindowValue(); - return result; + return extension_tabs_module_constants::kWindowTypeValueShell; } base::DictionaryValue* ShellWindowController::CreateWindowValueWithTabs() @@ -79,48 +81,32 @@ void ShellWindowController::SetFullscreenMode(bool is_fullscreen, ShellWindow* ShellWindow::Create(Profile* profile, const Extension* extension, const GURL& url) { - ExtensionProcessManager* manager = profile->GetExtensionProcessManager(); - DCHECK(manager); - // This object will delete itself when the window is closed. - return ShellWindow::CreateShellWindow( - manager->CreateShellHost(extension, url)); -} - -void ShellWindow::Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - switch (type) { - case chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE: - if (content::Details<ExtensionHost>(host_.get()) == details) - Close(); - break; - case chrome::NOTIFICATION_EXTENSION_UNLOADED: { - const Extension* unloaded_extension = - content::Details<UnloadedExtensionInfo>(details)->extension; - // We compare extension IDs and not Extension pointers since ExtensionHost - // nulls out its Extension pointer when it gets this notification. - if (host_->extension_id() == unloaded_extension->id()) - Close(); - break; - } - case content::NOTIFICATION_APP_TERMINATING: - Close(); - break; - default: - NOTREACHED() << "Received unexpected notification"; - } + return ShellWindow::CreateImpl(profile, extension, url); } -ShellWindow::ShellWindow(ExtensionHost* host) - : host_(host) { - // Close the window in response to window.close() and the like. - registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, - content::Source<Profile>(host->profile())); - // Also close if the window if the extension has been unloaded (parallels - // NOTIFICATION_EXTENSION_UNLOADED closing the app's tabs in TabStripModel). +ShellWindow::ShellWindow(Profile* profile, + const Extension* extension, + const GURL& url) + : profile_(profile), + extension_(extension), + ALLOW_THIS_IN_INITIALIZER_LIST( + extension_function_dispatcher_(profile, this)) { + web_contents_.reset(WebContents::Create( + profile, SiteInstance::CreateForURL(profile, url), MSG_ROUTING_NONE, NULL, + NULL)); + content::WebContentsObserver::Observe(web_contents_.get()); + web_contents_->SetDelegate(this); + web_contents_->SetViewType(chrome::VIEW_TYPE_APP_SHELL); + web_contents_->GetMutableRendererPrefs()->browser_handles_all_requests = + true; + web_contents_->GetRenderViewHost()->SyncRendererPrefs(); + + web_contents_->GetController().LoadURL( + url, content::Referrer(), content::PAGE_TRANSITION_LINK, + std::string()); registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, - content::Source<Profile>(host->profile())); + content::Source<Profile>(profile_)); // Close when the browser is exiting. // TODO(mihaip): we probably don't want this in the long run (when platform // apps are no longer tied to the browser process). @@ -132,7 +118,9 @@ ShellWindow::ShellWindow(ExtensionHost* host) // Make this window available to the extension API. extension_window_controller_.reset( - new internal::ShellWindowController(this, host->profile())); + new internal::ShellWindowController(this, profile_)); + + ShellWindowRegistry::Get(profile_)->AddShellWindow(this); } ShellWindow::~ShellWindow() { @@ -140,6 +128,56 @@ ShellWindow::~ShellWindow() { // last window open. registrar_.RemoveAll(); + ShellWindowRegistry::Get(profile_)->RemoveShellWindow(this); + // Remove shutdown prevention. BrowserList::EndKeepAlive(); } + +bool ShellWindow::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(ShellWindow, message) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void ShellWindow::CloseContents(WebContents* contents) { + Close(); +} + +// TODO(benwells): Rearrange so users of this can call +// WebContents::set_should_suppress_dialogs(bool) instead of overriding +// this delegate function. +bool ShellWindow::ShouldSuppressDialogs() { + return true; +} + +void ShellWindow::Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + switch (type) { + case chrome::NOTIFICATION_EXTENSION_UNLOADED: { + const Extension* unloaded_extension = + content::Details<UnloadedExtensionInfo>(details)->extension; + if (extension_ == unloaded_extension) + Close(); + break; + } + case content::NOTIFICATION_APP_TERMINATING: + Close(); + break; + default: + NOTREACHED() << "Received unexpected notification"; + } +} + +ExtensionWindowController* ShellWindow::GetExtensionWindowController() const { + return extension_window_controller_.get(); +} + +void ShellWindow::OnRequest(const ExtensionHostMsg_Request_Params& params) { + extension_function_dispatcher_.Dispatch(params, + web_contents_->GetRenderViewHost()); +} diff --git a/chrome/browser/ui/extensions/shell_window.h b/chrome/browser/ui/extensions/shell_window.h index 2790b74..dec4dd8 100644 --- a/chrome/browser/ui/extensions/shell_window.h +++ b/chrome/browser/ui/extensions/shell_window.h @@ -7,14 +7,15 @@ #pragma once #include "base/memory/scoped_ptr.h" +#include "chrome/browser/extensions/extension_function_dispatcher.h" #include "chrome/browser/sessions/session_id.h" -#include "chrome/browser/extensions/extension_host.h" #include "chrome/browser/ui/base_window.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#include "content/public/browser/web_contents_delegate.h" +#include "content/public/browser/web_contents_observer.h" class Extension; -class ExtensionHost; class ExtensionWindowController; class GURL; class Profile; @@ -23,43 +24,74 @@ namespace content { class WebContents; } +// ShellWindow is the type of window used by platform apps. Shell windows +// have a WebContents but none of the chrome of normal browser windows. class ShellWindow : public content::NotificationObserver, + public content::WebContentsDelegate, + public content::WebContentsObserver, + public ExtensionFunctionDispatcher::Delegate, public BaseWindow { public: - // TODO(mihaip): Switch from hardcoded defaults to passing in the window - // creation parameters to ShellWindow::Create. - static const int kDefaultWidth = 512; - static const int kDefaultHeight = 384; + static ShellWindow* Create(Profile* profile, + const Extension* extension, + const GURL& url); - content::WebContents* web_contents() const { return host_->host_contents(); } const SessionID& session_id() const { return session_id_; } const ExtensionWindowController* extension_window_controller() const { return extension_window_controller_.get(); } - static ShellWindow* Create(Profile* profile, - const Extension* extension, - const GURL& url); + protected: + // TODO(mihaip): Switch from hardcoded defaults to passing in the window + // creation parameters to ShellWindow::Create. + static const int kDefaultWidth = 512; + static const int kDefaultHeight = 384; + + ShellWindow(Profile* profile, + const Extension* extension, + const GURL& url); + virtual ~ShellWindow(); + + const Extension* extension() const { return extension_; } + content::WebContents* web_contents() const { return web_contents_.get(); } + + private: + // PlatformAppBrowserTest needs access to web_contents() + friend class PlatformAppBrowserTest; + + // Instantiates a platform-specific ShellWindow subclass (one implementation + // per platform). Public users of ShellWindow should use ShellWindow::Create. + static ShellWindow* CreateImpl(Profile* profile, + const Extension* extension, + const GURL& url); + + // content::WebContentsObserver + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + // content::WebContentsDelegate + virtual void CloseContents(content::WebContents* contents) OVERRIDE; + virtual bool ShouldSuppressDialogs() OVERRIDE; // content::NotificationObserver implementation. virtual void Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; - protected: - explicit ShellWindow(ExtensionHost* host_); - virtual ~ShellWindow(); + virtual ExtensionWindowController* GetExtensionWindowController() const + OVERRIDE; - // Instantiates a platform-specific ShellWindow subclass (one implementation - // per platform). Public users of ShellWindow should use ShellWindow::Create. - static ShellWindow* CreateShellWindow(ExtensionHost* host); + // Message handlers. + void OnRequest(const ExtensionHostMsg_Request_Params& params); + + Profile* profile_; // weak pointer - owned by ProfileManager. + const Extension* extension_; // weak pointer - owned by ExtensionService. const SessionID session_id_; - scoped_ptr<ExtensionHost> host_; + scoped_ptr<content::WebContents> web_contents_; content::NotificationRegistrar registrar_; scoped_ptr<ExtensionWindowController> extension_window_controller_; + ExtensionFunctionDispatcher extension_function_dispatcher_; - private: DISALLOW_COPY_AND_ASSIGN(ShellWindow); }; diff --git a/chrome/browser/ui/gtk/extensions/shell_window_gtk.cc b/chrome/browser/ui/gtk/extensions/shell_window_gtk.cc index 0dce063..04aaf78 100644 --- a/chrome/browser/ui/gtk/extensions/shell_window_gtk.cc +++ b/chrome/browser/ui/gtk/extensions/shell_window_gtk.cc @@ -4,25 +4,28 @@ #include "chrome/browser/ui/gtk/extensions/shell_window_gtk.h" -#include "chrome/browser/extensions/extension_host.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/extension.h" #include "content/public/browser/render_widget_host_view.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_view.h" #include "ui/base/x/active_window_watcher_x.h" #include "ui/gfx/rect.h" -ShellWindowGtk::ShellWindowGtk(ExtensionHost* host) - : ShellWindow(host), +ShellWindowGtk::ShellWindowGtk(Profile* profile, + const Extension* extension, + const GURL& url) + : ShellWindow(profile, extension, url), state_(GDK_WINDOW_STATE_WITHDRAWN), is_active_(!ui::ActiveWindowWatcherX::WMSupportsActivation()) { - host_->view()->SetContainer(this); window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); - gtk_container_add(GTK_CONTAINER(window_), host_->view()->native_view()); + gfx::NativeView native_view = + web_contents()->GetView()->GetNativeView(); + gtk_container_add(GTK_CONTAINER(window_), native_view); gtk_window_set_default_size(window_, kDefaultWidth, kDefaultHeight); - const Extension* extension = host_->extension(); - // TODO(mihaip): Mirror contents of <title> tag in window title gtk_window_set_title(window_, extension->name().c_str()); @@ -164,6 +167,8 @@ gboolean ShellWindowGtk::OnWindowState(GtkWidget* sender, } // static -ShellWindow* ShellWindow::CreateShellWindow(ExtensionHost* host) { - return new ShellWindowGtk(host); +ShellWindow* ShellWindow::CreateImpl(Profile* profile, + const Extension* extension, + const GURL& url) { + return new ShellWindowGtk(profile, extension, url); } diff --git a/chrome/browser/ui/gtk/extensions/shell_window_gtk.h b/chrome/browser/ui/gtk/extensions/shell_window_gtk.h index 3745548..1e14c89 100644 --- a/chrome/browser/ui/gtk/extensions/shell_window_gtk.h +++ b/chrome/browser/ui/gtk/extensions/shell_window_gtk.h @@ -14,13 +14,15 @@ #include "ui/base/x/active_window_watcher_x_observer.h" #include "ui/gfx/rect.h" -class ExtensionHost; +class Profile; class ShellWindowGtk : public ShellWindow, public ExtensionViewGtk::Container, public ui::ActiveWindowWatcherXObserver { public: - explicit ShellWindowGtk(ExtensionHost* host); + ShellWindowGtk(Profile* profile, + const Extension* extension, + const GURL& url); // BaseWindow implementation. virtual bool IsActive() const OVERRIDE; diff --git a/chrome/browser/ui/views/extensions/shell_window_views.cc b/chrome/browser/ui/views/extensions/shell_window_views.cc index ef37058..fd39285 100644 --- a/chrome/browser/ui/views/extensions/shell_window_views.cc +++ b/chrome/browser/ui/views/extensions/shell_window_views.cc @@ -7,6 +7,10 @@ #include "base/utf_string_conversions.h" #include "chrome/browser/extensions/extension_host.h" #include "chrome/common/extensions/extension.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_widget_host_view.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_view.h" #include "ui/base/hit_test.h" #include "ui/gfx/path.h" #include "ui/gfx/scoped_sk_region.h" @@ -17,8 +21,6 @@ #if defined(OS_WIN) && !defined(USE_AURA) #include "chrome/browser/shell_integration.h" #include "chrome/browser/web_applications/web_app.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/render_widget_host_view.h" #include "ui/base/win/shell.h" #endif @@ -96,9 +98,11 @@ void ShellWindowFrameView::GetWindowMask(const gfx::Size& size, // Don't touch it. } -ShellWindowViews::ShellWindowViews(ExtensionHost* host) - : ShellWindow(host) { - host_->view()->SetContainer(this); +ShellWindowViews::ShellWindowViews(Profile* profile, + const Extension* extension, + const GURL& url) + : ShellWindow(profile, extension, url), + initialized_(false) { window_ = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.delegate = this; @@ -108,13 +112,12 @@ ShellWindowViews::ShellWindowViews(ExtensionHost* host) window_->Init(params); #if defined(OS_WIN) && !defined(USE_AURA) std::string app_name = web_app::GenerateApplicationNameFromExtensionId( - host_->extension()->id()); + extension->id()); ui::win::SetAppIdForWindow( ShellIntegration::GetAppId(UTF8ToWide(app_name), - host_->profile()->GetPath()), + profile->GetPath()), GetWidget()->GetTopLevelWidget()->GetNativeWindow()); #endif - AddChildView(host_->view()); SetLayoutManager(new views::FillLayout); Layout(); @@ -122,6 +125,8 @@ ShellWindowViews::ShellWindowViews(ExtensionHost* host) } ShellWindowViews::~ShellWindowViews() { + if (initialized_) + NativeViewHost::Detach(); } bool ShellWindowViews::IsActive() const { @@ -234,7 +239,7 @@ views::NonClientFrameView* ShellWindowViews::CreateNonClientFrameView( } string16 ShellWindowViews::GetWindowTitle() const { - return UTF8ToUTF16(host_->extension()->name()); + return UTF8ToUTF16(extension()->name()); } views::Widget* ShellWindowViews::GetWidget() { @@ -249,7 +254,7 @@ void ShellWindowViews::OnViewWasResized() { // TODO(jeremya): this doesn't seem like a terribly elegant way to keep the // window shape in sync. #if defined(OS_WIN) && !defined(USE_AURA) - gfx::Size sz = host_->view()->size(); + gfx::Size sz = size(); int height = sz.height(), width = sz.width(); int radius = 1; gfx::Path path; @@ -267,7 +272,7 @@ void ShellWindowViews::OnViewWasResized() { path.lineTo(0, height - radius - 1); path.close(); } - SetWindowRgn(host_->view()->native_view(), path.CreateNativeRegion(), 1); + SetWindowRgn(native_view(), path.CreateNativeRegion(), 1); SkRegion* rgn = new SkRegion; if (caption_region_.Get()) @@ -278,11 +283,67 @@ void ShellWindowViews::OnViewWasResized() { rgn->op(width - kResizeBorderWidth, 0, width, height, SkRegion::kUnion_Op); rgn->op(0, height - kResizeBorderWidth, width, height, SkRegion::kUnion_Op); } - host_->render_view_host()->GetView()->SetClickthroughRegion(rgn); + web_contents()->GetRenderViewHost()->GetView()->SetClickthroughRegion(rgn); #endif } +gfx::NativeCursor ShellWindowViews::GetCursor(const views::MouseEvent& event) { + return gfx::kNullCursor; +} + +void ShellWindowViews::SetVisible(bool is_visible) { + if (is_visible != visible()) { + NativeViewHost::SetVisible(is_visible); + + // Also tell RenderWidgetHostView the new visibility. Despite its name, it + // is not part of the View hierarchy and does not know about the change + // unless we tell it. + content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); + if (rvh->GetView()) { + if (is_visible) + rvh->GetView()->Show(); + else + rvh->GetView()->Hide(); + } + } +} + +void ShellWindowViews::ViewHierarchyChanged(bool is_add, + views::View *parent, + views::View *child) { + NativeViewHost::ViewHierarchyChanged(is_add, parent, child); + if (is_add && GetWidget() && !initialized_) { + initialized_ = true; + NativeViewHost::Attach(web_contents()->GetView()->GetNativeView()); + } +} + +void ShellWindowViews::PreferredSizeChanged() { + View::PreferredSizeChanged(); +} + +bool ShellWindowViews::SkipDefaultKeyEventProcessing(const views::KeyEvent& e) { + // Let the tab key event be processed by the renderer (instead of moving the + // focus to the next focusable view). Also handle Backspace, since otherwise + // (on Windows at least), pressing Backspace, when focus is on a text field + // within the ExtensionView, will navigate the page back instead of erasing a + // character. + return (e.key_code() == ui::VKEY_TAB || e.key_code() == ui::VKEY_BACK); +} + +void ShellWindowViews::OnBoundsChanged(const gfx::Rect& previous_bounds) { + // Propagate the new size to RenderWidgetHostView. + // We can't send size zero because RenderWidget DCHECKs that. + content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); + if (rvh->GetView() && !bounds().IsEmpty()) { + rvh->GetView()->SetSize(size()); + OnViewWasResized(); + } +} + // static -ShellWindow* ShellWindow::CreateShellWindow(ExtensionHost* host) { - return new ShellWindowViews(host); +ShellWindow* ShellWindow::CreateImpl(Profile* profile, + const Extension* extension, + const GURL& url) { + return new ShellWindowViews(profile, extension, url); } diff --git a/chrome/browser/ui/views/extensions/shell_window_views.h b/chrome/browser/ui/views/extensions/shell_window_views.h index ba4b776..063c9e8 100644 --- a/chrome/browser/ui/views/extensions/shell_window_views.h +++ b/chrome/browser/ui/views/extensions/shell_window_views.h @@ -7,18 +7,20 @@ #pragma once #include "chrome/browser/ui/extensions/shell_window.h" -#include "chrome/browser/ui/views/extensions/extension_view.h" #include "ui/gfx/rect.h" #include "ui/gfx/scoped_sk_region.h" +#include "ui/views/controls/native/native_view_host.h" #include "ui/views/widget/widget_delegate.h" -class ExtensionHost; +class Profile; class ShellWindowViews : public ShellWindow, - public ExtensionView::Container, - public views::WidgetDelegateView { + public views::NativeViewHost, + public views::WidgetDelegate { public: - explicit ShellWindowViews(ExtensionHost* host); + ShellWindowViews(Profile* profile, + const Extension* extension, + const GURL& url); // BaseWindow implementation. virtual bool IsActive() const OVERRIDE; @@ -51,12 +53,24 @@ class ShellWindowViews : public ShellWindow, virtual string16 GetWindowTitle() const OVERRIDE; virtual void DeleteDelegate() OVERRIDE; - // ExtensionView::Container implementation. - virtual void OnViewWasResized() OVERRIDE; + // Overridden from views::NativeViewHost: + virtual gfx::NativeCursor GetCursor(const views::MouseEvent& event) OVERRIDE; + virtual void SetVisible(bool is_visible) OVERRIDE; + virtual void ViewHierarchyChanged( + bool is_add, views::View *parent, views::View *child) OVERRIDE; + + protected: + // Overridden from views::View. + virtual void PreferredSizeChanged() OVERRIDE; + virtual bool SkipDefaultKeyEventProcessing(const views::KeyEvent& e) OVERRIDE; + virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE; private: virtual ~ShellWindowViews(); + void OnViewWasResized(); + + bool initialized_; views::Widget* window_; gfx::ScopedSkRegion caption_region_; diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index bece4a8..b715547 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi @@ -415,6 +415,8 @@ 'browser/extensions/settings/testing_settings_storage.h', 'browser/extensions/settings/weak_unlimited_settings_storage.cc', 'browser/extensions/settings/weak_unlimited_settings_storage.h', + 'browser/extensions/shell_window_registry.cc', + 'browser/extensions/shell_window_registry.h', 'browser/extensions/theme_installed_infobar_delegate.cc', 'browser/extensions/theme_installed_infobar_delegate.h', 'browser/extensions/unpacked_installer.cc', diff --git a/chrome/common/chrome_notification_types.h b/chrome/common/chrome_notification_types.h index 50b3200..d31bd5b 100644 --- a/chrome/common/chrome_notification_types.h +++ b/chrome/common/chrome_notification_types.h @@ -529,6 +529,14 @@ enum NotificationType { // ExtensionAction* that changed. The details are a WebContents*. NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED, + // A new extension RenderViewHost has been registered. The details are + // the RenderViewHost*. + NOTIFICATION_EXTENSION_VIEW_REGISTERED, + + // An extension RenderViewHost has been unregistered. The details are + // the RenderViewHost*. + NOTIFICATION_EXTENSION_VIEW_UNREGISTERED, + // Sent by an extension to notify the browser about the results of a unit // test. NOTIFICATION_EXTENSION_TEST_PASSED, |