OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "ash/wm/workspace/auto_window_management.h" |
| 6 |
| 7 #include "ash/ash_switches.h" |
| 8 #include "ash/shell.h" |
| 9 #include "ash/wm/property_util.h" |
| 10 #include "ash/wm/window_animations.h" |
| 11 #include "ash/wm/window_util.h" |
| 12 #include "base/command_line.h" |
| 13 #include "ui/aura/window.h" |
| 14 #include "ui/aura/client/aura_constants.h" |
| 15 #include "ui/compositor/layer_animator.h" |
| 16 #include "ui/compositor/scoped_layer_animation_settings.h" |
| 17 #include "ui/gfx/screen.h" |
| 18 |
| 19 namespace ash { |
| 20 namespace internal { |
| 21 |
| 22 namespace { |
| 23 |
| 24 // The time in milliseconds which should be used to visually move a window |
| 25 // through an automatic "intelligent" window management option. |
| 26 const int kWindowAutoMoveDurationMS = 125; |
| 27 |
| 28 // Check if any management should be performed (with a given |window|). |
| 29 bool UseAutoWindowMagerForWindow(const aura::Window* window) { |
| 30 return !CommandLine::ForCurrentProcess()->HasSwitch( |
| 31 switches::kAshDisableAutoWindowPlacement) && |
| 32 GetTrackedByWorkspace(window) && |
| 33 wm::IsWindowPositionManaged(window); |
| 34 } |
| 35 |
| 36 // Check if a given |window| can be managed. This includes that it's state is |
| 37 // not minimized/maximized/the user has changed it's size by hand already. |
| 38 // It furthermore checks for the WindowIsManaged status. |
| 39 bool WindowPositionCanBeManaged(const aura::Window* window) { |
| 40 return (wm::IsWindowPositionManaged(window) && |
| 41 !wm::IsWindowMinimized(window) && |
| 42 !wm::IsWindowMaximized(window) && |
| 43 !wm::HasUserChangedWindowPositionOrSize(window)); |
| 44 } |
| 45 |
| 46 // Given a |window|, return the only |other_window| which has an impact on |
| 47 // the automated windows location management. If there is more then one window, |
| 48 // false is returned, but the |other_window| will be set to the first one |
| 49 // found. |
| 50 // If the return value is true a single window was found. |
| 51 bool GetOtherVisibleAndManageableWindow(const aura::Window* window, |
| 52 aura::Window** other_window) { |
| 53 *other_window = NULL; |
| 54 const aura::Window::Windows& windows = window->parent()->children(); |
| 55 // Find a single open managed window. |
| 56 for (size_t i = 0; i < windows.size(); i++) { |
| 57 aura::Window* iterated_window = windows[i]; |
| 58 if (window != iterated_window && |
| 59 iterated_window->type() == aura::client::WINDOW_TYPE_NORMAL && |
| 60 iterated_window->TargetVisibility() && |
| 61 wm::IsWindowPositionManaged(iterated_window)) { |
| 62 // Bail if we find a second usable window. |
| 63 if (*other_window) |
| 64 return false; |
| 65 *other_window = iterated_window; |
| 66 } |
| 67 } |
| 68 return *other_window != NULL; |
| 69 } |
| 70 |
| 71 // Get the work area for a given |window|. |
| 72 gfx::Rect GetWorkAreaForWindow(const aura::Window* window) { |
| 73 gfx::Rect work_area = gfx::Rect(window->parent()->bounds().size()); |
| 74 work_area.Inset(Shell::GetScreen()->GetDisplayMatching( |
| 75 work_area).GetWorkAreaInsets()); |
| 76 return work_area; |
| 77 } |
| 78 |
| 79 // Move the given |bounds| on the available |parent_width| to the |
| 80 // direction. If |move_right| is true, the rectangle gets moved to the right |
| 81 // corner, otherwise to the left one. |
| 82 bool MoveRectToOneSide(int parent_width, bool move_right, gfx::Rect* bounds) { |
| 83 if (move_right) { |
| 84 if (parent_width > bounds->right()) { |
| 85 bounds->set_x(parent_width - bounds->width()); |
| 86 return true; |
| 87 } |
| 88 } else { |
| 89 if (0 < bounds->x()) { |
| 90 bounds->set_x(0); |
| 91 return true; |
| 92 } |
| 93 } |
| 94 return false; |
| 95 } |
| 96 |
| 97 // Move a |window| to a new |bound|. Animate if desired by user. |
| 98 // Note: The function will do nothing if the bounds did not change. |
| 99 void SetBoundsAnimated(aura::Window* window, const gfx::Rect& bounds) { |
| 100 if (bounds == window->GetTargetBounds()) |
| 101 return; |
| 102 |
| 103 if (window->GetProperty(aura::client::kAnimationsDisabledKey) || |
| 104 CommandLine::ForCurrentProcess()->HasSwitch( |
| 105 ash::switches::kAshWindowAnimationsDisabled)) { |
| 106 window->SetBounds(bounds); |
| 107 return; |
| 108 } |
| 109 |
| 110 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); |
| 111 settings.SetTransitionDuration( |
| 112 base::TimeDelta::FromMilliseconds(kWindowAutoMoveDurationMS)); |
| 113 window->SetBounds(bounds); |
| 114 } |
| 115 |
| 116 } // namespace |
| 117 |
| 118 void RearrangeVisibleWindowOnHideOrRemove(const aura::Window* removed_window) { |
| 119 if (!UseAutoWindowMagerForWindow(removed_window)) |
| 120 return; |
| 121 // Find a single open browser window. |
| 122 aura::Window* other_shown_window = NULL; |
| 123 if (!GetOtherVisibleAndManageableWindow(removed_window, |
| 124 &other_shown_window) || |
| 125 !WindowPositionCanBeManaged(other_shown_window)) |
| 126 return; |
| 127 // Center the window (only in x). |
| 128 gfx::Rect work_area = GetWorkAreaForWindow(removed_window); |
| 129 gfx::Rect bounds = other_shown_window->bounds(); |
| 130 bounds.set_x((work_area.width() - bounds.width()) / 2); |
| 131 SetBoundsAnimated(other_shown_window, bounds); |
| 132 } |
| 133 |
| 134 void RearrangeVisibleWindowOnShow(aura::Window* added_window) { |
| 135 if (!UseAutoWindowMagerForWindow(added_window) || |
| 136 wm::HasUserChangedWindowPositionOrSize(added_window) || |
| 137 !added_window->TargetVisibility()) |
| 138 return; |
| 139 // Find a single open managed window. |
| 140 aura::Window* other_shown_window = NULL; |
| 141 if (!GetOtherVisibleAndManageableWindow(added_window, |
| 142 &other_shown_window)) { |
| 143 // It could be that this window is the first window joining the workspace. |
| 144 if (!WindowPositionCanBeManaged(added_window) || other_shown_window) |
| 145 return; |
| 146 |
| 147 // If so we have to make sure it is centered. |
| 148 gfx::Rect work_area = GetWorkAreaForWindow(added_window); |
| 149 gfx::Rect bounds = added_window->bounds(); |
| 150 bounds.set_x((work_area.width() - bounds.width()) / 2); |
| 151 added_window->SetBounds(bounds); |
| 152 return; |
| 153 } |
| 154 |
| 155 // When going from one to two windows both windows loose their "positioned |
| 156 // by user" flags. |
| 157 ash::wm::SetUserHasChangedWindowPositionOrSize(added_window, false); |
| 158 ash::wm::SetUserHasChangedWindowPositionOrSize(other_shown_window, false); |
| 159 |
| 160 if (WindowPositionCanBeManaged(other_shown_window)) { |
| 161 gfx::Rect work_area = GetWorkAreaForWindow(added_window); |
| 162 |
| 163 // Push away the other window. |
| 164 gfx::Rect other_bounds = other_shown_window->bounds(); |
| 165 bool move_right = other_bounds.CenterPoint().x() < work_area.width() / 2; |
| 166 if (MoveRectToOneSide(work_area.width(), move_right, &other_bounds)) |
| 167 SetBoundsAnimated(other_shown_window, other_bounds); |
| 168 |
| 169 // Push the new window also to the opposite location (if needed). |
| 170 // Since it is just coming into view, we do not need to animate it. |
| 171 gfx::Rect added_bounds = added_window->bounds(); |
| 172 if (MoveRectToOneSide(work_area.width(), !move_right, &added_bounds)) |
| 173 added_window->SetBounds(added_bounds); |
| 174 } |
| 175 } |
| 176 |
| 177 } // namespace internal |
| 178 } // namespace ash |
OLD | NEW |