| // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/ui/views/browser_bubble.h" |
| |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/views/frame/browser_view.h" |
| #include "views/widget/widget.h" |
| |
| BrowserBubble::BrowserBubble(Browser* browser, |
| views::View* view, |
| const gfx::Rect& relative_to, |
| views::BubbleBorder::ArrowLocation arrow_location) |
| : frame_(NULL), |
| view_(view), |
| relative_to_(relative_to), |
| arrow_location_(arrow_location), |
| delegate_(NULL), |
| attached_(false), |
| bubble_host_(NULL) { |
| BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser); |
| frame_ = browser_view->GetWidget(); |
| bubble_host_ = browser_view; |
| // Keep relative_to_ in frame-relative coordinates to aid in drag |
| // positioning. |
| gfx::Point origin = relative_to_.origin(); |
| views::View::ConvertPointToView(NULL, frame_->GetRootView(), &origin); |
| relative_to_.set_origin(origin); |
| |
| // Use half the corner radius as contents margins so that contents fit better |
| // in the bubble. See http://crbug.com/80416. |
| int corner_inset = views::BubbleBorder::GetCornerRadius() / 2; |
| gfx::Insets content_margins(corner_inset, corner_inset, |
| corner_inset, corner_inset); |
| InitPopup(content_margins); |
| } |
| |
| BrowserBubble::~BrowserBubble() { |
| DCHECK(!attached_); |
| popup_->Close(); |
| |
| // Don't call DetachFromBrowser from here. It needs to talk to the |
| // BrowserView to deregister itself, and if BrowserBubble is owned |
| // by a child of BrowserView, then it's possible that this stack frame |
| // is a descendant of BrowserView's destructor, which leads to problems. |
| // In that case, Detach doesn't need to get called anyway since BrowserView |
| // will do the necessary cleanup. |
| } |
| |
| void BrowserBubble::DetachFromBrowser() { |
| DCHECK(attached_); |
| if (!attached_) |
| return; |
| attached_ = false; |
| |
| if (bubble_host_) |
| bubble_host_->DetachBrowserBubble(this); |
| } |
| |
| void BrowserBubble::AttachToBrowser() { |
| DCHECK(!attached_); |
| if (attached_) |
| return; |
| |
| if (bubble_host_) |
| bubble_host_->AttachBrowserBubble(this); |
| |
| attached_ = true; |
| } |
| |
| void BrowserBubble::BrowserWindowMoved() { |
| if (delegate_) |
| delegate_->BubbleBrowserWindowMoved(this); |
| else |
| Hide(); |
| if (popup_->IsVisible()) |
| Reposition(); |
| } |
| |
| void BrowserBubble::BrowserWindowClosing() { |
| if (delegate_) |
| delegate_->BubbleBrowserWindowClosing(this); |
| else |
| Hide(); |
| } |
| |
| void BrowserBubble::SetBounds(int x, int y, int w, int h) { |
| // If the UI layout is RTL, we don't need to mirror coordinates, since |
| // View logic will do that for us. |
| bounds_.SetRect(x, y, w, h); |
| Reposition(); |
| } |
| |
| void BrowserBubble::MoveTo(int x, int y) { |
| SetBounds(x, y, bounds_.width(), bounds_.height()); |
| } |
| |
| void BrowserBubble::Reposition() { |
| gfx::Point top_left; |
| views::View::ConvertPointToScreen(frame_->GetRootView(), &top_left); |
| MovePopup(top_left.x() + bounds_.x(), |
| top_left.y() + bounds_.y(), |
| bounds_.width(), |
| bounds_.height()); |
| } |
| |
| gfx::Rect BrowserBubble::GetAbsoluteRelativeTo() { |
| // |relative_to_| is in browser-relative coordinates, so convert it to |
| // screen coordinates for use in placing the popup widgets. |
| gfx::Rect relative_rect = relative_to_; |
| gfx::Point relative_origin = relative_rect.origin(); |
| views::View::ConvertPointToScreen(frame_->GetRootView(), &relative_origin); |
| relative_rect.set_origin(relative_origin); |
| |
| return relative_rect; |
| } |
| |
| void BrowserBubble::SetAbsoluteBounds(const gfx::Rect& window_bounds) { |
| // Convert screen coordinates to frame relative. |
| gfx::Point relative_origin = window_bounds.origin(); |
| views::View::ConvertPointToView(NULL, frame_->GetRootView(), |
| &relative_origin); |
| SetBounds(relative_origin.x(), relative_origin.y(), |
| window_bounds.width(), window_bounds.height()); |
| } |
| |
| void BrowserBubble::MovePopup(int x, int y, int w, int h) { |
| popup_->SetBounds(gfx::Rect(x, y, w, h)); |
| } |