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

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

Issue 11085053: Improving window auto management between workspaces (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Improved the entire window (auto) management Created 8 years, 2 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_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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698