OLD | NEW |
---|---|
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_manager2.h" | 5 #include "ash/wm/workspace/workspace_manager2.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 | 9 |
10 #include "ash/root_window_controller.h" | 10 #include "ash/root_window_controller.h" |
11 #include "ash/shell.h" | 11 #include "ash/shell.h" |
12 #include "ash/shell_window_ids.h" | 12 #include "ash/shell_window_ids.h" |
13 #include "ash/wm/base_layout_manager.h" | 13 #include "ash/wm/base_layout_manager.h" |
14 #include "ash/wm/property_util.h" | 14 #include "ash/wm/property_util.h" |
15 #include "ash/wm/shelf_layout_manager.h" | 15 #include "ash/wm/shelf_layout_manager.h" |
16 #include "ash/wm/window_animations.h" | 16 #include "ash/wm/window_animations.h" |
17 #include "ash/wm/window_cycle_controller.h" | |
17 #include "ash/wm/window_properties.h" | 18 #include "ash/wm/window_properties.h" |
18 #include "ash/wm/window_util.h" | 19 #include "ash/wm/window_util.h" |
19 #include "ash/wm/workspace/workspace_layout_manager2.h" | 20 #include "ash/wm/workspace/workspace_layout_manager2.h" |
20 #include "ash/wm/workspace/workspace2.h" | 21 #include "ash/wm/workspace/workspace2.h" |
21 #include "base/auto_reset.h" | 22 #include "base/auto_reset.h" |
22 #include "base/command_line.h" | 23 #include "base/command_line.h" |
23 #include "base/logging.h" | 24 #include "base/logging.h" |
24 #include "base/stl_util.h" | 25 #include "base/stl_util.h" |
25 #include "base/stringprintf.h" | 26 #include "base/stringprintf.h" |
26 #include "ui/aura/client/aura_constants.h" | 27 #include "ui/aura/client/aura_constants.h" |
27 #include "ui/aura/root_window.h" | 28 #include "ui/aura/root_window.h" |
28 #include "ui/aura/window.h" | 29 #include "ui/aura/window.h" |
29 #include "ui/aura/window_property.h" | 30 #include "ui/aura/window_property.h" |
30 #include "ui/base/ui_base_types.h" | 31 #include "ui/base/ui_base_types.h" |
31 #include "ui/compositor/layer.h" | 32 #include "ui/compositor/layer.h" |
32 #include "ui/compositor/layer_animator.h" | 33 #include "ui/compositor/layer_animator.h" |
34 #include "ui/compositor/scoped_layer_animation_settings.h" | |
35 #include "ui/gfx/screen.h" | |
33 | 36 |
34 DECLARE_WINDOW_PROPERTY_TYPE(ash::internal::Workspace2*); | 37 DECLARE_WINDOW_PROPERTY_TYPE(ash::internal::Workspace2*); |
35 | 38 |
36 using aura::Window; | 39 using aura::Window; |
37 | 40 |
38 namespace ash { | 41 namespace ash { |
39 namespace internal { | 42 namespace internal { |
40 | 43 |
41 DEFINE_WINDOW_PROPERTY_KEY(Workspace2*, kWorkspaceKey, NULL); | 44 DEFINE_WINDOW_PROPERTY_KEY(Workspace2*, kWorkspaceKey, NULL); |
42 | 45 |
43 namespace { | 46 namespace { |
44 | 47 |
48 // The time which should be used to visually move a window through an | |
49 // automatic "intelligent" window management option. | |
50 const base::TimeDelta kWindowAutoMoveDuration = | |
sky
2012/10/11 19:50:54
Move all this logic out of this class. Maybe into
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Done.
| |
51 base::TimeDelta::FromMilliseconds(125); | |
52 | |
53 // Check if the given |window| has an impact on position manageability since it | |
54 // occupies screen space. Note: The minimized state is not included in this | |
sky
2012/10/11 19:50:54
'since it occupies screen space'?
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Hmm. Yeah, Somehow I have re-written this comment
| |
55 // test since a window which just got minimized might have an impact on the | |
56 // window ordering. | |
57 bool HasWindowImpactOnPositionManaging(const aura::Window* window) { | |
sky
2012/10/11 19:50:54
Name this WindowHasImpactOnPositioning
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Done.
| |
58 return (!wm::IsWindowMaximized(window) && | |
sky
2012/10/11 19:50:54
Don't you need to check visibility here? And why t
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Visibility check: Made sense, so I have tried it a
sky
2012/10/12 14:27:04
Can you point me at a test where what I have sugge
Mr4D (OOO till 08-26)
2012/10/12 23:21:30
Because when switching from maximize to minimize i
| |
59 !window->bounds().IsEmpty() && | |
60 wm::IsWindowPositionManageable(window)); | |
61 } | |
62 | |
63 // Check if a given |window| is considered to be an auto location manageable | |
64 // window or not. | |
65 bool IsWindowPositionManageable(const aura::Window* window) { | |
66 return (HasWindowImpactOnPositionManaging(window) && | |
67 !wm::IsWindowMinimized(window) && | |
68 !wm::HasUserChangedWindowPositionOrSize(window)); | |
69 } | |
70 | |
71 // Given a |window|, return the |work_area| of the desktop on which it is | |
72 // located as well as the only |other_window| which has an impact on the | |
73 // automated window location management. If there are more then one windows, | |
74 // false get returned, but the |other_window| will be set to the first one | |
75 // found. | |
76 // If the return value is true a single window was found. | |
77 // Note: |work_area| is undefined if false is returned and |other_window| is | |
78 // NULL. | |
79 bool GetOtherVisibleAndManageableWindow(const aura::Window* window, | |
80 gfx::Rect* work_area, | |
81 aura::Window** other_window) { | |
82 *other_window = NULL; | |
83 // If the given window was not manageable, it cannot have caused a management | |
84 // operation earlier. | |
85 if (!HasWindowImpactOnPositionManaging(window)) | |
86 return false; | |
87 | |
88 const std::vector<aura::Window*> windows = | |
89 ash::WindowCycleController::BuildWindowList(NULL); | |
90 | |
91 if (windows.empty()) | |
92 return false; | |
93 | |
94 // Get our work area. | |
95 *work_area = window->parent()->bounds(); | |
96 work_area->Inset(gfx::Screen::GetDisplayMatching( | |
97 *work_area).GetWorkAreaInsets()); | |
98 | |
99 // Find a single open browser window. | |
100 for (size_t i = 0; i < windows.size(); i++) { | |
101 aura::Window* j = windows[i]; | |
102 if (j && window != j && | |
sky
2012/10/11 19:50:54
You should not need a check for validity of j.
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Done.
| |
103 j->type() == aura::client::WINDOW_TYPE_NORMAL && | |
104 work_area->Intersects(j->GetBoundsInScreen()) && | |
sky
2012/10/11 19:50:54
Why the work_area check?
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
To make sure that the window is on this screen (an
sky
2012/10/12 14:27:04
Actually, why are you using the WindowCycleControl
Mr4D (OOO till 08-26)
2012/10/12 23:21:30
I thought it might be better to only include "note
| |
105 j->IsVisible() && HasWindowImpactOnPositionManaging(j)) { | |
106 // Bail if we find a second usable window. | |
107 if (*other_window) | |
108 return false; | |
109 *other_window = j; | |
110 } | |
111 } | |
112 return *other_window != NULL; | |
113 } | |
114 | |
115 // Move the given |bounds| on the available |work_area_width| to the | |
sky
2012/10/11 19:50:54
work_area_width is a misleading name since it isn'
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Done.
| |
116 // direction. If |move_right| is true, the rectangle gets moved to the right | |
117 // corner, otherwise to the left one. | |
118 bool MoveRect(int work_area_width, gfx::Rect& bounds, bool move_right) { | |
sky
2012/10/11 19:50:54
MoveRect is an extremely generic name. How about M
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Named it "MoveRectToOneSide". Done.
| |
119 if (move_right) { | |
120 if (work_area_width > bounds.right()) { | |
121 bounds.set_x(work_area_width - bounds.width()); | |
122 return true; | |
123 } | |
124 } else { | |
125 if (0 < bounds.x()) { | |
126 bounds.set_x(0); | |
127 return true; | |
128 } | |
129 } | |
130 return false; | |
131 } | |
132 | |
133 // Check if after removal of the given |removed_window| an automated desktop | |
134 // location management can be performed and rearrange accordingly | |
135 void RearrangeVisibleWindowOnRemove(const aura::Window* removed_window) { | |
136 // Find a single open browser window. | |
137 aura::Window* shown_window = NULL; | |
138 gfx::Rect work_area; | |
139 if (!GetOtherVisibleAndManageableWindow(removed_window, | |
140 &work_area, | |
141 &shown_window)) | |
142 return; | |
143 | |
144 if (shown_window && IsWindowPositionManageable(shown_window)) { | |
sky
2012/10/11 19:50:54
Why the shown_window test? Doesn't GetOtherVisible
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Sorry. My kind of defensive programming. Done.
| |
145 // Center the window (only in x). | |
146 gfx::Rect bounds = shown_window->bounds(); | |
147 bounds.set_x((work_area.width() - bounds.width()) / 2); | |
148 ui::LayerAnimator* animator = shown_window->layer()->GetAnimator(); | |
149 animator->set_preemption_strategy( | |
sky
2012/10/11 19:50:54
Why are you setting the preemption_strategy?
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Because I have seen it being used in a comparable
sky
2012/10/12 14:27:04
You need to investigate this. There should be no n
Mr4D (OOO till 08-26)
2012/10/12 23:21:30
Yes, I investigated it for 2.5 hours and it was ex
| |
150 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
151 | |
152 ui::ScopedLayerAnimationSettings animation_setter(animator); | |
153 animation_setter.SetTransitionDuration(kWindowAutoMoveDuration); | |
154 | |
155 shown_window->SetBounds(bounds); | |
156 } | |
157 } | |
158 | |
159 // Check if after insertion of the given |added_window| an automated desktop | |
160 // location management can be performed and rearrange accordingly. | |
161 void RearrangeVisibleWindowOnJoining(aura::Window* added_window) { | |
sky
2012/10/11 19:50:54
How about RearrangeVisibleWindowOnShow and Rearran
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Done.
| |
162 // Find a single open browser window. | |
163 aura::Window* shown_window = NULL; | |
164 gfx::Rect work_area; | |
165 if (!GetOtherVisibleAndManageableWindow(added_window, | |
166 &work_area, | |
167 &shown_window)) { | |
168 // It could be that this window is the first window joining the workspace. | |
169 if (!IsWindowPositionManageable(added_window) || shown_window) | |
sky
2012/10/11 19:50:54
How could shown_window be non-null here?
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Read the comment for GetOtherVisibleAndManageableW
| |
170 return; | |
171 // If so we have to make sure it is centered. | |
172 gfx::Rect bounds = added_window->bounds(); | |
173 bounds.set_x((work_area.width() - bounds.width()) / 2); | |
174 added_window->SetBounds(bounds); | |
175 return; | |
176 } | |
177 | |
178 if (shown_window && IsWindowPositionManageable(shown_window)) { | |
179 // Push away the other window. | |
180 gfx::Rect other_bounds = shown_window->bounds(); | |
181 bool move_right = other_bounds.CenterPoint().x() < work_area.width() / 2; | |
182 if (MoveRect(work_area.width(), other_bounds, move_right)) { | |
183 ui::LayerAnimator* animator = shown_window->layer()->GetAnimator(); | |
184 animator->set_preemption_strategy( | |
185 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); | |
186 | |
187 ui::ScopedLayerAnimationSettings animation_setter(animator); | |
188 animation_setter.SetTransitionDuration(kWindowAutoMoveDuration); | |
189 shown_window->SetBounds(other_bounds); | |
190 } | |
191 // Push the new window also to the opposite location (if needed). | |
192 // Since it is just coming into view, we do not need to animate it. | |
193 gfx::Rect added_bounds = added_window->bounds(); | |
194 if (MoveRect(work_area.width(), added_bounds, !move_right)) | |
195 added_window->SetBounds(added_bounds); | |
196 } | |
197 } | |
198 | |
45 // Changes the parent of |window| and all its transient children to | 199 // Changes the parent of |window| and all its transient children to |
46 // |new_parent|. If |stack_beneach| is non-NULL all the windows are stacked | 200 // |new_parent|. If |stack_beneach| is non-NULL all the windows are stacked |
47 // beneath it. | 201 // beneath it. |
48 void ReparentWindow(Window* window, | 202 void ReparentWindow(Window* window, |
49 Window* new_parent, | 203 Window* new_parent, |
50 Window* stack_beneath) { | 204 Window* stack_beneath) { |
51 window->SetParent(new_parent); | 205 window->SetParent(new_parent); |
52 if (stack_beneath) | 206 if (stack_beneath) |
53 new_parent->StackChildBelow(window, stack_beneath); | 207 new_parent->StackChildBelow(window, stack_beneath); |
54 for (size_t i = 0; i < window->transient_children().size(); ++i) | 208 for (size_t i = 0; i < window->transient_children().size(); ++i) |
(...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
483 // Do nothing (other than updating shelf visibility) as the right parent was | 637 // Do nothing (other than updating shelf visibility) as the right parent was |
484 // chosen by way of GetParentForNewWindow() or we explicitly moved the window | 638 // chosen by way of GetParentForNewWindow() or we explicitly moved the window |
485 // to the workspace. | 639 // to the workspace. |
486 if (workspace == active_workspace_) | 640 if (workspace == active_workspace_) |
487 UpdateShelfVisibility(); | 641 UpdateShelfVisibility(); |
488 } | 642 } |
489 | 643 |
490 void WorkspaceManager2::OnWillRemoveWindowFromWorkspace(Workspace2* workspace, | 644 void WorkspaceManager2::OnWillRemoveWindowFromWorkspace(Workspace2* workspace, |
491 Window* child) { | 645 Window* child) { |
492 child->ClearProperty(kWorkspaceKey); | 646 child->ClearProperty(kWorkspaceKey); |
647 RearrangeVisibleWindowOnRemove(child); | |
493 } | 648 } |
494 | 649 |
495 void WorkspaceManager2::OnWindowRemovedFromWorkspace(Workspace2* workspace, | 650 void WorkspaceManager2::OnWindowRemovedFromWorkspace(Workspace2* workspace, |
496 Window* child) { | 651 Window* child) { |
497 if (workspace->ShouldMoveToPending()) | 652 if (workspace->ShouldMoveToPending()) |
498 MoveWorkspaceToPendingOrDelete(workspace, NULL, ANIMATE_NEW); | 653 MoveWorkspaceToPendingOrDelete(workspace, NULL, ANIMATE_NEW); |
499 } | 654 } |
500 | 655 |
501 void WorkspaceManager2::OnWorkspaceChildWindowVisibilityChanged( | 656 void WorkspaceManager2::OnWorkspaceChildWindowVisibilityChanged( |
502 Workspace2* workspace, | 657 Workspace2* workspace, |
503 Window* child) { | 658 Window* child) { |
504 if (workspace->ShouldMoveToPending()) | 659 if (workspace->ShouldMoveToPending()) |
505 MoveWorkspaceToPendingOrDelete(workspace, NULL, ANIMATE_NEW); | 660 MoveWorkspaceToPendingOrDelete(workspace, NULL, ANIMATE_NEW); |
506 else if (workspace == active_workspace_) | 661 else if (workspace == active_workspace_) { |
507 UpdateShelfVisibility(); | 662 UpdateShelfVisibility(); |
663 if (child->IsVisible()) | |
sky
2012/10/11 19:50:54
Why make this depend upon whether the workspace is
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
There are two reasons:
1.) (the logical one) Why s
sky
2012/10/12 14:27:04
You should rearrange in the desktop the window is
Mr4D (OOO till 08-26)
2012/10/12 23:21:30
Changed the algorithm from my "on access" method t
| |
664 RearrangeVisibleWindowOnJoining(child); | |
665 else | |
666 RearrangeVisibleWindowOnRemove(child); | |
667 } | |
508 } | 668 } |
509 | 669 |
510 void WorkspaceManager2::OnWorkspaceWindowChildBoundsChanged( | 670 void WorkspaceManager2::OnWorkspaceWindowChildBoundsChanged( |
511 Workspace2* workspace, | 671 Workspace2* workspace, |
512 Window* child) { | 672 Window* child) { |
513 if (workspace == active_workspace_) | 673 if (workspace == active_workspace_) |
514 UpdateShelfVisibility(); | 674 UpdateShelfVisibility(); |
515 } | 675 } |
516 | 676 |
517 void WorkspaceManager2::OnWorkspaceWindowShowStateChanged( | 677 void WorkspaceManager2::OnWorkspaceWindowShowStateChanged( |
518 Workspace2* workspace, | 678 Workspace2* workspace, |
519 Window* child, | 679 Window* child, |
520 ui::WindowShowState last_show_state, | 680 ui::WindowShowState last_show_state, |
521 ui::Layer* old_layer) { | 681 ui::Layer* old_layer) { |
522 // |child| better still be in |workspace| else things have gone wrong. | 682 // |child| better still be in |workspace| else things have gone wrong. |
523 DCHECK_EQ(workspace, child->GetProperty(kWorkspaceKey)); | 683 DCHECK_EQ(workspace, child->GetProperty(kWorkspaceKey)); |
524 if (wm::IsWindowMinimized(child)) { | 684 if (wm::IsWindowMinimized(child)) { |
525 if (workspace->ShouldMoveToPending()) | 685 if (workspace->ShouldMoveToPending()) |
526 MoveWorkspaceToPendingOrDelete(workspace, NULL, ANIMATE_NEW); | 686 MoveWorkspaceToPendingOrDelete(workspace, NULL, ANIMATE_NEW); |
687 // When a window gets minimized, we have to re-arrange the visible windows | |
688 // here. This especially applies when you have two normal windows, maximize | |
689 // one and then minimize it. The other window on the desktop needs then to | |
690 // get centered. | |
691 RearrangeVisibleWindowOnRemove(child); | |
sky
2012/10/11 19:50:54
Minimize also results in OnWorkspaceChildWindowVis
Mr4D (OOO till 08-26)
2012/10/12 00:29:18
Yes I am. I was fixing several special cases I hav
sky
2012/10/12 14:27:04
Can you point me at the tests that fail when this
Mr4D (OOO till 08-26)
2012/10/12 23:21:30
Removed.
| |
527 DCHECK(!old_layer); | 692 DCHECK(!old_layer); |
528 } else { | 693 } else { |
529 // Set of cases to deal with: | 694 // Set of cases to deal with: |
530 // . More than one maximized window: move newly maximized window into | 695 // . More than one maximized window: move newly maximized window into |
531 // own workspace. | 696 // own workspace. |
532 // . One maximized window and not in a maximized workspace: move window | 697 // . One maximized window and not in a maximized workspace: move window |
533 // into own workspace. | 698 // into own workspace. |
534 // . No maximized window and not in desktop: move to desktop and further | 699 // . No maximized window and not in desktop: move to desktop and further |
535 // any existing windows are stacked beneath |child|. | 700 // any existing windows are stacked beneath |child|. |
536 const bool is_active = wm::IsActiveWindow(child); | 701 const bool is_active = wm::IsActiveWindow(child); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
595 const bool is_active = wm::IsActiveWindow(window); | 760 const bool is_active = wm::IsActiveWindow(window); |
596 if (is_active) | 761 if (is_active) |
597 new_workspace->window()->Show(); | 762 new_workspace->window()->Show(); |
598 ReparentWindow(window, new_workspace->window(), NULL); | 763 ReparentWindow(window, new_workspace->window(), NULL); |
599 if (is_active) | 764 if (is_active) |
600 SetActiveWorkspace(new_workspace, ANIMATE_OLD_AND_NEW); | 765 SetActiveWorkspace(new_workspace, ANIMATE_OLD_AND_NEW); |
601 } | 766 } |
602 | 767 |
603 } // namespace internal | 768 } // namespace internal |
604 } // namespace ash | 769 } // namespace ash |
OLD | NEW |