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