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

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

Issue 9113045: Reworks the workspace code. Here's the new heuristics: (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Incorporated feedback and fixed bugs 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_manager.h" 5 #include "ash/wm/workspace/workspace_manager.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "ash/wm/property_util.h"
10 #include "ash/wm/window_util.h"
9 #include "ash/wm/workspace/workspace.h" 11 #include "ash/wm/workspace/workspace.h"
10 #include "ash/wm/workspace/workspace_observer.h"
11 #include "base/auto_reset.h" 12 #include "base/auto_reset.h"
12 #include "base/logging.h" 13 #include "base/logging.h"
13 #include "base/stl_util.h" 14 #include "base/stl_util.h"
15 #include "ui/aura/client/aura_constants.h"
14 #include "ui/aura/root_window.h" 16 #include "ui/aura/root_window.h"
15 #include "ui/aura/screen_aura.h" 17 #include "ui/aura/screen_aura.h"
16 #include "ui/aura/window.h" 18 #include "ui/aura/window.h"
19 #include "ui/base/ui_base_types.h"
17 #include "ui/gfx/compositor/layer.h" 20 #include "ui/gfx/compositor/layer.h"
18 #include "ui/gfx/compositor/layer_animator.h" 21 #include "ui/gfx/compositor/layer_animator.h"
19 #include "ui/gfx/compositor/scoped_layer_animation_settings.h" 22 #include "ui/gfx/compositor/scoped_layer_animation_settings.h"
20 #include "ui/gfx/screen.h" 23 #include "ui/gfx/screen.h"
21 #include "ui/gfx/transform.h" 24 #include "ui/gfx/transform.h"
22 25
23 namespace { 26 namespace {
24 27
25 // The horizontal margein between workspaces in pixels. 28 // The horizontal margein between workspaces in pixels.
26 const int kWorkspaceHorizontalMargin = 50; 29 const int kWorkspaceHorizontalMargin = 50;
27 30
28 // Minimum/maximum scale for overview mode. 31 // Minimum/maximum scale for overview mode.
29 const float kMaxOverviewScale = 0.9f; 32 const float kMaxOverviewScale = 0.9f;
30 const float kMinOverviewScale = 0.3f; 33 const float kMinOverviewScale = 0.3f;
31 34
35 // Sets the visibility of the layer of each window in |windows| to |value|.
oshima 2012/01/26 16:37:25 I guess we set visibility on layer so that we trea
36 void SetWindowLayerVisibility(const std::vector<aura::Window*>& windows,
37 bool value) {
38 for (size_t i = 0; i < windows.size(); ++i){
39 if (windows[i]->layer())
40 windows[i]->layer()->SetVisible(value);
41 }
oshima 2012/01/26 16:37:25 Don't we have to change the visibility of transien
42 }
43
32 } 44 }
33 45
34 namespace ash { 46 namespace ash {
35 namespace internal { 47 namespace internal {
36 48
37 //////////////////////////////////////////////////////////////////////////////// 49 ////////////////////////////////////////////////////////////////////////////////
38 // WindowManager, public: 50 // WindowManager, public:
39 51
40 WorkspaceManager::WorkspaceManager(aura::Window* contents_view) 52 WorkspaceManager::WorkspaceManager(aura::Window* contents_view)
41 : contents_view_(contents_view), 53 : contents_view_(contents_view),
42 active_workspace_(NULL), 54 active_workspace_(NULL),
43 workspace_size_( 55 workspace_size_(
44 gfx::Screen::GetMonitorAreaNearestWindow(contents_view_).size()), 56 gfx::Screen::GetMonitorAreaNearestWindow(contents_view_).size()),
45 is_overview_(false), 57 is_overview_(false),
46 layout_in_progress_(false),
47 ignored_window_(NULL) { 58 ignored_window_(NULL) {
48 DCHECK(contents_view); 59 DCHECK(contents_view);
49 } 60 }
50 61
51 WorkspaceManager::~WorkspaceManager() { 62 WorkspaceManager::~WorkspaceManager() {
63 for (size_t i = 0; i < workspaces_.size(); ++i) {
64 Workspace* workspace = workspaces_[i];
65 for (size_t j = 0; j < workspace->windows().size(); ++j)
66 workspace->windows()[j]->RemoveObserver(this);
67 }
52 std::vector<Workspace*> copy_to_delete(workspaces_); 68 std::vector<Workspace*> copy_to_delete(workspaces_);
53 STLDeleteElements(&copy_to_delete); 69 STLDeleteElements(&copy_to_delete);
54 } 70 }
55 71
56 Workspace* WorkspaceManager::CreateWorkspace() { 72 bool WorkspaceManager::IsManagedWindow(aura::Window* window) const {
57 Workspace* workspace = new Workspace(this); 73 return window->type() == aura::client::WINDOW_TYPE_NORMAL &&
58 LayoutWorkspaces(); 74 !window->transient_parent();
59 return workspace;
60 } 75 }
61 76
62 Workspace* WorkspaceManager::GetActiveWorkspace() const { 77 void WorkspaceManager::AddWindow(aura::Window* window) {
63 return active_workspace_; 78 DCHECK(IsManagedWindow(window));
79
80 if (FindBy(window))
81 return; // Already know about this window.
82
83 window->AddObserver(this);
84
85 if (!window->GetProperty(aura::client::kShowStateKey)) {
oshima 2012/01/26 16:37:25 window->HasProperty
86 // TODO: set maximized if width < x.
87 window->SetIntProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL);
88 }
89
90 // TODO: handle fullscreen.
91 if (window_util::IsWindowMaximized(window)) {
92 if (!GetRestoreBounds(window))
93 SetRestoreBounds(window, window->GetTargetBounds());
94 else
95 SetWindowBounds(window, GetWorkAreaBounds());
96 }
97
98 Workspace* workspace = NULL;
99 Workspace::Type type_for_window = Workspace::TypeForWindow(window);
100 switch (type_for_window) {
101 case Workspace::TYPE_SPLIT:
102 // Splits either go in current workspace (if maximized or split). If the
103 // current workspace isn't split/maximized, then create a maximized
104 // workspace.
105 workspace = GetActiveWorkspace();
106 if (workspace &&
107 (workspace->type() == Workspace::TYPE_SPLIT ||
108 workspace->type() == Workspace::TYPE_MAXIMIZED)) {
109 // TODO: this needs to reset bounds of any existing windows in
110 // workspace.
111 workspace->SetType(Workspace::TYPE_SPLIT);
112 } else {
113 type_for_window = Workspace::TYPE_MAXIMIZED;
114 workspace = NULL;
115 }
116 break;
117
118 case Workspace::TYPE_NORMAL:
119 // All normal windows go in the same workspace.
120 workspace = GetNormalWorkspace();
121 break;
122
123 case Workspace::TYPE_MAXIMIZED:
124 // All maximized windows go in their own workspace.
125 break;
126
127 default:
128 NOTREACHED();
129 break;
130 }
131
132 if (!workspace) {
133 workspace = CreateWorkspace();
134 workspace->SetType(type_for_window);
135 }
136 workspace->AddWindowAfter(window, NULL);
137 workspace->Activate();
64 } 138 }
65 139
66 Workspace* WorkspaceManager::FindBy(aura::Window* window) const { 140 void WorkspaceManager::RemoveWindow(aura::Window* window) {
67 int index = GetWorkspaceIndexContaining(window); 141 Workspace* workspace = FindBy(window);
68 return index < 0 ? NULL : workspaces_[index]; 142 if (!workspace)
143 return;
144 window->RemoveObserver(this);
145 workspace->RemoveWindow(window);
146 if (workspace->is_empty())
147 delete workspace;
69 } 148 }
70 149
71 aura::Window* WorkspaceManager::FindRotateWindowForLocation( 150 void WorkspaceManager::SetActiveWorkspaceByWindow(aura::Window* window) {
72 const gfx::Point& point) { 151 Workspace* workspace = FindBy(window);
73 for (Workspaces::const_iterator i = workspaces_.begin(); 152 if (workspace)
74 i != workspaces_.end(); 153 workspace->Activate();
75 ++i) {
76 aura::Window* window = (*i)->FindRotateWindowForLocation(point);
77 if (window)
78 return window;
79 }
80 return NULL;
81 }
82
83 void WorkspaceManager::LayoutWorkspaces() {
84 UpdateContentsView();
85
86 gfx::Rect bounds(workspace_size_);
87 int x = 0;
88 for (Workspaces::const_iterator i = workspaces_.begin();
89 i != workspaces_.end();
90 ++i) {
91 Workspace* workspace = *i;
92 bounds.set_x(x);
93 workspace->SetBounds(bounds);
94 x += bounds.width() + kWorkspaceHorizontalMargin;
95 }
96 } 154 }
97 155
98 gfx::Rect WorkspaceManager::GetDragAreaBounds() { 156 gfx::Rect WorkspaceManager::GetDragAreaBounds() {
99 return GetWorkAreaBounds(gfx::Rect(contents_view_->bounds().size())); 157 return GetWorkAreaBounds();
100 } 158 }
101 159
102 void WorkspaceManager::SetOverview(bool overview) { 160 void WorkspaceManager::SetOverview(bool overview) {
103 if (is_overview_ == overview) 161 if (is_overview_ == overview)
104 return; 162 return;
105 is_overview_ = overview; 163 NOTIMPLEMENTED();
106
107 ui::Transform transform;
108 if (is_overview_) {
109 // TODO(oshima|sky): We limit the how small windows can be shrinked
110 // in overview mode, thus part of the contents_view may not be visible.
111 // We need to add capability to scroll/move contents_view in overview mode.
112 float scale = std::min(
113 kMaxOverviewScale,
114 workspace_size_.width() /
115 static_cast<float>(contents_view_->bounds().width()));
116 scale = std::max(kMinOverviewScale, scale);
117
118 transform.SetScale(scale, scale);
119
120 int overview_width = contents_view_->bounds().width() * scale;
121 int dx = 0;
122 if (overview_width < workspace_size_.width()) {
123 dx = (workspace_size_.width() - overview_width) / 2;
124 } else if (active_workspace_) {
125 // Center the active workspace.
126 int active_workspace_mid_x = (active_workspace_->bounds().x() +
127 active_workspace_->bounds().width() / 2) * scale;
128 dx = workspace_size_.width() / 2 - active_workspace_mid_x;
129 dx = std::min(0, std::max(dx, workspace_size_.width() - overview_width));
130 }
131
132 transform.SetTranslateX(dx);
133 transform.SetTranslateY(workspace_size_.height() * (1.0f - scale) / 2);
134 } else if (active_workspace_) {
135 transform.SetTranslateX(-active_workspace_->bounds().x());
136 }
137
138 ui::ScopedLayerAnimationSettings settings(
139 contents_view_->layer()->GetAnimator());
140 contents_view_->layer()->SetTransform(transform);
141 }
142
143 void WorkspaceManager::RotateWindows(aura::Window* source,
144 aura::Window* target) {
145 DCHECK(source);
146 DCHECK(target);
147 int source_ws_index = GetWorkspaceIndexContaining(source);
148 int target_ws_index = GetWorkspaceIndexContaining(target);
149 DCHECK(source_ws_index >= 0);
150 DCHECK(target_ws_index >= 0);
151 if (source_ws_index == target_ws_index) {
152 workspaces_[source_ws_index]->RotateWindows(source, target);
153 } else {
154 aura::Window* insert = source;
155 aura::Window* target_to_insert = target;
156 if (source_ws_index < target_ws_index) {
157 for (int i = target_ws_index; i >= source_ws_index; --i) {
158 insert = workspaces_[i]->ShiftWindows(
159 insert, source, target_to_insert, Workspace::SHIFT_TO_LEFT);
160 // |target| can only be in the 1st workspace.
161 target_to_insert = NULL;
162 }
163 } else {
164 for (int i = target_ws_index; i <= source_ws_index; ++i) {
165 insert = workspaces_[i]->ShiftWindows(
166 insert, source, target_to_insert, Workspace::SHIFT_TO_RIGHT);
167 // |target| can only be in the 1st workspace.
168 target_to_insert = NULL;
169 }
170 }
171 }
172 FOR_EACH_OBSERVER(WorkspaceObserver, observers_,
173 WindowMoved(this, source, target));
174 workspaces_[target_ws_index]->Activate();
175 } 164 }
176 165
177 void WorkspaceManager::SetWorkspaceSize(const gfx::Size& workspace_size) { 166 void WorkspaceManager::SetWorkspaceSize(const gfx::Size& workspace_size) {
178 if (workspace_size == workspace_size_) 167 if (workspace_size == workspace_size_)
179 return; 168 return;
180 workspace_size_ = workspace_size; 169 workspace_size_ = workspace_size;
181 LayoutWorkspaces(); 170 for (Workspaces::const_iterator i = workspaces_.begin();
171 i != workspaces_.end(); ++i) {
172 (*i)->WorkspaceSizeChanged();
173 }
182 } 174 }
183 175
184 void WorkspaceManager::AddObserver(WorkspaceObserver* observer) { 176 void WorkspaceManager::OnWindowPropertyChanged(aura::Window* window,
185 observers_.AddObserver(observer); 177 const char* name,
186 } 178 void* old) {
179 if (!IsManagedWindow(window))
180 return;
187 181
188 void WorkspaceManager::RemoveObserver(WorkspaceObserver* observer) { 182 if (name != aura::client::kShowStateKey)
189 observers_.RemoveObserver(observer); 183 return;
184 // TODO: handle fullscreen.
185 bool is_maximized = window->GetIntProperty(name) == ui::SHOW_STATE_MAXIMIZED;
186 bool was_maximized =
187 (old == reinterpret_cast<void*>(ui::SHOW_STATE_MAXIMIZED));
188 if (is_maximized == was_maximized)
189 return;
190
191 MaximizedStateChanged(window);
190 } 192 }
191 193
192 //////////////////////////////////////////////////////////////////////////////// 194 ////////////////////////////////////////////////////////////////////////////////
193 // WorkspaceManager, private: 195 // WorkspaceManager, private:
194 196
195 void WorkspaceManager::AddWorkspace(Workspace* workspace) { 197 void WorkspaceManager::AddWorkspace(Workspace* workspace) {
196 Workspaces::iterator i = std::find(workspaces_.begin(), 198 DCHECK(std::find(workspaces_.begin(), workspaces_.end(),
197 workspaces_.end(), 199 workspace) == workspaces_.end());
198 workspace); 200 if (active_workspace_) {
199 DCHECK(i == workspaces_.end()); 201 // New workspaces go right after current workspace.
200 workspaces_.push_back(workspace); 202 Workspaces::iterator i = std::find(workspaces_.begin(), workspaces_.end(),
203 active_workspace_);
204 workspaces_.insert(++i, workspace);
205 } else {
206 workspaces_.push_back(workspace);
207 }
201 } 208 }
202 209
203 void WorkspaceManager::RemoveWorkspace(Workspace* workspace) { 210 void WorkspaceManager::RemoveWorkspace(Workspace* workspace) {
204 Workspaces::iterator i = std::find(workspaces_.begin(), 211 Workspaces::iterator i = std::find(workspaces_.begin(),
205 workspaces_.end(), 212 workspaces_.end(),
206 workspace); 213 workspace);
207 DCHECK(i != workspaces_.end()); 214 DCHECK(i != workspaces_.end());
208 Workspace* old = NULL; 215 i = workspaces_.erase(i);
209 216 if (active_workspace_ == workspace) {
210 if (workspace == active_workspace_) { 217 // TODO: need mru order.
211 old = active_workspace_; 218 if (i != workspaces_.end())
212 active_workspace_ = NULL; 219 SetActiveWorkspace(*i);
213 } 220 else if (!workspaces_.empty())
214 workspaces_.erase(i); 221 SetActiveWorkspace(workspaces_.back());
215 LayoutWorkspaces(); 222 else
216 223 active_workspace_ = NULL;
217 if (old) {
218 FOR_EACH_OBSERVER(WorkspaceObserver, observers_,
219 ActiveWorkspaceChanged(this, old));
220 } 224 }
221 } 225 }
222 226
227 Workspace* WorkspaceManager::CreateWorkspace() {
228 Workspace* workspace = new Workspace(this);
229 return workspace;
oshima 2012/01/26 16:37:25 return new Workspace(this);
sky 2012/01/26 16:51:23 Probably not worth a method now. I removed it enti
230 }
231
232 Workspace* WorkspaceManager::GetActiveWorkspace() const {
233 return active_workspace_;
234 }
235
236 Workspace* WorkspaceManager::FindBy(aura::Window* window) const {
237 int index = GetWorkspaceIndexContaining(window);
238 return index < 0 ? NULL : workspaces_[index];
239 }
240
223 void WorkspaceManager::SetActiveWorkspace(Workspace* workspace) { 241 void WorkspaceManager::SetActiveWorkspace(Workspace* workspace) {
224 if (active_workspace_ == workspace) 242 if (active_workspace_ == workspace)
225 return; 243 return;
226 DCHECK(std::find(workspaces_.begin(), workspaces_.end(), 244 DCHECK(std::find(workspaces_.begin(), workspaces_.end(),
227 workspace) != workspaces_.end()); 245 workspace) != workspaces_.end());
228 Workspace* old = active_workspace_; 246 if (active_workspace_)
247 SetWindowLayerVisibility(active_workspace_->windows(), false);
229 active_workspace_ = workspace; 248 active_workspace_ = workspace;
249 if (active_workspace_)
250 SetWindowLayerVisibility(active_workspace_->windows(), true);
230 251
231 is_overview_ = false; 252 is_overview_ = false;
232 UpdateContentsView();
233
234 FOR_EACH_OBSERVER(WorkspaceObserver, observers_,
235 ActiveWorkspaceChanged(this, old));
236 } 253 }
237 254
238 gfx::Rect WorkspaceManager::GetWorkAreaBounds( 255 gfx::Rect WorkspaceManager::GetWorkAreaBounds() {
239 const gfx::Rect& workspace_bounds) { 256 gfx::Rect bounds(workspace_size_);
240 gfx::Rect bounds = workspace_bounds;
241 bounds.Inset( 257 bounds.Inset(
242 aura::RootWindow::GetInstance()->screen()->work_area_insets()); 258 aura::RootWindow::GetInstance()->screen()->work_area_insets());
243 return bounds; 259 return bounds;
244 } 260 }
245 261
246 // Returns the index of the workspace that contains the |window|. 262 // Returns the index of the workspace that contains the |window|.
247 int WorkspaceManager::GetWorkspaceIndexContaining(aura::Window* window) const { 263 int WorkspaceManager::GetWorkspaceIndexContaining(aura::Window* window) const {
248 for (Workspaces::const_iterator i = workspaces_.begin(); 264 for (Workspaces::const_iterator i = workspaces_.begin();
249 i != workspaces_.end(); 265 i != workspaces_.end();
250 ++i) { 266 ++i) {
251 if ((*i)->Contains(window)) 267 if ((*i)->Contains(window))
252 return i - workspaces_.begin(); 268 return i - workspaces_.begin();
253 } 269 }
254 return -1; 270 return -1;
255 } 271 }
256 272
257 void WorkspaceManager::UpdateContentsView() { 273 void WorkspaceManager::SetWindowBounds(aura::Window* window,
258 int num_workspaces = std::max(1, static_cast<int>(workspaces_.size())); 274 const gfx::Rect& bounds) {
259 int total_width = workspace_size_.width() * num_workspaces + 275 // TODO: I suspect it's possible for this to be invoked when ignored_window_
260 kWorkspaceHorizontalMargin * (num_workspaces - 1); 276 // is non-NULL.
oshima 2012/01/26 16:37:25 It's possible, but it shouldn't happen, should it?
sky 2012/01/26 16:51:23 It's possible with the current WorkspaceLayoutMana
261 gfx::Rect bounds(0, 0, total_width, workspace_size_.height()); 277 ignored_window_ = window;
278 window->SetBounds(bounds);
279 ignored_window_ = NULL;
280 }
262 281
263 if (contents_view_->GetTargetBounds() != bounds) 282 void WorkspaceManager::SetWindowBoundsFromRestoreBounds(aura::Window* window) {
264 contents_view_->SetBounds(bounds); 283 Workspace* workspace = FindBy(window);
284 DCHECK(workspace);
285 const gfx::Rect* restore = GetRestoreBounds(window);
286 if (restore) {
287 SetWindowBounds(window,
288 restore->AdjustToFit(workspace->GetWorkAreaBounds()));
289 } else {
290 SetWindowBounds(window, window->bounds().AdjustToFit(
291 workspace->GetWorkAreaBounds()));
292 }
293 ash::ClearRestoreBounds(window);
294 }
265 295
266 // Move to active workspace. 296 void WorkspaceManager::MaximizedStateChanged(aura::Window* window) {
267 if (active_workspace_) { 297 DCHECK(IsManagedWindow(window));
268 ui::Transform transform; 298 bool is_maximized = window_util::IsWindowMaximized(window);
269 transform.SetTranslateX(-active_workspace_->bounds().x()); 299 Workspace* current_workspace = FindBy(window);
270 ui::ScopedLayerAnimationSettings settings( 300 DCHECK(current_workspace);
271 contents_view_->layer()->GetAnimator()); 301 if (is_maximized) {
272 contents_view_->SetTransform(transform); 302 // Unmaximized -> maximized; create a new workspace (unless current only has
303 // one window).
304 SetRestoreBounds(window, window->GetTargetBounds());
305 if (current_workspace->num_windows() != 1) {
306 current_workspace->RemoveWindow(window);
307 Workspace* workspace = CreateWorkspace();
308 workspace->SetType(Workspace::TYPE_MAXIMIZED);
309 workspace->AddWindowAfter(window, NULL);
310 current_workspace = workspace;
311 } else {
312 current_workspace->SetType(Workspace::TYPE_MAXIMIZED);
313 }
314 SetWindowBounds(window, GetWorkAreaBounds());
315 } else {
316 // Maximized -> unmaximized; move window to unmaximized workspace (or reuse
317 // current if there isn't one).
318 window_util::SetOpenWindowSplit(window, false);
319 Workspace* workspace = GetNormalWorkspace();
320 if (workspace) {
321 current_workspace->RemoveWindow(window);
322 DCHECK(current_workspace->is_empty());
323 workspace->AddWindowAfter(window, NULL);
324 delete current_workspace;
325 current_workspace = workspace;
326 } else {
327 current_workspace->SetType(Workspace::TYPE_NORMAL);
328 }
329
330 SetWindowBoundsFromRestoreBounds(window);
273 } 331 }
332
333 SetActiveWorkspace(FindBy(window));
oshima 2012/01/26 16:37:25 Can this be SetActiveWorksace(current_workspace) ?
334 }
335
336 Workspace* WorkspaceManager::GetNormalWorkspace() {
337 for (size_t i = 0; i < workspaces_.size(); ++i) {
338 if (workspaces_[i]->type() == Workspace::TYPE_NORMAL)
339 return workspaces_[i];
340 }
341 return NULL;
274 } 342 }
275 343
276 } // namespace internal 344 } // namespace internal
277 } // namespace ash 345 } // namespace ash
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698