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
14class 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
108void 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
128void 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
133void 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
141void BrowserBubble::Hide() {
142  if (!visible_)
143    return;
144  views::WidgetWin* pop = static_cast<views::WidgetWin*>(popup_);
145  pop->Hide();
146  visible_ = false;
147}
148
149void 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