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 |