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