Index: ash/wm/workspace/workspace_manager2.cc |
diff --git a/ash/wm/workspace/workspace_manager2.cc b/ash/wm/workspace/workspace_manager2.cc |
index 805dd183584e96b98757554ab279df8c7c968a0a..67f1cb6dce3ef16520991713376622b1d7d28a62 100644 |
--- a/ash/wm/workspace/workspace_manager2.cc |
+++ b/ash/wm/workspace/workspace_manager2.cc |
@@ -14,6 +14,7 @@ |
#include "ash/wm/property_util.h" |
#include "ash/wm/shelf_layout_manager.h" |
#include "ash/wm/window_animations.h" |
+#include "ash/wm/window_cycle_controller.h" |
#include "ash/wm/window_properties.h" |
#include "ash/wm/window_util.h" |
#include "ash/wm/workspace/workspace_layout_manager2.h" |
@@ -30,6 +31,8 @@ |
#include "ui/base/ui_base_types.h" |
#include "ui/compositor/layer.h" |
#include "ui/compositor/layer_animator.h" |
+#include "ui/compositor/scoped_layer_animation_settings.h" |
+#include "ui/gfx/screen.h" |
DECLARE_WINDOW_PROPERTY_TYPE(ash::internal::Workspace2*); |
@@ -42,6 +45,157 @@ DEFINE_WINDOW_PROPERTY_KEY(Workspace2*, kWorkspaceKey, NULL); |
namespace { |
+// The time which should be used to visually move a window through an |
+// automatic "intelligent" window management option. |
+const base::TimeDelta kWindowAutoMoveDuration = |
sky
2012/10/11 19:50:54
Move all this logic out of this class. Maybe into
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Done.
|
+ base::TimeDelta::FromMilliseconds(125); |
+ |
+// Check if the given |window| has an impact on position manageability since it |
+// occupies screen space. Note: The minimized state is not included in this |
sky
2012/10/11 19:50:54
'since it occupies screen space'?
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Hmm. Yeah, Somehow I have re-written this comment
|
+// test since a window which just got minimized might have an impact on the |
+// window ordering. |
+bool HasWindowImpactOnPositionManaging(const aura::Window* window) { |
sky
2012/10/11 19:50:54
Name this WindowHasImpactOnPositioning
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Done.
|
+ return (!wm::IsWindowMaximized(window) && |
sky
2012/10/11 19:50:54
Don't you need to check visibility here? And why t
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Visibility check: Made sense, so I have tried it a
sky
2012/10/12 14:27:04
Can you point me at a test where what I have sugge
Mr4D (OOO till 08-26)
2012/10/12 23:21:30
Because when switching from maximize to minimize i
|
+ !window->bounds().IsEmpty() && |
+ wm::IsWindowPositionManageable(window)); |
+} |
+ |
+// Check if a given |window| is considered to be an auto location manageable |
+// window or not. |
+bool IsWindowPositionManageable(const aura::Window* window) { |
+ return (HasWindowImpactOnPositionManaging(window) && |
+ !wm::IsWindowMinimized(window) && |
+ !wm::HasUserChangedWindowPositionOrSize(window)); |
+} |
+ |
+// Given a |window|, return the |work_area| of the desktop on which it is |
+// located as well as the only |other_window| which has an impact on the |
+// automated window location management. If there are more then one windows, |
+// false get returned, but the |other_window| will be set to the first one |
+// found. |
+// If the return value is true a single window was found. |
+// Note: |work_area| is undefined if false is returned and |other_window| is |
+// NULL. |
+bool GetOtherVisibleAndManageableWindow(const aura::Window* window, |
+ gfx::Rect* work_area, |
+ aura::Window** other_window) { |
+ *other_window = NULL; |
+ // If the given window was not manageable, it cannot have caused a management |
+ // operation earlier. |
+ if (!HasWindowImpactOnPositionManaging(window)) |
+ return false; |
+ |
+ const std::vector<aura::Window*> windows = |
+ ash::WindowCycleController::BuildWindowList(NULL); |
+ |
+ if (windows.empty()) |
+ return false; |
+ |
+ // Get our work area. |
+ *work_area = window->parent()->bounds(); |
+ work_area->Inset(gfx::Screen::GetDisplayMatching( |
+ *work_area).GetWorkAreaInsets()); |
+ |
+ // Find a single open browser window. |
+ for (size_t i = 0; i < windows.size(); i++) { |
+ aura::Window* j = windows[i]; |
+ if (j && window != j && |
sky
2012/10/11 19:50:54
You should not need a check for validity of j.
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Done.
|
+ j->type() == aura::client::WINDOW_TYPE_NORMAL && |
+ work_area->Intersects(j->GetBoundsInScreen()) && |
sky
2012/10/11 19:50:54
Why the work_area check?
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
To make sure that the window is on this screen (an
sky
2012/10/12 14:27:04
Actually, why are you using the WindowCycleControl
Mr4D (OOO till 08-26)
2012/10/12 23:21:30
I thought it might be better to only include "note
|
+ j->IsVisible() && HasWindowImpactOnPositionManaging(j)) { |
+ // Bail if we find a second usable window. |
+ if (*other_window) |
+ return false; |
+ *other_window = j; |
+ } |
+ } |
+ return *other_window != NULL; |
+} |
+ |
+// Move the given |bounds| on the available |work_area_width| to the |
sky
2012/10/11 19:50:54
work_area_width is a misleading name since it isn'
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Done.
|
+// direction. If |move_right| is true, the rectangle gets moved to the right |
+// corner, otherwise to the left one. |
+bool MoveRect(int work_area_width, gfx::Rect& bounds, bool move_right) { |
sky
2012/10/11 19:50:54
MoveRect is an extremely generic name. How about M
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Named it "MoveRectToOneSide". Done.
|
+ if (move_right) { |
+ if (work_area_width > bounds.right()) { |
+ bounds.set_x(work_area_width - bounds.width()); |
+ return true; |
+ } |
+ } else { |
+ if (0 < bounds.x()) { |
+ bounds.set_x(0); |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+// Check if after removal of the given |removed_window| an automated desktop |
+// location management can be performed and rearrange accordingly |
+void RearrangeVisibleWindowOnRemove(const aura::Window* removed_window) { |
+ // Find a single open browser window. |
+ aura::Window* shown_window = NULL; |
+ gfx::Rect work_area; |
+ if (!GetOtherVisibleAndManageableWindow(removed_window, |
+ &work_area, |
+ &shown_window)) |
+ return; |
+ |
+ if (shown_window && IsWindowPositionManageable(shown_window)) { |
sky
2012/10/11 19:50:54
Why the shown_window test? Doesn't GetOtherVisible
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Sorry. My kind of defensive programming. Done.
|
+ // Center the window (only in x). |
+ gfx::Rect bounds = shown_window->bounds(); |
+ bounds.set_x((work_area.width() - bounds.width()) / 2); |
+ ui::LayerAnimator* animator = shown_window->layer()->GetAnimator(); |
+ animator->set_preemption_strategy( |
sky
2012/10/11 19:50:54
Why are you setting the preemption_strategy?
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Because I have seen it being used in a comparable
sky
2012/10/12 14:27:04
You need to investigate this. There should be no n
Mr4D (OOO till 08-26)
2012/10/12 23:21:30
Yes, I investigated it for 2.5 hours and it was ex
|
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
+ |
+ ui::ScopedLayerAnimationSettings animation_setter(animator); |
+ animation_setter.SetTransitionDuration(kWindowAutoMoveDuration); |
+ |
+ shown_window->SetBounds(bounds); |
+ } |
+} |
+ |
+// Check if after insertion of the given |added_window| an automated desktop |
+// location management can be performed and rearrange accordingly. |
+void RearrangeVisibleWindowOnJoining(aura::Window* added_window) { |
sky
2012/10/11 19:50:54
How about RearrangeVisibleWindowOnShow and Rearran
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Done.
|
+ // Find a single open browser window. |
+ aura::Window* shown_window = NULL; |
+ gfx::Rect work_area; |
+ if (!GetOtherVisibleAndManageableWindow(added_window, |
+ &work_area, |
+ &shown_window)) { |
+ // It could be that this window is the first window joining the workspace. |
+ if (!IsWindowPositionManageable(added_window) || shown_window) |
sky
2012/10/11 19:50:54
How could shown_window be non-null here?
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Read the comment for GetOtherVisibleAndManageableW
|
+ return; |
+ // If so we have to make sure it is centered. |
+ gfx::Rect bounds = added_window->bounds(); |
+ bounds.set_x((work_area.width() - bounds.width()) / 2); |
+ added_window->SetBounds(bounds); |
+ return; |
+ } |
+ |
+ if (shown_window && IsWindowPositionManageable(shown_window)) { |
+ // Push away the other window. |
+ gfx::Rect other_bounds = shown_window->bounds(); |
+ bool move_right = other_bounds.CenterPoint().x() < work_area.width() / 2; |
+ if (MoveRect(work_area.width(), other_bounds, move_right)) { |
+ ui::LayerAnimator* animator = shown_window->layer()->GetAnimator(); |
+ animator->set_preemption_strategy( |
+ ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
+ |
+ ui::ScopedLayerAnimationSettings animation_setter(animator); |
+ animation_setter.SetTransitionDuration(kWindowAutoMoveDuration); |
+ shown_window->SetBounds(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 (MoveRect(work_area.width(), added_bounds, !move_right)) |
+ added_window->SetBounds(added_bounds); |
+ } |
+} |
+ |
// Changes the parent of |window| and all its transient children to |
// |new_parent|. If |stack_beneach| is non-NULL all the windows are stacked |
// beneath it. |
@@ -490,6 +644,7 @@ void WorkspaceManager2::OnWindowAddedToWorkspace(Workspace2* workspace, |
void WorkspaceManager2::OnWillRemoveWindowFromWorkspace(Workspace2* workspace, |
Window* child) { |
child->ClearProperty(kWorkspaceKey); |
+ RearrangeVisibleWindowOnRemove(child); |
} |
void WorkspaceManager2::OnWindowRemovedFromWorkspace(Workspace2* workspace, |
@@ -503,8 +658,13 @@ void WorkspaceManager2::OnWorkspaceChildWindowVisibilityChanged( |
Window* child) { |
if (workspace->ShouldMoveToPending()) |
MoveWorkspaceToPendingOrDelete(workspace, NULL, ANIMATE_NEW); |
- else if (workspace == active_workspace_) |
+ else if (workspace == active_workspace_) { |
UpdateShelfVisibility(); |
+ if (child->IsVisible()) |
sky
2012/10/11 19:50:54
Why make this depend upon whether the workspace is
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
There are two reasons:
1.) (the logical one) Why s
sky
2012/10/12 14:27:04
You should rearrange in the desktop the window is
Mr4D (OOO till 08-26)
2012/10/12 23:21:30
Changed the algorithm from my "on access" method t
|
+ RearrangeVisibleWindowOnJoining(child); |
+ else |
+ RearrangeVisibleWindowOnRemove(child); |
+ } |
} |
void WorkspaceManager2::OnWorkspaceWindowChildBoundsChanged( |
@@ -524,6 +684,11 @@ void WorkspaceManager2::OnWorkspaceWindowShowStateChanged( |
if (wm::IsWindowMinimized(child)) { |
if (workspace->ShouldMoveToPending()) |
MoveWorkspaceToPendingOrDelete(workspace, NULL, ANIMATE_NEW); |
+ // When a window gets minimized, we have to re-arrange the visible windows |
+ // here. This especially applies when you have two normal windows, maximize |
+ // one and then minimize it. The other window on the desktop needs then to |
+ // get centered. |
+ RearrangeVisibleWindowOnRemove(child); |
sky
2012/10/11 19:50:54
Minimize also results in OnWorkspaceChildWindowVis
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Yes I am. I was fixing several special cases I hav
sky
2012/10/12 14:27:04
Can you point me at the tests that fail when this
Mr4D (OOO till 08-26)
2012/10/12 23:21:30
Removed.
|
DCHECK(!old_layer); |
} else { |
// Set of cases to deal with: |