| Index: chrome/browser/extensions/extension_popup_api.cc
|
| diff --git a/chrome/browser/extensions/extension_popup_api.cc b/chrome/browser/extensions/extension_popup_api.cc
|
| index c70747d47f20cf9524bc102db7d68ad8b99c5034..504a7a071be43d8a8cb2940c30b279533ff684da 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;
|
| }
|
|
|