0

Moves TrayBubbleView out of ash namespace

Creates TrayEventFilter and TrayBubbleWrapper.

BUG=150872
For ash.gyp:
TBR=ben@chromium.org

Review URL: https://codereview.chromium.org/11028134

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@161888 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
stevenjb@chromium.org
2012-10-15 17:54:38 +00:00
parent 24a65cc071
commit c3e07aebb4
21 changed files with 555 additions and 372 deletions

@ -204,12 +204,16 @@
'system/tray/tray_background_view.h',
'system/tray/tray_bubble_view.cc',
'system/tray/tray_bubble_view.h',
'system/tray/tray_bubble_wrapper.cc',
'system/tray/tray_bubble_wrapper.h',
'system/tray/tray_constants.cc',
'system/tray/tray_constants.h',
'system/tray/tray_details_view.cc',
'system/tray/tray_details_view.h',
'system/tray/tray_empty.cc',
'system/tray/tray_empty.h',
'system/tray/tray_event_filter.cc',
'system/tray/tray_event_filter.h',
'system/tray/tray_image_item.cc',
'system/tray/tray_image_item.h',
'system/tray/tray_item_more.cc',

@ -54,7 +54,6 @@ namespace ash {
// SystemTray
using internal::SystemTrayBubble;
using internal::TrayBubbleView;
SystemTray::SystemTray(internal::StatusAreaWidget* status_area_widget)
: internal::TrayBackgroundView(status_area_widget),
@ -270,18 +269,6 @@ void SystemTray::DestroyNotificationBubble() {
status_area_widget()->SetHideWebNotifications(false);
}
void SystemTray::RemoveBubble(SystemTrayBubble* bubble) {
if (bubble == bubble_.get()) {
DestroyBubble();
UpdateNotificationBubble(); // State changed, re-create notifications.
Shell::GetInstance()->shelf()->UpdateAutoHideState();
} else if (bubble == notification_bubble_) {
DestroyNotificationBubble();
} else {
NOTREACHED();
}
}
int SystemTray::GetTrayXOffset(SystemTrayItem* item) const {
// Don't attempt to align the arrow if the shelf is on the left or right.
if (shelf_alignment() != SHELF_ALIGNMENT_BOTTOM)
@ -331,7 +318,8 @@ void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items,
ash::Shell::GetInstance()->tray_delegate();
views::View* anchor = tray_container();
TrayBubbleView::InitParams init_params(TrayBubbleView::ANCHOR_TYPE_TRAY,
shelf_alignment());
GetAnchorAlignment(),
kTrayPopupWidth);
init_params.can_activate = can_activate;
if (detailed) {
// This is the case where a volume control or brightness control bubble
@ -344,7 +332,7 @@ void SystemTray::ShowItems(const std::vector<SystemTrayItem*>& items,
init_params.arrow_color = kHeaderBackgroundColorDark;
}
init_params.arrow_offset = arrow_offset;
bubble_->InitView(anchor, init_params, delegate->GetUserLoginStatus());
bubble_->InitView(anchor, delegate->GetUserLoginStatus(), &init_params);
}
// Save height of default view for creating detailed views directly.
if (!detailed)
@ -399,13 +387,15 @@ void SystemTray::UpdateNotificationBubble() {
anchor = tray_container();
anchor_type = TrayBubbleView::ANCHOR_TYPE_TRAY;
}
TrayBubbleView::InitParams init_params(anchor_type, shelf_alignment());
TrayBubbleView::InitParams init_params(anchor_type,
GetAnchorAlignment(),
kTrayPopupWidth);
init_params.top_color = kBackgroundColor;
init_params.arrow_color = kBackgroundColor;
init_params.arrow_offset = GetTrayXOffset(notification_items_[0]);
user::LoginStatus login_status =
Shell::GetInstance()->tray_delegate()->GetUserLoginStatus();
notification_bubble_->InitView(anchor, init_params, login_status);
notification_bubble_->InitView(anchor, login_status, &init_params);
if (notification_bubble_->bubble_view()->child_count() == 0) {
// It is possible that none of the items generated actual notifications.
DestroyNotificationBubble();
@ -450,6 +440,26 @@ string16 SystemTray::GetAccessibleName() {
return l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_ACCESSIBLE_NAME);
}
void SystemTray::HideBubbleWithView(const TrayBubbleView* bubble_view) {
if (bubble_.get() && bubble_view == bubble_->bubble_view()) {
DestroyBubble();
UpdateNotificationBubble(); // State changed, re-create notifications.
Shell::GetInstance()->shelf()->UpdateAutoHideState();
} else if (notification_bubble_.get() &&
bubble_view == notification_bubble_->bubble_view()) {
DestroyNotificationBubble();
}
}
bool SystemTray::ClickedOutsideBubble() {
if (!bubble_.get() ||
bubble_->bubble_type() == SystemTrayBubble::BUBBLE_TYPE_NOTIFICATION) {
return false;
}
HideBubbleWithView(bubble_->bubble_view());
return true;
}
bool SystemTray::PerformAction(const ui::Event& event) {
// If we're already showing the default view, hide it; otherwise, show it
// (and hide any popup that's currently shown).

@ -159,6 +159,8 @@ class ASH_EXPORT SystemTray : public internal::TrayBackgroundView {
virtual void SetShelfAlignment(ShelfAlignment alignment) OVERRIDE;
virtual void AnchorUpdated() OVERRIDE;
virtual string16 GetAccessibleName() OVERRIDE;
virtual void HideBubbleWithView(const TrayBubbleView* bubble_view) OVERRIDE;
virtual bool ClickedOutsideBubble() OVERRIDE;
private:
friend class internal::SystemTrayBubble;
@ -170,11 +172,6 @@ class ASH_EXPORT SystemTray : public internal::TrayBackgroundView {
// Resets |notification_bubble_| and clears any related state.
void DestroyNotificationBubble();
// Called when the widget associated with |bubble| closes. |bubble| should
// always == |bubble_|. This triggers destroying |bubble_| and hiding the
// launcher if necessary.
void RemoveBubble(internal::SystemTrayBubble* bubble);
const ScopedVector<SystemTrayItem>& items() const { return items_; }
// Calculates the x-offset for the item in the tray. Returns -1 if its tray

@ -8,6 +8,7 @@
#include "ash/system/tray/system_tray.h"
#include "ash/system/tray/system_tray_delegate.h"
#include "ash/system/tray/system_tray_item.h"
#include "ash/system/tray/tray_bubble_wrapper.h"
#include "ash/system/tray/tray_constants.h"
#include "base/message_loop.h"
#include "ui/aura/window.h"
@ -126,7 +127,6 @@ SystemTrayBubble::SystemTrayBubble(
BubbleType bubble_type)
: tray_(tray),
bubble_view_(NULL),
bubble_widget_(NULL),
items_(items),
bubble_type_(bubble_type),
autoclose_delay_(0) {
@ -136,12 +136,7 @@ SystemTrayBubble::~SystemTrayBubble() {
DestroyItemViews();
// Reset the host pointer in bubble_view_ in case its destruction is deferred.
if (bubble_view_)
bubble_view_->reset_host();
if (bubble_widget_) {
bubble_widget_->RemoveObserver(this);
// This triggers the destruction of bubble_view_.
bubble_widget_->Close();
}
bubble_view_->reset_delegate();
}
void SystemTrayBubble::UpdateView(
@ -209,7 +204,7 @@ void SystemTrayBubble::UpdateView(
return;
}
bubble_widget_->GetContentsView()->Layout();
bubble_view_->GetWidget()->GetContentsView()->Layout();
// Make sure that the bubble is large enough for the default view.
if (bubble_type_ == BUBBLE_TYPE_DEFAULT) {
bubble_view_->SetMaxHeight(0); // Clear max height limit.
@ -234,25 +229,22 @@ void SystemTrayBubble::UpdateView(
}
void SystemTrayBubble::InitView(views::View* anchor,
TrayBubbleView::InitParams init_params,
user::LoginStatus login_status) {
user::LoginStatus login_status,
TrayBubbleView::InitParams* init_params) {
DCHECK(bubble_view_ == NULL);
if (bubble_type_ == BUBBLE_TYPE_DETAILED &&
init_params.max_height < kDetailedBubbleMaxHeight) {
init_params.max_height = kDetailedBubbleMaxHeight;
init_params->max_height < kDetailedBubbleMaxHeight) {
init_params->max_height = kDetailedBubbleMaxHeight;
} else if (bubble_type_ == BUBBLE_TYPE_NOTIFICATION) {
init_params.close_on_deactivate = false;
init_params->close_on_deactivate = false;
}
bubble_view_ = TrayBubbleView::Create(anchor, this, init_params);
bubble_view_ = TrayBubbleView::Create(
tray_->GetBubbleWindowContainer(), anchor, this, init_params);
CreateItemViews(login_status);
DCHECK(bubble_widget_ == NULL);
bubble_widget_ = views::BubbleDelegateView::CreateBubble(bubble_view_);
bubble_widget_->AddObserver(this);
InitializeAndShowBubble(bubble_widget_, bubble_view_, tray_);
bubble_wrapper_.reset(new internal::TrayBubbleWrapper(tray_, bubble_view_));
}
void SystemTrayBubble::BubbleViewDestroyed() {
@ -268,15 +260,17 @@ void SystemTrayBubble::OnMouseExitedView() {
RestartAutoCloseTimer();
}
void SystemTrayBubble::OnClickedOutsideView() {
if (bubble_type_ != BUBBLE_TYPE_NOTIFICATION)
bubble_widget_->Close();
}
string16 SystemTrayBubble::GetAccessibleName() {
return tray_->GetAccessibleName();
}
gfx::Rect SystemTrayBubble::GetAnchorRect(
views::Widget* anchor_widget,
TrayBubbleView::AnchorType anchor_type,
TrayBubbleView::AnchorAlignment anchor_alignment) {
return tray_->GetAnchorRect(anchor_widget, anchor_type, anchor_alignment);
}
void SystemTrayBubble::DestroyItemViews() {
for (std::vector<ash::SystemTrayItem*>::iterator it = items_.begin();
it != items_.end();
@ -315,21 +309,21 @@ void SystemTrayBubble::RestartAutoCloseTimer() {
}
void SystemTrayBubble::Close() {
if (bubble_widget_)
bubble_widget_->Close();
tray_->HideBubbleWithView(bubble_view());
}
void SystemTrayBubble::SetVisible(bool is_visible) {
if (!bubble_widget_)
if (!bubble_view_)
return;
views::Widget* bubble_widget = bubble_view_->GetWidget();
if (is_visible)
bubble_widget_->Show();
bubble_widget->Show();
else
bubble_widget_->Hide();
bubble_widget->Hide();
}
bool SystemTrayBubble::IsVisible() {
return bubble_widget_ && bubble_widget_->IsVisible();
return bubble_view() && bubble_view()->GetWidget()->IsVisible();
}
void SystemTrayBubble::CreateItemViews(user::LoginStatus login_status) {
@ -355,11 +349,5 @@ void SystemTrayBubble::CreateItemViews(user::LoginStatus login_status) {
}
}
void SystemTrayBubble::OnWidgetClosing(views::Widget* widget) {
CHECK_EQ(bubble_widget_, widget);
bubble_widget_ = NULL;
tray_->RemoveBubble(this);
}
} // namespace internal
} // namespace ash

@ -8,8 +8,8 @@
#include "ash/system/tray/tray_bubble_view.h"
#include "ash/system/user/login_status.h"
#include "base/base_export.h"
#include "base/memory/scoped_ptr.h"
#include "base/timer.h"
#include "ui/views/widget/widget_observer.h"
#include <vector>
@ -20,8 +20,9 @@ class SystemTrayItem;
namespace internal {
class SystemTrayBubble : public TrayBubbleView::Host,
public views::WidgetObserver {
class TrayBubbleWrapper;
class SystemTrayBubble : public TrayBubbleView::Delegate {
public:
enum BubbleType {
BUBBLE_TYPE_DEFAULT,
@ -39,17 +40,19 @@ class SystemTrayBubble : public TrayBubbleView::Host,
BubbleType bubble_type);
// Creates |bubble_view_| and a child views for each member of |items_|.
// Also creates |bubble_widget_| and sets up animations.
// Also creates |bubble_wrapper_|. |init_params| may be modified.
void InitView(views::View* anchor,
TrayBubbleView::InitParams init_params,
user::LoginStatus login_status);
user::LoginStatus login_status,
TrayBubbleView::InitParams* init_params);
// Overridden from TrayBubbleView::Host.
// Overridden from TrayBubbleView::Delegate.
virtual void BubbleViewDestroyed() OVERRIDE;
virtual void OnMouseEnteredView() OVERRIDE;
virtual void OnMouseExitedView() OVERRIDE;
virtual void OnClickedOutsideView() OVERRIDE;
virtual string16 GetAccessibleName() OVERRIDE;
virtual gfx::Rect GetAnchorRect(views::Widget* anchor_widget,
AnchorType anchor_type,
AnchorAlignment anchor_alignment) OVERRIDE;
BubbleType bubble_type() const { return bubble_type_; }
TrayBubbleView* bubble_view() const { return bubble_view_; }
@ -65,12 +68,9 @@ class SystemTrayBubble : public TrayBubbleView::Host,
private:
void CreateItemViews(user::LoginStatus login_status);
// Overridden from views::WidgetObserver:
virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE;
ash::SystemTray* tray_;
TrayBubbleView* bubble_view_;
views::Widget* bubble_widget_;
scoped_ptr<TrayBubbleWrapper> bubble_wrapper_;
std::vector<ash::SystemTrayItem*> items_;
BubbleType bubble_type_;

@ -10,10 +10,13 @@
#include "ash/system/status_area_widget.h"
#include "ash/system/status_area_widget_delegate.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/wm/window_animations.h"
#include "ui/aura/event_filter.h"
#include "ui/aura/window.h"
#include "ui/base/accessibility/accessible_view_state.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/background.h"
#include "ui/views/layout/box_layout.h"
@ -29,6 +32,8 @@ const int kTrayContainerHorizontalPaddingBottomAlignment = 1;
const int kTrayContainerVerticalPaddingVerticalAlignment = 1;
const int kTrayContainerHorizontalPaddingVerticalAlignment = 1;
const int kAnimationDurationForPopupMS = 200;
} // namespace
namespace ash {
@ -277,5 +282,83 @@ void TrayBackgroundView::SetBorder() {
}
}
void TrayBackgroundView::InitializeBubbleAnimations(
views::Widget* bubble_widget) {
ash::SetWindowVisibilityAnimationType(
bubble_widget->GetNativeWindow(),
ash::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
ash::SetWindowVisibilityAnimationTransition(
bubble_widget->GetNativeWindow(),
ash::ANIMATE_BOTH);
ash::SetWindowVisibilityAnimationDuration(
bubble_widget->GetNativeWindow(),
base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMS));
}
aura::Window* TrayBackgroundView::GetBubbleWindowContainer() const {
return ash::Shell::GetContainer(
tray_container()->GetWidget()->GetNativeWindow()->GetRootWindow(),
ash::internal::kShellWindowId_SettingBubbleContainer);
}
gfx::Rect TrayBackgroundView::GetAnchorRect(
views::Widget* anchor_widget,
TrayBubbleView::AnchorType anchor_type,
TrayBubbleView::AnchorAlignment anchor_alignment) const {
gfx::Rect rect;
if (anchor_widget && anchor_widget->IsVisible()) {
rect = anchor_widget->GetWindowBoundsInScreen();
if (anchor_type == TrayBubbleView::ANCHOR_TYPE_TRAY) {
if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) {
bool rtl = base::i18n::IsRTL();
rect.Inset(
rtl ? kPaddingFromRightEdgeOfScreenBottomAlignment : 0,
0,
rtl ? 0 : kPaddingFromRightEdgeOfScreenBottomAlignment,
kPaddingFromBottomOfScreenBottomAlignment);
} else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_LEFT) {
rect.Inset(0, 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment,
kPaddingFromBottomOfScreenVerticalAlignment);
} else {
rect.Inset(kPaddingFromInnerEdgeOfLauncherVerticalAlignment,
0, 0, kPaddingFromBottomOfScreenVerticalAlignment);
}
} else if (anchor_type == TrayBubbleView::ANCHOR_TYPE_BUBBLE) {
// Invert the offsets to align with the bubble below.
if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_LEFT) {
rect.Inset(kPaddingFromInnerEdgeOfLauncherVerticalAlignment,
0, 0, kPaddingFromBottomOfScreenVerticalAlignment);
} else if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT) {
rect.Inset(0, 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment,
kPaddingFromBottomOfScreenVerticalAlignment);
}
}
}
// TODO(jennyz): May need to add left/right alignment in the following code.
if (rect.IsEmpty()) {
rect = Shell::GetScreen()->GetPrimaryDisplay().bounds();
rect = gfx::Rect(
base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreenBottomAlignment :
rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment,
rect.height() - kPaddingFromBottomOfScreenBottomAlignment,
0, 0);
}
return rect;
}
TrayBubbleView::AnchorAlignment TrayBackgroundView::GetAnchorAlignment() const {
switch (shelf_alignment_) {
case SHELF_ALIGNMENT_BOTTOM:
return TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM;
case SHELF_ALIGNMENT_LEFT:
return TrayBubbleView::ANCHOR_ALIGNMENT_LEFT;
case SHELF_ALIGNMENT_RIGHT:
return TrayBubbleView::ANCHOR_ALIGNMENT_RIGHT;
}
NOTREACHED();
return TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM;
}
} // namespace internal
} // namespace ash

@ -7,6 +7,7 @@
#include "ash/ash_export.h"
#include "ash/launcher/background_animator.h"
#include "ash/system/tray/tray_bubble_view.h"
#include "ash/system/tray/tray_views.h"
#include "ash/wm/shelf_types.h"
@ -82,8 +83,17 @@ class ASH_EXPORT TrayBackgroundView : public internal::ActionableView,
// Called when the anchor (tray or bubble) may have moved or changed.
virtual void AnchorUpdated() {}
// Called from GetAccessibleState, must return a valid accessible name.
virtual string16 GetAccessibleName() = 0;
// Hides the bubble associated with |bubble_view|. Called when the widget
// is closed.
virtual void HideBubbleWithView(const TrayBubbleView* bubble_view) = 0;
// Called by the bubble wrapper when a click event occurs outside the bubble.
// May close the bubble. Returns true if the event is handled.
virtual bool ClickedOutsideBubble() = 0;
// Sets |contents| as a child.
void SetContents(views::View* contents);
@ -96,6 +106,21 @@ class ASH_EXPORT TrayBackgroundView : public internal::ActionableView,
bool value,
internal::BackgroundAnimator::ChangeType change_type);
// Initializes animations for the bubble.
void InitializeBubbleAnimations(views::Widget* bubble_widget);
// Returns the window hosting the bubble.
aura::Window* GetBubbleWindowContainer() const;
// Returns the anchor rect for the bubble.
gfx::Rect GetAnchorRect(
views::Widget* anchor_widget,
TrayBubbleView::AnchorType anchor_type,
TrayBubbleView::AnchorAlignment anchor_alignment) const;
// Returns the bubble anchor alignment based on |shelf_alignment_|.
TrayBubbleView::AnchorAlignment GetAnchorAlignment() const;
StatusAreaWidget* status_area_widget() {
return status_area_widget_;
}

@ -4,14 +4,6 @@
#include "ash/system/tray/tray_bubble_view.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/wm/property_util.h"
#include "ash/wm/shelf_layout_manager.h"
#include "ash/wm/window_animations.h"
#include "grit/ash_strings.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkPaint.h"
@ -24,21 +16,20 @@
#include "ui/gfx/canvas.h"
#include "ui/gfx/insets.h"
#include "ui/gfx/path.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/skia_util.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/layout/box_layout.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace internal {
namespace {
// Inset the arrow a bit from the edge.
const int kArrowMinOffset = 20;
const int kBubbleSpacing = 20;
const int kAnimationDurationForPopupMS = 200;
} // namespace
namespace ash {
// Custom border for TrayBubbleView. Contains special logic for GetBounds()
// to stack bubbles with no arrows correctly. Also calculates the arrow offset.
@ -46,9 +37,8 @@ class TrayBubbleBorder : public views::BubbleBorder {
public:
TrayBubbleBorder(views::View* owner,
views::View* anchor,
views::BubbleBorder::ArrowLocation arrow_location,
TrayBubbleView::InitParams params)
: views::BubbleBorder(arrow_location, params.shadow),
: views::BubbleBorder(params.arrow_location, params.shadow),
owner_(owner),
anchor_(anchor),
tray_arrow_offset_(params.arrow_offset) {
@ -87,7 +77,7 @@ class TrayBubbleBorder : public views::BubbleBorder {
arrow_location() == views::BubbleBorder::BOTTOM_LEFT) {
// Note: tray_arrow_offset_ is relative to the anchor widget.
if (tray_arrow_offset_ ==
internal::TrayBubbleView::InitParams::kArrowDefaultOffset) {
TrayBubbleView::InitParams::kArrowDefaultOffset) {
arrow_offset = kArrowMinOffset;
} else {
const int width = owner_->GetWidget()->GetContentsView()->width();
@ -103,7 +93,7 @@ class TrayBubbleBorder : public views::BubbleBorder {
}
} else {
if (tray_arrow_offset_ ==
internal::TrayBubbleView::InitParams::kArrowDefaultOffset) {
TrayBubbleView::InitParams::kArrowDefaultOffset) {
arrow_offset = kArrowMinOffset;
} else {
gfx::Point pt(0, tray_arrow_offset_);
@ -185,7 +175,7 @@ class TrayBubbleBackground : public views::Background {
// enough height. Otherwise, makes sure the bottom rows are visible.
class BottomAlignedBoxLayout : public views::BoxLayout {
public:
explicit BottomAlignedBoxLayout(internal::TrayBubbleView* bubble_view)
explicit BottomAlignedBoxLayout(TrayBubbleView* bubble_view)
: views::BoxLayout(views::BoxLayout::kVertical, 0, 0, 0),
bubble_view_(bubble_view) {
}
@ -213,7 +203,7 @@ class BottomAlignedBoxLayout : public views::BoxLayout {
}
}
internal::TrayBubbleView* bubble_view_;
TrayBubbleView* bubble_view_;
DISALLOW_COPY_AND_ASSIGN(BottomAlignedBoxLayout);
};
@ -222,62 +212,60 @@ class BottomAlignedBoxLayout : public views::BoxLayout {
const int TrayBubbleView::InitParams::kArrowDefaultOffset = -1;
TrayBubbleView::InitParams::InitParams(AnchorType anchor_type,
ShelfAlignment shelf_alignment)
AnchorAlignment anchor_alignment,
int bubble_width)
: anchor_type(anchor_type),
shelf_alignment(shelf_alignment),
bubble_width(kTrayPopupWidth),
anchor_alignment(anchor_alignment),
bubble_width(bubble_width),
max_height(0),
can_activate(false),
close_on_deactivate(true),
top_color(SK_ColorBLACK),
arrow_color(SK_ColorBLACK),
arrow_location(views::BubbleBorder::NONE),
arrow_offset(kArrowDefaultOffset),
shadow(views::BubbleBorder::BIG_SHADOW) {
}
TrayBubbleView* TrayBubbleView::Create(views::View* anchor,
Host* host,
const InitParams& init_params) {
TrayBubbleView* TrayBubbleView::Create(aura::Window* parent_window,
views::View* anchor,
Delegate* delegate,
InitParams* init_params) {
// Set arrow_location here so that it can be passed correctly to the
// BubbleView constructor.
views::BubbleBorder::ArrowLocation arrow_location;
if (init_params.anchor_type == ANCHOR_TYPE_TRAY) {
if (init_params.shelf_alignment == SHELF_ALIGNMENT_BOTTOM) {
arrow_location = base::i18n::IsRTL() ?
if (init_params->anchor_type == ANCHOR_TYPE_TRAY) {
if (init_params->anchor_alignment == ANCHOR_ALIGNMENT_BOTTOM) {
init_params->arrow_location = base::i18n::IsRTL() ?
views::BubbleBorder::BOTTOM_LEFT : views::BubbleBorder::BOTTOM_RIGHT;
} else if (init_params.shelf_alignment == SHELF_ALIGNMENT_LEFT) {
arrow_location = views::BubbleBorder::LEFT_BOTTOM;
} else if (init_params->anchor_alignment == ANCHOR_ALIGNMENT_LEFT) {
init_params->arrow_location = views::BubbleBorder::LEFT_BOTTOM;
} else {
arrow_location = views::BubbleBorder::RIGHT_BOTTOM;
init_params->arrow_location = views::BubbleBorder::RIGHT_BOTTOM;
}
} else {
arrow_location = views::BubbleBorder::NONE;
init_params->arrow_location = views::BubbleBorder::NONE;
}
return new TrayBubbleView(init_params, arrow_location, anchor, host);
return new TrayBubbleView(parent_window, anchor, delegate, *init_params);
}
TrayBubbleView::TrayBubbleView(
const InitParams& init_params,
views::BubbleBorder::ArrowLocation arrow_location,
views::View* anchor,
Host* host)
: views::BubbleDelegateView(anchor, arrow_location),
TrayBubbleView::TrayBubbleView(aura::Window* parent_window,
views::View* anchor,
Delegate* delegate,
const InitParams& init_params)
: views::BubbleDelegateView(anchor, init_params.arrow_location),
params_(init_params),
host_(host),
delegate_(delegate),
bubble_border_(NULL),
bubble_background_(NULL),
is_gesture_dragging_(false) {
set_parent_window(Shell::GetContainer(
anchor->GetWidget()->GetNativeWindow()->GetRootWindow(),
internal::kShellWindowId_SettingBubbleContainer));
set_parent_window(parent_window);
set_notify_enter_exit_on_child(true);
set_close_on_deactivate(init_params.close_on_deactivate);
SetPaintToLayer(true);
SetFillsBoundsOpaquely(true);
bubble_border_ = new TrayBubbleBorder(
this, anchor_view(), arrow_location, params_);
bubble_border_ = new TrayBubbleBorder(this, anchor_view(), params_);
bubble_background_ = new TrayBubbleBackground(
bubble_border_, init_params.top_color, init_params.arrow_color);
@ -290,8 +278,17 @@ TrayBubbleView::TrayBubbleView(
TrayBubbleView::~TrayBubbleView() {
// Inform host items (models) that their views are being destroyed.
if (host_)
host_->BubbleViewDestroyed();
if (delegate_)
delegate_->BubbleViewDestroyed();
}
void TrayBubbleView::InitializeAndShowBubble() {
// Must occur after call to BubbleDelegateView::CreateBubble().
SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
bubble_border_->UpdateArrowOffset();
Show();
UpdateBubble();
}
void TrayBubbleView::UpdateBubble() {
@ -305,6 +302,10 @@ void TrayBubbleView::SetMaxHeight(int height) {
SizeToContents();
}
void TrayBubbleView::GetBorderInsets(gfx::Insets* insets) const {
bubble_border_->GetInsets(insets);
}
void TrayBubbleView::Init() {
views::BoxLayout* layout = new BottomAlignedBoxLayout(this);
layout->set_spread_blank_space(true);
@ -312,47 +313,11 @@ void TrayBubbleView::Init() {
}
gfx::Rect TrayBubbleView::GetAnchorRect() {
gfx::Rect rect;
if (anchor_widget() && anchor_widget()->IsVisible()) {
rect = anchor_widget()->GetWindowBoundsInScreen();
if (params_.anchor_type == ANCHOR_TYPE_TRAY) {
if (params_.shelf_alignment == SHELF_ALIGNMENT_BOTTOM) {
bool rtl = base::i18n::IsRTL();
rect.Inset(
rtl ? kPaddingFromRightEdgeOfScreenBottomAlignment : 0,
0,
rtl ? 0 : kPaddingFromRightEdgeOfScreenBottomAlignment,
kPaddingFromBottomOfScreenBottomAlignment);
} else if (params_.shelf_alignment == SHELF_ALIGNMENT_LEFT) {
rect.Inset(0, 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment,
kPaddingFromBottomOfScreenVerticalAlignment);
} else {
rect.Inset(kPaddingFromInnerEdgeOfLauncherVerticalAlignment,
0, 0, kPaddingFromBottomOfScreenVerticalAlignment);
}
} else if (params_.anchor_type == ANCHOR_TYPE_BUBBLE) {
// Invert the offsets to align with the bubble below.
if (params_.shelf_alignment == SHELF_ALIGNMENT_LEFT) {
rect.Inset(kPaddingFromInnerEdgeOfLauncherVerticalAlignment,
0, 0, kPaddingFromBottomOfScreenVerticalAlignment);
} else if (params_.shelf_alignment == SHELF_ALIGNMENT_RIGHT) {
rect.Inset(0, 0, kPaddingFromInnerEdgeOfLauncherVerticalAlignment,
kPaddingFromBottomOfScreenVerticalAlignment);
}
}
}
// TODO(jennyz): May need to add left/right alignment in the following code.
if (rect.IsEmpty()) {
rect = Shell::GetScreen()->GetPrimaryDisplay().bounds();
rect = gfx::Rect(
base::i18n::IsRTL() ? kPaddingFromRightEdgeOfScreenBottomAlignment :
rect.width() - kPaddingFromRightEdgeOfScreenBottomAlignment,
rect.height() - kPaddingFromBottomOfScreenBottomAlignment,
0, 0);
}
return rect;
if (!delegate_)
return gfx::Rect();
return delegate_->GetAnchorRect(anchor_widget(),
params_.anchor_type,
params_.anchor_alignment);
}
bool TrayBubbleView::CanActivate() const {
@ -386,19 +351,19 @@ gfx::Size TrayBubbleView::GetPreferredSize() {
}
void TrayBubbleView::OnMouseEntered(const ui::MouseEvent& event) {
if (host_)
host_->OnMouseEnteredView();
if (delegate_)
delegate_->OnMouseEnteredView();
}
void TrayBubbleView::OnMouseExited(const ui::MouseEvent& event) {
if (host_)
host_->OnMouseExitedView();
if (delegate_)
delegate_->OnMouseExitedView();
}
void TrayBubbleView::GetAccessibleState(ui::AccessibleViewState* state) {
if (params_.can_activate) {
state->role = ui::AccessibilityTypes::ROLE_WINDOW;
state->name = host_->GetAccessibleName();
state->name = delegate_->GetAccessibleName();
}
}
@ -416,101 +381,4 @@ void TrayBubbleView::ViewHierarchyChanged(bool is_add,
}
}
TrayBubbleView::Host::Host()
: widget_(NULL),
bubble_view_(NULL),
tray_view_(NULL) {
Shell::GetInstance()->AddEnvEventFilter(this);
}
TrayBubbleView::Host::~Host() {
Shell::GetInstance()->RemoveEnvEventFilter(this);
}
void TrayBubbleView::Host::InitializeAndShowBubble(views::Widget* widget,
TrayBubbleView* bubble_view,
views::View* tray_view) {
widget_ = widget;
bubble_view_ = bubble_view;
tray_view_ = tray_view;
// Must occur after call to BubbleDelegateView::CreateBubble().
bubble_view->SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
bubble_view->bubble_border()->UpdateArrowOffset();
// Setup animation.
ash::SetWindowVisibilityAnimationType(
widget->GetNativeWindow(),
ash::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
ash::SetWindowVisibilityAnimationTransition(
widget->GetNativeWindow(),
ash::ANIMATE_BOTH);
ash::SetWindowVisibilityAnimationDuration(
widget->GetNativeWindow(),
base::TimeDelta::FromMilliseconds(kAnimationDurationForPopupMS));
bubble_view->Show();
bubble_view->UpdateBubble();
}
bool TrayBubbleView::Host::PreHandleKeyEvent(aura::Window* target,
ui::KeyEvent* event) {
return false;
}
bool TrayBubbleView::Host::PreHandleMouseEvent(aura::Window* target,
ui::MouseEvent* event) {
if (event->type() == ui::ET_MOUSE_PRESSED)
ProcessLocatedEvent(target, *event);
return false;
}
ui::TouchStatus TrayBubbleView::Host::PreHandleTouchEvent(
aura::Window* target,
ui::TouchEvent* event) {
if (event->type() == ui::ET_TOUCH_PRESSED)
ProcessLocatedEvent(target, *event);
return ui::TOUCH_STATUS_UNKNOWN;
}
ui::EventResult TrayBubbleView::Host::PreHandleGestureEvent(
aura::Window* target,
ui::GestureEvent* event) {
return ui::ER_UNHANDLED;
}
void TrayBubbleView::Host::ProcessLocatedEvent(
aura::Window* target, const ui::LocatedEvent& event) {
if (target) {
// Don't process events that occurred inside an embedded menu.
RootWindowController* root_controller =
GetRootWindowController(target->GetRootWindow());
if (root_controller && root_controller->GetContainer(
ash::internal::kShellWindowId_MenuContainer)->Contains(target)) {
return;
}
}
if (!widget_)
return;
gfx::Rect bounds = widget_->GetWindowBoundsInScreen();
gfx::Insets insets;
bubble_view_->bubble_border()->GetInsets(&insets);
bounds.Inset(insets);
if (bounds.Contains(event.root_location()))
return;
if (tray_view_) {
// If the user clicks on the parent tray, don't process the event here,
// let the tray logic handle the event and determine show/hide behavior.
bounds = tray_view_->GetWidget()->GetClientAreaBoundsInScreen();
if (bounds.Contains(event.root_location()))
return;
}
// Handle clicking outside the bubble and tray. We don't block the event, so
// it will also be handled by whatever widget was clicked on.
OnClickedOutsideView();
}
} // namespace internal
} // namespace ash

@ -5,8 +5,6 @@
#ifndef ASH_SYSTEM_TRAY_TRAY_BUBBLE_VIEW_H_
#define ASH_SYSTEM_TRAY_TRAY_BUBBLE_VIEW_H_
#include "ash/wm/shelf_types.h"
#include "ui/aura/event_filter.h"
#include "ui/views/bubble/bubble_delegate.h"
namespace ui {
@ -19,7 +17,6 @@ class Widget;
}
namespace ash {
namespace internal {
class TrayBubbleBorder;
class TrayBubbleBackground;
@ -33,83 +30,78 @@ class TrayBubbleView : public views::BubbleDelegateView {
ANCHOR_TYPE_BUBBLE
};
class Host : public aura::EventFilter {
public:
Host();
virtual ~Host();
enum AnchorAlignment {
ANCHOR_ALIGNMENT_BOTTOM,
ANCHOR_ALIGNMENT_LEFT,
ANCHOR_ALIGNMENT_RIGHT
};
// Set widget_ and tray_view_, set up animations, and show the bubble.
// Must occur after bubble_view->CreateBubble() is called.
void InitializeAndShowBubble(views::Widget* widget,
TrayBubbleView* bubble_view,
views::View* tray_view);
class Delegate {
public:
typedef TrayBubbleView::AnchorType AnchorType;
typedef TrayBubbleView::AnchorAlignment AnchorAlignment;
Delegate() {}
virtual ~Delegate() {}
virtual void BubbleViewDestroyed() = 0;
virtual void OnMouseEnteredView() = 0;
virtual void OnMouseExitedView() = 0;
virtual void OnClickedOutsideView() = 0;
virtual string16 GetAccessibleName() = 0;
// Overridden from aura::EventFilter.
virtual bool PreHandleKeyEvent(aura::Window* target,
ui::KeyEvent* event) OVERRIDE;
virtual bool PreHandleMouseEvent(aura::Window* target,
ui::MouseEvent* event) OVERRIDE;
virtual ui::TouchStatus PreHandleTouchEvent(
aura::Window* target,
ui::TouchEvent* event) OVERRIDE;
virtual ui::EventResult PreHandleGestureEvent(
aura::Window* target,
ui::GestureEvent* event) OVERRIDE;
virtual gfx::Rect GetAnchorRect(views::Widget* anchor_widget,
AnchorType anchor_type,
AnchorAlignment anchor_alignment) = 0;
private:
void ProcessLocatedEvent(aura::Window* target,
const ui::LocatedEvent& event);
views::Widget* widget_;
TrayBubbleView* bubble_view_;
views::View* tray_view_;
DISALLOW_COPY_AND_ASSIGN(Host);
DISALLOW_COPY_AND_ASSIGN(Delegate);
};
struct InitParams {
static const int kArrowDefaultOffset;
InitParams(AnchorType anchor_type,
ShelfAlignment shelf_alignment);
AnchorAlignment anchor_alignment,
int bubble_width);
AnchorType anchor_type;
ShelfAlignment shelf_alignment;
AnchorAlignment anchor_alignment;
int bubble_width;
int max_height;
bool can_activate;
bool close_on_deactivate;
SkColor top_color;
SkColor arrow_color;
views::BubbleBorder::ArrowLocation arrow_location;
int arrow_offset;
views::BubbleBorder::Shadow shadow;
};
static TrayBubbleView* Create(views::View* anchor,
Host* host,
const InitParams& init_params);
// Constructs and returns a TrayBubbleView. init_params may be modified.
static TrayBubbleView* Create(aura::Window* parent_window,
views::View* anchor,
Delegate* delegate,
InitParams* init_params);
virtual ~TrayBubbleView();
// Sets up animations, and show the bubble. Must occur after CreateBubble()
// is called.
void InitializeAndShowBubble();
// Called whenever the bubble size or location may have changed.
void UpdateBubble();
// Sets the maximum bubble height and resizes the bubble.
void SetMaxHeight(int height);
// Called when the host is destroyed.
void reset_host() { host_ = NULL; }
// Returns the border insets. Called by TrayEventFilter.
void GetBorderInsets(gfx::Insets* insets) const;
// Called when the delegate is destroyed.
void reset_delegate() { delegate_ = NULL; }
void set_gesture_dragging(bool dragging) { is_gesture_dragging_ = dragging; }
bool is_gesture_dragging() const { return is_gesture_dragging_; }
TrayBubbleBorder* bubble_border() { return bubble_border_; }
// Overridden from views::WidgetDelegate.
virtual bool CanActivate() const OVERRIDE;
virtual views::NonClientFrameView* CreateNonClientFrameView(
@ -127,10 +119,10 @@ class TrayBubbleView : public views::BubbleDelegateView {
virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
protected:
TrayBubbleView(const InitParams& init_params,
views::BubbleBorder::ArrowLocation arrow_location,
TrayBubbleView(aura::Window* parent_window,
views::View* anchor,
Host* host);
Delegate* delegate,
const InitParams& init_params);
// Overridden from views::BubbleDelegateView.
virtual void Init() OVERRIDE;
@ -143,7 +135,7 @@ class TrayBubbleView : public views::BubbleDelegateView {
private:
InitParams params_;
Host* host_;
Delegate* delegate_;
TrayBubbleBorder* bubble_border_;
TrayBubbleBackground* bubble_background_;
bool is_gesture_dragging_;
@ -151,7 +143,6 @@ class TrayBubbleView : public views::BubbleDelegateView {
DISALLOW_COPY_AND_ASSIGN(TrayBubbleView);
};
} // namespace internal
} // namespace ash
#endif // ASH_SYSTEM_TRAY_TRAY_BUBBLE_VIEW_H_

@ -0,0 +1,43 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/tray/tray_bubble_wrapper.h"
#include "ash/system/tray/tray_background_view.h"
#include "ash/system/tray/tray_bubble_view.h"
#include "ash/system/tray/tray_event_filter.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace internal {
TrayBubbleWrapper::TrayBubbleWrapper(TrayBackgroundView* tray,
TrayBubbleView* bubble_view)
: tray_(tray),
bubble_view_(bubble_view) {
bubble_widget_ = views::BubbleDelegateView::CreateBubble(bubble_view_);
bubble_widget_->AddObserver(this);
bubble_view_->InitializeAndShowBubble();
tray_->InitializeBubbleAnimations(bubble_widget_);
tray_event_filter_.reset(new TrayEventFilter(this));
}
TrayBubbleWrapper::~TrayBubbleWrapper() {
tray_event_filter_.reset();
if (bubble_widget_) {
bubble_widget_->RemoveObserver(this);
bubble_widget_->Close();
}
}
void TrayBubbleWrapper::OnWidgetClosing(views::Widget* widget) {
CHECK_EQ(bubble_widget_, widget);
bubble_widget_ = NULL;
tray_->HideBubbleWithView(bubble_view_); // May destroy |bubble_view_|
}
} // namespace internal
} // namespace ash

@ -0,0 +1,47 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_TRAY_TRAY_BUBBLE_WRAPPER_H_
#define ASH_SYSTEM_TRAY_TRAY_BUBBLE_WRAPPER_H_
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "ui/views/widget/widget_observer.h"
namespace ash {
class TrayBubbleView;
namespace internal {
class TrayBackgroundView;
class TrayEventFilter;
// Creates and manages the Widget and EventFilter components of a bubble.
class TrayBubbleWrapper : public views::WidgetObserver {
public:
TrayBubbleWrapper(TrayBackgroundView* tray, TrayBubbleView* bubble_view);
virtual ~TrayBubbleWrapper();
// views::WidgetObserver overrides:
virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE;
TrayBackgroundView* tray() { return tray_; }
TrayBubbleView* bubble_view() { return bubble_view_; }
views::Widget* bubble_widget() { return bubble_widget_; }
private:
TrayBackgroundView* tray_;
TrayBubbleView* bubble_view_; // unowned
views::Widget* bubble_widget_;
scoped_ptr<TrayEventFilter> tray_event_filter_;
DISALLOW_COPY_AND_ASSIGN(TrayBubbleWrapper);
};
} // namespace internal
} // namespace ash
#endif // ASH_SYSTEM_TRAY_TRAY_BUBBLE_WRAPPER_H_

@ -0,0 +1,93 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/system/tray/tray_event_filter.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
#include "ash/shell_window_ids.h"
#include "ash/system/tray/tray_background_view.h"
#include "ash/system/tray/tray_bubble_view.h"
#include "ash/system/tray/tray_bubble_wrapper.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/tray/tray_event_filter.h"
#include "ash/wm/property_util.h"
#include "ash/wm/shelf_layout_manager.h"
#include "ui/aura/event_filter.h"
#include "ui/aura/window.h"
#include "ui/views/widget/widget.h"
namespace ash {
namespace internal {
TrayEventFilter::TrayEventFilter(TrayBubbleWrapper* wrapper)
: wrapper_(wrapper) {
ash::Shell::GetInstance()->AddEnvEventFilter(this);
}
TrayEventFilter::~TrayEventFilter() {
ash::Shell::GetInstance()->RemoveEnvEventFilter(this);
}
bool TrayEventFilter::PreHandleKeyEvent(aura::Window* target,
ui::KeyEvent* event) {
return false;
}
bool TrayEventFilter::PreHandleMouseEvent(aura::Window* target,
ui::MouseEvent* event) {
if (event->type() == ui::ET_MOUSE_PRESSED)
return ProcessLocatedEvent(target, *event);
return false;
}
ui::TouchStatus TrayEventFilter::PreHandleTouchEvent(aura::Window* target,
ui::TouchEvent* event) {
if (event->type() == ui::ET_TOUCH_PRESSED) {
if (ProcessLocatedEvent(target, *event))
return ui::TOUCH_STATUS_END;
}
return ui::TOUCH_STATUS_UNKNOWN;
}
ui::EventResult TrayEventFilter::PreHandleGestureEvent(
aura::Window* target,
ui::GestureEvent* event) {
return ui::ER_UNHANDLED;
}
bool TrayEventFilter::ProcessLocatedEvent(aura::Window* target,
const ui::LocatedEvent& event) {
if (target) {
// Don't process events that occurred inside an embedded menu.
ash::internal::RootWindowController* root_controller =
ash::GetRootWindowController(target->GetRootWindow());
if (root_controller && root_controller->GetContainer(
ash::internal::kShellWindowId_MenuContainer)->Contains(target)) {
return false;
}
}
if (!wrapper_->bubble_widget())
return false;
gfx::Rect bounds = wrapper_->bubble_widget()->GetWindowBoundsInScreen();
gfx::Insets insets;
wrapper_->bubble_view()->GetBorderInsets(&insets);
bounds.Inset(insets);
if (bounds.Contains(event.root_location()))
return false;
if (wrapper_->tray()) {
// If the user clicks on the parent tray, don't process the event here,
// let the tray logic handle the event and determine show/hide behavior.
bounds = wrapper_->tray()->GetWidget()->GetClientAreaBoundsInScreen();
if (bounds.Contains(event.root_location()))
return false;
}
// Handle clicking outside the bubble and tray and return true if the
// event was handled.
return wrapper_->tray()->ClickedOutsideBubble();
}
} // namespace internal
} // namespace ash

@ -0,0 +1,52 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ASH_SYSTEM_TRAY_TRAY_EVENT_FILTER_H_
#define ASH_SYSTEM_TRAY_TRAY_EVENT_FILTER_H_
#include "base/basictypes.h"
#include "ui/aura/event_filter.h"
#include "ui/base/events/event.h"
namespace aura {
class Window;
}
namespace ash {
namespace internal {
class TrayBubbleWrapper;
// Handles events for a tray bubble.
class TrayEventFilter : public aura::EventFilter {
public:
explicit TrayEventFilter(TrayBubbleWrapper* wrapper);
virtual ~TrayEventFilter();
// Overridden from aura::EventFilter.
virtual bool PreHandleKeyEvent(aura::Window* target,
ui::KeyEvent* event) OVERRIDE;
virtual bool PreHandleMouseEvent(aura::Window* target,
ui::MouseEvent* event) OVERRIDE;
virtual ui::TouchStatus PreHandleTouchEvent(aura::Window* target,
ui::TouchEvent* event) OVERRIDE;
virtual ui::EventResult PreHandleGestureEvent(
aura::Window* target,
ui::GestureEvent* event) OVERRIDE;
private:
// Returns true if the event is handled.
bool ProcessLocatedEvent(aura::Window* target,
const ui::LocatedEvent& event);
TrayBubbleWrapper* wrapper_;
DISALLOW_COPY_AND_ASSIGN(TrayEventFilter);
};
} // namespace internal
} // namespace ash
#endif // ASH_SYSTEM_TRAY_TRAY_EVENT_FILTER_H_

@ -22,7 +22,6 @@
namespace ash {
using internal::TrayBubbleView;
using internal::TrayPopupTextButton;
namespace message_center {
@ -197,7 +196,8 @@ MessageCenterBubble::MessageCenterBubble(WebNotificationTray* tray) :
init_params.max_height = message_center::kWebNotificationBubbleMaxHeight;
init_params.can_activate = true;
views::View* anchor = tray_->tray_container();
bubble_view_ = TrayBubbleView::Create(anchor, this, init_params);
bubble_view_ = TrayBubbleView::Create(
tray_->GetBubbleWindowContainer(), anchor, this, &init_params);
contents_view_ = new MessageCenterContentsView(tray);
Initialize(contents_view_);
@ -220,11 +220,6 @@ void MessageCenterBubble::UpdateBubbleView() {
bubble_view_->UpdateBubble();
}
void MessageCenterBubble::OnClickedOutsideView() {
// May delete |this|.
tray_->HideMessageCenterBubble();
}
} // namespace message_center
} // namespace ash

@ -24,11 +24,9 @@ class MessageCenterBubble : public WebNotificationBubble {
size_t NumMessageViewsForTest() const;
// Overridden from TrayBubbleView::Host.
// Overridden from TrayBubbleView::Delegate.
virtual void BubbleViewDestroyed() OVERRIDE;
virtual void OnClickedOutsideView() OVERRIDE;
private:
// Overridden from WebNotificationBubble.
virtual void UpdateBubbleView() OVERRIDE;

@ -15,8 +15,6 @@
namespace ash {
using internal::TrayBubbleView;
namespace message_center {
const int kAutocloseDelaySeconds = 5;
@ -76,7 +74,8 @@ PopupBubble::PopupBubble(WebNotificationTray* tray) :
init_params.arrow_color = kBackgroundColor;
init_params.close_on_deactivate = false;
views::View* anchor = tray_->tray_container();
bubble_view_ = TrayBubbleView::Create(anchor, this, init_params);
bubble_view_ = TrayBubbleView::Create(
tray_->GetBubbleWindowContainer(), anchor, this, &init_params);
contents_view_ = new PopupBubbleContentsView(tray);
Initialize(contents_view_);
@ -107,7 +106,7 @@ void PopupBubble::UpdateBubbleView() {
WebNotificationList::Notifications popup_notifications;
tray_->notification_list()->GetPopupNotifications(&popup_notifications);
if (popup_notifications.size() == 0) {
tray_->HideBubble(this); // deletes |this|!
tray_->HideBubbleWithView(bubble_view()); // deletes |this|
return;
}
// Only update the popup tray if the number of visible popup notifications

@ -28,11 +28,9 @@ class PopupBubble : public WebNotificationBubble {
bool dirty() const { return dirty_; }
void set_dirty(bool dirty) { dirty_ = dirty; }
// Overridden from TrayBubbleView::Host.
// Overridden from TrayBubbleView::Delegate.
virtual void BubbleViewDestroyed() OVERRIDE;
virtual void OnMouseEnteredView() OVERRIDE;
virtual void OnMouseExitedView() OVERRIDE;
private:

@ -4,6 +4,7 @@
#include "ash/system/web_notification/web_notification_bubble.h"
#include "ash/system/tray/tray_bubble_wrapper.h"
#include "ash/system/tray/tray_constants.h"
#include "ash/system/web_notification/web_notification_tray.h"
#include "ash/system/web_notification/web_notification_view.h"
@ -13,8 +14,6 @@
namespace ash {
using internal::TrayBubbleView;
namespace message_center {
// Delay laying out the WebNotificationBubble until all notifications have been
@ -24,29 +23,20 @@ const int kUpdateDelayMs = 50;
WebNotificationBubble::WebNotificationBubble(WebNotificationTray* tray)
: tray_(tray),
bubble_view_(NULL),
bubble_widget_(NULL),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)) {
}
void WebNotificationBubble::Initialize(views::View* contents_view) {
DCHECK(bubble_view_);
bubble_view_->AddChildView(contents_view);
bubble_widget_ = views::BubbleDelegateView::CreateBubble(bubble_view_);
bubble_widget_->AddObserver(this);
InitializeAndShowBubble(bubble_widget_, bubble_view_, tray_);
bubble_wrapper_.reset(new internal::TrayBubbleWrapper(tray_, bubble_view_));
UpdateBubbleView();
}
WebNotificationBubble::~WebNotificationBubble() {
if (bubble_view_)
bubble_view_->reset_host();
if (bubble_widget_) {
bubble_widget_->RemoveObserver(this);
bubble_widget_->Close();
}
bubble_view_->reset_delegate();
}
void WebNotificationBubble::ScheduleUpdate() {
@ -59,7 +49,7 @@ void WebNotificationBubble::ScheduleUpdate() {
}
bool WebNotificationBubble::IsVisible() const {
return bubble_widget_ && bubble_widget_->IsVisible();
return bubble_view() && bubble_view()->GetWidget()->IsVisible();
}
void WebNotificationBubble::BubbleViewDestroyed() {
@ -72,29 +62,27 @@ void WebNotificationBubble::OnMouseEnteredView() {
void WebNotificationBubble::OnMouseExitedView() {
}
void WebNotificationBubble::OnClickedOutsideView() {
// May delete |this|.
tray_->HideMessageCenterBubble();
}
string16 WebNotificationBubble::GetAccessibleName() {
return tray_->GetAccessibleName();
}
// Overridden from views::WidgetObserver:
void WebNotificationBubble::OnWidgetClosing(views::Widget* widget) {
CHECK_EQ(bubble_widget_, widget);
bubble_widget_ = NULL;
tray_->HideBubble(this); // Will destroy |this|.
gfx::Rect WebNotificationBubble::GetAnchorRect(
views::Widget* anchor_widget,
TrayBubbleView::AnchorType anchor_type,
TrayBubbleView::AnchorAlignment anchor_alignment) {
return tray_->GetAnchorRect(anchor_widget, anchor_type, anchor_alignment);
}
TrayBubbleView::InitParams WebNotificationBubble::GetInitParams() {
TrayBubbleView::AnchorAlignment anchor_alignment =
tray_->GetAnchorAlignment();
TrayBubbleView::InitParams init_params(TrayBubbleView::ANCHOR_TYPE_TRAY,
tray_->shelf_alignment());
anchor_alignment,
kTrayPopupWidth);
init_params.top_color = kBackgroundColor;
init_params.arrow_color = kHeaderBackgroundColorDark;
init_params.bubble_width = kWebNotificationWidth;
if (tray_->shelf_alignment() == SHELF_ALIGNMENT_BOTTOM) {
if (anchor_alignment == TrayBubbleView::ANCHOR_ALIGNMENT_BOTTOM) {
views::View* anchor = tray_->tray_container();
gfx::Point bounds(anchor->width() / 2, 0);

@ -6,21 +6,22 @@
#define ASH_SYSTEM_NOTIFICATION_WEB_NOTIFICATION_BUBBLE_H_
#include "ash/system/tray/tray_bubble_view.h"
#include "ui/views/widget/widget_observer.h"
#include "base/memory/scoped_ptr.h"
namespace ash {
class WebNotificationTray;
using internal::TrayBubbleView;
namespace internal {
class TrayBubbleWrapper;
}
namespace message_center {
class WebNotificationContentsView;
class WebNotificationView;
class WebNotificationBubble : public TrayBubbleView::Host,
public views::WidgetObserver {
class WebNotificationBubble : public TrayBubbleView::Delegate {
public:
explicit WebNotificationBubble(WebNotificationTray* tray);
@ -37,29 +38,23 @@ class WebNotificationBubble : public TrayBubbleView::Host,
bool IsVisible() const;
views::Widget* bubble_widget() const { return bubble_widget_; }
TrayBubbleView* bubble_view() const { return bubble_view_; }
// Overridden from TrayBubbleView::Host.
// Overridden from TrayBubbleView::Delegate.
virtual void BubbleViewDestroyed() OVERRIDE;
virtual void OnMouseEnteredView() OVERRIDE;
virtual void OnMouseExitedView() OVERRIDE;
virtual void OnClickedOutsideView() OVERRIDE;
virtual string16 GetAccessibleName() OVERRIDE;
// Overridden from views::WidgetObserver:
virtual void OnWidgetClosing(views::Widget* widget) OVERRIDE;
virtual gfx::Rect GetAnchorRect(views::Widget* anchor_widget,
AnchorType anchor_type,
AnchorAlignment anchor_alignment) OVERRIDE;
protected:
TrayBubbleView::InitParams GetInitParams();
WebNotificationTray* tray_;
TrayBubbleView* bubble_view_;
views::Widget* bubble_widget_;
scoped_ptr<internal::TrayBubbleWrapper> bubble_wrapper_;
base::WeakPtrFactory<WebNotificationBubble> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(WebNotificationBubble);

@ -350,14 +350,24 @@ void WebNotificationTray::UpdateTrayAndBubble() {
UpdateTray();
}
void WebNotificationTray::HideBubble(WebNotificationBubble* bubble) {
if (bubble == message_center_bubble()) {
void WebNotificationTray::HideBubbleWithView(
const TrayBubbleView* bubble_view) {
if (message_center_bubble() &&
bubble_view == message_center_bubble()->bubble_view()) {
HideMessageCenterBubble();
} else if (bubble == popup_bubble()) {
} else if (popup_bubble() && bubble_view == popup_bubble()->bubble_view()) {
HidePopupBubble();
}
}
bool WebNotificationTray::ClickedOutsideBubble() {
// Only hide the message center.
if (!message_center_bubble())
return false;
HideMessageCenterBubble();
return true;
}
// Methods for testing
size_t WebNotificationTray::GetNotificationCountForTest() const {

@ -124,6 +124,8 @@ class ASH_EXPORT WebNotificationTray : public internal::TrayBackgroundView,
virtual void SetShelfAlignment(ShelfAlignment alignment) OVERRIDE;
virtual void AnchorUpdated() OVERRIDE;
virtual string16 GetAccessibleName() OVERRIDE;
virtual void HideBubbleWithView(const TrayBubbleView* bubble_view) OVERRIDE;
virtual bool ClickedOutsideBubble() OVERRIDE;
// Overridden from internal::ActionableView.
virtual bool PerformAction(const ui::Event& event) OVERRIDE;
@ -187,9 +189,6 @@ class ASH_EXPORT WebNotificationTray : public internal::TrayBackgroundView,
// As above but also updates any visible bubble.
void UpdateTrayAndBubble();
// Hides the specified bubble (called when |bubble| is closed from Views).
void HideBubble(message_center::WebNotificationBubble* bubble);
// Testing accessors.
size_t GetNotificationCountForTest() const;
bool HasNotificationForTest(const std::string& id) const;