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

Side by Side Diff: ash/wm/workspace/workspace.cc

Issue 9113045: Reworks the workspace code. Here's the new heuristics: (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: More changes Created 8 years, 11 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ash/wm/workspace/workspace.h" 5 #include "ash/wm/workspace/workspace.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "ash/wm/property_util.h" 9 #include "ash/wm/property_util.h"
10 #include "ash/wm/window_util.h" 10 #include "ash/wm/window_util.h"
11 #include "ash/wm/workspace/workspace_manager.h" 11 #include "ash/wm/workspace/workspace_manager.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "ui/aura/client/aura_constants.h" 13 #include "ui/aura/client/aura_constants.h"
14 #include "ui/aura/root_window.h" 14 #include "ui/aura/root_window.h"
15 #include "ui/aura/window.h" 15 #include "ui/aura/window.h"
16 #include "ui/base/ui_base_types.h" 16 #include "ui/base/ui_base_types.h"
17 #include "ui/gfx/compositor/layer.h"
18 #include "ui/gfx/compositor/layer_animator.h"
19 #include "ui/gfx/compositor/scoped_layer_animation_settings.h"
20
21 namespace {
22 // Horizontal margin between windows.
23 const int kWindowHorizontalMargin = 10;
24
25 // Maximum number of windows a workspace can have.
26 size_t g_max_windows_per_workspace = 2;
27
28 // Returns the bounds of the window that should be used to calculate
29 // the layout. It uses the restore bounds if exits, or
30 // the target bounds of the window. The target bounds is the
31 // final destination of |window| if the window's layer is animating,
32 // or the current bounds of the window of no animation is currently
33 // in progress.
34 gfx::Rect GetLayoutBounds(aura::Window* window) {
35 const gfx::Rect* restore_bounds = ash::GetRestoreBounds(window);
36 return restore_bounds ? *restore_bounds : window->GetTargetBounds();
37 }
38
39 // Returns the width of the window that should be used to calculate
40 // the layout. See |GetLayoutBounds| for more details.
41 int GetLayoutWidth(aura::Window* window) {
42 return GetLayoutBounds(window).width();
43 }
44
45 } // namespace
46 17
47 namespace ash { 18 namespace ash {
48 namespace internal { 19 namespace internal {
49 20
50 Workspace::Workspace(WorkspaceManager* manager) 21 Workspace::Workspace(WorkspaceManager* manager)
51 : workspace_manager_(manager) { 22 : type_(TYPE_NORMAL),
23 workspace_manager_(manager) {
52 workspace_manager_->AddWorkspace(this); 24 workspace_manager_->AddWorkspace(this);
53 } 25 }
54 26
55 Workspace::~Workspace() { 27 Workspace::~Workspace() {
56 workspace_manager_->RemoveWorkspace(this); 28 workspace_manager_->RemoveWorkspace(this);
57 } 29 }
58 30
59 void Workspace::SetBounds(const gfx::Rect& bounds) { 31 // static
60 bool bounds_changed = bounds_ != bounds; 32 Workspace::Type Workspace::TypeForWindow(aura::Window* window) {
61 bounds_ = bounds; 33 if (window_util::GetOpenWindowSplit(window))
62 if (bounds_changed) 34 return TYPE_SPLIT;
63 Layout(NULL); 35 if (window_util::IsWindowMaximized(window) ||
36 window_util::IsWindowFullscreen(window)) {
37 return TYPE_MAXIMIZED;
38 }
39 return TYPE_NORMAL;
40 }
41
42 void Workspace::SetType(Type type) {
43 type_ = type;
oshima 2012/01/25 23:21:12 Since a workspace can morph to another type, it's
44 }
45
46 void Workspace::WorkspaceSizeChanged() {
47 if (!windows_.empty()) {
48 // TODO: need to handle size changing.
49 NOTIMPLEMENTED();
50 }
64 } 51 }
65 52
66 gfx::Rect Workspace::GetWorkAreaBounds() const { 53 gfx::Rect Workspace::GetWorkAreaBounds() const {
67 return workspace_manager_->GetWorkAreaBounds(bounds_); 54 return workspace_manager_->GetWorkAreaBounds();
68 } 55 }
69 56
70 bool Workspace::AddWindowAfter(aura::Window* window, aura::Window* after) { 57 bool Workspace::AddWindowAfter(aura::Window* window, aura::Window* after) {
71 if (!CanAdd(window)) 58 if (!CanAdd(window))
72 return false; 59 return false;
73 DCHECK(!Contains(window)); 60 DCHECK(!Contains(window));
74 61
75 if (!after) { // insert at the end. 62 aura::Window::Windows::iterator i =
63 std::find(windows_.begin(), windows_.end(), after);
64 if (!after || i == windows_.end())
76 windows_.push_back(window); 65 windows_.push_back(window);
77 } else { 66 else
78 DCHECK(Contains(after));
79 aura::Window::Windows::iterator i =
80 std::find(windows_.begin(), windows_.end(), after);
81 windows_.insert(++i, window); 67 windows_.insert(++i, window);
68
69 if (type_ == TYPE_MAXIMIZED) {
70 workspace_manager_->SetWindowBounds(window, GetWorkAreaBounds());
71 } else if (type_ == TYPE_SPLIT) {
72 // TODO: this needs to adjust bounds appropriately.
73 workspace_manager_->SetWindowBounds(window, GetWorkAreaBounds());
82 } 74 }
83 Layout(window);
84 75
85 return true; 76 return true;
86 } 77 }
87 78
88 void Workspace::RemoveWindow(aura::Window* window) { 79 void Workspace::RemoveWindow(aura::Window* window) {
89 DCHECK(Contains(window)); 80 DCHECK(Contains(window));
90 windows_.erase(std::find(windows_.begin(), windows_.end(), window)); 81 windows_.erase(std::find(windows_.begin(), windows_.end(), window));
91 Layout(NULL); 82 // TODO: this needs to adjust things.
92 } 83 }
93 84
94 bool Workspace::Contains(aura::Window* window) const { 85 bool Workspace::Contains(aura::Window* window) const {
95 return std::find(windows_.begin(), windows_.end(), window) != windows_.end(); 86 return std::find(windows_.begin(), windows_.end(), window) != windows_.end();
96 } 87 }
97 88
98 aura::Window* Workspace::FindRotateWindowForLocation(
99 const gfx::Point& position) {
100 aura::Window* active = ash::GetActiveWindow();
101 if (GetTotalWindowsWidth() < bounds_.width()) {
102 // If all windows fit to the width of the workspace, it returns the
103 // window which contains |position|'s x coordinate.
104 for (aura::Window::Windows::const_iterator i = windows_.begin();
105 i != windows_.end();
106 ++i) {
107 if (active == *i)
108 continue;
109 gfx::Rect bounds = (*i)->GetTargetBounds();
110 if (bounds.x() < position.x() && position.x() < bounds.right())
111 return *i;
112 }
113 } else if (bounds_.x() < position.x() && position.x() < bounds_.right()) {
114 // If windows are overlapping, it divides the workspace into
115 // regions with the same width, and returns the Nth window that
116 // corresponds to the region that contains the |position|.
117 int width = bounds_.width() / windows_.size();
118 size_t index = (position.x() - bounds_.x()) / width;
119 DCHECK(index < windows_.size());
120 aura::Window* window = windows_[index];
121 if (window != active)
122 return window;
123 }
124 return NULL;
125 }
126
127 void Workspace::RotateWindows(aura::Window* source, aura::Window* target) {
128 DCHECK(Contains(source));
129 DCHECK(Contains(target));
130 aura::Window::Windows::iterator source_iter =
131 std::find(windows_.begin(), windows_.end(), source);
132 aura::Window::Windows::iterator target_iter =
133 std::find(windows_.begin(), windows_.end(), target);
134 DCHECK(source_iter != target_iter);
135 if (source_iter < target_iter)
136 std::rotate(source_iter, source_iter + 1, target_iter + 1);
137 else
138 std::rotate(target_iter, source_iter, source_iter + 1);
139 Layout(NULL);
140 }
141
142 aura::Window* Workspace::ShiftWindows(aura::Window* insert,
143 aura::Window* until,
144 aura::Window* target,
145 ShiftDirection direction) {
146 DCHECK(until);
147 DCHECK(!Contains(insert));
148
149 bool shift_reached_until = GetIndexOf(until) >= 0;
150 if (shift_reached_until) {
151 // Calling RemoveWindow here causes the animation set in Layout below
152 // to be ignored. See crbug.com/102413.
153 windows_.erase(std::find(windows_.begin(), windows_.end(), until));
154 }
155 aura::Window* pushed = NULL;
156 if (direction == SHIFT_TO_RIGHT) {
157 aura::Window::Windows::iterator iter =
158 std::find(windows_.begin(), windows_.end(), target);
159 // Insert at |target| position, or at the begining.
160 if (iter == windows_.end())
161 iter = windows_.begin();
162 windows_.insert(iter, insert);
163 if (!shift_reached_until) {
164 pushed = windows_.back();
165 windows_.erase(--windows_.end());
166 }
167 } else {
168 aura::Window::Windows::iterator iter =
169 std::find(windows_.begin(), windows_.end(), target);
170 // Insert after |target|, or at the end.
171 if (iter != windows_.end())
172 ++iter;
173 windows_.insert(iter, insert);
174 if (!shift_reached_until) {
175 pushed = windows_.front();
176 windows_.erase(windows_.begin());
177 }
178 }
179 Layout(NULL);
180 return pushed;
181 }
182
183 void Workspace::Activate() { 89 void Workspace::Activate() {
184 workspace_manager_->SetActiveWorkspace(this); 90 workspace_manager_->SetActiveWorkspace(this);
185 } 91 }
186 92
187 void Workspace::Layout(aura::Window* no_animation) {
188 aura::Window* ignore = workspace_manager_->ignored_window();
189 workspace_manager_->set_layout_in_progress(true);
190 gfx::Rect work_area = workspace_manager_->GetWorkAreaBounds(bounds_);
191 int total_width = GetTotalWindowsWidth();
192 if (total_width < work_area.width()) {
193 int dx = (work_area.width() - total_width) / 2;
194 for (aura::Window::Windows::iterator i = windows_.begin();
195 i != windows_.end();
196 ++i) {
197 if (*i != ignore) {
198 MoveWindowTo(*i,
199 gfx::Point(work_area.x() + dx, work_area.y()),
200 no_animation != *i);
201 }
202 dx += GetLayoutWidth(*i) + kWindowHorizontalMargin;
203 }
204 } else {
205 DCHECK_LT(windows_.size(), 3U);
206 // TODO(oshima): This is messy. Figure out general algorithm to
207 // layout more than 2 windows.
208 if (windows_[0] != ignore) {
209 MoveWindowTo(windows_[0],
210 work_area.origin(),
211 no_animation != windows_[0]);
212 }
213 if (windows_.size() == 2 && windows_[1] != ignore) {
214 MoveWindowTo(windows_[1],
215 gfx::Point(work_area.right() - GetLayoutWidth(windows_[1]),
216 work_area.y()),
217 no_animation != windows_[1]);
218 }
219 }
220 workspace_manager_->set_layout_in_progress(false);
221 }
222
223 bool Workspace::ContainsFullscreenWindow() const { 93 bool Workspace::ContainsFullscreenWindow() const {
224 for (aura::Window::Windows::const_iterator i = windows_.begin(); 94 for (aura::Window::Windows::const_iterator i = windows_.begin();
225 i != windows_.end(); 95 i != windows_.end();
226 ++i) { 96 ++i) {
227 aura::Window* w = *i; 97 aura::Window* w = *i;
228 if (w->IsVisible() && 98 if (w->IsVisible() &&
229 w->GetIntProperty(aura::client::kShowStateKey) == 99 w->GetIntProperty(aura::client::kShowStateKey) ==
230 ui::SHOW_STATE_FULLSCREEN) 100 ui::SHOW_STATE_FULLSCREEN)
231 return true; 101 return true;
232 } 102 }
233 return false; 103 return false;
234 } 104 }
235 105
236 int Workspace::GetIndexOf(aura::Window* window) const { 106 int Workspace::GetIndexOf(aura::Window* window) const {
237 aura::Window::Windows::const_iterator i = 107 aura::Window::Windows::const_iterator i =
238 std::find(windows_.begin(), windows_.end(), window); 108 std::find(windows_.begin(), windows_.end(), window);
239 return i == windows_.end() ? -1 : i - windows_.begin(); 109 return i == windows_.end() ? -1 : i - windows_.begin();
240 } 110 }
241 111
242 bool Workspace::CanAdd(aura::Window* window) const { 112 bool Workspace::CanAdd(aura::Window* window) const {
243 // TODO(oshima): This should be based on available space and the 113 return TypeForWindow(window) == type_;
244 // size of the |window|.
245 //NOTIMPLEMENTED();
246 return windows_.size() < g_max_windows_per_workspace;
247 }
248
249 void Workspace::MoveWindowTo(
250 aura::Window* window,
251 const gfx::Point& origin,
252 bool animate) {
253 gfx::Rect bounds = GetLayoutBounds(window);
254 gfx::Rect work_area = GetWorkAreaBounds();
255 // Make sure the window isn't bigger than the workspace size.
256 bounds.SetRect(origin.x(), origin.y(),
257 std::min(work_area.width(), bounds.width()),
258 std::min(work_area.height(), bounds.height()));
259 if (animate) {
260 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
261 window->SetBounds(bounds);
262 } else {
263 window->SetBounds(bounds);
264 }
265 }
266
267 int Workspace::GetTotalWindowsWidth() const {
268 int total_width = 0;
269 for (aura::Window::Windows::const_iterator i = windows_.begin();
270 i != windows_.end();
271 ++i) {
272 if (total_width)
273 total_width += kWindowHorizontalMargin;
274 total_width += GetLayoutWidth(*i);
275 }
276 return total_width;
277 }
278
279 // static
280 size_t Workspace::SetMaxWindowsCount(size_t max) {
281 int old = g_max_windows_per_workspace;
282 g_max_windows_per_workspace = max;
283 return old;
284 } 114 }
285 115
286 } // namespace internal 116 } // namespace internal
287 } // namespace ash 117 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698