diff options
-rw-r--r-- | ash/system/status_area_widget.cc | 6 | ||||
-rw-r--r-- | ash/system/status_area_widget.h | 3 | ||||
-rw-r--r-- | ash/wm/shelf_layout_manager.cc | 24 | ||||
-rw-r--r-- | ash/wm/shelf_layout_manager_unittest.cc | 124 |
4 files changed, 153 insertions, 4 deletions
diff --git a/ash/system/status_area_widget.cc b/ash/system/status_area_widget.cc index ec610ab..9370625 100644 --- a/ash/system/status_area_widget.cc +++ b/ash/system/status_area_widget.cc @@ -360,6 +360,12 @@ bool StatusAreaWidget::ShouldShowLauncher() const { web_notification_tray_->IsMouseInNotificationBubble()); } +bool StatusAreaWidget::IsMessageBubbleShown() const { + return ((system_tray_ && system_tray_->IsAnyBubbleVisible()) || + (web_notification_tray_ && + web_notification_tray_->IsMessageCenterBubbleVisible())); +} + void StatusAreaWidget::AddSystemTray(ShellDelegate* shell_delegate) { system_tray_ = new SystemTray(this); status_area_widget_delegate_->AddTray(system_tray_); diff --git a/ash/system/status_area_widget.h b/ash/system/status_area_widget.h index 4a5e600..26ff2a3 100644 --- a/ash/system/status_area_widget.h +++ b/ash/system/status_area_widget.h @@ -74,6 +74,9 @@ class ASH_EXPORT StatusAreaWidget : public views::Widget { // the launcher to remain visible. bool ShouldShowLauncher() const; + // True if any message bubble is shown. + bool IsMessageBubbleShown() const; + private: void AddSystemTray(ShellDelegate* shell_delegate); void AddWebNotificationTray(); diff --git a/ash/wm/shelf_layout_manager.cc b/ash/wm/shelf_layout_manager.cc index 1b765b3..0264c1d 100644 --- a/ash/wm/shelf_layout_manager.cc +++ b/ash/wm/shelf_layout_manager.cc @@ -36,6 +36,11 @@ namespace { // Delay before showing the launcher. This is after the mouse stops moving. const int kAutoHideDelayMS = 200; +// To avoid hiding the shelf when the mouse transitions from a message bubble +// into the shelf, the hit test area is enlarged by this amount of pixels to +// keep the shelf from hiding. +const int kNotificationBubbleGapHeight = 6; + ui::Layer* GetLayer(views::Widget* widget) { return widget->GetNativeView()->layer(); } @@ -852,10 +857,21 @@ ShelfLayoutManager::AutoHideState ShelfLayoutManager::CalculateAutoHideState( if (event_filter_.get() && event_filter_->in_mouse_drag()) return AUTO_HIDE_HIDDEN; - bool mouse_over_launcher = - launcher_widget()->GetWindowBoundsInScreen().Contains( - gfx::Screen::GetCursorScreenPoint()); - return mouse_over_launcher ? AUTO_HIDE_SHOWN : AUTO_HIDE_HIDDEN; + gfx::Rect shelf_region = launcher_widget()->GetWindowBoundsInScreen(); + if (Shell::GetInstance()->status_area_widget()->IsMessageBubbleShown() && + IsVisible()) { + // Increase the the hit test area to prevent the shelf from disappearing + // when the mouse is over the bubble gap. + shelf_region.Inset(alignment_ == SHELF_ALIGNMENT_RIGHT ? + -kNotificationBubbleGapHeight : 0, + alignment_ == SHELF_ALIGNMENT_BOTTOM ? + -kNotificationBubbleGapHeight : 0, + alignment_ == SHELF_ALIGNMENT_LEFT ? + -kNotificationBubbleGapHeight : 0, + 0); + } + return shelf_region.Contains(gfx::Screen::GetCursorScreenPoint()) ? + AUTO_HIDE_SHOWN : AUTO_HIDE_HIDDEN; } void ShelfLayoutManager::UpdateHitTestBounds() { diff --git a/ash/wm/shelf_layout_manager_unittest.cc b/ash/wm/shelf_layout_manager_unittest.cc index 8b1685c..e5a8d16 100644 --- a/ash/wm/shelf_layout_manager_unittest.cc +++ b/ash/wm/shelf_layout_manager_unittest.cc @@ -12,9 +12,12 @@ #include "ash/shell.h" #include "ash/shell_delegate.h" #include "ash/shell_window_ids.h" +#include "ash/system/status_area_widget.h" #include "ash/system/tray/system_tray.h" +#include "ash/system/tray/system_tray_item.h" #include "ash/test/ash_test_base.h" #include "ash/wm/window_util.h" +#include "base/utf_string_conversions.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/env.h" #include "ui/aura/display_manager.h" @@ -26,6 +29,9 @@ #include "ui/compositor/layer_animator.h" #include "ui/gfx/display.h" #include "ui/gfx/screen.h" +#include "ui/views/controls/label.h" +#include "ui/views/layout/fill_layout.h" +#include "ui/views/view.h" #include "ui/views/widget/widget.h" namespace ash { @@ -68,6 +74,76 @@ class ShelfLayoutObserverTest : public ShelfLayoutManager::Observer { DISALLOW_COPY_AND_ASSIGN(ShelfLayoutObserverTest); }; +// Trivial item implementation that tracks its views for testing. +class TestItem : public SystemTrayItem { + public: + TestItem() + : tray_view_(NULL), + default_view_(NULL), + detailed_view_(NULL), + notification_view_(NULL) {} + + virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE { + tray_view_ = new views::View; + // Add a label so it has non-zero width. + tray_view_->SetLayoutManager(new views::FillLayout); + tray_view_->AddChildView(new views::Label(UTF8ToUTF16("Tray"))); + return tray_view_; + } + + virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE { + default_view_ = new views::View; + default_view_->SetLayoutManager(new views::FillLayout); + default_view_->AddChildView(new views::Label(UTF8ToUTF16("Default"))); + return default_view_; + } + + virtual views::View* CreateDetailedView(user::LoginStatus status) OVERRIDE { + detailed_view_ = new views::View; + detailed_view_->SetLayoutManager(new views::FillLayout); + detailed_view_->AddChildView(new views::Label(UTF8ToUTF16("Detailed"))); + return detailed_view_; + } + + virtual views::View* CreateNotificationView( + user::LoginStatus status) OVERRIDE { + notification_view_ = new views::View; + return notification_view_; + } + + virtual void DestroyTrayView() OVERRIDE { + tray_view_ = NULL; + } + + virtual void DestroyDefaultView() OVERRIDE { + default_view_ = NULL; + } + + virtual void DestroyDetailedView() OVERRIDE { + detailed_view_ = NULL; + } + + virtual void DestroyNotificationView() OVERRIDE { + notification_view_ = NULL; + } + + virtual void UpdateAfterLoginStatusChange( + user::LoginStatus status) OVERRIDE {} + + views::View* tray_view() const { return tray_view_; } + views::View* default_view() const { return default_view_; } + views::View* detailed_view() const { return detailed_view_; } + views::View* notification_view() const { return notification_view_; } + + private: + views::View* tray_view_; + views::View* default_view_; + views::View* detailed_view_; + views::View* notification_view_; + + DISALLOW_COPY_AND_ASSIGN(TestItem); +}; + } // namespace class ShelfLayoutManagerTest : public ash::test::AshTestBase { @@ -808,5 +884,53 @@ TEST_F(ShelfLayoutManagerTest, Dimming) { EXPECT_FALSE(Shell::GetInstance()->launcher()->GetDimsShelf()); } +// Make sure that the shelf will not hide if the mouse is between a bubble and +// the shelf. +TEST_F(ShelfLayoutManagerTest, BubbleEnlargesShelfMouseHitArea) { + ShelfLayoutManager* shelf = GetShelfLayoutManager(); + StatusAreaWidget* status_area = Shell::GetInstance()->status_area_widget(); + SystemTray* tray = Shell::GetInstance()->system_tray(); + + shelf->LayoutShelf(); + aura::test::EventGenerator generator(Shell::GetPrimaryRootWindow()); + + // Make two iterations - first without a message bubble which should make + // the shelf disappear and then with a message bubble which should keep it + // visible. + for (int i = 0; i < 2; i++) { + // Make sure the shelf is visible and position the mouse over it. Then + // allow auto hide. + shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); + EXPECT_FALSE(status_area->IsMessageBubbleShown()); + gfx::Point center = + shelf->status()->GetWindowBoundsInScreen().CenterPoint(); + generator.MoveMouseTo(center.x(), center.y()); + shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); + EXPECT_TRUE(shelf->IsVisible()); + if (!i) { + // In our first iteration we make sure there is no bubble. + tray->CloseBubbleForTest(); + EXPECT_FALSE(status_area->IsMessageBubbleShown()); + } else { + // In our second iteration we show a bubble. + TestItem *item = new TestItem; + tray->AddTrayItem(item); + tray->ShowNotificationView(item); + EXPECT_TRUE(status_area->IsMessageBubbleShown()); + } + // Move the pointer over the edge of the shelf. + generator.MoveMouseTo(center.x(), + shelf->status()->GetWindowBoundsInScreen().y() - 5); + shelf->UpdateVisibilityState(); + if (i) { + EXPECT_TRUE(shelf->IsVisible()); + EXPECT_TRUE(status_area->IsMessageBubbleShown()); + } else { + EXPECT_FALSE(shelf->IsVisible()); + EXPECT_FALSE(status_area->IsMessageBubbleShown()); + } + } +} + } // namespace internal } // namespace ash |