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

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

Issue 11293014: Renames Workspace*2 -> Workspace*. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 8 years, 1 month 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
(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/workspace_layout_manager2.h"
6
7 #include "ash/ash_switches.h"
8 #include "ash/screen_ash.h"
9 #include "ash/shell.h"
10 #include "ash/wm/always_on_top_controller.h"
11 #include "ash/wm/base_layout_manager.h"
12 #include "ash/wm/window_animations.h"
13 #include "ash/wm/window_properties.h"
14 #include "ash/wm/window_util.h"
15 #include "ash/wm/workspace/workspace2.h"
16 #include "ash/wm/workspace/workspace_manager2.h"
17 #include "ash/wm/workspace/workspace_window_resizer.h"
18 #include "base/auto_reset.h"
19 #include "base/command_line.h"
20 #include "ui/aura/client/aura_constants.h"
21 #include "ui/aura/root_window.h"
22 #include "ui/aura/window.h"
23 #include "ui/aura/window_observer.h"
24 #include "ui/base/events/event.h"
25 #include "ui/base/ui_base_types.h"
26
27 using aura::Window;
28
29 namespace ash {
30
31 namespace internal {
32
33 namespace {
34
35 typedef std::map<const aura::Window*, gfx::Rect> BoundsMap;
36
37 // Adds an entry from |window| to its bounds and recursively invokes this for
38 // all children.
39 void BuildWindowBoundsMap(const aura::Window* window, BoundsMap* bounds_map) {
40 (*bounds_map)[window] = window->bounds();
41 for (size_t i = 0; i < window->children().size(); ++i)
42 BuildWindowBoundsMap(window->children()[i], bounds_map);
43 }
44
45 // Resets |window|s bounds from |bounds_map| if currently empty. Recusively
46 // invokes this for all children.
47 void ResetBoundsIfNecessary(const BoundsMap& bounds_map, aura::Window* window) {
48 if (window->bounds().IsEmpty() && window->GetTargetBounds().IsEmpty()) {
49 BoundsMap::const_iterator i = bounds_map.find(window);
50 if (i != bounds_map.end())
51 window->SetBounds(i->second);
52 }
53 for (size_t i = 0; i < window->children().size(); ++i)
54 ResetBoundsIfNecessary(bounds_map, window->children()[i]);
55 }
56
57 // Resets |window|s bounds from |bounds_map| if |window| is marked as a
58 // constrained window. Recusively invokes this for all children.
59 // TODO(sky): this should key off window type.
60 void ResetConstrainedWindowBoundsIfNecessary(const BoundsMap& bounds_map,
61 aura::Window* window) {
62 if (window->GetProperty(aura::client::kConstrainedWindowKey)) {
63 BoundsMap::const_iterator i = bounds_map.find(window);
64 if (i != bounds_map.end())
65 window->SetBounds(i->second);
66 }
67 for (size_t i = 0; i < window->children().size(); ++i)
68 ResetConstrainedWindowBoundsIfNecessary(bounds_map, window->children()[i]);
69 }
70
71 } // namespace
72
73 WorkspaceLayoutManager2::WorkspaceLayoutManager2(Workspace2* workspace)
74 : root_window_(workspace->window()->GetRootWindow()),
75 workspace_(workspace),
76 work_area_(ScreenAsh::GetDisplayWorkAreaBoundsInParent(
77 workspace->window()->parent())) {
78 Shell::GetInstance()->AddShellObserver(this);
79 root_window_->AddRootWindowObserver(this);
80 root_window_->AddObserver(this);
81 }
82
83 WorkspaceLayoutManager2::~WorkspaceLayoutManager2() {
84 if (root_window_) {
85 root_window_->RemoveObserver(this);
86 root_window_->RemoveRootWindowObserver(this);
87 }
88 for (WindowSet::const_iterator i = windows_.begin(); i != windows_.end(); ++i)
89 (*i)->RemoveObserver(this);
90 Shell::GetInstance()->RemoveShellObserver(this);
91 }
92
93 void WorkspaceLayoutManager2::OnWindowAddedToLayout(Window* child) {
94 // Adjust window bounds in case that the new child is out of the workspace.
95 AdjustWindowSizeForScreenChange(child, ADJUST_WINDOW_DISPLAY_INSETS_CHANGED);
96
97 windows_.insert(child);
98 child->AddObserver(this);
99
100 // Only update the bounds if the window has a show state that depends on the
101 // workspace area.
102 if (wm::IsWindowMaximized(child) || wm::IsWindowFullscreen(child))
103 UpdateBoundsFromShowState(child);
104
105 workspace_manager()->OnWindowAddedToWorkspace(workspace_, child);
106 }
107
108 void WorkspaceLayoutManager2::OnWillRemoveWindowFromLayout(Window* child) {
109 windows_.erase(child);
110 child->RemoveObserver(this);
111 workspace_manager()->OnWillRemoveWindowFromWorkspace(workspace_, child);
112 }
113
114 void WorkspaceLayoutManager2::OnWindowRemovedFromLayout(Window* child) {
115 workspace_manager()->OnWindowRemovedFromWorkspace(workspace_, child);
116 }
117
118 void WorkspaceLayoutManager2::OnChildWindowVisibilityChanged(Window* child,
119 bool visible) {
120 if (visible && wm::IsWindowMinimized(child)) {
121 // Attempting to show a minimized window. Unminimize it.
122 child->SetProperty(aura::client::kShowStateKey,
123 child->GetProperty(internal::kRestoreShowStateKey));
124 child->ClearProperty(internal::kRestoreShowStateKey);
125 }
126 workspace_manager()->OnWorkspaceChildWindowVisibilityChanged(workspace_,
127 child);
128 }
129
130 void WorkspaceLayoutManager2::SetChildBounds(
131 Window* child,
132 const gfx::Rect& requested_bounds) {
133 if (!GetTrackedByWorkspace(child)) {
134 SetChildBoundsDirect(child, requested_bounds);
135 return;
136 }
137 gfx::Rect child_bounds(requested_bounds);
138 // Some windows rely on this to set their initial bounds.
139 if (!SetMaximizedOrFullscreenBounds(child)) {
140 // Non-maximized/full-screen windows have their size constrained to the
141 // work-area.
142 child_bounds.set_width(std::min(work_area_.width(), child_bounds.width()));
143 child_bounds.set_height(
144 std::min(work_area_.height(), child_bounds.height()));
145 SetChildBoundsDirect(child, child_bounds);
146 }
147 workspace_manager()->OnWorkspaceWindowChildBoundsChanged(workspace_, child);
148 }
149
150 void WorkspaceLayoutManager2::OnRootWindowResized(const aura::RootWindow* root,
151 const gfx::Size& old_size) {
152 AdjustWindowSizesForScreenChange(ADJUST_WINDOW_SCREEN_SIZE_CHANGED);
153 }
154
155 void WorkspaceLayoutManager2::OnDisplayWorkAreaInsetsChanged() {
156 if (workspace_manager()->active_workspace_ == workspace_) {
157 const gfx::Rect work_area(ScreenAsh::GetDisplayWorkAreaBoundsInParent(
158 workspace_->window()->parent()));
159 if (work_area != work_area_)
160 AdjustWindowSizesForScreenChange(ADJUST_WINDOW_DISPLAY_INSETS_CHANGED);
161 }
162 }
163
164 void WorkspaceLayoutManager2::OnWindowPropertyChanged(Window* window,
165 const void* key,
166 intptr_t old) {
167 if (key == aura::client::kShowStateKey) {
168 ui::WindowShowState old_state = static_cast<ui::WindowShowState>(old);
169 ui::WindowShowState new_state =
170 window->GetProperty(aura::client::kShowStateKey);
171 if (old_state != ui::SHOW_STATE_MINIMIZED &&
172 GetRestoreBoundsInScreen(window) == NULL &&
173 WorkspaceManager2::IsMaximizedState(new_state) &&
174 !WorkspaceManager2::IsMaximizedState(old_state)) {
175 SetRestoreBoundsInParent(window, window->bounds());
176 }
177 // When restoring from a minimized state, we want to restore to the
178 // previous (maybe L/R maximized) state. Since we do also want to keep the
179 // restore rectangle, we set the restore rectangle to the rectangle we want
180 // to restore to and restore it after we switched so that it is preserved.
181 gfx::Rect restore;
182 if (old_state == ui::SHOW_STATE_MINIMIZED &&
183 (new_state == ui::SHOW_STATE_NORMAL ||
184 new_state == ui::SHOW_STATE_DEFAULT) &&
185 GetRestoreBoundsInScreen(window)) {
186 restore = *GetRestoreBoundsInScreen(window);
187 SetRestoreBoundsInScreen(window, window->bounds());
188 }
189
190 // If maximizing or restoring, clone the layer. WorkspaceManager will use it
191 // (and take ownership of it) when animating. Ideally we could use that of
192 // BaseLayoutManager, but that proves problematic. In particular when
193 // restoring we need to animate on top of the workspace animating in.
194 ui::Layer* cloned_layer = NULL;
195 BoundsMap bounds_map;
196 if (wm::IsActiveWindow(window) &&
197 ((WorkspaceManager2::IsMaximizedState(new_state) &&
198 wm::IsWindowStateNormal(old_state)) ||
199 (!WorkspaceManager2::IsMaximizedState(new_state) &&
200 WorkspaceManager2::IsMaximizedState(old_state) &&
201 new_state != ui::SHOW_STATE_MINIMIZED))) {
202 BuildWindowBoundsMap(window, &bounds_map);
203 cloned_layer = wm::RecreateWindowLayers(window, false);
204 // Constrained windows don't get their bounds reset when we update the
205 // window bounds. Leaving them empty is unexpected, so we reset them now.
206 ResetConstrainedWindowBoundsIfNecessary(bounds_map, window);
207 }
208 UpdateBoundsFromShowState(window);
209
210 if (cloned_layer) {
211 // Even though we just set the bounds not all descendants may have valid
212 // bounds. For example, constrained windows don't resize with the parent.
213 // Ensure that all windows that had a bounds before we cloned the layer
214 // have a bounds now.
215 ResetBoundsIfNecessary(bounds_map, window);
216 }
217
218 ShowStateChanged(window, old_state, cloned_layer);
219
220 // Set the restore rectangle to the previously set restore rectangle.
221 if (!restore.IsEmpty())
222 SetRestoreBoundsInScreen(window, restore);
223 }
224
225 if (key == internal::kWindowTrackedByWorkspaceKey &&
226 GetTrackedByWorkspace(window)) {
227 workspace_manager()->OnTrackedByWorkspaceChanged(workspace_, window);
228 }
229
230 if (key == aura::client::kAlwaysOnTopKey &&
231 window->GetProperty(aura::client::kAlwaysOnTopKey)) {
232 internal::AlwaysOnTopController* controller =
233 window->GetRootWindow()->GetProperty(
234 internal::kAlwaysOnTopControllerKey);
235 controller->GetContainer(window)->AddChild(window);
236 }
237 }
238
239 void WorkspaceLayoutManager2::OnWindowDestroying(aura::Window* window) {
240 if (root_window_ == window) {
241 root_window_->RemoveObserver(this);
242 root_window_ = NULL;
243 }
244 }
245
246 void WorkspaceLayoutManager2::ShowStateChanged(
247 Window* window,
248 ui::WindowShowState last_show_state,
249 ui::Layer* cloned_layer) {
250 if (wm::IsWindowMinimized(window)) {
251 DCHECK(!cloned_layer);
252 // Save the previous show state so that we can correctly restore it.
253 window->SetProperty(internal::kRestoreShowStateKey, last_show_state);
254 SetWindowVisibilityAnimationType(
255 window, WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE);
256 workspace_manager()->OnWorkspaceWindowShowStateChanged(
257 workspace_, window, last_show_state, NULL);
258 window->Hide();
259 if (wm::IsActiveWindow(window))
260 wm::DeactivateWindow(window);
261 } else {
262 if ((window->TargetVisibility() ||
263 last_show_state == ui::SHOW_STATE_MINIMIZED) &&
264 !window->layer()->visible()) {
265 // The layer may be hidden if the window was previously minimized. Make
266 // sure it's visible.
267 window->Show();
268 }
269 workspace_manager()->OnWorkspaceWindowShowStateChanged(
270 workspace_, window, last_show_state, cloned_layer);
271 }
272 }
273
274 void WorkspaceLayoutManager2::AdjustWindowSizesForScreenChange(
275 AdjustWindowReason reason) {
276 work_area_ = ScreenAsh::GetDisplayWorkAreaBoundsInParent(
277 workspace_->window()->parent());
278 // If a user plugs an external display into a laptop running Aura the
279 // display size will change. Maximized windows need to resize to match.
280 // We also do this when developers running Aura on a desktop manually resize
281 // the host window.
282 // We also need to do this when the work area insets changes.
283 for (WindowSet::const_iterator it = windows_.begin();
284 it != windows_.end();
285 ++it) {
286 AdjustWindowSizeForScreenChange(*it, reason);
287 }
288 }
289
290 void WorkspaceLayoutManager2::AdjustWindowSizeForScreenChange(
291 Window* window,
292 AdjustWindowReason reason) {
293 if (GetTrackedByWorkspace(window) &&
294 !SetMaximizedOrFullscreenBounds(window)) {
295 if (reason == ADJUST_WINDOW_SCREEN_SIZE_CHANGED) {
296 // The work area may be smaller than the full screen. Put as much of the
297 // window as possible within the display area.
298 gfx::Rect bounds = window->bounds();
299 bounds.AdjustToFit(work_area_);
300 window->SetBounds(bounds);
301 } else if (reason == ADJUST_WINDOW_DISPLAY_INSETS_CHANGED) {
302 // Make sure the window isn't bigger than the display work area and that
303 // at least a portion of it is visible.
304 gfx::Rect bounds = window->bounds();
305 bounds.set_width(std::min(bounds.width(), work_area_.width()));
306 bounds.set_height(std::min(bounds.height(), work_area_.height()));
307 if (!work_area_.Intersects(bounds)) {
308 int y_offset = 0;
309 if (work_area_.bottom() < bounds.y()) {
310 y_offset = work_area_.bottom() - bounds.y() - kMinimumOnScreenArea;
311 } else if (bounds.bottom() < work_area_.y()) {
312 y_offset = work_area_.y() - bounds.bottom() + kMinimumOnScreenArea;
313 }
314
315 int x_offset = 0;
316 if (work_area_.right() < bounds.x()) {
317 x_offset = work_area_.right() - bounds.x() - kMinimumOnScreenArea;
318 } else if (bounds.right() < work_area_.x()) {
319 x_offset = work_area_.x() - bounds.right() + kMinimumOnScreenArea;
320 }
321 bounds.Offset(x_offset, y_offset);
322 }
323 if (window->bounds() != bounds)
324 window->SetBounds(bounds);
325 }
326 }
327 }
328
329 void WorkspaceLayoutManager2::UpdateBoundsFromShowState(Window* window) {
330 // See comment in SetMaximizedOrFullscreenBounds() as to why we use parent in
331 // these calculation.
332 switch (window->GetProperty(aura::client::kShowStateKey)) {
333 case ui::SHOW_STATE_DEFAULT:
334 case ui::SHOW_STATE_NORMAL: {
335 const gfx::Rect* restore = GetRestoreBoundsInScreen(window);
336 if (restore) {
337 gfx::Rect bounds_in_parent =
338 ScreenAsh::ConvertRectFromScreen(window->parent()->parent(),
339 *restore);
340 SetChildBoundsDirect(
341 window,
342 BaseLayoutManager::BoundsWithScreenEdgeVisible(
343 window->parent()->parent(),
344 bounds_in_parent));
345 }
346 window->ClearProperty(aura::client::kRestoreBoundsKey);
347 break;
348 }
349
350 case ui::SHOW_STATE_MAXIMIZED:
351 case ui::SHOW_STATE_FULLSCREEN:
352 SetMaximizedOrFullscreenBounds(window);
353 break;
354
355 default:
356 break;
357 }
358 }
359
360 bool WorkspaceLayoutManager2::SetMaximizedOrFullscreenBounds(
361 aura::Window* window) {
362 if (!GetTrackedByWorkspace(window))
363 return false;
364
365 // During animations there is a transform installed on the workspace
366 // windows. For this reason this code uses the parent so that the transform is
367 // ignored.
368 if (wm::IsWindowMaximized(window)) {
369 SetChildBoundsDirect(
370 window, ScreenAsh::GetMaximizedWindowBoundsInParent(
371 window->parent()->parent()));
372 return true;
373 }
374 if (wm::IsWindowFullscreen(window)) {
375 SetChildBoundsDirect(
376 window,
377 ScreenAsh::GetDisplayBoundsInParent(window->parent()->parent()));
378 return true;
379 }
380 return false;
381 }
382
383 WorkspaceManager2* WorkspaceLayoutManager2::workspace_manager() {
384 return workspace_->workspace_manager();
385 }
386
387 } // namespace internal
388 } // namespace ash
OLDNEW
« no previous file with comments | « ash/wm/workspace/workspace_layout_manager2.h ('k') | ash/wm/workspace/workspace_layout_manager2_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698