172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/ui/views/extensions/extension_popup.h" 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include <vector> 821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/debugger/devtools_manager.h" 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/debugger/devtools_toggle_action.h" 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_host.h" 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/extensions/extension_process_manager.h" 1321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h" 144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h" 1521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/browser_window.h" 1621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/ui/views/frame/browser_view.h" 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/extensions/extension.h" 18dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host.h" 19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/renderer_host/render_widget_host_view.h" 20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_details.h" 21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_source.h" 22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_type.h" 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/root_view.h" 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/window/window.h" 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_LINUX) 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "views/widget/widget_gtk.h" 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_CHROMEOS) 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/chromeos/wm_ipc.h" 3221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "third_party/cros/chromeos_wm_ipc_enums.h" 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenusing std::vector; 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing views::Widget; 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 3872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// The minimum/maximum dimensions of the popup. 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The minimum is just a little larger than the size of the button itself. 4072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// The maximum is an arbitrary number that should be smaller than most screens. 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int ExtensionPopup::kMinWidth = 25; 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int ExtensionPopup::kMinHeight = 25; 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int ExtensionPopup::kMaxWidth = 800; 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochconst int ExtensionPopup::kMaxHeight = 600; 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExtensionPopup::ExtensionPopup(ExtensionHost* host, 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch views::Widget* frame, 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Rect& relative_to, 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BubbleBorder::ArrowLocation arrow_location, 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool inspect_with_devtools, 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Observer* observer) 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch : BrowserBubble(host->view(), 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch frame, 54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen relative_to, 55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen arrow_location), 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch relative_to_(relative_to), 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_host_(host), 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inspect_with_devtools_(inspect_with_devtools), 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch close_on_lost_focus_(true), 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch closing_(false), 6172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen observer_(observer) { 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch AddRef(); // Balanced in Close(); 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set_delegate(this); 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host->view()->SetContainer(this); 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We wait to show the popup until the contained host finishes loading. 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NotificationType::EXTENSION_HOST_DID_STOP_LOADING, 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<Profile>(host->profile())); 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Listen for the containing view calling window.close(); 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<Profile>(host->profile())); 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExtensionPopup::~ExtensionPopup() { 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPopup::Show(bool activate) { 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (visible()) 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#if defined(OS_WIN) 8472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen frame_->GetWindow()->DisableInactiveRendering(); 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#endif 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ResizeToView(); 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BrowserBubble::Show(activate); 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPopup::BubbleBrowserWindowMoved(BrowserBubble* bubble) { 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ResizeToView(); 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPopup::BubbleBrowserWindowClosing(BrowserBubble* bubble) { 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!closing_) 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Close(); 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPopup::BubbleGotFocus(BrowserBubble* bubble) { 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Forward the focus to the renderer. 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch host()->render_view_host()->view()->Focus(); 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPopup::BubbleLostFocus(BrowserBubble* bubble, 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool lost_focus_to_child) { 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (closing_ || // We are already closing. 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch inspect_with_devtools_ || // The popup is being inspected. 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch !close_on_lost_focus_ || // Our client is handling focus listening. 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch lost_focus_to_child) // A child of this view got focus. 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // When we do close on BubbleLostFocus, we do it in the next event loop 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // because a subsequent event in this loop may also want to close this popup 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // and if so, we want to allow that. Example: Clicking the same browser 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // action button that opened the popup. If we closed immediately, the 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // browser action container would fail to discover that the same button 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // was pressed. 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &ExtensionPopup::Close)); 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPopup::Observe(NotificationType type, 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationSource& source, 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const NotificationDetails& details) { 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (type.value) { 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case NotificationType::EXTENSION_HOST_DID_STOP_LOADING: 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Once we receive did stop loading, the content will be complete and 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the width will have been computed. Now it's safe to show. 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (extension_host_.get() == Details<ExtensionHost>(details).ptr()) { 13272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen Show(true); 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (inspect_with_devtools_) { 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Listen for the the devtools window closing. 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch registrar_.Add(this, NotificationType::DEVTOOLS_WINDOW_CLOSING, 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Source<Profile>(extension_host_->profile())); 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DevToolsManager::GetInstance()->ToggleDevToolsWindow( 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch extension_host_->render_view_host(), 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE); 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we aren't the host of the popup, then disregard the notification. 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (Details<ExtensionHost>(host()) != details) 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Close(); 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case NotificationType::DEVTOOLS_WINDOW_CLOSING: 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure its the devtools window that inspecting our popup. 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (Details<RenderViewHost>(extension_host_->render_view_host()) != 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch details) 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the devtools window is closing, we post a task to ourselves to 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // close the popup. This gives the devtools window a chance to finish 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // detaching from the inspected RenderViewHost. 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch &ExtensionPopup::Close)); 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch default: 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch NOTREACHED() << L"Received unexpected notification"; 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPopup::OnExtensionPreferredSizeChanged(ExtensionView* view) { 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Constrain the size to popup min/max. 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch gfx::Size sz = view->GetPreferredSize(); 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch view->SetBounds(view->x(), view->y(), 17372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::max(kMinWidth, std::min(kMaxWidth, sz.width())), 17472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::max(kMinHeight, std::min(kMaxHeight, sz.height()))); 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ResizeToView(); 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochExtensionPopup* ExtensionPopup::Show( 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const GURL& url, 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Browser* browser, 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const gfx::Rect& relative_to, 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch BubbleBorder::ArrowLocation arrow_location, 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch bool inspect_with_devtools, 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Observer* observer) { 18772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ExtensionProcessManager* manager = 18872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen browser->profile()->GetExtensionProcessManager(); 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DCHECK(manager); 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!manager) 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return NULL; 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch ExtensionHost* host = manager->CreatePopup(url, browser); 19472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen views::Widget* frame = BrowserView::GetBrowserViewForNativeWindow( 19572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen browser->window()->GetNativeHandle())->GetWidget(); 19672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ExtensionPopup* popup = new ExtensionPopup(host, frame, relative_to, 19772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen arrow_location, 19872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen inspect_with_devtools, observer); 199201ade2fbba22bfb27ae029f4d23fca6ded109a0Ben Murdoch 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If the host had somehow finished loading, then we'd miss the notification 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // and not show. This seems to happen in single-process mode. 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (host->did_stop_loading()) 20372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen popup->Show(true); 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return popup; 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid ExtensionPopup::Close() { 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (closing_) 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch closing_ = true; 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch DetachFromBrowser(); 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (observer_) 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch observer_->ExtensionPopupIsClosing(this); 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Release(); // Balanced in ctor. 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch} 219