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_controller.h"
6 
7 #include <utility>
8 
9 #include "ash/public/cpp/shell_window_ids.h"
10 #include "ash/root_window_controller.h"
11 #include "ash/shelf/shelf.h"
12 #include "ash/shell.h"
13 #include "ash/wm/desks/desks_util.h"
14 #include "ash/wm/fullscreen_window_finder.h"
15 #include "ash/wm/mru_window_tracker.h"
16 #include "ash/wm/overview/overview_controller.h"
17 #include "ash/wm/window_animations.h"
18 #include "ash/wm/window_state.h"
19 #include "ash/wm/workspace/backdrop_controller.h"
20 #include "ash/wm/workspace/workspace_event_handler.h"
21 #include "ash/wm/workspace/workspace_layout_manager.h"
22 #include "ui/aura/window.h"
23 #include "ui/compositor/layer.h"
24 #include "ui/compositor/scoped_layer_animation_settings.h"
25 #include "ui/wm/core/window_animations.h"
26 
27 // Defines a window property to store a WorkspaceController in the properties of
28 // virtual desks container windows.
29 ASH_EXPORT extern const aura::WindowProperty<ash::WorkspaceController*>* const
30     kWorkspaceController;
31 
32 DEFINE_UI_CLASS_PROPERTY_TYPE(ash::WorkspaceController*)
33 
34 DEFINE_OWNED_UI_CLASS_PROPERTY_KEY(ash::WorkspaceController,
35                                    kWorkspaceController,
36                                    nullptr)
37 
38 namespace ash {
39 namespace {
40 
41 // Amount of time to pause before animating anything. Only used during initial
42 // animation (when logging in).
43 const int kInitialPauseTimeMS = 750;
44 
45 // The duration of the animation that occurs on first login.
46 const int kInitialAnimationDurationMS = 200;
47 
48 }  // namespace
49 
WorkspaceController(aura::Window * viewport)50 WorkspaceController::WorkspaceController(aura::Window* viewport)
51     : viewport_(viewport),
52       event_handler_(std::make_unique<WorkspaceEventHandler>(viewport)),
53       layout_manager_(new WorkspaceLayoutManager(viewport)) {
54   viewport_->AddObserver(this);
55   ::wm::SetWindowVisibilityAnimationTransition(viewport_, ::wm::ANIMATE_NONE);
56   viewport_->SetLayoutManager(layout_manager_);
57 }
58 
~WorkspaceController()59 WorkspaceController::~WorkspaceController() {
60   if (!viewport_)
61     return;
62 
63   viewport_->RemoveObserver(this);
64   viewport_->SetLayoutManager(nullptr);
65 }
66 
GetWindowState() const67 WorkspaceWindowState WorkspaceController::GetWindowState() const {
68   if (!viewport_)
69     return WorkspaceWindowState::kDefault;
70 
71   // Always use DEFAULT state in overview mode so that work area stays
72   // the same regardles of the window we have.
73   // The |overview_controller| can be null during shutdown.
74   if (Shell::Get()->overview_controller() &&
75       Shell::Get()->overview_controller()->InOverviewSession()) {
76     return WorkspaceWindowState::kDefault;
77   }
78 
79   const aura::Window* fullscreen =
80       GetWindowForFullscreenModeForContext(viewport_);
81   if (fullscreen)
82     return WorkspaceWindowState::kFullscreen;
83 
84   auto mru_list =
85       Shell::Get()->mru_window_tracker()->BuildWindowListIgnoreModal(
86           kActiveDesk);
87 
88   for (aura::Window* window : mru_list) {
89     if (window->GetRootWindow() != viewport_->GetRootWindow())
90       continue;
91     WindowState* window_state = WindowState::Get(window);
92     if (window->layer() && !window->layer()->GetTargetVisibility())
93       continue;
94     if (window_state->IsMaximized())
95       return WorkspaceWindowState::kMaximized;
96   }
97   return WorkspaceWindowState::kDefault;
98 }
99 
DoInitialAnimation()100 void WorkspaceController::DoInitialAnimation() {
101   viewport_->Show();
102 
103   ui::Layer* layer = viewport_->layer();
104   layer->SetOpacity(0.0f);
105   SetTransformForScaleAnimation(layer, LAYER_SCALE_ANIMATION_ABOVE);
106 
107   // In order for pause to work we need to stop animations.
108   layer->GetAnimator()->StopAnimating();
109 
110   {
111     ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
112 
113     settings.SetPreemptionStrategy(ui::LayerAnimator::ENQUEUE_NEW_ANIMATION);
114     layer->GetAnimator()->SchedulePauseForProperties(
115         base::TimeDelta::FromMilliseconds(kInitialPauseTimeMS),
116         ui::LayerAnimationElement::TRANSFORM |
117             ui::LayerAnimationElement::OPACITY |
118             ui::LayerAnimationElement::BRIGHTNESS |
119             ui::LayerAnimationElement::VISIBILITY);
120     settings.SetTweenType(gfx::Tween::EASE_OUT);
121     settings.SetTransitionDuration(
122         base::TimeDelta::FromMilliseconds(kInitialAnimationDurationMS));
123     layer->SetTransform(gfx::Transform());
124     layer->SetOpacity(1.0f);
125   }
126 }
127 
OnWindowDestroying(aura::Window * window)128 void WorkspaceController::OnWindowDestroying(aura::Window* window) {
129   DCHECK_EQ(window, viewport_);
130   viewport_->RemoveObserver(this);
131   viewport_ = nullptr;
132   // Destroy |event_handler_| too as it depends upon |window|.
133   event_handler_.reset();
134   layout_manager_ = nullptr;
135 }
136 
SetWorkspaceController(aura::Window * desk_container,WorkspaceController * workspace_controller)137 void SetWorkspaceController(aura::Window* desk_container,
138                             WorkspaceController* workspace_controller) {
139   DCHECK(desk_container);
140   DCHECK(desks_util::IsDeskContainer(desk_container));
141 
142   if (workspace_controller)
143     desk_container->SetProperty(kWorkspaceController, workspace_controller);
144   else
145     desk_container->ClearProperty(kWorkspaceController);
146 }
147 
GetWorkspaceController(aura::Window * desk_container)148 WorkspaceController* GetWorkspaceController(aura::Window* desk_container) {
149   DCHECK(desk_container);
150   DCHECK(desks_util::IsDeskContainer(desk_container));
151 
152   return desk_container->GetProperty(kWorkspaceController);
153 }
154 
GetWorkspaceControllerForContext(aura::Window * context)155 WorkspaceController* GetWorkspaceControllerForContext(aura::Window* context) {
156   DCHECK(!context->IsRootWindow());
157 
158   // Find the desk container to which |context| belongs.
159   while (context && !desks_util::IsDeskContainer(context))
160     context = context->parent();
161 
162   if (!context)
163     return nullptr;
164 
165   return GetWorkspaceController(context);
166 }
167 
GetActiveWorkspaceController(aura::Window * root)168 WorkspaceController* GetActiveWorkspaceController(aura::Window* root) {
169   DCHECK(root->IsRootWindow());
170 
171   return GetWorkspaceController(
172       desks_util::GetActiveDeskContainerForRoot(root));
173 }
174 
175 }  // namespace ash
176