diff options
Diffstat (limited to 'ash/wm')
-rw-r--r-- | ash/wm/property_util.cc | 4 | ||||
-rw-r--r-- | ash/wm/property_util.h | 4 | ||||
-rw-r--r-- | ash/wm/window_properties.cc | 2 | ||||
-rw-r--r-- | ash/wm/window_properties.h | 10 | ||||
-rw-r--r-- | ash/wm/window_util.cc | 29 | ||||
-rw-r--r-- | ash/wm/window_util.h | 25 | ||||
-rw-r--r-- | ash/wm/workspace/auto_window_management.cc | 178 | ||||
-rw-r--r-- | ash/wm/workspace/auto_window_management.h | 20 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_layout_manager2_unittest.cc | 7 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_manager2.cc | 17 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_manager2_unittest.cc | 285 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_window_resizer.cc | 1 |
12 files changed, 559 insertions, 23 deletions
diff --git a/ash/wm/property_util.cc b/ash/wm/property_util.cc index d52b196..6352797 100644 --- a/ash/wm/property_util.cc +++ b/ash/wm/property_util.cc @@ -48,7 +48,7 @@ void SetTrackedByWorkspace(aura::Window* window, bool value) { window->SetProperty(internal::kWindowTrackedByWorkspaceKey, value); } -bool GetTrackedByWorkspace(aura::Window* window) { +bool GetTrackedByWorkspace(const aura::Window* window) { return window->GetProperty(internal::kWindowTrackedByWorkspaceKey); } @@ -56,7 +56,7 @@ void SetIgnoredByShelf(aura::Window* window, bool value) { window->SetProperty(internal::kIgnoredByShelfKey, value); } -bool GetIgnoredByShelf(aura::Window* window) { +bool GetIgnoredByShelf(const aura::Window* window) { return window->GetProperty(internal::kIgnoredByShelfKey); } diff --git a/ash/wm/property_util.h b/ash/wm/property_util.h index dde0335..48f6e53 100644 --- a/ash/wm/property_util.h +++ b/ash/wm/property_util.h @@ -50,14 +50,14 @@ enum WindowPersistsAcrossAllWorkspacesType { // Sets whether |window| is ignored when determining whether the shelf should // be darkened when overlapped. ASH_EXPORT void SetIgnoredByShelf(aura::Window* window, bool value); -ASH_EXPORT bool GetIgnoredByShelf(aura::Window* window); +ASH_EXPORT bool GetIgnoredByShelf(const aura::Window* window); // Sets whether the specified window is tracked by workspace code. Default is // true. If set to false the workspace does not switch the current workspace, // nor does it attempt to impose constraints on the bounds of the window. This // is intended for tab dragging. ASH_EXPORT void SetTrackedByWorkspace(aura::Window* window, bool value); -ASH_EXPORT bool GetTrackedByWorkspace(aura::Window* window); +ASH_EXPORT bool GetTrackedByWorkspace(const aura::Window* window); // Makes |window| persist across all workspaces. The default is controlled // by SetDefaultPersistsAcrossAllWorkspaces(). diff --git a/ash/wm/window_properties.cc b/ash/wm/window_properties.cc index 6aad28a..560d14f 100644 --- a/ash/wm/window_properties.cc +++ b/ash/wm/window_properties.cc @@ -40,9 +40,11 @@ DEFINE_OWNED_WINDOW_PROPERTY_KEY(ui_controls::UIControlsAura, kUIControlsKey, NULL); DEFINE_WINDOW_PROPERTY_KEY(bool, kUsesScreenCoordinatesKey, false); +DEFINE_WINDOW_PROPERTY_KEY(bool, kUserChangedWindowPositionOrSizeKey, false); DEFINE_WINDOW_PROPERTY_KEY(ash::WindowPersistsAcrossAllWorkspacesType, kWindowPersistsAcrossAllWorkspacesKey, WINDOW_PERSISTS_ACROSS_ALL_WORKSPACES_VALUE_DEFAULT); +DEFINE_WINDOW_PROPERTY_KEY(bool, kWindowPositionManagedKey, false); DEFINE_WINDOW_PROPERTY_KEY(bool, kWindowTrackedByWorkspaceKey, true); } // namespace internal diff --git a/ash/wm/window_properties.h b/ash/wm/window_properties.h index 8677359..ae5a9c9 100644 --- a/ash/wm/window_properties.h +++ b/ash/wm/window_properties.h @@ -67,12 +67,22 @@ ASH_EXPORT extern const aura::WindowProperty<bool>* const extern const aura::WindowProperty<ui_controls::UIControlsAura*>* const kUIControlsKey; +// A property key to remember if a windows position or size was changed by a +// user. +ASH_EXPORT extern const aura::WindowProperty<bool>* const + kUserChangedWindowPositionOrSizeKey; + // Property to tell if the container uses the screen coordinates. extern const aura::WindowProperty<bool>* const kUsesScreenCoordinatesKey; extern const aura::WindowProperty<WindowPersistsAcrossAllWorkspacesType>* const kWindowPersistsAcrossAllWorkspacesKey; +// A property key to remember if a windows position can be managed by the +// workspace manager or not. +ASH_EXPORT extern const aura::WindowProperty<bool>* const + kWindowPositionManagedKey; + // True if the window is controlled by the workspace manager. extern const aura::WindowProperty<bool>* const kWindowTrackedByWorkspaceKey; diff --git a/ash/wm/window_util.cc b/ash/wm/window_util.cc index b3a9b5d..97e2761 100644 --- a/ash/wm/window_util.cc +++ b/ash/wm/window_util.cc @@ -6,6 +6,7 @@ #include <vector> +#include "ash/ash_constants.h" #include "ash/shell.h" #include "ash/wm/activation_controller.h" #include "ash/wm/window_properties.h" @@ -73,11 +74,11 @@ bool CanActivateWindow(aura::Window* window) { return client && client->CanActivateWindow(window); } -bool CanMaximizeWindow(aura::Window* window) { +bool CanMaximizeWindow(const aura::Window* window) { return window->GetProperty(aura::client::kCanMaximizeKey); } -bool IsWindowNormal(aura::Window* window) { +bool IsWindowNormal(const aura::Window* window) { return IsWindowStateNormal(window->GetProperty(aura::client::kShowStateKey)); } @@ -85,17 +86,17 @@ bool IsWindowStateNormal(ui::WindowShowState state) { return state == ui::SHOW_STATE_NORMAL || state == ui::SHOW_STATE_DEFAULT; } -bool IsWindowMaximized(aura::Window* window) { +bool IsWindowMaximized(const aura::Window* window) { return window->GetProperty(aura::client::kShowStateKey) == ui::SHOW_STATE_MAXIMIZED; } -bool IsWindowMinimized(aura::Window* window) { +bool IsWindowMinimized(const aura::Window* window) { return window->GetProperty(aura::client::kShowStateKey) == ui::SHOW_STATE_MINIMIZED; } -bool IsWindowFullscreen(aura::Window* window) { +bool IsWindowFullscreen(const aura::Window* window) { return window->GetProperty(aura::client::kShowStateKey) == ui::SHOW_STATE_FULLSCREEN; } @@ -153,5 +154,23 @@ void DeepDeleteLayers(ui::Layer* layer) { delete layer; } +bool IsWindowPositionManaged(const aura::Window* window) { + return window->GetProperty(ash::internal::kWindowPositionManagedKey); +} + +void SetWindowPositionManaged(aura::Window* window, bool managed) { + window->SetProperty(ash::internal::kWindowPositionManagedKey, managed); +} + +bool HasUserChangedWindowPositionOrSize(const aura::Window* window) { + return window->GetProperty( + ash::internal::kUserChangedWindowPositionOrSizeKey); +} + +void SetUserHasChangedWindowPositionOrSize(aura::Window* window, bool changed) { + window->SetProperty(ash::internal::kUserChangedWindowPositionOrSizeKey, + changed); +} + } // namespace wm } // namespace ash diff --git a/ash/wm/window_util.h b/ash/wm/window_util.h index 081a40e..7a9e3f0 100644 --- a/ash/wm/window_util.h +++ b/ash/wm/window_util.h @@ -39,22 +39,22 @@ ASH_EXPORT aura::Window* GetActivatableWindow(aura::Window* window); ASH_EXPORT bool IsActiveWindowFullscreen(); // Returns true if |window| can be maximized. -ASH_EXPORT bool CanMaximizeWindow(aura::Window* window); +ASH_EXPORT bool CanMaximizeWindow(const aura::Window* window); // Returns true if |window| is normal or default. -ASH_EXPORT bool IsWindowNormal(aura::Window* window); +ASH_EXPORT bool IsWindowNormal(const aura::Window* window); // Returns true if |state| is normal or default. -ASH_EXPORT bool IsWindowStateNormal(ui::WindowShowState state); +ASH_EXPORT bool IsWindowStateNormal(const ui::WindowShowState state); // Returns true if |window| is in the maximized state. -ASH_EXPORT bool IsWindowMaximized(aura::Window* window); +ASH_EXPORT bool IsWindowMaximized(const aura::Window* window); // Returns true if |window| is minimized. -ASH_EXPORT bool IsWindowMinimized(aura::Window* window); +ASH_EXPORT bool IsWindowMinimized(const aura::Window* window); // Returns true if |window| is in the fullscreen state. -ASH_EXPORT bool IsWindowFullscreen(aura::Window* window); +ASH_EXPORT bool IsWindowFullscreen(const aura::Window* window); // Maximizes |window|, which must not be NULL. ASH_EXPORT void MaximizeWindow(aura::Window* window); @@ -86,6 +86,19 @@ ASH_EXPORT ui::Layer* RecreateWindowLayers(aura::Window* window, // Deletes |layer| and all its child layers. ASH_EXPORT void DeepDeleteLayers(ui::Layer* layer); +// Returns true if |window|'s position can automatically be managed. +ASH_EXPORT bool IsWindowPositionManaged(const aura::Window* window); + +// Change the |window|'s position manageability to |managed|. +ASH_EXPORT void SetWindowPositionManaged(aura::Window* window, bool managed); + +// Returns true if the user has changed the |window|'s position or size. +ASH_EXPORT bool HasUserChangedWindowPositionOrSize(const aura::Window* window); + +// Marks a |window|'s coordinates to be changed by a user. +ASH_EXPORT void SetUserHasChangedWindowPositionOrSize(aura::Window* window, + bool changed); + } // namespace wm } // namespace ash diff --git a/ash/wm/workspace/auto_window_management.cc b/ash/wm/workspace/auto_window_management.cc new file mode 100644 index 0000000..ea2f89f --- /dev/null +++ b/ash/wm/workspace/auto_window_management.cc @@ -0,0 +1,178 @@ +// 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/wm/workspace/auto_window_management.h" + +#include "ash/ash_switches.h" +#include "ash/shell.h" +#include "ash/wm/property_util.h" +#include "ash/wm/window_animations.h" +#include "ash/wm/window_util.h" +#include "base/command_line.h" +#include "ui/aura/window.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/compositor/layer_animator.h" +#include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/gfx/screen.h" + +namespace ash { +namespace internal { + +namespace { + +// The time in milliseconds which should be used to visually move a window +// through an automatic "intelligent" window management option. +const int kWindowAutoMoveDurationMS = 125; + +// Check if any management should be performed (with a given |window|). +bool UseAutoWindowMagerForWindow(const aura::Window* window) { + return !CommandLine::ForCurrentProcess()->HasSwitch( + switches::kAshDisableAutoWindowPlacement) && + GetTrackedByWorkspace(window) && + wm::IsWindowPositionManaged(window); +} + +// Check if a given |window| can be managed. This includes that it's state is +// not minimized/maximized/the user has changed it's size by hand already. +// It furthermore checks for the WindowIsManaged status. +bool WindowPositionCanBeManaged(const aura::Window* window) { + return (wm::IsWindowPositionManaged(window) && + !wm::IsWindowMinimized(window) && + !wm::IsWindowMaximized(window) && + !wm::HasUserChangedWindowPositionOrSize(window)); +} + +// Given a |window|, return the only |other_window| which has an impact on +// the automated windows location management. If there is more then one window, +// false is returned, but the |other_window| will be set to the first one +// found. +// If the return value is true a single window was found. +bool GetOtherVisibleAndManageableWindow(const aura::Window* window, + aura::Window** other_window) { + *other_window = NULL; + const aura::Window::Windows& windows = window->parent()->children(); + // Find a single open managed window. + for (size_t i = 0; i < windows.size(); i++) { + aura::Window* iterated_window = windows[i]; + if (window != iterated_window && + iterated_window->type() == aura::client::WINDOW_TYPE_NORMAL && + iterated_window->TargetVisibility() && + wm::IsWindowPositionManaged(iterated_window)) { + // Bail if we find a second usable window. + if (*other_window) + return false; + *other_window = iterated_window; + } + } + return *other_window != NULL; +} + +// Get the work area for a given |window|. +gfx::Rect GetWorkAreaForWindow(const aura::Window* window) { + gfx::Rect work_area = gfx::Rect(window->parent()->bounds().size()); + work_area.Inset(Shell::GetScreen()->GetDisplayMatching( + work_area).GetWorkAreaInsets()); + return work_area; +} + +// Move the given |bounds| on the available |parent_width| to the +// direction. If |move_right| is true, the rectangle gets moved to the right +// corner, otherwise to the left one. +bool MoveRectToOneSide(int parent_width, bool move_right, gfx::Rect* bounds) { + if (move_right) { + if (parent_width > bounds->right()) { + bounds->set_x(parent_width - bounds->width()); + return true; + } + } else { + if (0 < bounds->x()) { + bounds->set_x(0); + return true; + } + } + return false; +} + +// Move a |window| to a new |bound|. Animate if desired by user. +// Note: The function will do nothing if the bounds did not change. +void SetBoundsAnimated(aura::Window* window, const gfx::Rect& bounds) { + if (bounds == window->GetTargetBounds()) + return; + + if (window->GetProperty(aura::client::kAnimationsDisabledKey) || + CommandLine::ForCurrentProcess()->HasSwitch( + ash::switches::kAshWindowAnimationsDisabled)) { + window->SetBounds(bounds); + return; + } + + ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); + settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kWindowAutoMoveDurationMS)); + window->SetBounds(bounds); +} + +} // namespace + +void RearrangeVisibleWindowOnHideOrRemove(const aura::Window* removed_window) { + if (!UseAutoWindowMagerForWindow(removed_window)) + return; + // Find a single open browser window. + aura::Window* other_shown_window = NULL; + if (!GetOtherVisibleAndManageableWindow(removed_window, + &other_shown_window) || + !WindowPositionCanBeManaged(other_shown_window)) + return; + // Center the window (only in x). + gfx::Rect work_area = GetWorkAreaForWindow(removed_window); + gfx::Rect bounds = other_shown_window->bounds(); + bounds.set_x((work_area.width() - bounds.width()) / 2); + SetBoundsAnimated(other_shown_window, bounds); +} + +void RearrangeVisibleWindowOnShow(aura::Window* added_window) { + if (!UseAutoWindowMagerForWindow(added_window) || + wm::HasUserChangedWindowPositionOrSize(added_window) || + !added_window->TargetVisibility()) + return; + // Find a single open managed window. + aura::Window* other_shown_window = NULL; + if (!GetOtherVisibleAndManageableWindow(added_window, + &other_shown_window)) { + // It could be that this window is the first window joining the workspace. + if (!WindowPositionCanBeManaged(added_window) || other_shown_window) + return; + + // If so we have to make sure it is centered. + gfx::Rect work_area = GetWorkAreaForWindow(added_window); + gfx::Rect bounds = added_window->bounds(); + bounds.set_x((work_area.width() - bounds.width()) / 2); + added_window->SetBounds(bounds); + return; + } + + // When going from one to two windows both windows loose their "positioned + // by user" flags. + ash::wm::SetUserHasChangedWindowPositionOrSize(added_window, false); + ash::wm::SetUserHasChangedWindowPositionOrSize(other_shown_window, false); + + if (WindowPositionCanBeManaged(other_shown_window)) { + gfx::Rect work_area = GetWorkAreaForWindow(added_window); + + // Push away the other window. + gfx::Rect other_bounds = other_shown_window->bounds(); + bool move_right = other_bounds.CenterPoint().x() < work_area.width() / 2; + if (MoveRectToOneSide(work_area.width(), move_right, &other_bounds)) + SetBoundsAnimated(other_shown_window, other_bounds); + + // Push the new window also to the opposite location (if needed). + // Since it is just coming into view, we do not need to animate it. + gfx::Rect added_bounds = added_window->bounds(); + if (MoveRectToOneSide(work_area.width(), !move_right, &added_bounds)) + added_window->SetBounds(added_bounds); + } +} + +} // namespace internal +} // namespace ash diff --git a/ash/wm/workspace/auto_window_management.h b/ash/wm/workspace/auto_window_management.h new file mode 100644 index 0000000..138cb54 --- /dev/null +++ b/ash/wm/workspace/auto_window_management.h @@ -0,0 +1,20 @@ +// 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 "ui/aura/window.h" + +namespace ash { +namespace internal { + +// Check if after removal or hide of the given |removed_window| an automated +// desktop location management can be performed and rearrange accordingly. +void RearrangeVisibleWindowOnHideOrRemove(const aura::Window* removed_window); + +// Check if after insertion or showing of the given |added_window| an automated +// desktop location management can be performed and rearrange accordingly. +void RearrangeVisibleWindowOnShow(aura::Window* added_window); + +} // namespace internal +} // namespace ash + diff --git a/ash/wm/workspace/workspace_layout_manager2_unittest.cc b/ash/wm/workspace/workspace_layout_manager2_unittest.cc index b559a3c..13496f0 100644 --- a/ash/wm/workspace/workspace_layout_manager2_unittest.cc +++ b/ash/wm/workspace/workspace_layout_manager2_unittest.cc @@ -13,9 +13,7 @@ #include "ui/aura/root_window.h" #include "ui/aura/test/test_windows.h" #include "ui/aura/window.h" -#include "ui/gfx/display.h" #include "ui/gfx/insets.h" -#include "ui/gfx/screen.h" namespace ash { @@ -147,15 +145,14 @@ TEST_F(WorkspaceLayoutManager2Test, SizeToWorkArea) { 100, 101, work_area.width() + 1, work_area.height() + 2); scoped_ptr<aura::Window> window(CreateTestWindow(window_bounds)); EXPECT_EQ(gfx::Rect(gfx::Point(100, 101), work_area).ToString(), - window->bounds().ToString()); + window->bounds().ToString()); // Directly setting the bounds triggers a slightly different code path. Verify // that too. window->SetBounds(window_bounds); EXPECT_EQ(gfx::Rect(gfx::Point(100, 101), work_area).ToString(), - window->bounds().ToString()); + window->bounds().ToString()); } } // namespace - } // namespace ash diff --git a/ash/wm/workspace/workspace_manager2.cc b/ash/wm/workspace/workspace_manager2.cc index 68250c3..4a46cb72 100644 --- a/ash/wm/workspace/workspace_manager2.cc +++ b/ash/wm/workspace/workspace_manager2.cc @@ -17,6 +17,7 @@ #include "ash/wm/window_animations.h" #include "ash/wm/window_properties.h" #include "ash/wm/window_util.h" +#include "ash/wm/workspace/auto_window_management.h" #include "ash/wm/workspace/desktop_background_fade_controller.h" #include "ash/wm/workspace/workspace_animations.h" #include "ash/wm/workspace/workspace_layout_manager2.h" @@ -593,10 +594,14 @@ void WorkspaceManager2::OnWindowAddedToWorkspace(Workspace2* workspace, // to the workspace. if (workspace == active_workspace_) UpdateShelfVisibility(); + + RearrangeVisibleWindowOnShow(child); } void WorkspaceManager2::OnWillRemoveWindowFromWorkspace(Workspace2* workspace, Window* child) { + if (child->TargetVisibility()) + RearrangeVisibleWindowOnHideOrRemove(child); child->ClearProperty(kWorkspaceKey); } @@ -609,10 +614,16 @@ void WorkspaceManager2::OnWindowRemovedFromWorkspace(Workspace2* workspace, void WorkspaceManager2::OnWorkspaceChildWindowVisibilityChanged( Workspace2* workspace, Window* child) { - if (workspace->ShouldMoveToPending()) + if (workspace->ShouldMoveToPending()) { MoveWorkspaceToPendingOrDelete(workspace, NULL, SWITCH_VISIBILITY_CHANGED); - else if (workspace == active_workspace_) - UpdateShelfVisibility(); + } else { + if (child->TargetVisibility()) + RearrangeVisibleWindowOnShow(child); + else + RearrangeVisibleWindowOnHideOrRemove(child); + if (workspace == active_workspace_) + UpdateShelfVisibility(); + } } void WorkspaceManager2::OnWorkspaceWindowChildBoundsChanged( diff --git a/ash/wm/workspace/workspace_manager2_unittest.cc b/ash/wm/workspace/workspace_manager2_unittest.cc index 70a39e6..29e9232 100644 --- a/ash/wm/workspace/workspace_manager2_unittest.cc +++ b/ash/wm/workspace/workspace_manager2_unittest.cc @@ -1107,5 +1107,290 @@ TEST_F(WorkspaceManager2Test, DeactivateDropsToDesktop) { ASSERT_EQ("1 M1 active=1", StateString()); } +// Test the basic auto placement of one and or two windows in a "simulated +// session" of sequential window operations. +TEST_F(WorkspaceManager2Test, BasicAutoPlacing) { + // Test 1: In case there is no manageable window, no window should shift. + + scoped_ptr<aura::Window> window1( + aura::test::CreateTestWindowWithId(0, NULL)); + window1->SetBounds(gfx::Rect(16, 32, 640, 320)); + gfx::Rect desktop_area = window1->parent()->bounds(); + + scoped_ptr<aura::Window> window2( + aura::test::CreateTestWindowWithId(1, NULL)); + // Trigger the auto window placement function by making it visible. + // Note that the bounds are getting changed while it is invisible. + window2->Hide(); + window2->SetBounds(gfx::Rect(32, 48, 256, 512)); + window2->Show(); + + // Check the initial position of the windows is unchanged. + EXPECT_EQ("16,32 640x320", window1->bounds().ToString()); + EXPECT_EQ("32,48 256x512", window2->bounds().ToString()); + + // Remove the second window and make sure that the first window + // does NOT get centered. + window2.reset(); + EXPECT_EQ("16,32 640x320", window1->bounds().ToString()); + + // Test 2: Set up two managed windows and check their auto positioning. + ash::wm::SetWindowPositionManaged(window1.get(), true); + scoped_ptr<aura::Window> window3( + aura::test::CreateTestWindowWithId(2, NULL)); + ash::wm::SetWindowPositionManaged(window3.get(), true); + // To avoid any auto window manager changes due to SetBounds, the window + // gets first hidden and then shown again. + window3->Hide(); + window3->SetBounds(gfx::Rect(32, 48, 256, 512)); + window3->Show(); + // |window1| should be flush right and |window3| flush left. + EXPECT_EQ("0,32 640x320", window1->bounds().ToString()); + EXPECT_EQ(base::IntToString( + desktop_area.width() - window3->bounds().width()) + + ",48 256x512", window3->bounds().ToString()); + + // After removing |window3|, |window1| should be centered again. + window3.reset(); + EXPECT_EQ( + base::IntToString( + (desktop_area.width() - window1->bounds().width()) / 2) + + ",32 640x320", window1->bounds().ToString()); + + // Test 3: Set up a manageable and a non manageable window and check + // positioning. + scoped_ptr<aura::Window> window4( + aura::test::CreateTestWindowWithId(3, NULL)); + // To avoid any auto window manager changes due to SetBounds, the window + // gets first hidden and then shown again. + window1->Hide(); + window1->SetBounds(gfx::Rect(16, 32, 640, 320)); + window4->SetBounds(gfx::Rect(32, 48, 256, 512)); + window1->Show(); + // |window1| should be centered and |window4| untouched. + EXPECT_EQ( + base::IntToString( + (desktop_area.width() - window1->bounds().width()) / 2) + + ",32 640x320", window1->bounds().ToString()); + EXPECT_EQ("32,48 256x512", window4->bounds().ToString()); + + // Test4: A single manageable window should get centered. + window4.reset(); + ash::wm::SetUserHasChangedWindowPositionOrSize(window1.get(), false); + // Trigger the auto window placement function by showing (and hiding) it. + window1->Hide(); + window1->Show(); + // |window1| should be centered. + EXPECT_EQ( + base::IntToString( + (desktop_area.width() - window1->bounds().width()) / 2) + + ",32 640x320", window1->bounds().ToString()); +} + +// Test the proper usage of user window movement interaction. +TEST_F(WorkspaceManager2Test, TestUserMovedWindowRepositioning) { + scoped_ptr<aura::Window> window1( + aura::test::CreateTestWindowWithId(0, NULL)); + window1->SetBounds(gfx::Rect(16, 32, 640, 320)); + gfx::Rect desktop_area = window1->parent()->bounds(); + scoped_ptr<aura::Window> window2( + aura::test::CreateTestWindowWithId(1, NULL)); + window2->SetBounds(gfx::Rect(32, 48, 256, 512)); + window1->Hide(); + window2->Hide(); + ash::wm::SetWindowPositionManaged(window1.get(), true); + ash::wm::SetWindowPositionManaged(window2.get(), true); + EXPECT_FALSE(ash::wm::HasUserChangedWindowPositionOrSize(window1.get())); + EXPECT_FALSE(ash::wm::HasUserChangedWindowPositionOrSize(window2.get())); + + // Check that the current location gets preserved if the user has + // positioned it previously. + ash::wm::SetUserHasChangedWindowPositionOrSize(window1.get(), true); + window1->Show(); + EXPECT_EQ("16,32 640x320", window1->bounds().ToString()); + // Flag should be still set. + EXPECT_TRUE(ash::wm::HasUserChangedWindowPositionOrSize(window1.get())); + EXPECT_FALSE(ash::wm::HasUserChangedWindowPositionOrSize(window2.get())); + + // Turn on the second window and make sure that both windows are now + // positionable again (user movement cleared). + window2->Show(); + + // |window1| should be flush right and |window3| flush left. + EXPECT_EQ(base::IntToString( + desktop_area.width() - window1->bounds().width()) + + ",32 640x320", window1->bounds().ToString()); + EXPECT_EQ("0,48 256x512", window2->bounds().ToString()); + // FLag should now be reset. + EXPECT_FALSE(ash::wm::HasUserChangedWindowPositionOrSize(window1.get())); + EXPECT_FALSE(ash::wm::HasUserChangedWindowPositionOrSize(window1.get())); + + // Going back to one shown window should keep the state. + ash::wm::SetUserHasChangedWindowPositionOrSize(window1.get(), true); + window2->Hide(); + EXPECT_EQ(base::IntToString( + desktop_area.width() - window1->bounds().width()) + + ",32 640x320", window1->bounds().ToString()); + EXPECT_TRUE(ash::wm::HasUserChangedWindowPositionOrSize(window1.get())); +} + +// Test that a window from normal to minimize will repos the remaining. +TEST_F(WorkspaceManager2Test, ToMinimizeRepositionsRemaining) { + scoped_ptr<aura::Window> window1( + aura::test::CreateTestWindowWithId(0, NULL)); + ash::wm::SetWindowPositionManaged(window1.get(), true); + window1->SetBounds(gfx::Rect(16, 32, 640, 320)); + gfx::Rect desktop_area = window1->parent()->bounds(); + + scoped_ptr<aura::Window> window2( + aura::test::CreateTestWindowWithId(1, NULL)); + ash::wm::SetWindowPositionManaged(window2.get(), true); + window2->SetBounds(gfx::Rect(32, 48, 256, 512)); + + ash::wm::MinimizeWindow(window1.get()); + + // |window2| should be centered now. + EXPECT_TRUE(window2->IsVisible()); + EXPECT_TRUE(ash::wm::IsWindowNormal(window2.get())); + EXPECT_EQ(base::IntToString( + (desktop_area.width() - window2->bounds().width()) / 2) + + ",48 256x512", window2->bounds().ToString()); + + ash::wm::RestoreWindow(window1.get()); + // |window1| should be flush right and |window3| flush left. + EXPECT_EQ(base::IntToString( + desktop_area.width() - window1->bounds().width()) + + ",32 640x320", window1->bounds().ToString()); + EXPECT_EQ("0,48 256x512", window2->bounds().ToString()); +} + +// Test that minimizing an initially maximized window will repos the remaining. +TEST_F(WorkspaceManager2Test, MaxToMinRepositionsRemaining) { + scoped_ptr<aura::Window> window1( + aura::test::CreateTestWindowWithId(0, NULL)); + ash::wm::SetWindowPositionManaged(window1.get(), true); + gfx::Rect desktop_area = window1->parent()->bounds(); + + scoped_ptr<aura::Window> window2( + aura::test::CreateTestWindowWithId(1, NULL)); + ash::wm::SetWindowPositionManaged(window2.get(), true); + window2->SetBounds(gfx::Rect(32, 48, 256, 512)); + + ash::wm::MaximizeWindow(window1.get()); + ash::wm::MinimizeWindow(window1.get()); + + // |window2| should be centered now. + EXPECT_TRUE(window2->IsVisible()); + EXPECT_TRUE(ash::wm::IsWindowNormal(window2.get())); + EXPECT_EQ(base::IntToString( + (desktop_area.width() - window2->bounds().width()) / 2) + + ",48 256x512", window2->bounds().ToString()); +} + +// Test that nomral, maximize, minimizing will repos the remaining. +TEST_F(WorkspaceManager2Test, NormToMaxToMinRepositionsRemaining) { + scoped_ptr<aura::Window> window1( + aura::test::CreateTestWindowWithId(0, NULL)); + window1->SetBounds(gfx::Rect(16, 32, 640, 320)); + ash::wm::SetWindowPositionManaged(window1.get(), true); + gfx::Rect desktop_area = window1->parent()->bounds(); + + scoped_ptr<aura::Window> window2( + aura::test::CreateTestWindowWithId(1, NULL)); + ash::wm::SetWindowPositionManaged(window2.get(), true); + window2->SetBounds(gfx::Rect(32, 48, 256, 512)); + + // Trigger the auto window placement function by showing (and hiding) it. + window1->Hide(); + window1->Show(); + + // |window1| should be flush right and |window3| flush left. + EXPECT_EQ(base::IntToString( + desktop_area.width() - window1->bounds().width()) + + ",32 640x320", window1->bounds().ToString()); + EXPECT_EQ("0,48 256x512", window2->bounds().ToString()); + + ash::wm::MaximizeWindow(window1.get()); + ash::wm::MinimizeWindow(window1.get()); + + // |window2| should be centered now. + EXPECT_TRUE(window2->IsVisible()); + EXPECT_TRUE(ash::wm::IsWindowNormal(window2.get())); + EXPECT_EQ(base::IntToString( + (desktop_area.width() - window2->bounds().width()) / 2) + + ",48 256x512", window2->bounds().ToString()); +} + +// Test that nomral, maximize, normal will repos the remaining. +TEST_F(WorkspaceManager2Test, NormToMaxToNormRepositionsRemaining) { + scoped_ptr<aura::Window> window1( + aura::test::CreateTestWindowWithId(0, NULL)); + window1->SetBounds(gfx::Rect(16, 32, 640, 320)); + ash::wm::SetWindowPositionManaged(window1.get(), true); + gfx::Rect desktop_area = window1->parent()->bounds(); + + scoped_ptr<aura::Window> window2( + aura::test::CreateTestWindowWithId(1, NULL)); + ash::wm::SetWindowPositionManaged(window2.get(), true); + window2->SetBounds(gfx::Rect(32, 48, 256, 512)); + + // Trigger the auto window placement function by showing (and hiding) it. + window1->Hide(); + window1->Show(); + + // |window1| should be flush right and |window3| flush left. + EXPECT_EQ(base::IntToString( + desktop_area.width() - window1->bounds().width()) + + ",32 640x320", window1->bounds().ToString()); + EXPECT_EQ("0,48 256x512", window2->bounds().ToString()); + + ash::wm::MaximizeWindow(window1.get()); + ash::wm::RestoreWindow(window1.get()); + + // |window1| should be flush right and |window2| flush left. + EXPECT_EQ(base::IntToString( + desktop_area.width() - window1->bounds().width()) + + ",32 640x320", window1->bounds().ToString()); + EXPECT_EQ("0,48 256x512", window2->bounds().ToString()); +} + +// Test that animations are triggered. +TEST_F(WorkspaceManager2Test, AnimatedNormToMaxToNormRepositionsRemaining) { + ui::LayerAnimator::set_disable_animations_for_test(false); + scoped_ptr<aura::Window> window1( + aura::test::CreateTestWindowWithId(0, NULL)); + window1->Hide(); + window1->SetBounds(gfx::Rect(16, 32, 640, 320)); + gfx::Rect desktop_area = window1->parent()->bounds(); + scoped_ptr<aura::Window> window2( + aura::test::CreateTestWindowWithId(1, NULL)); + window2->Hide(); + window2->SetBounds(gfx::Rect(32, 48, 256, 512)); + + ash::wm::SetWindowPositionManaged(window1.get(), true); + ash::wm::SetWindowPositionManaged(window2.get(), true); + // Make sure nothing is animating. + window1->layer()->GetAnimator()->StopAnimating(); + window2->layer()->GetAnimator()->StopAnimating(); + window2->Show(); + + // The second window should now animate. + EXPECT_FALSE(window1->layer()->GetAnimator()->is_animating()); + EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating()); + window2->layer()->GetAnimator()->StopAnimating(); + + window1->Show(); + EXPECT_TRUE(window1->layer()->GetAnimator()->is_animating()); + EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating()); + + window1->layer()->GetAnimator()->StopAnimating(); + window2->layer()->GetAnimator()->StopAnimating(); + // |window1| should be flush right and |window2| flush left. + EXPECT_EQ(base::IntToString( + desktop_area.width() - window1->bounds().width()) + + ",32 640x320", window1->bounds().ToString()); + EXPECT_EQ("0,48 256x512", window2->bounds().ToString()); +} + } // namespace internal } // namespace ash diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc index 4185c442..4a7e9cc 100644 --- a/ash/wm/workspace/workspace_window_resizer.cc +++ b/ash/wm/workspace/workspace_window_resizer.cc @@ -313,6 +313,7 @@ void WorkspaceWindowResizer::Drag(const gfx::Point& location_in_parent, } void WorkspaceWindowResizer::CompleteDrag(int event_flags) { + wm::SetUserHasChangedWindowPositionOrSize(details_.window, true); window()->layer()->SetOpacity(details_.initial_opacity); drag_phantom_window_controller_.reset(); snap_phantom_window_controller_.reset(); |