| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/message_center/views/message_popup_collection.h" | 5 #include "ui/message_center/views/message_popup_collection.h" |
| 6 | 6 |
| 7 #include <set> | 7 #include <set> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/i18n/rtl.h" | 10 #include "base/i18n/rtl.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/weak_ptr.h" | 12 #include "base/memory/weak_ptr.h" |
| 13 #include "base/run_loop.h" | 13 #include "base/run_loop.h" |
| 14 #include "base/time/time.h" | 14 #include "base/time/time.h" |
| 15 #include "base/timer/timer.h" | 15 #include "base/timer/timer.h" |
| 16 #include "ui/accessibility/ax_enums.h" | 16 #include "ui/accessibility/ax_enums.h" |
| 17 #include "ui/gfx/animation/animation_delegate.h" | 17 #include "ui/gfx/animation/animation_delegate.h" |
| 18 #include "ui/gfx/animation/slide_animation.h" | 18 #include "ui/gfx/animation/slide_animation.h" |
| 19 #include "ui/gfx/screen.h" | 19 #include "ui/gfx/screen.h" |
| 20 #include "ui/message_center/message_center.h" | 20 #include "ui/message_center/message_center.h" |
| 21 #include "ui/message_center/message_center_style.h" | 21 #include "ui/message_center/message_center_style.h" |
| 22 #include "ui/message_center/message_center_tray.h" | 22 #include "ui/message_center/message_center_tray.h" |
| 23 #include "ui/message_center/notification.h" | 23 #include "ui/message_center/notification.h" |
| 24 #include "ui/message_center/notification_list.h" | 24 #include "ui/message_center/notification_list.h" |
| 25 #include "ui/message_center/views/message_view_context_menu_controller.h" | 25 #include "ui/message_center/views/message_view_context_menu_controller.h" |
| 26 #include "ui/message_center/views/notification_view.h" | 26 #include "ui/message_center/views/notification_view.h" |
| 27 #include "ui/message_center/views/popup_alignment_delegate.h" |
| 27 #include "ui/message_center/views/toast_contents_view.h" | 28 #include "ui/message_center/views/toast_contents_view.h" |
| 28 #include "ui/views/background.h" | 29 #include "ui/views/background.h" |
| 29 #include "ui/views/layout/fill_layout.h" | 30 #include "ui/views/layout/fill_layout.h" |
| 30 #include "ui/views/view.h" | 31 #include "ui/views/view.h" |
| 31 #include "ui/views/views_delegate.h" | 32 #include "ui/views/views_delegate.h" |
| 32 #include "ui/views/widget/widget.h" | 33 #include "ui/views/widget/widget.h" |
| 33 #include "ui/views/widget/widget_delegate.h" | 34 #include "ui/views/widget/widget_delegate.h" |
| 34 | 35 |
| 35 namespace message_center { | 36 namespace message_center { |
| 36 namespace { | 37 namespace { |
| 37 | 38 |
| 38 // Timeout between the last user-initiated close of the toast and the moment | 39 // Timeout between the last user-initiated close of the toast and the moment |
| 39 // when normal layout/update of the toast stack continues. If the last toast was | 40 // when normal layout/update of the toast stack continues. If the last toast was |
| 40 // just closed, the timeout is shorter. | 41 // just closed, the timeout is shorter. |
| 41 const int kMouseExitedDeferTimeoutMs = 200; | 42 const int kMouseExitedDeferTimeoutMs = 200; |
| 42 | 43 |
| 43 // The margin between messages (and between the anchor unless | 44 // The margin between messages (and between the anchor unless |
| 44 // first_item_has_no_margin was specified). | 45 // first_item_has_no_margin was specified). |
| 45 const int kToastMarginY = kMarginBetweenItems; | 46 const int kToastMarginY = kMarginBetweenItems; |
| 46 #if defined(OS_CHROMEOS) | |
| 47 const int kToastMarginX = 3; | |
| 48 #else | |
| 49 const int kToastMarginX = kMarginBetweenItems; | |
| 50 #endif | |
| 51 | |
| 52 | |
| 53 // If there should be no margin for the first item, this value needs to be | |
| 54 // substracted to flush the message to the shelf (the width of the border + | |
| 55 // shadow). | |
| 56 const int kNoToastMarginBorderAndShadowOffset = 2; | |
| 57 | 47 |
| 58 } // namespace. | 48 } // namespace. |
| 59 | 49 |
| 60 MessagePopupCollection::MessagePopupCollection(gfx::NativeView parent, | 50 MessagePopupCollection::MessagePopupCollection( |
| 61 MessageCenter* message_center, | 51 gfx::NativeView parent, |
| 62 MessageCenterTray* tray, | 52 MessageCenter* message_center, |
| 63 bool first_item_has_no_margin) | 53 MessageCenterTray* tray, |
| 54 PopupAlignmentDelegate* alignment_delegate) |
| 64 : parent_(parent), | 55 : parent_(parent), |
| 65 message_center_(message_center), | 56 message_center_(message_center), |
| 66 tray_(tray), | 57 tray_(tray), |
| 67 display_id_(gfx::Display::kInvalidDisplayID), | 58 alignment_delegate_(alignment_delegate), |
| 68 screen_(NULL), | |
| 69 defer_counter_(0), | 59 defer_counter_(0), |
| 70 latest_toast_entered_(NULL), | 60 latest_toast_entered_(NULL), |
| 71 user_is_closing_toasts_by_clicking_(false), | 61 user_is_closing_toasts_by_clicking_(false), |
| 72 first_item_has_no_margin_(first_item_has_no_margin), | |
| 73 context_menu_controller_(new MessageViewContextMenuController(this)), | 62 context_menu_controller_(new MessageViewContextMenuController(this)), |
| 74 weak_factory_(this) { | 63 weak_factory_(this) { |
| 75 DCHECK(message_center_); | 64 DCHECK(message_center_); |
| 76 defer_timer_.reset(new base::OneShotTimer<MessagePopupCollection>); | 65 defer_timer_.reset(new base::OneShotTimer<MessagePopupCollection>); |
| 77 message_center_->AddObserver(this); | 66 message_center_->AddObserver(this); |
| 67 alignment_delegate_->set_collection(this); |
| 78 } | 68 } |
| 79 | 69 |
| 80 MessagePopupCollection::~MessagePopupCollection() { | 70 MessagePopupCollection::~MessagePopupCollection() { |
| 81 weak_factory_.InvalidateWeakPtrs(); | 71 weak_factory_.InvalidateWeakPtrs(); |
| 82 | 72 |
| 83 if (screen_) | |
| 84 screen_->RemoveObserver(this); | |
| 85 message_center_->RemoveObserver(this); | 73 message_center_->RemoveObserver(this); |
| 86 | 74 |
| 87 CloseAllWidgets(); | 75 CloseAllWidgets(); |
| 88 } | 76 } |
| 89 | 77 |
| 90 void MessagePopupCollection::ClickOnNotification( | 78 void MessagePopupCollection::ClickOnNotification( |
| 91 const std::string& notification_id) { | 79 const std::string& notification_id) { |
| 92 message_center_->ClickOnNotification(notification_id); | 80 message_center_->ClickOnNotification(notification_id); |
| 93 } | 81 } |
| 94 | 82 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 125 | 113 |
| 126 void MessagePopupCollection::UpdateWidgets() { | 114 void MessagePopupCollection::UpdateWidgets() { |
| 127 NotificationList::PopupNotifications popups = | 115 NotificationList::PopupNotifications popups = |
| 128 message_center_->GetPopupNotifications(); | 116 message_center_->GetPopupNotifications(); |
| 129 | 117 |
| 130 if (popups.empty()) { | 118 if (popups.empty()) { |
| 131 CloseAllWidgets(); | 119 CloseAllWidgets(); |
| 132 return; | 120 return; |
| 133 } | 121 } |
| 134 | 122 |
| 135 bool top_down = alignment_ & POPUP_ALIGNMENT_TOP; | 123 bool top_down = alignment_delegate_->IsTopDown(); |
| 136 int base = GetBaseLine(toasts_.empty() ? NULL : toasts_.back()); | 124 int base = GetBaseLine(toasts_.empty() ? NULL : toasts_.back()); |
| 137 | 125 |
| 138 // Iterate in the reverse order to keep the oldest toasts on screen. Newer | 126 // Iterate in the reverse order to keep the oldest toasts on screen. Newer |
| 139 // items may be ignored if there are no room to place them. | 127 // items may be ignored if there are no room to place them. |
| 140 for (NotificationList::PopupNotifications::const_reverse_iterator iter = | 128 for (NotificationList::PopupNotifications::const_reverse_iterator iter = |
| 141 popups.rbegin(); iter != popups.rend(); ++iter) { | 129 popups.rbegin(); iter != popups.rend(); ++iter) { |
| 142 if (FindToast((*iter)->id())) | 130 if (FindToast((*iter)->id())) |
| 143 continue; | 131 continue; |
| 144 | 132 |
| 145 NotificationView* view = | 133 NotificationView* view = |
| 146 NotificationView::Create(NULL, | 134 NotificationView::Create(NULL, |
| 147 *(*iter), | 135 *(*iter), |
| 148 true); // Create top-level notification. | 136 true); // Create top-level notification. |
| 149 view->set_context_menu_controller(context_menu_controller_.get()); | 137 view->set_context_menu_controller(context_menu_controller_.get()); |
| 150 int view_height = ToastContentsView::GetToastSizeForView(view).height(); | 138 int view_height = ToastContentsView::GetToastSizeForView(view).height(); |
| 151 int height_available = top_down ? work_area_.bottom() - base : base; | 139 int height_available = |
| 140 top_down ? alignment_delegate_->GetWorkAreaBottom() - base : base; |
| 152 | 141 |
| 153 if (height_available - view_height - kToastMarginY < 0) { | 142 if (height_available - view_height - kToastMarginY < 0) { |
| 154 delete view; | 143 delete view; |
| 155 break; | 144 break; |
| 156 } | 145 } |
| 157 | 146 |
| 158 ToastContentsView* toast = | 147 ToastContentsView* toast = |
| 159 new ToastContentsView((*iter)->id(), weak_factory_.GetWeakPtr()); | 148 new ToastContentsView((*iter)->id(), weak_factory_.GetWeakPtr()); |
| 160 // There will be no contents already since this is a new ToastContentsView. | 149 // There will be no contents already since this is a new ToastContentsView. |
| 161 toast->SetContents(view, /*a11y_feedback_for_updates=*/false); | 150 toast->SetContents(view, /*a11y_feedback_for_updates=*/false); |
| 162 toasts_.push_back(toast); | 151 toasts_.push_back(toast); |
| 163 view->set_controller(toast); | 152 view->set_controller(toast); |
| 164 | 153 |
| 165 gfx::Size preferred_size = toast->GetPreferredSize(); | 154 gfx::Size preferred_size = toast->GetPreferredSize(); |
| 166 gfx::Point origin(GetToastOriginX(gfx::Rect(preferred_size)), base); | 155 gfx::Point origin( |
| 156 alignment_delegate_->GetToastOriginX(gfx::Rect(preferred_size)), base); |
| 167 // The toast slides in from the edge of the screen horizontally. | 157 // The toast slides in from the edge of the screen horizontally. |
| 168 if (alignment_ & POPUP_ALIGNMENT_LEFT) | 158 if (alignment_delegate_->IsFromLeft()) |
| 169 origin.set_x(origin.x() - preferred_size.width()); | 159 origin.set_x(origin.x() - preferred_size.width()); |
| 170 else | 160 else |
| 171 origin.set_x(origin.x() + preferred_size.width()); | 161 origin.set_x(origin.x() + preferred_size.width()); |
| 172 if (top_down) | 162 if (top_down) |
| 173 origin.set_y(origin.y() + view_height); | 163 origin.set_y(origin.y() + view_height); |
| 174 | 164 |
| 175 toast->RevealWithAnimation(origin); | 165 toast->RevealWithAnimation(origin); |
| 176 | 166 |
| 177 // Shift the base line to be a few pixels above the last added toast or (few | 167 // Shift the base line to be a few pixels above the last added toast or (few |
| 178 // pixels below last added toast if top-aligned). | 168 // pixels below last added toast if top-aligned). |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 void MessagePopupCollection::RemoveToast(ToastContentsView* toast, | 236 void MessagePopupCollection::RemoveToast(ToastContentsView* toast, |
| 247 bool mark_as_shown) { | 237 bool mark_as_shown) { |
| 248 ForgetToast(toast); | 238 ForgetToast(toast); |
| 249 | 239 |
| 250 toast->CloseWithAnimation(); | 240 toast->CloseWithAnimation(); |
| 251 | 241 |
| 252 if (mark_as_shown) | 242 if (mark_as_shown) |
| 253 message_center_->MarkSinglePopupAsShown(toast->id(), false); | 243 message_center_->MarkSinglePopupAsShown(toast->id(), false); |
| 254 } | 244 } |
| 255 | 245 |
| 256 int MessagePopupCollection::GetToastOriginX(const gfx::Rect& toast_bounds) | |
| 257 const { | |
| 258 #if defined(OS_CHROMEOS) | |
| 259 // In ChromeOS, RTL UI language mirrors the whole desktop layout, so the toast | |
| 260 // widgets should be at the bottom-left instead of bottom right. | |
| 261 if (base::i18n::IsRTL()) | |
| 262 return work_area_.x() + kToastMarginX; | |
| 263 #endif | |
| 264 if (alignment_ & POPUP_ALIGNMENT_LEFT) | |
| 265 return work_area_.x() + kToastMarginX; | |
| 266 return work_area_.right() - kToastMarginX - toast_bounds.width(); | |
| 267 } | |
| 268 | |
| 269 void MessagePopupCollection::RepositionWidgets() { | 246 void MessagePopupCollection::RepositionWidgets() { |
| 270 bool top_down = alignment_ & POPUP_ALIGNMENT_TOP; | 247 bool top_down = alignment_delegate_->IsTopDown(); |
| 271 int base = GetBaseLine(NULL); // We don't want to position relative to last | 248 int base = GetBaseLine(NULL); // We don't want to position relative to last |
| 272 // toast - we want re-position. | 249 // toast - we want re-position. |
| 273 | 250 |
| 274 for (Toasts::const_iterator iter = toasts_.begin(); iter != toasts_.end();) { | 251 for (Toasts::const_iterator iter = toasts_.begin(); iter != toasts_.end();) { |
| 275 Toasts::const_iterator curr = iter++; | 252 Toasts::const_iterator curr = iter++; |
| 276 gfx::Rect bounds((*curr)->bounds()); | 253 gfx::Rect bounds((*curr)->bounds()); |
| 277 bounds.set_x(GetToastOriginX(bounds)); | 254 bounds.set_x(alignment_delegate_->GetToastOriginX(bounds)); |
| 278 bounds.set_y(alignment_ & POPUP_ALIGNMENT_TOP ? base | 255 bounds.set_y(top_down ? base : base - bounds.height()); |
| 279 : base - bounds.height()); | |
| 280 | 256 |
| 281 // The notification may scrolls the boundary of the screen due to image | 257 // The notification may scrolls the boundary of the screen due to image |
| 282 // load and such notifications should disappear. Do not call | 258 // load and such notifications should disappear. Do not call |
| 283 // CloseWithAnimation, we don't want to show the closing animation, and we | 259 // CloseWithAnimation, we don't want to show the closing animation, and we |
| 284 // don't want to mark such notifications as shown. See crbug.com/233424 | 260 // don't want to mark such notifications as shown. See crbug.com/233424 |
| 285 if ((top_down ? work_area_.bottom() - bounds.bottom() : bounds.y()) >= 0) | 261 if ((top_down ? alignment_delegate_->GetWorkAreaBottom() - bounds.bottom() |
| 262 : bounds.y()) >= 0) |
| 286 (*curr)->SetBoundsWithAnimation(bounds); | 263 (*curr)->SetBoundsWithAnimation(bounds); |
| 287 else | 264 else |
| 288 RemoveToast(*curr, /*mark_as_shown=*/false); | 265 RemoveToast(*curr, /*mark_as_shown=*/false); |
| 289 | 266 |
| 290 // Shift the base line to be a few pixels above the last added toast or (few | 267 // Shift the base line to be a few pixels above the last added toast or (few |
| 291 // pixels below last added toast if top-aligned). | 268 // pixels below last added toast if top-aligned). |
| 292 if (top_down) | 269 if (top_down) |
| 293 base += bounds.height() + kToastMarginY; | 270 base += bounds.height() + kToastMarginY; |
| 294 else | 271 else |
| 295 base -= bounds.height() + kToastMarginY; | 272 base -= bounds.height() + kToastMarginY; |
| 296 } | 273 } |
| 297 } | 274 } |
| 298 | 275 |
| 299 void MessagePopupCollection::RepositionWidgetsWithTarget() { | 276 void MessagePopupCollection::RepositionWidgetsWithTarget() { |
| 300 if (toasts_.empty()) | 277 if (toasts_.empty()) |
| 301 return; | 278 return; |
| 302 | 279 |
| 303 bool top_down = alignment_ & POPUP_ALIGNMENT_TOP; | 280 bool top_down = alignment_delegate_->IsTopDown(); |
| 304 | 281 |
| 305 // Nothing to do if there are no widgets above target if bottom-aligned or no | 282 // Nothing to do if there are no widgets above target if bottom-aligned or no |
| 306 // widgets below target if top-aligned. | 283 // widgets below target if top-aligned. |
| 307 if (top_down ? toasts_.back()->origin().y() < target_top_edge_ | 284 if (top_down ? toasts_.back()->origin().y() < target_top_edge_ |
| 308 : toasts_.back()->origin().y() > target_top_edge_) | 285 : toasts_.back()->origin().y() > target_top_edge_) |
| 309 return; | 286 return; |
| 310 | 287 |
| 311 Toasts::reverse_iterator iter = toasts_.rbegin(); | 288 Toasts::reverse_iterator iter = toasts_.rbegin(); |
| 312 for (; iter != toasts_.rend(); ++iter) { | 289 for (; iter != toasts_.rend(); ++iter) { |
| 313 // We only reposition widgets above target if bottom-aligned or widgets | 290 // We only reposition widgets above target if bottom-aligned or widgets |
| (...skipping 16 matching lines...) Expand all Loading... |
| 330 bounds.set_y(bounds.y() - slide_length); | 307 bounds.set_y(bounds.y() - slide_length); |
| 331 else | 308 else |
| 332 bounds.set_y(bounds.y() + slide_length); | 309 bounds.set_y(bounds.y() + slide_length); |
| 333 (*iter)->SetBoundsWithAnimation(bounds); | 310 (*iter)->SetBoundsWithAnimation(bounds); |
| 334 | 311 |
| 335 if (iter == toasts_.rbegin()) | 312 if (iter == toasts_.rbegin()) |
| 336 break; | 313 break; |
| 337 } | 314 } |
| 338 } | 315 } |
| 339 | 316 |
| 340 void MessagePopupCollection::ComputePopupAlignment(gfx::Rect work_area, | |
| 341 gfx::Rect screen_bounds) { | |
| 342 // If the taskbar is at the top, render notifications top down. Some platforms | |
| 343 // like Gnome can have taskbars at top and bottom. In this case it's more | |
| 344 // likely that the systray is on the top one. | |
| 345 alignment_ = work_area.y() > screen_bounds.y() ? POPUP_ALIGNMENT_TOP | |
| 346 : POPUP_ALIGNMENT_BOTTOM; | |
| 347 | |
| 348 // If the taskbar is on the left show the notifications on the left. Otherwise | |
| 349 // show it on right since it's very likely that the systray is on the right if | |
| 350 // the taskbar is on the top or bottom. | |
| 351 // Since on some platforms like Ubuntu Unity there's also a launcher along | |
| 352 // with a taskbar (panel), we need to check that there is really nothing at | |
| 353 // the top before concluding that the taskbar is at the left. | |
| 354 alignment_ = static_cast<PopupAlignment>( | |
| 355 alignment_ | | |
| 356 ((work_area.x() > screen_bounds.x() && work_area.y() == screen_bounds.y()) | |
| 357 ? POPUP_ALIGNMENT_LEFT | |
| 358 : POPUP_ALIGNMENT_RIGHT)); | |
| 359 } | |
| 360 | |
| 361 int MessagePopupCollection::GetBaseLine(ToastContentsView* last_toast) const { | 317 int MessagePopupCollection::GetBaseLine(ToastContentsView* last_toast) const { |
| 362 bool top_down = alignment_ & POPUP_ALIGNMENT_TOP; | 318 if (!last_toast) { |
| 363 int base; | 319 return alignment_delegate_->GetBaseLine(); |
| 364 | 320 } else if (alignment_delegate_->IsTopDown()) { |
| 365 if (top_down) { | 321 return toasts_.back()->bounds().bottom() + kToastMarginY; |
| 366 if (!last_toast) { | |
| 367 base = work_area_.y(); | |
| 368 if (!first_item_has_no_margin_) | |
| 369 base += kToastMarginY; | |
| 370 else | |
| 371 base -= kNoToastMarginBorderAndShadowOffset; | |
| 372 } else { | |
| 373 base = toasts_.back()->bounds().bottom() + kToastMarginY; | |
| 374 } | |
| 375 } else { | 322 } else { |
| 376 if (!last_toast) { | 323 return toasts_.back()->origin().y() - kToastMarginY; |
| 377 base = work_area_.bottom(); | |
| 378 if (!first_item_has_no_margin_) | |
| 379 base -= kToastMarginY; | |
| 380 else | |
| 381 base += kNoToastMarginBorderAndShadowOffset; | |
| 382 } else { | |
| 383 base = toasts_.back()->origin().y() - kToastMarginY; | |
| 384 } | |
| 385 } | 324 } |
| 386 return base; | |
| 387 } | 325 } |
| 388 | 326 |
| 389 void MessagePopupCollection::OnNotificationAdded( | 327 void MessagePopupCollection::OnNotificationAdded( |
| 390 const std::string& notification_id) { | 328 const std::string& notification_id) { |
| 391 DoUpdateIfPossible(); | 329 DoUpdateIfPossible(); |
| 392 } | 330 } |
| 393 | 331 |
| 394 void MessagePopupCollection::OnNotificationRemoved( | 332 void MessagePopupCollection::OnNotificationRemoved( |
| 395 const std::string& notification_id, | 333 const std::string& notification_id, |
| 396 bool by_user) { | 334 bool by_user) { |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 501 DoUpdateIfPossible(); | 439 DoUpdateIfPossible(); |
| 502 } | 440 } |
| 503 | 441 |
| 504 // This is the main sequencer of tasks. It does a step, then waits for | 442 // This is the main sequencer of tasks. It does a step, then waits for |
| 505 // all started transitions to play out before doing the next step. | 443 // all started transitions to play out before doing the next step. |
| 506 // First, remove all expired toasts. | 444 // First, remove all expired toasts. |
| 507 // Then, reposition widgets (the reposition on close happens before all | 445 // Then, reposition widgets (the reposition on close happens before all |
| 508 // deferred tasks are even able to run) | 446 // deferred tasks are even able to run) |
| 509 // Then, see if there is vacant space for new toasts. | 447 // Then, see if there is vacant space for new toasts. |
| 510 void MessagePopupCollection::DoUpdateIfPossible() { | 448 void MessagePopupCollection::DoUpdateIfPossible() { |
| 511 if (!screen_) { | |
| 512 gfx::Display display; | |
| 513 if (!parent_) { | |
| 514 // On Win+Aura, we don't have a parent since the popups currently show up | |
| 515 // on the Windows desktop, not in the Aura/Ash desktop. This code will | |
| 516 // display the popups on the primary display. | |
| 517 screen_ = gfx::Screen::GetNativeScreen(); | |
| 518 display = screen_->GetPrimaryDisplay(); | |
| 519 } else { | |
| 520 screen_ = gfx::Screen::GetScreenFor(parent_); | |
| 521 display = screen_->GetDisplayNearestWindow(parent_); | |
| 522 } | |
| 523 screen_->AddObserver(this); | |
| 524 | |
| 525 display_id_ = display.id(); | |
| 526 // |work_area_| can be set already and it should not be overwritten here. | |
| 527 if (work_area_.IsEmpty()) { | |
| 528 work_area_ = display.work_area(); | |
| 529 ComputePopupAlignment(work_area_, display.bounds()); | |
| 530 } | |
| 531 } | |
| 532 | |
| 533 if (defer_counter_ > 0) | 449 if (defer_counter_ > 0) |
| 534 return; | 450 return; |
| 535 | 451 |
| 536 RepositionWidgets(); | 452 RepositionWidgets(); |
| 537 | 453 |
| 538 if (defer_counter_ > 0) | 454 if (defer_counter_ > 0) |
| 539 return; | 455 return; |
| 540 | 456 |
| 541 // Reposition could create extra space which allows additional widgets. | 457 // Reposition could create extra space which allows additional widgets. |
| 542 UpdateWidgets(); | 458 UpdateWidgets(); |
| 543 | 459 |
| 544 if (defer_counter_ > 0) | 460 if (defer_counter_ > 0) |
| 545 return; | 461 return; |
| 546 | 462 |
| 547 // Test support. Quit the test run loop when no more updates are deferred, | 463 // Test support. Quit the test run loop when no more updates are deferred, |
| 548 // meaining th echeck for updates did not cause anything to change so no new | 464 // meaining th echeck for updates did not cause anything to change so no new |
| 549 // transition animations were started. | 465 // transition animations were started. |
| 550 if (run_loop_for_test_.get()) | 466 if (run_loop_for_test_.get()) |
| 551 run_loop_for_test_->Quit(); | 467 run_loop_for_test_->Quit(); |
| 552 } | 468 } |
| 553 | 469 |
| 554 void MessagePopupCollection::SetDisplayInfo(const gfx::Rect& work_area, | |
| 555 const gfx::Rect& screen_bounds) { | |
| 556 if (work_area_ == work_area) | |
| 557 return; | |
| 558 | |
| 559 work_area_ = work_area; | |
| 560 ComputePopupAlignment(work_area, screen_bounds); | |
| 561 RepositionWidgets(); | |
| 562 } | |
| 563 | |
| 564 void MessagePopupCollection::OnDisplayAdded(const gfx::Display& new_display) { | |
| 565 } | |
| 566 | |
| 567 void MessagePopupCollection::OnDisplayRemoved(const gfx::Display& old_display) { | |
| 568 if (display_id_ == old_display.id() && !parent_) { | |
| 569 gfx::Display display = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay(); | |
| 570 display_id_ = display.id(); | |
| 571 SetDisplayInfo(display.work_area(), display.bounds()); | |
| 572 } | |
| 573 } | |
| 574 | |
| 575 void MessagePopupCollection::OnDisplayMetricsChanged( | 470 void MessagePopupCollection::OnDisplayMetricsChanged( |
| 576 const gfx::Display& display, uint32_t metrics) { | 471 const gfx::Display& display) { |
| 577 if (display.id() != display_id_) | 472 alignment_delegate_->RecomputeAlignment(display); |
| 578 return; | |
| 579 | |
| 580 SetDisplayInfo(display.work_area(), display.bounds()); | |
| 581 } | 473 } |
| 582 | 474 |
| 583 views::Widget* MessagePopupCollection::GetWidgetForTest(const std::string& id) | 475 views::Widget* MessagePopupCollection::GetWidgetForTest(const std::string& id) |
| 584 const { | 476 const { |
| 585 for (Toasts::const_iterator iter = toasts_.begin(); iter != toasts_.end(); | 477 for (Toasts::const_iterator iter = toasts_.begin(); iter != toasts_.end(); |
| 586 ++iter) { | 478 ++iter) { |
| 587 if ((*iter)->id() == id) | 479 if ((*iter)->id() == id) |
| 588 return (*iter)->GetWidget(); | 480 return (*iter)->GetWidget(); |
| 589 } | 481 } |
| 590 return NULL; | 482 return NULL; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 608 views::Widget* widget = (*iter)->GetWidget(); | 500 views::Widget* widget = (*iter)->GetWidget(); |
| 609 if (widget) | 501 if (widget) |
| 610 return widget->GetWindowBoundsInScreen(); | 502 return widget->GetWindowBoundsInScreen(); |
| 611 break; | 503 break; |
| 612 } | 504 } |
| 613 } | 505 } |
| 614 return gfx::Rect(); | 506 return gfx::Rect(); |
| 615 } | 507 } |
| 616 | 508 |
| 617 } // namespace message_center | 509 } // namespace message_center |
| OLD | NEW |