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

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: Merged and all that good stuff. 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
« no previous file with comments | « ash/wm/workspace/workspace.h ('k') | ash/wm/workspace/workspace_event_filter.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 // Can only change the type when there are no windows, or the type of window
44 // matches the type changing to. We need only check the first window as CanAdd
45 // only allows new windows if the type matches.
46 DCHECK(windows_.empty() || TypeForWindow(windows_[0]) == type);
47 type_ = type;
48 }
49
50 void Workspace::WorkspaceSizeChanged() {
51 if (!windows_.empty()) {
52 // TODO: need to handle size changing.
53 NOTIMPLEMENTED();
54 }
64 } 55 }
65 56
66 gfx::Rect Workspace::GetWorkAreaBounds() const { 57 gfx::Rect Workspace::GetWorkAreaBounds() const {
67 return workspace_manager_->GetWorkAreaBounds(bounds_); 58 return workspace_manager_->GetWorkAreaBounds();
68 } 59 }
69 60
70 bool Workspace::AddWindowAfter(aura::Window* window, aura::Window* after) { 61 bool Workspace::AddWindowAfter(aura::Window* window, aura::Window* after) {
71 if (!CanAdd(window)) 62 if (!CanAdd(window))
72 return false; 63 return false;
73 DCHECK(!Contains(window)); 64 DCHECK(!Contains(window));
74 65
75 if (!after) { // insert at the end. 66 aura::Window::Windows::iterator i =
67 std::find(windows_.begin(), windows_.end(), after);
68 if (!after || i == windows_.end())
76 windows_.push_back(window); 69 windows_.push_back(window);
77 } else { 70 else
78 DCHECK(Contains(after));
79 aura::Window::Windows::iterator i =
80 std::find(windows_.begin(), windows_.end(), after);
81 windows_.insert(++i, window); 71 windows_.insert(++i, window);
72
73 if (type_ == TYPE_MAXIMIZED) {
74 workspace_manager_->SetWindowBounds(window, GetWorkAreaBounds());
75 } else if (type_ == TYPE_SPLIT) {
76 // TODO: this needs to adjust bounds appropriately.
77 workspace_manager_->SetWindowBounds(window, GetWorkAreaBounds());
82 } 78 }
83 Layout(window);
84 79
85 return true; 80 return true;
86 } 81 }
87 82
88 void Workspace::RemoveWindow(aura::Window* window) { 83 void Workspace::RemoveWindow(aura::Window* window) {
89 DCHECK(Contains(window)); 84 DCHECK(Contains(window));
90 windows_.erase(std::find(windows_.begin(), windows_.end(), window)); 85 windows_.erase(std::find(windows_.begin(), windows_.end(), window));
91 Layout(NULL); 86 // TODO: this needs to adjust things.
92 } 87 }
93 88
94 bool Workspace::Contains(aura::Window* window) const { 89 bool Workspace::Contains(aura::Window* window) const {
95 return std::find(windows_.begin(), windows_.end(), window) != windows_.end(); 90 return std::find(windows_.begin(), windows_.end(), window) != windows_.end();
96 } 91 }
97 92
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() { 93 void Workspace::Activate() {
184 workspace_manager_->SetActiveWorkspace(this); 94 workspace_manager_->SetActiveWorkspace(this);
185 } 95 }
186 96
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 { 97 bool Workspace::ContainsFullscreenWindow() const {
224 for (aura::Window::Windows::const_iterator i = windows_.begin(); 98 for (aura::Window::Windows::const_iterator i = windows_.begin();
225 i != windows_.end(); 99 i != windows_.end();
226 ++i) { 100 ++i) {
227 aura::Window* w = *i; 101 aura::Window* w = *i;
228 if (w->IsVisible() && 102 if (w->IsVisible() &&
229 w->GetIntProperty(aura::client::kShowStateKey) == 103 w->GetIntProperty(aura::client::kShowStateKey) ==
230 ui::SHOW_STATE_FULLSCREEN) 104 ui::SHOW_STATE_FULLSCREEN)
231 return true; 105 return true;
232 } 106 }
233 return false; 107 return false;
234 } 108 }
235 109
236 int Workspace::GetIndexOf(aura::Window* window) const { 110 int Workspace::GetIndexOf(aura::Window* window) const {
237 aura::Window::Windows::const_iterator i = 111 aura::Window::Windows::const_iterator i =
238 std::find(windows_.begin(), windows_.end(), window); 112 std::find(windows_.begin(), windows_.end(), window);
239 return i == windows_.end() ? -1 : i - windows_.begin(); 113 return i == windows_.end() ? -1 : i - windows_.begin();
240 } 114 }
241 115
242 bool Workspace::CanAdd(aura::Window* window) const { 116 bool Workspace::CanAdd(aura::Window* window) const {
243 // TODO(oshima): This should be based on available space and the 117 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 } 118 }
285 119
286 } // namespace internal 120 } // namespace internal
287 } // namespace ash 121 } // namespace ash
OLDNEW
« no previous file with comments | « ash/wm/workspace/workspace.h ('k') | ash/wm/workspace/workspace_event_filter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698