1 // Copyright 2014 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 "ash/system/web_notification/ash_popup_alignment_delegate.h" 6 7 #include "ash/display/display_controller.h" 8 #include "ash/shelf/shelf_constants.h" 9 #include "ash/shelf/shelf_layout_manager.h" 10 #include "ash/shelf/shelf_types.h" 11 #include "ash/shelf/shelf_widget.h" 12 #include "ash/shell.h" 13 #include "base/i18n/rtl.h" 14 #include "ui/aura/window.h" 15 #include "ui/gfx/display.h" 16 #include "ui/gfx/geometry/rect.h" 17 #include "ui/gfx/screen.h" 18 #include "ui/message_center/message_center_style.h" 19 #include "ui/message_center/views/message_popup_collection.h" 20 21 namespace ash { 22 23 namespace { 24 25 const int kToastMarginX = 3; 26 27 // If there should be no margin for the first item, this value needs to be 28 // substracted to flush the message to the shelf (the width of the border + 29 // shadow). 30 const int kNoToastMarginBorderAndShadowOffset = 2; 31 32 } 33 34 AshPopupAlignmentDelegate::AshPopupAlignmentDelegate() 35 : display_id_(gfx::Display::kInvalidDisplayID), 36 screen_(NULL), 37 root_window_(NULL), 38 shelf_(NULL), 39 system_tray_height_(0) { 40 } 41 42 AshPopupAlignmentDelegate::~AshPopupAlignmentDelegate() { 43 if (screen_) 44 screen_->RemoveObserver(this); 45 Shell::GetInstance()->RemoveShellObserver(this); 46 if (shelf_) 47 shelf_->RemoveObserver(this); 48 } 49 50 void AshPopupAlignmentDelegate::StartObserving(gfx::Screen* screen, 51 const gfx::Display& display) { 52 screen_ = screen; 53 display_id_ = display.id(); 54 work_area_ = display.work_area(); 55 root_window_ = ash::Shell::GetInstance()->display_controller()-> 56 GetRootWindowForDisplayId(display_id_); 57 UpdateShelf(); 58 screen->AddObserver(this); 59 Shell::GetInstance()->AddShellObserver(this); 60 if (system_tray_height_ > 0) 61 OnAutoHideStateChanged(shelf_->auto_hide_state()); 62 } 63 64 void AshPopupAlignmentDelegate::SetSystemTrayHeight(int height) { 65 system_tray_height_ = height; 66 67 // If the shelf is shown during auto-hide state, the distance from the edge 68 // should be reduced by the height of shelf's shown height. 69 if (shelf_ && shelf_->visibility_state() == SHELF_AUTO_HIDE && 70 shelf_->auto_hide_state() == SHELF_AUTO_HIDE_SHOWN) { 71 system_tray_height_ -= kShelfSize - ShelfLayoutManager::kAutoHideSize; 72 } 73 74 if (system_tray_height_ > 0) 75 system_tray_height_ += message_center::kMarginBetweenItems; 76 else 77 system_tray_height_ = 0; 78 79 if (!shelf_) 80 return; 81 82 DoUpdateIfPossible(); 83 } 84 85 int AshPopupAlignmentDelegate::GetToastOriginX( 86 const gfx::Rect& toast_bounds) const { 87 // In Ash, RTL UI language mirrors the whole ash layout, so the toast 88 // widgets should be at the bottom-left instead of bottom right. 89 if (base::i18n::IsRTL()) 90 return work_area_.x() + kToastMarginX; 91 92 if (IsFromLeft()) 93 return work_area_.x() + kToastMarginX; 94 return work_area_.right() - kToastMarginX - toast_bounds.width(); 95 } 96 97 int AshPopupAlignmentDelegate::GetBaseLine() const { 98 return IsTopDown() 99 ? work_area_.y() + kNoToastMarginBorderAndShadowOffset + 100 system_tray_height_ 101 : work_area_.bottom() - kNoToastMarginBorderAndShadowOffset - 102 system_tray_height_; 103 } 104 105 int AshPopupAlignmentDelegate::GetWorkAreaBottom() const { 106 return work_area_.bottom() - system_tray_height_; 107 } 108 109 bool AshPopupAlignmentDelegate::IsTopDown() const { 110 return GetAlignment() == SHELF_ALIGNMENT_TOP; 111 } 112 113 bool AshPopupAlignmentDelegate::IsFromLeft() const { 114 return GetAlignment() == SHELF_ALIGNMENT_LEFT; 115 } 116 117 void AshPopupAlignmentDelegate::RecomputeAlignment( 118 const gfx::Display& display) { 119 // Nothing needs to be done. 120 } 121 122 ShelfAlignment AshPopupAlignmentDelegate::GetAlignment() const { 123 return shelf_ ? shelf_->GetAlignment() : SHELF_ALIGNMENT_BOTTOM; 124 } 125 126 void AshPopupAlignmentDelegate::UpdateShelf() { 127 if (shelf_) 128 return; 129 130 shelf_ = ShelfLayoutManager::ForShelf(root_window_); 131 if (shelf_) 132 shelf_->AddObserver(this); 133 } 134 135 void AshPopupAlignmentDelegate::OnDisplayWorkAreaInsetsChanged() { 136 UpdateShelf(); 137 138 work_area_ = Shell::GetScreen()->GetDisplayNearestWindow( 139 shelf_->shelf_widget()->GetNativeView()).work_area(); 140 } 141 142 void AshPopupAlignmentDelegate::OnAutoHideStateChanged( 143 ShelfAutoHideState new_state) { 144 work_area_ = Shell::GetScreen()->GetDisplayNearestWindow( 145 shelf_->shelf_widget()->GetNativeView()).work_area(); 146 int width = 0; 147 if ((shelf_->visibility_state() == SHELF_AUTO_HIDE) && 148 new_state == SHELF_AUTO_HIDE_SHOWN) { 149 // Since the work_area is already reduced by kAutoHideSize, the inset width 150 // should be just the difference. 151 width = kShelfSize - ShelfLayoutManager::kAutoHideSize; 152 } 153 work_area_.Inset(shelf_->SelectValueForShelfAlignment( 154 gfx::Insets(0, 0, width, 0), 155 gfx::Insets(0, width, 0, 0), 156 gfx::Insets(0, 0, 0, width), 157 gfx::Insets(width, 0, 0, 0))); 158 159 DoUpdateIfPossible(); 160 } 161 162 void AshPopupAlignmentDelegate::OnDisplayAdded( 163 const gfx::Display& new_display) { 164 } 165 166 void AshPopupAlignmentDelegate::OnDisplayRemoved( 167 const gfx::Display& old_display) { 168 } 169 170 void AshPopupAlignmentDelegate::OnDisplayMetricsChanged( 171 const gfx::Display& display, 172 uint32_t metrics) { 173 if (display.id() == display_id_ && shelf_) 174 OnAutoHideStateChanged(shelf_->auto_hide_state()); 175 } 176 177 } // namespace ash 178