OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/views/extensions/extension_popup.h" | 5 #include "chrome/browser/views/extensions/extension_popup.h" |
6 | 6 |
7 #include "chrome/browser/browser.h" | 7 #include "chrome/browser/browser.h" |
8 #include "chrome/browser/browser_list.h" | 8 #include "chrome/browser/browser_list.h" |
9 #include "chrome/browser/browser_window.h" | 9 #include "chrome/browser/browser_window.h" |
| 10 #include "chrome/browser/debugger/devtools_manager.h" |
| 11 #include "chrome/browser/extensions/extension_host.h" |
| 12 #include "chrome/browser/extensions/extension_process_manager.h" |
10 #include "chrome/browser/profile.h" | 13 #include "chrome/browser/profile.h" |
11 #include "chrome/browser/extensions/extension_process_manager.h" | 14 #include "chrome/browser/renderer_host/render_widget_host_view.h" |
| 15 #include "chrome/browser/renderer_host/render_view_host.h" |
12 #include "chrome/browser/views/frame/browser_view.h" | 16 #include "chrome/browser/views/frame/browser_view.h" |
13 #include "chrome/common/extensions/extension.h" | 17 #include "chrome/common/extensions/extension.h" |
14 #include "chrome/common/notification_details.h" | 18 #include "chrome/common/notification_details.h" |
15 #include "chrome/common/notification_source.h" | 19 #include "chrome/common/notification_source.h" |
16 #include "chrome/common/notification_type.h" | 20 #include "chrome/common/notification_type.h" |
17 #include "third_party/skia/include/core/SkColor.h" | 21 #include "third_party/skia/include/core/SkColor.h" |
18 #include "views/widget/root_view.h" | 22 #include "views/widget/root_view.h" |
19 #include "views/window/window.h" | 23 #include "views/window/window.h" |
20 | 24 |
21 #if defined(OS_LINUX) | 25 #if defined(OS_LINUX) |
(...skipping 17 matching lines...) Expand all Loading... |
39 // The width, in pixels, of the black-border on a popup. | 43 // The width, in pixels, of the black-border on a popup. |
40 const int kPopupBorderWidth = 1; | 44 const int kPopupBorderWidth = 1; |
41 | 45 |
42 const int kPopupBubbleCornerRadius = BubbleBorder::GetCornerRadius() / 2; | 46 const int kPopupBubbleCornerRadius = BubbleBorder::GetCornerRadius() / 2; |
43 | 47 |
44 ExtensionPopup::ExtensionPopup(ExtensionHost* host, | 48 ExtensionPopup::ExtensionPopup(ExtensionHost* host, |
45 views::Widget* frame, | 49 views::Widget* frame, |
46 const gfx::Rect& relative_to, | 50 const gfx::Rect& relative_to, |
47 BubbleBorder::ArrowLocation arrow_location, | 51 BubbleBorder::ArrowLocation arrow_location, |
48 bool activate_on_show, | 52 bool activate_on_show, |
49 PopupChrome chrome) | 53 bool inspect_with_devtools, |
| 54 PopupChrome chrome, |
| 55 Observer* observer) |
50 : BrowserBubble(host->view(), | 56 : BrowserBubble(host->view(), |
51 frame, | 57 frame, |
52 gfx::Point(), | 58 gfx::Point(), |
53 RECTANGLE_CHROME == chrome), // If no bubble chrome is to | 59 RECTANGLE_CHROME == chrome), // If no bubble chrome is to |
54 // be displayed, then enable a | 60 // be displayed, then enable a |
55 // drop-shadow on the bubble | 61 // drop-shadow on the bubble |
56 // widget. | 62 // widget. |
57 relative_to_(relative_to), | 63 relative_to_(relative_to), |
58 extension_host_(host), | 64 extension_host_(host), |
59 activate_on_show_(activate_on_show), | 65 activate_on_show_(activate_on_show), |
| 66 inspect_with_devtools_(inspect_with_devtools), |
| 67 close_on_lost_focus_(true), |
| 68 closing_(false), |
60 border_widget_(NULL), | 69 border_widget_(NULL), |
61 border_(NULL), | 70 border_(NULL), |
62 border_view_(NULL), | 71 border_view_(NULL), |
63 popup_chrome_(chrome), | 72 popup_chrome_(chrome), |
| 73 observer_(observer), |
64 anchor_position_(arrow_location) { | 74 anchor_position_(arrow_location) { |
| 75 AddRef(); // Balanced in Close(); |
| 76 set_delegate(this); |
65 host->view()->SetContainer(this); | 77 host->view()->SetContainer(this); |
| 78 |
| 79 // We wait to show the popup until the contained host finishes loading. |
66 registrar_.Add(this, | 80 registrar_.Add(this, |
67 NotificationType::EXTENSION_HOST_DID_STOP_LOADING, | 81 NotificationType::EXTENSION_HOST_DID_STOP_LOADING, |
68 Source<Profile>(host->profile())); | 82 Source<Profile>(host->profile())); |
69 | 83 |
| 84 // Listen for the containing view calling window.close(); |
| 85 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, |
| 86 Source<Profile>(host->profile())); |
| 87 |
70 // TODO(erikkay) Some of this border code is derived from InfoBubble. | 88 // TODO(erikkay) Some of this border code is derived from InfoBubble. |
71 // We should see if we can unify these classes. | 89 // We should see if we can unify these classes. |
72 | 90 |
73 // The bubble chrome requires a separate window, so construct it here. | 91 // The bubble chrome requires a separate window, so construct it here. |
74 if (BUBBLE_CHROME == popup_chrome_) { | 92 if (BUBBLE_CHROME == popup_chrome_) { |
75 gfx::NativeView native_window = frame->GetNativeView(); | 93 gfx::NativeView native_window = frame->GetNativeView(); |
76 #if defined(OS_LINUX) | 94 #if defined(OS_LINUX) |
77 border_widget_ = new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW); | 95 border_widget_ = new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW); |
78 static_cast<views::WidgetGtk*>(border_widget_)->MakeTransparent(); | 96 static_cast<views::WidgetGtk*>(border_widget_)->MakeTransparent(); |
79 static_cast<views::WidgetGtk*>(border_widget_)->make_transient_to_parent(); | 97 static_cast<views::WidgetGtk*>(border_widget_)->make_transient_to_parent(); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 | 178 |
161 origin.set_x(origin.x() + border_insets.left() + kPopupBubbleCornerRadius); | 179 origin.set_x(origin.x() + border_insets.left() + kPopupBubbleCornerRadius); |
162 origin.set_y(origin.y() + border_insets.top() + kPopupBubbleCornerRadius); | 180 origin.set_y(origin.y() + border_insets.top() + kPopupBubbleCornerRadius); |
163 | 181 |
164 SetBounds(origin.x(), origin.y(), new_size.width(), new_size.height()); | 182 SetBounds(origin.x(), origin.y(), new_size.width(), new_size.height()); |
165 } else { | 183 } else { |
166 SetBounds(origin.x(), origin.y(), rect.width(), rect.height()); | 184 SetBounds(origin.x(), origin.y(), rect.width(), rect.height()); |
167 } | 185 } |
168 } | 186 } |
169 | 187 |
| 188 void ExtensionPopup::BubbleBrowserWindowMoved(BrowserBubble* bubble) { |
| 189 if (!closing_) |
| 190 Close(); |
| 191 // TODO(rafaelw) -- the border must move as well. |
| 192 } |
| 193 |
| 194 void ExtensionPopup::BubbleBrowserWindowClosing(BrowserBubble* bubble) { |
| 195 if (!closing_) |
| 196 Close(); |
| 197 } |
| 198 |
| 199 void ExtensionPopup::BubbleGotFocus(BrowserBubble* bubble) { |
| 200 // Forward the focus to the renderer. |
| 201 host()->render_view_host()->view()->Focus(); |
| 202 } |
| 203 |
| 204 void ExtensionPopup::BubbleLostFocus(BrowserBubble* bubble, |
| 205 bool lost_focus_to_child) { |
| 206 if (closing_ || // We are already closing. |
| 207 inspect_with_devtools_ || // The popup is being inspected. |
| 208 !close_on_lost_focus_ || // Our client is handling focus listening. |
| 209 lost_focus_to_child) // A child of this view got focus. |
| 210 return; |
| 211 |
| 212 // When we do close on BubbleLostFocus, we do it in the next event loop |
| 213 // because a subsequent event in this loop may also want to close this popup |
| 214 // and if so, we want to allow that. Example: Clicking the same browser |
| 215 // action button that opened the popup. If we closed immediately, the |
| 216 // browser action container would fail to discover that the same button |
| 217 // was pressed. |
| 218 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 219 &ExtensionPopup::Close)); |
| 220 } |
| 221 |
| 222 |
170 void ExtensionPopup::Observe(NotificationType type, | 223 void ExtensionPopup::Observe(NotificationType type, |
171 const NotificationSource& source, | 224 const NotificationSource& source, |
172 const NotificationDetails& details) { | 225 const NotificationDetails& details) { |
173 if (type == NotificationType::EXTENSION_HOST_DID_STOP_LOADING) { | 226 switch (type.value) { |
174 // Once we receive did stop loading, the content will be complete and | 227 case NotificationType::EXTENSION_HOST_DID_STOP_LOADING: |
175 // the width will have been computed. Now it's safe to show. | 228 // Once we receive did stop loading, the content will be complete and |
176 if (extension_host_.get() == Details<ExtensionHost>(details).ptr()) | 229 // the width will have been computed. Now it's safe to show. |
177 Show(activate_on_show_); | 230 if (extension_host_.get() == Details<ExtensionHost>(details).ptr()) { |
178 } else { | 231 Show(activate_on_show_); |
179 NOTREACHED() << L"Received unexpected notification"; | 232 |
| 233 if (inspect_with_devtools_) { |
| 234 // Listen for the the devtools window closing. |
| 235 registrar_.Add(this, NotificationType::DEVTOOLS_WINDOW_CLOSING, |
| 236 Source<Profile>(extension_host_->profile())); |
| 237 DevToolsManager::GetInstance()->ToggleDevToolsWindow( |
| 238 extension_host_->render_view_host(), true); |
| 239 } |
| 240 } |
| 241 break; |
| 242 case NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE: |
| 243 // If we aren't the host of the popup, then disregard the notification. |
| 244 if (Details<ExtensionHost>(host()) != details) |
| 245 return; |
| 246 Close(); |
| 247 |
| 248 break; |
| 249 case NotificationType::DEVTOOLS_WINDOW_CLOSING: |
| 250 // Make sure its the devtools window that inspecting our popup. |
| 251 if (Details<RenderViewHost>(extension_host_->render_view_host()) != detail
s) |
| 252 return; |
| 253 |
| 254 // If the devtools window is closing, we post a task to ourselves to |
| 255 // close the popup. This gives the devtools window a chance to finish |
| 256 // detaching from the inspected RenderViewHost. |
| 257 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 258 &ExtensionPopup::Close)); |
| 259 |
| 260 break; |
| 261 default: |
| 262 NOTREACHED() << L"Received unexpected notification"; |
180 } | 263 } |
181 } | 264 } |
182 | 265 |
183 void ExtensionPopup::OnExtensionPreferredSizeChanged(ExtensionView* view) { | 266 void ExtensionPopup::OnExtensionPreferredSizeChanged(ExtensionView* view) { |
184 // Constrain the size to popup min/max. | 267 // Constrain the size to popup min/max. |
185 gfx::Size sz = view->GetPreferredSize(); | 268 gfx::Size sz = view->GetPreferredSize(); |
186 view->SetBounds(view->x(), view->y(), | 269 view->SetBounds(view->x(), view->y(), |
187 std::max(kMinWidth, std::min(kMaxWidth, sz.width())), | 270 std::max(kMinWidth, std::min(kMaxWidth, sz.width())), |
188 std::max(kMinHeight, std::min(kMaxHeight, sz.height()))); | 271 std::max(kMinHeight, std::min(kMaxHeight, sz.height()))); |
189 | 272 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 | 308 |
226 // static | 309 // static |
227 ExtensionPopup* ExtensionPopup::Show( | 310 ExtensionPopup* ExtensionPopup::Show( |
228 const GURL& url, | 311 const GURL& url, |
229 Browser* browser, | 312 Browser* browser, |
230 Profile* profile, | 313 Profile* profile, |
231 gfx::NativeWindow frame_window, | 314 gfx::NativeWindow frame_window, |
232 const gfx::Rect& relative_to, | 315 const gfx::Rect& relative_to, |
233 BubbleBorder::ArrowLocation arrow_location, | 316 BubbleBorder::ArrowLocation arrow_location, |
234 bool activate_on_show, | 317 bool activate_on_show, |
235 PopupChrome chrome) { | 318 bool inspect_with_devtools, |
| 319 PopupChrome chrome, |
| 320 Observer* observer) { |
236 DCHECK(profile); | 321 DCHECK(profile); |
237 DCHECK(frame_window); | 322 DCHECK(frame_window); |
238 ExtensionProcessManager* manager = profile->GetExtensionProcessManager(); | 323 ExtensionProcessManager* manager = profile->GetExtensionProcessManager(); |
239 DCHECK(manager); | 324 DCHECK(manager); |
240 if (!manager) | 325 if (!manager) |
241 return NULL; | 326 return NULL; |
242 | 327 |
243 // If no Browser instance was given, attempt to look up one matching the given | 328 // If no Browser instance was given, attempt to look up one matching the given |
244 // profile. | 329 // profile. |
245 if (!browser) | 330 if (!browser) |
246 browser = BrowserList::FindBrowserWithProfile(profile); | 331 browser = BrowserList::FindBrowserWithProfile(profile); |
247 | 332 |
248 Widget* frame_widget = Widget::GetWidgetFromNativeWindow(frame_window); | 333 Widget* frame_widget = Widget::GetWidgetFromNativeWindow(frame_window); |
249 DCHECK(frame_widget); | 334 DCHECK(frame_widget); |
250 if (!frame_widget) | 335 if (!frame_widget) |
251 return NULL; | 336 return NULL; |
252 | 337 |
253 ExtensionHost* host = manager->CreatePopup(url, browser); | 338 ExtensionHost* host = manager->CreatePopup(url, browser); |
254 ExtensionPopup* popup = new ExtensionPopup(host, frame_widget, relative_to, | 339 ExtensionPopup* popup = new ExtensionPopup(host, frame_widget, relative_to, |
255 arrow_location, activate_on_show, | 340 arrow_location, activate_on_show, |
256 chrome); | 341 inspect_with_devtools, chrome, |
| 342 observer); |
257 | 343 |
258 // If the host had somehow finished loading, then we'd miss the notification | 344 // If the host had somehow finished loading, then we'd miss the notification |
259 // and not show. This seems to happen in single-process mode. | 345 // and not show. This seems to happen in single-process mode. |
260 if (host->did_stop_loading()) | 346 if (host->did_stop_loading()) |
261 popup->Show(activate_on_show); | 347 popup->Show(activate_on_show); |
262 | 348 |
263 return popup; | 349 return popup; |
264 } | 350 } |
| 351 |
| 352 void ExtensionPopup::Close() { |
| 353 if (closing_) |
| 354 return; |
| 355 closing_ = true; |
| 356 DetachFromBrowser(); |
| 357 if (observer_) |
| 358 observer_->ExtensionPopupClosed(this); |
| 359 Release(); // Balanced in ctor. |
| 360 } |
OLD | NEW |