OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 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 "ui/aura_shell/workspace/workspace_manager.h" | |
6 | |
7 #include <algorithm> | |
8 | |
9 #include "base/auto_reset.h" | |
10 #include "base/logging.h" | |
11 #include "base/stl_util.h" | |
12 #include "ui/aura/root_window.h" | |
13 #include "ui/aura/screen_aura.h" | |
14 #include "ui/aura/window.h" | |
15 #include "ui/aura_shell/workspace/workspace.h" | |
16 #include "ui/aura_shell/workspace/workspace_observer.h" | |
17 #include "ui/gfx/compositor/layer.h" | |
18 #include "ui/gfx/compositor/layer_animator.h" | |
19 #include "ui/gfx/screen.h" | |
20 #include "ui/gfx/transform.h" | |
21 | |
22 namespace { | |
23 | |
24 // The horizontal margein between workspaces in pixels. | |
25 const int kWorkspaceHorizontalMargin = 50; | |
26 | |
27 // Minimum/maximum scale for overview mode. | |
28 const float kMaxOverviewScale = 0.9f; | |
29 const float kMinOverviewScale = 0.3f; | |
30 | |
31 } | |
32 | |
33 namespace aura_shell { | |
34 namespace internal { | |
35 | |
36 //////////////////////////////////////////////////////////////////////////////// | |
37 // WindowManager, public: | |
38 | |
39 WorkspaceManager::WorkspaceManager(aura::Window* contents_view) | |
40 : contents_view_(contents_view), | |
41 active_workspace_(NULL), | |
42 workspace_size_( | |
43 gfx::Screen::GetMonitorAreaNearestWindow(contents_view_).size()), | |
44 is_overview_(false), | |
45 layout_in_progress_(false), | |
46 ignored_window_(NULL) { | |
47 DCHECK(contents_view); | |
48 } | |
49 | |
50 WorkspaceManager::~WorkspaceManager() { | |
51 std::vector<Workspace*> copy_to_delete(workspaces_); | |
52 STLDeleteElements(©_to_delete); | |
53 } | |
54 | |
55 Workspace* WorkspaceManager::CreateWorkspace() { | |
56 Workspace* workspace = new Workspace(this); | |
57 LayoutWorkspaces(); | |
58 return workspace; | |
59 } | |
60 | |
61 Workspace* WorkspaceManager::GetActiveWorkspace() const { | |
62 return active_workspace_; | |
63 } | |
64 | |
65 Workspace* WorkspaceManager::FindBy(aura::Window* window) const { | |
66 int index = GetWorkspaceIndexContaining(window); | |
67 return index < 0 ? NULL : workspaces_[index]; | |
68 } | |
69 | |
70 aura::Window* WorkspaceManager::FindRotateWindowForLocation( | |
71 const gfx::Point& point) { | |
72 for (Workspaces::const_iterator i = workspaces_.begin(); | |
73 i != workspaces_.end(); | |
74 ++i) { | |
75 aura::Window* window = (*i)->FindRotateWindowForLocation(point); | |
76 if (window) | |
77 return window; | |
78 } | |
79 return NULL; | |
80 } | |
81 | |
82 void WorkspaceManager::LayoutWorkspaces() { | |
83 UpdateContentsView(); | |
84 | |
85 gfx::Rect bounds(workspace_size_); | |
86 int x = 0; | |
87 for (Workspaces::const_iterator i = workspaces_.begin(); | |
88 i != workspaces_.end(); | |
89 ++i) { | |
90 Workspace* workspace = *i; | |
91 bounds.set_x(x); | |
92 workspace->SetBounds(bounds); | |
93 x += bounds.width() + kWorkspaceHorizontalMargin; | |
94 } | |
95 } | |
96 | |
97 gfx::Rect WorkspaceManager::GetDragAreaBounds() { | |
98 return GetWorkAreaBounds(gfx::Rect(contents_view_->bounds().size())); | |
99 } | |
100 | |
101 void WorkspaceManager::SetOverview(bool overview) { | |
102 if (is_overview_ == overview) | |
103 return; | |
104 is_overview_ = overview; | |
105 | |
106 ui::Transform transform; | |
107 if (is_overview_) { | |
108 // TODO(oshima|sky): We limit the how small windows can be shrinked | |
109 // in overview mode, thus part of the contents_view may not be visible. | |
110 // We need to add capability to scroll/move contents_view in overview mode. | |
111 float scale = std::min( | |
112 kMaxOverviewScale, | |
113 workspace_size_.width() / | |
114 static_cast<float>(contents_view_->bounds().width())); | |
115 scale = std::max(kMinOverviewScale, scale); | |
116 | |
117 transform.SetScale(scale, scale); | |
118 | |
119 int overview_width = contents_view_->bounds().width() * scale; | |
120 int dx = 0; | |
121 if (overview_width < workspace_size_.width()) { | |
122 dx = (workspace_size_.width() - overview_width) / 2; | |
123 } else if (active_workspace_) { | |
124 // Center the active workspace. | |
125 int active_workspace_mid_x = (active_workspace_->bounds().x() + | |
126 active_workspace_->bounds().width() / 2) * scale; | |
127 dx = workspace_size_.width() / 2 - active_workspace_mid_x; | |
128 dx = std::min(0, std::max(dx, workspace_size_.width() - overview_width)); | |
129 } | |
130 | |
131 transform.SetTranslateX(dx); | |
132 transform.SetTranslateY(workspace_size_.height() * (1.0f - scale) / 2); | |
133 } else if (active_workspace_) { | |
134 transform.SetTranslateX(-active_workspace_->bounds().x()); | |
135 } | |
136 | |
137 ui::LayerAnimator::ScopedSettings settings( | |
138 contents_view_->layer()->GetAnimator()); | |
139 contents_view_->layer()->SetTransform(transform); | |
140 } | |
141 | |
142 void WorkspaceManager::RotateWindows(aura::Window* source, | |
143 aura::Window* target) { | |
144 DCHECK(source); | |
145 DCHECK(target); | |
146 int source_ws_index = GetWorkspaceIndexContaining(source); | |
147 int target_ws_index = GetWorkspaceIndexContaining(target); | |
148 DCHECK(source_ws_index >= 0); | |
149 DCHECK(target_ws_index >= 0); | |
150 if (source_ws_index == target_ws_index) { | |
151 workspaces_[source_ws_index]->RotateWindows(source, target); | |
152 } else { | |
153 aura::Window* insert = source; | |
154 aura::Window* target_to_insert = target; | |
155 if (source_ws_index < target_ws_index) { | |
156 for (int i = target_ws_index; i >= source_ws_index; --i) { | |
157 insert = workspaces_[i]->ShiftWindows( | |
158 insert, source, target_to_insert, Workspace::SHIFT_TO_LEFT); | |
159 // |target| can only be in the 1st workspace. | |
160 target_to_insert = NULL; | |
161 } | |
162 } else { | |
163 for (int i = target_ws_index; i <= source_ws_index; ++i) { | |
164 insert = workspaces_[i]->ShiftWindows( | |
165 insert, source, target_to_insert, Workspace::SHIFT_TO_RIGHT); | |
166 // |target| can only be in the 1st workspace. | |
167 target_to_insert = NULL; | |
168 } | |
169 } | |
170 } | |
171 FOR_EACH_OBSERVER(WorkspaceObserver, observers_, | |
172 WindowMoved(this, source, target)); | |
173 workspaces_[target_ws_index]->Activate(); | |
174 } | |
175 | |
176 void WorkspaceManager::SetWorkspaceSize(const gfx::Size& workspace_size) { | |
177 if (workspace_size == workspace_size_) | |
178 return; | |
179 workspace_size_ = workspace_size; | |
180 LayoutWorkspaces(); | |
181 } | |
182 | |
183 void WorkspaceManager::AddObserver(WorkspaceObserver* observer) { | |
184 observers_.AddObserver(observer); | |
185 } | |
186 | |
187 void WorkspaceManager::RemoveObserver(WorkspaceObserver* observer) { | |
188 observers_.RemoveObserver(observer); | |
189 } | |
190 | |
191 //////////////////////////////////////////////////////////////////////////////// | |
192 // WorkspaceManager, private: | |
193 | |
194 void WorkspaceManager::AddWorkspace(Workspace* workspace) { | |
195 Workspaces::iterator i = std::find(workspaces_.begin(), | |
196 workspaces_.end(), | |
197 workspace); | |
198 DCHECK(i == workspaces_.end()); | |
199 workspaces_.push_back(workspace); | |
200 } | |
201 | |
202 void WorkspaceManager::RemoveWorkspace(Workspace* workspace) { | |
203 Workspaces::iterator i = std::find(workspaces_.begin(), | |
204 workspaces_.end(), | |
205 workspace); | |
206 DCHECK(i != workspaces_.end()); | |
207 Workspace* old = NULL; | |
208 | |
209 if (workspace == active_workspace_) { | |
210 old = active_workspace_; | |
211 active_workspace_ = NULL; | |
212 } | |
213 workspaces_.erase(i); | |
214 LayoutWorkspaces(); | |
215 | |
216 if (old) { | |
217 FOR_EACH_OBSERVER(WorkspaceObserver, observers_, | |
218 ActiveWorkspaceChanged(this, old)); | |
219 } | |
220 } | |
221 | |
222 void WorkspaceManager::SetActiveWorkspace(Workspace* workspace) { | |
223 if (active_workspace_ == workspace) | |
224 return; | |
225 DCHECK(std::find(workspaces_.begin(), workspaces_.end(), | |
226 workspace) != workspaces_.end()); | |
227 Workspace* old = active_workspace_; | |
228 active_workspace_ = workspace; | |
229 | |
230 is_overview_ = false; | |
231 UpdateContentsView(); | |
232 | |
233 FOR_EACH_OBSERVER(WorkspaceObserver, observers_, | |
234 ActiveWorkspaceChanged(this, old)); | |
235 } | |
236 | |
237 gfx::Rect WorkspaceManager::GetWorkAreaBounds( | |
238 const gfx::Rect& workspace_bounds) { | |
239 gfx::Rect bounds = workspace_bounds; | |
240 bounds.Inset( | |
241 aura::RootWindow::GetInstance()->screen()->work_area_insets()); | |
242 return bounds; | |
243 } | |
244 | |
245 // Returns the index of the workspace that contains the |window|. | |
246 int WorkspaceManager::GetWorkspaceIndexContaining(aura::Window* window) const { | |
247 for (Workspaces::const_iterator i = workspaces_.begin(); | |
248 i != workspaces_.end(); | |
249 ++i) { | |
250 if ((*i)->Contains(window)) | |
251 return i - workspaces_.begin(); | |
252 } | |
253 return -1; | |
254 } | |
255 | |
256 void WorkspaceManager::UpdateContentsView() { | |
257 int num_workspaces = std::max(1, static_cast<int>(workspaces_.size())); | |
258 int total_width = workspace_size_.width() * num_workspaces + | |
259 kWorkspaceHorizontalMargin * (num_workspaces - 1); | |
260 gfx::Rect bounds(0, 0, total_width, workspace_size_.height()); | |
261 | |
262 if (contents_view_->GetTargetBounds() != bounds) | |
263 contents_view_->SetBounds(bounds); | |
264 | |
265 // Move to active workspace. | |
266 if (active_workspace_) { | |
267 ui::Transform transform; | |
268 transform.SetTranslateX(-active_workspace_->bounds().x()); | |
269 ui::LayerAnimator::ScopedSettings settings( | |
270 contents_view_->layer()->GetAnimator()); | |
271 contents_view_->SetTransform(transform); | |
272 } | |
273 } | |
274 | |
275 } // namespace internal | |
276 } // namespace aura_shell | |
OLD | NEW |