16e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
26e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
36e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// found in the LICENSE file.
46e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
56e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "athena/wm/title_drag_controller.h"
66e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
76e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/bind.h"
86e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/aura/window.h"
96e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/aura/window_delegate.h"
106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/base/hit_test.h"
116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/compositor/closure_animation_observer.h"
126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/compositor/layer.h"
136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/compositor/scoped_layer_animation_settings.h"
146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/wm/core/shadow.h"
156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "ui/wm/core/window_util.h"
166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)namespace {
186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// The minimum amount to drag to confirm a window switch at the end of the
206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// non-fling gesture.
216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const int kMinDragDistanceForSwitch = 300;
226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// The minimum velocity to confirm a window switch for a fling (only applicable
236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// if the amount dragged was not sufficient, i.e. smaller than
246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)// kMinDragDistanceForSwitch).
256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)const int kMinDragVelocityForSwitch = 5000;
266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)namespace athena {
306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)TitleDragController::TitleDragController(aura::Window* container,
326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                         TitleDragControllerDelegate* delegate)
336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    : container_(container),
346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      delegate_(delegate),
356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      weak_ptr_(this) {
366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  CHECK(container_);
376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  CHECK(delegate_);
386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  container_->AddPreTargetHandler(this);
396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)TitleDragController::~TitleDragController() {
426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  container_->RemovePreTargetHandler(this);
436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
456e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void TitleDragController::EndTransition(aura::Window* window, bool complete) {
466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  settings.SetPreemptionStrategy(
486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  settings.AddObserver(new ui::ClosureAnimationObserver(
506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      base::Bind(&TitleDragController::OnTransitionEnd,
516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                 weak_ptr_.GetWeakPtr(),
526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                 window,
536e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                 complete)));
546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  gfx::Transform transform;
556e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  transform.Translate(0, complete ? window->bounds().height() : 0);
566e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  window->SetTransform(transform);
576e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void TitleDragController::OnTransitionEnd(aura::Window* window, bool complete) {
606e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  weak_ptr_.InvalidateWeakPtrs();
616e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!tracker_.Contains(window))
626e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    window = NULL;
636e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  shadow_.reset();
646e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (window) {
656e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    window->SetTransform(gfx::Transform());
666e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    tracker_.Remove(window);
676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (complete && window && wm::IsActiveWindow(window))
696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    delegate_->OnTitleDragCompleted(window);
706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  else
716e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    delegate_->OnTitleDragCanceled(window);
726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void TitleDragController::OnGestureEvent(ui::GestureEvent* gesture) {
756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Do not process any gesture events if an animation is still in progress from
766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // a previous drag.
776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (weak_ptr_.HasWeakPtrs())
786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return;
796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (gesture->type() == ui::ET_GESTURE_TAP_DOWN) {
816e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // It is possible to start a gesture sequence on a second window while a
826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // drag is already in progress (e.g. the user starts interacting with the
836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // window that is being revealed by the title-drag). Ignore these gesture
846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    // sequences.
856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (!tracker_.windows().empty())
866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return;
876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    aura::Window* window = static_cast<aura::Window*>(gesture->target());
886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (!window || !window->delegate())
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return;
906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    int component =
916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        window->delegate()->GetNonClientComponent(gesture->location());
926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (component != HTCAPTION)
936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return;
946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if (!delegate_->GetWindowBehind(window))
956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      return;
966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    tracker_.Add(window);
976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    drag_start_location_ = gesture->root_location();
986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return;
996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // If this gesture is for a different window, then ignore.
1026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  aura::Window* window = static_cast<aura::Window*>(gesture->target());
1036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (!tracker_.Contains(window))
1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return;
1056e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1066e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (gesture->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    delegate_->OnTitleDragStarted(window);
1086e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    shadow_.reset(new wm::Shadow());
1096e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    shadow_->Init(wm::Shadow::STYLE_ACTIVE);
1106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    shadow_->SetContentBounds(gfx::Rect(window->bounds().size()));
1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    window->layer()->Add(shadow_->layer());
1126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    gesture->SetHandled();
1136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return;
1146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
1176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    gfx::Vector2dF distance = gesture->root_location() - drag_start_location_;
1186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    gfx::Transform transform;
1196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    transform.Translate(0, std::max(0.f, distance.y()));
1206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    window->SetTransform(transform);
1216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    gesture->SetHandled();
1226e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return;
1236e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1256e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (gesture->type() == ui::ET_GESTURE_SCROLL_END) {
1266e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    gfx::Vector2dF distance = gesture->root_location() - drag_start_location_;
1276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    EndTransition(window, distance.y() >= kMinDragDistanceForSwitch);
1286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    gesture->SetHandled();
1296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    return;
1306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (gesture->type() == ui::ET_SCROLL_FLING_START) {
1336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    gfx::Vector2dF distance = gesture->root_location() - drag_start_location_;
1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    bool swipe_downwards = gesture->details().velocity_y() > 0;
1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    EndTransition(
1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        window,
1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        swipe_downwards &&
1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)            (distance.y() >= kMinDragDistanceForSwitch ||
1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)             gesture->details().velocity_y() >= kMinDragVelocityForSwitch));
1406e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    gesture->SetHandled();
1416e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  }
1426e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}  // namespace athena
145