OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ash/system/tray/system_tray.h" | 5 #include "ash/system/tray/system_tray.h" |
6 | 6 |
7 #include "ash/shell.h" | 7 #include "ash/shell.h" |
8 #include "ash/shell/panel_window.h" | 8 #include "ash/shell/panel_window.h" |
9 #include "ash/shell_window_ids.h" | 9 #include "ash/shell_window_ids.h" |
10 #include "ash/system/audio/tray_volume.h" | 10 #include "ash/system/audio/tray_volume.h" |
(...skipping 12 matching lines...) Expand all Loading... |
23 #include "ash/system/tray/system_tray_bubble.h" | 23 #include "ash/system/tray/system_tray_bubble.h" |
24 #include "ash/system/tray/system_tray_delegate.h" | 24 #include "ash/system/tray/system_tray_delegate.h" |
25 #include "ash/system/tray/system_tray_item.h" | 25 #include "ash/system/tray/system_tray_item.h" |
26 #include "ash/system/tray/tray_constants.h" | 26 #include "ash/system/tray/tray_constants.h" |
27 #include "ash/system/tray_accessibility.h" | 27 #include "ash/system/tray_accessibility.h" |
28 #include "ash/system/tray_caps_lock.h" | 28 #include "ash/system/tray_caps_lock.h" |
29 #include "ash/system/tray_update.h" | 29 #include "ash/system/tray_update.h" |
30 #include "ash/system/user/login_status.h" | 30 #include "ash/system/user/login_status.h" |
31 #include "ash/system/user/tray_user.h" | 31 #include "ash/system/user/tray_user.h" |
32 #include "ash/wm/shelf_layout_manager.h" | 32 #include "ash/wm/shelf_layout_manager.h" |
33 #include "base/i18n/rtl.h" | |
34 #include "base/logging.h" | 33 #include "base/logging.h" |
35 #include "base/timer.h" | 34 #include "base/timer.h" |
36 #include "base/utf_string_conversions.h" | 35 #include "base/utf_string_conversions.h" |
37 #include "grit/ash_strings.h" | 36 #include "grit/ash_strings.h" |
38 #include "ui/aura/root_window.h" | 37 #include "ui/aura/root_window.h" |
39 #include "ui/base/accessibility/accessible_view_state.h" | 38 #include "ui/base/accessibility/accessible_view_state.h" |
40 #include "ui/base/events.h" | 39 #include "ui/base/events.h" |
41 #include "ui/base/l10n/l10n_util.h" | 40 #include "ui/base/l10n/l10n_util.h" |
42 #include "ui/compositor/layer.h" | 41 #include "ui/compositor/layer.h" |
43 #include "ui/gfx/canvas.h" | 42 #include "ui/gfx/canvas.h" |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
136 | 135 |
137 DISALLOW_COPY_AND_ASSIGN(SystemTrayLayerAnimationObserver); | 136 DISALLOW_COPY_AND_ASSIGN(SystemTrayLayerAnimationObserver); |
138 }; | 137 }; |
139 | 138 |
140 } // namespace internal | 139 } // namespace internal |
141 | 140 |
142 // SystemTray | 141 // SystemTray |
143 | 142 |
144 using internal::SystemTrayBubble; | 143 using internal::SystemTrayBubble; |
145 using internal::SystemTrayLayerAnimationObserver; | 144 using internal::SystemTrayLayerAnimationObserver; |
| 145 using internal::TrayBubbleView; |
146 | 146 |
147 SystemTray::SystemTray() | 147 SystemTray::SystemTray() |
148 : items_(), | 148 : items_(), |
149 accessibility_observer_(NULL), | 149 accessibility_observer_(NULL), |
150 audio_observer_(NULL), | 150 audio_observer_(NULL), |
151 bluetooth_observer_(NULL), | 151 bluetooth_observer_(NULL), |
152 brightness_observer_(NULL), | 152 brightness_observer_(NULL), |
153 caps_lock_observer_(NULL), | 153 caps_lock_observer_(NULL), |
154 clock_observer_(NULL), | 154 clock_observer_(NULL), |
155 drive_observer_(NULL), | 155 drive_observer_(NULL), |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
245 PreferredSizeChanged(); | 245 PreferredSizeChanged(); |
246 tray_item_map_[item] = tray_item; | 246 tray_item_map_[item] = tray_item; |
247 } | 247 } |
248 } | 248 } |
249 | 249 |
250 void SystemTray::RemoveTrayItem(SystemTrayItem* item) { | 250 void SystemTray::RemoveTrayItem(SystemTrayItem* item) { |
251 NOTIMPLEMENTED(); | 251 NOTIMPLEMENTED(); |
252 } | 252 } |
253 | 253 |
254 void SystemTray::ShowDefaultView(BubbleCreationType creation_type) { | 254 void SystemTray::ShowDefaultView(BubbleCreationType creation_type) { |
255 ShowDefaultViewWithOffset(creation_type, -1); | 255 ShowDefaultViewWithOffset(creation_type, |
| 256 TrayBubbleView::InitParams::kArrowDefaultOffset); |
256 } | 257 } |
257 | 258 |
258 void SystemTray::ShowDetailedView(SystemTrayItem* item, | 259 void SystemTray::ShowDetailedView(SystemTrayItem* item, |
259 int close_delay, | 260 int close_delay, |
260 bool activate, | 261 bool activate, |
261 BubbleCreationType creation_type) { | 262 BubbleCreationType creation_type) { |
262 std::vector<SystemTrayItem*> items; | 263 std::vector<SystemTrayItem*> items; |
263 items.push_back(item); | 264 items.push_back(item); |
264 ShowItems(items, true, activate, creation_type, GetTrayXOffset(item)); | 265 ShowItems(items, true, activate, creation_type, GetTrayXOffset(item)); |
265 bubble_->StartAutoCloseTimer(close_delay); | 266 bubble_->StartAutoCloseTimer(close_delay); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 Shell::GetInstance()->shelf()->UpdateAutoHideState(); | 357 Shell::GetInstance()->shelf()->UpdateAutoHideState(); |
357 } | 358 } |
358 } else if (bubble == notification_bubble_) { | 359 } else if (bubble == notification_bubble_) { |
359 notification_bubble_.reset(); | 360 notification_bubble_.reset(); |
360 } else { | 361 } else { |
361 NOTREACHED(); | 362 NOTREACHED(); |
362 } | 363 } |
363 } | 364 } |
364 | 365 |
365 int SystemTray::GetTrayXOffset(SystemTrayItem* item) const { | 366 int SystemTray::GetTrayXOffset(SystemTrayItem* item) const { |
| 367 // Don't attempt to align the arrow if the shelf is on the left or right. |
| 368 if (shelf_alignment() != SHELF_ALIGNMENT_BOTTOM) |
| 369 return TrayBubbleView::InitParams::kArrowDefaultOffset; |
| 370 |
366 std::map<SystemTrayItem*, views::View*>::const_iterator it = | 371 std::map<SystemTrayItem*, views::View*>::const_iterator it = |
367 tray_item_map_.find(item); | 372 tray_item_map_.find(item); |
368 if (it == tray_item_map_.end()) | 373 if (it == tray_item_map_.end()) |
369 return -1; | 374 return TrayBubbleView::InitParams::kArrowDefaultOffset; |
370 | 375 |
371 const views::View* item_view = it->second; | 376 const views::View* item_view = it->second; |
372 gfx::Rect item_bounds = item_view->bounds(); | 377 gfx::Rect rect(item_view->width() / 2, 0, 0, 0); |
373 if (!item_bounds.IsEmpty()) { | 378 gfx::Rect item_bounds = item_view->ConvertRectToWidget(rect); |
374 int x_offset = item_bounds.x() + item_bounds.width() / 2; | 379 if (!item_view->bounds().IsEmpty()) |
375 return base::i18n::IsRTL() ? x_offset : tray_container_->width() - x_offset; | 380 return item_bounds.x(); |
376 } | |
377 | 381 |
378 // The bounds of item could be still empty. It could happen in the case that | 382 // The bounds of item could be still empty if it does not have a visible |
379 // the view appears for the first time in the current session, because the | 383 // tray view. In that case, use the default (minimum) offset. |
380 // bounds is not calculated yet. In that case, we want to guess the offset | 384 return TrayBubbleView::InitParams::kArrowDefaultOffset; |
381 // from the position of its parent. | |
382 int x_offset = 0; | |
383 for (int i = 0; i < tray_container_->child_count(); ++i) { | |
384 const views::View* child = tray_container_->child_at(i); | |
385 if (child == item_view) | |
386 return base::i18n::IsRTL() ? | |
387 x_offset : tray_container_->width() - x_offset; | |
388 | |
389 if (!child->visible()) | |
390 continue; | |
391 x_offset = child->bounds().right(); | |
392 } | |
393 | |
394 return -1; | |
395 } | 385 } |
396 | 386 |
397 void SystemTray::ShowDefaultViewWithOffset(BubbleCreationType creation_type, | 387 void SystemTray::ShowDefaultViewWithOffset(BubbleCreationType creation_type, |
398 int arrow_offset) { | 388 int arrow_offset) { |
399 ShowItems(items_.get(), false, true, creation_type, arrow_offset); | 389 ShowItems(items_.get(), false, true, creation_type, arrow_offset); |
400 } | 390 } |
401 | 391 |
402 void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items, | 392 void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items, |
403 bool detailed, | 393 bool detailed, |
404 bool can_activate, | 394 bool can_activate, |
405 BubbleCreationType creation_type, | 395 BubbleCreationType creation_type, |
406 int arrow_offset) { | 396 int arrow_offset) { |
407 // Destroy any existing bubble and create a new one. | 397 // Destroy any existing bubble and create a new one. |
408 SystemTrayBubble::BubbleType bubble_type = detailed ? | 398 SystemTrayBubble::BubbleType bubble_type = detailed ? |
409 SystemTrayBubble::BUBBLE_TYPE_DETAILED : | 399 SystemTrayBubble::BUBBLE_TYPE_DETAILED : |
410 SystemTrayBubble::BUBBLE_TYPE_DEFAULT; | 400 SystemTrayBubble::BUBBLE_TYPE_DEFAULT; |
411 | 401 |
412 // Destroy the notification bubble here so that it doesn't get rebuilt | 402 // Destroy the notification bubble here so that it doesn't get rebuilt |
413 // while we add items to the main bubble_ (e.g. in HideNotificationView). | 403 // while we add items to the main bubble_ (e.g. in HideNotificationView). |
414 notification_bubble_.reset(); | 404 notification_bubble_.reset(); |
415 | 405 |
416 if (bubble_.get() && creation_type == BUBBLE_USE_EXISTING) { | 406 if (bubble_.get() && creation_type == BUBBLE_USE_EXISTING) { |
417 bubble_->UpdateView(items, bubble_type); | 407 bubble_->UpdateView(items, bubble_type); |
418 } else { | 408 } else { |
419 bubble_.reset(new SystemTrayBubble(this, items, bubble_type)); | 409 bubble_.reset(new SystemTrayBubble(this, items, bubble_type)); |
420 ash::SystemTrayDelegate* delegate = | 410 ash::SystemTrayDelegate* delegate = |
421 ash::Shell::GetInstance()->tray_delegate(); | 411 ash::Shell::GetInstance()->tray_delegate(); |
422 views::View* anchor = tray_container_; | 412 views::View* anchor = tray_container_; |
423 SystemTrayBubble::InitParams init_params( | 413 TrayBubbleView::InitParams init_params(TrayBubbleView::ANCHOR_TYPE_TRAY, |
424 SystemTrayBubble::ANCHOR_TYPE_TRAY, | 414 shelf_alignment()); |
425 shelf_alignment()); | |
426 init_params.anchor = anchor; | |
427 init_params.can_activate = can_activate; | 415 init_params.can_activate = can_activate; |
428 init_params.login_status = delegate->GetUserLoginStatus(); | |
429 if (arrow_offset >= 0) | |
430 init_params.arrow_offset = arrow_offset; | |
431 if (detailed) | 416 if (detailed) |
432 init_params.max_height = default_bubble_height_; | 417 init_params.max_height = default_bubble_height_; |
433 bubble_->InitView(init_params); | 418 init_params.arrow_offset = arrow_offset; |
| 419 bubble_->InitView(anchor, init_params, delegate->GetUserLoginStatus()); |
434 } | 420 } |
435 // Save height of default view for creating detailed views directly. | 421 // Save height of default view for creating detailed views directly. |
436 if (!detailed) | 422 if (!detailed) |
437 default_bubble_height_ = bubble_->bubble_view()->height(); | 423 default_bubble_height_ = bubble_->bubble_view()->height(); |
438 | 424 |
439 if (detailed && items.size() > 0) | 425 if (detailed && items.size() > 0) |
440 detailed_item_ = items[0]; | 426 detailed_item_ = items[0]; |
441 else | 427 else |
442 detailed_item_ = NULL; | 428 detailed_item_ = NULL; |
443 | 429 |
(...skipping 25 matching lines...) Expand all Loading... |
469 items.push_back(*iter); | 455 items.push_back(*iter); |
470 } | 456 } |
471 notification_bubble_.reset(new SystemTrayBubble( | 457 notification_bubble_.reset(new SystemTrayBubble( |
472 this, items, SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION)); | 458 this, items, SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION)); |
473 } else { | 459 } else { |
474 // Show all notifications. | 460 // Show all notifications. |
475 notification_bubble_.reset(new SystemTrayBubble( | 461 notification_bubble_.reset(new SystemTrayBubble( |
476 this, notification_items_, SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION)); | 462 this, notification_items_, SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION)); |
477 } | 463 } |
478 views::View* anchor; | 464 views::View* anchor; |
479 SystemTrayBubble::AnchorType anchor_type; | 465 TrayBubbleView::AnchorType anchor_type; |
480 if (bubble_.get()) { | 466 if (bubble_.get()) { |
481 anchor = bubble_->bubble_view(); | 467 anchor = bubble_->bubble_view(); |
482 anchor_type = SystemTrayBubble::ANCHOR_TYPE_BUBBLE; | 468 anchor_type = TrayBubbleView::ANCHOR_TYPE_BUBBLE; |
483 } else { | 469 } else { |
484 anchor = tray_container_; | 470 anchor = tray_container_; |
485 anchor_type = SystemTrayBubble::ANCHOR_TYPE_TRAY; | 471 anchor_type = TrayBubbleView::ANCHOR_TYPE_TRAY; |
486 } | 472 } |
487 SystemTrayBubble::InitParams init_params(anchor_type, shelf_alignment()); | 473 TrayBubbleView::InitParams init_params(anchor_type, shelf_alignment()); |
488 init_params.anchor = anchor; | 474 init_params.arrow_offset = GetTrayXOffset(notification_items_[0]); |
489 init_params.login_status = | 475 user::LoginStatus login_status = |
490 ash::Shell::GetInstance()->tray_delegate()->GetUserLoginStatus(); | 476 Shell::GetInstance()->tray_delegate()->GetUserLoginStatus(); |
491 int arrow_offset = GetTrayXOffset(notification_items_[0]); | 477 notification_bubble_->InitView(anchor, init_params, login_status); |
492 if (arrow_offset >= 0) | |
493 init_params.arrow_offset = arrow_offset; | |
494 notification_bubble_->InitView(init_params); | |
495 if (hide_notifications_) | 478 if (hide_notifications_) |
496 notification_bubble_->SetVisible(false); | 479 notification_bubble_->SetVisible(false); |
497 } | 480 } |
498 | 481 |
499 void SystemTray::UpdateNotificationAnchor() { | 482 void SystemTray::UpdateNotificationAnchor() { |
500 if (!notification_bubble_.get()) | 483 if (!notification_bubble_.get()) |
501 return; | 484 return; |
502 notification_bubble_->bubble_view()->UpdateAnchor(); | 485 notification_bubble_->bubble_view()->UpdateAnchor(); |
503 // Ensure that the notification buble is above the launcher/status area. | 486 // Ensure that the notification buble is above the launcher/status area. |
504 notification_bubble_->bubble_view()->GetWidget()->StackAtTop(); | 487 notification_bubble_->bubble_view()->GetWidget()->StackAtTop(); |
(...skipping 18 matching lines...) Expand all Loading... |
523 } | 506 } |
524 } | 507 } |
525 | 508 |
526 void SystemTray::SetShelfAlignment(ShelfAlignment alignment) { | 509 void SystemTray::SetShelfAlignment(ShelfAlignment alignment) { |
527 if (alignment == shelf_alignment()) | 510 if (alignment == shelf_alignment()) |
528 return; | 511 return; |
529 internal::TrayBackgroundView::SetShelfAlignment(alignment); | 512 internal::TrayBackgroundView::SetShelfAlignment(alignment); |
530 UpdateAfterShelfAlignmentChange(alignment); | 513 UpdateAfterShelfAlignmentChange(alignment); |
531 SetBorder(); | 514 SetBorder(); |
532 tray_container_->UpdateLayout(alignment); | 515 tray_container_->UpdateLayout(alignment); |
| 516 // Destroy an existing bubble so that it is rebuilt correctly. |
| 517 bubble_.reset(); |
| 518 // Rebuild any notification bubble. |
| 519 if (notification_bubble_.get()) { |
| 520 notification_bubble_.reset(); |
| 521 UpdateNotificationBubble(); |
| 522 } |
533 } | 523 } |
534 | 524 |
535 bool SystemTray::PerformAction(const views::Event& event) { | 525 bool SystemTray::PerformAction(const views::Event& event) { |
536 // If we're already showing the default view, hide it; otherwise, show it | 526 // If we're already showing the default view, hide it; otherwise, show it |
537 // (and hide any popup that's currently shown). | 527 // (and hide any popup that's currently shown). |
538 if (bubble_.get() && | 528 if (bubble_.get() && |
539 bubble_->bubble_type() == SystemTrayBubble::BUBBLE_TYPE_DEFAULT) { | 529 bubble_->bubble_type() == SystemTrayBubble::BUBBLE_TYPE_DEFAULT) { |
540 bubble_->Close(); | 530 bubble_->Close(); |
541 } else { | 531 } else { |
542 int arrow_offset = -1; | 532 int arrow_offset = TrayBubbleView::InitParams::kArrowDefaultOffset; |
543 if (event.IsMouseEvent() || event.type() == ui::ET_GESTURE_TAP) { | 533 if (event.IsMouseEvent() || event.type() == ui::ET_GESTURE_TAP) { |
544 const views::LocatedEvent& located_event = | 534 const views::LocatedEvent& located_event = |
545 static_cast<const views::LocatedEvent&>(event); | 535 static_cast<const views::LocatedEvent&>(event); |
546 if (shelf_alignment() == SHELF_ALIGNMENT_BOTTOM) | 536 if (shelf_alignment() == SHELF_ALIGNMENT_BOTTOM) { |
547 arrow_offset = base::i18n::IsRTL() ? | 537 gfx::Rect bounds(located_event.x(), 0, 0, 0); |
548 located_event.x() : tray_container_->width() - located_event.x(); | 538 bounds = ConvertRectToWidget(bounds); |
| 539 arrow_offset = bounds.x(); |
| 540 } |
549 } | 541 } |
550 ShowDefaultViewWithOffset(BUBBLE_CREATE_NEW, arrow_offset); | 542 ShowDefaultViewWithOffset(BUBBLE_CREATE_NEW, arrow_offset); |
551 } | 543 } |
552 return true; | 544 return true; |
553 } | 545 } |
554 | 546 |
555 void SystemTray::OnMouseEntered(const views::MouseEvent& event) { | 547 void SystemTray::OnMouseEntered(const views::MouseEvent& event) { |
556 TrayBackgroundView::OnMouseEntered(event); | 548 TrayBackgroundView::OnMouseEntered(event); |
557 should_show_launcher_ = true; | 549 should_show_launcher_ = true; |
558 } | 550 } |
(...skipping 19 matching lines...) Expand all Loading... |
578 | 570 |
579 void SystemTray::OnPaintFocusBorder(gfx::Canvas* canvas) { | 571 void SystemTray::OnPaintFocusBorder(gfx::Canvas* canvas) { |
580 // The tray itself expands to the right and bottom edge of the screen to make | 572 // The tray itself expands to the right and bottom edge of the screen to make |
581 // sure clicking on the edges brings up the popup. However, the focus border | 573 // sure clicking on the edges brings up the popup. However, the focus border |
582 // should be only around the container. | 574 // should be only around the container. |
583 if (GetWidget() && GetWidget()->IsActive()) | 575 if (GetWidget() && GetWidget()->IsActive()) |
584 canvas->DrawFocusRect(tray_container_->bounds()); | 576 canvas->DrawFocusRect(tray_container_->bounds()); |
585 } | 577 } |
586 | 578 |
587 } // namespace ash | 579 } // namespace ash |
OLD | NEW |