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

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

Issue 11085053: Improving window auto management between workspaces (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: No auto movement for tab dragging 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/auto_window_management.cc
diff --git a/ash/wm/workspace/auto_window_management.cc b/ash/wm/workspace/auto_window_management.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e1833a807be93bc7fda1fb9fb99e4bbb3d664ad8
--- /dev/null
+++ b/ash/wm/workspace/auto_window_management.cc
@@ -0,0 +1,193 @@
+// 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 the given |window| is marked to get managed.
+bool WindowIsManaged(const aura::Window* window) {
+ return 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 (WindowIsManaged(window) &&
+ !wm::IsWindowMinimized(window) &&
+ !wm::IsWindowMaximized(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 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;
+ // If the given window was not manageable, it cannot have caused a management
+ // operation earlier.
+ if (!WindowIsManaged(window))
+ return false;
+
+ 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() &&
+ WindowIsManaged(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 the window isn't visible it was just added. Invisible windows have no
+ // effect on auto window management.
+ // Tab dragging windows get ignored as well.
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAshDisableAutoWindowPlacement) ||
+ !GetTrackedByWorkspace(removed_window) ||
+ wm::HasUserChangedWindowPositionOrSize(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 the window isn't visible it was just added. Invisible windows have no
+ // effect on auto window management.
+ // Tab dragging windows get ignored as well.
+ if (!added_window->TargetVisibility() ||
+ !GetTrackedByWorkspace(added_window) ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
sky 2012/10/23 19:35:39 Instead of sprinkling checks for the switch have a
Mr4D (OOO till 08-26) 2012/10/24 16:41:37 I had exactly that at the beginning: GetOtherVisib
+ switches::kAshDisableAutoWindowPlacement))
+ 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
+

Powered by Google App Engine
This is Rietveld 408576698