Only fsync leveldb's directory when the manifest is being updated.
[chromium-blink-merge.git] / ash / wm / workspace / workspace_cycler_animator.cc
blob1a0c3c3e05861aabc7c8937327b9d865d5990ed4
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.
5 #include "ash/wm/workspace/workspace_cycler_animator.h"
7 #include <algorithm>
8 #include <cmath>
10 #include "ash/launcher/launcher.h"
11 #include "ash/root_window_controller.h"
12 #include "ash/screen_ash.h"
13 #include "ash/shelf/shelf_layout_manager.h"
14 #include "ash/shelf/shelf_widget.h"
15 #include "ash/shell_window_ids.h"
16 #include "ash/wm/property_util.h"
17 #include "ash/wm/window_properties.h"
18 #include "ash/wm/workspace/colored_window_controller.h"
19 #include "ash/wm/workspace/workspace.h"
20 #include "ash/wm/workspace/workspace_cycler_configuration.h"
21 #include "base/values.h"
22 #include "ui/aura/root_window.h"
23 #include "ui/aura/window.h"
24 #include "ui/base/events/event_utils.h"
25 #include "ui/compositor/layer_animator.h"
26 #include "ui/compositor/scoped_layer_animation_settings.h"
27 #include "ui/gfx/transform_util.h"
28 #include "ui/views/widget/widget.h"
30 typedef ash::WorkspaceCyclerConfiguration Config;
32 namespace ash {
33 namespace internal {
35 // Class which computes the transform, brightness, and visbility of workspaces
36 // on behalf of the animator.
37 class StyleCalculator {
38 public:
39 StyleCalculator(const gfx::Rect& screen_bounds,
40 const gfx::Rect& maximized_bounds,
41 size_t num_workspaces);
42 ~StyleCalculator();
44 // Returns the transform, brightness, and visibility that the workspace at
45 // |workspace_index| should be animated to when the user has stopped cycling
46 // through workspaces given |selected_workspace_index|.
47 // Unlike GetTargetProperties(), the method does not have a |scroll_delta|
48 // argument as stopping the workspace cycler always results in complately
49 // selecting a workspace.
50 void GetStoppedTargetProperties(size_t selected_workspace_index,
51 size_t workspace_index,
52 gfx::Transform* transform,
53 float* brightness,
54 bool* visible) const;
56 // Returns the transform, brightness, and visibility that the workspace at
57 // |workspace_index| should be animated to when the user is cycling through
58 // workspaces given |selected_workspace_index| and |scroll_delta|.
59 // |scroll_delta| is the amount of pixels that the user has scrolled
60 // vertically since completely selecting the workspace at
61 // |selected_workspace_index|.
62 void GetTargetProperties(size_t selected_workspace_index,
63 size_t workspace_index,
64 double scroll_delta,
65 gfx::Transform* transform,
66 float* brightness,
67 bool* visible) const;
69 private:
70 // Returns the target animation transform of the workspace which is at
71 // |offset_from_selected| from the selected workspace when the user is not
72 // cycling through workspaces.
73 // This method assumes |scroll_delta| == 0.
74 gfx::Transform GetStoppedTargetTransformForOffset(
75 int offset_from_selected) const;
77 // Returns the target animation transform of the workspace which is at
78 // |offset_from_selected| from the selected workspace.
79 // This method like all the methods below assumes |scroll_delta| == 0 for the
80 // sake of simplicity. The transform for |scroll_delta| != 0 can be obtained
81 // via interpolation.
82 gfx::DecomposedTransform GetTargetTransformForOffset(
83 int offset_from_selected) const;
85 // Returns the target animation brightness of the workspace which is at
86 // |offset_from_selected| from the selected workspace.
87 // This method assumes |scroll_delta| == 0.
88 float GetTargetBrightnessForOffset(int offset_from_selected) const;
90 // Returns the target animation visibility of the workspace with the given
91 // parameters.
92 // This method assumes |scroll_delta| == 0.
93 bool GetTargetVisibilityForOffset(int offset_from_selected,
94 size_t workspace_index) const;
96 // Returns the minimum offset from the selected workspace at which a
97 // workspace can be visible. The offset is used to limit the amount of
98 // workspaces which are simultaneously visible.
99 int GetMinVisibleOffsetFromSelected() const;
101 // Returns the maximum offset from the selected workspace at which a
102 // workspace can be visible. The offset is used to limit the amount of
103 // workspaces which are simultaneously visible.
104 int GetMaxVisibleOffsetFromSelected() const;
106 // The bounds of the display containing the workspaces in workspace
107 // coordinates, including the shelf if any.
108 const gfx::Rect screen_bounds_;
110 // The bounds of a maximized window. This excludes the shelf if any.
111 const gfx::Rect maximized_bounds_;
113 // The combined number of visible and hidden workspaces.
114 size_t num_workspaces_;
116 DISALLOW_COPY_AND_ASSIGN(StyleCalculator);
119 StyleCalculator::StyleCalculator(const gfx::Rect& screen_bounds,
120 const gfx::Rect& maximized_bounds,
121 size_t num_workspaces)
122 : screen_bounds_(screen_bounds),
123 maximized_bounds_(maximized_bounds),
124 num_workspaces_(num_workspaces) {
127 StyleCalculator::~StyleCalculator() {
130 void StyleCalculator::GetStoppedTargetProperties(
131 size_t selected_workspace_index,
132 size_t workspace_index,
133 gfx::Transform* transform,
134 float* brightness,
135 bool* visible) const {
136 DCHECK_LT(selected_workspace_index, num_workspaces_);
137 DCHECK_LT(workspace_index, num_workspaces_);
138 int offset_from_selected = static_cast<int>(
139 workspace_index - selected_workspace_index);
140 if (transform)
141 *transform = GetStoppedTargetTransformForOffset(offset_from_selected);
143 if (brightness)
144 *brightness = GetTargetBrightnessForOffset(offset_from_selected);
146 // All the workspaces other than the selected workspace are either occluded by
147 // the selected workspace or off screen.
148 if (visible)
149 *visible = (selected_workspace_index == workspace_index);
152 void StyleCalculator::GetTargetProperties(
153 size_t selected_workspace_index,
154 size_t workspace_index,
155 double scroll_delta,
156 gfx::Transform* transform,
157 float* brightness,
158 bool* visible) const {
159 DCHECK_LT(selected_workspace_index, num_workspaces_);
160 DCHECK_LT(workspace_index, num_workspaces_);
162 int offset_from_selected = static_cast<int>(
163 workspace_index - selected_workspace_index);
165 int first_offset_from_selected = offset_from_selected;
166 int second_offset_from_selected = offset_from_selected;
167 if (scroll_delta < 0) {
168 // The user is part of the way to selecting the workspace at
169 // |selected_workspace_index| - 1 -> |offset_from_selected| + 1.
170 second_offset_from_selected = offset_from_selected + 1;
171 } else if (scroll_delta > 0) {
172 // The user is part of the way to selecting the workspace at
173 // |selected_workspace_index| + 1 -> |offset_from_selected| - 1.
174 second_offset_from_selected = offset_from_selected - 1;
177 double scroll_distance_to_cycle_to_next_workspace = Config::GetDouble(
178 Config::SCROLL_DISTANCE_TO_CYCLE_TO_NEXT_WORKSPACE);
179 double progress = fabs(
180 scroll_delta / scroll_distance_to_cycle_to_next_workspace);
181 DCHECK_GT(1.0, progress);
183 if (transform) {
184 gfx::DecomposedTransform first_transform = GetTargetTransformForOffset(
185 first_offset_from_selected);
187 gfx::DecomposedTransform interpolated_transform;
188 if (first_offset_from_selected == second_offset_from_selected) {
189 interpolated_transform = first_transform;
190 } else {
191 gfx::DecomposedTransform second_transform = GetTargetTransformForOffset(
192 second_offset_from_selected);
193 gfx::BlendDecomposedTransforms(&interpolated_transform,
194 second_transform,
195 first_transform,
196 progress);
198 *transform = gfx::ComposeTransform(interpolated_transform);
201 if (brightness) {
202 float first_brightness = GetTargetBrightnessForOffset(
203 first_offset_from_selected);
204 float second_brightness = GetTargetBrightnessForOffset(
205 second_offset_from_selected);
206 *brightness = first_brightness + progress *
207 (second_brightness - first_brightness);
210 if (visible) {
211 bool first_visible = GetTargetVisibilityForOffset(
212 first_offset_from_selected, workspace_index);
213 bool second_visible = GetTargetVisibilityForOffset(
214 second_offset_from_selected, workspace_index);
215 *visible = (first_visible || second_visible);
219 gfx::Transform StyleCalculator::GetStoppedTargetTransformForOffset(
220 int offset_from_selected) const {
221 if (offset_from_selected <= 0) {
222 // The selected workspace takes up the entire screen. The workspaces deeper
223 // than the selected workspace are stacked exactly under the selected
224 // workspace and are completely occluded by it.
225 return gfx::Transform();
228 // The workspaces shallower than the selected workspace are stacked exactly
229 // on top of each other offscreen.
230 double max_scale = Config::GetDouble(Config::MAX_SCALE);
232 gfx::Transform transform;
233 transform.Translate(0, screen_bounds_.height());
234 transform.Scale(max_scale, max_scale);
235 return transform;
238 gfx::DecomposedTransform StyleCalculator::GetTargetTransformForOffset(
239 int offset_from_selected) const {
240 // When cycling, the workspaces are spread out from the positions computed by
241 // GetStoppedTargetTransformForOffset(). The transforms are computed so that
242 // on screen the workspaces look like this:
243 // ____________________________________________
244 // | ________________________ |
245 // | | deepest workpace |_________|_
246 // | _|________________________|_ | |
247 // | | | | |
248 // | _|____________________________|_ | |_ top stack.
249 // | | selected / shallowest workspace| | |
250 // | | | | |
251 // | | |_____|_|
252 // | | | |
253 // | | | |
254 // | _|________________________________|_ |
255 // | | deepest workspace |___|_
256 // | _|____________________________________|_ | |_ bottom stack.
257 // | | shallowest workspace |_|_|
258 // |_|________________________________________|_|
259 // The selected workspace is the most visible workspace. It is the workspace
260 // which will be activated if the user does not do any more cycling.
261 bool in_top_stack = (offset_from_selected <= 0);
263 int min_visible_offset_from_selected = GetMinVisibleOffsetFromSelected();
264 int max_visible_offset_from_selected = GetMaxVisibleOffsetFromSelected();
266 // Give workspaces at hidden offsets the transform of the workspace at the
267 // nearest visible offset. This is needed to produce a valid result when
268 // interpolating between the values of GetTargetTransformForOffset() for a
269 // visible and hidden offset.
270 if (offset_from_selected < min_visible_offset_from_selected)
271 offset_from_selected = min_visible_offset_from_selected;
272 else if (offset_from_selected > max_visible_offset_from_selected)
273 offset_from_selected = max_visible_offset_from_selected;
275 double selected_scale = Config::GetDouble(Config::SELECTED_SCALE);
277 double scale = selected_scale;
278 if (in_top_stack) {
279 double min_scale = Config::GetDouble(Config::MIN_SCALE);
280 scale -= static_cast<double>(offset_from_selected) /
281 min_visible_offset_from_selected * (selected_scale - min_scale);
282 } else {
283 double max_scale = Config::GetDouble(Config::MAX_SCALE);
284 scale += static_cast<double>(offset_from_selected) /
285 max_visible_offset_from_selected * (max_scale - selected_scale);
288 // Compute the workspace's y offset.
289 double y_offset = 0;
290 if (offset_from_selected == 0) {
291 y_offset = Config::GetDouble(Config::SELECTED_Y_OFFSET);
292 } else {
293 Config::Property y_offsets_property;
294 if (in_top_stack) {
295 y_offsets_property = Config::DEEPER_THAN_SELECTED_Y_OFFSETS;
296 } else {
297 y_offsets_property = Config::SHALLOWER_THAN_SELECTED_Y_OFFSETS;
298 y_offset = maximized_bounds_.height();
300 const base::ListValue& y_offsets = Config::GetListValue(y_offsets_property);
301 size_t y_offset_index = static_cast<size_t>(
302 std::abs(offset_from_selected) - 1);
303 DCHECK_GT(y_offsets.GetSize(), y_offset_index);
304 double y_offset_config_value = 0;
305 y_offsets.GetDouble(y_offset_index, &y_offset_config_value);
306 y_offset += y_offset_config_value;
309 // Center the workspace horizontally.
310 double x_offset = maximized_bounds_.width() * (1 - scale) / 2;
312 gfx::DecomposedTransform transform;
313 transform.translate[0] = x_offset;
314 transform.translate[1] = y_offset;
315 transform.scale[0] = scale;
316 transform.scale[1] = scale;
317 return transform;
320 float StyleCalculator::GetTargetBrightnessForOffset(
321 int offset_from_selected) const {
322 int max_visible_distance_from_selected = std::max(
323 std::abs(GetMinVisibleOffsetFromSelected()),
324 GetMaxVisibleOffsetFromSelected());
325 return Config::GetDouble(Config::MIN_BRIGHTNESS) * std::min(
326 1.0,
327 static_cast<double>(std::abs(offset_from_selected)) /
328 max_visible_distance_from_selected);
331 bool StyleCalculator::GetTargetVisibilityForOffset(
332 int offset_from_selected,
333 size_t workspace_index) const {
334 // The workspace at the highest possible index is the shallowest workspace
335 // out of both stacks and is always visible.
336 // The workspace at |GetMaxVisibleOffsetFromSelected()| is hidden because it
337 // has the same transform as the shallowest workspace and is completely
338 // occluded by it.
339 if (workspace_index == num_workspaces_ - 1)
340 return true;
342 return offset_from_selected >= GetMinVisibleOffsetFromSelected() &&
343 offset_from_selected < GetMaxVisibleOffsetFromSelected();
346 int StyleCalculator::GetMinVisibleOffsetFromSelected() const {
347 const base::ListValue& y_offsets = Config::GetListValue(
348 Config::DEEPER_THAN_SELECTED_Y_OFFSETS);
349 // Hide workspaces for which there is no y offset specified.
350 return -1 * static_cast<int>(y_offsets.GetSize());
353 int StyleCalculator::GetMaxVisibleOffsetFromSelected() const {
354 const base::ListValue& y_offsets = Config::GetListValue(
355 Config::SHALLOWER_THAN_SELECTED_Y_OFFSETS);
356 // Hide workspaces for which there is no y offset specified.
357 return y_offsets.GetSize();
360 WorkspaceCyclerAnimator::WorkspaceCyclerAnimator(Delegate* delegate)
361 : delegate_(delegate),
362 initial_active_workspace_index_(0),
363 selected_workspace_index_(0),
364 scroll_delta_(0),
365 animation_type_(NONE),
366 launcher_background_controller_(NULL),
367 style_calculator_(NULL) {
370 WorkspaceCyclerAnimator::~WorkspaceCyclerAnimator() {
371 StopObservingImplicitAnimations();
372 animation_type_ = NONE;
375 void WorkspaceCyclerAnimator::Init(const std::vector<Workspace*>& workspaces,
376 Workspace* initial_active_workspace) {
377 workspaces_ = workspaces;
379 std::vector<Workspace*>::iterator it = std::find(workspaces_.begin(),
380 workspaces_.end(), initial_active_workspace);
381 DCHECK(it != workspaces_.end());
382 initial_active_workspace_index_ = it - workspaces_.begin();
383 selected_workspace_index_ = initial_active_workspace_index_;
385 screen_bounds_ = ScreenAsh::GetDisplayBoundsInParent(
386 workspaces_[0]->window());
387 maximized_bounds_ = ScreenAsh::GetMaximizedWindowBoundsInParent(
388 workspaces_[0]->window());
389 style_calculator_.reset(new StyleCalculator(
390 screen_bounds_, maximized_bounds_, workspaces_.size()));
393 void WorkspaceCyclerAnimator::AnimateStartingCycler() {
394 // Set kCyclingThroughWorkspaces so that the window frame is painted with the
395 // correct style.
396 workspaces_[0]->window()->GetRootWindow()->SetProperty(
397 ash::internal::kCyclingThroughWorkspacesKey, true);
399 // Ensure that the workspaces are stacked with respect to their order
400 // in |workspaces_|.
401 aura::Window* parent = workspaces_[0]->window()->parent();
402 DCHECK(parent);
403 for (size_t i = 0; i < workspaces_.size() - 1; ++i) {
404 parent->StackChildAbove(workspaces_[i + 1]->window(),
405 workspaces_[i]->window());
408 // Set the initial transform and brightness of the workspaces such that they
409 // animate correctly when AnimateToUpdatedState() is called after the loop.
410 // Start at index 1 as the desktop workspace is not animated.
411 for (size_t i = 1; i < workspaces_.size(); ++i) {
412 aura::Window* window = workspaces_[i]->window();
413 ui::Layer* layer = window->layer();
415 gfx::Transform transform;
416 float brightness = 0.0f;
417 style_calculator_->GetStoppedTargetProperties(selected_workspace_index_, i,
418 &transform, &brightness, NULL);
419 layer->SetTransform(transform);
420 layer->SetLayerBrightness(brightness);
423 int start_cycler_animation_duration = static_cast<int>(Config::GetDouble(
424 Config::START_CYCLER_ANIMATION_DURATION));
426 scroll_delta_ = 0;
427 animation_type_ = CYCLER_START;
428 AnimateToUpdatedState(start_cycler_animation_duration);
430 // Dim the desktop workspace and the desktop background.
431 AnimateTo(0, false, start_cycler_animation_duration, gfx::Transform(),
432 Config::GetDouble(Config::DESKTOP_WORKSPACE_BRIGHTNESS), true);
434 aura::Window* background = GetDesktopBackground();
435 if (background) {
436 ui::Layer* layer = background->layer();
438 if (!background->IsVisible()) {
439 background->Show();
440 layer->SetOpacity(0.0f);
444 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
445 settings.SetPreemptionStrategy(
446 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
447 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
448 start_cycler_animation_duration));
450 layer->SetOpacity(Config::GetDouble(Config::BACKGROUND_OPACITY));
454 // Create a window to simulate a fully opaque launcher. This prevents
455 // workspaces from showing from behind the launcher.
456 CreateLauncherBackground();
459 void WorkspaceCyclerAnimator::AnimateStoppingCycler() {
460 if (scroll_delta_ != 0) {
461 // Completely select the workspace at |selected_workspace_index_|.
462 int animation_duration = GetAnimationDurationForChangeInScrollDelta(
463 -scroll_delta_);
464 scroll_delta_ = 0;
465 animation_type_ = CYCLER_COMPLETELY_SELECT;
466 AnimateToUpdatedState(animation_duration);
467 return;
470 int stop_cycler_animation_duration = static_cast<int>(Config::GetDouble(
471 Config::STOP_CYCLER_ANIMATION_DURATION));
473 animation_type_ = CYCLER_END;
474 AnimateToUpdatedState(stop_cycler_animation_duration);
476 AnimateTo(0, false, stop_cycler_animation_duration, gfx::Transform(),
477 0.0f, true);
479 aura::Window* background = GetDesktopBackground();
480 if (background) {
481 ui::Layer* layer = background->layer();
482 ui::ScopedLayerAnimationSettings settings(layer->GetAnimator());
483 settings.SetPreemptionStrategy(
484 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
485 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
486 stop_cycler_animation_duration));
488 layer->SetOpacity((selected_workspace_index_ == 0) ? 1.0f : 0.0f);
492 void WorkspaceCyclerAnimator::AbortAnimations() {
493 StopObservingImplicitAnimations();
494 animation_type_ = NONE;
495 CyclerStopped(initial_active_workspace_index_);
498 void WorkspaceCyclerAnimator::AnimateCyclingByScrollDelta(double scroll_delta) {
499 if (scroll_delta == 0)
500 return;
502 // Drop any updates received while an animation is running.
503 // TODO(pkotwicz): Do something better.
504 if (animation_type_ != NONE)
505 return;
507 if (ui::IsNaturalScrollEnabled())
508 scroll_delta *= -1;
510 double old_scroll_delta = scroll_delta_;
511 scroll_delta_ += scroll_delta;
513 double scroll_distance_to_cycle_to_next_workspace = Config::GetDouble(
514 Config::SCROLL_DISTANCE_TO_CYCLE_TO_NEXT_WORKSPACE);
516 double min_scroll_delta = -1 *
517 static_cast<double>(selected_workspace_index_) *
518 scroll_distance_to_cycle_to_next_workspace;
519 double max_scroll_delta = static_cast<double>(
520 workspaces_.size() - 1 - selected_workspace_index_) *
521 scroll_distance_to_cycle_to_next_workspace;
523 if (scroll_delta_ < min_scroll_delta)
524 scroll_delta_ = min_scroll_delta;
525 else if (scroll_delta_ > max_scroll_delta)
526 scroll_delta_ = max_scroll_delta;
528 if (scroll_delta_ == old_scroll_delta)
529 return;
531 // Set the selected workspace to the workspace that the user is closest to
532 // selecting completely. A workspace is completely selected when the user
533 // has scrolled the exact amount to select the workspace with no undershoot /
534 // overshoot.
535 int workspace_change = floor(scroll_delta_ /
536 scroll_distance_to_cycle_to_next_workspace + .5);
537 selected_workspace_index_ += workspace_change;
539 // Set |scroll_delta_| to the amount of undershoot / overshoot.
540 scroll_delta_ -= workspace_change *
541 scroll_distance_to_cycle_to_next_workspace;
543 int animation_duration = GetAnimationDurationForChangeInScrollDelta(
544 scroll_delta_ - old_scroll_delta);
546 animation_type_ = CYCLER_UPDATE;
547 AnimateToUpdatedState(animation_duration);
550 void WorkspaceCyclerAnimator::AnimateToUpdatedState(int animation_duration) {
551 DCHECK_NE(NONE, animation_type_);
553 bool animator_to_wait_for_selected = false;
555 // Start at index 1, as the animator does not animate the desktop workspace.
556 for (size_t i = 1; i < workspaces_.size(); ++i) {
557 gfx::Transform transform;
558 float brightness = 0.0f;
559 bool visible = false;
560 if (animation_type_ == CYCLER_END) {
561 DCHECK_EQ(0, scroll_delta_);
562 style_calculator_->GetStoppedTargetProperties(selected_workspace_index_,
563 i, &transform, &brightness, &visible);
564 } else {
565 style_calculator_->GetTargetProperties(selected_workspace_index_, i,
566 scroll_delta_, &transform, &brightness, &visible);
569 aura::Window* window = workspaces_[i]->window();
570 int workspace_animation_duration = animation_duration;
571 if (!window->IsVisible()) {
572 if (visible) {
573 // The workspace's previous state is unknown, set the state immediately.
574 workspace_animation_duration = 0;
575 } else {
576 // Don't bother animating workspaces which aren't visible.
577 continue;
580 // Hide the workspace after |animation_duration| in the case of
581 // |visible| == false as the workspace to be hidden may not be completely
582 // occluded till the animation has completed.
584 bool wait_for_animator = false;
585 if (!animator_to_wait_for_selected && workspace_animation_duration != 0) {
586 // The completion of the animations for this workspace will be used to
587 // indicate that the animations for all workspaces have completed.
588 wait_for_animator = true;
589 animator_to_wait_for_selected = true;
592 AnimateTo(i, wait_for_animator, workspace_animation_duration,
593 transform, brightness, visible);
596 // All of the animations started by this method were of zero duration.
597 // Call the animation callback.
598 if (!animator_to_wait_for_selected)
599 OnImplicitAnimationsCompleted();
602 void WorkspaceCyclerAnimator::CyclerStopped(size_t visible_workspace_index) {
603 aura::Window* root_window = workspaces_[0]->window()->GetRootWindow();
604 root_window->SetProperty(ash::internal::kCyclingThroughWorkspacesKey,
605 false);
607 for(size_t i = 0; i < workspaces_.size(); ++i) {
608 aura::Window* window = workspaces_[i]->window();
609 ui::Layer* layer = window->layer();
610 layer->SetLayerBrightness(0.0f);
611 layer->SetTransform(gfx::Transform());
613 if (i == visible_workspace_index)
614 window->Show();
615 else
616 window->Hide();
619 aura::Window* background = GetDesktopBackground();
620 if (background) {
621 background->layer()->SetOpacity(1.0);
622 if (visible_workspace_index != 0u)
623 background->Hide();
626 launcher_background_controller_.reset();
629 void WorkspaceCyclerAnimator::AnimateTo(size_t workspace_index,
630 bool wait_for_animation_to_complete,
631 int animation_duration,
632 const gfx::Transform& target_transform,
633 float target_brightness,
634 bool target_visibility) {
635 aura::Window* window = workspaces_[workspace_index]->window();
636 ui::Layer* layer = window->layer();
637 ui::LayerAnimator* animator = layer->GetAnimator();
638 ui::ScopedLayerAnimationSettings settings(animator);
640 if (wait_for_animation_to_complete) {
641 StopObservingImplicitAnimations();
642 DCHECK_NE(animation_type_, NONE);
643 settings.AddObserver(this);
646 settings.SetPreemptionStrategy(
647 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
648 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(
649 animation_duration));
651 if (target_visibility) {
652 window->Show();
654 // Set the opacity in case the layer has some weird initial state.
655 layer->SetOpacity(1.0f);
656 } else {
657 window->Hide();
660 layer->SetTransform(target_transform);
661 layer->SetLayerBrightness(target_brightness);
664 int WorkspaceCyclerAnimator::GetAnimationDurationForChangeInScrollDelta(
665 double change) const {
666 double ratio = Config::GetDouble(
667 Config::CYCLER_STEP_ANIMATION_DURATION_RATIO);
668 return static_cast<int>(fabs(change) * ratio);
671 void WorkspaceCyclerAnimator::CreateLauncherBackground() {
672 if (screen_bounds_ == maximized_bounds_)
673 return;
675 // TODO(pkotwicz): Figure out what to do when the launcher visible state is
676 // SHELF_AUTO_HIDE.
677 ShelfLayoutManager* shelf_layout_manager =
678 ShelfLayoutManager::ForLauncher(workspaces_[0]->window());
679 if (!shelf_layout_manager->IsVisible())
680 return;
682 aura::Window* launcher_window = shelf_layout_manager->shelf_widget()->
683 GetNativeWindow();
685 gfx::Rect shelf_bounds = shelf_layout_manager->GetIdealBounds();
687 launcher_background_controller_.reset(new ColoredWindowController(
688 launcher_window->parent(), "LauncherBackground"));
689 launcher_background_controller_->SetColor(SK_ColorBLACK);
690 aura::Window* tint_window =
691 launcher_background_controller_->GetWidget()->GetNativeWindow();
692 tint_window->SetBounds(shelf_bounds);
693 launcher_window->parent()->StackChildBelow(tint_window, launcher_window);
694 tint_window->Show();
697 aura::Window* WorkspaceCyclerAnimator::GetDesktopBackground() const {
698 RootWindowController* root_controller = GetRootWindowController(
699 workspaces_[0]->window()->GetRootWindow());
700 if (!root_controller)
701 return NULL;
703 return root_controller->GetContainer(
704 kShellWindowId_DesktopBackgroundContainer);
707 void WorkspaceCyclerAnimator::NotifyDelegate(
708 AnimationType completed_animation) {
709 if (completed_animation == CYCLER_START)
710 delegate_->StartWorkspaceCyclerAnimationFinished();
711 else if (completed_animation == CYCLER_END)
712 delegate_->StopWorkspaceCyclerAnimationFinished();
715 void WorkspaceCyclerAnimator::OnImplicitAnimationsCompleted() {
716 AnimationType completed_animation = animation_type_;
717 animation_type_ = NONE;
719 if (completed_animation == CYCLER_COMPLETELY_SELECT)
720 AnimateStoppingCycler();
721 else if (completed_animation == CYCLER_END)
722 CyclerStopped(selected_workspace_index_);
724 if (completed_animation == CYCLER_START ||
725 completed_animation == CYCLER_END) {
726 // Post a task to notify the delegate of the animation completion because
727 // the delegate may delete |this| as a result of getting notified.
728 base::MessageLoopForUI::current()->PostTask(
729 FROM_HERE,
730 base::Bind(&WorkspaceCyclerAnimator::NotifyDelegate,
731 AsWeakPtr(),
732 completed_animation));
736 } // namespace internal
737 } // namespace ash