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/bubble/border_contents.h" 8 #include "chrome/browser/ui/views/bubble/border_widget_win.h" 9 #include "chrome/browser/ui/views/frame/browser_view.h" 10 #include "views/widget/root_view.h" 11 #include "views/widget/widget_win.h" 12 #include "views/window/window.h" 13 14 class BubbleWidget : public views::WidgetWin { 15 public: 16 explicit BubbleWidget(BrowserBubble* bubble) 17 : bubble_(bubble), 18 border_widget_(new BorderWidgetWin) { 19 set_window_style(WS_POPUP | WS_CLIPCHILDREN); 20 set_window_ex_style(WS_EX_TOOLWINDOW); 21 } 22 23 void ShowAndActivate(bool activate) { 24 // Show the border first, then the popup overlaid on top. 25 border_widget_->Show(); 26 if (activate) 27 ShowWindow(SW_SHOW); 28 else 29 views::WidgetWin::Show(); 30 } 31 32 void Close() { 33 if (!bubble_) 34 return; // We have already been closed. 35 if (IsActive()) { 36 BrowserBubble::Delegate* delegate = bubble_->delegate(); 37 if (delegate) 38 delegate->BubbleLostFocus(bubble_, NULL); 39 } 40 border_widget_->Close(); 41 views::WidgetWin::Close(); 42 bubble_ = NULL; 43 } 44 45 void Hide() { 46 if (IsActive() && bubble_) { 47 BrowserBubble::Delegate* delegate = bubble_->delegate(); 48 if (delegate) 49 delegate->BubbleLostFocus(bubble_, NULL); 50 } 51 views::WidgetWin::Hide(); 52 border_widget_->Hide(); 53 } 54 55 void OnActivate(UINT action, BOOL minimized, HWND window) { 56 WidgetWin::OnActivate(action, minimized, window); 57 if (!bubble_) 58 return; 59 60 BrowserBubble::Delegate* delegate = bubble_->delegate(); 61 if (!delegate) { 62 if (action == WA_INACTIVE) { 63 bubble_->DetachFromBrowser(); 64 delete bubble_; 65 } 66 return; 67 } 68 69 if (action == WA_INACTIVE) { 70 bool lost_focus_to_child = false; 71 72 // Are we a parent of this window? 73 gfx::NativeView parent = window; 74 while (parent = ::GetParent(parent)) { 75 if (window == GetNativeView()) { 76 lost_focus_to_child = true; 77 break; 78 } 79 } 80 81 // Do we own this window? 82 if (!lost_focus_to_child && 83 ::GetWindow(window, GW_OWNER) == GetNativeView()) { 84 lost_focus_to_child = true; 85 } 86 87 delegate->BubbleLostFocus(bubble_, lost_focus_to_child); 88 } 89 } 90 91 virtual void OnSetFocus(HWND focused_window) { 92 WidgetWin::OnSetFocus(focused_window); 93 if (bubble_ && bubble_->delegate()) 94 bubble_->delegate()->BubbleGotFocus(bubble_); 95 } 96 97 BorderWidgetWin* border_widget() { 98 return border_widget_; 99 } 100 101 private: 102 BrowserBubble* bubble_; 103 BorderWidgetWin* border_widget_; 104 105 DISALLOW_COPY_AND_ASSIGN(BubbleWidget); 106 }; 107 108 void BrowserBubble::InitPopup() { 109 // popup_ is a Widget, but we need to do some WidgetWin stuff first, then 110 // we'll assign it into popup_. 111 BubbleWidget* pop = new BubbleWidget(this); 112 113 BorderWidgetWin* border_widget = pop->border_widget(); 114 border_widget->Init(new BorderContents, frame_->GetNativeView()); 115 116 // We make the BorderWidgetWin the owner of the Bubble HWND, so that the 117 // latter is displayed on top of the former. 118 pop->Init(border_widget->GetNativeView(), gfx::Rect()); 119 pop->SetContentsView(view_); 120 121 popup_ = pop; 122 123 ResizeToView(); 124 Reposition(); 125 AttachToBrowser(); 126 } 127 128 void BrowserBubble::MovePopup(int x, int y, int w, int h) { 129 views::WidgetWin* pop = static_cast<views::WidgetWin*>(popup_); 130 pop->SetBounds(gfx::Rect(x, y, w, h)); 131 } 132 133 void BrowserBubble::Show(bool activate) { 134 if (visible_) 135 return; 136 BubbleWidget* pop = static_cast<BubbleWidget*>(popup_); 137 pop->ShowAndActivate(activate); 138 visible_ = true; 139 } 140 141 void BrowserBubble::Hide() { 142 if (!visible_) 143 return; 144 views::WidgetWin* pop = static_cast<views::WidgetWin*>(popup_); 145 pop->Hide(); 146 visible_ = false; 147 } 148 149 void BrowserBubble::ResizeToView() { 150 BorderWidgetWin* border_widget = 151 static_cast<BubbleWidget*>(popup_)->border_widget(); 152 153 gfx::Rect window_bounds; 154 window_bounds = border_widget->SizeAndGetBounds(GetAbsoluteRelativeTo(), 155 arrow_location_, view_->size()); 156 157 SetAbsoluteBounds(window_bounds); 158 } 159