Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2424)

Unified Diff: ash/wm/workspace/workspace_manager2.cc

Issue 11085053: Improving window auto management between workspaces (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Improved the entire window (auto) management Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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:

Powered by Google App Engine
This is Rietveld 408576698