summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
authorstevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-14 22:38:26 +0000
committerstevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-14 22:38:26 +0000
commit92b34f71dff1fdd493194acde42a225aecf4cc2f (patch)
treed9b6ccf88c35f6a1867e5233c13aa603e46e4c29 /chrome
parent8eb93ed662dcbc6c4414b9524099b80760831d48 (diff)
downloadchromium_src-92b34f71dff1fdd493194acde42a225aecf4cc2f.zip
chromium_src-92b34f71dff1fdd493194acde42a225aecf4cc2f.tar.gz
chromium_src-92b34f71dff1fdd493194acde42a225aecf4cc2f.tar.bz2
Add ShellWindowContents and AppWindow/Panel implementations.
This CL: * Adds ShellWindowRenderInterface to abstract creating and observing web contents and passing messages to the extensions system * Moves related ShellWindow to AppWindowRenderInterface * Adds AshPanelRenderInterface for v1 ash panel specific impl * Hooks up chrome.windows.create(type = panel) to use Ash Panels. BUG=160645 Review URL: https://codereview.chromium.org/12209028 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182559 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/extensions/api/tabs/ash_panel_contents.cc221
-rw-r--r--chrome/browser/extensions/api/tabs/ash_panel_contents.h66
-rw-r--r--chrome/browser/extensions/api/tabs/tabs_api.cc41
-rw-r--r--chrome/browser/extensions/app_window_contents.cc172
-rw-r--r--chrome/browser/extensions/app_window_contents.h73
-rw-r--r--chrome/browser/extensions/browser_extension_window_controller.cc9
-rw-r--r--chrome/browser/extensions/browser_extension_window_controller.h2
-rw-r--r--chrome/browser/extensions/extension_tab_util.cc35
-rw-r--r--chrome/browser/extensions/window_controller.h3
-rw-r--r--chrome/browser/extensions/window_controller_list.cc15
-rw-r--r--chrome/browser/extensions/window_controller_list.h3
-rw-r--r--chrome/browser/extensions/window_open_apitest.cc106
-rw-r--r--chrome/browser/ui/extensions/shell_window.cc166
-rw-r--r--chrome/browser/ui/extensions/shell_window.h76
-rw-r--r--chrome/browser/ui/panels/panel.cc61
-rw-r--r--chrome/browser/ui/views/extensions/native_app_window_views.h1
-rw-r--r--chrome/chrome_browser_extensions.gypi8
17 files changed, 808 insertions, 250 deletions
diff --git a/chrome/browser/extensions/api/tabs/ash_panel_contents.cc b/chrome/browser/extensions/api/tabs/ash_panel_contents.cc
new file mode 100644
index 0000000..cb21550
--- /dev/null
+++ b/chrome/browser/extensions/api/tabs/ash_panel_contents.cc
@@ -0,0 +1,221 @@
+// Copyright 2013 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/api/tabs/ash_panel_contents.h"
+
+#include "base/values.h"
+#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
+#include "chrome/browser/extensions/api/tabs/tabs_windows_api.h"
+#include "chrome/browser/extensions/api/tabs/windows_event_router.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/extensions/window_controller_list.h"
+#include "chrome/browser/ui/extensions/native_app_window.h"
+#include "chrome/browser/ui/extensions/shell_window.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_messages.h"
+#include "content/public/browser/site_instance.h"
+#include "content/public/browser/web_contents.h"
+
+// AshPanelWindowController ----------------------------------------------------
+
+// This class enables a ShellWindow instance to be accessed (to a limited
+// extent) via the chrome.windows and chrome.tabs API. This is a temporary
+// bridge to support instantiating ShellWindows from v1 apps, specifically
+// for creating Panels in Ash. See crbug.com/160645.
+class AshPanelWindowController : public extensions::WindowController {
+ public:
+ AshPanelWindowController(ShellWindow* window, Profile* profile);
+ virtual ~AshPanelWindowController();
+
+ void NativeWindowChanged();
+
+ // Overridden from extensions::WindowController.
+ virtual int GetWindowId() const OVERRIDE;
+ virtual std::string GetWindowTypeText() const OVERRIDE;
+ virtual base::DictionaryValue* CreateWindowValueWithTabs(
+ const extensions::Extension* extension) const OVERRIDE;
+ virtual base::DictionaryValue* CreateTabValue(
+ const extensions::Extension* extension, int tab_index) const OVERRIDE;
+ virtual bool CanClose(Reason* reason) const OVERRIDE;
+ virtual void SetFullscreenMode(bool is_fullscreen,
+ const GURL& extension_url) const OVERRIDE;
+ virtual bool IsVisibleToExtension(
+ const extensions::Extension* extension) const OVERRIDE;
+
+ private:
+ ShellWindow* shell_window_; // Weak pointer; this is owned by shell_window_
+ bool is_active_;
+
+ DISALLOW_COPY_AND_ASSIGN(AshPanelWindowController);
+};
+
+AshPanelWindowController::AshPanelWindowController(
+ ShellWindow* shell_window, Profile* profile)
+ : extensions::WindowController(shell_window->GetBaseWindow(), profile),
+ shell_window_(shell_window),
+ is_active_(shell_window->GetBaseWindow()->IsActive()) {
+ extensions::WindowControllerList::GetInstance()->AddExtensionWindow(this);
+}
+
+AshPanelWindowController::~AshPanelWindowController() {
+ extensions::WindowControllerList::GetInstance()->RemoveExtensionWindow(this);
+}
+
+int AshPanelWindowController::GetWindowId() const {
+ return static_cast<int>(shell_window_->session_id().id());
+}
+
+std::string AshPanelWindowController::GetWindowTypeText() const {
+ return extensions::tabs_constants::kWindowTypeValuePanel;
+}
+
+base::DictionaryValue* AshPanelWindowController::CreateWindowValueWithTabs(
+ const extensions::Extension* extension) const {
+ DCHECK(IsVisibleToExtension(extension));
+ base::DictionaryValue* result = CreateWindowValue();
+ DictionaryValue* tab_value = CreateTabValue(extension, 0);
+ if (tab_value) {
+ base::ListValue* tab_list = new ListValue();
+ tab_list->Append(tab_value);
+ result->Set(extensions::tabs_constants::kTabsKey, tab_list);
+ }
+ return result;
+}
+
+base::DictionaryValue* AshPanelWindowController::CreateTabValue(
+ const extensions::Extension* extension, int tab_index) const {
+ if ((extension && !IsVisibleToExtension(extension)) ||
+ (tab_index > 0)) {
+ return NULL;
+ }
+ content::WebContents* web_contents = shell_window_->web_contents();
+ if (!web_contents)
+ return NULL;
+
+ DictionaryValue* tab_value = new DictionaryValue();
+ tab_value->SetInteger(extensions::tabs_constants::kIdKey,
+ SessionID::IdForTab(web_contents));
+ tab_value->SetInteger(extensions::tabs_constants::kIndexKey, 0);
+ const int window_id = GetWindowId();
+ tab_value->SetInteger(extensions::tabs_constants::kWindowIdKey, window_id);
+ tab_value->SetString(
+ extensions::tabs_constants::kUrlKey, web_contents->GetURL().spec());
+ tab_value->SetString(
+ extensions::tabs_constants::kStatusKey,
+ ExtensionTabUtil::GetTabStatusText(web_contents->IsLoading()));
+ tab_value->SetBoolean(
+ extensions::tabs_constants::kActiveKey,
+ shell_window_->GetBaseWindow()->IsActive());
+ // ShellWindow only ever contains one tab, so that tab is always effectively
+ // selcted and highlighted (for purposes of the chrome.tabs API).
+ tab_value->SetInteger(extensions::tabs_constants::kWindowIdKey, window_id);
+ tab_value->SetInteger(extensions::tabs_constants::kIdKey, window_id);
+ tab_value->SetBoolean(extensions::tabs_constants::kSelectedKey, true);
+ tab_value->SetBoolean(extensions::tabs_constants::kHighlightedKey, true);
+ tab_value->SetBoolean(extensions::tabs_constants::kPinnedKey, false);
+ tab_value->SetString(
+ extensions::tabs_constants::kTitleKey, web_contents->GetTitle());
+ tab_value->SetBoolean(
+ extensions::tabs_constants::kIncognitoKey,
+ web_contents->GetBrowserContext()->IsOffTheRecord());
+ return tab_value;
+}
+
+bool AshPanelWindowController::CanClose(Reason* reason) const {
+ return true;
+}
+
+void AshPanelWindowController::SetFullscreenMode(
+ bool is_fullscreen, const GURL& extension_url) const {
+ // Do nothing. Panels cannot be fullscreen.
+}
+
+bool AshPanelWindowController::IsVisibleToExtension(
+ const extensions::Extension* extension) const {
+ return shell_window_->extension() &&
+ extension->id() == shell_window_->extension()->id();
+}
+
+void AshPanelWindowController::NativeWindowChanged() {
+ bool active = shell_window_->GetBaseWindow()->IsActive();
+ if (active == is_active_)
+ return;
+ is_active_ = active;
+ // Let the extension API know that the active window changed.
+ extensions::TabsWindowsAPI* tabs_windows_api =
+ extensions::TabsWindowsAPI::Get(profile());
+ if (!tabs_windows_api)
+ return;
+ tabs_windows_api->windows_event_router()->OnActiveWindowChanged(
+ active ? this : NULL);
+}
+
+// AshPanelContents -----------------------------------------------------
+
+AshPanelContents::AshPanelContents(ShellWindow* host)
+ : host_(host) {
+}
+
+AshPanelContents::~AshPanelContents() {
+}
+
+void AshPanelContents::Initialize(Profile* profile, const GURL& url) {
+ url_ = url;
+
+ extension_function_dispatcher_.reset(
+ new ExtensionFunctionDispatcher(profile, this));
+
+ web_contents_.reset(content::WebContents::Create(
+ content::WebContents::CreateParams(
+ profile, content::SiteInstance::CreateForURL(profile, url_))));
+
+ content::WebContentsObserver::Observe(web_contents_.get());
+}
+
+void AshPanelContents::LoadContents(int32 creator_process_id) {
+ // This must be created after the native window has been created.
+ window_controller_.reset(
+ new AshPanelWindowController(host_, host_->profile()));
+
+ web_contents_->GetController().LoadURL(
+ url_, content::Referrer(), content::PAGE_TRANSITION_LINK,
+ std::string());
+}
+
+void AshPanelContents::NativeWindowChanged(NativeAppWindow* native_app_window) {
+ if (window_controller_)
+ window_controller_->NativeWindowChanged();
+}
+
+void AshPanelContents::NativeWindowClosed() {
+}
+
+content::WebContents* AshPanelContents::GetWebContents() const {
+ return web_contents_.get();
+}
+
+bool AshPanelContents::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(AshPanelContents, message)
+ IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+extensions::WindowController*
+AshPanelContents::GetExtensionWindowController() const {
+ return window_controller_.get();
+}
+
+content::WebContents* AshPanelContents::GetAssociatedWebContents() const {
+ return web_contents_.get();
+}
+
+void AshPanelContents::OnRequest(
+ const ExtensionHostMsg_Request_Params& params) {
+ extension_function_dispatcher_->Dispatch(
+ params, web_contents_->GetRenderViewHost());
+}
diff --git a/chrome/browser/extensions/api/tabs/ash_panel_contents.h b/chrome/browser/extensions/api/tabs/ash_panel_contents.h
new file mode 100644
index 0000000..871139b
--- /dev/null
+++ b/chrome/browser/extensions/api/tabs/ash_panel_contents.h
@@ -0,0 +1,66 @@
+// Copyright 2013 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_API_TABS_ASH_PANEL_CONTENTS_H_
+#define CHROME_BROWSER_EXTENSIONS_API_TABS_ASH_PANEL_CONTENTS_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/extensions/extension_function_dispatcher.h"
+#include "chrome/browser/ui/extensions/shell_window.h"
+#include "content/public/browser/web_contents_observer.h"
+
+class AshPanelWindowController;
+class GURL;
+
+namespace content {
+class RenderViewHost;
+}
+
+namespace extensions {
+struct DraggableRegion;
+}
+
+// ShellWindowContents class specific to panel windows created by v1
+// extenstions. This class maintains a WebContents instance and observes it for
+// the purpose of passing messages to the extensions system. It also creates
+// an extensions::WindowController instance for interfacing with the v1
+// extensions API.
+class AshPanelContents : public ShellWindowContents,
+ public content::WebContentsObserver,
+ public ExtensionFunctionDispatcher::Delegate {
+ public:
+ explicit AshPanelContents(ShellWindow* host);
+ virtual ~AshPanelContents();
+
+ // ShellWindowContents
+ virtual void Initialize(Profile* profile, const GURL& url) OVERRIDE;
+ virtual void LoadContents(int32 creator_process_id) OVERRIDE;
+ virtual void NativeWindowChanged(NativeAppWindow* native_app_window) OVERRIDE;
+ virtual void NativeWindowClosed() OVERRIDE;
+ virtual content::WebContents* GetWebContents() const OVERRIDE;
+
+ // ExtensionFunctionDispatcher::Delegate
+ virtual extensions::WindowController* GetExtensionWindowController() const
+ OVERRIDE;
+ virtual content::WebContents* GetAssociatedWebContents() const OVERRIDE;
+
+ private:
+ // content::WebContentsObserver
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ void OnRequest(const ExtensionHostMsg_Request_Params& params);
+
+ ShellWindow* host_;
+ GURL url_;
+ scoped_ptr<content::WebContents> web_contents_;
+ scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
+ scoped_ptr<AshPanelWindowController> window_controller_;
+
+ DISALLOW_COPY_AND_ASSIGN(AshPanelContents);
+};
+
+#endif // CHROME_BROWSER_EXTENSIONS_API_TABS_ASH_PANEL_CONTENTS_H_
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc
index b227e6d..44e732f 100644
--- a/chrome/browser/extensions/api/tabs/tabs_api.cc
+++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -88,6 +88,12 @@
#include "win8/util/win8_util.h"
#endif // OS_WIN
+#if defined(USE_ASH)
+#include "ash/ash_switches.h"
+#include "chrome/browser/extensions/api/tabs/ash_panel_contents.h"
+#include "chrome/browser/extensions/shell_window_registry.h"
+#endif
+
namespace Get = extensions::api::windows::Get;
namespace GetAll = extensions::api::windows::GetAll;
namespace GetCurrent = extensions::api::windows::GetCurrent;
@@ -516,8 +522,8 @@ bool WindowsCreateFunction::RunImpl() {
#endif
if (use_panels) {
window_type = Browser::TYPE_PANEL;
-#if !defined(OS_CHROMEOS)
- // Non-ChromeOS has both docked and detached panel types.
+#if !defined(USE_ASH)
+ // Non-Ash has both docked and detached panel types.
if (type_str == keys::kWindowTypeValueDetachedPanel)
panel_create_mode = PanelManager::CREATE_AS_DETACHED;
#endif
@@ -531,15 +537,8 @@ bool WindowsCreateFunction::RunImpl() {
}
// Initialize default window bounds according to window type.
- // In ChromiumOS the default popup bounds is 0x0 which indicates default
- // window sizes in PanelBrowserView. In other OSs use the same default
- // bounds as windows.
-#if !defined(OS_CHROMEOS)
if (Browser::TYPE_TABBED == window_type ||
Browser::TYPE_POPUP == window_type) {
-#else
- if (Browser::TYPE_TABBED == window_type) {
-#endif
// Try to position the new browser relative to its originating
// browser window. The call offsets the bounds by kWindowTilePixels
// (defined in WindowSizer to be 10).
@@ -594,8 +593,28 @@ bool WindowsCreateFunction::RunImpl() {
}
}
-#if !defined(OS_CHROMEOS)
if (window_type == Browser::TYPE_PANEL) {
+#if defined(USE_ASH)
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels) &&
+ PanelManager::ShouldUsePanels(extension_id)) {
+ ShellWindow::CreateParams create_params;
+ create_params.window_type = ShellWindow::WINDOW_TYPE_PANEL;
+ create_params.bounds = window_bounds;
+ create_params.minimum_size = window_bounds.size();
+ create_params.maximum_size = window_bounds.size();
+ ShellWindow* shell_window =
+ new ShellWindow(window_profile, GetExtension());
+ AshPanelContents* ash_panel_contents = new AshPanelContents(shell_window);
+ shell_window->Init(urls[0], ash_panel_contents, create_params);
+ SetResult(ash_panel_contents->GetExtensionWindowController()->
+ CreateWindowValueWithTabs(GetExtension()));
+ // Add the panel to the shell window registry so that it shows up in
+ // the launcher and as an active render process.
+ extensions::ShellWindowRegistry::Get(window_profile)->AddShellWindow(
+ shell_window);
+ return true;
+ }
+#else
std::string title =
web_app::GenerateApplicationNameFromExtensionId(extension_id);
// Note: Panels ignore all but the first url provided.
@@ -612,8 +631,8 @@ bool WindowsCreateFunction::RunImpl() {
panel->extension_window_controller()->CreateWindowValueWithTabs(
GetExtension()));
return true;
- }
#endif
+ }
// Create a new BrowserWindow.
chrome::HostDesktopType host_desktop_type = chrome::GetActiveDesktop();
diff --git a/chrome/browser/extensions/app_window_contents.cc b/chrome/browser/extensions/app_window_contents.cc
new file mode 100644
index 0000000..88be3e6
--- /dev/null
+++ b/chrome/browser/extensions/app_window_contents.cc
@@ -0,0 +1,172 @@
+// Copyright 2013 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/app_window_contents.h"
+
+#include "chrome/browser/ui/extensions/native_app_window.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/extensions/api/app_window.h"
+#include "chrome/common/extensions/extension_messages.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/resource_dispatcher_host.h"
+#include "content/public/browser/site_instance.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/renderer_preferences.h"
+
+namespace app_window = extensions::api::app_window;
+
+AppWindowContents::AppWindowContents(ShellWindow* host)
+ : host_(host) {
+}
+
+AppWindowContents::~AppWindowContents() {
+}
+
+void AppWindowContents::Initialize(Profile* profile, const GURL& url) {
+ url_ = url;
+
+ extension_function_dispatcher_.reset(
+ new ExtensionFunctionDispatcher(profile, this));
+
+ web_contents_.reset(content::WebContents::Create(
+ content::WebContents::CreateParams(
+ profile, content::SiteInstance::CreateForURL(profile, url_))));
+
+ content::WebContentsObserver::Observe(web_contents_.get());
+ web_contents_->GetMutableRendererPrefs()->
+ browser_handles_all_top_level_requests = true;
+ web_contents_->GetRenderViewHost()->SyncRendererPrefs();
+}
+
+void AppWindowContents::LoadContents(int32 creator_process_id) {
+ // If the new view is in the same process as the creator, block the created
+ // RVH from loading anything until the background page has had a chance to
+ // do any initialization it wants. If it's a different process, the new RVH
+ // shouldn't communicate with the background page anyway (e.g. sandboxed).
+ if (web_contents_->GetRenderViewHost()->GetProcess()->GetID() ==
+ creator_process_id) {
+ SuspendRenderViewHost(web_contents_->GetRenderViewHost());
+ } else {
+ VLOG(1) << "ShellWindow created in new process ("
+ << web_contents_->GetRenderViewHost()->GetProcess()->GetID()
+ << ") != creator (" << creator_process_id
+ << "). Routing disabled.";
+ }
+
+ // TODO(jeremya): there's a bug where navigating a web contents to an
+ // extension URL causes it to create a new RVH and discard the old
+ // (perfectly usable) one. To work around this, we watch for a RVH_CHANGED
+ // message from the web contents (which will be sent during LoadURL) and
+ // suspend resource requests on the new RVH to ensure that we block the new
+ // RVH from loading anything. It should be okay to remove the
+ // NOTIFICATION_RVH_CHANGED registration once http://crbug.com/123007 is
+ // fixed.
+ registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
+ content::Source<content::NavigationController>(
+ &web_contents()->GetController()));
+ web_contents_->GetController().LoadURL(
+ url_, content::Referrer(), content::PAGE_TRANSITION_LINK,
+ std::string());
+ registrar_.RemoveAll();
+}
+
+void AppWindowContents::NativeWindowChanged(
+ NativeAppWindow* native_app_window) {
+ ListValue args;
+ DictionaryValue* dictionary = new DictionaryValue();
+ args.Append(dictionary);
+
+ gfx::Rect bounds = native_app_window->GetBounds();
+ bounds.Inset(native_app_window->GetFrameInsets());
+ app_window::Bounds update;
+ update.left.reset(new int(bounds.x()));
+ update.top.reset(new int(bounds.y()));
+ update.width.reset(new int(bounds.width()));
+ update.height.reset(new int(bounds.height()));
+ dictionary->Set("bounds", update.ToValue().release());
+ dictionary->SetBoolean("minimized", native_app_window->IsMinimized());
+ dictionary->SetBoolean("maximized", native_app_window->IsMaximized());
+
+ content::RenderViewHost* rvh = web_contents_->GetRenderViewHost();
+ rvh->Send(new ExtensionMsg_MessageInvoke(rvh->GetRoutingID(),
+ host_->extension()->id(),
+ "updateAppWindowProperties",
+ args,
+ GURL(),
+ false));
+
+}
+
+void AppWindowContents::NativeWindowClosed() {
+ content::RenderViewHost* rvh = web_contents_->GetRenderViewHost();
+ rvh->Send(new ExtensionMsg_AppWindowClosed(rvh->GetRoutingID()));
+}
+
+content::WebContents* AppWindowContents::GetWebContents() const {
+ return web_contents_.get();
+}
+
+void AppWindowContents::Observe(
+ int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ switch (type) {
+ case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: {
+ // TODO(jeremya): once http://crbug.com/123007 is fixed, we'll no longer
+ // need to suspend resource requests here (the call in the constructor
+ // should be enough).
+ content::Details<std::pair<content::RenderViewHost*,
+ content::RenderViewHost*> >
+ host_details(details);
+ if (host_details->first)
+ SuspendRenderViewHost(host_details->second);
+ break;
+ }
+ default:
+ NOTREACHED() << "Received unexpected notification";
+ }
+}
+
+bool AppWindowContents::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(AppWindowContents, message)
+ IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
+ IPC_MESSAGE_HANDLER(ExtensionHostMsg_UpdateDraggableRegions,
+ UpdateDraggableRegions)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+extensions::WindowController*
+AppWindowContents::GetExtensionWindowController() const {
+ return NULL;
+}
+
+content::WebContents* AppWindowContents::GetAssociatedWebContents() const {
+ return web_contents_.get();
+}
+
+void AppWindowContents::OnRequest(
+ const ExtensionHostMsg_Request_Params& params) {
+ extension_function_dispatcher_->Dispatch(
+ params, web_contents_->GetRenderViewHost());
+}
+
+void AppWindowContents::UpdateDraggableRegions(
+ const std::vector<extensions::DraggableRegion>& regions) {
+ host_->UpdateDraggableRegions(regions);
+}
+
+void AppWindowContents::SuspendRenderViewHost(
+ content::RenderViewHost* rvh) {
+ DCHECK(rvh);
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::Bind(&content::ResourceDispatcherHost::BlockRequestsForRoute,
+ base::Unretained(content::ResourceDispatcherHost::Get()),
+ rvh->GetProcess()->GetID(), rvh->GetRoutingID()));
+}
diff --git a/chrome/browser/extensions/app_window_contents.h b/chrome/browser/extensions/app_window_contents.h
new file mode 100644
index 0000000..3cf2a32
--- /dev/null
+++ b/chrome/browser/extensions/app_window_contents.h
@@ -0,0 +1,73 @@
+// Copyright 2013 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_APP_WINDOW_CONTENTS_H_
+#define CHROME_BROWSER_EXTENSIONS_APP_WINDOW_CONTENTS_H_
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/extensions/extension_function_dispatcher.h"
+#include "chrome/browser/ui/extensions/shell_window.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/web_contents_observer.h"
+
+class GURL;
+
+namespace content {
+class RenderViewHost;
+}
+
+namespace extensions {
+struct DraggableRegion;
+}
+
+// ShellWindowContents class specific to app windows. It maintains a
+// WebContents instance and observes it for the purpose of passing
+// messages to the extensions system.
+class AppWindowContents : public ShellWindowContents,
+ public content::NotificationObserver,
+ public content::WebContentsObserver,
+ public ExtensionFunctionDispatcher::Delegate {
+ public:
+ explicit AppWindowContents(ShellWindow* host);
+ virtual ~AppWindowContents();
+
+ // ShellWindowContents
+ virtual void Initialize(Profile* profile, const GURL& url) OVERRIDE;
+ virtual void LoadContents(int32 creator_process_id) OVERRIDE;
+ virtual void NativeWindowChanged(NativeAppWindow* native_app_window) OVERRIDE;
+ virtual void NativeWindowClosed() OVERRIDE;
+ virtual content::WebContents* GetWebContents() const OVERRIDE;
+
+ private:
+ // content::NotificationObserver
+ virtual void Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) OVERRIDE;
+
+ // content::WebContentsObserver
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ // ExtensionFunctionDispatcher::Delegate
+ virtual extensions::WindowController* GetExtensionWindowController() const
+ OVERRIDE;
+ virtual content::WebContents* GetAssociatedWebContents() const OVERRIDE;
+
+ void OnRequest(const ExtensionHostMsg_Request_Params& params);
+ void UpdateDraggableRegions(
+ const std::vector<extensions::DraggableRegion>& regions);
+ void SuspendRenderViewHost(content::RenderViewHost* rvh);
+
+ ShellWindow* host_; // This class is owned by |host_|
+ GURL url_;
+ content::NotificationRegistrar registrar_;
+ scoped_ptr<content::WebContents> web_contents_;
+ scoped_ptr<ExtensionFunctionDispatcher> extension_function_dispatcher_;
+
+ DISALLOW_COPY_AND_ASSIGN(AppWindowContents);
+};
+
+#endif // CHROME_BROWSER_EXTENSIONS_APP_WINDOW_CONTENTS_H_
diff --git a/chrome/browser/extensions/browser_extension_window_controller.cc b/chrome/browser/extensions/browser_extension_window_controller.cc
index 665c5ad..9e50e50 100644
--- a/chrome/browser/extensions/browser_extension_window_controller.cc
+++ b/chrome/browser/extensions/browser_extension_window_controller.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/extensions/extension.h"
BrowserExtensionWindowController::BrowserExtensionWindowController(
@@ -58,6 +59,14 @@ BrowserExtensionWindowController::CreateWindowValueWithTabs(
return result;
}
+base::DictionaryValue* BrowserExtensionWindowController::CreateTabValue(
+ const extensions::Extension* extension, int tab_index) const {
+ TabStripModel* tab_strip = browser_->tab_strip_model();
+ DictionaryValue* result = ExtensionTabUtil::CreateTabValue(
+ tab_strip->GetWebContentsAt(tab_index), tab_strip, tab_index);
+ return result;
+}
+
bool BrowserExtensionWindowController::CanClose(Reason* reason) const {
// Don't let an extension remove the window if the user is dragging tabs
// in that window.
diff --git a/chrome/browser/extensions/browser_extension_window_controller.h b/chrome/browser/extensions/browser_extension_window_controller.h
index a1e220a..2dfb3d4 100644
--- a/chrome/browser/extensions/browser_extension_window_controller.h
+++ b/chrome/browser/extensions/browser_extension_window_controller.h
@@ -24,6 +24,8 @@ class BrowserExtensionWindowController : public extensions::WindowController {
virtual base::DictionaryValue* CreateWindowValue() const OVERRIDE;
virtual base::DictionaryValue* CreateWindowValueWithTabs(
const extensions::Extension* extension) const OVERRIDE;
+ virtual base::DictionaryValue* CreateTabValue(
+ const extensions::Extension* extension, int tab_index) const OVERRIDE;
virtual bool CanClose(Reason* reason) const OVERRIDE;
virtual void SetFullscreenMode(bool is_fullscreen,
const GURL& extension_url) const OVERRIDE;
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index 2ed787d..5e89316 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -5,8 +5,10 @@
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
+#include "chrome/browser/extensions/shell_window_registry.h"
#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/extensions/window_controller.h"
+#include "chrome/browser/extensions/window_controller_list.h"
#include "chrome/browser/net/url_fixer_upper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sessions/session_id.h"
@@ -14,6 +16,7 @@
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_iterator.h"
#include "chrome/browser/ui/browser_window.h"
+#include "chrome/browser/ui/extensions/shell_window.h"
#include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/extensions/extension.h"
@@ -33,6 +36,25 @@ using content::WebContents;
using extensions::APIPermission;
using extensions::Extension;
+namespace {
+
+extensions::WindowController* GetShellWindowController(
+ const WebContents* contents) {
+ Profile* profile = Profile::FromBrowserContext(contents->GetBrowserContext());
+ extensions::ShellWindowRegistry* registry =
+ extensions::ShellWindowRegistry::Get(profile);
+ if (!registry)
+ return NULL;
+ ShellWindow* shell_window =
+ registry->GetShellWindowForRenderViewHost(contents->GetRenderViewHost());
+ if (!shell_window)
+ return NULL;
+ return extensions::WindowControllerList::GetInstance()->
+ FindWindowById(shell_window->session_id().id());
+}
+
+} // namespace
+
int ExtensionTabUtil::GetWindowId(const Browser* browser) {
return browser->session_id().id();
}
@@ -63,6 +85,13 @@ DictionaryValue* ExtensionTabUtil::CreateTabValue(
TabStripModel* tab_strip,
int tab_index,
const Extension* extension) {
+ // If we have a matching ShellWindow with a controller, get the tab value
+ // from its controller instead.
+ extensions::WindowController* controller = GetShellWindowController(contents);
+ if (controller &&
+ (!extension || controller->IsVisibleToExtension(extension))) {
+ return controller->CreateTabValue(extension, tab_index);
+ }
DictionaryValue *result = CreateTabValue(contents, tab_strip, tab_index);
ScrubTabValueForExtension(contents, extension, result);
return result;
@@ -87,6 +116,12 @@ DictionaryValue* ExtensionTabUtil::CreateTabValue(
const WebContents* contents,
TabStripModel* tab_strip,
int tab_index) {
+ // If we have a matching ShellWindow with a controller, get the tab value
+ // from its controller instead.
+ extensions::WindowController* controller = GetShellWindowController(contents);
+ if (controller)
+ return controller->CreateTabValue(NULL, tab_index);
+
if (!tab_strip)
ExtensionTabUtil::GetTabStripModel(contents, &tab_strip, &tab_index);
diff --git a/chrome/browser/extensions/window_controller.h b/chrome/browser/extensions/window_controller.h
index ec9f6e2..48a881e 100644
--- a/chrome/browser/extensions/window_controller.h
+++ b/chrome/browser/extensions/window_controller.h
@@ -60,6 +60,9 @@ class WindowController {
virtual base::DictionaryValue* CreateWindowValueWithTabs(
const extensions::Extension* extension) const = 0;
+ virtual base::DictionaryValue* CreateTabValue(
+ const extensions::Extension* extension, int tab_index) const = 0;
+
// Returns false if the window is in a state where closing the window is not
// permitted and sets |reason| if not NULL.
virtual bool CanClose(Reason* reason) const = 0;
diff --git a/chrome/browser/extensions/window_controller_list.cc b/chrome/browser/extensions/window_controller_list.cc
index 0dfdffa..257c680b 100644
--- a/chrome/browser/extensions/window_controller_list.cc
+++ b/chrome/browser/extensions/window_controller_list.cc
@@ -52,17 +52,24 @@ void WindowControllerList::RemoveObserver(
observers_.RemoveObserver(observer);
}
-WindowController* WindowControllerList::FindWindowForFunctionById(
- const UIThreadExtensionFunction* function,
- int id) const {
+WindowController* WindowControllerList::FindWindowById(int id) const {
for (ControllerList::const_iterator iter = windows().begin();
iter != windows().end(); ++iter) {
- if (function->CanOperateOnWindow(*iter) && (*iter)->GetWindowId() == id)
+ if ((*iter)->GetWindowId() == id)
return *iter;
}
return NULL;
}
+WindowController* WindowControllerList::FindWindowForFunctionById(
+ const UIThreadExtensionFunction* function,
+ int id) const {
+ WindowController* controller = FindWindowById(id);
+ if (controller && function->CanOperateOnWindow(controller))
+ return controller;
+ return NULL;
+}
+
WindowController* WindowControllerList::CurrentWindowForFunction(
const UIThreadExtensionFunction* function) const {
WindowController* result = NULL;
diff --git a/chrome/browser/extensions/window_controller_list.h b/chrome/browser/extensions/window_controller_list.h
index a32baf6..4b9b934 100644
--- a/chrome/browser/extensions/window_controller_list.h
+++ b/chrome/browser/extensions/window_controller_list.h
@@ -33,6 +33,9 @@ class WindowControllerList {
void AddObserver(WindowControllerListObserver* observer);
void RemoveObserver(WindowControllerListObserver* observer);
+ // Returns a window matching |id|.
+ WindowController* FindWindowById(int id) const;
+
// Returns a window matching the context the function was invoked in.
WindowController* FindWindowForFunctionById(
const UIThreadExtensionFunction* function,
diff --git a/chrome/browser/extensions/window_open_apitest.cc b/chrome/browser/extensions/window_open_apitest.cc
index cac1d4c..b448aee 100644
--- a/chrome/browser/extensions/window_open_apitest.cc
+++ b/chrome/browser/extensions/window_open_apitest.cc
@@ -26,6 +26,15 @@
#include "net/base/mock_host_resolver.h"
#include "testing/gtest/include/gtest/gtest.h"
+#if defined(USE_ASH)
+#include "chrome/browser/extensions/shell_window_registry.h"
+#endif
+
+#if defined(USE_ASH) && !defined(OS_WIN)
+// TODO(stevenjb): Figure out the correct behavior for Ash + Win
+#define USE_ASH_PANELS
+#endif
+
using content::OpenURLParams;
using content::Referrer;
using content::WebContents;
@@ -41,7 +50,16 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_WindowOpen) {
EXPECT_TRUE(catcher.GetNextResult()) << catcher.message();
}
-void WaitForTabsAndPopups(Browser* browser,
+int GetPanelCount(Browser* browser) {
+#if defined(USE_ASH_PANELS)
+ return static_cast<int>(extensions::ShellWindowRegistry::Get(
+ browser->profile())->shell_windows().size());
+#else
+ return PanelManager::GetInstance()->num_panels();
+#endif
+}
+
+bool WaitForTabsAndPopups(Browser* browser,
int num_tabs,
int num_popups,
int num_panels) {
@@ -52,12 +70,12 @@ void WaitForTabsAndPopups(Browser* browser,
++num_tabs;
size_t num_browsers = static_cast<size_t>(num_popups) + 1;
- const base::TimeDelta kWaitTime = base::TimeDelta::FromSeconds(15);
+ const base::TimeDelta kWaitTime = base::TimeDelta::FromSeconds(10);
base::TimeTicks end_time = base::TimeTicks::Now() + kWaitTime;
while (base::TimeTicks::Now() < end_time) {
if (chrome::GetBrowserCount(browser->profile()) == num_browsers &&
browser->tab_strip_model()->count() == num_tabs &&
- PanelManager::GetInstance()->num_panels() == num_panels)
+ GetPanelCount(browser) == num_panels)
break;
content::RunAllPendingInMessageLoop();
@@ -65,7 +83,7 @@ void WaitForTabsAndPopups(Browser* browser,
EXPECT_EQ(num_browsers, chrome::GetBrowserCount(browser->profile()));
EXPECT_EQ(num_tabs, browser->tab_strip_model()->count());
- EXPECT_EQ(num_panels, PanelManager::GetInstance()->num_panels());
+ EXPECT_EQ(num_panels, GetPanelCount(browser));
int num_popups_seen = 0;
for (chrome::BrowserIterator iter; !iter.done(); iter.Next()) {
@@ -73,10 +91,8 @@ void WaitForTabsAndPopups(Browser* browser,
continue;
// Check for TYPE_POPUP.
-// TODO: this ifdef will have to be updated when we have win ash bots running
-// browser_tests.
-#if defined(USE_ASH) && !defined(OS_WIN)
- // On Ash, panel windows open as popup windows.
+#if defined(USE_ASH_PANELS)
+ // On Ash, panel windows may open as popup windows.
EXPECT_TRUE((*iter)->is_type_popup() || (*iter)->is_type_panel());
#else
EXPECT_TRUE((*iter)->is_type_popup());
@@ -84,6 +100,11 @@ void WaitForTabsAndPopups(Browser* browser,
++num_popups_seen;
}
EXPECT_EQ(num_popups, num_popups_seen);
+
+ return ((num_browsers == chrome::GetBrowserCount(browser->profile())) &&
+ (num_tabs == browser->tab_strip_model()->count()) &&
+ (num_panels == GetPanelCount(browser)) &&
+ (num_popups == num_popups_seen));
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, BrowserIsApp) {
@@ -92,7 +113,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, BrowserIsApp) {
ASSERT_TRUE(LoadExtension(
test_data_dir_.AppendASCII("window_open").AppendASCII("browser_is_app")));
- WaitForTabsAndPopups(browser(), 0, 2, 0);
+ EXPECT_TRUE(WaitForTabsAndPopups(browser(), 0, 2, 0));
for (chrome::BrowserIterator iter; !iter.done(); iter.Next()) {
if (*iter == browser())
@@ -109,7 +130,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupDefault) {
const int num_tabs = 1;
const int num_popups = 0;
- WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0);
+ EXPECT_TRUE(WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0));
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupLarge) {
@@ -120,7 +141,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupLarge) {
// On other systems this should open a new popup window.
const int num_tabs = 0;
const int num_popups = 1;
- WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0);
+ EXPECT_TRUE(WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0));
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupSmall) {
@@ -132,7 +153,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowOpenPopupSmall) {
// On other systems this should open a new popup window.
const int num_tabs = 0;
const int num_popups = 1;
- WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0);
+ EXPECT_TRUE(WaitForTabsAndPopups(browser(), num_tabs, num_popups, 0));
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PopupBlockingExtension) {
@@ -143,7 +164,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PopupBlockingExtension) {
test_data_dir_.AppendASCII("window_open").AppendASCII("popup_blocking")
.AppendASCII("extension")));
- WaitForTabsAndPopups(browser(), 5, 3, 0);
+ EXPECT_TRUE(WaitForTabsAndPopups(browser(), 5, 3, 0));
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PopupBlockingHostedApp) {
@@ -178,7 +199,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, PopupBlockingHostedApp) {
open_popup, Referrer(), NEW_FOREGROUND_TAB,
content::PAGE_TRANSITION_TYPED, false));
- WaitForTabsAndPopups(browser(), 3, 1, 0);
+ EXPECT_TRUE(WaitForTabsAndPopups(browser(), 3, 1, 0));
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, WindowArgumentsOverflow) {
@@ -205,9 +226,7 @@ class WindowOpenPanelTest : public ExtensionApiTest {
}
};
-// TODO: this ifdef will have to be updated when we have win ash bots running
-// browser_tests.
-#if defined(USE_ASH) && !defined(OS_WIN)
+#if defined(USE_ASH_PANELS)
// On Ash, this currently fails because we're currently opening new panel
// windows as popup windows instead.
#define MAYBE_WindowOpenPanel DISABLED_WindowOpenPanel
@@ -218,9 +237,7 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_WindowOpenPanel) {
ASSERT_TRUE(RunExtensionTest("window_open/panel")) << message_;
}
-// TODO: this ifdef will have to be updated when we have win ash bots running
-// browser_tests.
-#if defined(USE_ASH)
+#if defined(USE_ASH_PANELS)
// On Ash, this currently fails because we're currently opening new panel
// windows as popup windows instead.
#define MAYBE_WindowOpenPanelDetached DISABLED_WindowOpenPanelDetached
@@ -233,12 +250,16 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_WindowOpenPanelDetached) {
IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest,
CloseNonExtensionPanelsOnUninstall) {
-// TODO: this ifdef will have to be updated when we have win ash bots running
-// browser_tests.
-#if defined(USE_ASH) && !defined(OS_WIN)
+#if defined(USE_ASH_PANELS)
// On Ash, new panel windows open as popup windows instead.
- int num_popups = 4;
- int num_panels = 0;
+ int num_popups, num_panels;
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels)) {
+ num_popups = 2;
+ num_panels = 2;
+ } else {
+ num_popups = 4;
+ num_panels = 0;
+ }
#else
int num_popups = 2;
int num_panels = 2;
@@ -266,7 +287,7 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest,
// Two tabs. One in extension domain and one in non-extension domain.
// Two popups - one in extension domain and one in non-extension domain.
// Two panels - one in extension domain and one in non-extension domain.
- WaitForTabsAndPopups(browser(), 2, num_popups, num_panels);
+ EXPECT_TRUE(WaitForTabsAndPopups(browser(), 2, num_popups, num_panels));
// Wait on test messages to make sure the pages loaded.
for (size_t i = 0; i < listeners.size(); ++i)
@@ -276,16 +297,15 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest,
// Wait for the tabs and popups in non-extension domain to stay open.
// Expect everything else, including panels, to close.
-// TODO: this ifdef will have to be updated when we have win ash bots running
-// browser_tests.
-#if defined(USE_ASH) && !defined(OS_WIN)
- // On Ash, new panel windows open as popup windows instead, so there are 2
- // extension domain popups that will close (instead of 1 popup on non-Ash).
- num_popups -= 2;
-#else
num_popups -= 1;
+#if defined(USE_ASH_PANELS)
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnablePanels)) {
+ // On Ash, new panel windows open as popup windows instead, so there are 2
+ // extension domain popups that will close (instead of 1 popup on non-Ash).
+ num_popups -= 1;
+ }
#endif
- WaitForTabsAndPopups(browser(), 1, num_popups, 0);
+ EXPECT_TRUE(WaitForTabsAndPopups(browser(), 1, num_popups, 0));
}
#if defined(OS_CHROMEOS)
@@ -297,9 +317,7 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest,
#define MAYBE_ClosePanelsOnExtensionCrash ClosePanelsOnExtensionCrash
#endif
IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_ClosePanelsOnExtensionCrash) {
-// TODO: this ifdef will have to be updated when we have win ash bots running
-// browser_tests.
-#if defined(USE_ASH) && !defined(OS_WIN)
+#if defined(USE_ASH_PANELS)
// On Ash, new panel windows open as popup windows instead.
int num_popups = 4;
int num_panels = 0;
@@ -330,7 +348,7 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_ClosePanelsOnExtensionCrash) {
// Two tabs. One in extension domain and one in non-extension domain.
// Two popups - one in extension domain and one in non-extension domain.
// Two panels - one in extension domain and one in non-extension domain.
- WaitForTabsAndPopups(browser(), 2, num_popups, num_panels);
+ EXPECT_TRUE(WaitForTabsAndPopups(browser(), 2, num_popups, num_panels));
// Wait on test messages to make sure the pages loaded.
for (size_t i = 0; i < listeners.size(); ++i)
@@ -346,14 +364,12 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_ClosePanelsOnExtensionCrash) {
WaitForExtensionCrash(extension->id());
// Only expect panels to close. The rest stay open to show a sad-tab.
- WaitForTabsAndPopups(browser(), 2, num_popups, 0);
+ EXPECT_TRUE(WaitForTabsAndPopups(browser(), 2, num_popups, 0));
}
-// TODO: this ifdef will have to be updated when we have win ash bots running
-// browser_tests.
-#if defined(USE_ASH) && !defined(OS_WIN)
-// This test is not applicable on Ash. Ash opens panel windows as popup
-// windows. The modified window.open behavior only applies to panel windows.
+#if defined(USE_ASH_PANELS)
+// This test is not applicable on Ash. The modified window.open behavior only
+// applies to non-Ash panel windows.
#define MAYBE_WindowOpenFromPanel DISABLED_WindowOpenFromPanel
#else
#define MAYBE_WindowOpenFromPanel WindowOpenFromPanel
@@ -368,7 +384,7 @@ IN_PROC_BROWSER_TEST_F(WindowOpenPanelTest, MAYBE_WindowOpenFromPanel) {
// Expect one panel (opened by extension) and one tab (from the panel calling
// window.open). Panels modify the WindowOpenDisposition in window.open
// to always open in a tab.
- WaitForTabsAndPopups(browser(), 1, 0, 1);
+ EXPECT_TRUE(WaitForTabsAndPopups(browser(), 1, 0, 1));
}
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, DISABLED_WindowOpener) {
diff --git a/chrome/browser/ui/extensions/shell_window.cc b/chrome/browser/ui/extensions/shell_window.cc
index bdc53b2..bd1e950 100644
--- a/chrome/browser/ui/extensions/shell_window.cc
+++ b/chrome/browser/ui/extensions/shell_window.cc
@@ -6,13 +6,13 @@
#include "base/utf_string_conversions.h"
#include "base/values.h"
+#include "chrome/browser/extensions/app_window_contents.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/image_loader.h"
#include "chrome/browser/extensions/shell_window_geometry_cache.h"
#include "chrome/browser/extensions/shell_window_registry.h"
#include "chrome/browser/extensions/suggest_permission_util.h"
-#include "chrome/browser/extensions/tab_helper.h"
#include "chrome/browser/favicon/favicon_tab_helper.h"
#include "chrome/browser/file_select_helper.h"
#include "chrome/browser/lifetime/application_lifetime.h"
@@ -27,25 +27,20 @@
#include "chrome/browser/ui/web_contents_modal_dialog_manager.h"
#include "chrome/browser/view_type_utils.h"
#include "chrome/common/chrome_notification_types.h"
-#include "chrome/common/extensions/api/app_window.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/extensions/request_media_access_permission_helper.h"
-#include "content/public/browser/browser_thread.h"
#include "content/public/browser/invalidate_type.h"
#include "content/public/browser/navigation_entry.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_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/resource_dispatcher_host.h"
-#include "content/public/browser/site_instance.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/media_stream_request.h"
-#include "content/public/common/renderer_preferences.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/gfx/image/image_skia.h"
@@ -54,13 +49,7 @@
#include "ash/launcher/launcher_types.h"
#endif
-namespace app_window = extensions::api::app_window;
-
-using content::BrowserThread;
using content::ConsoleMessageLevel;
-using content::RenderViewHost;
-using content::ResourceDispatcherHost;
-using content::SiteInstance;
using content::WebContents;
using extensions::APIPermission;
using extensions::RequestMediaAccessPermissionHelper;
@@ -76,14 +65,6 @@ const int kPreferredIconSize = ash::kLauncherPreferredSize;
const int kPreferredIconSize = extension_misc::EXTENSION_ICON_SMALL;
#endif
-void SuspendRenderViewHost(RenderViewHost* rvh) {
- DCHECK(rvh);
- BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
- base::Bind(&ResourceDispatcherHost::BlockRequestsForRoute,
- base::Unretained(ResourceDispatcherHost::Get()),
- rvh->GetProcess()->GetID(), rvh->GetRoutingID()));
-}
-
} // namespace
ShellWindow::CreateParams::CreateParams()
@@ -103,7 +84,7 @@ ShellWindow* ShellWindow::Create(Profile* profile,
const CreateParams& params) {
// This object will delete itself when the window is closed.
ShellWindow* window = new ShellWindow(profile, extension);
- window->Init(url, params);
+ window->Init(url, new AppWindowContents(window), params);
extensions::ShellWindowRegistry::Get(profile)->AddShellWindow(window);
return window;
}
@@ -112,29 +93,26 @@ ShellWindow::ShellWindow(Profile* profile,
const extensions::Extension* extension)
: profile_(profile),
extension_(extension),
- web_contents_(NULL),
window_type_(WINDOW_TYPE_DEFAULT),
- ALLOW_THIS_IN_INITIALIZER_LIST(
- extension_function_dispatcher_(profile, this)),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
ALLOW_THIS_IN_INITIALIZER_LIST(image_loader_ptr_factory_(this)) {
}
void ShellWindow::Init(const GURL& url,
+ ShellWindowContents* shell_window_contents,
const ShellWindow::CreateParams& params) {
- window_type_ = params.window_type;
+ // Initialize the render interface and web contents
+ shell_window_contents_.reset(shell_window_contents);
+ shell_window_contents_->Initialize(profile(), url);
+ WebContents* web_contents = shell_window_contents_->GetWebContents();
+ WebContentsModalDialogManager::CreateForWebContents(web_contents);
+ FaviconTabHelper::CreateForWebContents(web_contents);
- web_contents_.reset(WebContents::Create(WebContents::CreateParams(
- profile(), SiteInstance::CreateForURL(profile(), url))));
- WebContentsModalDialogManager::CreateForWebContents(web_contents_.get());
- FaviconTabHelper::CreateForWebContents(web_contents_.get());
+ web_contents->SetDelegate(this);
+ chrome::SetViewType(web_contents, chrome::VIEW_TYPE_APP_SHELL);
- content::WebContentsObserver::Observe(web_contents_.get());
- web_contents_->SetDelegate(this);
- chrome::SetViewType(web_contents_.get(), chrome::VIEW_TYPE_APP_SHELL);
- web_contents_->GetMutableRendererPrefs()->
- browser_handles_all_top_level_requests = true;
- web_contents_->GetRenderViewHost()->SyncRendererPrefs();
+ // Initialize the window
+ window_type_ = params.window_type;
gfx::Rect bounds = params.bounds;
@@ -192,34 +170,7 @@ void ShellWindow::Init(const GURL& url,
GetBaseWindow()->Show();
}
- // If the new view is in the same process as the creator, block the created
- // RVH from loading anything until the background page has had a chance to do
- // any initialization it wants. If it's a different process, the new RVH
- // shouldn't communicate with the background page anyway (e.g. sandboxed).
- if (web_contents_->GetRenderViewHost()->GetProcess()->GetID() ==
- params.creator_process_id) {
- SuspendRenderViewHost(web_contents_->GetRenderViewHost());
- } else {
- VLOG(1) << "ShellWindow created in new process ("
- << web_contents_->GetRenderViewHost()->GetProcess()->GetID()
- << ") != creator (" << params.creator_process_id
- << "). Routing disabled.";
- }
-
- // TODO(jeremya): there's a bug where navigating a web contents to an
- // extension URL causes it to create a new RVH and discard the old (perfectly
- // usable) one. To work around this, we watch for a RVH_CHANGED message from
- // the web contents (which will be sent during LoadURL) and suspend resource
- // requests on the new RVH to ensure that we block the new RVH from loading
- // anything. It should be okay to remove the NOTIFICATION_RVH_CHANGED
- // registration once http://crbug.com/123007 is fixed.
- registrar_.Add(this, content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED,
- content::Source<content::NavigationController>(
- &web_contents_->GetController()));
- web_contents_->GetController().LoadURL(
- url, content::Referrer(), content::PAGE_TRANSITION_LINK,
- std::string());
- registrar_.RemoveAll();
+ shell_window_contents_->LoadContents(params.creator_process_id);
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
content::Source<Profile>(profile_));
@@ -262,8 +213,6 @@ void ShellWindow::RequestMediaAccessPermission(
WebContents* ShellWindow::OpenURLFromTab(WebContents* source,
const content::OpenURLParams& params) {
- DCHECK(source == web_contents_);
-
// Don't allow the current tab to be navigated. It would be nice to map all
// anchor tags (even those without target="_blank") to new tabs, but right
// now we can't distinguish between those and <meta> refreshes or window.href
@@ -311,7 +260,6 @@ void ShellWindow::AddNewContents(WebContents* source,
const gfx::Rect& initial_pos,
bool user_gesture,
bool* was_blocked) {
- DCHECK(source == web_contents_);
DCHECK(Profile::FromBrowserContext(new_contents->GetBrowserContext()) ==
profile_);
Browser* browser =
@@ -327,7 +275,6 @@ void ShellWindow::AddNewContents(WebContents* source,
void ShellWindow::HandleKeyboardEvent(
WebContents* source,
const content::NativeWebKeyboardEvent& event) {
- DCHECK_EQ(source, web_contents_);
native_app_window_->HandleKeyboardEvent(event);
}
@@ -344,37 +291,15 @@ void ShellWindow::RequestToLockMouse(WebContents* web_contents,
void ShellWindow::OnNativeClose() {
extensions::ShellWindowRegistry::Get(profile_)->RemoveShellWindow(this);
- content::RenderViewHost* rvh = web_contents_->GetRenderViewHost();
- rvh->Send(new ExtensionMsg_AppWindowClosed(rvh->GetRoutingID()));
+ if (shell_window_contents_)
+ shell_window_contents_->NativeWindowClosed();
delete this;
}
void ShellWindow::OnNativeWindowChanged() {
SaveWindowPosition();
- if (!native_app_window_ || !web_contents_)
- return;
- ListValue args;
- DictionaryValue* dictionary = new DictionaryValue();
- args.Append(dictionary);
-
- gfx::Rect bounds = native_app_window_->GetBounds();
- bounds.Inset(native_app_window_->GetFrameInsets());
- app_window::Bounds update;
- update.left.reset(new int(bounds.x()));
- update.top.reset(new int(bounds.y()));
- update.width.reset(new int(bounds.width()));
- update.height.reset(new int(bounds.height()));
- dictionary->Set("bounds", update.ToValue().release());
- dictionary->SetBoolean("minimized", native_app_window_->IsMinimized());
- dictionary->SetBoolean("maximized", native_app_window_->IsMaximized());
-
- content::RenderViewHost* rvh = web_contents_->GetRenderViewHost();
- rvh->Send(new ExtensionMsg_MessageInvoke(rvh->GetRoutingID(),
- extension_->id(),
- "updateAppWindowProperties",
- args,
- GURL(),
- false));
+ if (shell_window_contents_ && native_app_window_)
+ shell_window_contents_->NativeWindowChanged(native_app_window_.get());
}
gfx::Image* ShellWindow::GetAppListIcon() {
@@ -392,6 +317,10 @@ gfx::Image* ShellWindow::GetAppListIcon() {
return new gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bmp));
}
+content::WebContents* ShellWindow::web_contents() const {
+ return shell_window_contents_->GetWebContents();
+}
+
NativeAppWindow* ShellWindow::GetBaseWindow() {
return native_app_window_.get();
}
@@ -420,25 +349,14 @@ void ShellWindow::SetAppIconUrl(const GURL& url) {
weak_ptr_factory_.GetWeakPtr()));
}
-//------------------------------------------------------------------------------
-// Private methods
-
-bool ShellWindow::OnMessageReceived(const IPC::Message& message) {
- bool handled = true;
- IPC_BEGIN_MESSAGE_MAP(ShellWindow, message)
- IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
- IPC_MESSAGE_HANDLER(ExtensionHostMsg_UpdateDraggableRegions,
- UpdateDraggableRegions)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- return handled;
-}
-
void ShellWindow::UpdateDraggableRegions(
const std::vector<extensions::DraggableRegion>& regions) {
native_app_window_->UpdateDraggableRegions(regions);
}
+//------------------------------------------------------------------------------
+// Private methods
+
void ShellWindow::OnImageLoaded(const gfx::Image& image) {
UpdateAppIcon(image);
}
@@ -486,7 +404,6 @@ void ShellWindow::UpdateExtensionAppIcon() {
}
void ShellWindow::CloseContents(WebContents* contents) {
- DCHECK(contents == web_contents_);
native_app_window_->Close();
}
@@ -500,18 +417,15 @@ void ShellWindow::RunFileChooser(WebContents* tab,
}
bool ShellWindow::IsPopupOrPanel(const WebContents* source) const {
- DCHECK(source == web_contents_.get());
return true;
}
void ShellWindow::MoveContents(WebContents* source, const gfx::Rect& pos) {
- DCHECK(source == web_contents_.get());
native_app_window_->SetBounds(pos);
}
void ShellWindow::NavigationStateChanged(
const content::WebContents* source, unsigned changed_flags) {
- DCHECK(source == web_contents_.get());
if (changed_flags & content::INVALIDATE_TYPE_TITLE)
native_app_window_->UpdateWindowTitle();
else if (changed_flags & content::INVALIDATE_TYPE_TAB)
@@ -520,14 +434,10 @@ void ShellWindow::NavigationStateChanged(
void ShellWindow::ToggleFullscreenModeForTab(content::WebContents* source,
bool enter_fullscreen) {
- DCHECK(source == web_contents_.get());
- if (source != web_contents_.get())
- return;
-
bool has_permission = IsExtensionWithPermissionOrSuggestInConsole(
APIPermission::kFullscreen,
extension_,
- web_contents_->GetRenderViewHost());
+ source->GetRenderViewHost());
if (has_permission)
native_app_window_->SetFullscreen(enter_fullscreen);
@@ -535,7 +445,6 @@ void ShellWindow::ToggleFullscreenModeForTab(content::WebContents* source,
bool ShellWindow::IsFullscreenForTabOrPending(
const content::WebContents* source) const {
- DCHECK(source == web_contents_.get());
return native_app_window_->IsFullscreenOrPending();
}
@@ -544,13 +453,6 @@ void ShellWindow::Observe(int type,
const content::NotificationDetails& details) {
switch (type) {
case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: {
- // TODO(jeremya): once http://crbug.com/123007 is fixed, we'll no longer
- // need to suspend resource requests here (the call in the constructor
- // should be enough).
- content::Details<std::pair<RenderViewHost*, RenderViewHost*> >
- host_details(details);
- if (host_details->first)
- SuspendRenderViewHost(host_details->second);
// TODO(jianli): once http://crbug.com/123007 is fixed, we'll no longer
// need to make the native window (ShellWindowViews specially) update
// the clickthrough region for the new RVH.
@@ -573,29 +475,15 @@ void ShellWindow::Observe(int type,
}
}
-extensions::WindowController*
-ShellWindow::GetExtensionWindowController() const {
- return NULL;
-}
-
-content::WebContents* ShellWindow::GetAssociatedWebContents() const {
- return web_contents_.get();
-}
-
extensions::ActiveTabPermissionGranter*
ShellWindow::GetActiveTabPermissionGranter() {
// Shell windows don't support the activeTab permission.
return NULL;
}
-void ShellWindow::OnRequest(const ExtensionHostMsg_Request_Params& params) {
- extension_function_dispatcher_.Dispatch(params,
- web_contents_->GetRenderViewHost());
-}
-
void ShellWindow::AddMessageToDevToolsConsole(ConsoleMessageLevel level,
const std::string& message) {
- content::RenderViewHost* rvh = web_contents_->GetRenderViewHost();
+ content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
rvh->Send(new ExtensionMsg_AddMessageToConsole(
rvh->GetRoutingID(), level, message));
}
diff --git a/chrome/browser/ui/extensions/shell_window.h b/chrome/browser/ui/extensions/shell_window.h
index 981c725..4d66ae0 100644
--- a/chrome/browser/ui/extensions/shell_window.h
+++ b/chrome/browser/ui/extensions/shell_window.h
@@ -6,14 +6,13 @@
#define CHROME_BROWSER_UI_EXTENSIONS_SHELL_WINDOW_H_
#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/extensions/extension_function_dispatcher.h"
+#include "base/memory/weak_ptr.h"
#include "chrome/browser/extensions/extension_keybinding_registry.h"
#include "chrome/browser/sessions/session_id.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"
#include "content/public/common/console_message_level.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/rect.h"
@@ -34,12 +33,37 @@ class WindowController;
struct DraggableRegion;
}
+// Manages the web contents for Shell Windows. The implementation for this
+// class should create and maintain the WebContents for the window, and handle
+// any message passing between the web contents and the extension system or
+// native window.
+class ShellWindowContents {
+ public:
+ ShellWindowContents() {}
+ virtual ~ShellWindowContents() {}
+
+ // Called to initialize the WebContents, before the app window is created.
+ virtual void Initialize(Profile* profile, const GURL& url) = 0;
+
+ // Called to load the contents, after the app window is created.
+ virtual void LoadContents(int32 creator_process_id) = 0;
+
+ // Called when the native window changes.
+ virtual void NativeWindowChanged(NativeAppWindow* native_app_window) = 0;
+
+ // Called when the native window closes.
+ virtual void NativeWindowClosed() = 0;
+
+ virtual content::WebContents* GetWebContents() const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ShellWindowContents);
+};
+
// 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 extensions::ExtensionKeybindingRegistry::Delegate {
public:
enum WindowType {
@@ -78,6 +102,7 @@ class ShellWindow : public content::NotificationObserver,
bool hidden;
};
+ // Helper function for creating and intiailizing a v2 app window.
static ShellWindow* Create(Profile* profile,
const extensions::Extension* extension,
const GURL& url,
@@ -88,10 +113,22 @@ class ShellWindow : public content::NotificationObserver,
static SkRegion* RawDraggableRegionsToSkRegion(
const std::vector<extensions::DraggableRegion>& regions);
+ // The constructor and Init methods are public for constructing a ShellWindow
+ // with a non-standard render interface (e.g. v1 apps using Ash Panels).
+ // Normally ShellWindow::Create should be used.
+ ShellWindow(Profile* profile, const extensions::Extension* extension);
+
+ // Initializes the render interface, web contents, and native window.
+ // |shell_window_contents| will become owned by ShellWindow.
+ void Init(const GURL& url,
+ ShellWindowContents* shell_window_contents,
+ const CreateParams& params);
+
+
const std::string& window_key() const { return window_key_; }
const SessionID& session_id() const { return session_id_; }
const extensions::Extension* extension() const { return extension_; }
- content::WebContents* web_contents() const { return web_contents_.get(); }
+ content::WebContents* web_contents() const;
WindowType window_type() const { return window_type_; }
Profile* profile() const { return profile_; }
const gfx::Image& app_icon() const { return app_icon_; }
@@ -107,7 +144,7 @@ class ShellWindow : public content::NotificationObserver,
// NativeAppWindows should call this to determine what the window's title
// is on startup and from within UpdateWindowTitle().
- virtual string16 GetTitle() const;
+ string16 GetTitle() const;
// Call to notify ShellRegistry and delete the window. Subclasses should
// invoke this method instead of using "delete this".
@@ -120,22 +157,17 @@ class ShellWindow : public content::NotificationObserver,
// Specifies a url for the launcher icon.
void SetAppIconUrl(const GURL& icon_url);
+ // Called from the render interface to modify the draggable regions.
+ void UpdateDraggableRegions(
+ const std::vector<extensions::DraggableRegion>& regions);
+
protected:
- ShellWindow(Profile* profile,
- const extensions::Extension* extension);
virtual ~ShellWindow();
private:
// PlatformAppBrowserTest needs access to web_contents()
friend class extensions::PlatformAppBrowserTest;
- // Instantiates a platform-specific ShellWindow subclass (one implementation
- // per platform). Public users of ShellWindow should use ShellWindow::Create.
- void Init(const GURL& url, const CreateParams& params);
-
- // content::WebContentsObserver implementation.
- virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
-
// content::WebContentsDelegate implementation.
virtual void CloseContents(content::WebContents* contents) OVERRIDE;
virtual bool ShouldSuppressDialogs() OVERRIDE;
@@ -177,14 +209,6 @@ class ShellWindow : public content::NotificationObserver,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
- // ExtensionFunctionDispatcher::Delegate implementation.
- virtual extensions::WindowController* GetExtensionWindowController() const
- OVERRIDE;
- virtual content::WebContents* GetAssociatedWebContents() const OVERRIDE;
-
- // Message handlers.
- void OnRequest(const ExtensionHostMsg_Request_Params& params);
-
// Helper method to add a message to the renderer's DevTools console.
void AddMessageToDevToolsConsole(content::ConsoleMessageLevel level,
const std::string& message);
@@ -192,9 +216,6 @@ class ShellWindow : public content::NotificationObserver,
// Saves the window geometry/position.
void SaveWindowPosition();
- virtual void UpdateDraggableRegions(
- const std::vector<extensions::DraggableRegion>& regions);
-
// Load the app's image, firing a load state change when loaded.
void UpdateExtensionAppIcon();
@@ -222,10 +243,8 @@ class ShellWindow : public content::NotificationObserver,
std::string window_key_;
const SessionID session_id_;
- scoped_ptr<content::WebContents> web_contents_;
WindowType window_type_;
content::NotificationRegistrar registrar_;
- ExtensionFunctionDispatcher extension_function_dispatcher_;
// Icon shown in the task bar.
gfx::Image app_icon_;
@@ -235,6 +254,7 @@ class ShellWindow : public content::NotificationObserver,
GURL app_icon_url_;
scoped_ptr<NativeAppWindow> native_app_window_;
+ scoped_ptr<ShellWindowContents> shell_window_contents_;
base::WeakPtrFactory<ShellWindow> weak_ptr_factory_;
diff --git a/chrome/browser/ui/panels/panel.cc b/chrome/browser/ui/panels/panel.cc
index c63aac8..77ec909 100644
--- a/chrome/browser/ui/panels/panel.cc
+++ b/chrome/browser/ui/panels/panel.cc
@@ -54,6 +54,8 @@ class PanelExtensionWindowController : public extensions::WindowController {
virtual std::string GetWindowTypeText() const OVERRIDE;
virtual base::DictionaryValue* CreateWindowValueWithTabs(
const extensions::Extension* extension) const OVERRIDE;
+ virtual base::DictionaryValue* CreateTabValue(
+ const extensions::Extension* extension, int tab_index) const OVERRIDE;
virtual bool CanClose(Reason* reason) const OVERRIDE;
virtual void SetFullscreenMode(bool is_fullscreen,
const GURL& extension_url) const OVERRIDE;
@@ -90,29 +92,8 @@ PanelExtensionWindowController::CreateWindowValueWithTabs(
base::DictionaryValue* result = CreateWindowValue();
DCHECK(IsVisibleToExtension(extension));
- content::WebContents* web_contents = panel_->GetWebContents();
- if (web_contents) {
- DictionaryValue* tab_value = new DictionaryValue();
- tab_value->SetInteger(extensions::tabs_constants::kIdKey,
- SessionID::IdForTab(web_contents));
- tab_value->SetInteger(extensions::tabs_constants::kIndexKey, 0);
- tab_value->SetInteger(extensions::tabs_constants::kWindowIdKey,
- SessionID::IdForWindowContainingTab(web_contents));
- tab_value->SetString(
- extensions::tabs_constants::kUrlKey, web_contents->GetURL().spec());
- tab_value->SetString(extensions::tabs_constants::kStatusKey,
- ExtensionTabUtil::GetTabStatusText(web_contents->IsLoading()));
- tab_value->SetBoolean(
- extensions::tabs_constants::kActiveKey, panel_->IsActive());
- tab_value->SetBoolean(extensions::tabs_constants::kSelectedKey, true);
- tab_value->SetBoolean(extensions::tabs_constants::kHighlightedKey, true);
- tab_value->SetBoolean(extensions::tabs_constants::kPinnedKey, false);
- tab_value->SetString(
- extensions::tabs_constants::kTitleKey, web_contents->GetTitle());
- tab_value->SetBoolean(
- extensions::tabs_constants::kIncognitoKey,
- web_contents->GetBrowserContext()->IsOffTheRecord());
-
+ DictionaryValue* tab_value = CreateTabValue(extension, 0);
+ if (tab_value) {
base::ListValue* tab_list = new ListValue();
tab_list->Append(tab_value);
result->Set(extensions::tabs_constants::kTabsKey, tab_list);
@@ -120,6 +101,40 @@ PanelExtensionWindowController::CreateWindowValueWithTabs(
return result;
}
+base::DictionaryValue* PanelExtensionWindowController::CreateTabValue(
+ const extensions::Extension* extension, int tab_index) const {
+ if (tab_index > 0)
+ return NULL;
+
+ content::WebContents* web_contents = panel_->GetWebContents();
+ if (!web_contents)
+ return NULL;
+
+ DCHECK(IsVisibleToExtension(extension));
+ DictionaryValue* tab_value = new DictionaryValue();
+ tab_value->SetInteger(extensions::tabs_constants::kIdKey,
+ SessionID::IdForTab(web_contents));
+ tab_value->SetInteger(extensions::tabs_constants::kIndexKey, 0);
+ tab_value->SetInteger(extensions::tabs_constants::kWindowIdKey,
+ SessionID::IdForWindowContainingTab(web_contents));
+ tab_value->SetString(
+ extensions::tabs_constants::kUrlKey, web_contents->GetURL().spec());
+ tab_value->SetString(extensions::tabs_constants::kStatusKey,
+ ExtensionTabUtil::GetTabStatusText(
+ web_contents->IsLoading()));
+ tab_value->SetBoolean(
+ extensions::tabs_constants::kActiveKey, panel_->IsActive());
+ tab_value->SetBoolean(extensions::tabs_constants::kSelectedKey, true);
+ tab_value->SetBoolean(extensions::tabs_constants::kHighlightedKey, true);
+ tab_value->SetBoolean(extensions::tabs_constants::kPinnedKey, false);
+ tab_value->SetString(
+ extensions::tabs_constants::kTitleKey, web_contents->GetTitle());
+ tab_value->SetBoolean(
+ extensions::tabs_constants::kIncognitoKey,
+ web_contents->GetBrowserContext()->IsOffTheRecord());
+ return tab_value;
+}
+
bool PanelExtensionWindowController::CanClose(Reason* reason) const {
return true;
}
diff --git a/chrome/browser/ui/views/extensions/native_app_window_views.h b/chrome/browser/ui/views/extensions/native_app_window_views.h
index f59184c..1fc797a 100644
--- a/chrome/browser/ui/views/extensions/native_app_window_views.h
+++ b/chrome/browser/ui/views/extensions/native_app_window_views.h
@@ -9,6 +9,7 @@
#include "chrome/browser/ui/extensions/native_app_window.h"
#include "chrome/browser/ui/extensions/shell_window.h"
#include "chrome/browser/ui/views/unhandled_keyboard_event_handler.h"
+#include "content/public/browser/web_contents_observer.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/rect.h"
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi
index b78dbce..88f9a34 100644
--- a/chrome/chrome_browser_extensions.gypi
+++ b/chrome/chrome_browser_extensions.gypi
@@ -468,6 +468,8 @@
'browser/extensions/app_sync_bundle.h',
'browser/extensions/app_sync_data.cc',
'browser/extensions/app_sync_data.h',
+ 'browser/extensions/app_window_contents.cc',
+ 'browser/extensions/app_window_contents.h',
'browser/extensions/blacklist.cc',
'browser/extensions/blacklist.h',
'browser/extensions/blocked_actions.cc',
@@ -743,6 +745,12 @@
'browser/extensions/api/terminal/terminal_private_api.h',
],
}],
+ ['use_ash==1', {
+ 'sources': [
+ 'browser/extensions/api/tabs/ash_panel_contents.cc',
+ 'browser/extensions/api/tabs/ash_panel_contents.h',
+ ],
+ }],
['enable_extensions==0', {
'sources/': [
# Handle files in browser/extensions/api. Exclude everything by default, white list