Home | History | Annotate | Download | only in views
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/ui/views/browser_bubble.h"
      6 
      7 #include "chrome/browser/ui/views/frame/browser_view.h"
      8 #if defined(OS_WIN)
      9 #include "chrome/browser/external_tab_container_win.h"
     10 #endif
     11 #include "views/widget/root_view.h"
     12 #include "views/window/window.h"
     13 
     14 namespace {
     15 
     16 BrowserBubbleHost* GetBubbleHostFromFrame(views::Widget* frame) {
     17   if (!frame)
     18     return NULL;
     19 
     20   BrowserBubbleHost* bubble_host = NULL;
     21   views::Window* window = frame->GetWindow();
     22   if (window) {
     23     bubble_host = BrowserView::GetBrowserViewForNativeWindow(
     24         window->GetNativeWindow());
     25     DCHECK(bubble_host);
     26   }
     27 
     28   return bubble_host;
     29 }
     30 
     31 }  // namespace
     32 
     33 BrowserBubble::BrowserBubble(views::View* view,
     34                              views::Widget* frame,
     35                              const gfx::Rect& relative_to,
     36                              BubbleBorder::ArrowLocation arrow_location)
     37     : frame_(frame),
     38       view_(view),
     39       relative_to_(relative_to),
     40       arrow_location_(arrow_location),
     41       visible_(false),
     42       delegate_(NULL),
     43       attached_(false),
     44       bubble_host_(GetBubbleHostFromFrame(frame)) {
     45   // Keep relative_to_ in frame-relative coordinates to aid in drag
     46   // positioning.
     47   gfx::Point origin = relative_to_.origin();
     48   views::View::ConvertPointToView(NULL, frame_->GetRootView(), &origin);
     49   relative_to_.set_origin(origin);
     50 
     51   InitPopup();
     52 }
     53 
     54 BrowserBubble::~BrowserBubble() {
     55   DCHECK(!attached_);
     56   popup_->Close();
     57 
     58   // Don't call DetachFromBrowser from here.  It needs to talk to the
     59   // BrowserView to deregister itself, and if BrowserBubble is owned
     60   // by a child of BrowserView, then it's possible that this stack frame
     61   // is a descendant of BrowserView's destructor, which leads to problems.
     62   // In that case, Detach doesn't need to get called anyway since BrowserView
     63   // will do the necessary cleanup.
     64 }
     65 
     66 void BrowserBubble::DetachFromBrowser() {
     67   DCHECK(attached_);
     68   if (!attached_)
     69     return;
     70   attached_ = false;
     71 
     72   if (bubble_host_)
     73     bubble_host_->DetachBrowserBubble(this);
     74 }
     75 
     76 void BrowserBubble::AttachToBrowser() {
     77   DCHECK(!attached_);
     78   if (attached_)
     79     return;
     80 
     81   if (bubble_host_)
     82     bubble_host_->AttachBrowserBubble(this);
     83 
     84   attached_ = true;
     85 }
     86 
     87 void BrowserBubble::BrowserWindowMoved() {
     88   if (delegate_)
     89     delegate_->BubbleBrowserWindowMoved(this);
     90   else
     91     Hide();
     92   if (visible_)
     93     Reposition();
     94 }
     95 
     96 void BrowserBubble::BrowserWindowClosing() {
     97   if (delegate_)
     98     delegate_->BubbleBrowserWindowClosing(this);
     99   else
    100     Hide();
    101 }
    102 
    103 void BrowserBubble::SetBounds(int x, int y, int w, int h) {
    104   // If the UI layout is RTL, we don't need to mirror coordinates, since
    105   // View logic will do that for us.
    106   bounds_.SetRect(x, y, w, h);
    107   Reposition();
    108 }
    109 
    110 void BrowserBubble::MoveTo(int x, int y) {
    111   SetBounds(x, y, bounds_.width(), bounds_.height());
    112 }
    113 
    114 void BrowserBubble::Reposition() {
    115   gfx::Point top_left;
    116   views::View::ConvertPointToScreen(frame_->GetRootView(), &top_left);
    117   MovePopup(top_left.x() + bounds_.x(),
    118             top_left.y() + bounds_.y(),
    119             bounds_.width(),
    120             bounds_.height());
    121 }
    122 
    123 gfx::Rect BrowserBubble::GetAbsoluteRelativeTo() {
    124   // |relative_to_| is in browser-relative coordinates, so convert it to
    125   // screen coordinates for use in placing the popup widgets.
    126   gfx::Rect relative_rect = relative_to_;
    127   gfx::Point relative_origin = relative_rect.origin();
    128   views::View::ConvertPointToScreen(frame_->GetRootView(), &relative_origin);
    129   relative_rect.set_origin(relative_origin);
    130 
    131   return relative_rect;
    132 }
    133 
    134 void BrowserBubble::SetAbsoluteBounds(const gfx::Rect& window_bounds) {
    135   // Convert screen coordinates to frame relative.
    136   gfx::Point relative_origin = window_bounds.origin();
    137   views::View::ConvertPointToView(NULL, frame_->GetRootView(),
    138                                   &relative_origin);
    139   SetBounds(relative_origin.x(), relative_origin.y(),
    140             window_bounds.width(), window_bounds.height());
    141 }
    142