summaryrefslogtreecommitdiffstats
path: root/chrome/browser/ui/views/browser_bubble.cc
blob: 71a92765b642c3c972d79da7141809433e0d708c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// 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 "ui/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));
}