OLD | NEW |
| (Empty) |
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 "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" | |
20 | |
21 #if defined(OS_WIN) | |
22 #include "ui/views/win/hwnd_util.h" | |
23 #endif | |
24 | |
25 #if defined(USE_ASH) | |
26 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" | |
27 #endif | |
28 | |
29 namespace message_center { | |
30 | |
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(), | |
38 mc_tray, | |
39 pos_info.max_height, | |
40 initially_settings_visible, | |
41 pos_info.message_center_alignment & | |
42 ALIGNMENT_TOP, // Show buttons on top if message | |
43 // center is top aligned | |
44 title), | |
45 pos_info_(pos_info), | |
46 tray_(tray) { | |
47 // A WidgetDelegate should be deleted on DeleteDelegate. | |
48 set_owned_by_client(); | |
49 | |
50 views::BoxLayout* layout = | |
51 new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0); | |
52 layout->SetDefaultFlex(1); | |
53 SetLayoutManager(layout); | |
54 | |
55 AddAccelerator(ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE)); | |
56 | |
57 SetPaintToLayer(true); | |
58 SetFillsBoundsOpaquely(true); | |
59 | |
60 InitWidget(); | |
61 } | |
62 | |
63 MessageCenterWidgetDelegate::~MessageCenterWidgetDelegate() { | |
64 views::Widget* widget = GetWidget(); | |
65 if (widget) { | |
66 widget->RemoveObserver(this); | |
67 } | |
68 } | |
69 | |
70 views::View* MessageCenterWidgetDelegate::GetContentsView() { | |
71 return this; | |
72 } | |
73 | |
74 views::NonClientFrameView* | |
75 MessageCenterWidgetDelegate::CreateNonClientFrameView(views::Widget* widget) { | |
76 MessageCenterFrameView* frame_view = new MessageCenterFrameView(); | |
77 border_insets_ = frame_view->GetInsets(); | |
78 return frame_view; | |
79 } | |
80 | |
81 void MessageCenterWidgetDelegate::DeleteDelegate() { | |
82 delete this; | |
83 } | |
84 | |
85 views::Widget* MessageCenterWidgetDelegate::GetWidget() { | |
86 return View::GetWidget(); | |
87 } | |
88 | |
89 const views::Widget* MessageCenterWidgetDelegate::GetWidget() const { | |
90 return View::GetWidget(); | |
91 } | |
92 | |
93 void MessageCenterWidgetDelegate::OnWidgetActivationChanged( | |
94 views::Widget* widget, | |
95 bool active) { | |
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) | |
101 if (!active) { | |
102 tray_->SendHideMessageCenter(); | |
103 } | |
104 #endif | |
105 } | |
106 | |
107 void MessageCenterWidgetDelegate::OnWidgetClosing(views::Widget* widget) { | |
108 SetIsClosing(true); | |
109 tray_->MarkMessageCenterHidden(); | |
110 } | |
111 | |
112 void MessageCenterWidgetDelegate::PreferredSizeChanged() { | |
113 GetWidget()->SetBounds(GetMessageCenterBounds()); | |
114 views::View::PreferredSizeChanged(); | |
115 } | |
116 | |
117 gfx::Size MessageCenterWidgetDelegate::GetPreferredSize() const { | |
118 int preferred_width = kNotificationWidth + 2 * kMarginBetweenItems; | |
119 return gfx::Size(preferred_width, GetHeightForWidth(preferred_width)); | |
120 } | |
121 | |
122 gfx::Size MessageCenterWidgetDelegate::GetMaximumSize() const { | |
123 gfx::Size size = GetPreferredSize(); | |
124 return size; | |
125 } | |
126 | |
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; | |
131 } | |
132 | |
133 bool MessageCenterWidgetDelegate::AcceleratorPressed( | |
134 const ui::Accelerator& accelerator) { | |
135 if (accelerator.key_code() != ui::VKEY_ESCAPE) | |
136 return false; | |
137 tray_->SendHideMessageCenter(); | |
138 return true; | |
139 } | |
140 | |
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; | |
147 #if defined(USE_ASH) | |
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 | |
152 // native desktop. | |
153 params.native_widget = new views::DesktopNativeWidgetAura(widget); | |
154 #endif | |
155 widget->Init(params); | |
156 | |
157 widget->AddObserver(this); | |
158 widget->StackAtTop(); | |
159 widget->SetAlwaysOnTop(true); | |
160 | |
161 const NotificationList::Notifications& notifications = | |
162 tray_->message_center()->GetVisibleNotifications(); | |
163 SetNotifications(notifications); | |
164 | |
165 widget->SetBounds(GetMessageCenterBounds()); | |
166 widget->Show(); | |
167 widget->Activate(); | |
168 } | |
169 | |
170 gfx::Point MessageCenterWidgetDelegate::GetCorrectedAnchor( | |
171 gfx::Size calculated_size) { | |
172 gfx::Point corrected_anchor = pos_info_.inital_anchor_point; | |
173 | |
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; | |
177 | |
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(); | |
181 | |
182 if (pos_info_.message_center_alignment & ALIGNMENT_RIGHT) { | |
183 int opposite_x_corner = | |
184 pos_info_.inital_anchor_point.x() - insetted_width; | |
185 | |
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)); | |
191 } else { | |
192 int opposite_x_corner = | |
193 pos_info_.inital_anchor_point.x() + insetted_width; | |
194 | |
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)); | |
198 } | |
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(); | |
202 | |
203 if (pos_info_.message_center_alignment & ALIGNMENT_BOTTOM) { | |
204 int opposite_y_corner = | |
205 pos_info_.inital_anchor_point.y() - insetted_width; | |
206 | |
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)); | |
212 } else { | |
213 int opposite_y_corner = | |
214 pos_info_.inital_anchor_point.y() + insetted_width; | |
215 | |
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)); | |
219 } | |
220 } | |
221 return corrected_anchor; | |
222 } | |
223 | |
224 gfx::Rect MessageCenterWidgetDelegate::GetMessageCenterBounds() { | |
225 gfx::Size size = GetPreferredSize(); | |
226 | |
227 // Make space for borders on sides. | |
228 size.Enlarge(border_insets_.width(), border_insets_.height()); | |
229 gfx::Rect bounds(size); | |
230 | |
231 gfx::Point corrected_anchor = GetCorrectedAnchor(size); | |
232 | |
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()); | |
241 | |
242 return bounds; | |
243 } | |
244 | |
245 } // namespace message_center | |
OLD | NEW |