1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Use of this source code is governed by a BSD-style license that can be
3ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// found in the LICENSE file.
4ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
5ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/views/bubble/bubble.h"
6ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
7ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include <vector>
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
9ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/views/bubble/border_contents.h"
10ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h"
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/base/animation/slide_animation.h"
12ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/base/keycodes/keyboard_codes.h"
13ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "ui/gfx/color_utils.h"
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "views/layout/fill_layout.h"
15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "views/widget/root_view.h"
16ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "views/widget/widget.h"
17ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "views/window/client_view.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "views/window/window.h"
19ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_CHROMEOS)
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/chromeos/wm_ipc.h"
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "third_party/cros/chromeos_wm_ipc_enums.h"
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN)
26ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/ui/views/bubble/border_widget_win.h"
27ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
28ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
29ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenusing std::vector;
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// How long the fade should last for.
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstatic const int kHideFadeDurationMS = 200;
33ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
34ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Background color of the bubble.
35ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN)
36ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst SkColor Bubble::kBackgroundColor =
37ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    color_utils::GetSysSkColor(COLOR_WINDOW);
38ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#else
39ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// TODO(beng): source from theme provider.
40ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenconst SkColor Bubble::kBackgroundColor = SK_ColorWHITE;
41ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
42ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
43ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// BubbleDelegate ---------------------------------------------------------
44ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
45ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstd::wstring BubbleDelegate::accessible_name() {
46ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return L"";
47ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
48ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
49ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Bubble -----------------------------------------------------------------
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
51ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// static
52ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenBubble* Bubble::Show(views::Widget* parent,
53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     const gfx::Rect& position_relative_to,
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     BubbleBorder::ArrowLocation arrow_location,
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     views::View* contents,
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     BubbleDelegate* delegate) {
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Bubble* bubble = new Bubble;
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bubble->InitBubble(parent, position_relative_to, arrow_location,
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     contents, delegate);
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return bubble;
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_CHROMEOS)
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// static
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenBubble* Bubble::ShowFocusless(
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    views::Widget* parent,
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const gfx::Rect& position_relative_to,
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BubbleBorder::ArrowLocation arrow_location,
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    views::View* contents,
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    BubbleDelegate* delegate,
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool show_while_screen_is_locked) {
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Bubble* bubble = new Bubble(views::WidgetGtk::TYPE_POPUP,
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                              show_while_screen_is_locked);
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bubble->InitBubble(parent, position_relative_to, arrow_location,
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                     contents, delegate);
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return bubble;
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid Bubble::Close() {
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (show_status_ != kOpen)
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  show_status_ = kClosing;
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (fade_away_on_close_)
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    FadeOut();
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  else
89ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DoClose(false);
90ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
91ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid Bubble::AnimationEnded(const ui::Animation* animation) {
93ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (static_cast<int>(animation_->GetCurrentValue()) == 0) {
94ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // When fading out we just need to close the bubble at the end
95ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DoClose(false);
96ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
97ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN)
98ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // When fading in we need to remove the layered window style flag, since
99ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // that style prevents some bubble content from working properly.
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SetWindowLong(GWL_EXSTYLE, GetWindowLong(GWL_EXSTYLE) & ~WS_EX_LAYERED);
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid Bubble::AnimationProgressed(const ui::Animation* animation) {
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN)
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Set the opacity for the main contents window.
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  unsigned char opacity = static_cast<unsigned char>(
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      animation_->GetCurrentValue() * 255);
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetLayeredWindowAttributes(GetNativeView(), 0,
111ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      static_cast<byte>(opacity), LWA_ALPHA);
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  contents_->SchedulePaint();
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Also fade in/out the bubble border window.
115ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_->SetOpacity(opacity);
116ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_->border_contents()->SchedulePaint();
117ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#else
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  NOTIMPLEMENTED();
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
121ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
122ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenBubble::Bubble()
123ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    :
124ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_LINUX)
125ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      WidgetGtk(TYPE_WINDOW),
126ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      border_contents_(NULL),
127ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#elif defined(OS_WIN)
128ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      border_(NULL),
129ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
130ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      delegate_(NULL),
131ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      show_status_(kOpen),
132ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      fade_away_on_close_(false),
133ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_CHROMEOS)
134ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      show_while_screen_is_locked_(false),
135ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
136ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      arrow_location_(BubbleBorder::NONE),
137ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      contents_(NULL) {
138ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
139ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
140ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_CHROMEOS)
141ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenBubble::Bubble(views::WidgetGtk::Type type, bool show_while_screen_is_locked)
142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : WidgetGtk(type),
143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      border_contents_(NULL),
144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      delegate_(NULL),
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      show_status_(kOpen),
146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      fade_away_on_close_(false),
147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      show_while_screen_is_locked_(show_while_screen_is_locked),
148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      arrow_location_(BubbleBorder::NONE),
149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      contents_(NULL) {
150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenBubble::~Bubble() {
154ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
155ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
156ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid Bubble::InitBubble(views::Widget* parent,
157ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        const gfx::Rect& position_relative_to,
158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        BubbleBorder::ArrowLocation arrow_location,
159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        views::View* contents,
160ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                        BubbleDelegate* delegate) {
161ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  delegate_ = delegate;
162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  position_relative_to_ = position_relative_to;
163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  arrow_location_ = arrow_location;
164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  contents_ = contents;
165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Create the main window.
167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN)
168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  views::Window* parent_window = parent->GetWindow();
169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (parent_window)
170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    parent_window->DisableInactiveRendering();
171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  set_window_style(WS_POPUP | WS_CLIPCHILDREN);
172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int extended_style = WS_EX_TOOLWINDOW;
173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // During FadeIn we need to turn on the layered window style to deal with
174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // transparency. This flag needs to be reset after fading in is complete.
175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool fade_in = delegate_ && delegate_->FadeInOnShow();
176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (fade_in)
177ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    extended_style |= WS_EX_LAYERED;
178ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  set_window_ex_style(extended_style);
179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
180ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(!border_);
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_ = new BorderWidgetWin();
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
183ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (fade_in) {
184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    border_->SetOpacity(0);
185ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    SetOpacity(0);
186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_->Init(CreateBorderContents(), parent->GetNativeView());
189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_->border_contents()->SetBackgroundColor(kBackgroundColor);
190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We make the BorderWidgetWin the owner of the Bubble HWND, so that the
192ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // latter is displayed on top of the former.
193ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  WidgetWin::Init(border_->GetNativeView(), gfx::Rect());
194ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
195ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetWindowText(GetNativeView(), delegate_->accessible_name().c_str());
196ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#elif defined(OS_LINUX)
197ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  MakeTransparent();
198ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  make_transient_to_parent();
199ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  WidgetGtk::InitWithWidget(parent, gfx::Rect());
200ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_CHROMEOS)
201ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  {
202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    vector<int> params;
203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    params.push_back(show_while_screen_is_locked_ ? 1 : 0);
204ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    chromeos::WmIpc::instance()->SetWindowType(
205ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        GetNativeView(),
206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        chromeos::WM_IPC_WINDOW_CHROME_INFO_BUBBLE,
207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        &params);
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Create a View to hold the contents of the main window.
213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  views::View* contents_view = new views::View;
214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // We add |contents_view| to ourselves before the AddChildView() call below so
215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // that when |contents| gets added, it will already have a widget, and thus
216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // any NativeButtons it creates in ViewHierarchyChanged() will be functional
217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // (e.g. calling SetChecked() on checkboxes is safe).
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetContentsView(contents_view);
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Adding |contents| as a child has to be done before we call
220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // contents->GetPreferredSize() below, since some supplied views don't
221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // actually initialize themselves until they're added to a hierarchy.
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  contents_view->AddChildView(contents);
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Calculate and set the bounds for all windows and views.
225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gfx::Rect window_bounds;
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN)
228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Initialize and position the border window.
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  window_bounds = border_->SizeAndGetBounds(position_relative_to,
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                            arrow_location,
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                            contents->GetPreferredSize());
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Make |contents| take up the entire contents view.
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  contents_view->SetLayoutManager(new views::FillLayout);
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Paint the background color behind the contents.
237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  contents_view->set_background(
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      views::Background::CreateSolidBackground(kBackgroundColor));
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#else
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Create a view to paint the border and background.
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_contents_ = CreateBorderContents();
242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_contents_->Init();
243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_contents_->SetBackgroundColor(kBackgroundColor);
244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gfx::Rect contents_bounds;
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_contents_->SizeAndGetBounds(position_relative_to,
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      arrow_location, false, contents->GetPreferredSize(),
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      &contents_bounds, &window_bounds);
248ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // This new view must be added before |contents| so it will paint under it.
249ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  contents_view->AddChildViewAt(border_contents_, 0);
250ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
251ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // |contents_view| has no layout manager, so we have to explicitly position
252ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // its children.
253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_contents_->SetBoundsRect(
254ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      gfx::Rect(gfx::Point(), window_bounds.size()));
255ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  contents->SetBoundsRect(contents_bounds);
256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
257ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetBounds(window_bounds);
258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
259ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Register the Escape accelerator for closing.
260ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GetFocusManager()->RegisterAccelerator(
261ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      views::Accelerator(ui::VKEY_ESCAPE, false, false, false), this);
262ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
263ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Done creating the bubble.
264ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  NotificationService::current()->Notify(NotificationType::INFO_BUBBLE_CREATED,
265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                         Source<Bubble>(this),
266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                         NotificationService::NoDetails());
267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Show the window.
269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN)
270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_->ShowWindow(SW_SHOW);
271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ShowWindow(SW_SHOW);
272ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (fade_in)
273ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    FadeIn();
274ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#elif defined(OS_LINUX)
275ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  views::WidgetGtk::Show();
276ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
277ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
278ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
279ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenBorderContents* Bubble::CreateBorderContents() {
280ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return new BorderContents();
281ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid Bubble::SizeToContents() {
284ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gfx::Rect window_bounds;
285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
286ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN)
287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Initialize and position the border window.
288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  window_bounds = border_->SizeAndGetBounds(position_relative_to_,
289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                            arrow_location_,
290ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                            contents_->GetPreferredSize());
291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#else
292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  gfx::Rect contents_bounds;
293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_contents_->SizeAndGetBounds(position_relative_to_,
294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      arrow_location_, false, contents_->GetPreferredSize(),
295ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      &contents_bounds, &window_bounds);
296ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // |contents_view| has no layout manager, so we have to explicitly position
297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // its children.
298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_contents_->SetBoundsRect(
299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      gfx::Rect(gfx::Point(), window_bounds.size()));
300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  contents_->SetBoundsRect(contents_bounds);
301ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
302ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetBounds(window_bounds);
303ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
304ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
305ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN)
306ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid Bubble::OnActivate(UINT action, BOOL minimized, HWND window) {
307ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // The popup should close when it is deactivated.
308ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (action == WA_INACTIVE) {
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    Close();
310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else if (action == WA_ACTIVE) {
311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DCHECK(GetRootView()->has_children());
312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    GetRootView()->GetChildViewAt(0)->RequestFocus();
313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#elif defined(OS_LINUX)
316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid Bubble::IsActiveChanged() {
317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!IsActive())
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    Close();
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid Bubble::DoClose(bool closed_by_escape) {
323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (show_status_ == kClosed)
324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GetFocusManager()->UnregisterAccelerator(
327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      views::Accelerator(ui::VKEY_ESCAPE, false, false, false), this);
328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (delegate_)
329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    delegate_->BubbleClosing(this, closed_by_escape);
330ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  show_status_ = kClosed;
331ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN)
332ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  border_->Close();
333ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  WidgetWin::Close();
334ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#elif defined(OS_LINUX)
335ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  WidgetGtk::Close();
336ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
337ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
338ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
339ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid Bubble::FadeIn() {
340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Fade(true);  // |fade_in|.
341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid Bubble::FadeOut() {
344ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#if defined(OS_WIN)
345ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // The contents window cannot have the layered flag on by default, since its
346ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // content doesn't always work inside a layered window, but when animating it
347ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // is ok to set that style on the window for the purpose of fading it out.
348ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetWindowLong(GWL_EXSTYLE, GetWindowLong(GWL_EXSTYLE) | WS_EX_LAYERED);
349ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // This must be the very next call, otherwise we can get flicker on close.
350ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  SetLayeredWindowAttributes(GetNativeView(), 0,
351ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      static_cast<byte>(255), LWA_ALPHA);
352ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#endif
353ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
354ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  Fade(false);  // |fade_in|.
355ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
356ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
357ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid Bubble::Fade(bool fade_in) {
358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  animation_.reset(new ui::SlideAnimation(this));
359ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  animation_->SetSlideDuration(kHideFadeDurationMS);
360ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  animation_->SetTweenType(ui::Tween::LINEAR);
361ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
362ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  animation_->Reset(fade_in ? 0.0 : 1.0);
363ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (fade_in)
364ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    animation_->Show();
365ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  else
366ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    animation_->Hide();
367ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
368ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
369ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool Bubble::AcceleratorPressed(const views::Accelerator& accelerator) {
370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!delegate_ || delegate_->CloseOnEscape()) {
371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    DoClose(true);
372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return true;
373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
374ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return false;
375ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
376