Chromium Code Reviews| 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 |