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 "ui/base/base_window.h"
19 #include "ui/gfx/screen.h"
20 #include "ui/views/background.h"
21 #include "ui/views/widget/widget.h"
24 using content::BrowserContext
;
25 using content::WebContents
;
27 ExtensionDialog::ExtensionDialog(extensions::ExtensionViewHost
* host
,
28 ExtensionDialogObserver
* observer
)
31 AddRef(); // Balanced in DeleteDelegate();
33 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING
,
34 content::Source
<BrowserContext
>(host
->browser_context()));
35 // Listen for the containing view calling window.close();
36 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE
,
37 content::Source
<BrowserContext
>(host
->browser_context()));
38 // Listen for a crash or other termination of the extension process.
39 registrar_
.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED
,
40 content::Source
<BrowserContext
>(host
->browser_context()));
43 ExtensionDialog::~ExtensionDialog() {
47 ExtensionDialog
* ExtensionDialog::Show(
49 aura::Window
* parent_window
,
51 WebContents
* web_contents
,
56 const base::string16
& title
,
57 ExtensionDialogObserver
* observer
) {
58 extensions::ExtensionViewHost
* host
=
59 extensions::ExtensionViewHostFactory::CreateDialogHost(url
, profile
);
62 // Preferred size must be set before views::Widget::CreateWindowWithParent
63 // is called because CreateWindowWithParent refers the result of CanResize().
64 host
->view()->SetPreferredSize(gfx::Size(width
, height
));
65 host
->view()->set_minimum_size(gfx::Size(min_width
, min_height
));
66 host
->SetAssociatedWebContents(web_contents
);
68 DCHECK(parent_window
);
69 ExtensionDialog
* dialog
= new ExtensionDialog(host
, observer
);
70 dialog
->set_title(title
);
71 dialog
->InitWindow(parent_window
, width
, height
);
73 // Show a white background while the extension loads. This is prettier than
74 // flashing a black unfilled window frame.
75 host
->view()->set_background(
76 views::Background::CreateSolidBackground(0xFF, 0xFF, 0xFF));
77 host
->view()->SetVisible(true);
79 // Ensure the DOM JavaScript can respond immediately to keyboard shortcuts.
80 host
->host_contents()->Focus();
84 void ExtensionDialog::InitWindow(aura::Window
* parent
,
87 views::Widget
* window
= CreateBrowserModalDialogViews(this, parent
);
89 // Center the window over the browser.
90 gfx::Point center
= parent
->GetBoundsInScreen().CenterPoint();
91 int x
= center
.x() - width
/ 2;
92 int y
= center
.y() - height
/ 2;
93 // Ensure the top left and top right of the window are on screen, with
94 // priority given to the top left.
95 gfx::Rect screen_rect
= gfx::Screen::GetScreenFor(parent
)->
96 GetDisplayNearestPoint(center
).bounds();
97 gfx::Rect bounds_rect
= gfx::Rect(x
, y
, width
, height
);
98 bounds_rect
.AdjustToFit(screen_rect
);
99 window
->SetBounds(bounds_rect
);
102 // TODO(jamescook): Remove redundant call to Activate()?
106 void ExtensionDialog::ObserverDestroyed() {
110 void ExtensionDialog::MaybeFocusRenderView() {
111 views::FocusManager
* focus_manager
= GetWidget()->GetFocusManager();
112 DCHECK(focus_manager
!= NULL
);
114 // Already there's a focused view, so no need to switch the focus.
115 if (focus_manager
->GetFocusedView())
118 content::RenderWidgetHostView
* view
= host()->render_view_host()->GetView();
125 /////////////////////////////////////////////////////////////////////////////
126 // views::DialogDelegate overrides.
128 int ExtensionDialog::GetDialogButtons() const {
129 // The only user, SelectFileDialogExtension, provides its own buttons.
130 return ui::DIALOG_BUTTON_NONE
;
133 bool ExtensionDialog::CanResize() const {
134 // Can resize only if minimum contents size set.
135 return host_
->view()->GetPreferredSize() != gfx::Size();
138 void ExtensionDialog::SetMinimumContentsSize(int width
, int height
) {
139 host_
->view()->SetPreferredSize(gfx::Size(width
, height
));
142 ui::ModalType
ExtensionDialog::GetModalType() const {
143 return ui::MODAL_TYPE_WINDOW
;
146 bool ExtensionDialog::ShouldShowWindowTitle() const {
147 return !window_title_
.empty();
150 base::string16
ExtensionDialog::GetWindowTitle() const {
151 return window_title_
;
154 void ExtensionDialog::WindowClosing() {
156 observer_
->ExtensionDialogClosing(this);
159 void ExtensionDialog::DeleteDelegate() {
160 // The window has finished closing. Allow ourself to be deleted.
164 views::Widget
* ExtensionDialog::GetWidget() {
165 return host_
->view()->GetWidget();
168 const views::Widget
* ExtensionDialog::GetWidget() const {
169 return host_
->view()->GetWidget();
172 views::View
* ExtensionDialog::GetContentsView() {
173 return host_
->view();
176 bool ExtensionDialog::UseNewStyleForThisDialog() const {
180 /////////////////////////////////////////////////////////////////////////////
181 // content::NotificationObserver overrides.
183 void ExtensionDialog::Observe(int type
,
184 const content::NotificationSource
& source
,
185 const content::NotificationDetails
& details
) {
187 case chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING
:
188 // Avoid potential overdraw by removing the temporary background after
189 // the extension finishes loading.
190 host_
->view()->set_background(NULL
);
191 // The render view is created during the LoadURL(), so we should
192 // set the focus to the view if nobody else takes the focus.
193 if (content::Details
<extensions::ExtensionHost
>(host()) == details
)
194 MaybeFocusRenderView();
196 case chrome::NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE
:
197 // If we aren't the host of the popup, then disregard the notification.
198 if (content::Details
<extensions::ExtensionHost
>(host()) != details
)
200 GetWidget()->Close();
202 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED
:
203 if (content::Details
<extensions::ExtensionHost
>(host()) != details
)
206 observer_
->ExtensionTerminated(this);
209 NOTREACHED() << L
"Received unexpected notification";