1 // Copyright 2014 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 "athena/wm/window_overview_mode.h"
10 #include "athena/wm/overview_toolbar.h"
11 #include "athena/wm/public/window_list_provider.h"
12 #include "athena/wm/public/window_list_provider_observer.h"
13 #include "athena/wm/split_view_controller.h"
14 #include "base/bind.h"
15 #include "base/memory/scoped_vector.h"
16 #include "ui/aura/scoped_window_targeter.h"
17 #include "ui/aura/window.h"
18 #include "ui/aura/window_delegate.h"
19 #include "ui/aura/window_property.h"
20 #include "ui/aura/window_targeter.h"
21 #include "ui/aura/window_tree_host.h"
22 #include "ui/compositor/closure_animation_observer.h"
23 #include "ui/compositor/compositor.h"
24 #include "ui/compositor/compositor_animation_observer.h"
25 #include "ui/compositor/scoped_layer_animation_settings.h"
26 #include "ui/events/event_handler.h"
27 #include "ui/events/gestures/fling_curve.h"
28 #include "ui/gfx/frame_time.h"
29 #include "ui/gfx/transform.h"
30 #include "ui/wm/core/shadow_types.h"
31 #include "ui/wm/core/window_animations.h"
32 #include "ui/wm/core/window_util.h"
33 #include "ui/wm/public/activation_client.h"
37 struct WindowOverviewState {
38 // The current overview state of the window. 0.f means the window is at the
39 // topmost position. 1.f means the window is at the bottom-most position.
42 // The top-most and bottom-most vertical position of the window in overview
47 // |split| is set if this window is one of the two split windows in split-view
54 DECLARE_WINDOW_PROPERTY_TYPE(WindowOverviewState*);
55 DEFINE_OWNED_WINDOW_PROPERTY_KEY(WindowOverviewState,
63 const float kOverviewDefaultScale = 0.75f;
65 gfx::Transform GetTransformForSplitWindow(aura::Window* window, float scale) {
66 const float kScrollWindowPositionInOverview = 0.65f;
67 int x_translate = window->bounds().width() * (1 - scale) / 2;
68 gfx::Transform transform;
70 x_translate, window->bounds().height() * kScrollWindowPositionInOverview);
71 transform.Scale(scale, scale);
75 // Gets the transform for the window in its current state.
76 gfx::Transform GetTransformForState(aura::Window* window,
77 WindowOverviewState* state) {
79 return GetTransformForSplitWindow(window, kOverviewDefaultScale);
81 const float kProgressToStartShrinking = 0.07;
82 const float kOverviewScale = 0.75f;
83 float scale = kOverviewScale;
84 if (state->progress < kProgressToStartShrinking) {
85 const float kShrunkMinimumScale = 0.7f;
86 scale = gfx::Tween::FloatValueBetween(
87 state->progress / kProgressToStartShrinking,
91 int container_width = window->parent()->bounds().width();
92 int window_width = window->bounds().width();
93 int window_x = window->bounds().x();
94 float x_translate = (container_width - (window_width * scale)) / 2 - window_x;
95 float y_translate = gfx::Tween::FloatValueBetween(
96 state->progress, state->min_y, state->max_y);
97 gfx::Transform transform;
98 transform.Translate(x_translate, y_translate);
99 transform.Scale(scale, scale);
103 // A utility class used to set the transform/opacity to the window and
104 // its transient children.
105 class TransientGroupSetter {
107 explicit TransientGroupSetter(aura::Window* window) : window_(window) {
109 ~TransientGroupSetter() {}
111 // Aborts all animations including its transient children.
112 void AbortAllAnimations() {
113 window_->layer()->GetAnimator()->AbortAllAnimations();
114 for (aura::Window* transient_child : wm::GetTransientChildren(window_))
115 transient_child->layer()->GetAnimator()->AbortAllAnimations();
118 // Applys transform to the window and its transient children.
119 // Transient children gets a tranfrorm with the offset relateive
120 // it its transient parent.
121 void SetTransform(const gfx::Transform& transform) {
122 window_->SetTransform(transform);
123 for (aura::Window* transient_child : wm::GetTransientChildren(window_)) {
124 gfx::Rect window_bounds = window_->bounds();
125 gfx::Rect child_bounds = transient_child->bounds();
126 gfx::Transform transient_window_transform(TranslateTransformOrigin(
127 child_bounds.origin() - window_bounds.origin(), transform));
128 transient_child->SetTransform(transient_window_transform);
132 // Sets the opacity to the window and its transient children.
133 void SetOpacity(float opacity) {
134 window_->layer()->SetOpacity(opacity);
135 for (aura::Window* transient_child : wm::GetTransientChildren(window_)) {
136 transient_child->layer()->SetOpacity(opacity);
140 // Apply the transform with the overview scroll |progress|.
141 void SetWindowProgress(float progress) {
142 WindowOverviewState* state = window_->GetProperty(kWindowOverviewState);
143 state->progress = progress;
145 SetTransform(GetTransformForState(window_, state));
149 static gfx::Transform TranslateTransformOrigin(
150 const gfx::Vector2d& new_origin,
151 const gfx::Transform& transform) {
152 gfx::Transform result;
153 result.Translate(-new_origin.x(), -new_origin.y());
154 result.PreconcatTransform(transform);
155 result.Translate(new_origin.x(), new_origin.y());
159 aura::Window* window_;
161 DISALLOW_COPY_AND_ASSIGN(TransientGroupSetter);
164 // TransientGroupSetter with animation.
165 class AnimateTransientGroupSetter : public TransientGroupSetter {
167 explicit AnimateTransientGroupSetter(aura::Window* window)
168 : TransientGroupSetter(window) {
169 animation_settings_.push_back(CreateScopedLayerAnimationSettings(window));
170 for (aura::Window* transient_child : wm::GetTransientChildren(window)) {
171 animation_settings_.push_back(
172 CreateScopedLayerAnimationSettings(transient_child));
175 ~AnimateTransientGroupSetter() {}
177 ui::ScopedLayerAnimationSettings* GetMainWindowAnimationSettings() {
178 CHECK(animation_settings_.size());
179 return animation_settings_[0];
183 static ui::ScopedLayerAnimationSettings* CreateScopedLayerAnimationSettings(
184 aura::Window* window) {
185 const int kTransitionMs = 250;
187 ui::ScopedLayerAnimationSettings* settings =
188 new ui::ScopedLayerAnimationSettings(window->layer()->GetAnimator());
189 settings->SetPreemptionStrategy(
190 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
191 settings->SetTransitionDuration(
192 base::TimeDelta::FromMilliseconds(kTransitionMs));
196 ScopedVector<ui::ScopedLayerAnimationSettings> animation_settings_;
197 DISALLOW_COPY_AND_ASSIGN(AnimateTransientGroupSetter);
200 void HideWindowIfNotVisible(aura::Window* window,
201 SplitViewController* split_view_controller) {
202 bool should_hide = true;
203 if (split_view_controller->IsSplitViewModeActive()) {
204 should_hide = window != split_view_controller->left_window() &&
205 window != split_view_controller->right_window();
207 aura::Window* active = aura::client::GetActivationClient(
208 window->GetRootWindow())->GetActiveWindow();
209 should_hide = active != window && wm::GetTransientParent(active) != window;
215 // Resets the overview-related state for |window|.
216 void RestoreWindowState(aura::Window* window,
217 SplitViewController* split_view_controller) {
218 window->ClearProperty(kWindowOverviewState);
220 AnimateTransientGroupSetter setter(window);
222 setter.GetMainWindowAnimationSettings()->AddObserver(
223 new ui::ClosureAnimationObserver(
224 base::Bind(&HideWindowIfNotVisible, window, split_view_controller)));
226 setter.SetTransform(gfx::Transform());
227 // Reset the window opacity in case the user is dragging a window.
228 setter.SetOpacity(1.0f);
230 wm::SetShadowType(window, wm::SHADOW_TYPE_NONE);
233 gfx::RectF GetTransformedBounds(aura::Window* window) {
234 gfx::Transform transform;
235 gfx::RectF bounds = window->bounds();
236 transform.Translate(bounds.x(), bounds.y());
237 transform.PreconcatTransform(window->layer()->transform());
238 transform.Translate(-bounds.x(), -bounds.y());
239 transform.TransformRect(&bounds);
243 void TransformSplitWindowScale(aura::Window* window, float scale) {
244 gfx::Transform transform = window->layer()->GetTargetTransform();
245 if (transform.Scale2d() == gfx::Vector2dF(scale, scale))
247 AnimateTransientGroupSetter setter(window);
248 setter.SetTransform(GetTransformForSplitWindow(window, scale));
251 void AnimateWindowTo(aura::Window* animate_window,
252 aura::Window* target_window) {
253 AnimateTransientGroupSetter setter(animate_window);
255 WindowOverviewState* target_state =
256 target_window->GetProperty(kWindowOverviewState);
257 setter.SetWindowProgress(target_state->progress);
260 // Always returns the same target.
261 class StaticWindowTargeter : public aura::WindowTargeter {
263 explicit StaticWindowTargeter(aura::Window* target) : target_(target) {}
264 ~StaticWindowTargeter() override {}
267 // aura::WindowTargeter:
268 ui::EventTarget* FindTargetForEvent(ui::EventTarget* root,
269 ui::Event* event) override {
273 ui::EventTarget* FindTargetForLocatedEvent(ui::EventTarget* root,
274 ui::LocatedEvent* event) override {
278 aura::Window* target_;
279 DISALLOW_COPY_AND_ASSIGN(StaticWindowTargeter);
282 class WindowOverviewModeImpl : public WindowOverviewMode,
283 public ui::EventHandler,
284 public ui::CompositorAnimationObserver,
285 public WindowListProviderObserver {
287 WindowOverviewModeImpl(aura::Window* container,
288 WindowListProvider* window_list_provider,
289 SplitViewController* split_view_controller,
290 WindowOverviewModeDelegate* delegate)
291 : container_(container),
292 window_list_provider_(window_list_provider),
293 split_view_controller_(split_view_controller),
295 scoped_targeter_(new aura::ScopedWindowTargeter(
297 scoped_ptr<ui::EventTargeter>(
298 new StaticWindowTargeter(container)))),
299 dragged_window_(nullptr) {
301 container_->set_target_handler(this);
303 // Prepare the desired transforms for all the windows, and set the initial
304 // state on the windows.
305 ComputeTerminalStatesForAllWindows();
306 SetInitialWindowStates();
308 window_list_provider_->AddObserver(this);
311 ~WindowOverviewModeImpl() override {
312 window_list_provider_->RemoveObserver(this);
313 container_->set_target_handler(container_->delegate());
314 RemoveAnimationObserver();
315 const aura::Window::Windows& windows =
316 window_list_provider_->GetWindowList();
319 for (aura::Window* window : windows)
320 RestoreWindowState(window, split_view_controller_);
324 // Computes the transforms for all windows in both the topmost and bottom-most
325 // positions. The transforms are set in the |kWindowOverviewState| property of
327 void ComputeTerminalStatesForAllWindows() {
330 const aura::Window::Windows& windows =
331 window_list_provider_->GetWindowList();
332 for (aura::Window::Windows::const_reverse_iterator iter = windows.rbegin();
333 iter != windows.rend();
335 aura::Window* window = (*iter);
336 wm::SetShadowType(window, wm::SHADOW_TYPE_RECTANGULAR_ALWAYS_ACTIVE);
338 WindowOverviewState* state = new WindowOverviewState;
339 window->SetProperty(kWindowOverviewState, state);
340 if (split_view_controller_->IsSplitViewModeActive() &&
341 (window == split_view_controller_->left_window() ||
342 window == split_view_controller_->right_window())) {
343 // Do not let the left/right windows be scrolled.
344 gfx::Transform transform =
345 GetTransformForSplitWindow(window, kOverviewDefaultScale);
346 state->max_y = state->min_y = transform.To2dTranslation().y();
351 state->split = false;
352 UpdateTerminalStateForWindowAtIndex(window, index, windows.size());
356 // Computes the terminal states (i.e. the transforms for the top-most and
357 // bottom-most position in the stack) for |window|. |window_count| is the
358 // number of windows in the stack, and |index| is the position of the window
359 // in the stack (0 being the front-most window).
360 void UpdateTerminalStateForWindowAtIndex(aura::Window* window,
362 size_t window_count) {
363 const int kGapBetweenWindowsBottom = 10;
364 const int kGapBetweenWindowsTop = 5;
366 int top = (window_count - index - 1) * kGapBetweenWindowsTop;
367 int bottom = GetScrollableHeight() - (index * kGapBetweenWindowsBottom);
369 WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
374 state->max_y = bottom - window->bounds().y();
375 state->progress = 0.f;
378 // Sets the initial position for the windows for the overview mode.
379 void SetInitialWindowStates() {
380 // The initial overview state of the topmost three windows.
381 const float kInitialProgress[] = { 0.5f, 0.05f, 0.01f };
383 const aura::Window::Windows& windows =
384 window_list_provider_->GetWindowList();
385 for (aura::Window::Windows::const_reverse_iterator iter = windows.rbegin();
386 iter != windows.rend();
388 float progress = 0.f;
389 aura::Window* window = *iter;
390 if (split_view_controller_->IsSplitViewModeActive() &&
391 (window == split_view_controller_->left_window() ||
392 window == split_view_controller_->right_window())) {
395 if (index < arraysize(kInitialProgress))
396 progress = kInitialProgress[index];
400 TransientGroupSetter setter(window);
402 // Unset any in-progress animation.
403 setter.AbortAllAnimations();
405 // Showing transient parent will show the transient children if any.
408 setter.SetTransform(gfx::Transform());
409 // Setup the animation.
411 AnimateTransientGroupSetter setter(window);
412 setter.SetWindowProgress(progress);
417 aura::Window* SelectWindowAt(ui::LocatedEvent* event) {
418 CHECK_EQ(container_, event->target());
419 // Find the old targeter to find the target of the event.
420 ui::EventTarget* window = container_;
421 ui::EventTargeter* targeter = scoped_targeter_->old_targeter();
422 while (!targeter && window->GetParentTarget()) {
423 window = window->GetParentTarget();
424 targeter = window->GetEventTargeter();
428 aura::Window* target = static_cast<aura::Window*>(
429 targeter->FindTargetForLocatedEvent(container_, event));
430 while (target && target->parent() != container_)
431 target = target->parent();
432 aura::Window* transient_parent =
433 target ? wm::GetTransientParent(target) : nullptr;
434 return transient_parent ? transient_parent : target;
437 // Scroll the window list by |delta_y| amount. |delta_y| is negative when
438 // scrolling up; and positive when scrolling down.
439 void DoScroll(float delta_y) {
440 const float kEpsilon = 1e-3f;
441 float delta_y_p = std::abs(delta_y) / GetScrollableHeight();
442 const aura::Window::Windows& windows =
443 window_list_provider_->GetWindowList();
445 // Scroll up. Start with the top-most (i.e. behind-most in terms of
446 // z-index) window, and try to scroll them up.
447 for (aura::Window::Windows::const_iterator iter = windows.begin();
448 delta_y_p > kEpsilon && iter != windows.end();
450 aura::Window* window = (*iter);
451 WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
452 if (state->progress > kEpsilon) {
453 // It is possible to scroll |window| up. Scroll it up, and update
454 // |delta_y_p| for the next window.
455 float apply = delta_y_p * state->progress;
456 TransientGroupSetter setter(window);
457 setter.SetWindowProgress(std::max(0.f, state->progress - apply * 3));
462 // Scroll down. Start with the bottom-most (i.e. front-most in terms of
463 // z-index) window, and try to scroll them down.
464 aura::Window::Windows::const_reverse_iterator iter;
465 for (iter = windows.rbegin();
466 delta_y_p > kEpsilon && iter != windows.rend();
468 aura::Window* window = (*iter);
469 WindowOverviewState* state = window->GetProperty(kWindowOverviewState);
470 if (1.f - state->progress > kEpsilon) {
471 // It is possible to scroll |window| down. Scroll it down, and update
472 // |delta_y_p| for the next window.
473 TransientGroupSetter setter(window);
474 setter.SetWindowProgress(std::min(1.f, state->progress + delta_y_p));
481 int GetScrollableHeight() const {
482 const float kScrollableFraction = 0.85f;
483 const float kScrollableFractionInSplit = 0.5f;
484 const float fraction = split_view_controller_->IsSplitViewModeActive()
485 ? kScrollableFractionInSplit
486 : kScrollableFraction;
487 return container_->bounds().height() * fraction;
490 void CreateFlingerFor(const ui::GestureEvent& event) {
491 gfx::Vector2dF velocity(event.details().velocity_x(),
492 event.details().velocity_y());
493 fling_.reset(new ui::FlingCurve(velocity, gfx::FrameTime::Now()));
496 void AddAnimationObserver() {
497 ui::Compositor* compositor = container_->GetHost()->compositor();
498 if (!compositor->HasAnimationObserver(this))
499 compositor->AddAnimationObserver(this);
502 void RemoveAnimationObserver() {
503 ui::Compositor* compositor = container_->GetHost()->compositor();
504 if (compositor->HasAnimationObserver(this))
505 compositor->RemoveAnimationObserver(this);
508 aura::Window* GetSplitWindowDropTarget(const ui::GestureEvent& event) const {
509 if (!split_view_controller_->IsSplitViewModeActive())
511 CHECK(dragged_window_);
512 CHECK_NE(split_view_controller_->left_window(), dragged_window_);
513 CHECK_NE(split_view_controller_->right_window(), dragged_window_);
514 aura::Window* window = split_view_controller_->left_window();
515 if (GetTransformedBounds(window).Contains(event.location()))
517 window = split_view_controller_->right_window();
518 if (GetTransformedBounds(window).Contains(event.location()))
523 void DragWindow(const ui::GestureEvent& event) {
524 CHECK(dragged_window_);
525 CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE, event.type());
526 CHECK(overview_toolbar_);
527 gfx::Vector2dF dragged_distance =
528 dragged_start_location_ - event.location();
529 WindowOverviewState* dragged_state =
530 dragged_window_->GetProperty(kWindowOverviewState);
531 CHECK(dragged_state);
532 gfx::Transform transform =
533 GetTransformForState(dragged_window_, dragged_state);
534 transform.Translate(-dragged_distance.x(), 0);
535 TransientGroupSetter setter(dragged_window_);
536 setter.SetTransform(transform);
538 // Update the toolbar.
539 const int kMinDistanceForActionButtons = 20;
540 if (fabs(dragged_distance.x()) > kMinDistanceForActionButtons)
541 overview_toolbar_->ShowActionButtons();
543 overview_toolbar_->HideActionButtons();
545 // See if the touch-point is above one of the action-buttons.
546 OverviewToolbar::ActionType new_action =
547 overview_toolbar_->GetHighlightAction(event);
549 // If the touch-point is not above any of the action buttons, then highlight
550 // the close-button by default, if the user has dragged enough to close the
552 if (new_action == OverviewToolbar::ACTION_TYPE_NONE) {
553 if (fabs(dragged_distance.x()) > kMinDistanceForDismissal)
554 new_action = OverviewToolbar::ACTION_TYPE_CLOSE;
556 new_action = OverviewToolbar::ACTION_TYPE_NONE;
558 OverviewToolbar::ActionType previous_action =
559 overview_toolbar_->current_action();
560 overview_toolbar_->SetHighlightAction(new_action);
562 aura::Window* split_drop = GetSplitWindowDropTarget(event);
564 // If the user has selected to get into split-view mode, then show the
565 // window with full opacity. Otherwise, fade it out as it closes. Animate
566 // the opacity if transitioning to/from the split-view button.
567 bool animate_opacity =
568 (new_action != previous_action) &&
569 ((new_action == OverviewToolbar::ACTION_TYPE_SPLIT) ||
570 (previous_action == OverviewToolbar::ACTION_TYPE_SPLIT));
571 float ratio = std::min(
572 1.f, std::abs(dragged_distance.x()) / kMinDistanceForDismissal);
574 (new_action == OverviewToolbar::ACTION_TYPE_SPLIT || split_drop)
576 : gfx::Tween::FloatValueBetween(ratio, kMaxOpacity, kMinOpacity);
577 if (animate_opacity) {
578 AnimateTransientGroupSetter setter(dragged_window_);
579 setter.SetOpacity(opacity);
581 TransientGroupSetter setter(dragged_window_);
582 setter.SetOpacity(opacity);
585 if (split_view_controller_->IsSplitViewModeActive()) {
586 float scale = kOverviewDefaultScale;
587 if (split_drop == split_view_controller_->left_window())
588 scale = kMaxScaleForSplitTarget;
589 TransformSplitWindowScale(split_view_controller_->left_window(), scale);
591 scale = kOverviewDefaultScale;
592 if (split_drop == split_view_controller_->right_window())
593 scale = kMaxScaleForSplitTarget;
594 TransformSplitWindowScale(split_view_controller_->right_window(), scale);
598 bool ShouldCloseDragWindow(const ui::GestureEvent& event) const {
599 gfx::Vector2dF dragged_distance =
600 dragged_start_location_ - event.location();
601 if (event.type() == ui::ET_GESTURE_SCROLL_END)
602 return std::abs(dragged_distance.x()) >= kMinDistanceForDismissal;
603 CHECK_EQ(ui::ET_SCROLL_FLING_START, event.type());
604 const bool dragging_towards_right = dragged_distance.x() < 0;
605 const bool swipe_towards_right = event.details().velocity_x() > 0;
606 if (dragging_towards_right != swipe_towards_right)
608 const float kMinVelocityForDismissal = 500.f;
609 return std::abs(event.details().velocity_x()) > kMinVelocityForDismissal;
612 void CloseDragWindow(const ui::GestureEvent& gesture) {
613 // Animate |dragged_window_| offscreen first, then destroy it.
615 AnimateTransientGroupSetter setter(dragged_window_);
617 WindowOverviewState* dragged_state =
618 dragged_window_->GetProperty(kWindowOverviewState);
619 CHECK(dragged_state);
620 gfx::Transform transform = dragged_window_->layer()->transform();
621 gfx::RectF transformed_bounds = dragged_window_->bounds();
622 transform.TransformRect(&transformed_bounds);
623 float transform_x = 0.f;
624 if (gesture.location().x() > dragged_start_location_.x())
625 transform_x = container_->bounds().right() - transformed_bounds.x();
627 transform_x = -(transformed_bounds.x() + transformed_bounds.width());
628 transform.Translate(transform_x / kOverviewDefaultScale, 0);
630 setter.SetOpacity(kMinOpacity);
632 delete dragged_window_;
633 dragged_window_ = nullptr;
636 void RestoreDragWindow() {
637 CHECK(dragged_window_);
638 WindowOverviewState* dragged_state =
639 dragged_window_->GetProperty(kWindowOverviewState);
640 CHECK(dragged_state);
642 AnimateTransientGroupSetter setter(dragged_window_);
643 setter.SetTransform(GetTransformForState(dragged_window_, dragged_state));
644 setter.SetOpacity(1.0f);
645 dragged_window_ = nullptr;
648 void EndDragWindow(const ui::GestureEvent& gesture) {
649 CHECK(dragged_window_);
650 CHECK(overview_toolbar_);
651 OverviewToolbar::ActionType action = overview_toolbar_->current_action();
652 overview_toolbar_.reset();
653 if (action == OverviewToolbar::ACTION_TYPE_SPLIT) {
654 delegate_->OnSelectSplitViewWindow(
655 nullptr, dragged_window_, dragged_window_);
659 // If the window is dropped on one of the left/right windows in split-mode,
660 // then switch that window.
661 aura::Window* split_drop = GetSplitWindowDropTarget(gesture);
663 aura::Window* left = split_view_controller_->left_window();
664 aura::Window* right = split_view_controller_->right_window();
665 if (left == split_drop)
666 left = dragged_window_;
668 right = dragged_window_;
669 delegate_->OnSelectSplitViewWindow(left, right, dragged_window_);
673 if (ShouldCloseDragWindow(gesture))
674 CloseDragWindow(gesture);
679 void SelectWindow(aura::Window* window) {
680 if (!split_view_controller_->IsSplitViewModeActive()) {
681 delegate_->OnSelectWindow(window);
683 // If the selected window is one of the left/right windows, then keep the
685 if (window == split_view_controller_->left_window() ||
686 window == split_view_controller_->right_window()) {
687 delegate_->OnSelectSplitViewWindow(
688 split_view_controller_->left_window(),
689 split_view_controller_->right_window(),
692 delegate_->OnSelectWindow(window);
698 void OnMouseEvent(ui::MouseEvent* mouse) override {
699 if (mouse->type() == ui::ET_MOUSE_PRESSED) {
700 aura::Window* select = SelectWindowAt(mouse);
703 SelectWindow(select);
705 } else if (mouse->type() == ui::ET_MOUSEWHEEL) {
706 DoScroll(static_cast<ui::MouseWheelEvent*>(mouse)->y_offset());
710 void OnScrollEvent(ui::ScrollEvent* scroll) override {
711 if (scroll->type() == ui::ET_SCROLL)
712 DoScroll(scroll->y_offset());
715 void OnGestureEvent(ui::GestureEvent* gesture) override {
716 if (gesture->type() == ui::ET_GESTURE_TAP) {
717 aura::Window* select = SelectWindowAt(gesture);
719 gesture->SetHandled();
720 SelectWindow(select);
722 } else if (gesture->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
723 if (std::abs(gesture->details().scroll_x_hint()) >
724 std::abs(gesture->details().scroll_y_hint()) * 2) {
725 dragged_start_location_ = gesture->location();
726 dragged_window_ = SelectWindowAt(gesture);
727 if (split_view_controller_->IsSplitViewModeActive() &&
728 (dragged_window_ == split_view_controller_->left_window() ||
729 dragged_window_ == split_view_controller_->right_window())) {
730 // TODO(sad): Allow closing the left/right window. Closing one of
731 // these windows will terminate the split-view mode. Until then, do
732 // not allow closing these (since otherwise it gets into an undefined
734 dragged_window_ = nullptr;
737 if (dragged_window_) {
738 // Show the toolbar (for closing a window, or going into split-view
739 // mode). If already in split-view mode, then do not show the 'Split'
741 overview_toolbar_.reset(new OverviewToolbar(container_));
742 if (!split_view_controller_->CanActivateSplitViewMode()) {
743 overview_toolbar_->DisableAction(
744 OverviewToolbar::ACTION_TYPE_SPLIT);
748 } else if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
750 DragWindow(*gesture);
752 DoScroll(gesture->details().scroll_y());
753 gesture->SetHandled();
754 } else if (gesture->type() == ui::ET_GESTURE_SCROLL_END) {
756 EndDragWindow(*gesture);
757 gesture->SetHandled();
758 } else if (gesture->type() == ui::ET_SCROLL_FLING_START) {
759 if (dragged_window_) {
760 EndDragWindow(*gesture);
762 CreateFlingerFor(*gesture);
763 AddAnimationObserver();
765 gesture->SetHandled();
766 } else if (gesture->type() == ui::ET_GESTURE_TAP_DOWN) {
769 RemoveAnimationObserver();
770 gesture->SetHandled();
772 dragged_window_ = nullptr;
776 // ui::CompositorAnimationObserver:
777 void OnAnimationStep(base::TimeTicks timestamp) override {
779 gfx::Vector2dF delta;
780 bool fling_active = fling_->ComputeScrollDeltaAtTime(timestamp, &delta);
787 RemoveAnimationObserver();
791 // WindowListProviderObserver:
792 void OnWindowStackingChangedInList() override {
793 // Recompute the states of all windows. There isn't enough information at
794 // this point to do anything more clever.
795 ComputeTerminalStatesForAllWindows();
796 SetInitialWindowStates();
799 void OnWindowAddedToList(aura::Window* removed_window) override {}
801 void OnWindowRemovedFromList(aura::Window* removed_window,
802 int index) override {
803 const aura::Window::Windows& windows =
804 window_list_provider_->GetWindowList();
807 CHECK_LE(index, static_cast<int>(windows.size()));
809 // The back-most window has been removed. Move all the remaining windows
810 // one step backwards.
811 for (int i = windows.size() - 1; i > 0; --i) {
812 UpdateTerminalStateForWindowAtIndex(
813 windows[i], windows.size() - 1 - i, windows.size());
814 AnimateWindowTo(windows[i], windows[i - 1]);
816 UpdateTerminalStateForWindowAtIndex(windows.front(),
819 AnimateWindowTo(windows.front(), removed_window);
821 // Move all windows behind the removed window one step forwards.
822 for (int i = 0; i < index - 1; ++i) {
823 UpdateTerminalStateForWindowAtIndex(windows[i], windows.size() - 1 - i,
825 AnimateWindowTo(windows[i], windows[i + 1]);
827 UpdateTerminalStateForWindowAtIndex(windows[index - 1],
828 windows.size() - index,
830 AnimateWindowTo(windows[index - 1], removed_window);
834 const int kMinDistanceForDismissal = 300;
835 const float kMaxOpacity = 1.0f;
836 const float kMinOpacity = 0.2f;
837 const float kMaxScaleForSplitTarget = 0.9f;
839 aura::Window* container_;
840 // Provider of the stack of windows to show in the overview mode. Not owned.
841 WindowListProvider* window_list_provider_;
842 SplitViewController* split_view_controller_;
844 WindowOverviewModeDelegate* delegate_;
845 scoped_ptr<aura::ScopedWindowTargeter> scoped_targeter_;
846 scoped_ptr<ui::FlingCurve> fling_;
848 aura::Window* dragged_window_;
849 gfx::Point dragged_start_location_;
850 scoped_ptr<OverviewToolbar> overview_toolbar_;
852 DISALLOW_COPY_AND_ASSIGN(WindowOverviewModeImpl);
858 scoped_ptr<WindowOverviewMode> WindowOverviewMode::Create(
859 aura::Window* container,
860 WindowListProvider* window_list_provider,
861 SplitViewController* split_view_controller,
862 WindowOverviewModeDelegate* delegate) {
863 return scoped_ptr<WindowOverviewMode>(
864 new WindowOverviewModeImpl(container, window_list_provider,
865 split_view_controller, delegate));
868 } // namespace athena