Index: chrome/browser/views/extensions/extension_popup.cc |
diff --git a/chrome/browser/views/extensions/extension_popup.cc b/chrome/browser/views/extensions/extension_popup.cc |
index c417e8e2c78cd0181ee16ee73f2ff05c51fd95e0..6755c0de8b8518cc8e17357a0889f9e50c1d0d94 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. |
+} |