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 |