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