diff options
author | Ben Murdoch <benm@google.com> | 2013-08-08 10:24:53 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2013-08-08 10:24:53 +0100 |
commit | bb1529ce867d8845a77ec7cdf3e3003ef1771a40 (patch) | |
tree | f78d0de03cc8aed1a934d921636a0beb8d164378 /ash | |
parent | c95505573d864f17cabf515e32f5b8e0831ae237 (diff) | |
download | chromium_org-bb1529ce867d8845a77ec7cdf3e3003ef1771a40.tar.gz |
Merge from Chromium at DEPS revision r216370
This commit was generated by merge_to_master.py.
Change-Id: I739228187a6f1df6c28c5761160e593a49891113
Diffstat (limited to 'ash')
44 files changed, 741 insertions, 299 deletions
diff --git a/ash/drag_drop/drag_drop_tracker_unittest.cc b/ash/drag_drop/drag_drop_tracker_unittest.cc index acb87a46a5..c0a9e91fa5 100644 --- a/ash/drag_drop/drag_drop_tracker_unittest.cc +++ b/ash/drag_drop/drag_drop_tracker_unittest.cc @@ -19,7 +19,7 @@ class DragDropTrackerTest : public test::AshTestBase { public: virtual void SetUp() OVERRIDE { AshTestBase::SetUp(); - UpdateDisplay("200x200,200x200"); + UpdateDisplay("200x200,300x300"); } aura::Window* CreateTestWindow(const gfx::Rect& bounds) { diff --git a/ash/launcher/launcher.cc b/ash/launcher/launcher.cc index 03e7ff8107..3dd2a14c88 100644 --- a/ash/launcher/launcher.cc +++ b/ash/launcher/launcher.cc @@ -186,4 +186,8 @@ gfx::Rect Launcher::GetLauncherViewBounds() const { return launcher_view_->bounds(); } +app_list::ApplicationDragAndDropHost* Launcher::GetDragAndDropHostForAppList() { + return launcher_view_; +} + } // namespace ash diff --git a/ash/launcher/launcher.h b/ash/launcher/launcher.h index f9bdcc0b48..c670801734 100644 --- a/ash/launcher/launcher.h +++ b/ash/launcher/launcher.h @@ -13,6 +13,10 @@ #include "ui/gfx/size.h" #include "ui/views/widget/widget_observer.h" +namespace app_list { +class ApplicationDragAndDropHost; +} + namespace aura { class Window; } @@ -103,6 +107,9 @@ class ASH_EXPORT Launcher { void SetLauncherViewBounds(gfx::Rect bounds); gfx::Rect GetLauncherViewBounds() const; + // Returns ApplicationDragAndDropHost for this Launcher. + app_list::ApplicationDragAndDropHost* GetDragAndDropHostForAppList(); + private: // LauncherView used to display icons. internal::LauncherView* launcher_view_; diff --git a/ash/launcher/launcher_view.cc b/ash/launcher/launcher_view.cc index ea027f6f33..3d328929e4 100644 --- a/ash/launcher/launcher_view.cc +++ b/ash/launcher/launcher_view.cc @@ -25,7 +25,6 @@ #include "ash/shelf/shelf_widget.h" #include "ash/shell_delegate.h" #include "base/auto_reset.h" -#include "base/command_line.h" #include "base/memory/scoped_ptr.h" #include "grit/ash_resources.h" #include "grit/ash_strings.h" @@ -1524,11 +1523,6 @@ void LauncherView::ButtonPressed(views::Button* sender, Shell::GetInstance()->delegate()->RecordUserMetricsAction( UMA_LAUNCHER_CLICK_ON_APPLIST_BUTTON); Shell::GetInstance()->ToggleAppList(GetWidget()->GetNativeView()); - // By setting us as DnD recipient, the app list knows that we can - // handle items. - if (!CommandLine::ForCurrentProcess()->HasSwitch( - ash::switches::kAshDisableDragAndDropAppListToLauncher)) - Shell::GetInstance()->SetDragAndDropHostOfCurrentAppList(this); break; } } diff --git a/ash/root_window_controller.cc b/ash/root_window_controller.cc index 33e6873701..6d5fb62777 100644 --- a/ash/root_window_controller.cc +++ b/ash/root_window_controller.cc @@ -48,7 +48,9 @@ #include "ui/aura/client/tooltip_client.h" #include "ui/aura/root_window.h" #include "ui/aura/window.h" +#include "ui/aura/window_delegate.h" #include "ui/aura/window_observer.h" +#include "ui/base/hit_test.h" #include "ui/base/models/menu_model.h" #include "ui/gfx/screen.h" #include "ui/keyboard/keyboard_controller.h" @@ -137,6 +139,64 @@ void DescendantShouldStayInSameRootWindow(aura::Window* container) { container->SetProperty(internal::kStayInSameRootWindowKey, true); } +// A window delegate which does nothing. Used to create a window that +// is a event target, but do nothing. +class EmptyWindowDelegate : public aura::WindowDelegate { + public: + EmptyWindowDelegate() {} + virtual ~EmptyWindowDelegate() {} + + // aura::WindowDelegate overrides: + virtual gfx::Size GetMinimumSize() const OVERRIDE { + return gfx::Size(); + } + virtual gfx::Size GetMaximumSize() const OVERRIDE { + return gfx::Size(); + } + virtual void OnBoundsChanged(const gfx::Rect& old_bounds, + const gfx::Rect& new_bounds) OVERRIDE { + } + virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE { + return gfx::kNullCursor; + } + virtual int GetNonClientComponent( + const gfx::Point& point) const OVERRIDE { + return HTNOWHERE; + } + virtual bool ShouldDescendIntoChildForEventHandling( + aura::Window* child, + const gfx::Point& location) OVERRIDE { + return false; + } + virtual bool CanFocus() OVERRIDE { + return false; + } + virtual void OnCaptureLost() OVERRIDE { + } + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { + } + virtual void OnDeviceScaleFactorChanged( + float device_scale_factor) OVERRIDE { + } + virtual void OnWindowDestroying() OVERRIDE {} + virtual void OnWindowDestroyed() OVERRIDE { + delete this; + } + virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE { + } + virtual bool HasHitTestMask() const OVERRIDE { + return false; + } + virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {} + virtual scoped_refptr<ui::Texture> CopyTexture() OVERRIDE { + NOTREACHED(); + return scoped_refptr<ui::Texture>(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(EmptyWindowDelegate); +}; + } // namespace namespace internal { @@ -278,6 +338,8 @@ void RootWindowController::OnLauncherCreated() { void RootWindowController::UpdateAfterLoginStatusChange( user::LoginStatus status) { + if (status != user::LOGGED_IN_NONE) + mouse_event_target_.reset(); if (shelf_->status_area_widget()) shelf_->status_area_widget()->UpdateAfterLoginStatusChange(status); } @@ -316,6 +378,8 @@ void RootWindowController::OnWallpaperAnimationFinished(views::Widget* widget) { } void RootWindowController::CloseChildWindows() { + mouse_event_target_.reset(); + if (!shelf_.get()) return; // panel_layout_manager_ needs to be shut down before windows are destroyed. @@ -460,6 +524,19 @@ void RootWindowController::InitLayoutManagers() { shelf_.reset(new ShelfWidget( shelf_container, status_container, workspace_controller())); + if (!Shell::GetInstance()->session_state_delegate()-> + IsActiveUserSessionStarted()) { + // This window exists only to be a event target on login screen. + // It does not have to handle events, nor be visible. + mouse_event_target_.reset(new aura::Window(new EmptyWindowDelegate)); + mouse_event_target_->Init(ui::LAYER_NOT_DRAWN); + + aura::Window* lock_background_container = + GetContainer(internal::kShellWindowId_LockScreenBackgroundContainer); + lock_background_container->AddChild(mouse_event_target_.get()); + mouse_event_target_->Show(); + } + // Create Docked windows layout manager aura::Window* docked_container = GetContainer( internal::kShellWindowId_DockedContainer); diff --git a/ash/root_window_controller.h b/ash/root_window_controller.h index 05ab29f9fd..bbf29ce1e3 100644 --- a/ash/root_window_controller.h +++ b/ash/root_window_controller.h @@ -241,6 +241,13 @@ class ASH_EXPORT RootWindowController : public ShellObserver { // The shelf for managing the launcher and the status widget. scoped_ptr<ShelfWidget> shelf_; + // An invisible/empty window used as a event target for + // |MouseCursorEventFilter| before a user logs in. + // (crbug.com/266987) + // Its container is |LockScreenBackgroundContainer| and + // this must be deleted before the container is deleted. + scoped_ptr<aura::Window> mouse_event_target_; + // Manages layout of docked windows. Owned by DockedContainer. DockedWindowLayoutManager* docked_layout_manager_; diff --git a/ash/root_window_controller_unittest.cc b/ash/root_window_controller_unittest.cc index b27cc52ca1..0d40125b90 100644 --- a/ash/root_window_controller_unittest.cc +++ b/ash/root_window_controller_unittest.cc @@ -473,5 +473,24 @@ TEST_F(RootWindowControllerTest, FocusBlockedWindow) { } } +typedef test::NoSessionAshTestBase NoSessionRootWindowControllerTest; + +// Make sure that an event handler exists for entire display area. +TEST_F(NoSessionRootWindowControllerTest, Event) { + aura::RootWindow* root = Shell::GetPrimaryRootWindow(); + const gfx::Size size = root->bounds().size(); + aura::Window* event_target = root->GetEventHandlerForPoint(gfx::Point(0, 0)); + EXPECT_TRUE(event_target); + EXPECT_EQ(event_target, + root->GetEventHandlerForPoint(gfx::Point(0, size.height() - 1))); + EXPECT_EQ(event_target, + root->GetEventHandlerForPoint(gfx::Point(size.width() - 1, 0))); + EXPECT_EQ(event_target, + root->GetEventHandlerForPoint(gfx::Point(0, size.height() - 1))); + EXPECT_EQ(event_target, + root->GetEventHandlerForPoint( + gfx::Point(size.width() - 1, size.height() - 1))); +} + } // namespace test } // namespace ash diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc index 82f2b20952..c0e5f77863 100644 --- a/ash/shelf/shelf_layout_manager.cc +++ b/ash/shelf/shelf_layout_manager.cc @@ -60,6 +60,18 @@ const int kAutoHideDelayMS = 200; // keep the shelf from hiding. const int kNotificationBubbleGapHeight = 6; +// The maximum size of the region on the display opposing the shelf managed by +// this ShelfLayoutManager which can trigger showing the shelf. +// For instance: +// - Primary display is left of secondary display. +// - Shelf is left aligned +// - This ShelfLayoutManager manages the shelf for the secondary display. +// |kMaxAutoHideShowShelfRegionSize| refers to the maximum size of the region +// from the right edge of the primary display which can trigger showing the +// auto hidden shelf. The region is used to make it easier to trigger showing +// the auto hidden shelf when the shelf is on the boundary between displays. +const int kMaxAutoHideShowShelfRegionSize = 10; + ui::Layer* GetLayer(views::Widget* widget) { return widget->GetNativeView()->layer(); } @@ -187,6 +199,7 @@ ShelfLayoutManager::ShelfLayoutManager(ShelfWidget* shelf) shelf_(shelf), workspace_controller_(NULL), window_overlaps_shelf_(false), + mouse_over_shelf_when_auto_hide_timer_started_(false), bezel_event_filter_(new ShelfBezelEventFilter(this)), gesture_drag_status_(GESTURE_DRAG_NONE), gesture_drag_amount_(0.f), @@ -332,14 +345,18 @@ void ShelfLayoutManager::UpdateAutoHideState() { // Hides happen immediately. SetState(state_.visibility_state); } else { - auto_hide_timer_.Stop(); + if (!auto_hide_timer_.IsRunning()) { + mouse_over_shelf_when_auto_hide_timer_started_ = + shelf_->GetWindowBoundsInScreen().Contains( + Shell::GetScreen()->GetCursorScreenPoint()); + } auto_hide_timer_.Start( FROM_HERE, base::TimeDelta::FromMilliseconds(kAutoHideDelayMS), this, &ShelfLayoutManager::UpdateAutoHideStateNow); } } else { - auto_hide_timer_.Stop(); + StopAutoHideTimer(); } } @@ -575,7 +592,7 @@ void ShelfLayoutManager::SetState(ShelfVisibilityState visibility_state) { auto_hide_event_filter_.reset(NULL); } - auto_hide_timer_.Stop(); + StopAutoHideTimer(); // The transition of background from auto-hide to visible is janky if the // transition also cause the shelf's slide animation from the bottom edge. @@ -889,6 +906,34 @@ ShelfBackgroundType ShelfLayoutManager::GetShelfBackgroundType() const { void ShelfLayoutManager::UpdateAutoHideStateNow() { SetState(state_.visibility_state); + + // If the state did not change, the auto hide timer may still be running. + StopAutoHideTimer(); +} + +void ShelfLayoutManager::StopAutoHideTimer() { + auto_hide_timer_.Stop(); + mouse_over_shelf_when_auto_hide_timer_started_ = false; +} + +gfx::Rect ShelfLayoutManager::GetAutoHideShowShelfRegionInScreen() const { + gfx::Rect shelf_bounds_in_screen = shelf_->GetWindowBoundsInScreen(); + gfx::Vector2d offset = SelectValueForShelfAlignment( + gfx::Vector2d(0, shelf_bounds_in_screen.height()), + gfx::Vector2d(-kMaxAutoHideShowShelfRegionSize, 0), + gfx::Vector2d(shelf_bounds_in_screen.width(), 0), + gfx::Vector2d(0, -kMaxAutoHideShowShelfRegionSize)); + + gfx::Rect show_shelf_region_in_screen = shelf_bounds_in_screen; + show_shelf_region_in_screen += offset; + if (IsHorizontalAlignment()) + show_shelf_region_in_screen.set_height(kMaxAutoHideShowShelfRegionSize); + else + show_shelf_region_in_screen.set_width(kMaxAutoHideShowShelfRegionSize); + + // TODO: Figure out if we need any special handling when the keyboard is + // visible. + return show_shelf_region_in_screen; } ShelfAutoHideState ShelfLayoutManager::CalculateAutoHideState( @@ -936,8 +981,29 @@ ShelfAutoHideState ShelfLayoutManager::CalculateAutoHideState( -kNotificationBubbleGapHeight : 0); } - if (shelf_region.Contains(Shell::GetScreen()->GetCursorScreenPoint())) + gfx::Point cursor_position_in_screen = + Shell::GetScreen()->GetCursorScreenPoint(); + if (shelf_region.Contains(cursor_position_in_screen)) + return SHELF_AUTO_HIDE_SHOWN; + + // When the shelf is auto hidden and the shelf is on the boundary between two + // displays, it is hard to trigger showing the shelf. For instance, if a + // user's primary display is left of their secondary display, it is hard to + // unautohide a left aligned shelf on the secondary display. + // It is hard because: + // - It is hard to stop the cursor in the shelf "light bar" and not overshoot. + // - The cursor is warped to the other display if the cursor gets to the edge + // of the display. + // Show the shelf if the cursor started on the shelf and the user overshot the + // shelf slightly to make it easier to show the shelf in this situation. We + // do not check |auto_hide_timer_|.IsRunning() because it returns false when + // the timer's task is running. + if ((state_.auto_hide_state == SHELF_AUTO_HIDE_SHOWN || + mouse_over_shelf_when_auto_hide_timer_started_) && + GetAutoHideShowShelfRegionInScreen().Contains( + cursor_position_in_screen)) { return SHELF_AUTO_HIDE_SHOWN; + } const std::vector<aura::Window*> windows = ash::MruWindowTracker::BuildWindowList(false); diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h index ce69366a26..467fe1a742 100644 --- a/ash/shelf/shelf_layout_manager.h +++ b/ash/shelf/shelf_layout_manager.h @@ -277,6 +277,16 @@ class ASH_EXPORT ShelfLayoutManager : // Updates the auto hide state immediately. void UpdateAutoHideStateNow(); + // Stops the auto hide timer and clears + // |mouse_over_shelf_when_auto_hide_timer_started_|. + void StopAutoHideTimer(); + + // Returns the bounds of an additional region which can trigger showing the + // shelf. This region exists to make it easier to trigger showing the shelf + // when the shelf is auto hidden and the shelf is on the boundary between + // two displays. + gfx::Rect GetAutoHideShowShelfRegionInScreen() const; + // Returns the AutoHideState. This value is determined from the launcher and // tray. ShelfAutoHideState CalculateAutoHideState( @@ -330,6 +340,10 @@ class ASH_EXPORT ShelfLayoutManager : base::OneShotTimer<ShelfLayoutManager> auto_hide_timer_; + // Whether the mouse was over the shelf when the auto hide timer started. + // False when neither the auto hide timer nor the timer task are running. + bool mouse_over_shelf_when_auto_hide_timer_started_; + // EventFilter used to detect when user moves the mouse over the launcher to // trigger showing the launcher. scoped_ptr<AutoHideEventFilter> auto_hide_event_filter_; diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc index 0a82cebf24..2781e6c2c6 100644 --- a/ash/shelf/shelf_layout_manager_unittest.cc +++ b/ash/shelf/shelf_layout_manager_unittest.cc @@ -7,6 +7,7 @@ #include "ash/accelerators/accelerator_controller.h" #include "ash/accelerators/accelerator_table.h" #include "ash/ash_switches.h" +#include "ash/display/display_controller.h" #include "ash/display/display_manager.h" #include "ash/focus_cycler.h" #include "ash/launcher/launcher.h" @@ -777,6 +778,99 @@ TEST_F(ShelfLayoutManagerTest, MAYBE_AutoHide) { EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); } +// Test the behavior of the shelf when it is auto hidden and it is on the +// boundary between the primary and the secondary display. +TEST_F(ShelfLayoutManagerTest, AutoHideShelfOnScreenBoundary) { + if (!SupportsMultipleDisplays()) + return; + + UpdateDisplay("800x600,800x600"); + DisplayLayout display_layout(DisplayLayout::RIGHT, 0); + Shell::GetInstance()->display_controller()->SetLayoutForCurrentDisplays( + display_layout); + // Put the primary monitor's shelf on the display boundary. + ShelfLayoutManager* shelf = GetShelfLayoutManager(); + shelf->SetAlignment(SHELF_ALIGNMENT_RIGHT); + + // Create a window because the shelf is always shown when no windows are + // visible. + CreateTestWidget(); + + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + ASSERT_EQ(root_windows[0], + GetShelfWidget()->GetNativeWindow()->GetRootWindow()); + + shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); + EXPECT_EQ(SHELF_AUTO_HIDE, shelf->visibility_state()); + + int right_edge = root_windows[0]->GetBoundsInScreen().right() - 1; + int y = root_windows[0]->GetBoundsInScreen().y(); + + // Start off the mouse nowhere near the shelf; the shelf should be hidden. + aura::test::EventGenerator& generator(GetEventGenerator()); + generator.MoveMouseTo(right_edge - 50, y); + UpdateAutoHideStateNow(); + EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); + + // Moving the mouse over the light bar (but not to the edge of the screen) + // should show the shelf. + generator.MoveMouseTo(right_edge - 1, y); + UpdateAutoHideStateNow(); + EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); + EXPECT_EQ(right_edge - 1, Shell::GetScreen()->GetCursorScreenPoint().x()); + + // Moving the mouse off the light bar should hide the shelf. + generator.MoveMouseTo(right_edge - 50, y); + UpdateAutoHideStateNow(); + EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); + + // Moving the mouse to the right edge of the screen crossing the light bar + // should show the shelf despite the mouse cursor getting warped to the + // secondary display. + generator.MoveMouseTo(right_edge - 1, y); + generator.MoveMouseTo(right_edge, y); + UpdateAutoHideStateNow(); + EXPECT_NE(right_edge - 1, Shell::GetScreen()->GetCursorScreenPoint().x()); + EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); + + // Hide the shelf. + generator.MoveMouseTo(right_edge - 50, y); + UpdateAutoHideStateNow(); + EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); + + // Moving the mouse to the right edge of the screen crossing the light bar and + // overshooting by a lot should keep the shelf hidden. + generator.MoveMouseTo(right_edge - 1, y); + generator.MoveMouseTo(right_edge + 50, y); + UpdateAutoHideStateNow(); + EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); + + // Moving the mouse to the right edge of the screen crossing the light bar and + // overshooting a bit should show the shelf. + generator.MoveMouseTo(right_edge - 1, y); + generator.MoveMouseTo(right_edge + 2, y); + UpdateAutoHideStateNow(); + EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); + + // Keeping the mouse close to the left edge of the secondary display after the + // shelf is shown should keep the shelf shown. + generator.MoveMouseTo(right_edge + 2, y + 1); + UpdateAutoHideStateNow(); + EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->auto_hide_state()); + + // Moving the mouse far from the left edge of the secondary display should + // hide the shelf. + generator.MoveMouseTo(right_edge + 50, y); + UpdateAutoHideStateNow(); + EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); + + // Moving to the left edge of the secondary display without first crossing + // the primary display's right aligned shelf first should not show the shelf. + generator.MoveMouseTo(right_edge + 2, y); + UpdateAutoHideStateNow(); + EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->auto_hide_state()); +} + // Assertions around the lock screen showing. TEST_F(ShelfLayoutManagerTest, VisibleWhenLockScreenShowing) { // Since ShelfLayoutManager queries for mouse location, move the mouse so diff --git a/ash/shell.cc b/ash/shell.cc index c7b4b1f564..1bade434dd 100644 --- a/ash/shell.cc +++ b/ash/shell.cc @@ -675,13 +675,6 @@ void Shell::ToggleAppList(aura::Window* window) { app_list_controller_->SetVisible(!app_list_controller_->IsVisible(), window); } -void Shell::SetDragAndDropHostOfCurrentAppList( - app_list::ApplicationDragAndDropHost* drag_and_drop_host) { - if (app_list_controller_.get()) - app_list_controller_->SetDragAndDropHostOfCurrentAppList( - drag_and_drop_host); -} - bool Shell::GetAppListTargetVisibility() const { return app_list_controller_.get() && app_list_controller_->GetTargetVisibility(); diff --git a/ash/shell.h b/ash/shell.h index 237a1a8866..c3adade53b 100644 --- a/ash/shell.h +++ b/ash/shell.h @@ -27,9 +27,6 @@ class CommandLine; -namespace app_list { -class ApplicationDragAndDropHost; -} namespace aura { class EventFilter; class RootWindow; @@ -224,11 +221,6 @@ class ASH_EXPORT Shell // will be used. void ToggleAppList(aura::Window* anchor); - // If |drag_and_drop_host| is not NULL it will be called upon drag and drop - // operations outside the application list. - void SetDragAndDropHostOfCurrentAppList( - app_list::ApplicationDragAndDropHost* drag_and_drop_host); - // Returns app list target visibility. bool GetAppListTargetVisibility() const; diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc index 318873c608..20d0a7f65f 100644 --- a/ash/shell/shell_delegate_impl.cc +++ b/ash/shell/shell_delegate_impl.cc @@ -231,16 +231,6 @@ void ShellDelegateImpl::HandleMediaPlayPause() { void ShellDelegateImpl::HandleMediaPrevTrack() { } -base::string16 ShellDelegateImpl::GetTimeRemainingString( - base::TimeDelta delta) { - return base::string16(); -} - -base::string16 ShellDelegateImpl::GetTimeDurationLongString( - base::TimeDelta delta) { - return base::string16(); -} - void ShellDelegateImpl::SaveScreenMagnifierScale(double scale) { } diff --git a/ash/shell/shell_delegate_impl.h b/ash/shell/shell_delegate_impl.h index c01b201ebd..7a4e5d6f41 100644 --- a/ash/shell/shell_delegate_impl.h +++ b/ash/shell/shell_delegate_impl.h @@ -71,9 +71,6 @@ class ShellDelegateImpl : public ash::ShellDelegate { virtual void HandleMediaNextTrack() OVERRIDE; virtual void HandleMediaPlayPause() OVERRIDE; virtual void HandleMediaPrevTrack() OVERRIDE; - virtual base::string16 GetTimeRemainingString(base::TimeDelta delta) OVERRIDE; - virtual base::string16 GetTimeDurationLongString( - base::TimeDelta delta) OVERRIDE; virtual void SaveScreenMagnifierScale(double scale) OVERRIDE; virtual double GetSavedScreenMagnifierScale() OVERRIDE; virtual ui::MenuModel* CreateContextMenu( diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h index 2bf08c1766..38164f2add 100644 --- a/ash/shell_delegate.h +++ b/ash/shell_delegate.h @@ -12,7 +12,6 @@ #include "ash/shell.h" #include "base/callback.h" #include "base/strings/string16.h" -#include "base/time/time.h" namespace app_list { class AppListViewDelegate; @@ -235,14 +234,6 @@ class ASH_EXPORT ShellDelegate { // Handles the Previous Track Media shortcut key. virtual void HandleMediaPrevTrack() = 0; - // Produces l10n-ed text of remaining time, e.g.: "13 minutes left" or - // "13 Minuten links". - // Used, for example, to display the remaining battery life. - virtual base::string16 GetTimeRemainingString(base::TimeDelta delta) = 0; - - // Produces l10n-ed text for time duration, e.g.: "13 minutes" or "2 hours". - virtual base::string16 GetTimeDurationLongString(base::TimeDelta delta) = 0; - // Saves the zoom scale of the full screen magnifier. virtual void SaveScreenMagnifierScale(double scale) = 0; diff --git a/ash/system/chromeos/audio/tray_audio.cc b/ash/system/chromeos/audio/tray_audio.cc index 20cc1ef8d4..6ad4362a44 100644 --- a/ash/system/chromeos/audio/tray_audio.cc +++ b/ash/system/chromeos/audio/tray_audio.cc @@ -153,12 +153,12 @@ class BarSeparator : public views::View { BarSeparator() {} virtual ~BarSeparator() {} - private: // Overriden from views::View. virtual gfx::Size GetPreferredSize() OVERRIDE { return gfx::Size(kBarSeparatorWidth, kBarSeparatorHeight); } + private: virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { canvas->FillRect(gfx::Rect(width() / 2, 0, 1, height()), kButtonStrokeColor); @@ -189,12 +189,12 @@ class VolumeView : public ActionableView, slider_ = new VolumeSlider(this); AddChildView(slider_); - device_type_ = new views::ImageView; - AddChildView(device_type_); - bar_ = new BarSeparator; AddChildView(bar_); + device_type_ = new views::ImageView; + AddChildView(device_type_); + more_ = new views::ImageView; more_->EnableCanvasFlippingForRTLUI(true); more_->SetImage(ui::ResourceBundle::GetSharedInstance().GetImageNamed( @@ -252,15 +252,14 @@ class VolumeView : public ActionableView, if (!audio_handler->GetActiveOutputDevice(&device)) return; int device_icon = GetAudioDeviceIconId(device.type); + bar_->SetVisible(show_more); if (device_icon != kNoAudioDeviceIcon) { device_type_->SetVisible(true); device_type_->SetImage( ui::ResourceBundle::GetSharedInstance().GetImageNamed( device_icon).ToImageSkia()); - bar_->SetVisible(false); } else { device_type_->SetVisible(false); - bar_->SetVisible(show_more); } } @@ -302,24 +301,33 @@ class VolumeView : public ActionableView, bounds.set_y((height() - size.height()) / 2); more_->SetBoundsRect(bounds); - // Layout bar_ or device_type_ at the left of the more_ button. + // Layout either bar_ or device_type_ at the left of the more_ button. views::View* view_left_to_more; - if (bar_->visible()) - view_left_to_more = bar_; - else + if (device_type_->visible()) view_left_to_more = device_type_; - gfx::Size bar_size = view_left_to_more->GetPreferredSize(); - gfx::Rect bar_bounds(bar_size); - bar_bounds.set_x(more_->bounds().x() - bar_size.width() - + else + view_left_to_more = bar_; + gfx::Size view_size = view_left_to_more->GetPreferredSize(); + gfx::Rect view_bounds(view_size); + view_bounds.set_x(more_->bounds().x() - view_size.width() - kExtraPaddingBetweenBarAndMore); - bar_bounds.set_y((height() - bar_size.height()) / 2); - view_left_to_more->SetBoundsRect(bar_bounds); - + view_bounds.set_y((height() - view_size.height()) / 2); + view_left_to_more->SetBoundsRect(view_bounds); + + // Layout vertical bar next to view_left_to_more if device_type_ is visible. + if (device_type_->visible()) { + gfx::Size bar_size = bar_->GetPreferredSize(); + gfx::Rect bar_bounds(bar_size); + bar_bounds.set_x(view_left_to_more->bounds().x() - bar_size.width()); + bar_bounds.set_y((height() - bar_size.height()) / 2); + bar_->SetBoundsRect(bar_bounds); + } // Layout slider, calculate slider width. gfx::Rect slider_bounds = slider_->bounds(); slider_bounds.set_width( - view_left_to_more->bounds().x() - kTrayPopupPaddingBetweenItems + bar_->bounds().x() + - (device_type_->visible() ? 0 : kTrayPopupPaddingBetweenItems) - slider_bounds.x()); slider_->SetBoundsRect(slider_bounds); } diff --git a/ash/system/chromeos/power/power_status.cc b/ash/system/chromeos/power/power_status.cc index a9f4dbfaae..0283a0c3fe 100644 --- a/ash/system/chromeos/power/power_status.cc +++ b/ash/system/chromeos/power/power_status.cc @@ -17,6 +17,7 @@ #include "grit/ash_resources.h" #include "grit/ash_strings.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/time_format.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_skia_operations.h" @@ -47,19 +48,15 @@ void SanitizeProto(power_manager::PowerSupplyProperties* proto) { base::string16 GetBatteryTimeAccessibilityString(int hour, int min) { DCHECK(hour || min); if (hour && !min) { - return Shell::GetInstance()->delegate()->GetTimeDurationLongString( - base::TimeDelta::FromHours(hour)); + return ui::TimeFormat::TimeDurationLong(base::TimeDelta::FromHours(hour)); } if (min && !hour) { - return Shell::GetInstance()->delegate()->GetTimeDurationLongString( - base::TimeDelta::FromMinutes(min)); + return ui::TimeFormat::TimeDurationLong(base::TimeDelta::FromMinutes(min)); } return l10n_util::GetStringFUTF16( IDS_ASH_STATUS_TRAY_BATTERY_TIME_ACCESSIBLE, - Shell::GetInstance()->delegate()->GetTimeDurationLongString( - base::TimeDelta::FromHours(hour)), - Shell::GetInstance()->delegate()->GetTimeDurationLongString( - base::TimeDelta::FromMinutes(min))); + ui::TimeFormat::TimeDurationLong(base::TimeDelta::FromHours(hour)), + ui::TimeFormat::TimeDurationLong(base::TimeDelta::FromMinutes(min))); } static PowerStatus* g_power_status = NULL; diff --git a/ash/system/chromeos/power/power_status_view.cc b/ash/system/chromeos/power/power_status_view.cc index a38d31568a..5323f5c1a6 100644 --- a/ash/system/chromeos/power/power_status_view.cc +++ b/ash/system/chromeos/power/power_status_view.cc @@ -14,6 +14,7 @@ #include "base/strings/utf_string_conversions.h" #include "grit/ash_strings.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/time_format.h" #include "ui/base/resource/resource_bundle.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" @@ -193,13 +194,8 @@ void PowerStatusView::UpdateTextForNotificationView() { } else { // This is a low battery warning prompting the user in minutes. min = hour * 60 + min; - ShellDelegate* delegate = Shell::GetInstance()->delegate(); - if (delegate) { - time_label_->SetText(delegate->GetTimeRemainingString( - base::TimeDelta::FromMinutes(min))); - } else { - time_label_->SetText(base::string16()); - } + time_label_->SetText(ui::TimeFormat::TimeRemaining( + base::TimeDelta::FromMinutes(min))); } } else { time_label_->SetText(base::string16()); diff --git a/ash/system/chromeos/screen_security/screen_capture_tray_item.cc b/ash/system/chromeos/screen_security/screen_capture_tray_item.cc index f375bf7331..6563e4bad8 100644 --- a/ash/system/chromeos/screen_security/screen_capture_tray_item.cc +++ b/ash/system/chromeos/screen_security/screen_capture_tray_item.cc @@ -8,9 +8,19 @@ #include "grit/ash_resources.h" #include "grit/ash_strings.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" + +using message_center::Notification; namespace ash { namespace internal { +namespace { + +const char kScreenCaptureNotificationId[] = "chrome://screen/capture"; + +} // namespace ScreenCaptureTrayItem::ScreenCaptureTrayItem(SystemTray* system_tray) : ScreenTrayItem(system_tray) { @@ -33,7 +43,6 @@ views::View* ScreenCaptureTrayItem::CreateDefaultView( user::LoginStatus status) { set_default_view(new tray::ScreenStatusView( this, - tray::ScreenStatusView::VIEW_DEFAULT, IDR_AURA_UBER_TRAY_DISPLAY, screen_capture_status_, l10n_util::GetStringUTF16( @@ -41,15 +50,27 @@ views::View* ScreenCaptureTrayItem::CreateDefaultView( return default_view(); } -views::View* ScreenCaptureTrayItem::CreateNotificationView( - user::LoginStatus status) { - set_notification_view(new tray::ScreenNotificationView( - this, - IDR_AURA_UBER_TRAY_DISPLAY, +void ScreenCaptureTrayItem::CreateOrUpdateNotification() { + message_center::RichNotificationData data; + data.buttons.push_back(message_center::ButtonInfo( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_CAPTURE_STOP))); + ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance(); + scoped_ptr<Notification> notification(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + kScreenCaptureNotificationId, screen_capture_status_, - l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_SCREEN_CAPTURE_STOP))); - return notification_view(); + base::string16() /* body is blank */, + resource_bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DISPLAY), + base::string16() /* display_source */, + std::string() /* extension_id */, + data, + new tray::ScreenNotificationDelegate(this))); + notification->SetSystemPriority(); + message_center::MessageCenter::Get()->AddNotification(notification.Pass()); +} + +std::string ScreenCaptureTrayItem::GetNotificationId() { + return kScreenCaptureNotificationId; } void ScreenCaptureTrayItem::OnScreenCaptureStart( diff --git a/ash/system/chromeos/screen_security/screen_capture_tray_item.h b/ash/system/chromeos/screen_security/screen_capture_tray_item.h index f1fb4b5295..92f6c8a711 100644 --- a/ash/system/chromeos/screen_security/screen_capture_tray_item.h +++ b/ash/system/chromeos/screen_security/screen_capture_tray_item.h @@ -22,11 +22,13 @@ class ASH_EXPORT ScreenCaptureTrayItem : public ScreenTrayItem, virtual ~ScreenCaptureTrayItem(); private: - // Overridden from ScreenTrayItem. + // Overridden from SystemTrayItem. virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE; virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE; - virtual views::View* CreateNotificationView( - user::LoginStatus status) OVERRIDE; + + // Overridden from ScreenTrayItem. + virtual void CreateOrUpdateNotification() OVERRIDE; + virtual std::string GetNotificationId() OVERRIDE; // Overridden from ScreenCaptureObserver. virtual void OnScreenCaptureStart( diff --git a/ash/system/chromeos/screen_security/screen_share_tray_item.cc b/ash/system/chromeos/screen_security/screen_share_tray_item.cc index 3e107639ae..18dd317883 100644 --- a/ash/system/chromeos/screen_security/screen_share_tray_item.cc +++ b/ash/system/chromeos/screen_security/screen_share_tray_item.cc @@ -8,9 +8,19 @@ #include "grit/ash_resources.h" #include "grit/ash_strings.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/message_center/message_center.h" +#include "ui/message_center/notification.h" + +using message_center::Notification; namespace ash { namespace internal { +namespace { + +const char kScreenShareNotificationId[] = "chrome://screen/share"; + +} ScreenShareTrayItem::ScreenShareTrayItem(SystemTray* system_tray) : ScreenTrayItem(system_tray) { @@ -32,7 +42,6 @@ views::View* ScreenShareTrayItem::CreateTrayView(user::LoginStatus status) { views::View* ScreenShareTrayItem::CreateDefaultView(user::LoginStatus status) { set_default_view(new tray::ScreenStatusView( this, - tray::ScreenStatusView::VIEW_DEFAULT, IDR_AURA_UBER_TRAY_DISPLAY, l10n_util::GetStringUTF16( IDS_ASH_STATUS_TRAY_SCREEN_SHARE_BEING_HELPED), @@ -41,8 +50,7 @@ views::View* ScreenShareTrayItem::CreateDefaultView(user::LoginStatus status) { return default_view(); } -views::View* ScreenShareTrayItem::CreateNotificationView( - user::LoginStatus status) { +void ScreenShareTrayItem::CreateOrUpdateNotification() { base::string16 help_label_text; if (!helper_name_.empty()) { help_label_text = l10n_util::GetStringFUTF16( @@ -53,13 +61,26 @@ views::View* ScreenShareTrayItem::CreateNotificationView( IDS_ASH_STATUS_TRAY_SCREEN_SHARE_BEING_HELPED); } - set_notification_view(new tray::ScreenNotificationView( - this, - IDR_AURA_UBER_TRAY_DISPLAY, + message_center::RichNotificationData data; + data.buttons.push_back(message_center::ButtonInfo( + l10n_util::GetStringUTF16(IDS_ASH_STATUS_TRAY_SCREEN_SHARE_STOP))); + ui::ResourceBundle& resource_bundle = ui::ResourceBundle::GetSharedInstance(); + scoped_ptr<Notification> notification(new Notification( + message_center::NOTIFICATION_TYPE_SIMPLE, + kScreenShareNotificationId, help_label_text, - l10n_util::GetStringUTF16( - IDS_ASH_STATUS_TRAY_SCREEN_SHARE_STOP))); - return notification_view(); + base::string16() /* body is blank */, + resource_bundle.GetImageNamed(IDR_AURA_UBER_TRAY_DISPLAY), + base::string16() /* display_source */, + std::string() /* extension_id */, + data, + new tray::ScreenNotificationDelegate(this))); + notification->SetSystemPriority(); + message_center::MessageCenter::Get()->AddNotification(notification.Pass()); +} + +std::string ScreenShareTrayItem::GetNotificationId() { + return kScreenShareNotificationId; } void ScreenShareTrayItem::OnScreenShareStart( diff --git a/ash/system/chromeos/screen_security/screen_share_tray_item.h b/ash/system/chromeos/screen_security/screen_share_tray_item.h index 4624ac2ee6..14f26e5667 100644 --- a/ash/system/chromeos/screen_security/screen_share_tray_item.h +++ b/ash/system/chromeos/screen_security/screen_share_tray_item.h @@ -25,8 +25,10 @@ class ASH_EXPORT ScreenShareTrayItem : public ScreenTrayItem, // Overridden from SystemTrayItem. virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE; virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE; - virtual views::View* CreateNotificationView( - user::LoginStatus status) OVERRIDE; + + // Overridden from ScreenTrayItem. + virtual void CreateOrUpdateNotification() OVERRIDE; + virtual std::string GetNotificationId() OVERRIDE; // Overridden from ScreenShareObserver. virtual void OnScreenShareStart( diff --git a/ash/system/chromeos/screen_security/screen_tray_item.cc b/ash/system/chromeos/screen_security/screen_tray_item.cc index 8c845e7efb..4b10a27072 100644 --- a/ash/system/chromeos/screen_security/screen_tray_item.cc +++ b/ash/system/chromeos/screen_security/screen_tray_item.cc @@ -7,14 +7,12 @@ #include "ash/system/tray/fixed_sized_image_view.h" #include "ash/system/tray/tray_constants.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/message_center/message_center.h" #include "ui/views/controls/label.h" #include "ui/views/layout/box_layout.h" namespace { -const int kStopButtonRightPaddingDefaultView = 18; -const int kStopButtonRightPaddingNotificationView = 0; -const int kStopButtonLeftPaddingNotificationView = 4; -const int kVerticalPaddingScreenCaptureNotitification = 12; +const int kStopButtonRightPadding = 18; } // namespace namespace ash { @@ -43,7 +41,6 @@ void ScreenTrayView::Update() { // ScreenStatusView implementations. ScreenStatusView::ScreenStatusView(ScreenTrayItem* screen_tray_item, - ViewType view_type, int icon_id, const base::string16& label_text, const base::string16& stop_button_text) @@ -51,7 +48,6 @@ ScreenStatusView::ScreenStatusView(ScreenTrayItem* screen_tray_item, icon_(NULL), label_(NULL), stop_button_(NULL), - view_type_(view_type), icon_id_(icon_id), label_text_(label_text), stop_button_text_(stop_button_text) { @@ -65,18 +61,10 @@ ScreenStatusView::~ScreenStatusView() { void ScreenStatusView::Layout() { views::View::Layout(); - int stop_button_right_padding = - view_type_ == VIEW_DEFAULT ? - kStopButtonRightPaddingDefaultView : - kStopButtonRightPaddingNotificationView; - int stop_button_left_padding = - view_type_ == VIEW_DEFAULT ? - kTrayPopupPaddingBetweenItems : - kStopButtonLeftPaddingNotificationView; // Give the stop button the space it requests. gfx::Size stop_size = stop_button_->GetPreferredSize(); gfx::Rect stop_bounds(stop_size); - stop_bounds.set_x(width() - stop_size.width() - stop_button_right_padding); + stop_bounds.set_x(width() - stop_size.width() - kStopButtonRightPadding); stop_bounds.set_y((height() - stop_size.height()) / 2); stop_button_->SetBoundsRect(stop_bounds); @@ -84,7 +72,7 @@ void ScreenStatusView::Layout() { if (label_->bounds().Intersects(stop_button_->bounds())) { gfx::Rect label_bounds = label_->bounds(); label_bounds.set_width( - stop_button_->x() - stop_button_left_padding - label_->x()); + stop_button_->x() - kTrayPopupPaddingBetweenItems - label_->x()); label_->SetBoundsRect(label_bounds); } } @@ -99,22 +87,13 @@ void ScreenStatusView::ButtonPressed( void ScreenStatusView::CreateItems() { set_background(views::Background::CreateSolidBackground(kBackgroundColor)); ui::ResourceBundle& bundle = ui::ResourceBundle::GetSharedInstance(); - if (view_type_ == VIEW_DEFAULT) { - SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, - kTrayPopupPaddingHorizontal, - 0, - kTrayPopupPaddingBetweenItems)); - icon_ = new FixedSizedImageView(0, kTrayPopupItemHeight); - icon_->SetImage(bundle.GetImageNamed(icon_id_).ToImageSkia()); - AddChildView(icon_); - } else { - SetLayoutManager( - new views::BoxLayout(views::BoxLayout::kHorizontal, - 0, - kVerticalPaddingScreenCaptureNotitification, - 0)); - } - + SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, + kTrayPopupPaddingHorizontal, + 0, + kTrayPopupPaddingBetweenItems)); + icon_ = new FixedSizedImageView(0, kTrayPopupItemHeight); + icon_->SetImage(bundle.GetImageNamed(icon_id_).ToImageSkia()); + AddChildView(icon_); label_ = new views::Label; label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); label_->SetMultiLine(true); @@ -126,40 +105,34 @@ void ScreenStatusView::CreateItems() { } void ScreenStatusView::Update() { - if (view_type_ == VIEW_DEFAULT) { - // Hide the notification bubble when the ash tray bubble opens. - screen_tray_item_->HideNotificationView(); - SetVisible(screen_tray_item_->is_started()); - } + // Hide the notification bubble when the ash tray bubble opens. + screen_tray_item_->HideNotificationView(); + SetVisible(screen_tray_item_->is_started()); } +ScreenNotificationDelegate::ScreenNotificationDelegate( + ScreenTrayItem* screen_tray) + : screen_tray_(screen_tray) { +} -// ScreenNotificationView implementations. -ScreenNotificationView::ScreenNotificationView( - ScreenTrayItem* screen_tray_item, - int icon_id, - const base::string16& label_text, - const base::string16& stop_button_text) - : TrayNotificationView(screen_tray_item, icon_id), - screen_tray_item_(screen_tray_item) { - screen_status_view_ = new ScreenStatusView( - screen_tray_item, - ScreenStatusView::VIEW_NOTIFICATION, - icon_id, - label_text, - stop_button_text); - InitView(screen_status_view_); - Update(); +ScreenNotificationDelegate::~ScreenNotificationDelegate() { +} + +void ScreenNotificationDelegate::Display() { } -ScreenNotificationView::~ScreenNotificationView() { +void ScreenNotificationDelegate::Error() { } -void ScreenNotificationView::Update() { - if (screen_tray_item_->is_started()) - screen_status_view_->Update(); - else - screen_tray_item_->HideNotificationView(); +void ScreenNotificationDelegate::Close(bool by_user) { +} + +void ScreenNotificationDelegate::Click() { +} + +void ScreenNotificationDelegate::ButtonClick(int button_index) { + DCHECK_EQ(0, button_index); + screen_tray_->Stop(); } } // namespace tray @@ -168,7 +141,6 @@ ScreenTrayItem::ScreenTrayItem(SystemTray* system_tray) : SystemTrayItem(system_tray), tray_view_(NULL), default_view_(NULL), - notification_view_(NULL), is_started_(false), stop_callback_(base::Bind(&base::DoNothing)) { } @@ -180,8 +152,12 @@ void ScreenTrayItem::Update() { tray_view_->Update(); if (default_view_) default_view_->Update(); - if (notification_view_) - notification_view_->Update(); + if (is_started_) { + CreateOrUpdateNotification(); + } else { + message_center::MessageCenter::Get()->RemoveNotification( + GetNotificationId(), false /* by_user */); + } } void ScreenTrayItem::Start(const base::Closure& stop_callback) { @@ -196,7 +172,7 @@ void ScreenTrayItem::Start(const base::Closure& stop_callback) { if (!system_tray()->HasSystemBubbleType( SystemTrayBubble::BUBBLE_TYPE_DEFAULT)) { - ShowNotificationView(); + CreateOrUpdateNotification(); } } @@ -220,9 +196,5 @@ void ScreenTrayItem::DestroyDefaultView() { default_view_ = NULL; } -void ScreenTrayItem::DestroyNotificationView() { - notification_view_ = NULL; -} - } // namespace internal } // namespace ash diff --git a/ash/system/chromeos/screen_security/screen_tray_item.h b/ash/system/chromeos/screen_security/screen_tray_item.h index 03b8435d34..f078a39f0e 100644 --- a/ash/system/chromeos/screen_security/screen_tray_item.h +++ b/ash/system/chromeos/screen_security/screen_tray_item.h @@ -11,6 +11,7 @@ #include "ash/system/tray/tray_item_view.h" #include "ash/system/tray/tray_notification_view.h" #include "ash/system/tray/tray_popup_label_button.h" +#include "ui/message_center/notification_delegate.h" #include "ui/views/controls/button/button.h" #include "ui/views/controls/image_view.h" @@ -41,13 +42,7 @@ class ScreenTrayView : public TrayItemView { class ScreenStatusView : public views::View, public views::ButtonListener { public: - enum ViewType { - VIEW_DEFAULT, - VIEW_NOTIFICATION - }; - ScreenStatusView(ScreenTrayItem* screen_tray_item, - ViewType view_type, int icon_id, const base::string16& label_text, const base::string16& stop_button_text); @@ -68,7 +63,6 @@ class ScreenStatusView : public views::View, views::ImageView* icon_; views::Label* label_; TrayPopupLabelButton* stop_button_; - ViewType view_type_; int icon_id_; base::string16 label_text_; base::string16 stop_button_text_; @@ -76,21 +70,24 @@ class ScreenStatusView : public views::View, DISALLOW_COPY_AND_ASSIGN(ScreenStatusView); }; -class ScreenNotificationView : public TrayNotificationView { +class ScreenNotificationDelegate : public message_center::NotificationDelegate { public: - ScreenNotificationView(ScreenTrayItem* screen_tray_item, - int icon_id, - const base::string16& label_text, - const base::string16& stop_button_text); - virtual ~ScreenNotificationView(); + explicit ScreenNotificationDelegate(ScreenTrayItem* screen_tray); - void Update(); + // message_center::NotificationDelegate overrides: + virtual void Display() OVERRIDE; + virtual void Error() OVERRIDE; + virtual void Close(bool by_user) OVERRIDE; + virtual void Click() OVERRIDE; + virtual void ButtonClick(int button_index) OVERRIDE; + + protected: + virtual ~ScreenNotificationDelegate(); private: - ScreenTrayItem* screen_tray_item_; - ScreenStatusView* screen_status_view_; + ScreenTrayItem* screen_tray_; - DISALLOW_COPY_AND_ASSIGN(ScreenNotificationView); + DISALLOW_COPY_AND_ASSIGN(ScreenNotificationDelegate); }; } // namespace tray @@ -114,13 +111,6 @@ class ASH_EXPORT ScreenTrayItem : public SystemTrayItem { default_view_ = default_view; } - tray::ScreenNotificationView* notification_view() { - return notification_view_; - } - void set_notification_view(tray::ScreenNotificationView* notification_view) { - notification_view_ = notification_view; - } - bool is_started() const { return is_started_; } void set_is_started(bool is_started) { is_started_ = is_started; } @@ -128,20 +118,21 @@ class ASH_EXPORT ScreenTrayItem : public SystemTrayItem { void Start(const base::Closure& stop_callback); void Stop(); + // Creates or updates the notification for the tray item. + virtual void CreateOrUpdateNotification() = 0; + + // Returns the id of the notification for the tray item. + virtual std::string GetNotificationId() = 0; + // Overridden from SystemTrayItem. virtual views::View* CreateTrayView(user::LoginStatus status) OVERRIDE = 0; virtual views::View* CreateDefaultView(user::LoginStatus status) OVERRIDE = 0; - virtual views::View* CreateNotificationView( - user::LoginStatus status) OVERRIDE = 0; - virtual void DestroyTrayView() OVERRIDE; virtual void DestroyDefaultView() OVERRIDE; - virtual void DestroyNotificationView() OVERRIDE; private: tray::ScreenTrayView* tray_view_; tray::ScreenStatusView* default_view_; - tray::ScreenNotificationView* notification_view_; bool is_started_; base::Closure stop_callback_; diff --git a/ash/system/chromeos/screen_security/screen_tray_item_unittest.cc b/ash/system/chromeos/screen_security/screen_tray_item_unittest.cc index d95bed9372..e51a91fa83 100644 --- a/ash/system/chromeos/screen_security/screen_tray_item_unittest.cc +++ b/ash/system/chromeos/screen_security/screen_tray_item_unittest.cc @@ -12,6 +12,7 @@ #include "base/strings/utf_string_conversions.h" #include "ui/base/events/event.h" #include "ui/gfx/point.h" +#include "ui/message_center/message_center.h" #include "ui/views/view.h" namespace ash { @@ -177,12 +178,9 @@ void TestNotificationView(ScreenTrayItemTest* test) { ScreenTrayItem* tray_item = test->tray_item(); test->StartSession(); - EXPECT_TRUE(tray_item->notification_view()->visible()); - - // Clicking on the notification view should dismiss the view - ClickViewCenter(tray_item->notification_view()); - EXPECT_FALSE(tray_item->notification_view()); - + message_center::MessageCenter* message_center = + message_center::MessageCenter::Get(); + EXPECT_TRUE(message_center->HasNotification(tray_item->GetNotificationId())); test->StopSession(); } diff --git a/ash/test/ash_test_base.cc b/ash/test/ash_test_base.cc index 85ba7ae83d..2b0b32a5f2 100644 --- a/ash/test/ash_test_base.cc +++ b/ash/test/ash_test_base.cc @@ -84,7 +84,8 @@ content::WebContents* AshTestViewsDelegate::CreateWebContents( AshTestBase::AshTestBase() : setup_called_(false), - teardown_called_(false) { + teardown_called_(false), + start_session_(true) { // Must initialize |ash_test_helper_| here because some tests rely on // AshTestBase methods before they call AshTestBase::SetUp(). ash_test_helper_.reset(new AshTestHelper(base::MessageLoopForUI::current())); @@ -109,7 +110,7 @@ void AshTestBase::SetUp() { #endif ui::InitializeInputMethodForTesting(); - ash_test_helper_->SetUp(); + ash_test_helper_->SetUp(start_session_); Shell::GetPrimaryRootWindow()->Show(); Shell::GetPrimaryRootWindow()->ShowRootWindow(); diff --git a/ash/test/ash_test_base.h b/ash/test/ash_test_base.h index c0567be5f2..5e8fdd2adc 100644 --- a/ash/test/ash_test_base.h +++ b/ash/test/ash_test_base.h @@ -110,6 +110,8 @@ class AshTestBase : public testing::Test { // or false otherwise (e.g. win8 bot). static bool SupportsHostWindowResize(); + void set_start_session(bool start_session) { start_session_ = start_session; } + void RunAllPendingInMessageLoop(); // Utility methods to emulate user logged in or not, session started or not @@ -127,6 +129,8 @@ class AshTestBase : public testing::Test { private: bool setup_called_; bool teardown_called_; + // |SetUp()| doesn't activate session if this is set to false. + bool start_session_; content::TestBrowserThreadBundle thread_bundle_; scoped_ptr<AshTestHelper> ash_test_helper_; scoped_ptr<aura::test::EventGenerator> event_generator_; @@ -141,6 +145,17 @@ class AshTestBase : public testing::Test { DISALLOW_COPY_AND_ASSIGN(AshTestBase); }; +class NoSessionAshTestBase : public AshTestBase { + public: + NoSessionAshTestBase() { + set_start_session(false); + } + virtual ~NoSessionAshTestBase() {} + + private: + DISALLOW_COPY_AND_ASSIGN(NoSessionAshTestBase); +}; + } // namespace test } // namespace ash diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc index 1d8c7d1774..45a1740953 100644 --- a/ash/test/ash_test_helper.cc +++ b/ash/test/ash_test_helper.cc @@ -39,7 +39,7 @@ AshTestHelper::AshTestHelper(base::MessageLoopForUI* message_loop) AshTestHelper::~AshTestHelper() { } -void AshTestHelper::SetUp() { +void AshTestHelper::SetUp(bool start_session) { // Disable animations during tests. zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); @@ -60,9 +60,12 @@ void AshTestHelper::SetUp() { ash::Shell::CreateInstance(test_shell_delegate_); Shell* shell = Shell::GetInstance(); - test_shell_delegate_->test_session_state_delegate()-> - SetActiveUserSessionStarted(true); - test_shell_delegate_->test_session_state_delegate()->SetHasActiveUser(true); + if (start_session) { + test_shell_delegate_->test_session_state_delegate()-> + SetActiveUserSessionStarted(true); + test_shell_delegate_->test_session_state_delegate()-> + SetHasActiveUser(true); + } test::DisplayManagerTestApi(shell->display_manager()). DisableChangeDisplayUponHostResize(); diff --git a/ash/test/ash_test_helper.h b/ash/test/ash_test_helper.h index 669ec292f1..f4d7706469 100644 --- a/ash/test/ash_test_helper.h +++ b/ash/test/ash_test_helper.h @@ -33,7 +33,9 @@ class AshTestHelper { ~AshTestHelper(); // Creates the ash::Shell and performs associated initialization. - void SetUp(); + // Set |start_session| to true if the user should log in before + // the test is run. + void SetUp(bool start_session); // Destroys the ash::Shell and performs associated cleanup. void TearDown(); diff --git a/ash/test/ash_test_helper_unittest.cc b/ash/test/ash_test_helper_unittest.cc index fdb27f9e46..0de950f43c 100644 --- a/ash/test/ash_test_helper_unittest.cc +++ b/ash/test/ash_test_helper_unittest.cc @@ -18,7 +18,7 @@ class AshTestHelperTest : public testing::Test { virtual void SetUp() OVERRIDE { testing::Test::SetUp(); ash_test_helper_.reset(new ash::test::AshTestHelper(&message_loop_)); - ash_test_helper_->SetUp(); + ash_test_helper_->SetUp(true); } virtual void TearDown() OVERRIDE { diff --git a/ash/test/test_shell_delegate.cc b/ash/test/test_shell_delegate.cc index 532876ec85..9b51e6a782 100644 --- a/ash/test/test_shell_delegate.cc +++ b/ash/test/test_shell_delegate.cc @@ -191,16 +191,6 @@ void TestShellDelegate::HandleMediaPlayPause() { void TestShellDelegate::HandleMediaPrevTrack() { } -base::string16 TestShellDelegate::GetTimeRemainingString( - base::TimeDelta delta) { - return base::string16(); -} - -base::string16 TestShellDelegate::GetTimeDurationLongString( - base::TimeDelta delta) { - return base::string16(); -} - void TestShellDelegate::SaveScreenMagnifierScale(double scale) { } diff --git a/ash/test/test_shell_delegate.h b/ash/test/test_shell_delegate.h index b8a618bcf6..dc8875b136 100644 --- a/ash/test/test_shell_delegate.h +++ b/ash/test/test_shell_delegate.h @@ -74,9 +74,6 @@ class TestShellDelegate : public ShellDelegate { virtual void HandleMediaNextTrack() OVERRIDE; virtual void HandleMediaPlayPause() OVERRIDE; virtual void HandleMediaPrevTrack() OVERRIDE; - virtual base::string16 GetTimeRemainingString(base::TimeDelta delta) OVERRIDE; - virtual base::string16 GetTimeDurationLongString( - base::TimeDelta delta) OVERRIDE; virtual void SaveScreenMagnifierScale(double scale) OVERRIDE; virtual double GetSavedScreenMagnifierScale() OVERRIDE; virtual ui::MenuModel* CreateContextMenu(aura::RootWindow* root) OVERRIDE; diff --git a/ash/wm/app_list_controller.cc b/ash/wm/app_list_controller.cc index 45a6bcf2fa..ea5e4f4ce9 100644 --- a/ash/wm/app_list_controller.cc +++ b/ash/wm/app_list_controller.cc @@ -12,6 +12,7 @@ #include "ash/shell_delegate.h" #include "ash/shell_window_ids.h" #include "ash/wm/property_util.h" +#include "base/command_line.h" #include "ui/app_list/app_list_constants.h" #include "ui/app_list/pagination_model.h" #include "ui/app_list/views/app_list_view.h" @@ -192,6 +193,13 @@ void AppListController::SetVisible(bool visible, aura::Window* window) { true /* border_accepts_events */); } SetView(view); + // By setting us as DnD recipient, the app list knows that we can + // handle items. + if (!CommandLine::ForCurrentProcess()->HasSwitch( + ash::switches::kAshDisableDragAndDropAppListToLauncher)) { + SetDragAndDropHostOfCurrentAppList( + Launcher::ForWindow(window)->GetDragAndDropHostForAppList()); + } } } @@ -203,15 +211,15 @@ aura::Window* AppListController::GetWindow() { return is_visible_ && view_ ? view_->GetWidget()->GetNativeWindow() : NULL; } +//////////////////////////////////////////////////////////////////////////////// +// AppListController, private: + void AppListController::SetDragAndDropHostOfCurrentAppList( app_list::ApplicationDragAndDropHost* drag_and_drop_host) { if (view_ && is_visible_) view_->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host); } -//////////////////////////////////////////////////////////////////////////////// -// AppListController, private: - void AppListController::SetView(app_list::AppListView* view) { DCHECK(view_ == NULL); DCHECK(is_visible_); diff --git a/ash/wm/app_list_controller.h b/ash/wm/app_list_controller.h index 8aa7e3012a..b2c7961a7f 100644 --- a/ash/wm/app_list_controller.h +++ b/ash/wm/app_list_controller.h @@ -62,12 +62,12 @@ class AppListController : public ui::EventHandler, // Returns app list window or NULL if it is not visible. aura::Window* GetWindow(); + private: // If |drag_and_drop_host| is not NULL it will be called upon drag and drop // operations outside the application list. void SetDragAndDropHostOfCurrentAppList( app_list::ApplicationDragAndDropHost* drag_and_drop_host); - private: // Sets the app list view and attempts to show it. void SetView(app_list::AppListView* view); diff --git a/ash/wm/base_layout_manager.cc b/ash/wm/base_layout_manager.cc index 10f8311f61..6842f3e3c0 100644 --- a/ash/wm/base_layout_manager.cc +++ b/ash/wm/base_layout_manager.cc @@ -107,7 +107,8 @@ void BaseLayoutManager::SetChildBounds(aura::Window* child, // BaseLayoutManager, ash::ShellObserver overrides: void BaseLayoutManager::OnDisplayWorkAreaInsetsChanged() { - AdjustWindowSizesForScreenChange(ADJUST_WINDOW_DISPLAY_INSETS_CHANGED); + AdjustAllWindowsBoundsForWorkAreaChange( + ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED); } ///////////////////////////////////////////////////////////////////////////// @@ -145,7 +146,7 @@ void BaseLayoutManager::OnWindowBoundsChanged(aura::Window* window, const gfx::Rect& old_bounds, const gfx::Rect& new_bounds) { if (root_window_ == window) - AdjustWindowSizesForScreenChange(ADJUST_WINDOW_SCREEN_SIZE_CHANGED); + AdjustAllWindowsBoundsForWorkAreaChange(ADJUST_WINDOW_DISPLAY_SIZE_CHANGED); } ////////////////////////////////////////////////////////////////////////////// @@ -192,12 +193,12 @@ void BaseLayoutManager::ShowStateChanged(aura::Window* window, } } -void BaseLayoutManager::AdjustWindowSizesForScreenChange( +void BaseLayoutManager::AdjustAllWindowsBoundsForWorkAreaChange( AdjustWindowReason reason) { // Don't do any adjustments of the insets while we are in screen locked mode. // This would happen if the launcher was auto hidden before the login screen // was shown and then gets shown when the login screen gets presented. - if (reason == ADJUST_WINDOW_DISPLAY_INSETS_CHANGED && + if (reason == ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED && Shell::GetInstance()->session_state_delegate()->IsScreenLocked()) return; @@ -209,11 +210,11 @@ void BaseLayoutManager::AdjustWindowSizesForScreenChange( for (WindowSet::const_iterator it = windows_.begin(); it != windows_.end(); ++it) { - AdjustWindowSizeForScreenChange(*it, reason); + AdjustWindowBoundsForWorkAreaChange(*it, reason); } } -void BaseLayoutManager::AdjustWindowSizeForScreenChange( +void BaseLayoutManager::AdjustWindowBoundsForWorkAreaChange( aura::Window* window, AdjustWindowReason reason) { if (wm::IsWindowMaximized(window)) { diff --git a/ash/wm/base_layout_manager.h b/ash/wm/base_layout_manager.h index 7fe25e5fe6..0fc2b36917 100644 --- a/ash/wm/base_layout_manager.h +++ b/ash/wm/base_layout_manager.h @@ -77,27 +77,29 @@ class ASH_EXPORT BaseLayoutManager protected: enum AdjustWindowReason { - ADJUST_WINDOW_SCREEN_SIZE_CHANGED, - ADJUST_WINDOW_DISPLAY_INSETS_CHANGED, - ADJUST_WINDOW_WINDOW_ADDED + ADJUST_WINDOW_DISPLAY_SIZE_CHANGED, + ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED, }; // Invoked from OnWindowPropertyChanged() if |kShowStateKey| changes. virtual void ShowStateChanged(aura::Window* window, ui::WindowShowState last_show_state); - // Adjusts the window sizes when the screen changes its size or its - // work area insets. If this is called for a screen size change (i.e. |reason| - // is ADJUST_WINDOW_SCREEN_SIZE_CHANGED), the non-maximized/non-fullscreen + // Adjusts the window's bounds when the display area changes for given + // window. This happens when the display size, work area insets or + // the display on which the window exists has changed. + // If this is called for a display size change (i.e. |reason| + // is ADJUST_WINDOW_DISPLAY_SIZE_CHANGED), the non-maximized/non-fullscreen // windows are readjusted to make sure the window is completely within the // display region. Otherwise, it makes sure at least some parts of the window // is on display. - virtual void AdjustWindowSizesForScreenChange(AdjustWindowReason reason); + virtual void AdjustAllWindowsBoundsForWorkAreaChange( + AdjustWindowReason reason); // Adjusts the sizes of the specific window in respond to a screen change or // display-area size change. - virtual void AdjustWindowSizeForScreenChange(aura::Window* window, - AdjustWindowReason reason); + virtual void AdjustWindowBoundsForWorkAreaChange(aura::Window* window, + AdjustWindowReason reason); aura::RootWindow* root_window() { return root_window_; } diff --git a/ash/wm/dock/docked_window_layout_manager.cc b/ash/wm/dock/docked_window_layout_manager.cc index d9d1c07897..d73a0ccac7 100644 --- a/ash/wm/dock/docked_window_layout_manager.cc +++ b/ash/wm/dock/docked_window_layout_manager.cc @@ -15,6 +15,7 @@ #include "ash/wm/window_properties.h" #include "ash/wm/window_util.h" #include "base/auto_reset.h" +#include "third_party/skia/include/core/SkColor.h" #include "ui/aura/client/activation_client.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/focus_manager.h" @@ -33,6 +34,39 @@ const int kWindowIdealSpacing = 4; namespace { +const SkColor kDockBackgroundColor = SkColorSetARGB(0xff, 0x10, 0x10, 0x10); +const float kDockBackgroundOpacity = 0.5f; + +class DockedBackgroundWidget : public views::Widget { + public: + explicit DockedBackgroundWidget(aura::Window* container) { + InitWidget(container); + } + + private: + void InitWidget(aura::Window* parent) { + views::Widget::InitParams params; + params.type = views::Widget::InitParams::TYPE_POPUP; + params.opacity = views::Widget::InitParams::OPAQUE_WINDOW; + params.can_activate = false; + params.keep_on_top = false; + params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; + params.parent = parent; + params.accept_events = false; + set_focus_on_creation(false); + Init(params); + DCHECK_EQ(GetNativeView()->GetRootWindow(), parent->GetRootWindow()); + views::View* content_view = new views::View; + content_view->set_background( + views::Background::CreateSolidBackground(kDockBackgroundColor)); + SetContentsView(content_view); + GetNativeWindow()->layer()->SetOpacity(kDockBackgroundOpacity); + Hide(); + } + + DISALLOW_COPY_AND_ASSIGN(DockedBackgroundWidget); +}; + DockedWindowLayoutManager* GetDockLayoutManager(aura::Window* window, const gfx::Point& location) { gfx::Rect near_location(location, gfx::Size()); @@ -69,7 +103,8 @@ DockedWindowLayoutManager::DockedWindowLayoutManager( shelf_hidden_(false), docked_width_(0), alignment_(DOCKED_ALIGNMENT_NONE), - last_active_window_(NULL) { + last_active_window_(NULL), + background_widget_(new DockedBackgroundWidget(dock_container_)) { DCHECK(dock_container); aura::client::GetActivationClient(Shell::GetPrimaryRootWindow())-> AddObserver(this); @@ -546,6 +581,17 @@ void DockedWindowLayoutManager::UpdateDockBounds() { DockedWindowLayoutManagerObserver, observer_list_, OnDockBoundsChanging(bounds)); + + // Show or hide background for docked area. + gfx::Rect background_bounds(docked_bounds_); + const gfx::Rect work_area = + Shell::GetScreen()->GetDisplayNearestWindow(dock_container_).work_area(); + background_bounds.set_height(work_area.height()); + background_widget_->SetBounds(background_bounds); + if (docked_width_ > 0) + background_widget_->Show(); + else + background_widget_->Hide(); } void DockedWindowLayoutManager::UpdateStacking(aura::Window* active_window) { @@ -571,13 +617,15 @@ void DockedWindowLayoutManager::UpdateStacking(aura::Window* active_window) { for (aura::Window::Windows::const_iterator it = dock_container_->children().begin(); it != dock_container_->children().end(); ++it) { + if (!IsUsedByLayout(*it)) + continue; gfx::Rect bounds = (*it)->bounds(); window_ordering.insert(std::make_pair(bounds.y() + bounds.height() / 2, *it)); } int active_center_y = active_window->bounds().CenterPoint().y(); - aura::Window* previous_window = NULL; + aura::Window* previous_window = background_widget_->GetNativeWindow(); for (std::map<int, aura::Window*>::const_iterator it = window_ordering.begin(); it != window_ordering.end() && it->first < active_center_y; ++it) { diff --git a/ash/wm/dock/docked_window_layout_manager.h b/ash/wm/dock/docked_window_layout_manager.h index 28c81fccd7..aa02b34342 100644 --- a/ash/wm/dock/docked_window_layout_manager.h +++ b/ash/wm/dock/docked_window_layout_manager.h @@ -13,6 +13,7 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/gtest_prod_util.h" +#include "base/memory/scoped_ptr.h" #include "base/observer_list.h" #include "ui/aura/client/activation_change_observer.h" #include "ui/aura/layout_manager.h" @@ -28,6 +29,10 @@ namespace gfx { class Point; } +namespace views { +class Widget; +} + namespace ash { class Launcher; @@ -182,6 +187,9 @@ class ASH_EXPORT DockedWindowLayoutManager // are currently focused. aura::Window* last_active_window_; + // Widget used to paint a background for the docked area. + scoped_ptr<views::Widget> background_widget_; + // Observers of dock bounds changes. ObserverList<DockedWindowLayoutManagerObserver> observer_list_; diff --git a/ash/wm/property_util.h b/ash/wm/property_util.h index adb983df6d..32ae278ca9 100644 --- a/ash/wm/property_util.h +++ b/ash/wm/property_util.h @@ -24,7 +24,7 @@ class RootWindowController; // Sets the restore bounds property on |window| in the virtual screen // coordinates. Deletes existing bounds value if exists. ASH_EXPORT void SetRestoreBoundsInScreen(aura::Window* window, - const gfx::Rect& screen_bounds); + const gfx::Rect& screen_bounds); // Same as |SetRestoreBoundsInScreen| except that the bounds is in the // parent's coordinates. ASH_EXPORT void SetRestoreBoundsInParent(aura::Window* window, diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc index f11b3bc65d..67dcd95c4c 100644 --- a/ash/wm/window_util.cc +++ b/ash/wm/window_util.cc @@ -173,21 +173,19 @@ void AdjustBoundsToEnsureWindowVisibility(const gfx::Rect& work_area, gfx::Rect* bounds) { bounds->set_width(std::min(bounds->width(), work_area.width())); bounds->set_height(std::min(bounds->height(), work_area.height())); - if (!work_area.Intersects(*bounds)) { - int y_offset = 0; - if (work_area.bottom() < bounds->y()) { - y_offset = work_area.bottom() - bounds->y() - min_height; - } else if (bounds->bottom() < work_area.y()) { - y_offset = work_area.y() - bounds->bottom() + min_height; - } - - int x_offset = 0; - if (work_area.right() < bounds->x()) { - x_offset = work_area.right() - bounds->x() - min_width; - } else if (bounds->right() < work_area.x()) { - x_offset = work_area.x() - bounds->right() + min_width; - } - bounds->Offset(x_offset, y_offset); + + min_width = std::min(min_width, work_area.width()); + min_height = std::min(min_height, work_area.height()); + + if (bounds->x() + min_width > work_area.right()) { + bounds->set_x(work_area.right() - min_width); + } else if (bounds->right() - min_width < 0) { + bounds->set_x(min_width - bounds->width()); + } + if (bounds->y() + min_height > work_area.bottom()) { + bounds->set_y(work_area.bottom() - min_height); + } else if (bounds->bottom() - min_height < 0) { + bounds->set_y(min_height - bounds->height()); } } diff --git a/ash/wm/workspace/workspace_event_handler_unittest.cc b/ash/wm/workspace/workspace_event_handler_unittest.cc index f97038504d..e592ad5a94 100644 --- a/ash/wm/workspace/workspace_event_handler_unittest.cc +++ b/ash/wm/workspace/workspace_event_handler_unittest.cc @@ -248,20 +248,21 @@ TEST_F(WorkspaceEventHandlerTest, TEST_F(WorkspaceEventHandlerTest, DoubleClickCaptionTogglesMaximize) { aura::test::TestWindowDelegate wd; - scoped_ptr<aura::Window> window(CreateTestWindow(&wd, gfx::Rect(1, 2, 3, 4))); + scoped_ptr<aura::Window> window( + CreateTestWindow(&wd, gfx::Rect(1, 2, 30, 40))); window->SetProperty(aura::client::kCanMaximizeKey, true); wd.set_window_component(HTCAPTION); EXPECT_FALSE(wm::IsWindowMaximized(window.get())); aura::RootWindow* root = Shell::GetPrimaryRootWindow(); aura::test::EventGenerator generator(root, window.get()); generator.DoubleClickLeftButton(); - EXPECT_NE("1,2 3x4", window->bounds().ToString()); + EXPECT_NE("1,2 30x40", window->bounds().ToString()); EXPECT_TRUE(wm::IsWindowMaximized(window.get())); generator.DoubleClickLeftButton(); EXPECT_FALSE(wm::IsWindowMaximized(window.get())); - EXPECT_EQ("1,2 3x4", window->bounds().ToString()); + EXPECT_EQ("1,2 30x40", window->bounds().ToString()); // Double-clicking the middle button shouldn't toggle the maximized state. WindowPropertyObserver observer(window.get()); @@ -275,7 +276,7 @@ TEST_F(WorkspaceEventHandlerTest, DoubleClickCaptionTogglesMaximize) { root->AsRootWindowHostDelegate()->OnHostMouseEvent(&release); EXPECT_FALSE(wm::IsWindowMaximized(window.get())); - EXPECT_EQ("1,2 3x4", window->bounds().ToString()); + EXPECT_EQ("1,2 30x40", window->bounds().ToString()); EXPECT_FALSE(observer.DidPropertyChange(aura::client::kShowStateKey)); } diff --git a/ash/wm/workspace/workspace_layout_manager.cc b/ash/wm/workspace/workspace_layout_manager.cc index 21aa08c604..2fd56af26c 100644 --- a/ash/wm/workspace/workspace_layout_manager.cc +++ b/ash/wm/workspace/workspace_layout_manager.cc @@ -32,9 +32,9 @@ namespace internal { namespace { -// This specifies how much percent (2/3=66%) of a window must be visible when -// the window is added to the workspace. -const float kMinimumPercentOnScreenArea = 0.66f; +// This specifies how much percent 30% of a window rect (width / height) +// must be visible when the window is added to the workspace. +const float kMinimumPercentOnScreenArea = 0.3f; bool IsMaximizedState(ui::WindowShowState state) { return state == ui::SHOW_STATE_MAXIMIZED || @@ -59,8 +59,14 @@ void WorkspaceLayoutManager::SetShelf(internal::ShelfLayoutManager* shelf) { } void WorkspaceLayoutManager::OnWindowAddedToLayout(Window* child) { - // Adjust window bounds in case that the new child is out of the workspace. - AdjustWindowSizeForScreenChange(child, ADJUST_WINDOW_WINDOW_ADDED); + // Adjust window bounds in case that the new child is given the bounds that + // is out of the workspace. Exclude the case where bounds is empty + // (this happens when a views::Widget is created), or the window + // is added with the bounds because a user explicitly moved to + // this position (drag and drop for example). + if (!child->bounds().IsEmpty() && + !wm::HasUserChangedWindowPositionOrSize(child)) + AdjustWindowBoundsWhenAdded(child); BaseLayoutManager::OnWindowAddedToLayout(child); UpdateDesktopVisibility(); RearrangeVisibleWindowOnShow(child); @@ -110,8 +116,10 @@ void WorkspaceLayoutManager::SetChildBounds( void WorkspaceLayoutManager::OnDisplayWorkAreaInsetsChanged() { const gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent( window_->parent())); - if (work_area != work_area_) - AdjustWindowSizesForScreenChange(ADJUST_WINDOW_DISPLAY_INSETS_CHANGED); + if (work_area != work_area_) { + AdjustAllWindowsBoundsForWorkAreaChange( + ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED); + } } void WorkspaceLayoutManager::OnWindowPropertyChanged(Window* window, @@ -170,13 +178,13 @@ void WorkspaceLayoutManager::ShowStateChanged( UpdateDesktopVisibility(); } -void WorkspaceLayoutManager::AdjustWindowSizesForScreenChange( +void WorkspaceLayoutManager::AdjustAllWindowsBoundsForWorkAreaChange( AdjustWindowReason reason) { work_area_ = ScreenAsh::GetDisplayWorkAreaBoundsInParent(window_->parent()); - BaseLayoutManager::AdjustWindowSizesForScreenChange(reason); + BaseLayoutManager::AdjustAllWindowsBoundsForWorkAreaChange(reason); } -void WorkspaceLayoutManager::AdjustWindowSizeForScreenChange( +void WorkspaceLayoutManager::AdjustWindowBoundsForWorkAreaChange( Window* window, AdjustWindowReason reason) { if (!GetTrackedByWorkspace(window)) @@ -190,7 +198,7 @@ void WorkspaceLayoutManager::AdjustWindowSizeForScreenChange( // cross fade. I think this is better, but should reconsider if someone // raises voice for this. if (wm::IsWindowMaximized(window) && - reason == ADJUST_WINDOW_DISPLAY_INSETS_CHANGED) { + reason == ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED) { CrossFadeToBounds(window, ScreenAsh::GetMaximizedWindowBoundsInParent( window->parent()->parent())); return; @@ -200,22 +208,38 @@ void WorkspaceLayoutManager::AdjustWindowSizeForScreenChange( return; gfx::Rect bounds = window->bounds(); - if (reason == ADJUST_WINDOW_SCREEN_SIZE_CHANGED) { - // The work area may be smaller than the full screen. Put as much of the - // window as possible within the display area. - bounds.AdjustToFit(work_area_); - } else if (reason == ADJUST_WINDOW_DISPLAY_INSETS_CHANGED) { - ash::wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area_, &bounds); - } else if (reason == ADJUST_WINDOW_WINDOW_ADDED) { - int min_width = bounds.width() * kMinimumPercentOnScreenArea; - int min_height = bounds.height() * kMinimumPercentOnScreenArea; - ash::wm::AdjustBoundsToEnsureWindowVisibility( - work_area_, min_width, min_height, &bounds); + switch (reason) { + case ADJUST_WINDOW_DISPLAY_SIZE_CHANGED: + // The work area may be smaller than the full screen. Put as much of the + // window as possible within the display area. + bounds.AdjustToFit(work_area_); + break; + case ADJUST_WINDOW_WORK_AREA_INSETS_CHANGED: + ash::wm::AdjustBoundsToEnsureMinimumWindowVisibility(work_area_, &bounds); + break; } if (window->bounds() != bounds) window->SetBounds(bounds); } +void WorkspaceLayoutManager::AdjustWindowBoundsWhenAdded( + Window* window) { + if (!GetTrackedByWorkspace(window)) + return; + + if (SetMaximizedOrFullscreenBounds(window)) + return; + + gfx::Rect bounds = window->bounds(); + int min_width = bounds.width() * kMinimumPercentOnScreenArea; + int min_height = bounds.height() * kMinimumPercentOnScreenArea; + ash::wm::AdjustBoundsToEnsureWindowVisibility( + work_area_, min_width, min_height, &bounds); + + if (window->bounds() != bounds) + window->SetBounds(bounds); +} + void WorkspaceLayoutManager::UpdateDesktopVisibility() { if (shelf_) shelf_->UpdateVisibilityState(); @@ -229,10 +253,27 @@ void WorkspaceLayoutManager::UpdateBoundsFromShowState(Window* window) { case ui::SHOW_STATE_DEFAULT: case ui::SHOW_STATE_NORMAL: { const gfx::Rect* restore = GetRestoreBoundsInScreen(window); + // Make sure that the part of the window is always visible + // when restored. + gfx::Rect bounds_in_parent; if (restore) { - gfx::Rect bounds_in_parent = + bounds_in_parent = ScreenAsh::ConvertRectFromScreen(window->parent()->parent(), *restore); + + ash::wm::AdjustBoundsToEnsureMinimumWindowVisibility( + work_area_, &bounds_in_parent); + } else { + // Minimized windows have no restore bounds. + // Use the current bounds instead. + bounds_in_parent = window->bounds(); + ash::wm::AdjustBoundsToEnsureMinimumWindowVisibility( + work_area_, &bounds_in_parent); + // Don't start animation if the bounds didn't change. + if (bounds_in_parent == window->bounds()) + bounds_in_parent.SetRect(0, 0, 0, 0); + } + if (!bounds_in_parent.IsEmpty()) { CrossFadeToBounds( window, BaseLayoutManager::BoundsWithScreenEdgeVisible( diff --git a/ash/wm/workspace/workspace_layout_manager.h b/ash/wm/workspace/workspace_layout_manager.h index a599d87f60..4476ddc99c 100644 --- a/ash/wm/workspace/workspace_layout_manager.h +++ b/ash/wm/workspace/workspace_layout_manager.h @@ -60,12 +60,14 @@ class ASH_EXPORT WorkspaceLayoutManager : public BaseLayoutManager { // Overridden from BaseLayoutManager: virtual void ShowStateChanged(aura::Window* window, ui::WindowShowState last_show_state) OVERRIDE; - virtual void AdjustWindowSizesForScreenChange( + virtual void AdjustAllWindowsBoundsForWorkAreaChange( AdjustWindowReason reason) OVERRIDE; - virtual void AdjustWindowSizeForScreenChange( + virtual void AdjustWindowBoundsForWorkAreaChange( aura::Window* window, AdjustWindowReason reason) OVERRIDE; + void AdjustWindowBoundsWhenAdded(aura::Window* window); + void UpdateDesktopVisibility(); // Updates the bounds of the window from a show state change. diff --git a/ash/wm/workspace/workspace_layout_manager_unittest.cc b/ash/wm/workspace/workspace_layout_manager_unittest.cc index 30cdf6b098..3e3a1c7d65 100644 --- a/ash/wm/workspace/workspace_layout_manager_unittest.cc +++ b/ash/wm/workspace/workspace_layout_manager_unittest.cc @@ -62,6 +62,42 @@ TEST_F(WorkspaceLayoutManagerTest, RestoreFromMinimizeKeepsRestore) { Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds())); } +TEST_F(WorkspaceLayoutManagerTest, KeepRestoredWindowInDisplay) { + if (!SupportsHostWindowResize()) + return; + scoped_ptr<aura::Window> window( + CreateTestWindowInShellWithBounds(gfx::Rect(1, 2, 30, 40))); + // Maximized -> Normal transition. + wm::MaximizeWindow(window.get()); + SetRestoreBoundsInScreen(window.get(), gfx::Rect(-100, -100, 30, 40)); + wm::RestoreWindow(window.get()); + EXPECT_TRUE( + Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds())); + EXPECT_EQ("-20,-30 30x40", window->bounds().ToString()); + + // Minimized -> Normal transition. + window->SetBounds(gfx::Rect(-100, -100, 30, 40)); + wm::MinimizeWindow(window.get()); + EXPECT_FALSE( + Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds())); + EXPECT_EQ("-100,-100 30x40", window->bounds().ToString()); + window->Show(); + EXPECT_TRUE( + Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds())); + EXPECT_EQ("-20,-30 30x40", window->bounds().ToString()); + + // Fullscreen -> Normal transition. + window->SetBounds(gfx::Rect(0, 0, 30, 40)); // reset bounds. + ASSERT_EQ("0,0 30x40", window->bounds().ToString()); + window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); + EXPECT_EQ(window->bounds(), window->GetRootWindow()->bounds()); + SetRestoreBoundsInScreen(window.get(), gfx::Rect(-100, -100, 30, 40)); + wm::RestoreWindow(window.get()); + EXPECT_TRUE( + Shell::GetPrimaryRootWindow()->bounds().Intersects(window->bounds())); + EXPECT_EQ("-20,-30 30x40", window->bounds().ToString()); +} + // WindowObserver implementation used by DontClobberRestoreBoundsWindowObserver. // This code mirrors what BrowserFrameAura does. In particular when this code // sees the window was maximized it changes the bounds of a secondary @@ -110,7 +146,7 @@ TEST_F(WorkspaceLayoutManagerTest, DontClobberRestoreBounds) { window->AddObserver(&window_observer); SetDefaultParentByPrimaryRootWindow(window.get()); window->Show(); - ash::wm::ActivateWindow(window.get()); + wm::ActivateWindow(window.get()); scoped_ptr<aura::Window> window2( CreateTestWindowInShellWithBounds(gfx::Rect(12, 20, 30, 40))); @@ -128,12 +164,12 @@ TEST_F(WorkspaceLayoutManagerTest, ChildBoundsResetOnMaximize) { scoped_ptr<aura::Window> window( CreateTestWindowInShellWithBounds(gfx::Rect(10, 20, 30, 40))); window->Show(); - ash::wm::ActivateWindow(window.get()); + wm::ActivateWindow(window.get()); scoped_ptr<aura::Window> child_window( aura::test::CreateTestWindowWithBounds(gfx::Rect(5, 6, 7, 8), window.get())); child_window->Show(); - ash::wm::MaximizeWindow(window.get()); + wm::MaximizeWindow(window.get()); EXPECT_EQ("5,6 7x8", child_window->bounds().ToString()); } @@ -146,7 +182,7 @@ TEST_F(WorkspaceLayoutManagerTest, WindowShouldBeOnScreenWhenAdded) { // If the window is out of the workspace, it would be moved on screen. gfx::Rect root_window_bounds = - ash::Shell::GetInstance()->GetPrimaryRootWindow()->bounds(); + Shell::GetInstance()->GetPrimaryRootWindow()->bounds(); window_bounds.Offset(root_window_bounds.width(), root_window_bounds.height()); ASSERT_FALSE(window_bounds.Intersects(root_window_bounds)); scoped_ptr<aura::Window> out_window( @@ -154,9 +190,45 @@ TEST_F(WorkspaceLayoutManagerTest, WindowShouldBeOnScreenWhenAdded) { EXPECT_EQ(window_bounds.size(), out_window->bounds().size()); gfx::Rect bounds = out_window->bounds(); bounds.Intersect(root_window_bounds); - // 2/3 of the window must be visible. - EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.6); - EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.6); + + // 30% of the window edge must be visible. + EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29); + EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29); + + // Make sure we always make more than 1/3 of the window edge visible even + // if the initial bounds intersects with display. + window_bounds.SetRect(-150, -150, 200, 200); + bounds = window_bounds; + bounds.Intersect(root_window_bounds); + + // Make sure that the initial bounds' visible area is less than 26% + // so that the auto adjustment logic kicks in. + ASSERT_LT(bounds.width(), out_window->bounds().width() * 0.26); + ASSERT_LT(bounds.height(), out_window->bounds().height() * 0.26); + ASSERT_TRUE(window_bounds.Intersects(root_window_bounds)); + + scoped_ptr<aura::Window> partially_out_window( + CreateTestWindowInShellWithBounds(window_bounds)); + EXPECT_EQ(window_bounds.size(), partially_out_window->bounds().size()); + bounds = partially_out_window->bounds(); + bounds.Intersect(root_window_bounds); + EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29); + EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29); + + // Make sure the window whose 30% width/height is bigger than display + // will be placed correctly. + window_bounds.SetRect(-1900, -1900, 3000, 3000); + scoped_ptr<aura::Window> window_bigger_than_display( + CreateTestWindowInShellWithBounds(window_bounds)); + EXPECT_GE(root_window_bounds.width(), + window_bigger_than_display->bounds().width()); + EXPECT_GE(root_window_bounds.height(), + window_bigger_than_display->bounds().height()); + + bounds = window_bigger_than_display->bounds(); + bounds.Intersect(root_window_bounds); + EXPECT_GT(bounds.width(), out_window->bounds().width() * 0.29); + EXPECT_GT(bounds.height(), out_window->bounds().height() * 0.29); } // Verifies the size of a window is enforced to be smaller than the work area. |