| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/ui/views/extensions/extension_popup.h" | 5 #include "chrome/browser/ui/views/extensions/extension_popup.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "chrome/browser/debugger/devtools_manager.h" | 9 #include "chrome/browser/debugger/devtools_manager.h" |
| 10 #include "chrome/browser/debugger/devtools_toggle_action.h" | 10 #include "chrome/browser/debugger/devtools_toggle_action.h" |
| 11 #include "chrome/browser/extensions/extension_host.h" | 11 #include "chrome/browser/extensions/extension_host.h" |
| 12 #include "chrome/browser/extensions/extension_process_manager.h" | 12 #include "chrome/browser/extensions/extension_process_manager.h" |
| 13 #include "chrome/browser/profiles/profile.h" | 13 #include "chrome/browser/profiles/profile.h" |
| 14 #include "chrome/browser/renderer_host/render_widget_host_view.h" | 14 #include "chrome/browser/renderer_host/render_widget_host_view.h" |
| 15 #include "chrome/browser/renderer_host/render_view_host.h" | 15 #include "chrome/browser/renderer_host/render_view_host.h" |
| 16 #include "chrome/browser/ui/browser.h" | 16 #include "chrome/browser/ui/browser.h" |
| 17 #include "chrome/browser/ui/browser_list.h" | |
| 18 #include "chrome/browser/ui/browser_window.h" | 17 #include "chrome/browser/ui/browser_window.h" |
| 19 #include "chrome/browser/ui/views/frame/browser_view.h" | 18 #include "chrome/browser/ui/views/frame/browser_view.h" |
| 20 #include "chrome/browser/ui/window_sizer.h" | |
| 21 #include "chrome/common/extensions/extension.h" | 19 #include "chrome/common/extensions/extension.h" |
| 22 #include "chrome/common/notification_details.h" | 20 #include "chrome/common/notification_details.h" |
| 23 #include "chrome/common/notification_source.h" | 21 #include "chrome/common/notification_source.h" |
| 24 #include "chrome/common/notification_type.h" | 22 #include "chrome/common/notification_type.h" |
| 25 #include "third_party/skia/include/core/SkColor.h" | |
| 26 #include "views/widget/root_view.h" | 23 #include "views/widget/root_view.h" |
| 27 #include "views/window/window.h" | 24 #include "views/window/window.h" |
| 28 | 25 |
| 29 #if defined(OS_LINUX) | 26 #if defined(OS_LINUX) |
| 30 #include "views/widget/widget_gtk.h" | 27 #include "views/widget/widget_gtk.h" |
| 31 #endif | 28 #endif |
| 32 | 29 |
| 33 #if defined(OS_CHROMEOS) | 30 #if defined(OS_CHROMEOS) |
| 34 #include "chrome/browser/chromeos/wm_ipc.h" | 31 #include "chrome/browser/chromeos/wm_ipc.h" |
| 35 #include "third_party/cros/chromeos_wm_ipc_enums.h" | 32 #include "third_party/cros/chromeos_wm_ipc_enums.h" |
| 36 #endif | 33 #endif |
| 37 | 34 |
| 38 using std::vector; | 35 using std::vector; |
| 39 using views::Widget; | 36 using views::Widget; |
| 40 | 37 |
| 41 // The minimum, and default maximum dimensions of the popup. | 38 // The minimum/maximum dimensions of the popup. |
| 42 // The minimum is just a little larger than the size of the button itself. | 39 // The minimum is just a little larger than the size of the button itself. |
| 43 // The default maximum is an arbitrary number that should be smaller than most | 40 // The maximum is an arbitrary number that should be smaller than most screens. |
| 44 // screens. | |
| 45 const int ExtensionPopup::kMinWidth = 25; | 41 const int ExtensionPopup::kMinWidth = 25; |
| 46 const int ExtensionPopup::kMinHeight = 25; | 42 const int ExtensionPopup::kMinHeight = 25; |
| 47 const int ExtensionPopup::kMaxWidth = 800; | 43 const int ExtensionPopup::kMaxWidth = 800; |
| 48 const int ExtensionPopup::kMaxHeight = 600; | 44 const int ExtensionPopup::kMaxHeight = 600; |
| 49 | 45 |
| 50 namespace { | 46 namespace { |
| 51 | 47 |
| 52 // The width, in pixels, of the black-border on a popup. | 48 // The width, in pixels, of the black-border on a popup. |
| 53 const int kPopupBorderWidth = 1; | 49 const int kPopupBorderWidth = 1; |
| 54 | 50 |
| 55 const int kPopupBubbleCornerRadius = BubbleBorder::GetCornerRadius() / 2; | 51 const int kPopupBubbleCornerRadius = BubbleBorder::GetCornerRadius() / 2; |
| 56 | 52 |
| 57 } // namespace | 53 } // namespace |
| 58 | 54 |
| 59 ExtensionPopup::ExtensionPopup(ExtensionHost* host, | 55 ExtensionPopup::ExtensionPopup(ExtensionHost* host, |
| 60 views::Widget* frame, | 56 views::Widget* frame, |
| 61 const gfx::Rect& relative_to, | 57 const gfx::Rect& relative_to, |
| 62 BubbleBorder::ArrowLocation arrow_location, | 58 BubbleBorder::ArrowLocation arrow_location, |
| 63 bool activate_on_show, | |
| 64 bool inspect_with_devtools, | 59 bool inspect_with_devtools, |
| 65 PopupChrome chrome, | |
| 66 Observer* observer) | 60 Observer* observer) |
| 67 : BrowserBubble(host->view(), | 61 : BrowserBubble(host->view(), |
| 68 frame, | 62 frame, |
| 69 gfx::Point(), | 63 gfx::Point()), |
| 70 RECTANGLE_CHROME == chrome), // If no bubble chrome is to | |
| 71 // be displayed, then enable a | |
| 72 // drop-shadow on the bubble | |
| 73 // widget. | |
| 74 relative_to_(relative_to), | 64 relative_to_(relative_to), |
| 75 extension_host_(host), | 65 extension_host_(host), |
| 76 activate_on_show_(activate_on_show), | |
| 77 inspect_with_devtools_(inspect_with_devtools), | 66 inspect_with_devtools_(inspect_with_devtools), |
| 78 close_on_lost_focus_(true), | 67 close_on_lost_focus_(true), |
| 79 closing_(false), | 68 closing_(false), |
| 80 border_widget_(NULL), | 69 border_widget_(NULL), |
| 81 border_(NULL), | 70 border_(NULL), |
| 82 border_view_(NULL), | 71 border_view_(NULL), |
| 83 popup_chrome_(chrome), | |
| 84 max_size_(kMaxWidth, kMaxHeight), | |
| 85 observer_(observer), | 72 observer_(observer), |
| 86 anchor_position_(arrow_location), | 73 anchor_position_(arrow_location) { |
| 87 instance_lifetime_(new InternalRefCounter()){ | |
| 88 AddRef(); // Balanced in Close(); | 74 AddRef(); // Balanced in Close(); |
| 89 set_delegate(this); | 75 set_delegate(this); |
| 90 host->view()->SetContainer(this); | 76 host->view()->SetContainer(this); |
| 91 | 77 |
| 92 // We wait to show the popup until the contained host finishes loading. | 78 // We wait to show the popup until the contained host finishes loading. |
| 93 registrar_.Add(this, | 79 registrar_.Add(this, |
| 94 NotificationType::EXTENSION_HOST_DID_STOP_LOADING, | 80 NotificationType::EXTENSION_HOST_DID_STOP_LOADING, |
| 95 Source<Profile>(host->profile())); | 81 Source<Profile>(host->profile())); |
| 96 | 82 |
| 97 // Listen for the containing view calling window.close(); | 83 // Listen for the containing view calling window.close(); |
| 98 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, | 84 registrar_.Add(this, NotificationType::EXTENSION_HOST_VIEW_SHOULD_CLOSE, |
| 99 Source<Profile>(host->profile())); | 85 Source<Profile>(host->profile())); |
| 100 | 86 |
| 101 // TODO(erikkay) Some of this border code is derived from InfoBubble. | 87 // TODO(erikkay) Some of this border code is derived from InfoBubble. |
| 102 // We should see if we can unify these classes. | 88 // We should see if we can unify these classes. |
| 103 | 89 |
| 104 // Keep relative_to_ in frame-relative coordinates to aid in drag | 90 // Keep relative_to_ in frame-relative coordinates to aid in drag |
| 105 // positioning. | 91 // positioning. |
| 106 gfx::Point origin = relative_to_.origin(); | 92 gfx::Point origin = relative_to_.origin(); |
| 107 views::View::ConvertPointToView(NULL, frame_->GetRootView(), &origin); | 93 views::View::ConvertPointToView(NULL, frame_->GetRootView(), &origin); |
| 108 relative_to_.set_origin(origin); | 94 relative_to_.set_origin(origin); |
| 109 | 95 |
| 110 // The bubble chrome requires a separate window, so construct it here. | 96 // The bubble chrome requires a separate window, so construct it here. |
| 111 if (BUBBLE_CHROME == popup_chrome_) { | 97 gfx::NativeView native_window = frame->GetNativeView(); |
| 112 gfx::NativeView native_window = frame->GetNativeView(); | |
| 113 #if defined(OS_LINUX) | 98 #if defined(OS_LINUX) |
| 114 border_widget_ = new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW); | 99 border_widget_ = new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW); |
| 115 static_cast<views::WidgetGtk*>(border_widget_)->MakeTransparent(); | 100 static_cast<views::WidgetGtk*>(border_widget_)->MakeTransparent(); |
| 116 static_cast<views::WidgetGtk*>(border_widget_)->make_transient_to_parent(); | 101 static_cast<views::WidgetGtk*>(border_widget_)->make_transient_to_parent(); |
| 117 #else | 102 #else |
| 118 border_widget_ = Widget::CreatePopupWidget(Widget::Transparent, | 103 border_widget_ = Widget::CreatePopupWidget(Widget::Transparent, |
| 119 Widget::NotAcceptEvents, | 104 Widget::NotAcceptEvents, |
| 120 Widget::DeleteOnDestroy, | 105 Widget::DeleteOnDestroy, |
| 121 Widget::MirrorOriginInRTL); | 106 Widget::MirrorOriginInRTL); |
| 122 #endif | 107 #endif |
| 123 border_widget_->Init(native_window, bounds()); | 108 border_widget_->Init(native_window, bounds()); |
| 124 #if defined(OS_CHROMEOS) | 109 #if defined(OS_CHROMEOS) |
| 125 { | 110 { |
| 126 vector<int> params; | 111 vector<int> params; |
| 127 params.push_back(0); // don't show while screen is locked | 112 params.push_back(0); // don't show while screen is locked |
| 128 chromeos::WmIpc::instance()->SetWindowType( | 113 chromeos::WmIpc::instance()->SetWindowType( |
| 129 border_widget_->GetNativeView(), | 114 border_widget_->GetNativeView(), |
| 130 chromeos::WM_IPC_WINDOW_CHROME_INFO_BUBBLE, | 115 chromeos::WM_IPC_WINDOW_CHROME_INFO_BUBBLE, |
| 131 ¶ms); | 116 ¶ms); |
| 132 } | 117 } |
| 133 #endif | 118 #endif |
| 134 border_ = new BubbleBorder(arrow_location); | 119 border_ = new BubbleBorder(arrow_location); |
| 135 border_view_ = new views::View; | 120 border_view_ = new views::View; |
| 136 border_view_->set_background(new BubbleBackground(border_)); | 121 border_view_->set_background(new BubbleBackground(border_)); |
| 137 | 122 |
| 138 border_view_->set_border(border_); | 123 border_view_->set_border(border_); |
| 139 border_widget_->SetContentsView(border_view_); | 124 border_widget_->SetContentsView(border_view_); |
| 140 // Ensure that the popup contents are always displayed ontop of the border | 125 // Ensure that the popup contents are always displayed ontop of the border |
| 141 // widget. | 126 // widget. |
| 142 border_widget_->MoveAbove(popup_); | 127 border_widget_->MoveAbove(popup_); |
| 143 } else { | |
| 144 // Otherwise simply set a black-border on the view containing the popup | |
| 145 // extension view. | |
| 146 views::Border* border = views::Border::CreateSolidBorder(kPopupBorderWidth, | |
| 147 SK_ColorBLACK); | |
| 148 view()->set_border(border); | |
| 149 } | |
| 150 } | 128 } |
| 151 | 129 |
| 152 ExtensionPopup::~ExtensionPopup() { | 130 ExtensionPopup::~ExtensionPopup() { |
| 153 // The widget is set to delete on destroy, so no leak here. | 131 // The widget is set to delete on destroy, so no leak here. |
| 154 if (border_widget_) | 132 border_widget_->Close(); |
| 155 border_widget_->Close(); | |
| 156 } | |
| 157 | |
| 158 void ExtensionPopup::SetArrowPosition( | |
| 159 BubbleBorder::ArrowLocation arrow_location) { | |
| 160 DCHECK_NE(BubbleBorder::NONE, arrow_location) << | |
| 161 "Extension popups must be positioned relative to an arrow."; | |
| 162 | |
| 163 anchor_position_ = arrow_location; | |
| 164 if (border_) | |
| 165 border_->set_arrow_location(anchor_position_); | |
| 166 } | 133 } |
| 167 | 134 |
| 168 void ExtensionPopup::Hide() { | 135 void ExtensionPopup::Hide() { |
| 169 BrowserBubble::Hide(); | 136 BrowserBubble::Hide(); |
| 170 if (border_widget_) | 137 border_widget_->Hide(); |
| 171 border_widget_->Hide(); | |
| 172 } | 138 } |
| 173 | 139 |
| 174 void ExtensionPopup::Show(bool activate) { | 140 void ExtensionPopup::Show(bool activate) { |
| 175 if (visible()) | 141 if (visible()) |
| 176 return; | 142 return; |
| 177 | 143 |
| 178 #if defined(OS_WIN) | 144 #if defined(OS_WIN) |
| 179 if (frame_->GetWindow()) | 145 frame_->GetWindow()->DisableInactiveRendering(); |
| 180 frame_->GetWindow()->DisableInactiveRendering(); | |
| 181 #endif | 146 #endif |
| 182 | 147 |
| 183 ResizeToView(); | 148 ResizeToView(); |
| 184 | 149 |
| 185 // Show the border first, then the popup overlaid on top. | 150 // Show the border first, then the popup overlaid on top. |
| 186 if (border_widget_) | 151 border_widget_->Show(); |
| 187 border_widget_->Show(); | |
| 188 BrowserBubble::Show(activate); | 152 BrowserBubble::Show(activate); |
| 189 } | 153 } |
| 190 | 154 |
| 191 void ExtensionPopup::ResizeToView() { | 155 void ExtensionPopup::ResizeToView() { |
| 192 if (observer_) | 156 // We'll be sizing ourselves to this size shortly, but wait until we |
| 193 observer_->ExtensionPopupResized(this); | 157 // know our position to do it. |
| 158 gfx::Size new_size = view()->size(); |
| 194 | 159 |
| 195 gfx::Rect rect = GetOuterBounds(); | 160 // The rounded corners cut off more of the view than the border insets claim. |
| 161 // Since we can't clip the ExtensionView's corners, we need to increase the |
| 162 // inset by half the corner radius as well as lying about the size of the |
| 163 // contents size to compensate. |
| 164 int corner_inset = BubbleBorder::GetCornerRadius() / 2; |
| 165 gfx::Size adjusted_size = new_size; |
| 166 adjusted_size.Enlarge(2 * corner_inset, 2 * corner_inset); |
| 167 gfx::Rect rect = border_->GetBounds(relative_to_, adjusted_size); |
| 168 border_widget_->SetBounds(rect); |
| 196 | 169 |
| 170 // Now calculate the inner bounds. This is a bit more convoluted than |
| 171 // it should be because BrowserBubble coordinates are in Browser coordinates |
| 172 // while |rect| is in screen coordinates. |
| 173 gfx::Insets border_insets; |
| 174 border_->GetInsets(&border_insets); |
| 197 gfx::Point origin = rect.origin(); | 175 gfx::Point origin = rect.origin(); |
| 198 views::View::ConvertPointToView(NULL, frame_->GetRootView(), &origin); | 176 views::View::ConvertPointToView(NULL, frame_->GetRootView(), &origin); |
| 199 | 177 |
| 200 if (border_widget_) { | 178 origin.set_x(origin.x() + border_insets.left() + corner_inset); |
| 201 // Set the bubble-chrome widget according to the outer bounds of the entire | 179 origin.set_y(origin.y() + border_insets.top() + corner_inset); |
| 202 // popup. | |
| 203 border_widget_->SetBounds(rect); | |
| 204 | 180 |
| 205 // Now calculate the inner bounds. This is a bit more convoluted than | 181 SetBounds(origin.x(), origin.y(), new_size.width(), new_size.height()); |
| 206 // it should be because BrowserBubble coordinates are in Browser coordinates | |
| 207 // while |rect| is in screen coordinates. | |
| 208 gfx::Insets border_insets; | |
| 209 border_->GetInsets(&border_insets); | |
| 210 | |
| 211 origin.set_x(origin.x() + border_insets.left() + kPopupBubbleCornerRadius); | |
| 212 origin.set_y(origin.y() + border_insets.top() + kPopupBubbleCornerRadius); | |
| 213 | |
| 214 gfx::Size new_size = view()->size(); | |
| 215 SetBounds(origin.x(), origin.y(), new_size.width(), new_size.height()); | |
| 216 } else { | |
| 217 SetBounds(origin.x(), origin.y(), rect.width(), rect.height()); | |
| 218 } | |
| 219 } | 182 } |
| 220 | 183 |
| 221 void ExtensionPopup::BubbleBrowserWindowMoved(BrowserBubble* bubble) { | 184 void ExtensionPopup::BubbleBrowserWindowMoved(BrowserBubble* bubble) { |
| 222 ResizeToView(); | 185 ResizeToView(); |
| 223 } | 186 } |
| 224 | 187 |
| 225 void ExtensionPopup::BubbleBrowserWindowClosing(BrowserBubble* bubble) { | 188 void ExtensionPopup::BubbleBrowserWindowClosing(BrowserBubble* bubble) { |
| 226 if (!closing_) | 189 if (!closing_) |
| 227 Close(); | 190 Close(); |
| 228 } | 191 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 252 | 215 |
| 253 | 216 |
| 254 void ExtensionPopup::Observe(NotificationType type, | 217 void ExtensionPopup::Observe(NotificationType type, |
| 255 const NotificationSource& source, | 218 const NotificationSource& source, |
| 256 const NotificationDetails& details) { | 219 const NotificationDetails& details) { |
| 257 switch (type.value) { | 220 switch (type.value) { |
| 258 case NotificationType::EXTENSION_HOST_DID_STOP_LOADING: | 221 case NotificationType::EXTENSION_HOST_DID_STOP_LOADING: |
| 259 // Once we receive did stop loading, the content will be complete and | 222 // Once we receive did stop loading, the content will be complete and |
| 260 // the width will have been computed. Now it's safe to show. | 223 // the width will have been computed. Now it's safe to show. |
| 261 if (extension_host_.get() == Details<ExtensionHost>(details).ptr()) { | 224 if (extension_host_.get() == Details<ExtensionHost>(details).ptr()) { |
| 262 Show(activate_on_show_); | 225 Show(true); |
| 263 | 226 |
| 264 if (inspect_with_devtools_) { | 227 if (inspect_with_devtools_) { |
| 265 // Listen for the the devtools window closing. | 228 // Listen for the the devtools window closing. |
| 266 registrar_.Add(this, NotificationType::DEVTOOLS_WINDOW_CLOSING, | 229 registrar_.Add(this, NotificationType::DEVTOOLS_WINDOW_CLOSING, |
| 267 Source<Profile>(extension_host_->profile())); | 230 Source<Profile>(extension_host_->profile())); |
| 268 DevToolsManager::GetInstance()->ToggleDevToolsWindow( | 231 DevToolsManager::GetInstance()->ToggleDevToolsWindow( |
| 269 extension_host_->render_view_host(), | 232 extension_host_->render_view_host(), |
| 270 DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE); | 233 DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE); |
| 271 } | 234 } |
| 272 } | 235 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 292 | 255 |
| 293 break; | 256 break; |
| 294 default: | 257 default: |
| 295 NOTREACHED() << L"Received unexpected notification"; | 258 NOTREACHED() << L"Received unexpected notification"; |
| 296 } | 259 } |
| 297 } | 260 } |
| 298 | 261 |
| 299 void ExtensionPopup::OnExtensionPreferredSizeChanged(ExtensionView* view) { | 262 void ExtensionPopup::OnExtensionPreferredSizeChanged(ExtensionView* view) { |
| 300 // Constrain the size to popup min/max. | 263 // Constrain the size to popup min/max. |
| 301 gfx::Size sz = view->GetPreferredSize(); | 264 gfx::Size sz = view->GetPreferredSize(); |
| 302 | |
| 303 // Enforce that the popup never resizes to larger than the working monitor | |
| 304 // bounds. | |
| 305 scoped_ptr<WindowSizer::MonitorInfoProvider> monitor_provider( | |
| 306 WindowSizer::CreateDefaultMonitorInfoProvider()); | |
| 307 gfx::Rect monitor_bounds( | |
| 308 monitor_provider->GetMonitorWorkAreaMatching(relative_to_)); | |
| 309 | |
| 310 int max_width = std::min(max_size_.width(), monitor_bounds.width()); | |
| 311 int max_height = std::min(max_size_.height(), monitor_bounds.height()); | |
| 312 view->SetBounds(view->x(), view->y(), | 265 view->SetBounds(view->x(), view->y(), |
| 313 std::max(kMinWidth, std::min(max_width, sz.width())), | 266 std::max(kMinWidth, std::min(kMaxWidth, sz.width())), |
| 314 std::max(kMinHeight, std::min(max_height, sz.height()))); | 267 std::max(kMinHeight, std::min(kMaxHeight, sz.height()))); |
| 315 | |
| 316 // If popup_chrome_ == RECTANGLE_CHROME, the border is drawn in the client | |
| 317 // area of the ExtensionView, rather than in a window which sits behind it. | |
| 318 // In this case, the actual size of the view must be enlarged so that the | |
| 319 // web contents portion of the view gets its full PreferredSize area. | |
| 320 if (view->border()) { | |
| 321 gfx::Insets border_insets; | |
| 322 view->border()->GetInsets(&border_insets); | |
| 323 | |
| 324 gfx::Rect bounds(view->bounds()); | |
| 325 gfx::Size size(bounds.size()); | |
| 326 size.Enlarge(border_insets.width(), border_insets.height()); | |
| 327 view->SetBounds(bounds.x(), bounds.y(), size.width(), size.height()); | |
| 328 } | |
| 329 | 268 |
| 330 ResizeToView(); | 269 ResizeToView(); |
| 331 } | 270 } |
| 332 | 271 |
| 333 gfx::Rect ExtensionPopup::GetOuterBounds() const { | |
| 334 gfx::Rect relative_rect = relative_to_; | |
| 335 gfx::Point origin = relative_rect.origin(); | |
| 336 views::View::ConvertPointToScreen(frame_->GetRootView(), &origin); | |
| 337 relative_rect.set_origin(origin); | |
| 338 | |
| 339 gfx::Size contents_size = view()->size(); | |
| 340 | |
| 341 // If the popup has a bubble-chrome, then let the BubbleBorder compute | |
| 342 // the bounds. | |
| 343 if (BUBBLE_CHROME == popup_chrome_) { | |
| 344 // The rounded corners cut off more of the view than the border insets | |
| 345 // claim. Since we can't clip the ExtensionView's corners, we need to | |
| 346 // increase the inset by half the corner radius as well as lying about the | |
| 347 // size of the contents size to compensate. | |
| 348 contents_size.Enlarge(2 * kPopupBubbleCornerRadius, | |
| 349 2 * kPopupBubbleCornerRadius); | |
| 350 return border_->GetBounds(relative_rect, contents_size); | |
| 351 } | |
| 352 | |
| 353 // Position the bounds according to the location of the |anchor_position_|. | |
| 354 int y; | |
| 355 if (BubbleBorder::is_arrow_on_top(anchor_position_)) | |
| 356 y = relative_rect.bottom(); | |
| 357 else | |
| 358 y = relative_rect.y() - contents_size.height(); | |
| 359 | |
| 360 int x; | |
| 361 if (BubbleBorder::is_arrow_on_left(anchor_position_)) | |
| 362 x = relative_rect.x(); | |
| 363 else | |
| 364 // Note that if the arrow is on the right, that the x position of the popup | |
| 365 // is assigned so that the rightmost edge of the popup is aligned with the | |
| 366 // rightmost edge of the relative region. | |
| 367 x = relative_rect.right() - contents_size.width(); | |
| 368 | |
| 369 return gfx::Rect(x, y, contents_size.width(), contents_size.height()); | |
| 370 } | |
| 371 | |
| 372 // static | 272 // static |
| 373 ExtensionPopup* ExtensionPopup::Show( | 273 ExtensionPopup* ExtensionPopup::Show( |
| 374 const GURL& url, | 274 const GURL& url, |
| 375 Browser* browser, | 275 Browser* browser, |
| 376 Profile* profile, | |
| 377 gfx::NativeWindow frame_window, | |
| 378 const gfx::Rect& relative_to, | 276 const gfx::Rect& relative_to, |
| 379 BubbleBorder::ArrowLocation arrow_location, | 277 BubbleBorder::ArrowLocation arrow_location, |
| 380 bool activate_on_show, | |
| 381 bool inspect_with_devtools, | 278 bool inspect_with_devtools, |
| 382 PopupChrome chrome, | |
| 383 Observer* observer) { | 279 Observer* observer) { |
| 384 DCHECK(profile); | 280 ExtensionProcessManager* manager = |
| 385 DCHECK(frame_window); | 281 browser->profile()->GetExtensionProcessManager(); |
| 386 ExtensionProcessManager* manager = profile->GetExtensionProcessManager(); | |
| 387 DCHECK(manager); | 282 DCHECK(manager); |
| 388 if (!manager) | 283 if (!manager) |
| 389 return NULL; | 284 return NULL; |
| 390 | 285 |
| 391 // If no Browser instance was given, attempt to look up one matching the given | |
| 392 // profile. | |
| 393 if (!browser) | |
| 394 browser = BrowserList::FindBrowserWithProfile(profile); | |
| 395 | |
| 396 Widget* frame_widget = Widget::GetWidgetFromNativeWindow(frame_window); | |
| 397 DCHECK(frame_widget); | |
| 398 if (!frame_widget) | |
| 399 return NULL; | |
| 400 | |
| 401 ExtensionHost* host = manager->CreatePopup(url, browser); | 286 ExtensionHost* host = manager->CreatePopup(url, browser); |
| 402 if (observer) | 287 views::Widget* frame = BrowserView::GetBrowserViewForNativeWindow( |
| 403 observer->ExtensionHostCreated(host); | 288 browser->window()->GetNativeHandle())->GetWidget(); |
| 404 | 289 ExtensionPopup* popup = new ExtensionPopup(host, frame, relative_to, |
| 405 ExtensionPopup* popup = new ExtensionPopup(host, frame_widget, relative_to, | 290 arrow_location, |
| 406 arrow_location, activate_on_show, | 291 inspect_with_devtools, observer); |
| 407 inspect_with_devtools, chrome, | |
| 408 observer); | |
| 409 | |
| 410 if (observer) | |
| 411 observer->ExtensionPopupCreated(popup); | |
| 412 | 292 |
| 413 // If the host had somehow finished loading, then we'd miss the notification | 293 // If the host had somehow finished loading, then we'd miss the notification |
| 414 // and not show. This seems to happen in single-process mode. | 294 // and not show. This seems to happen in single-process mode. |
| 415 if (host->did_stop_loading()) | 295 if (host->did_stop_loading()) |
| 416 popup->Show(activate_on_show); | 296 popup->Show(true); |
| 417 | 297 |
| 418 return popup; | 298 return popup; |
| 419 } | 299 } |
| 420 | 300 |
| 421 void ExtensionPopup::Close() { | 301 void ExtensionPopup::Close() { |
| 422 if (closing_) | 302 if (closing_) |
| 423 return; | 303 return; |
| 424 closing_ = true; | 304 closing_ = true; |
| 425 DetachFromBrowser(); | 305 DetachFromBrowser(); |
| 426 | 306 |
| 427 if (observer_) | 307 if (observer_) |
| 428 observer_->ExtensionPopupIsClosing(this); | 308 observer_->ExtensionPopupIsClosing(this); |
| 429 | 309 |
| 430 Release(); // Balanced in ctor. | 310 Release(); // Balanced in ctor. |
| 431 } | 311 } |
| 432 | |
| 433 void ExtensionPopup::Release() { | |
| 434 bool final_release = instance_lifetime_->HasOneRef(); | |
| 435 instance_lifetime_->Release(); | |
| 436 if (final_release) { | |
| 437 DCHECK(closing_) << "ExtensionPopup to be destroyed before being closed."; | |
| 438 ExtensionPopup::Observer* observer = observer_; | |
| 439 delete this; | |
| 440 | |
| 441 // |this| is passed only as a 'cookie'. The observer API explicitly takes a | |
| 442 // void* argument to emphasize this. | |
| 443 if (observer) | |
| 444 observer->ExtensionPopupClosed(this); | |
| 445 } | |
| 446 } | |
| OLD | NEW |