message_center_widget_delegate.cc revision a36e5920737c6adbddd3e43b760e5de8431db6e0
1// Copyright 2013 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/message_center/message_center_widget_delegate.h"
6
7#include <complex>
8
9#include "chrome/browser/ui/views/message_center/message_center_frame_view.h"
10#include "content/public/browser/user_metrics.h"
11#include "ui/base/accessibility/accessible_view_state.h"
12#include "ui/gfx/screen.h"
13#include "ui/message_center/message_center_style.h"
14#include "ui/message_center/message_center_util.h"
15#include "ui/message_center/views/message_center_view.h"
16#include "ui/native_theme/native_theme.h"
17#include "ui/views/border.h"
18#include "ui/views/layout/box_layout.h"
19#include "ui/views/widget/widget.h"
20
21#if defined(OS_WIN)
22#include "ui/views/win/hwnd_util.h"
23#endif
24
25namespace message_center {
26
27MessageCenterWidgetDelegate::MessageCenterWidgetDelegate(
28    WebNotificationTray* tray,
29    MessageCenterTray* mc_tray,
30    bool initially_settings_visible,
31    const PositionInfo& pos_info)
32    : MessageCenterView(tray->message_center(),
33                        mc_tray,
34                        pos_info.max_height,
35                        initially_settings_visible,
36                        pos_info.message_center_alignment &
37                            ALIGNMENT_TOP),  // Show buttons on top if message
38                                             // center is top aligned
39      pos_info_(pos_info),
40      tray_(tray) {
41  // A WidgetDelegate should be deleted on DeleteDelegate.
42  set_owned_by_client();
43
44  views::BoxLayout* layout =
45      new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0);
46  layout->set_spread_blank_space(true);
47  SetLayoutManager(layout);
48
49  AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE));
50
51  if (get_use_acceleration_when_possible()) {
52    SetPaintToLayer(true);
53    SetFillsBoundsOpaquely(true);
54  }
55
56  InitWidget();
57}
58
59MessageCenterWidgetDelegate::~MessageCenterWidgetDelegate() {
60  views::Widget* widget = GetWidget();
61  if (widget) {
62    widget->RemoveObserver(this);
63  }
64}
65
66views::View* MessageCenterWidgetDelegate::GetContentsView() {
67  return this;
68}
69
70views::NonClientFrameView*
71MessageCenterWidgetDelegate::CreateNonClientFrameView(views::Widget* widget) {
72  MessageCenterFrameView* frame_view = new MessageCenterFrameView();
73  border_insets_ = frame_view->GetInsets();
74  return frame_view;
75}
76
77void MessageCenterWidgetDelegate::DeleteDelegate() {
78  delete this;
79}
80
81views::Widget* MessageCenterWidgetDelegate::GetWidget() {
82  return View::GetWidget();
83}
84
85const views::Widget* MessageCenterWidgetDelegate::GetWidget() const {
86  return View::GetWidget();
87}
88
89void MessageCenterWidgetDelegate::OnWidgetActivationChanged(
90    views::Widget* widget,
91    bool active) {
92  if (!active) {
93    tray_->SendHideMessageCenter();
94  }
95}
96
97void MessageCenterWidgetDelegate::OnWidgetClosing(views::Widget* widget) {
98  tray_->MarkMessageCenterHidden();
99}
100
101void MessageCenterWidgetDelegate::PreferredSizeChanged() {
102  GetWidget()->SetBounds(GetMessageCenterBounds());
103  views::View::PreferredSizeChanged();
104}
105
106gfx::Size MessageCenterWidgetDelegate::GetPreferredSize() {
107  int preferred_width = kNotificationWidth + 2 * kMarginBetweenItems;
108  return gfx::Size(preferred_width, GetHeightForWidth(preferred_width));
109}
110
111gfx::Size MessageCenterWidgetDelegate::GetMaximumSize() {
112  gfx::Size size = GetPreferredSize();
113  return size;
114}
115
116int MessageCenterWidgetDelegate::GetHeightForWidth(int width) {
117  int height = MessageCenterView::GetHeightForWidth(width);
118  return (pos_info_.max_height != 0) ?
119    std::min(height, pos_info_.max_height - border_insets_.height()) : height;
120}
121
122bool MessageCenterWidgetDelegate::AcceleratorPressed(
123    const ui::Accelerator& accelerator) {
124  if (accelerator.key_code() != ui::VKEY_ESCAPE)
125    return false;
126  tray_->SendHideMessageCenter();
127  return true;
128}
129
130void MessageCenterWidgetDelegate::InitWidget() {
131  views::Widget* widget = new views::Widget();
132  views::Widget::InitParams params(views::Widget::InitParams::TYPE_BUBBLE);
133  params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
134  params.delegate = this;
135  params.keep_on_top = true;
136  params.top_level = true;
137  widget->Init(params);
138
139#if defined(OS_WIN)
140  // Remove the Message Center from taskbar and alt-tab rotation.
141  HWND hwnd = views::HWNDForWidget(widget);
142  LONG_PTR ex_styles = ::GetWindowLongPtr(hwnd, GWL_EXSTYLE);
143  ex_styles |= WS_EX_TOOLWINDOW;
144  ::SetWindowLongPtr(hwnd, GWL_EXSTYLE, ex_styles);
145#endif
146
147  widget->AddObserver(this);
148  widget->StackAtTop();
149  widget->SetAlwaysOnTop(true);
150
151  const NotificationList::Notifications& notifications =
152      tray_->message_center()->GetNotifications();
153  SetNotifications(notifications);
154
155  widget->SetBounds(GetMessageCenterBounds());
156  widget->Show();
157  widget->Activate();
158}
159
160gfx::Point MessageCenterWidgetDelegate::GetCorrectedAnchor(
161    gfx::Size calculated_size) {
162  gfx::Point corrected_anchor = pos_info_.inital_anchor_point;
163
164  // Inset the width slightly so that the click point is not exactly on the edge
165  // of the message center but somewhere within the middle 60 %.
166  int insetted_width = (calculated_size.width() * 4) / 5;
167
168  if (pos_info_.taskbar_alignment == ALIGNMENT_TOP ||
169      pos_info_.taskbar_alignment == ALIGNMENT_BOTTOM) {
170    int click_point_x = tray_->mouse_click_point().x();
171
172    if (pos_info_.message_center_alignment & ALIGNMENT_RIGHT) {
173      int opposite_x_corner =
174          pos_info_.inital_anchor_point.x() - insetted_width;
175
176      // If the click point is outside the x axis length of the message center,
177      // push the message center towards the left to align with the click point.
178      if (opposite_x_corner > click_point_x)
179        corrected_anchor.set_x(pos_info_.inital_anchor_point.x() -
180                               (opposite_x_corner - click_point_x));
181    } else {
182      int opposite_x_corner =
183          pos_info_.inital_anchor_point.x() + insetted_width;
184
185      if (opposite_x_corner < click_point_x)
186        corrected_anchor.set_x(pos_info_.inital_anchor_point.x() +
187                               (click_point_x - opposite_x_corner));
188    }
189  } else if (pos_info_.taskbar_alignment == ALIGNMENT_LEFT ||
190             pos_info_.taskbar_alignment == ALIGNMENT_RIGHT) {
191    int click_point_y = tray_->mouse_click_point().y();
192
193    if (pos_info_.message_center_alignment & ALIGNMENT_BOTTOM) {
194      int opposite_y_corner =
195          pos_info_.inital_anchor_point.y() - insetted_width;
196
197      // If the click point is outside the y axis length of the message center,
198      // push the message center upwards to align with the click point.
199      if (opposite_y_corner > click_point_y)
200        corrected_anchor.set_y(pos_info_.inital_anchor_point.y() -
201                               (opposite_y_corner - click_point_y));
202    } else {
203      int opposite_y_corner =
204          pos_info_.inital_anchor_point.y() + insetted_width;
205
206      if (opposite_y_corner < click_point_y)
207        corrected_anchor.set_y(pos_info_.inital_anchor_point.y() +
208                               (click_point_y - opposite_y_corner));
209    }
210  }
211  return corrected_anchor;
212}
213
214gfx::Rect MessageCenterWidgetDelegate::GetMessageCenterBounds() {
215  gfx::Size size = GetPreferredSize();
216
217  // Make space for borders on sides.
218  size.Enlarge(border_insets_.width(), border_insets_.height());
219  gfx::Rect bounds(size);
220
221  gfx::Point corrected_anchor = GetCorrectedAnchor(size);
222
223  if (pos_info_.message_center_alignment & ALIGNMENT_TOP)
224    bounds.set_y(corrected_anchor.y());
225  if (pos_info_.message_center_alignment & ALIGNMENT_BOTTOM)
226    bounds.set_y(corrected_anchor.y() - size.height());
227  if (pos_info_.message_center_alignment & ALIGNMENT_LEFT)
228    bounds.set_x(corrected_anchor.x());
229  if (pos_info_.message_center_alignment & ALIGNMENT_RIGHT)
230    bounds.set_x(corrected_anchor.x() - size.width());
231
232  return bounds;
233}
234
235}  // namespace message_center
236