Index: chrome/browser/extensions/extension_popup_api.cc |
=================================================================== |
--- chrome/browser/extensions/extension_popup_api.cc (revision 46029) |
+++ chrome/browser/extensions/extension_popup_api.cc (working copy) |
@@ -12,6 +12,9 @@ |
#include "chrome/browser/browser.h" |
#include "chrome/browser/browser_window.h" |
#include "chrome/browser/profile.h" |
+#include "chrome/browser/renderer_host/render_view_host.h" |
+#include "chrome/browser/renderer_host/render_view_host_delegate.h" |
+#include "chrome/browser/renderer_host/render_widget_host_view.h" |
#include "chrome/browser/tab_contents/tab_contents.h" |
#include "chrome/common/extensions/extension.h" |
#include "chrome/common/notification_details.h" |
@@ -22,9 +25,6 @@ |
#include "gfx/point.h" |
#if defined(TOOLKIT_VIEWS) |
-#include "chrome/browser/renderer_host/render_view_host.h" |
-#include "chrome/browser/renderer_host/render_view_host_delegate.h" |
-#include "chrome/browser/renderer_host/render_widget_host_view.h" |
#include "chrome/browser/views/extensions/extension_popup.h" |
#include "views/view.h" |
#include "views/focus/focus_manager.h" |
@@ -42,6 +42,8 @@ |
const char kBadAnchorArgument[] = "Invalid anchor argument."; |
const char kInvalidURLError[] = "Invalid URL."; |
const char kNotAnExtension[] = "Not an extension view."; |
+const char kPopupsDisallowed[] = |
+ "Popups are only supported from toolstrip or tab-contents views."; |
// Keys. |
const wchar_t kUrlKey[] = L"url"; |
@@ -70,7 +72,8 @@ |
// containing view or any of *its* children. |
class ExtensionPopupHost : public ExtensionPopup::Observer, |
public views::WidgetFocusChangeListener, |
- public base::RefCounted<ExtensionPopupHost> { |
+ public base::RefCounted<ExtensionPopupHost>, |
+ public NotificationObserver { |
public: |
explicit ExtensionPopupHost(ExtensionFunctionDispatcher* dispatcher) |
: dispatcher_(dispatcher), popup_(NULL) { |
@@ -85,9 +88,18 @@ |
void set_popup(ExtensionPopup* popup) { |
popup_ = popup; |
+ |
+ // Now that a popup has been assigned, listen for subsequent popups being |
+ // created in the same extension - we want to disallow more than one |
+ // concurrently displayed popup windows. |
+ registrar_.Add( |
+ this, |
+ NotificationType::EXTENSION_HOST_CREATED, |
+ Source<ExtensionProcessManager>( |
+ dispatcher_->profile()->GetExtensionProcessManager())); |
} |
- // Overriden from ExtensionPopup::Observer |
+ // Overridden from ExtensionPopup::Observer |
virtual void ExtensionPopupClosed(ExtensionPopup* popup) { |
// Unregister the automation resource routing registered upon host |
// creation. |
@@ -119,7 +131,7 @@ |
Release(); // Balanced in ctor. |
} |
- // Overriden from views::WidgetFocusChangeListener |
+ // Overridden 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 |
@@ -156,6 +168,23 @@ |
&ExtensionPopup::Close)); |
} |
+ // Overridden from NotificationObserver |
+ virtual void Observe(NotificationType type, |
+ const NotificationSource& source, |
+ const NotificationDetails& details) { |
+ DCHECK(NotificationType::EXTENSION_HOST_CREATED == type); |
+ if (NotificationType::EXTENSION_HOST_CREATED == type) { |
+ Details<ExtensionHost> details_host(details); |
+ // Disallow multiple pop-ups from the same extension, by closing |
+ // the presently opened popup during construction of any new popups. |
+ if (ViewType::EXTENSION_POPUP == details_host->GetRenderViewType() && |
+ popup_->host()->extension() == details_host->extension() && |
+ Details<ExtensionHost>(popup_->host()) != details) { |
+ popup_->Close(); |
+ } |
+ } |
+ } |
+ |
private: |
// Returns the AutomationResourceRoutingDelegate interface for |dispatcher|. |
static AutomationResourceRoutingDelegate* |
@@ -177,6 +206,8 @@ |
// A pointer to the popup. |
ExtensionPopup* popup_; |
+ NotificationRegistrar registrar_; |
+ |
DISALLOW_COPY_AND_ASSIGN(ExtensionPopupHost); |
}; |
#endif // TOOLKIT_VIEWS |
@@ -211,6 +242,16 @@ |
} |
bool PopupShowFunction::RunImpl() { |
+ // Popups may only be displayed from TAB_CONTENTS and EXTENSION_TOOLSTRIP |
+ // views. |
+ ViewType::Type view_type = |
+ dispatcher()->render_view_host()->delegate()->GetRenderViewType(); |
+ if (ViewType::EXTENSION_TOOLSTRIP != view_type && |
+ ViewType::TAB_CONTENTS != view_type) { |
+ error_ = kPopupsDisallowed; |
+ return false; |
+ } |
+ |
EXTENSION_FUNCTION_VALIDATE(args_->IsType(Value::TYPE_LIST)); |
const ListValue* args = args_as_list(); |
@@ -272,7 +313,6 @@ |
return false; |
} |
-#if defined(TOOLKIT_VIEWS) |
gfx::Point origin(dom_left, dom_top); |
if (!dispatcher()->render_view_host()->view()) { |
error_ = kNotAnExtension; |
@@ -284,14 +324,6 @@ |
origin.Offset(content_bounds.x(), content_bounds.y()); |
gfx::Rect rect(origin.x(), origin.y(), dom_width, dom_height); |
- // Pop-up from extension views (ExtensionShelf, etc.), and drop-down when |
- // in a TabContents view. |
- ViewType::Type view_type = |
- dispatcher()->render_view_host()->delegate()->GetRenderViewType(); |
- BubbleBorder::ArrowLocation arrow_location = |
- view_type == ViewType::TAB_CONTENTS ? |
- BubbleBorder::TOP_LEFT : BubbleBorder::BOTTOM_LEFT; |
- |
// Get the correct native window to pass to ExtensionPopup. |
// ExtensionFunctionDispatcher::Delegate may provide a custom implementation |
// of this. |
@@ -300,6 +332,13 @@ |
if (!window) |
window = GetCurrentBrowser()->window()->GetNativeHandle(); |
+#if defined(TOOLKIT_VIEWS) |
+ // Pop-up from extension views (ExtensionShelf, etc.), and drop-down when |
+ // in a TabContents view. |
+ BubbleBorder::ArrowLocation arrow_location = |
+ view_type == ViewType::TAB_CONTENTS ? |
+ BubbleBorder::TOP_LEFT : BubbleBorder::BOTTOM_LEFT; |
+ |
// ExtensionPopupHost manages it's own lifetime. |
ExtensionPopupHost* popup_host = new ExtensionPopupHost(dispatcher()); |
popup_ = ExtensionPopup::Show(url, |
@@ -329,6 +368,8 @@ |
type == NotificationType::EXTENSION_HOST_DESTROYED); |
DCHECK(popup_ != NULL); |
+ // Wait for notification that the popup view is ready (and onload has been |
+ // called), before completing the API call. |
if (popup_ && type == NotificationType::EXTENSION_POPUP_VIEW_READY && |
Details<ExtensionHost>(popup_->host()) == details) { |
SendResponse(true); |