extension_dialog.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/views/extensions/extension_dialog.h" 6 7#include "chrome/browser/chrome_notification_types.h" 8#include "chrome/browser/extensions/extension_view_host.h" 9#include "chrome/browser/extensions/extension_view_host_factory.h" 10#include "chrome/browser/profiles/profile.h" 11#include "chrome/browser/ui/views/constrained_window_views.h" 12#include "chrome/browser/ui/views/extensions/extension_dialog_observer.h" 13#include "chrome/browser/ui/views/extensions/extension_view_views.h" 14#include "content/public/browser/notification_details.h" 15#include "content/public/browser/notification_source.h" 16#include "content/public/browser/render_view_host.h" 17#include "content/public/browser/render_widget_host_view.h" 18#include "content/public/browser/web_contents.h" 19#include "ui/base/base_window.h" 20#include "ui/gfx/screen.h" 21#include "ui/views/background.h" 22#include "ui/views/widget/widget.h" 23#include "url/gurl.h" 24 25using content::BrowserContext; 26using content::WebContents; 27 28namespace { 29 30ExtensionViewViews* GetExtensionView(extensions::ExtensionViewHost* host) { 31 return static_cast<ExtensionViewViews*>(host->view()); 32} 33 34} // namespace 35 36ExtensionDialog::ExtensionDialog(extensions::ExtensionViewHost* host, 37 ExtensionDialogObserver* observer) 38 : host_(host), 39 observer_(observer) { 40 AddRef(); // Balanced in DeleteDelegate(); 41 42 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, 43 content::Source<BrowserContext>(host->browser_context())); 44 // Listen for the containing view calling window.close(); 45 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE, 46 content::Source<BrowserContext>(host->browser_context())); 47 // Listen for a crash or other termination of the extension process. 48 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED, 49 content::Source<BrowserContext>(host->browser_context())); 50} 51 52ExtensionDialog::~ExtensionDialog() { 53} 54 55// static 56ExtensionDialog* ExtensionDialog::Show( 57 const GURL& url, 58 aura::Window* parent_window, 59 Profile* profile, 60 WebContents* web_contents, 61 int width, 62 int height, 63 int min_width, 64 int min_height, 65 const base::string16& title, 66 ExtensionDialogObserver* observer) { 67 extensions::ExtensionViewHost* host = 68 extensions::ExtensionViewHostFactory::CreateDialogHost(url, profile); 69 if (!host) 70 return NULL; 71 // Preferred size must be set before views::Widget::CreateWindowWithParent 72 // is called because CreateWindowWithParent refers the result of CanResize(). 73 ExtensionViewViews* view = GetExtensionView(host); 74 view->SetPreferredSize(gfx::Size(width, height)); 75 view->set_minimum_size(gfx::Size(min_width, min_height)); 76 host->SetAssociatedWebContents(web_contents); 77 78 DCHECK(parent_window); 79 ExtensionDialog* dialog = new ExtensionDialog(host, observer); 80 dialog->set_title(title); 81 dialog->InitWindow(parent_window, width, height); 82 83 // Show a white background while the extension loads. This is prettier than 84 // flashing a black unfilled window frame. 85 view->set_background( 86 views::Background::CreateSolidBackground(0xFF, 0xFF, 0xFF)); 87 view->SetVisible(true); 88 89 // Ensure the DOM JavaScript can respond immediately to keyboard shortcuts. 90 host->host_contents()->Focus(); 91 return dialog; 92} 93 94void ExtensionDialog::InitWindow(aura::Window* parent, 95 int width, 96 int height) { 97 views::Widget* window = CreateBrowserModalDialogViews(this, parent); 98 99 // Center the window over the browser. 100 gfx::Point center = parent->GetBoundsInScreen().CenterPoint(); 101 int x = center.x() - width / 2; 102 int y = center.y() - height / 2; 103 // Ensure the top left and top right of the window are on screen, with 104 // priority given to the top left. 105 gfx::Rect screen_rect = gfx::Screen::GetScreenFor(parent)-> 106 GetDisplayNearestPoint(center).bounds(); 107 gfx::Rect bounds_rect = gfx::Rect(x, y, width, height); 108 bounds_rect.AdjustToFit(screen_rect); 109 window->SetBounds(bounds_rect); 110 111 window->Show(); 112 // TODO(jamescook): Remove redundant call to Activate()? 113 window->Activate(); 114} 115 116void ExtensionDialog::ObserverDestroyed() { 117 observer_ = NULL; 118} 119 120void ExtensionDialog::MaybeFocusRenderView() { 121 views::FocusManager* focus_manager = GetWidget()->GetFocusManager(); 122 DCHECK(focus_manager != NULL); 123 124 // Already there's a focused view, so no need to switch the focus. 125 if (focus_manager->GetFocusedView()) 126 return; 127 128 content::RenderWidgetHostView* view = host()->render_view_host()->GetView(); 129 if (!view) 130 return; 131 132 view->Focus(); 133} 134 135///////////////////////////////////////////////////////////////////////////// 136// views::DialogDelegate overrides. 137 138int ExtensionDialog::GetDialogButtons() const { 139 // The only user, SelectFileDialogExtension, provides its own buttons. 140 return ui::DIALOG_BUTTON_NONE; 141} 142 143bool ExtensionDialog::CanResize() const { 144 // Can resize only if minimum contents size set. 145 return GetExtensionView(host_.get())->GetPreferredSize() != gfx::Size(); 146} 147 148void ExtensionDialog::SetMinimumContentsSize(int width, int height) { 149 GetExtensionView(host_.get())->SetPreferredSize(gfx::Size(width, height)); 150} 151 152ui::ModalType ExtensionDialog::GetModalType() const { 153 return ui::MODAL_TYPE_WINDOW; 154} 155 156bool ExtensionDialog::ShouldShowWindowTitle() const { 157 return !window_title_.empty(); 158} 159 160base::string16 ExtensionDialog::GetWindowTitle() const { 161 return window_title_; 162} 163 164void ExtensionDialog::WindowClosing() { 165 if (observer_) 166 observer_->ExtensionDialogClosing(this); 167} 168 169void ExtensionDialog::DeleteDelegate() { 170 // The window has finished closing. Allow ourself to be deleted. 171 Release(); 172} 173 174views::Widget* ExtensionDialog::GetWidget() { 175 return GetExtensionView(host_.get())->GetWidget(); 176} 177 178const views::Widget* ExtensionDialog::GetWidget() const { 179 return GetExtensionView(host_.get())->GetWidget(); 180} 181 182views::View* ExtensionDialog::GetContentsView() { 183 return GetExtensionView(host_.get()); 184} 185 186bool ExtensionDialog::UseNewStyleForThisDialog() const { 187 return false; 188} 189 190///////////////////////////////////////////////////////////////////////////// 191// content::NotificationObserver overrides. 192 193void ExtensionDialog::Observe(int type, 194 const content::NotificationSource& source, 195 const content::NotificationDetails& details) { 196 switch (type) { 197 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING: 198 // Avoid potential overdraw by removing the temporary background after 199 // the extension finishes loading. 200 GetExtensionView(host_.get())->set_background(NULL); 201 // The render view is created during the LoadURL(), so we should 202 // set the focus to the view if nobody else takes the focus. 203 if (content::Details<extensions::ExtensionHost>(host()) == details) 204 MaybeFocusRenderView(); 205 break; 206 case chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE: 207 // If we aren't the host of the popup, then disregard the notification. 208 if (content::Details<extensions::ExtensionHost>(host()) != details) 209 return; 210 GetWidget()->Close(); 211 break; 212 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: 213 if (content::Details<extensions::ExtensionHost>(host()) != details) 214 return; 215 if (observer_) 216 observer_->ExtensionTerminated(this); 217 break; 218 default: 219 NOTREACHED() << L"Received unexpected notification"; 220 break; 221 } 222} 223