Chromium Code Reviews| Index: ash/system/tray/system_tray.cc |
| diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc |
| index 836066745f4e00377d166c572a179a4c0a6f5c10..2a94c3e160a531140b62b5e69f54cf9cc89ec0ee 100644 |
| --- a/ash/system/tray/system_tray.cc |
| +++ b/ash/system/tray/system_tray.cc |
| @@ -210,10 +210,16 @@ class SystemTrayBubbleBackground : public views::Background { |
| class SystemTrayBubbleBorder : public views::BubbleBorder { |
| public: |
| - explicit SystemTrayBubbleBorder(views::View* owner) |
| + enum ArrowType { |
| + ARROW_TYPE_NONE, |
| + ARROW_TYPE_BOTTOM, |
| + }; |
| + |
| + SystemTrayBubbleBorder(views::View* owner, ArrowType arrow_type) |
| : views::BubbleBorder(views::BubbleBorder::BOTTOM_RIGHT, |
| views::BubbleBorder::NO_SHADOW), |
| - owner_(owner) { |
| + owner_(owner), |
| + arrow_type_(arrow_type) { |
| set_alignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); |
| } |
| @@ -256,30 +262,33 @@ class SystemTrayBubbleBorder : public views::BubbleBorder { |
| return; |
| // Draw the arrow. |
| - int left_base_x = base::i18n::IsRTL() ? kArrowWidth : |
| - owner_->width() - kArrowPaddingFromRight - kArrowWidth; |
| - int left_base_y = y; |
| - int tip_x = left_base_x + kArrowWidth / 2; |
| - int tip_y = left_base_y + kArrowHeight; |
| - SkPath path; |
| - path.incReserve(4); |
| - path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y)); |
| - path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y)); |
| - path.lineTo(SkIntToScalar(left_base_x + kArrowWidth), |
| - SkIntToScalar(left_base_y)); |
| - |
| - SkPaint paint; |
| - paint.setStyle(SkPaint::kFill_Style); |
| - paint.setColor(kBackgroundColor); |
| - canvas->DrawPath(path, paint); |
| - |
| - // Now draw the arrow border. |
| - paint.setStyle(SkPaint::kStroke_Style); |
| - paint.setColor(kBorderDarkColor); |
| - canvas->DrawPath(path, paint); |
| + if (arrow_type_ == ARROW_TYPE_BOTTOM) { |
| + int left_base_x = base::i18n::IsRTL() ? kArrowWidth : |
| + owner_->width() - kArrowPaddingFromRight - kArrowWidth; |
| + int left_base_y = y; |
| + int tip_x = left_base_x + kArrowWidth / 2; |
| + int tip_y = left_base_y + kArrowHeight; |
| + SkPath path; |
| + path.incReserve(4); |
| + path.moveTo(SkIntToScalar(left_base_x), SkIntToScalar(left_base_y)); |
| + path.lineTo(SkIntToScalar(tip_x), SkIntToScalar(tip_y)); |
| + path.lineTo(SkIntToScalar(left_base_x + kArrowWidth), |
| + SkIntToScalar(left_base_y)); |
| + |
| + SkPaint paint; |
| + paint.setStyle(SkPaint::kFill_Style); |
| + paint.setColor(kBackgroundColor); |
| + canvas->DrawPath(path, paint); |
| + |
| + // Now draw the arrow border. |
| + paint.setStyle(SkPaint::kStroke_Style); |
| + paint.setColor(kBorderDarkColor); |
| + canvas->DrawPath(path, paint); |
| + } |
| } |
| views::View* owner_; |
| + ArrowType arrow_type_; |
| DISALLOW_COPY_AND_ASSIGN(SystemTrayBubbleBorder); |
| }; |
| @@ -327,6 +336,11 @@ class SystemTrayBubbleView : public views::BubbleDelegateView { |
| GetBubbleFrameView()->SetBubbleBorder(border); |
| } |
| + void UpdateAnchor() { |
| + SizeToContents(); |
| + GetWidget()->GetRootView()->SchedulePaint(); |
| + } |
| + |
| // Called when the host is destroyed. |
| void reset_host() { host_ = NULL; } |
| @@ -351,21 +365,35 @@ class SystemTrayBubbleView : public views::BubbleDelegateView { |
| class SystemTrayBubble : public base::MessagePumpObserver, |
| public views::Widget::Observer { |
| public: |
| + enum BubbleType { |
| + BUBBLE_TYPE_DEFAULT, |
| + BUBBLE_TYPE_DETAILED, |
| + BUBBLE_TYPE_NOTIFICATION |
| + }; |
| + |
| + enum AnchorType { |
| + ANCHOR_TYPE_TRAY, |
| + ANCHOR_TYPE_BUBBLE |
| + }; |
| + |
| SystemTrayBubble(ash::SystemTray* tray, |
| const std::vector<ash::SystemTrayItem*>& items, |
| - bool detailed); |
| + BubbleType bubble_type); |
| virtual ~SystemTrayBubble(); |
| // Creates |bubble_view_| and a child views for each member of |items_|. |
| // Also creates |bubble_widget_| and sets up animations. |
| void InitView(views::View* anchor, |
| + AnchorType anchor_type, |
| bool can_activate, |
| ash::user::LoginStatus login_status); |
| - bool detailed() const { return detailed_; } |
| + gfx::Rect GetAnchorRect() const; |
| + |
| + BubbleType bubble_type() const { return bubble_type_; } |
| + SystemTrayBubbleView* bubble_view() const { return bubble_view_; } |
| void DestroyItemViews(); |
| - views::Widget* GetTrayWidget() const; |
| void StartAutoCloseTimer(int seconds); |
| void StopAutoCloseTimer(); |
| void RestartAutoCloseTimer(); |
| @@ -385,7 +413,9 @@ class SystemTrayBubble : public base::MessagePumpObserver, |
| SystemTrayBubbleView* bubble_view_; |
| views::Widget* bubble_widget_; |
| std::vector<ash::SystemTrayItem*> items_; |
| - bool detailed_; |
| + BubbleType bubble_type_; |
| + AnchorType anchor_type_; |
| + views::View* anchor_; |
| int autoclose_delay_; |
| base::OneShotTimer<SystemTrayBubble> autoclose_; |
| @@ -419,22 +449,17 @@ void SystemTrayBubbleView::Init() { |
| } |
| gfx::Rect SystemTrayBubbleView::GetAnchorRect() { |
| - if (host_) { |
| - views::Widget* widget = host_->GetTrayWidget(); |
| - if (widget->IsVisible()) { |
| - gfx::Rect rect = widget->GetWindowScreenBounds(); |
| - rect.Inset( |
| - base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreen : 0, 0, |
| - base::i18n::IsRTL() ? 0 : kPaddingFromRightEdgeOfScreen, |
| - kPaddingFromBottomOfScreen); |
| - return rect; |
| - } |
| + gfx::Rect rect; |
| + if (host_) |
| + rect = host_->GetAnchorRect(); |
| + if (rect.IsEmpty()) { |
| + rect = gfx::Screen::GetPrimaryMonitor().bounds(); |
| + rect = gfx::Rect(base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreen : |
| + rect.width() - kPaddingFromRightEdgeOfScreen, |
| + rect.height() - kPaddingFromBottomOfScreen, |
| + 0, 0); |
| } |
| - gfx::Rect rect = gfx::Screen::GetPrimaryMonitor().bounds(); |
| - return gfx::Rect(base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreen : |
| - rect.width() - kPaddingFromRightEdgeOfScreen, |
| - rect.height() - kPaddingFromBottomOfScreen, |
| - 0, 0); |
| + return rect; |
| } |
| void SystemTrayBubbleView::ChildPreferredSizeChanged(View* child) { |
| @@ -473,12 +498,14 @@ void SystemTrayBubbleView::OnMouseExited(const views::MouseEvent& event) { |
| SystemTrayBubble::SystemTrayBubble( |
| ash::SystemTray* tray, |
| const std::vector<ash::SystemTrayItem*>& items, |
| - bool detailed) |
| + BubbleType bubble_type) |
| : tray_(tray), |
| bubble_view_(NULL), |
| bubble_widget_(NULL), |
| items_(items), |
| - detailed_(detailed), |
| + bubble_type_(bubble_type), |
| + anchor_type_(ANCHOR_TYPE_TRAY), |
| + anchor_(NULL), |
| autoclose_delay_(0) { |
| } |
| @@ -499,17 +526,29 @@ SystemTrayBubble::~SystemTrayBubble() { |
| } |
| void SystemTrayBubble::InitView(views::View* anchor, |
| + AnchorType anchor_type, |
| bool can_activate, |
| ash::user::LoginStatus login_status) { |
| DCHECK(bubble_view_ == NULL); |
| + anchor_type_ = anchor_type; |
| + anchor_ = anchor; |
| bubble_view_ = new SystemTrayBubbleView(anchor, this, can_activate); |
| for (std::vector<ash::SystemTrayItem*>::iterator it = items_.begin(); |
| it != items_.end(); |
| ++it) { |
| - views::View* view = detailed_ ? |
| - (*it)->CreateDetailedView(login_status) : |
| - (*it)->CreateDefaultView(login_status); |
| + views::View* view = NULL; |
| + switch (bubble_type_) { |
| + case BUBBLE_TYPE_DEFAULT: |
| + view = (*it)->CreateDefaultView(login_status); |
| + break; |
| + case BUBBLE_TYPE_DETAILED: |
| + view = (*it)->CreateDetailedView(login_status); |
| + break; |
| + case BUBBLE_TYPE_NOTIFICATION: |
| + view = (*it)->CreateNotificationView(login_status); |
| + break; |
| + } |
| if (view) |
| bubble_view_->AddChildView(new TrayPopupItemContainer(view)); |
| } |
| @@ -520,7 +559,13 @@ void SystemTrayBubble::InitView(views::View* anchor, |
| // Must occur after call to CreateBubble() |
| bubble_view_->SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE); |
| bubble_widget_->non_client_view()->frame_view()->set_background(NULL); |
| - bubble_view_->SetBubbleBorder(new SystemTrayBubbleBorder(bubble_view_)); |
| + SystemTrayBubbleBorder::ArrowType arrow_type; |
| + if (anchor_type_ == ANCHOR_TYPE_TRAY) |
| + arrow_type = SystemTrayBubbleBorder::ARROW_TYPE_BOTTOM; |
| + else |
| + arrow_type = SystemTrayBubbleBorder::ARROW_TYPE_NONE; |
| + bubble_view_->SetBubbleBorder( |
| + new SystemTrayBubbleBorder(bubble_view_, arrow_type)); |
| bubble_widget_->AddObserver(this); |
| @@ -538,21 +583,46 @@ void SystemTrayBubble::InitView(views::View* anchor, |
| bubble_view_->Show(); |
| } |
| +gfx::Rect SystemTrayBubble::GetAnchorRect() const { |
| + gfx::Rect rect; |
| + views::Widget* widget = anchor_->GetWidget(); |
|
sadrul
2012/05/08 19:40:17
I think instead of keeping anchor_ around, you can
stevenjb
2012/05/08 22:49:20
Good call. Done.
|
| + if (widget->IsVisible()) { |
| + rect = widget->GetWindowScreenBounds(); |
| + if (anchor_type_ == ANCHOR_TYPE_TRAY) { |
| + rect.Inset( |
| + base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreen : 0, |
| + 0, |
| + base::i18n::IsRTL() ? 0 : kPaddingFromRightEdgeOfScreen, |
| + kPaddingFromBottomOfScreen); |
| + } else if (anchor_type_ == ANCHOR_TYPE_BUBBLE) { |
| + rect.Inset( |
| + base::i18n::IsRTL() ? kShadowThickness - 1 : 0, |
| + 0, |
| + base::i18n::IsRTL() ? 0 : kShadowThickness - 1, |
| + 0); |
| + } |
| + } |
| + return rect; |
| +} |
| + |
| void SystemTrayBubble::DestroyItemViews() { |
| for (std::vector<ash::SystemTrayItem*>::iterator it = items_.begin(); |
| it != items_.end(); |
| ++it) { |
| - if (detailed_) |
| - (*it)->DestroyDetailedView(); |
| - else |
| - (*it)->DestroyDefaultView(); |
| + switch (bubble_type_) { |
| + case BUBBLE_TYPE_DEFAULT: |
| + (*it)->DestroyDefaultView(); |
| + break; |
| + case BUBBLE_TYPE_DETAILED: |
| + (*it)->DestroyDetailedView(); |
| + break; |
| + case BUBBLE_TYPE_NOTIFICATION: |
| + (*it)->DestroyNotificationView(); |
| + break; |
| + } |
| } |
| } |
| -views::Widget* SystemTrayBubble::GetTrayWidget() const { |
| - return tray_->GetWidget(); |
| -} |
| - |
| void SystemTrayBubble::StartAutoCloseTimer(int seconds) { |
| autoclose_.Stop(); |
| autoclose_delay_ = seconds; |
| @@ -580,7 +650,8 @@ void SystemTrayBubble::Close() { |
| base::EventStatus SystemTrayBubble::WillProcessEvent( |
| const base::NativeEvent& event) { |
| // Check if the user clicked outside of the bubble and close it if they did. |
| - if (ui::EventTypeFromNative(event) == ui::ET_MOUSE_PRESSED) { |
| + if (bubble_type_ != BUBBLE_TYPE_NOTIFICATION && |
| + ui::EventTypeFromNative(event) == ui::ET_MOUSE_PRESSED) { |
| gfx::Point cursor_in_view = ui::EventLocationFromNative(event); |
| views::View::ConvertPointFromScreen(bubble_view_, &cursor_in_view); |
| if (!bubble_view_->HitTest(cursor_in_view)) { |
| @@ -608,10 +679,36 @@ void SystemTrayBubble::OnWidgetVisibilityChanged(views::Widget* widget, |
| MessageLoopForUI::current()->AddObserver(this); |
| } |
| +// Observe the tray layer animation and update the anchor when it changes. |
| +// TODO(stevenjb): Observe or mirror the actual animation, not just the start |
| +// and end points. |
| +class SystemTrayLayerAnimationObserver : public ui::LayerAnimationObserver { |
| + public: |
| + explicit SystemTrayLayerAnimationObserver(SystemTray* host) : host_(host) {} |
| + |
| + virtual void OnLayerAnimationEnded(ui::LayerAnimationSequence* sequence) { |
| + host_->UpdateNotificationAnchor(); |
| + } |
| + |
| + virtual void OnLayerAnimationAborted(ui::LayerAnimationSequence* sequence) { |
| + host_->UpdateNotificationAnchor(); |
| + } |
| + |
| + virtual void OnLayerAnimationScheduled(ui::LayerAnimationSequence* sequence) { |
| + host_->UpdateNotificationAnchor(); |
| + } |
| + |
| + private: |
| + SystemTray* host_; |
|
sadrul
2012/05/08 19:40:17
DISALLOW_COPY_AND_ASSIGN
stevenjb
2012/05/08 22:49:20
Done.
|
| +}; |
| + |
| } // namespace internal |
| // SystemTray |
| +using internal::SystemTrayBubble; |
| +using internal::SystemTrayLayerAnimationObserver; |
| + |
| SystemTray::SystemTray() |
| : items_(), |
| accessibility_observer_(NULL), |
| @@ -633,17 +730,17 @@ SystemTray::SystemTray() |
| 0, kTrayBackgroundAlpha)), |
| ALLOW_THIS_IN_INITIALIZER_LIST(hover_background_animator_(this, |
| 0, kTrayBackgroundHoverAlpha - kTrayBackgroundAlpha)) { |
| - container_ = new views::View; |
| - container_->SetLayoutManager(new views::BoxLayout( |
| + tray_container_ = new views::View; |
| + tray_container_->SetLayoutManager(new views::BoxLayout( |
| views::BoxLayout::kHorizontal, 0, 0, 0)); |
| - container_->set_background(background_); |
| - container_->set_border( |
| + tray_container_->set_background(background_); |
| + tray_container_->set_border( |
| views::Border::CreateEmptyBorder(1, 1, 1, 1)); |
| set_border(views::Border::CreateEmptyBorder(0, 0, |
| kPaddingFromBottomOfScreen, kPaddingFromRightEdgeOfScreen)); |
| set_notify_enter_exit_on_child(true); |
| SetLayoutManager(new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0)); |
| - AddChildView(container_); |
| + AddChildView(tray_container_); |
| // Initially we want to paint the background, but without the hover effect. |
| SetPaintsBackground(true, internal::BackgroundAnimator::CHANGE_IMMEDIATE); |
| @@ -725,6 +822,10 @@ void SystemTray::CreateWidget() { |
| widget_->SetContentsView(status_area_view); |
| widget_->Show(); |
| widget_->GetNativeView()->SetName("StatusTrayWidget"); |
| + |
| + layer_animation_observer_.reset(new SystemTrayLayerAnimationObserver(this)); |
| + widget_->GetNativeView()->layer()->GetAnimator()->AddObserver( |
| + layer_animation_observer_.get()); |
| } |
| void SystemTray::AddTrayItem(SystemTrayItem* item) { |
| @@ -733,7 +834,7 @@ void SystemTray::AddTrayItem(SystemTrayItem* item) { |
| SystemTrayDelegate* delegate = Shell::GetInstance()->tray_delegate(); |
| views::View* tray_item = item->CreateTrayView(delegate->GetUserLoginStatus()); |
| if (tray_item) { |
| - container_->AddChildViewAt(tray_item, 0); |
| + tray_container_->AddChildViewAt(tray_item, 0); |
| PreferredSizeChanged(); |
| } |
| } |
| @@ -755,8 +856,26 @@ void SystemTray::ShowDetailedView(SystemTrayItem* item, |
| bubble_->StartAutoCloseTimer(close_delay); |
| } |
| +void SystemTray::ShowNotificationView(SystemTrayItem* item) { |
| + if (std::find(notification_items_.begin(), notification_items_.end(), item) |
| + != notification_items_.end()) |
| + return; |
| + notification_items_.push_back(item); |
| + ShowNotifications(); |
| +} |
| + |
| +void SystemTray::HideNotificationView(SystemTrayItem* item) { |
| + std::vector<SystemTrayItem*>::iterator found_iter = |
| + std::find(notification_items_.begin(), notification_items_.end(), item); |
| + if (found_iter == notification_items_.end()) |
| + return; |
| + notification_items_.erase(found_iter); |
| + ShowNotifications(); |
| +} |
| + |
| void SystemTray::SetDetailedViewCloseDelay(int close_delay) { |
| - if (bubble_.get() && bubble_->detailed()) |
| + if (bubble_.get() && |
| + bubble_->bubble_type() == SystemTrayBubble::BUBBLE_TYPE_DETAILED) |
| bubble_->StartAutoCloseTimer(close_delay); |
| } |
| @@ -782,18 +901,23 @@ bool SystemTray::CloseBubbleForTest() const { |
| // Private methods. |
| -void SystemTray::RemoveBubble(internal::SystemTrayBubble* bubble) { |
| - CHECK_EQ(bubble_.get(), bubble); |
| - bubble_.reset(); |
| - |
| - if (should_show_launcher_) { |
| - // No need to show the launcher if the mouse isn't over the status area |
| - // anymore. |
| - aura::RootWindow* root = GetWidget()->GetNativeView()->GetRootWindow(); |
| - should_show_launcher_ = GetWidget()->GetWindowScreenBounds().Contains( |
| - root->last_mouse_location()); |
| - if (!should_show_launcher_) |
| - Shell::GetInstance()->shelf()->UpdateAutoHideState(); |
| +void SystemTray::RemoveBubble(SystemTrayBubble* bubble) { |
| + if (bubble == bubble_.get()) { |
| + bubble_.reset(); |
| + ShowNotifications(); // State changed, re-create notifications. |
| + if (should_show_launcher_) { |
| + // No need to show the launcher if the mouse isn't over the status area |
| + // anymore. |
| + aura::RootWindow* root = GetWidget()->GetNativeView()->GetRootWindow(); |
| + should_show_launcher_ = GetWidget()->GetWindowScreenBounds().Contains( |
| + root->last_mouse_location()); |
| + if (!should_show_launcher_) |
| + Shell::GetInstance()->shelf()->UpdateAutoHideState(); |
| + } |
| + } else if (bubble == notification_bubble_) { |
| + notification_bubble_.reset(); |
| + } else { |
| + NOTREACHED(); |
| } |
| } |
| @@ -807,23 +931,66 @@ void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items, |
| bool detailed, |
| bool can_activate) { |
| // Destroy any existing bubble and create a new one. |
| - bubble_.reset(new internal::SystemTrayBubble(this, items, detailed)); |
| + SystemTrayBubble::BubbleType bubble_type = detailed ? |
| + SystemTrayBubble::BUBBLE_TYPE_DETAILED : |
| + SystemTrayBubble::BUBBLE_TYPE_DEFAULT; |
| + bubble_.reset(new SystemTrayBubble(this, items, bubble_type)); |
| ash::SystemTrayDelegate* delegate = |
| ash::Shell::GetInstance()->tray_delegate(); |
| - bubble_->InitView(container_, can_activate, delegate->GetUserLoginStatus()); |
| + views::View* anchor = tray_container_; |
| + bubble_->InitView(anchor, SystemTrayBubble::ANCHOR_TYPE_TRAY, |
| + can_activate, delegate->GetUserLoginStatus()); |
| // If we have focus the shelf should be visible and we need to continue |
| // showing the shelf when the popup is shown. |
| if (GetWidget()->IsActive()) |
| should_show_launcher_ = true; |
| + ShowNotifications(); // State changed, re-create notifications. |
| +} |
| + |
| +void SystemTray::ShowNotifications() { |
|
sadrul
2012/05/08 19:40:17
Since this can hide the notifications in some case
stevenjb
2012/05/08 22:49:20
Done.
|
| + // Only show the notification buble if we have notifications and we are not |
| + // showing the default bubble. |
| + if (notification_items_.empty() || |
| + (bubble_.get() && |
| + bubble_->bubble_type() == SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) { |
| + notification_bubble_.reset(); |
| + return; |
| + } |
| + notification_bubble_.reset( |
| + new SystemTrayBubble(this, notification_items_, |
| + SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION)); |
| + views::View* anchor; |
| + SystemTrayBubble::AnchorType anchor_type; |
| + if (bubble_.get()) { |
| + anchor = bubble_->bubble_view(); |
| + anchor_type = SystemTrayBubble::ANCHOR_TYPE_BUBBLE; |
| + } else { |
| + anchor = tray_container_; |
| + anchor_type = SystemTrayBubble::ANCHOR_TYPE_TRAY; |
| + } |
| + notification_bubble_->InitView( |
| + anchor, anchor_type, |
| + false /* can_activate */, |
| + ash::Shell::GetInstance()->tray_delegate()->GetUserLoginStatus()); |
| +} |
| + |
| +void SystemTray::UpdateNotificationAnchor() { |
| + if (!notification_bubble_.get()) |
| + return; |
| + notification_bubble_->bubble_view()->UpdateAnchor(); |
| + // Ensure that the notification buble is above the launcher/status area. |
| + notification_bubble_->bubble_view()->GetWidget()->StackAtTop(); |
| } |
| bool SystemTray::PerformAction(const views::Event& event) { |
| // If we're already showing the default view, hide it; otherwise, show it |
| // (and hide any popup that's currently shown). |
| - if (bubble_.get() && !bubble_->detailed()) |
| + if (bubble_.get() && |
| + bubble_->bubble_type() == SystemTrayBubble::BUBBLE_TYPE_DEFAULT) { |
| bubble_->Close(); |
| - else |
| + } else { |
| ShowDefaultView(); |
| + } |
| return true; |
| } |
| @@ -858,7 +1025,7 @@ void SystemTray::OnPaintFocusBorder(gfx::Canvas* canvas) { |
| // sure clicking on the edges brings up the popup. However, the focus border |
| // should be only around the container. |
| if (GetWidget() && GetWidget()->IsActive()) |
| - canvas->DrawFocusRect(container_->bounds()); |
| + canvas->DrawFocusRect(tray_container_->bounds()); |
| } |
| void SystemTray::UpdateBackground(int alpha) { |