message_center_widget_delegate.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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) ? std::min(height, pos_info_.max_height) 119 : 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