| 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 |