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