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.
5 #include "chrome/browser/ui/views/message_center/message_center_widget_delegate.h"
9 #include "chrome/browser/ui/views/message_center/message_center_frame_view.h"
10 #include "chrome/browser/ui/views/message_center/web_notification_tray.h"
11 #include "content/public/browser/user_metrics.h"
12 #include "ui/accessibility/ax_view_state.h"
13 #include "ui/gfx/screen.h"
14 #include "ui/message_center/message_center_style.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"
22 #include "ui/views/win/hwnd_util.h"
26 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
29 namespace message_center
{
31 MessageCenterWidgetDelegate::MessageCenterWidgetDelegate(
32 WebNotificationTray
* tray
,
33 MessageCenterTray
* mc_tray
,
34 bool initially_settings_visible
,
35 const PositionInfo
& pos_info
,
36 const base::string16
& title
)
37 : MessageCenterView(tray
->message_center(),
40 initially_settings_visible
,
41 pos_info
.message_center_alignment
&
42 ALIGNMENT_TOP
, // Show buttons on top if message
43 // center is top aligned
47 // A WidgetDelegate should be deleted on DeleteDelegate.
48 set_owned_by_client();
50 views::BoxLayout
* layout
=
51 new views::BoxLayout(views::BoxLayout::kVertical
, 0, 0, 0);
52 layout
->SetDefaultFlex(1);
53 SetLayoutManager(layout
);
55 AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE
, ui::EF_NONE
));
57 SetPaintToLayer(true);
58 SetFillsBoundsOpaquely(true);
63 MessageCenterWidgetDelegate::~MessageCenterWidgetDelegate() {
64 views::Widget
* widget
= GetWidget();
66 widget
->RemoveObserver(this);
70 views::View
* MessageCenterWidgetDelegate::GetContentsView() {
74 views::NonClientFrameView
*
75 MessageCenterWidgetDelegate::CreateNonClientFrameView(views::Widget
* widget
) {
76 MessageCenterFrameView
* frame_view
= new MessageCenterFrameView();
77 border_insets_
= frame_view
->GetInsets();
81 void MessageCenterWidgetDelegate::DeleteDelegate() {
85 views::Widget
* MessageCenterWidgetDelegate::GetWidget() {
86 return View::GetWidget();
89 const views::Widget
* MessageCenterWidgetDelegate::GetWidget() const {
90 return View::GetWidget();
93 void MessageCenterWidgetDelegate::OnWidgetActivationChanged(
94 views::Widget
* widget
,
96 // Some Linux users set 'focus-follows-mouse' where the activation is lost
97 // immediately after the mouse exists from the bubble, which is a really bad
98 // experience. Disable hiding until the bug around the focus is fixed.
99 // TODO(erg, pkotwicz): fix the activation issue and then remove this ifdef.
100 #if !defined(OS_LINUX)
102 tray_
->SendHideMessageCenter();
107 void MessageCenterWidgetDelegate::OnWidgetClosing(views::Widget
* widget
) {
109 tray_
->MarkMessageCenterHidden();
112 void MessageCenterWidgetDelegate::PreferredSizeChanged() {
113 GetWidget()->SetBounds(GetMessageCenterBounds());
114 views::View::PreferredSizeChanged();
117 gfx::Size
MessageCenterWidgetDelegate::GetPreferredSize() const {
118 int preferred_width
= kNotificationWidth
+ 2 * kMarginBetweenItems
;
119 return gfx::Size(preferred_width
, GetHeightForWidth(preferred_width
));
122 gfx::Size
MessageCenterWidgetDelegate::GetMaximumSize() const {
123 gfx::Size size
= GetPreferredSize();
127 int MessageCenterWidgetDelegate::GetHeightForWidth(int width
) const {
128 int height
= MessageCenterView::GetHeightForWidth(width
);
129 return (pos_info_
.max_height
!= 0) ?
130 std::min(height
, pos_info_
.max_height
- border_insets_
.height()) : height
;
133 bool MessageCenterWidgetDelegate::AcceleratorPressed(
134 const ui::Accelerator
& accelerator
) {
135 if (accelerator
.key_code() != ui::VKEY_ESCAPE
)
137 tray_
->SendHideMessageCenter();
141 void MessageCenterWidgetDelegate::InitWidget() {
142 views::Widget
* widget
= new views::Widget();
143 views::Widget::InitParams
params(views::Widget::InitParams::TYPE_BUBBLE
);
144 params
.opacity
= views::Widget::InitParams::TRANSLUCENT_WINDOW
;
145 params
.delegate
= this;
146 params
.keep_on_top
= true;
148 // This class is not used in Ash; there is another container for the message
149 // center that's used there. So, we must be in a Views + Ash environment. We
150 // want the notification center to be available on both desktops. Setting the
151 // |native_widget| variable here ensures that the widget is hosted on the
153 params
.native_widget
= new views::DesktopNativeWidgetAura(widget
);
155 widget
->Init(params
);
157 widget
->AddObserver(this);
158 widget
->StackAtTop();
159 widget
->SetAlwaysOnTop(true);
161 const NotificationList::Notifications
& notifications
=
162 tray_
->message_center()->GetVisibleNotifications();
163 SetNotifications(notifications
);
165 widget
->SetBounds(GetMessageCenterBounds());
170 gfx::Point
MessageCenterWidgetDelegate::GetCorrectedAnchor(
171 gfx::Size calculated_size
) {
172 gfx::Point corrected_anchor
= pos_info_
.inital_anchor_point
;
174 // Inset the width slightly so that the click point is not exactly on the edge
175 // of the message center but somewhere within the middle 60 %.
176 int insetted_width
= (calculated_size
.width() * 4) / 5;
178 if (pos_info_
.taskbar_alignment
== ALIGNMENT_TOP
||
179 pos_info_
.taskbar_alignment
== ALIGNMENT_BOTTOM
) {
180 int click_point_x
= tray_
->mouse_click_point().x();
182 if (pos_info_
.message_center_alignment
& ALIGNMENT_RIGHT
) {
183 int opposite_x_corner
=
184 pos_info_
.inital_anchor_point
.x() - insetted_width
;
186 // If the click point is outside the x axis length of the message center,
187 // push the message center towards the left to align with the click point.
188 if (opposite_x_corner
> click_point_x
)
189 corrected_anchor
.set_x(pos_info_
.inital_anchor_point
.x() -
190 (opposite_x_corner
- click_point_x
));
192 int opposite_x_corner
=
193 pos_info_
.inital_anchor_point
.x() + insetted_width
;
195 if (opposite_x_corner
< click_point_x
)
196 corrected_anchor
.set_x(pos_info_
.inital_anchor_point
.x() +
197 (click_point_x
- opposite_x_corner
));
199 } else if (pos_info_
.taskbar_alignment
== ALIGNMENT_LEFT
||
200 pos_info_
.taskbar_alignment
== ALIGNMENT_RIGHT
) {
201 int click_point_y
= tray_
->mouse_click_point().y();
203 if (pos_info_
.message_center_alignment
& ALIGNMENT_BOTTOM
) {
204 int opposite_y_corner
=
205 pos_info_
.inital_anchor_point
.y() - insetted_width
;
207 // If the click point is outside the y axis length of the message center,
208 // push the message center upwards to align with the click point.
209 if (opposite_y_corner
> click_point_y
)
210 corrected_anchor
.set_y(pos_info_
.inital_anchor_point
.y() -
211 (opposite_y_corner
- click_point_y
));
213 int opposite_y_corner
=
214 pos_info_
.inital_anchor_point
.y() + insetted_width
;
216 if (opposite_y_corner
< click_point_y
)
217 corrected_anchor
.set_y(pos_info_
.inital_anchor_point
.y() +
218 (click_point_y
- opposite_y_corner
));
221 return corrected_anchor
;
224 gfx::Rect
MessageCenterWidgetDelegate::GetMessageCenterBounds() {
225 gfx::Size size
= GetPreferredSize();
227 // Make space for borders on sides.
228 size
.Enlarge(border_insets_
.width(), border_insets_
.height());
229 gfx::Rect
bounds(size
);
231 gfx::Point corrected_anchor
= GetCorrectedAnchor(size
);
233 if (pos_info_
.message_center_alignment
& ALIGNMENT_TOP
)
234 bounds
.set_y(corrected_anchor
.y());
235 if (pos_info_
.message_center_alignment
& ALIGNMENT_BOTTOM
)
236 bounds
.set_y(corrected_anchor
.y() - size
.height());
237 if (pos_info_
.message_center_alignment
& ALIGNMENT_LEFT
)
238 bounds
.set_x(corrected_anchor
.x());
239 if (pos_info_
.message_center_alignment
& ALIGNMENT_RIGHT
)
240 bounds
.set_x(corrected_anchor
.x() - size
.width());
245 } // namespace message_center