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
GetBubbleHostFromFrame(views::Widget * frame)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
BrowserBubble(views::View * view,views::Widget * frame,const gfx::Rect & relative_to,BubbleBorder::ArrowLocation arrow_location)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
~BrowserBubble()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
DetachFromBrowser()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
AttachToBrowser()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
BrowserWindowMoved()87 void BrowserBubble::BrowserWindowMoved() {
88 if (delegate_)
89 delegate_->BubbleBrowserWindowMoved(this);
90 else
91 Hide();
92 if (visible_)
93 Reposition();
94 }
95
BrowserWindowClosing()96 void BrowserBubble::BrowserWindowClosing() {
97 if (delegate_)
98 delegate_->BubbleBrowserWindowClosing(this);
99 else
100 Hide();
101 }
102
SetBounds(int x,int y,int w,int h)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
MoveTo(int x,int y)110 void BrowserBubble::MoveTo(int x, int y) {
111 SetBounds(x, y, bounds_.width(), bounds_.height());
112 }
113
Reposition()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
GetAbsoluteRelativeTo()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
SetAbsoluteBounds(const gfx::Rect & window_bounds)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