summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-17 18:20:31 +0000
committerrafaelw@chromium.org <rafaelw@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-17 18:20:31 +0000
commit01f829ab3cc802b79942f5a988f6a72e7a2b594d (patch)
tree8d5566ebfa133239e7947cac02b685df95d5b66f /chrome/browser
parent5715c63e814adcf7d0515ea08c16955d49615a33 (diff)
downloadchromium_src-01f829ab3cc802b79942f5a988f6a72e7a2b594d.zip
chromium_src-01f829ab3cc802b79942f5a988f6a72e7a2b594d.tar.gz
chromium_src-01f829ab3cc802b79942f5a988f6a72e7a2b594d.tar.bz2
Initial support for inspecting extension popups.
The primary change in this CL is a refactor which makes ExtensionPopup a bit more self-contained WRT its clients. It adds the ability to specify an "inspect_with_devtools" flag to its Show() method which will cause the popup to remain open regardless of losing focus and to focus a devtools window on the popup's render view host. This CL also pulls apart some aspects of the extension_popup_api from ExtensionFunctionDispatcher and ExtensionHost. Still remaining to be done are: 1) Also the popup to stay open when the host window drags (it current closes) 2) Support for GTK 3) Support for Mac BUG=24477 Review URL: http://codereview.chromium.org/1001002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@41854 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/debugger/devtools_manager.cc6
-rw-r--r--chrome/browser/extensions/extension_action_context_menu_model.cc37
-rw-r--r--chrome/browser/extensions/extension_action_context_menu_model.h28
-rw-r--r--chrome/browser/extensions/extension_dom_ui.h4
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc12
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.h5
-rw-r--r--chrome/browser/extensions/extension_host.h12
-rw-r--r--chrome/browser/extensions/extension_popup_api.cc117
-rw-r--r--chrome/browser/extensions/extension_popup_host.cc202
-rw-r--r--chrome/browser/extensions/extension_popup_host.h113
-rw-r--r--chrome/browser/gtk/browser_actions_toolbar_gtk.cc5
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.cc4
-rw-r--r--chrome/browser/views/browser_actions_container.cc116
-rw-r--r--chrome/browser/views/browser_actions_container.h32
-rw-r--r--chrome/browser/views/extensions/browser_action_overflow_menu_controller.cc10
-rw-r--r--chrome/browser/views/extensions/extension_action_context_menu.cc8
-rw-r--r--chrome/browser/views/extensions/extension_action_context_menu.h8
-rw-r--r--chrome/browser/views/extensions/extension_popup.cc118
-rw-r--r--chrome/browser/views/extensions/extension_popup.h54
-rw-r--r--chrome/browser/views/infobars/extension_infobar.cc10
-rw-r--r--chrome/browser/views/location_bar_view.cc81
-rw-r--r--chrome/browser/views/location_bar_view.h28
22 files changed, 455 insertions, 555 deletions
diff --git a/chrome/browser/debugger/devtools_manager.cc b/chrome/browser/debugger/devtools_manager.cc
index f55dbba..fe3462e 100644
--- a/chrome/browser/debugger/devtools_manager.cc
+++ b/chrome/browser/debugger/devtools_manager.cc
@@ -171,6 +171,12 @@ void DevToolsManager::ClientHostClosing(DevToolsClientHost* host) {
}
return;
}
+
+ NotificationService::current()->Notify(
+ NotificationType::DEVTOOLS_WINDOW_CLOSING,
+ Source<Profile>(inspected_rvh->site_instance()->GetProcess()->profile()),
+ Details<RenderViewHost>(inspected_rvh));
+
SendDetachToAgent(inspected_rvh);
inspected_rvh_to_client_host_.erase(inspected_rvh);
diff --git a/chrome/browser/extensions/extension_action_context_menu_model.cc b/chrome/browser/extensions/extension_action_context_menu_model.cc
index 40b49b7..fa49c4e 100644
--- a/chrome/browser/extensions/extension_action_context_menu_model.cc
+++ b/chrome/browser/extensions/extension_action_context_menu_model.cc
@@ -7,10 +7,14 @@
#include "app/l10n_util.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_process.h"
+#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/extensions/extensions_service.h"
+#include "chrome/browser/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_action.h"
#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "grit/generated_resources.h"
@@ -20,20 +24,29 @@ enum MenuEntries {
DISABLE,
UNINSTALL,
MANAGE,
+ INSPECT_POPUP
};
ExtensionActionContextMenuModel::ExtensionActionContextMenuModel(
- Extension* extension)
+ Extension* extension, ExtensionAction* extension_action, PrefService* prefs,
+ MenuDelegate* delegate)
: ALLOW_THIS_IN_INITIALIZER_LIST(SimpleMenuModel(this)),
- extension_(extension) {
+ extension_(extension),
+ extension_action_(extension_action),
+ delegate_(delegate) {
AddItem(NAME, UTF8ToUTF16(extension->name()));
AddSeparator();
AddItemWithStringId(CONFIGURE, IDS_EXTENSIONS_OPTIONS);
AddItemWithStringId(DISABLE, IDS_EXTENSIONS_DISABLE);
AddItemWithStringId(UNINSTALL, IDS_EXTENSIONS_UNINSTALL);
AddSeparator();
-
AddItemWithStringId(MANAGE, IDS_MANAGE_EXTENSIONS);
+
+ if (extension_ && delegate_ && prefs &&
+ prefs->GetBoolean(prefs::kExtensionsUIDeveloperMode)) {
+ AddSeparator();
+ AddItemWithStringId(INSPECT_POPUP, IDS_EXTENSION_ACTION_INSPECT_POPUP);
+ }
}
ExtensionActionContextMenuModel::~ExtensionActionContextMenuModel() {
@@ -52,6 +65,19 @@ bool ExtensionActionContextMenuModel::IsCommandIdEnabled(int command_id) const {
// homepage url, so we just disable this menu item on those cases, at least
// for now.
return extension_->update_url().DomainIs("google.com");
+ } else if (command_id == INSPECT_POPUP) {
+ if (!delegate_ || !extension_)
+ return false;
+ Browser* browser = BrowserList::GetLastActive();
+ if (!browser)
+ return false;
+ TabContents* contents = browser->GetSelectedTabContents();
+ if (!contents)
+ return false;
+
+ // Different tabs can have different popups set. We need to make sure we
+ // only enable the menu item if the current tab has a popup.
+ return (extension_action_->HasPopup(ExtensionTabUtil::GetTabId(contents)));
}
return true;
}
@@ -97,6 +123,11 @@ void ExtensionActionContextMenuModel::ExecuteCommand(int command_id) {
SINGLETON_TAB, PageTransition::LINK);
break;
}
+ case INSPECT_POPUP: {
+ if (delegate_)
+ delegate_->ShowPopupForDevToolsWindow(extension_, extension_action_);
+ break;
+ }
default:
NOTREACHED() << "Unknown option";
break;
diff --git a/chrome/browser/extensions/extension_action_context_menu_model.h b/chrome/browser/extensions/extension_action_context_menu_model.h
index 1a8e664..a35d269 100644
--- a/chrome/browser/extensions/extension_action_context_menu_model.h
+++ b/chrome/browser/extensions/extension_action_context_menu_model.h
@@ -9,6 +9,8 @@
#include "chrome/browser/extensions/extension_install_ui.h"
class Extension;
+class ExtensionAction;
+class PrefService;
// The menu model for the context menu for extension action icons (browser and
// page actions).
@@ -17,7 +19,25 @@ class ExtensionActionContextMenuModel
public menus::SimpleMenuModel::Delegate,
public ExtensionInstallUI::Delegate {
public:
- explicit ExtensionActionContextMenuModel(Extension* extension);
+ // Delegate to handle menu commands.
+ class MenuDelegate {
+ public:
+ // Called when the user selects the menu item which requests that the
+ // popup be shown and inspected.
+ virtual void ShowPopupForDevToolsWindow(Extension* extension,
+ ExtensionAction* extension_action) {
+ }
+ };
+
+ // |extension_action|, |prefs|, & |delegate| call all be NULL. If valid
+ // values are provided for all three, and prefs::kExtensionsUIDeveloperMode
+ // is enabled in the PrefService, a menu item will be shown for "Inspect
+ // Popup" which, when selected, will cause ShowPopupForDevToolsWindow() to be
+ // called on |delegate|.
+ ExtensionActionContextMenuModel(Extension* extension,
+ ExtensionAction* extension_action,
+ PrefService* prefs,
+ MenuDelegate* delegate);
~ExtensionActionContextMenuModel();
// SimpleMenuModel behavior overrides.
@@ -35,6 +55,12 @@ class ExtensionActionContextMenuModel
// The extension we are displaying the context menu for.
Extension* extension_;
+ // The extension action we are displaying the context menu for.
+ ExtensionAction* extension_action_;
+
+ // The delegate which handles the 'inspect popup' menu command.
+ MenuDelegate* delegate_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionActionContextMenuModel);
};
diff --git a/chrome/browser/extensions/extension_dom_ui.h b/chrome/browser/extensions/extension_dom_ui.h
index fd98355..54de39c 100644
--- a/chrome/browser/extensions/extension_dom_ui.h
+++ b/chrome/browser/extensions/extension_dom_ui.h
@@ -11,7 +11,6 @@
#include "chrome/browser/dom_ui/dom_ui.h"
#include "chrome/browser/extensions/extension_bookmark_manager_api.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
-#include "chrome/browser/extensions/extension_popup_host.h"
#include "chrome/common/extensions/extension.h"
class ListValue;
@@ -25,7 +24,6 @@ class TabContents;
// the main tab contents area.
class ExtensionDOMUI
: public DOMUI,
- public ExtensionPopupHost::PopupDelegate,
public ExtensionFunctionDispatcher::Delegate {
public:
explicit ExtensionDOMUI(TabContents* tab_contents);
@@ -47,8 +45,6 @@ class ExtensionDOMUI
virtual ExtensionDOMUI* GetExtensionDOMUI() { return this; }
virtual gfx::NativeWindow GetFrameNativeWindow();
- // ExtensionPopupHost::Delegate
- virtual Browser* GetBrowser() const { return GetBrowser(true); }
virtual RenderViewHost* GetRenderViewHost();
virtual Profile* GetProfile();
virtual gfx::NativeView GetNativeViewOfHost();
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 1e6bee1..640725d 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -321,18 +321,6 @@ Browser* ExtensionFunctionDispatcher::GetBrowser(bool include_incognito) {
return delegate_->GetBrowser(include_incognito);
}
-ExtensionPopupHost* ExtensionFunctionDispatcher::GetPopupHost() {
- ExtensionHost* extension_host = GetExtensionHost();
- if (extension_host) {
- DCHECK(!GetExtensionDOMUI()) <<
- "Function dispatcher registered in too many environments.";
- return extension_host->popup_host();
- } else {
- ExtensionDOMUI* dom_ui = GetExtensionDOMUI();
- return dom_ui->popup_host();
- }
-}
-
ExtensionHost* ExtensionFunctionDispatcher::GetExtensionHost() {
return delegate_->GetExtensionHost();
}
diff --git a/chrome/browser/extensions/extension_function_dispatcher.h b/chrome/browser/extensions/extension_function_dispatcher.h
index d87d22c..6fe4ba0 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.h
+++ b/chrome/browser/extensions/extension_function_dispatcher.h
@@ -18,7 +18,6 @@ class Extension;
class ExtensionDOMUI;
class ExtensionFunction;
class ExtensionHost;
-class ExtensionPopupHost;
class Profile;
class RenderViewHost;
class RenderViewHostDelegate;
@@ -96,10 +95,6 @@ class ExtensionFunctionDispatcher {
// we will fall back to a regular browser window or NULL if unavailable.
Browser* GetBrowser(bool include_incognito);
- // Get the extension popup hosting environment for the ExtensionHost
- // or ExtensionDOMUI associted with this dispatcher.
- ExtensionPopupHost* GetPopupHost();
-
// Gets the ExtensionHost associated with this object. In the case of
// tab hosted extension pages, this will return NULL.
ExtensionHost* GetExtensionHost();
diff --git a/chrome/browser/extensions/extension_host.h b/chrome/browser/extensions/extension_host.h
index 6d442fa..ad26e9f 100644
--- a/chrome/browser/extensions/extension_host.h
+++ b/chrome/browser/extensions/extension_host.h
@@ -10,7 +10,6 @@
#include "base/perftimer.h"
#include "base/scoped_ptr.h"
#include "chrome/browser/extensions/extension_function_dispatcher.h"
-#include "chrome/browser/extensions/extension_popup_host.h"
#include "chrome/browser/jsmessage_box_client.h"
#include "chrome/browser/renderer_host/render_view_host_delegate.h"
#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
@@ -37,8 +36,7 @@ struct WebPreferences;
// It handles setting up the renderer process, if needed, with special
// privileges available to extensions. It may have a view to be shown in the
// in the browser UI, or it may be hidden.
-class ExtensionHost : public ExtensionPopupHost::PopupDelegate,
- public RenderViewHostDelegate,
+class ExtensionHost : public RenderViewHostDelegate,
public RenderViewHostDelegate::View,
public ExtensionFunctionDispatcher::Delegate,
public NotificationObserver,
@@ -79,6 +77,10 @@ class ExtensionHost : public ExtensionPopupHost::PopupDelegate,
bool document_element_available() const {
return document_element_available_;
}
+ gfx::NativeView GetNativeViewOfHost() {
+ return view() ? view()->native_view() : NULL;
+ }
+
Profile* profile() const { return profile_; }
ViewType::Type extension_host_type() const { return extension_host_type_; }
@@ -204,12 +206,8 @@ class ExtensionHost : public ExtensionPopupHost::PopupDelegate,
virtual Browser* GetBrowser(bool include_incognito) const;
virtual ExtensionHost* GetExtensionHost() { return this; }
- // ExtensionPopupHost::Delegate
virtual Browser* GetBrowser() const { return GetBrowser(true); }
virtual RenderViewHost* GetRenderViewHost() { return render_view_host(); }
- virtual gfx::NativeView GetNativeViewOfHost() {
- return view() ? view()->native_view() : NULL;
- }
// Handles keyboard events that were not handled by HandleKeyboardEvent().
// Platform specific implementation may override this method to handle the
diff --git a/chrome/browser/extensions/extension_popup_api.cc b/chrome/browser/extensions/extension_popup_api.cc
index c70747d..504a7a07 100644
--- a/chrome/browser/extensions/extension_popup_api.cc
+++ b/chrome/browser/extensions/extension_popup_api.cc
@@ -21,9 +21,12 @@
#include "gfx/point.h"
#if defined(TOOLKIT_VIEWS)
+#include "chrome/browser/renderer_host/render_view_host.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/views/extensions/extension_popup.h"
#include "views/view.h"
-#endif
+#include "views/focus/focus_manager.h"
+#endif // TOOLKIT_VIEWS
namespace extension_popup_module_events {
@@ -53,6 +56,97 @@ const char kRectangleChrome[] = "rectangle";
}; // namespace
+#if defined(TOOLKIT_VIEWS)
+// ExtensionPopupHost objects implement the environment necessary to host
+// an ExtensionPopup views for the popup api. Its main job is to handle
+// its lifetime and to fire the popup-closed event when the popup is closed.
+// Because the close-on-focus-lost behavior is different from page action
+// and browser action, it also manages its own focus change listening. The
+// difference in close-on-focus-lost is that in the page action and browser
+// action cases, the popup closes when the focus leaves the popup or any of its
+// children. In this case, the popup closes when the focus leaves the popups
+// containing view or any of *its* children.
+class ExtensionPopupHost : public ExtensionPopup::Observer,
+ public views::WidgetFocusChangeListener,
+ public base::RefCounted<ExtensionPopupHost> {
+ public:
+ explicit ExtensionPopupHost(ExtensionFunctionDispatcher* dispatcher)
+ : dispatcher_(dispatcher), popup_(NULL) {
+ AddRef(); // Balanced in ExtensionPopupClosed().
+ views::FocusManager::GetWidgetFocusManager()->AddFocusChangeListener(this);
+ }
+
+ ~ExtensionPopupHost() {
+ views::FocusManager::GetWidgetFocusManager()->
+ RemoveFocusChangeListener(this);
+ }
+
+ void set_popup(ExtensionPopup* popup) {
+ popup_ = popup;
+ }
+
+ // Overriden from ExtensionPopup::Observer
+ virtual void ExtensionPopupClosed(ExtensionPopup* popup) {
+ RenderViewHost* render_view_host = dispatcher_->GetExtensionHost() ?
+ dispatcher_->GetExtensionHost()->render_view_host() :
+ dispatcher_->GetExtensionDOMUI()->GetRenderViewHost();
+
+ PopupEventRouter::OnPopupClosed(dispatcher_->profile(),
+ render_view_host->routing_id());
+ dispatcher_ = NULL;
+ Release(); // Balanced in ctor.
+ }
+
+ // Overriden from views::WidgetFocusChangeListener
+ virtual void NativeFocusWillChange(gfx::NativeView focused_before,
+ gfx::NativeView focused_now) {
+ // If no view is to be focused, then Chrome was deactivated, so hide the
+ // popup.
+ if (focused_now) {
+ gfx::NativeView host_view = dispatcher_->GetExtensionHost() ?
+ dispatcher_->GetExtensionHost()->GetNativeViewOfHost() :
+ dispatcher_->GetExtensionDOMUI()->GetNativeViewOfHost();
+
+ // If the widget hosting the popup contains the newly focused view, then
+ // don't dismiss the pop-up.
+ views::Widget* popup_root_widget = popup_->host()->view()->GetWidget();
+ if (popup_root_widget &&
+ popup_root_widget->ContainsNativeView(focused_now))
+ return;
+
+ // If the widget or RenderWidgetHostView hosting the extension that
+ // launched the pop-up is receiving focus, then don't dismiss the popup.
+ views::Widget* host_widget =
+ views::Widget::GetWidgetFromNativeView(host_view);
+ if (host_widget && host_widget->ContainsNativeView(focused_now))
+ return;
+
+ RenderWidgetHostView* render_host_view =
+ RenderWidgetHostView::GetRenderWidgetHostViewFromNativeView(
+ host_view);
+ if (render_host_view &&
+ render_host_view->ContainsNativeView(focused_now))
+ return;
+ }
+
+ // We are careful here to let the current event loop unwind before
+ // causing the popup to be closed.
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(popup_,
+ &ExtensionPopup::Close));
+ }
+
+ private:
+ // A pointer to the dispatcher that handled the request that opened this
+ // popup view.
+ ExtensionFunctionDispatcher* dispatcher_;
+
+ // A pointer to the popup.
+ ExtensionPopup* popup_;
+
+ DISALLOW_COPY_AND_ASSIGN(ExtensionPopupHost);
+};
+#endif // TOOLKIT_VIEWS
+
PopupShowFunction::PopupShowFunction()
#if defined (TOOLKIT_VIEWS)
: popup_(NULL)
@@ -157,19 +251,24 @@ bool PopupShowFunction::RunImpl() {
BubbleBorder::ArrowLocation arrow_location =
(NULL != dispatcher()->GetExtensionHost()) ? BubbleBorder::BOTTOM_LEFT :
BubbleBorder::TOP_LEFT;
- popup_ = ExtensionPopup::Show(url, GetBrowser(),
+
+ // ExtensionPopupHost manages it's own lifetime.
+ ExtensionPopupHost* popup_host = new ExtensionPopupHost(dispatcher());
+ popup_ = ExtensionPopup::Show(url,
+ GetBrowser(),
dispatcher()->profile(),
dispatcher()->GetFrameNativeWindow(),
rect,
arrow_location,
give_focus,
- chrome);
-
- ExtensionPopupHost* popup_host = dispatcher()->GetPopupHost();
- DCHECK(popup_host);
-
- popup_host->set_child_popup(popup_);
- popup_->set_delegate(popup_host);
+ false, // inspect_with_devtools
+ chrome,
+ popup_host); // ExtensionPopup::Observer
+
+ // popup_host will handle focus change listening and close the popup when
+ // focus leaves the containing views hierarchy.
+ popup_->set_close_on_lost_focus(false);
+ popup_host->set_popup(popup_);
#endif // defined(TOOLKIT_VIEWS)
return true;
}
diff --git a/chrome/browser/extensions/extension_popup_host.cc b/chrome/browser/extensions/extension_popup_host.cc
deleted file mode 100644
index ec679e3..0000000
--- a/chrome/browser/extensions/extension_popup_host.cc
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright (c) 2009 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/extension_popup_host.h"
-
-#include "base/message_loop.h"
-#if defined(TOOLKIT_VIEWS)
-#include "chrome/browser/extensions/extension_popup_api.h"
-#endif
-#include "chrome/browser/profile.h"
-#include "chrome/browser/browser.h"
-#include "chrome/browser/renderer_host/render_view_host.h"
-#include "chrome/browser/renderer_host/render_widget_host_view.h"
-#if defined(TOOLKIT_VIEWS)
-#include "chrome/browser/views/extensions/extension_popup.h"
-#endif
-#include "chrome/common/notification_details.h"
-#include "chrome/common/notification_source.h"
-#include "chrome/common/notification_type.h"
-#if defined(TOOLKIT_VIEWS)
-#include "views/focus/focus_manager.h"
-#include "views/widget/root_view.h"
-#endif
-
-#if defined(TOOLKIT_VIEWS)
-// A helper class that monitors native focus change events. Because the views
-// FocusManager does not listen for view-change notification across
-// native-windows, we need to use native-listener utilities.
-class ExtensionPopupHost::PopupFocusListener
- : public views::WidgetFocusChangeListener {
- public:
- // Constructs and registers a new PopupFocusListener for the given
- // |popup_host|.
- explicit PopupFocusListener(ExtensionPopupHost* popup_host)
- : popup_host_(popup_host) {
- views::FocusManager::GetWidgetFocusManager()->AddFocusChangeListener(this);
- }
-
- virtual ~PopupFocusListener() {
- views::FocusManager::GetWidgetFocusManager()->
- RemoveFocusChangeListener(this);
- }
-
- virtual void NativeFocusWillChange(gfx::NativeView focused_before,
- gfx::NativeView focused_now) {
- // If no view is to be focused, then Chrome was deactivated, so hide the
- // popup.
- if (!focused_now) {
- popup_host_->DismissPopupAsync();
- return;
- }
-
- gfx::NativeView host_view = popup_host_->delegate()->GetNativeViewOfHost();
-
- // If the widget hosting the popup contains the newly focused view, then
- // don't dismiss the pop-up.
- views::Widget* popup_root_widget =
- popup_host_->child_popup()->host()->view()->GetWidget();
- if (popup_root_widget &&
- popup_root_widget->ContainsNativeView(focused_now)) {
- return;
- }
-
- // If the widget or RenderWidgetHostView hosting the extension that
- // launched the pop-up is receiving focus, then don't dismiss the popup.
- views::Widget* host_widget =
- views::Widget::GetWidgetFromNativeView(host_view);
- if (host_widget && host_widget->ContainsNativeView(focused_now)) {
- return;
- }
-
- RenderWidgetHostView* render_host_view =
- RenderWidgetHostView::GetRenderWidgetHostViewFromNativeView(
- host_view);
- if (render_host_view &&
- render_host_view->ContainsNativeView(focused_now)) {
- return;
- }
-
- popup_host_->DismissPopupAsync();
- }
-
- private:
- ExtensionPopupHost* popup_host_;
- DISALLOW_COPY_AND_ASSIGN(PopupFocusListener);
-};
-#endif // if defined(TOOLKIT_VIEWS)
-
-
-ExtensionPopupHost::PopupDelegate::~PopupDelegate() {
- // If the PopupDelegate is being torn down, then make sure to reset the
- // cached pointer in the host to prevent access to a stale pointer.
- if (popup_host_.get())
- popup_host_->RevokeDelegate();
-}
-
-ExtensionPopupHost* ExtensionPopupHost::PopupDelegate::popup_host() {
- if (!popup_host_.get())
- popup_host_.reset(new ExtensionPopupHost(this));
-
- return popup_host_.get();
-}
-
-Profile* ExtensionPopupHost::PopupDelegate::GetProfile() {
- // If there is a browser present, return the profile associated with it.
- // When hosting a view in an ExternalTabContainer, it is possible to have
- // no Browser instance.
- Browser* browser = GetBrowser();
- if (browser) {
- return browser->profile();
- }
-
- return NULL;
-}
-
-ExtensionPopupHost::ExtensionPopupHost(PopupDelegate* delegate)
- : // NO LINT
-#if defined(TOOLKIT_VIEWS)
- listener_(NULL),
- child_popup_(NULL),
-#endif
- delegate_(delegate),
- ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
- DCHECK(delegate_);
-
- // Listen for view close requests, so that we can dismiss a hosted pop-up
- // view, if necessary.
- Profile* profile = delegate_->GetProfile();
- DCHECK(profile);
- registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
- Source<Profile>(profile));
-}
-
-ExtensionPopupHost::~ExtensionPopupHost() {
- DismissPopup();
-}
-
-#if defined(TOOLKIT_VIEWS)
-void ExtensionPopupHost::set_child_popup(ExtensionPopup* popup) {
- // An extension may only have one popup active at a given time.
- DismissPopup();
- if (popup)
- listener_.reset(new PopupFocusListener(this));
-
- child_popup_ = popup;
-}
-
-void ExtensionPopupHost::BubbleBrowserWindowMoved(BrowserBubble* bubble) {
- DismissPopupAsync();
-}
-
-void ExtensionPopupHost::BubbleBrowserWindowClosing(BrowserBubble* bubble) {
- DismissPopupAsync();
-}
-#endif // defined(TOOLKIT_VIEWS)
-
-void ExtensionPopupHost::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- if (type == NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE) {
-#if defined(TOOLKIT_VIEWS)
- // If we aren't the host of the popup, then disregard the notification.
- if (!child_popup_ ||
- Details<ExtensionHost>(child_popup_->host()) != details) {
- return;
- }
- DismissPopup();
-#endif
- } else {
- NOTREACHED();
- }
-}
-
-void ExtensionPopupHost::DismissPopup() {
-#if defined(TOOLKIT_VIEWS)
- listener_.reset(NULL);
- if (child_popup_) {
- child_popup_->Hide();
- child_popup_->DetachFromBrowser();
- delete child_popup_;
- child_popup_ = NULL;
-
- if (delegate_) {
- PopupEventRouter::OnPopupClosed(
- delegate_->GetProfile(),
- delegate_->GetRenderViewHost()->routing_id());
- }
- }
-#endif // defined(TOOLKIT_VIEWS)
-}
-
-void ExtensionPopupHost::DismissPopupAsync() {
- // Dismiss the popup asynchronously, as we could be deep in a message loop
- // processing activations, and the focus manager may get confused if the
- // currently focused view is destroyed.
- method_factory_.RevokeAll();
- MessageLoop::current()->PostNonNestableTask(
- FROM_HERE,
- method_factory_.NewRunnableMethod(
- &ExtensionPopupHost::DismissPopup));
-}
diff --git a/chrome/browser/extensions/extension_popup_host.h b/chrome/browser/extensions/extension_popup_host.h
deleted file mode 100644
index 6f77b4d..0000000
--- a/chrome/browser/extensions/extension_popup_host.h
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (c) 2009 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_EXTENSION_POPUP_HOST_H_
-#define CHROME_BROWSER_EXTENSIONS_EXTENSION_POPUP_HOST_H_
-
-#include "base/scoped_ptr.h"
-#include "base/task.h"
-#include "build/build_config.h"
-#if defined(TOOLKIT_VIEWS)
-#include "chrome/browser/views/browser_bubble.h"
-#endif
-#include "chrome/common/notification_observer.h"
-#include "chrome/common/notification_registrar.h"
-#include "gfx/native_widget_types.h"
-
-#if defined(TOOLKIT_VIEWS)
-class ExtensionPopup;
-#endif
-
-class Browser;
-class Profile;
-class RenderViewHost;
-
-// ExtensionPopupHost objects implement the environment necessary to host
-// ExtensionPopup views. This class manages the creation and life-time
-// of extension pop-up views.
-class ExtensionPopupHost : // NOLINT
-#if defined(TOOLKIT_VIEWS)
- public BrowserBubble::Delegate,
-#endif
- public NotificationObserver {
- public:
- // Classes wishing to host pop-ups should inherit from this class, and
- // implement the virtual methods below. This class manages the lifetime
- // of an ExtensionPopupHost instance.
- class PopupDelegate {
- public:
- PopupDelegate() {}
- virtual ~PopupDelegate();
- virtual Browser* GetBrowser() const = 0;
- virtual RenderViewHost* GetRenderViewHost() = 0;
- virtual gfx::NativeView GetNativeViewOfHost() = 0;
- virtual Profile* GetProfile();
-
- // Constructs, or returns the existing ExtensionPopupHost instance.
- ExtensionPopupHost* popup_host();
-
- private:
- scoped_ptr<ExtensionPopupHost> popup_host_;
-
- DISALLOW_COPY_AND_ASSIGN(PopupDelegate);
- };
-
- explicit ExtensionPopupHost(PopupDelegate* delegate);
- virtual ~ExtensionPopupHost();
-
- PopupDelegate* delegate() { return delegate_; }
- void RevokeDelegate() { delegate_ = NULL; }
-
- // Dismiss the hosted pop-up, if one is present.
- void DismissPopup();
-
-#if defined(TOOLKIT_VIEWS)
- ExtensionPopup* child_popup() const { return child_popup_; }
- void set_child_popup(ExtensionPopup* popup);
-
- // BrowserBubble::Delegate implementation.
- // Called when the Browser Window that this bubble is attached to moves.
- virtual void BubbleBrowserWindowMoved(BrowserBubble* bubble);
-
- // Called with the Browser Window that this bubble is attached to is
- // about to close.
- virtual void BubbleBrowserWindowClosing(BrowserBubble* bubble);
-#endif // defined(TOOLKIT_VIEWS)
-
- // NotificationObserver implementation.
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- private:
- // Posts a task to the current thread's message-loop that will dismiss the
- // popup.
- void DismissPopupAsync();
-
-#if defined(TOOLKIT_VIEWS)
- // A native-view focus listener that monitors when the pop-up should be
- // dismissed due to focus change events.
- class PopupFocusListener;
- scoped_ptr<PopupFocusListener> listener_;
-
- // A popup view that is anchored to and owned by this ExtensionHost. However,
- // the popup contains its own separate ExtensionHost
- ExtensionPopup* child_popup_;
-#endif
-
- NotificationRegistrar registrar_;
-
- // Non-owning pointer to the delegate for this host.
- PopupDelegate* delegate_;
-
- // Boolean value used to ensure that the host only registers for event
- // notifications once.
- bool listeners_registered_;
-
- ScopedRunnableMethodFactory<ExtensionPopupHost> method_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ExtensionPopupHost);
-};
-
-#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_POPUP_HOST_H_
diff --git a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
index 621a42f..5ab13c6 100644
--- a/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
+++ b/chrome/browser/gtk/browser_actions_toolbar_gtk.cc
@@ -188,9 +188,12 @@ class BrowserActionButton : public NotificationObserver,
if (event->button.button != 3)
return FALSE;
+ // TODO(rafaelw): support inspecting popups.
if (!action->context_menu_model_.get()) {
action->context_menu_model_.reset(
- new ExtensionActionContextMenuModel(action->extension_));
+ new ExtensionActionContextMenuModel(action->extension_,
+ action->extension_->browser_action(),
+ action->toolbar_->browser()->profile()->GetPrefs(), NULL));
}
action->context_menu_.reset(
diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc
index 1d8c786..815bb2f 100644
--- a/chrome/browser/gtk/location_bar_view_gtk.cc
+++ b/chrome/browser/gtk/location_bar_view_gtk.cc
@@ -1217,8 +1217,10 @@ gboolean LocationBarViewGtk::PageActionViewGtk::OnButtonPressed(
Extension* extension = profile_->GetExtensionsService()->GetExtensionById(
page_action()->extension_id(), false);
+ // TODO(rafaelw): support inspecting popups.
if (!context_menu_model_.get())
- context_menu_model_.reset(new ExtensionActionContextMenuModel(extension));
+ context_menu_model_.reset(new ExtensionActionContextMenuModel(extension,
+ page_action_, profile_->GetPrefs(), NULL));
context_menu_.reset(
new MenuGtk(NULL, context_menu_model_.get()));
diff --git a/chrome/browser/views/browser_actions_container.cc b/chrome/browser/views/browser_actions_container.cc
index a8fa362..32f0f02 100644
--- a/chrome/browser/views/browser_actions_container.cc
+++ b/chrome/browser/views/browser_actions_container.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/browser_theme_provider.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/extensions/extension_browser_event_router.h"
+#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/extensions/extension_tabs_module.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
@@ -133,9 +134,9 @@ gfx::Insets BrowserActionButton::GetInsets() const {
return zero_inset;
}
-void BrowserActionButton::ButtonPressed(
- views::Button* sender, const views::Event& event) {
- panel_->OnBrowserActionExecuted(this);
+void BrowserActionButton::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
+ panel_->OnBrowserActionExecuted(this, false); // inspect_with_devtools
}
void BrowserActionButton::OnImageLoaded(SkBitmap* image, size_t index) {
@@ -198,7 +199,7 @@ GURL BrowserActionButton::GetPopupUrl() {
bool BrowserActionButton::Activate() {
if (IsPopup()) {
- panel_->OnBrowserActionExecuted(this);
+ panel_->OnBrowserActionExecuted(this, false); // inspect_with_devtools
// TODO(erikkay): Run a nested modal loop while the mouse is down to
// enable menu-like drag-select behavior.
@@ -224,7 +225,8 @@ bool BrowserActionButton::OnMousePressed(const views::MouseEvent& e) {
// Make the menu appear below the button.
point.Offset(0, height());
- panel_->GetContextMenu()->Run(extension(), point);
+ panel_->GetContextMenu()->Run(extension(), extension()->browser_action(),
+ panel_, panel_->profile()->GetPrefs(), point);
SetButtonNotPushed();
return false;
@@ -340,9 +342,6 @@ BrowserActionsContainer::BrowserActionsContainer(
if (!extension_service) // The |extension_service| can be NULL in Incognito.
return;
- registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
- Source<Profile>(profile_));
-
model_ = extension_service->toolbar_model();
model_->AddObserver(this);
@@ -484,29 +483,13 @@ void BrowserActionsContainer::OnBrowserActionVisibilityChanged() {
}
void BrowserActionsContainer::HidePopup() {
- if (popup_) {
- // This sometimes gets called via a timer (See BubbleLostFocus), so clear
- // the task factory in case one is pending.
- task_factory_.RevokeAll();
-
- // Save these variables in local temporaries since destroying the popup
- // calls BubbleLostFocus to be called, which will try to call HidePopup()
- // again if popup_ is non-null.
- ExtensionPopup* closing_popup = popup_;
- BrowserActionButton* closing_button = popup_button_;
- popup_ = NULL;
- popup_button_ = NULL;
-
- closing_popup->DetachFromBrowser();
- delete closing_popup;
- closing_button->SetButtonNotPushed();
- return;
- }
+ if (popup_)
+ popup_->Close();
}
void BrowserActionsContainer::TestExecuteBrowserAction(int index) {
BrowserActionButton* button = browser_action_views_[index]->button();
- OnBrowserActionExecuted(button);
+ OnBrowserActionExecuted(button, false); // inspect_with_devtools
}
void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) {
@@ -517,7 +500,7 @@ void BrowserActionsContainer::TestSetIconVisibilityCount(size_t icons) {
}
void BrowserActionsContainer::OnBrowserActionExecuted(
- BrowserActionButton* button) {
+ BrowserActionButton* button, bool inspect_with_devtools) {
ExtensionAction* browser_action = button->browser_action();
// Popups just display. No notification to the extension.
@@ -548,18 +531,15 @@ void BrowserActionsContainer::OnBrowserActionExecuted(
BubbleBorder::ArrowLocation arrow_location = UILayoutIsRightToLeft() ?
BubbleBorder::TOP_LEFT : BubbleBorder::TOP_RIGHT;
- popup_ = ExtensionPopup::Show(
- button->GetPopupUrl(),
- browser_,
- browser_->profile(),
- frame_window,
- rect,
- arrow_location,
+ popup_ = ExtensionPopup::Show(button->GetPopupUrl(), browser_,
+ browser_->profile(), frame_window, rect, arrow_location,
true, // Activate the popup window.
- ExtensionPopup::BUBBLE_CHROME);
- popup_->set_delegate(this);
+ inspect_with_devtools,
+ ExtensionPopup::BUBBLE_CHROME,
+ this); // ExtensionPopupDelegate
popup_button_ = button;
popup_button_->SetButtonPushed();
+
return;
}
@@ -809,54 +789,6 @@ void BrowserActionsContainer::MoveBrowserAction(
SchedulePaint();
}
-void BrowserActionsContainer::Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE:
- // If we aren't the host of the popup, then disregard the notification.
- if (!popup_ || Details<ExtensionHost>(popup_->host()) != details)
- return;
-
- HidePopup();
- break;
-
- default:
- NOTREACHED() << "Unexpected notification";
- }
-}
-
-void BrowserActionsContainer::BubbleBrowserWindowMoved(BrowserBubble* bubble) {
-}
-
-void BrowserActionsContainer::BubbleBrowserWindowClosing(
- BrowserBubble* bubble) {
- HidePopup();
-}
-
-void BrowserActionsContainer::BubbleGotFocus(BrowserBubble* bubble) {
- if (!popup_)
- return;
-
- // Forward the focus to the renderer.
- popup_->host()->render_view_host()->view()->Focus();
-}
-
-void BrowserActionsContainer::BubbleLostFocus(BrowserBubble* bubble,
- bool lost_focus_to_child) {
- // Don't close when we are losing focus to a child window, this is the case
- // for select popups and alert for example.
- if (!popup_ || lost_focus_to_child)
- return;
-
- // This is a bit annoying. If you click on the button that generated the
- // current popup, then we first get this lost focus message, and then
- // we get the click action. This results in the popup being immediately
- // shown again. To workaround this, we put in a delay.
- MessageLoop::current()->PostTask(FROM_HERE,
- task_factory_.NewRunnableMethod(&BrowserActionsContainer::HidePopup));
-}
-
void BrowserActionsContainer::RunMenu(View* source, const gfx::Point& pt) {
if (source == chevron_) {
overflow_menu_ = new BrowserActionOverflowMenuController(
@@ -1142,6 +1074,20 @@ void BrowserActionsContainer::NotifyMenuDeleted(
overflow_menu_ = NULL;
}
+void BrowserActionsContainer::ShowPopupForDevToolsWindow(Extension* extension,
+ ExtensionAction* extension_action) {
+ OnBrowserActionExecuted(GetBrowserActionView(extension)->button(),
+ true); // inspect_with_devtools
+}
+
+void BrowserActionsContainer::ExtensionPopupClosed(ExtensionPopup* popup) {
+ // ExtensionPopup is ref-counted, so we don't need to delete it.
+ DCHECK_EQ(popup_, popup);
+ popup_ = NULL;
+ popup_button_->SetButtonNotPushed();
+ popup_button_ = NULL;
+}
+
bool BrowserActionsContainer::ShouldDisplayBrowserAction(Extension* extension) {
// Only display incognito-enabled extensions while in incognito mode.
return (!profile_->IsOffTheRecord() ||
diff --git a/chrome/browser/views/browser_actions_container.h b/chrome/browser/views/browser_actions_container.h
index 1452358..bd25f897 100644
--- a/chrome/browser/views/browser_actions_container.h
+++ b/chrome/browser/views/browser_actions_container.h
@@ -11,11 +11,13 @@
#include "app/slide_animation.h"
#include "base/task.h"
+#include "chrome/browser/extensions/extension_action_context_menu_model.h"
#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/extensions/image_loading_tracker.h"
#include "chrome/browser/views/browser_bubble.h"
#include "chrome/browser/views/extensions/browser_action_overflow_menu_controller.h"
#include "chrome/browser/views/extensions/extension_action_context_menu.h"
+#include "chrome/browser/views/extensions/extension_popup.h"
#include "chrome/common/notification_observer.h"
#include "chrome/common/notification_registrar.h"
#include "views/controls/button/menu_button.h"
@@ -225,14 +227,15 @@ class BrowserActionView : public views::View {
////////////////////////////////////////////////////////////////////////////////
class BrowserActionsContainer
: public views::View,
- public NotificationObserver,
- public BrowserBubble::Delegate,
public views::ViewMenuDelegate,
public views::DragController,
public views::ResizeGripper::ResizeGripperDelegate,
public AnimationDelegate,
public ExtensionToolbarModel::Observer,
- public BrowserActionOverflowMenuController::Observer {
+ public BrowserActionOverflowMenuController::Observer,
+ public ExtensionActionContextMenuModel::MenuDelegate,
+ public ExtensionPopup::Observer {
+
friend class ShowFolderMenuTask;
public:
BrowserActionsContainer(Browser* browser, views::View* owner_view);
@@ -284,7 +287,8 @@ class BrowserActionsContainer
size_t VisibleBrowserActions() const;
// Called when the user clicks on the browser action icon.
- void OnBrowserActionExecuted(BrowserActionButton* button);
+ void OnBrowserActionExecuted(BrowserActionButton* button,
+ bool inspect_with_devtools);
// Overridden from views::View:
virtual gfx::Size GetPreferredSize();
@@ -302,17 +306,6 @@ class BrowserActionsContainer
virtual void OnDragExited();
virtual int OnPerformDrop(const views::DropTargetEvent& event);
- // Overridden from NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
- // BrowserBubble::Delegate methods.
- virtual void BubbleBrowserWindowMoved(BrowserBubble* bubble);
- virtual void BubbleBrowserWindowClosing(BrowserBubble* bubble);
- virtual void BubbleGotFocus(BrowserBubble* bubble);
- virtual void BubbleLostFocus(BrowserBubble* bubble, bool lost_focus_to_child);
-
// Overridden from views::ViewMenuDelegate:
virtual void RunMenu(View* source, const gfx::Point& pt);
@@ -336,6 +329,13 @@ class BrowserActionsContainer
virtual void NotifyMenuDeleted(
BrowserActionOverflowMenuController* controller);
+ // Overridden from ExtensionActionContextMenuModel::MenuDelegate
+ virtual void ShowPopupForDevToolsWindow(Extension* extension,
+ ExtensionAction* extension_action);
+
+ // Overriden from ExtensionPopup::Delegate
+ virtual void ExtensionPopupClosed(ExtensionPopup* popup);
+
// Moves a browser action with |id| to |new_index|.
void MoveBrowserAction(const std::string& extension_id, size_t new_index);
@@ -418,8 +418,6 @@ class BrowserActionsContainer
// this collection. Some extensions may be disabled in incognito windows.
BrowserActionViews browser_action_views_;
- NotificationRegistrar registrar_;
-
Profile* profile_;
// The Browser object the container is associated with.
diff --git a/chrome/browser/views/extensions/browser_action_overflow_menu_controller.cc b/chrome/browser/views/extensions/browser_action_overflow_menu_controller.cc
index f0bb80d..dbee697 100644
--- a/chrome/browser/views/extensions/browser_action_overflow_menu_controller.cc
+++ b/chrome/browser/views/extensions/browser_action_overflow_menu_controller.cc
@@ -7,6 +7,7 @@
#include "app/gfx/canvas.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/browser_list.h"
+#include "chrome/browser/profile.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/views/browser_actions_container.h"
#include "chrome/browser/views/extensions/browser_action_drag_data.h"
@@ -80,7 +81,8 @@ void BrowserActionOverflowMenuController::CancelMenu() {
void BrowserActionOverflowMenuController::ExecuteCommand(int id) {
BrowserActionView* view = (*views_)[start_index_ + id - 1];
- owner_->OnBrowserActionExecuted(view->button());
+ owner_->OnBrowserActionExecuted(view->button(),
+ false); // inspect_with_devtools
}
bool BrowserActionOverflowMenuController::ShowContextMenu(
@@ -90,7 +92,11 @@ bool BrowserActionOverflowMenuController::ShowContextMenu(
bool is_mouse_gesture) {
// This blocks until the user choses something or dismisses the menu.
owner_->GetContextMenu()->Run(
- (*views_)[start_index_ + id - 1]->button()->extension(), p);
+ (*views_)[start_index_ + id - 1]->button()->extension(),
+ (*views_)[start_index_ + id - 1]->button()->extension()->browser_action(),
+ owner_,
+ owner_->profile()->GetPrefs(),
+ p);
// The user is done with the context menu, so we can close the underlying
// menu.
diff --git a/chrome/browser/views/extensions/extension_action_context_menu.cc b/chrome/browser/views/extensions/extension_action_context_menu.cc
index 2e9ee7c..da7017d 100644
--- a/chrome/browser/views/extensions/extension_action_context_menu.cc
+++ b/chrome/browser/views/extensions/extension_action_context_menu.cc
@@ -17,11 +17,15 @@ ExtensionActionContextMenu::~ExtensionActionContextMenu() {
}
void ExtensionActionContextMenu::Run(Extension* extension,
- const gfx::Point& point) {
+ ExtensionAction* extension_action,
+ ExtensionActionContextMenuModel::MenuDelegate* delegate,
+ PrefService* prefs,
+ const gfx::Point& point) {
extension_ = extension;
context_menu_contents_.reset(
- new ExtensionActionContextMenuModel(extension));
+ new ExtensionActionContextMenuModel(extension, extension_action, prefs,
+ delegate));
context_menu_menu_.reset(new views::Menu2(context_menu_contents_.get()));
// This call blocks until the menu is dismissed or something is selected.
context_menu_menu_->RunContextMenuAt(point);
diff --git a/chrome/browser/views/extensions/extension_action_context_menu.h b/chrome/browser/views/extensions/extension_action_context_menu.h
index 5340a389..8aec10a 100644
--- a/chrome/browser/views/extensions/extension_action_context_menu.h
+++ b/chrome/browser/views/extensions/extension_action_context_menu.h
@@ -10,6 +10,8 @@
#include "chrome/browser/extensions/extension_action_context_menu_model.h"
class Extension;
+class ExtensionAction;
+class PrefService;
// Displays the context menu for extension action icons (browser/page actions).
class ExtensionActionContextMenu {
@@ -18,7 +20,11 @@ class ExtensionActionContextMenu {
~ExtensionActionContextMenu();
// Display the context menu at a given point.
- void Run(Extension* extension, const gfx::Point& point);
+ void Run(Extension* extension,
+ ExtensionAction* extension_action,
+ ExtensionActionContextMenuModel::MenuDelegate* delegate,
+ PrefService* prefs,
+ const gfx::Point& point);
// Closes the context menu if open.
void Cancel();
diff --git a/chrome/browser/views/extensions/extension_popup.cc b/chrome/browser/views/extensions/extension_popup.cc
index c417e8e2..6755c0d 100644
--- a/chrome/browser/views/extensions/extension_popup.cc
+++ b/chrome/browser/views/extensions/extension_popup.cc
@@ -7,8 +7,12 @@
#include "chrome/browser/browser.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser_window.h"
-#include "chrome/browser/profile.h"
+#include "chrome/browser/debugger/devtools_manager.h"
+#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
+#include "chrome/browser/profile.h"
+#include "chrome/browser/renderer_host/render_widget_host_view.h"
+#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/views/frame/browser_view.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_details.h"
@@ -46,7 +50,9 @@ ExtensionPopup::ExtensionPopup(ExtensionHost* host,
const gfx::Rect& relative_to,
BubbleBorder::ArrowLocation arrow_location,
bool activate_on_show,
- PopupChrome chrome)
+ bool inspect_with_devtools,
+ PopupChrome chrome,
+ Observer* observer)
: BrowserBubble(host->view(),
frame,
gfx::Point(),
@@ -57,16 +63,28 @@ ExtensionPopup::ExtensionPopup(ExtensionHost* host,
relative_to_(relative_to),
extension_host_(host),
activate_on_show_(activate_on_show),
+ inspect_with_devtools_(inspect_with_devtools),
+ close_on_lost_focus_(true),
+ closing_(false),
border_widget_(NULL),
border_(NULL),
border_view_(NULL),
popup_chrome_(chrome),
+ observer_(observer),
anchor_position_(arrow_location) {
+ AddRef(); // Balanced in Close();
+ set_delegate(this);
host->view()->SetContainer(this);
+
+ // We wait to show the popup until the contained host finishes loading.
registrar_.Add(this,
NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
Source<Profile>(host->profile()));
+ // Listen for the containing view calling window.close();
+ registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
+ Source<Profile>(host->profile()));
+
// TODO(erikkay) Some of this border code is derived from InfoBubble.
// We should see if we can unify these classes.
@@ -167,16 +185,81 @@ void ExtensionPopup::ResizeToView() {
}
}
+void ExtensionPopup::BubbleBrowserWindowMoved(BrowserBubble* bubble) {
+ if (!closing_)
+ Close();
+ // TODO(rafaelw) -- the border must move as well.
+}
+
+void ExtensionPopup::BubbleBrowserWindowClosing(BrowserBubble* bubble) {
+ if (!closing_)
+ Close();
+}
+
+void ExtensionPopup::BubbleGotFocus(BrowserBubble* bubble) {
+ // Forward the focus to the renderer.
+ host()->render_view_host()->view()->Focus();
+}
+
+void ExtensionPopup::BubbleLostFocus(BrowserBubble* bubble,
+ bool lost_focus_to_child) {
+ if (closing_ || // We are already closing.
+ inspect_with_devtools_ || // The popup is being inspected.
+ !close_on_lost_focus_ || // Our client is handling focus listening.
+ lost_focus_to_child) // A child of this view got focus.
+ return;
+
+ // When we do close on BubbleLostFocus, we do it in the next event loop
+ // because a subsequent event in this loop may also want to close this popup
+ // and if so, we want to allow that. Example: Clicking the same browser
+ // action button that opened the popup. If we closed immediately, the
+ // browser action container would fail to discover that the same button
+ // was pressed.
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &ExtensionPopup::Close));
+}
+
+
void ExtensionPopup::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
- if (type == NotificationType::EXTENSION_HOST_DID_STOP_LOADING) {
- // Once we receive did stop loading, the content will be complete and
- // the width will have been computed. Now it's safe to show.
- if (extension_host_.get() == Details<ExtensionHost>(details).ptr())
- Show(activate_on_show_);
- } else {
- NOTREACHED() << L"Received unexpected notification";
+ switch (type.value) {
+ case NotificationType::EXTENSION_HOST_DID_STOP_LOADING:
+ // Once we receive did stop loading, the content will be complete and
+ // the width will have been computed. Now it's safe to show.
+ if (extension_host_.get() == Details<ExtensionHost>(details).ptr()) {
+ Show(activate_on_show_);
+
+ if (inspect_with_devtools_) {
+ // Listen for the the devtools window closing.
+ registrar_.Add(this, NotificationType::DEVTOOLS_WINDOW_CLOSING,
+ Source<Profile>(extension_host_->profile()));
+ DevToolsManager::GetInstance()->ToggleDevToolsWindow(
+ extension_host_->render_view_host(), true);
+ }
+ }
+ break;
+ case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE:
+ // If we aren't the host of the popup, then disregard the notification.
+ if (Details<ExtensionHost>(host()) != details)
+ return;
+ Close();
+
+ break;
+ case NotificationType::DEVTOOLS_WINDOW_CLOSING:
+ // Make sure its the devtools window that inspecting our popup.
+ if (Details<RenderViewHost>(extension_host_->render_view_host()) != details)
+ return;
+
+ // If the devtools window is closing, we post a task to ourselves to
+ // close the popup. This gives the devtools window a chance to finish
+ // detaching from the inspected RenderViewHost.
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this,
+ &ExtensionPopup::Close));
+
+ break;
+ default:
+ NOTREACHED() << L"Received unexpected notification";
}
}
@@ -232,7 +315,9 @@ ExtensionPopup* ExtensionPopup::Show(
const gfx::Rect& relative_to,
BubbleBorder::ArrowLocation arrow_location,
bool activate_on_show,
- PopupChrome chrome) {
+ bool inspect_with_devtools,
+ PopupChrome chrome,
+ Observer* observer) {
DCHECK(profile);
DCHECK(frame_window);
ExtensionProcessManager* manager = profile->GetExtensionProcessManager();
@@ -253,7 +338,8 @@ ExtensionPopup* ExtensionPopup::Show(
ExtensionHost* host = manager->CreatePopup(url, browser);
ExtensionPopup* popup = new ExtensionPopup(host, frame_widget, relative_to,
arrow_location, activate_on_show,
- chrome);
+ inspect_with_devtools, chrome,
+ observer);
// If the host had somehow finished loading, then we'd miss the notification
// and not show. This seems to happen in single-process mode.
@@ -262,3 +348,13 @@ ExtensionPopup* ExtensionPopup::Show(
return popup;
}
+
+void ExtensionPopup::Close() {
+ if (closing_)
+ return;
+ closing_ = true;
+ DetachFromBrowser();
+ if (observer_)
+ observer_->ExtensionPopupClosed(this);
+ Release(); // Balanced in ctor.
+}
diff --git a/chrome/browser/views/extensions/extension_popup.h b/chrome/browser/views/extensions/extension_popup.h
index 6969fc2..f44ace3 100644
--- a/chrome/browser/views/extensions/extension_popup.h
+++ b/chrome/browser/views/extensions/extension_popup.h
@@ -23,9 +23,20 @@ class Widget;
}
class ExtensionPopup : public BrowserBubble,
+ public BrowserBubble::Delegate,
public NotificationObserver,
- public ExtensionView::Container {
+ public ExtensionView::Container,
+ public base::RefCounted<ExtensionPopup> {
public:
+ // Observer to ExtensionPopup events.
+ class Observer {
+ public:
+ // Called when the ExtensionPopup has closed. Note that it
+ // is ref-counted, and thus will be released shortly after
+ // making this delegate call.
+ virtual void ExtensionPopupClosed(ExtensionPopup* popup) {}
+ };
+
enum PopupChrome {
BUBBLE_CHROME,
RECTANGLE_CHROME
@@ -47,6 +58,8 @@ class ExtensionPopup : public BrowserBubble,
// If |arrow_location| is BOTTOM_*, then the popup 'pops up', otherwise
// the popup 'drops down'.
// Pass |activate_on_show| as true to activate the popup window.
+ // Pass |inspect_with_devtools| as true to pin the popup open and show the
+ // devtools window for it.
// The |chrome| argument controls the chrome that surrounds the pop-up.
// Passing BUBBLE_CHROME will give the pop-up a bubble-like appearance,
// including the arrow mentioned above. Passing RECTANGLE_CHROME will give
@@ -62,7 +75,20 @@ class ExtensionPopup : public BrowserBubble,
const gfx::Rect& relative_to,
BubbleBorder::ArrowLocation arrow_location,
bool activate_on_show,
- PopupChrome chrome);
+ bool inspect_with_devtools,
+ PopupChrome chrome,
+ Observer* observer);
+
+ // Closes the ExtensionPopup (this will cause the delegate
+ // ExtensionPopupClosed to fire.
+ void Close();
+
+ // Some clients wish to do their own custom focus change management. If this
+ // is set to false, then the ExtensionPopup will not do anything in response
+ // to the BubbleLostFocus() calls it gets from the BrowserBubble.
+ void set_close_on_lost_focus(bool close_on_lost_focus) {
+ close_on_lost_focus_ = close_on_lost_focus;
+ }
ExtensionHost* host() const { return extension_host_.get(); }
@@ -71,6 +97,13 @@ class ExtensionPopup : public BrowserBubble,
virtual void Show(bool activate);
virtual void ResizeToView();
+ // BrowserBubble::Delegate methods.
+ virtual void BubbleBrowserWindowMoved(BrowserBubble* bubble);
+ virtual void BubbleBrowserWindowClosing(BrowserBubble* bubble);
+ virtual void BubbleGotFocus(BrowserBubble* bubble);
+ virtual void BubbleLostFocus(BrowserBubble* bubble,
+ bool lost_focus_to_child);
+
// NotificationObserver overrides.
virtual void Observe(NotificationType type,
const NotificationSource& source,
@@ -93,7 +126,9 @@ class ExtensionPopup : public BrowserBubble,
const gfx::Rect& relative_to,
BubbleBorder::ArrowLocation arrow_location,
bool activate_on_show,
- PopupChrome chrome);
+ bool inspect_with_devtools,
+ PopupChrome chrome,
+ Observer* observer);
// Gives the desired bounds (in screen coordinates) given the rect to point
// to and the size of the contained contents. Includes all of the
@@ -110,6 +145,16 @@ class ExtensionPopup : public BrowserBubble,
// Flag used to indicate if the pop-up should be activated upon first display.
bool activate_on_show_;
+ // Flag used to indicate if the pop-up should open a devtools window once
+ // it is shown inspecting it.
+ bool inspect_with_devtools_;
+
+ // If false, ignore BrowserBubble::Delegate::BubbleLostFocus() calls.
+ bool close_on_lost_focus_;
+
+ // Whether the ExtensionPopup is current going about closing itself.
+ bool closing_;
+
NotificationRegistrar registrar_;
// A separate widget and associated pieces to draw a border behind the
@@ -123,6 +168,9 @@ class ExtensionPopup : public BrowserBubble,
// The type of chrome associated with the popup window.
PopupChrome popup_chrome_;
+ // The observer of this popup.
+ Observer* observer_;
+
// A cached copy of the arrow-position for the bubble chrome.
// If a black-border was requested, we still need this value to determine
// the position of the pop-up in relation to |relative_to_|.
diff --git a/chrome/browser/views/infobars/extension_infobar.cc b/chrome/browser/views/infobars/extension_infobar.cc
index 70f3f7f..9303aff 100644
--- a/chrome/browser/views/infobars/extension_infobar.cc
+++ b/chrome/browser/views/infobars/extension_infobar.cc
@@ -89,10 +89,14 @@ void ExtensionInfoBar::Layout() {
}
void ExtensionInfoBar::RunMenu(View* source, const gfx::Point& pt) {
- if (!options_menu_contents_.get()) {
+ if (!options_menu_contents_.get())
options_menu_contents_.reset(new ExtensionActionContextMenuModel(
- delegate_->extension_host()->extension()));
- }
+ delegate_->extension_host()->extension(),
+ // Do not include "Inspect Popup" in menu:
+ NULL, // ExtensionAction
+ NULL, // PrefService
+ NULL)); // ExtensionActionContextMenuModel::MenuDelegate
+
options_menu_menu_.reset(new views::Menu2(options_menu_contents_.get()));
options_menu_menu_->RunMenuAt(pt, views::Menu2::ALIGN_TOPLEFT);
}
diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc
index 37c1759..98823bc 100644
--- a/chrome/browser/views/location_bar_view.cc
+++ b/chrome/browser/views/location_bar_view.cc
@@ -1427,8 +1427,7 @@ LocationBarView::PageActionImageView::PageActionImageView(
tracker_(NULL),
current_tab_id_(-1),
preview_enabled_(false),
- popup_(NULL),
- ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
+ popup_(NULL) {
Extension* extension = profile->GetExtensionsService()->GetExtensionById(
page_action->extension_id(), false);
DCHECK(extension);
@@ -1447,9 +1446,6 @@ LocationBarView::PageActionImageView::PageActionImageView(
gfx::Size(Extension::kPageActionIconMaxSize,
Extension::kPageActionIconMaxSize));
}
-
- registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE,
- Source<Profile>(profile_));
}
LocationBarView::PageActionImageView::~PageActionImageView() {
@@ -1460,7 +1456,8 @@ LocationBarView::PageActionImageView::~PageActionImageView() {
HidePopup();
}
-void LocationBarView::PageActionImageView::ExecuteAction(int button) {
+void LocationBarView::PageActionImageView::ExecuteAction(int button,
+ bool inspect_with_devtools) {
if (current_tab_id_ < 0) {
NOTREACHED() << "No current tab.";
return;
@@ -1500,8 +1497,9 @@ void LocationBarView::PageActionImageView::ExecuteAction(int button) {
rect,
BubbleBorder::TOP_RIGHT,
true, // Activate the popup window.
- ExtensionPopup::BUBBLE_CHROME);
- popup_->set_delegate(this);
+ inspect_with_devtools,
+ ExtensionPopup::BUBBLE_CHROME,
+ this); // ExtensionPopup::Observer
} else {
ExtensionBrowserEventRouter::GetInstance()->PageActionExecuted(
profile_, page_action_->extension_id(), page_action_->id(),
@@ -1547,11 +1545,15 @@ void LocationBarView::PageActionImageView::OnMouseReleased(
if (!context_menu_.get())
context_menu_.reset(new ExtensionActionContextMenu());
- context_menu_->Run(extension, point);
+ context_menu_->Run(extension,
+ extension->page_action(),
+ this, // ExtensionActionContextMenuModel::Delegate
+ profile_->GetPrefs(),
+ point);
return;
}
- ExecuteAction(button);
+ ExecuteAction(button, false); // inspect_with_devtools
}
void LocationBarView::PageActionImageView::ShowInfoBubble() {
@@ -1629,56 +1631,22 @@ void LocationBarView::PageActionImageView::UpdateVisibility(
SetVisible(visible);
}
-void LocationBarView::PageActionImageView::BubbleBrowserWindowClosing(
- BrowserBubble* bubble) {
- HidePopup();
-}
-
-void LocationBarView::PageActionImageView::BubbleLostFocus(
- BrowserBubble* bubble, bool lost_focus_to_child) {
- // Don't close when we are losing focus to a child window, this is the case
- // for select popups and alert for example.
- if (!popup_ || lost_focus_to_child)
- return;
-
- MessageLoop::current()->PostTask(FROM_HERE,
- method_factory_.NewRunnableMethod(
- &LocationBarView::PageActionImageView::HidePopup));
+void LocationBarView::PageActionImageView::ShowPopupForDevToolsWindow(
+ Extension* extension, ExtensionAction* extension_action) {
+ ExecuteAction(1, // left-click
+ true); // inspect_with_devtools
}
-void LocationBarView::PageActionImageView::HidePopup() {
- if (!popup_)
- return;
-
- // This sometimes gets called via a timer (See BubbleLostFocus), so clear
- // the method factory. in case one is pending.
- method_factory_.RevokeAll();
-
- // Save the popup in a local since destroying it calls BubbleLostFocus,
- // which will try to call HidePopup() again.
- ExtensionPopup* closing_popup = popup_;
+void LocationBarView::PageActionImageView::ExtensionPopupClosed(
+ ExtensionPopup* popup) {
+ DCHECK_EQ(popup_, popup);
+ // ExtensionPopup is ref-counted, so we don't need to delete it.
popup_ = NULL;
-
- closing_popup->DetachFromBrowser();
- delete closing_popup;
}
-void LocationBarView::PageActionImageView::Observe(
- NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details) {
- switch (type.value) {
- case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE:
- // If we aren't the host of the popup, then disregard the notification.
- if (!popup_ || Details<ExtensionHost>(popup_->host()) != details)
- return;
-
- HidePopup();
- break;
- default:
- NOTREACHED() << "Unexpected notification";
- break;
- }
+void LocationBarView::PageActionImageView::HidePopup() {
+ if (popup_)
+ popup_->Close();
}
////////////////////////////////////////////////////////////////////////////////
@@ -1767,7 +1735,8 @@ void LocationBarView::TestPageActionPressed(size_t index) {
if (page_action_views_[i]->IsVisible()) {
if (current == index) {
const int kLeftMouseButton = 1;
- page_action_views_[i]->image_view()->ExecuteAction(kLeftMouseButton);
+ page_action_views_[i]->image_view()->ExecuteAction(kLeftMouseButton,
+ false); // inspect_with_devtools
return;
}
++current;
diff --git a/chrome/browser/views/location_bar_view.h b/chrome/browser/views/location_bar_view.h
index e3b4597..d591e97 100644
--- a/chrome/browser/views/location_bar_view.h
+++ b/chrome/browser/views/location_bar_view.h
@@ -18,6 +18,7 @@
#include "chrome/browser/toolbar_model.h"
#include "chrome/browser/views/browser_bubble.h"
#include "chrome/browser/views/extensions/extension_action_context_menu.h"
+#include "chrome/browser/views/extensions/extension_popup.h"
#include "chrome/browser/views/info_bubble.h"
#include "chrome/common/content_settings_types.h"
#include "chrome/common/notification_observer.h"
@@ -409,9 +410,9 @@ class LocationBarView : public LocationBar,
// PageActionImageView is used to display the icon for a given PageAction
// and notify the extension when the icon is clicked.
class PageActionImageView : public LocationBarImageView,
- public ImageLoadingTracker::Observer,
- public NotificationObserver,
- public BrowserBubble::Delegate {
+ public ImageLoadingTracker::Observer,
+ public ExtensionActionContextMenuModel::MenuDelegate,
+ public ExtensionPopup::Observer {
public:
PageActionImageView(LocationBarView* owner,
Profile* profile,
@@ -438,10 +439,12 @@ class LocationBarView : public LocationBar,
// Overridden from ImageLoadingTracker.
virtual void OnImageLoaded(SkBitmap* image, size_t index);
- // Overridden from BrowserBubble::Delegate
- virtual void BubbleBrowserWindowClosing(BrowserBubble* bubble);
- virtual void BubbleLostFocus(BrowserBubble* bubble,
- bool lost_focus_to_child);
+ // Overridden from ExtensionActionContextMenuModel::MenuDelegate
+ virtual void ShowPopupForDevToolsWindow(Extension* extension,
+ ExtensionAction* extension_action);
+
+ // Overriden from ExtensionPopup::Observer
+ virtual void ExtensionPopupClosed(ExtensionPopup* popup);
// Called to notify the PageAction that it should determine whether to be
// visible or hidden. |contents| is the TabContents that is active, |url|
@@ -449,17 +452,12 @@ class LocationBarView : public LocationBar,
void UpdateVisibility(TabContents* contents, const GURL& url);
// Either notify listeners or show a popup depending on the page action.
- void ExecuteAction(int button);
+ void ExecuteAction(int button, bool inspect_with_devtools);
private:
// Hides the active popup, if there is one.
void HidePopup();
- // Overridden from NotificationObserver:
- virtual void Observe(NotificationType type,
- const NotificationSource& source,
- const NotificationDetails& details);
-
// The location bar view that owns us.
LocationBarView* owner_;
@@ -497,10 +495,6 @@ class LocationBarView : public LocationBar,
// The current popup and the button it came from. NULL if no popup.
ExtensionPopup* popup_;
- ScopedRunnableMethodFactory<PageActionImageView> method_factory_;
-
- NotificationRegistrar registrar_;
-
DISALLOW_COPY_AND_ASSIGN(PageActionImageView);
};
friend class PageActionImageView;