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.
5 #include "chrome/browser/ui/views/extensions/extension_dialog.h"
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 "content/public/browser/notification_details.h"
14 #include "content/public/browser/notification_source.h"
15 #include "content/public/browser/render_view_host.h"
16 #include "content/public/browser/render_widget_host_view.h"
17 #include "content/public/browser/web_contents.h"
18 #include "content/public/browser/web_contents_view.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"
25 using content::BrowserContext;
26 using content::WebContents;
28 ExtensionDialog::ExtensionDialog(extensions::ExtensionViewHost* host,
29 ExtensionDialogObserver* observer)
32 AddRef(); // Balanced in DeleteDelegate();
34 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
35 content::Source<BrowserContext>(host->browser_context()));
36 // Listen for the containing view calling window.close();
37 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
38 content::Source<BrowserContext>(host->browser_context()));
39 // Listen for a crash or other termination of the extension process.
40 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
41 content::Source<BrowserContext>(host->browser_context()));
44 ExtensionDialog::~ExtensionDialog() {
48 ExtensionDialog* ExtensionDialog::Show(
50 aura::Window* parent_window,
52 WebContents* web_contents,
57 const base::string16& title,
58 ExtensionDialogObserver* observer) {
59 extensions::ExtensionViewHost* host =
60 extensions::ExtensionViewHostFactory::CreateDialogHost(url, profile);
63 // Preferred size must be set before views::Widget::CreateWindowWithParent
64 // is called because CreateWindowWithParent refers the result of CanResize().
65 host->view()->SetPreferredSize(gfx::Size(width, height));
66 host->view()->set_minimum_size(gfx::Size(min_width, min_height));
67 host->SetAssociatedWebContents(web_contents);
69 DCHECK(parent_window);
70 ExtensionDialog* dialog = new ExtensionDialog(host, observer);
71 dialog->set_title(title);
72 dialog->InitWindow(parent_window, width, height);
74 // Show a white background while the extension loads. This is prettier than
75 // flashing a black unfilled window frame.
76 host->view()->set_background(
77 views::Background::CreateSolidBackground(0xFF, 0xFF, 0xFF));
78 host->view()->SetVisible(true);
80 // Ensure the DOM JavaScript can respond immediately to keyboard shortcuts.
81 host->host_contents()->GetView()->Focus();
85 void ExtensionDialog::InitWindow(aura::Window* parent,
88 views::Widget* window = CreateBrowserModalDialogViews(this, parent);
90 // Center the window over the browser.
91 gfx::Point center = parent->GetBoundsInScreen().CenterPoint();
92 int x = center.x() - width / 2;
93 int y = center.y() - height / 2;
94 // Ensure the top left and top right of the window are on screen, with
95 // priority given to the top left.
96 gfx::Rect screen_rect = gfx::Screen::GetScreenFor(parent)->
97 GetDisplayNearestPoint(center).bounds();
98 gfx::Rect bounds_rect = gfx::Rect(x, y, width, height);
99 bounds_rect.AdjustToFit(screen_rect);
100 window->SetBounds(bounds_rect);
103 // TODO(jamescook): Remove redundant call to Activate()?
107 void ExtensionDialog::ObserverDestroyed() {
111 void ExtensionDialog::MaybeFocusRenderView() {
112 views::FocusManager* focus_manager = GetWidget()->GetFocusManager();
113 DCHECK(focus_manager != NULL);
115 // Already there's a focused view, so no need to switch the focus.
116 if (focus_manager->GetFocusedView())
119 content::RenderWidgetHostView* view = host()->render_view_host()->GetView();
126 /////////////////////////////////////////////////////////////////////////////
127 // views::DialogDelegate overrides.
129 int ExtensionDialog::GetDialogButtons() const {
130 // The only user, SelectFileDialogExtension, provides its own buttons.
131 return ui::DIALOG_BUTTON_NONE;
134 bool ExtensionDialog::CanResize() const {
135 // Can resize only if minimum contents size set.
136 return host_->view()->GetPreferredSize() != gfx::Size();
139 void ExtensionDialog::SetMinimumContentsSize(int width, int height) {
140 host_->view()->SetPreferredSize(gfx::Size(width, height));
143 ui::ModalType ExtensionDialog::GetModalType() const {
144 return ui::MODAL_TYPE_WINDOW;
147 bool ExtensionDialog::ShouldShowWindowTitle() const {
148 return !window_title_.empty();
151 base::string16 ExtensionDialog::GetWindowTitle() const {
152 return window_title_;
155 void ExtensionDialog::WindowClosing() {
157 observer_->ExtensionDialogClosing(this);
160 void ExtensionDialog::DeleteDelegate() {
161 // The window has finished closing. Allow ourself to be deleted.
165 views::Widget* ExtensionDialog::GetWidget() {
166 return host_->view()->GetWidget();
169 const views::Widget* ExtensionDialog::GetWidget() const {
170 return host_->view()->GetWidget();
173 views::View* ExtensionDialog::GetContentsView() {
174 return host_->view();
177 bool ExtensionDialog::UseNewStyleForThisDialog() const {
181 /////////////////////////////////////////////////////////////////////////////
182 // content::NotificationObserver overrides.
184 void ExtensionDialog::Observe(int type,
185 const content::NotificationSource& source,
186 const content::NotificationDetails& details) {
188 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING:
189 // Avoid potential overdraw by removing the temporary background after
190 // the extension finishes loading.
191 host_->view()->set_background(NULL);
192 // The render view is created during the LoadURL(), so we should
193 // set the focus to the view if nobody else takes the focus.
194 if (content::Details<extensions::ExtensionHost>(host()) == details)
195 MaybeFocusRenderView();
197 case chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE:
198 // If we aren't the host of the popup, then disregard the notification.
199 if (content::Details<extensions::ExtensionHost>(host()) != details)
201 GetWidget()->Close();
203 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED:
204 if (content::Details<extensions::ExtensionHost>(host()) != details)
207 observer_->ExtensionTerminated(this);
210 NOTREACHED() << L"Received unexpected notification";