• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "athena/wm/title_drag_controller.h"
6 
7 #include "base/bind.h"
8 #include "ui/aura/window.h"
9 #include "ui/aura/window_delegate.h"
10 #include "ui/base/hit_test.h"
11 #include "ui/compositor/closure_animation_observer.h"
12 #include "ui/compositor/layer.h"
13 #include "ui/compositor/scoped_layer_animation_settings.h"
14 #include "ui/wm/core/shadow.h"
15 #include "ui/wm/core/window_util.h"
16 
17 namespace {
18 
19 // The minimum amount to drag to confirm a window switch at the end of the
20 // non-fling gesture.
21 const int kMinDragDistanceForSwitch = 300;
22 // The minimum velocity to confirm a window switch for a fling (only applicable
23 // if the amount dragged was not sufficient, i.e. smaller than
24 // kMinDragDistanceForSwitch).
25 const int kMinDragVelocityForSwitch = 5000;
26 
27 }
28 
29 namespace athena {
30 
TitleDragController(aura::Window * container,TitleDragControllerDelegate * delegate)31 TitleDragController::TitleDragController(aura::Window* container,
32                                          TitleDragControllerDelegate* delegate)
33     : container_(container),
34       delegate_(delegate),
35       weak_ptr_(this) {
36   CHECK(container_);
37   CHECK(delegate_);
38   container_->AddPreTargetHandler(this);
39 }
40 
~TitleDragController()41 TitleDragController::~TitleDragController() {
42   container_->RemovePreTargetHandler(this);
43 }
44 
EndTransition(aura::Window * window,bool complete)45 void TitleDragController::EndTransition(aura::Window* window, bool complete) {
46   ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
47   settings.SetPreemptionStrategy(
48       ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
49   settings.AddObserver(new ui::ClosureAnimationObserver(
50       base::Bind(&TitleDragController::OnTransitionEnd,
51                  weak_ptr_.GetWeakPtr(),
52                  window,
53                  complete)));
54   gfx::Transform transform;
55   transform.Translate(0, complete ? window->bounds().height() : 0);
56   window->SetTransform(transform);
57 }
58 
OnTransitionEnd(aura::Window * window,bool complete)59 void TitleDragController::OnTransitionEnd(aura::Window* window, bool complete) {
60   weak_ptr_.InvalidateWeakPtrs();
61   if (!tracker_.Contains(window))
62     window = NULL;
63   shadow_.reset();
64   if (window) {
65     window->SetTransform(gfx::Transform());
66     tracker_.Remove(window);
67   }
68   if (complete && window && wm::IsActiveWindow(window))
69     delegate_->OnTitleDragCompleted(window);
70   else
71     delegate_->OnTitleDragCanceled(window);
72 }
73 
OnGestureEvent(ui::GestureEvent * gesture)74 void TitleDragController::OnGestureEvent(ui::GestureEvent* gesture) {
75   // Do not process any gesture events if an animation is still in progress from
76   // a previous drag.
77   if (weak_ptr_.HasWeakPtrs())
78     return;
79 
80   if (gesture->type() == ui::ET_GESTURE_TAP_DOWN) {
81     // It is possible to start a gesture sequence on a second window while a
82     // drag is already in progress (e.g. the user starts interacting with the
83     // window that is being revealed by the title-drag). Ignore these gesture
84     // sequences.
85     if (!tracker_.windows().empty())
86       return;
87     aura::Window* window = static_cast<aura::Window*>(gesture->target());
88     if (!window || !window->delegate())
89       return;
90     int component =
91         window->delegate()->GetNonClientComponent(gesture->location());
92     if (component != HTCAPTION)
93       return;
94     if (!delegate_->GetWindowBehind(window))
95       return;
96     tracker_.Add(window);
97     drag_start_location_ = gesture->root_location();
98     return;
99   }
100 
101   // If this gesture is for a different window, then ignore.
102   aura::Window* window = static_cast<aura::Window*>(gesture->target());
103   if (!tracker_.Contains(window))
104     return;
105 
106   if (gesture->type() == ui::ET_GESTURE_SCROLL_BEGIN) {
107     delegate_->OnTitleDragStarted(window);
108     shadow_.reset(new wm::Shadow());
109     shadow_->Init(wm::Shadow::STYLE_ACTIVE);
110     shadow_->SetContentBounds(gfx::Rect(window->bounds().size()));
111     window->layer()->Add(shadow_->layer());
112     gesture->SetHandled();
113     return;
114   }
115 
116   if (gesture->type() == ui::ET_GESTURE_SCROLL_UPDATE) {
117     gfx::Vector2dF distance = gesture->root_location() - drag_start_location_;
118     gfx::Transform transform;
119     transform.Translate(0, std::max(0.f, distance.y()));
120     window->SetTransform(transform);
121     gesture->SetHandled();
122     return;
123   }
124 
125   if (gesture->type() == ui::ET_GESTURE_SCROLL_END) {
126     gfx::Vector2dF distance = gesture->root_location() - drag_start_location_;
127     EndTransition(window, distance.y() >= kMinDragDistanceForSwitch);
128     gesture->SetHandled();
129     return;
130   }
131 
132   if (gesture->type() == ui::ET_SCROLL_FLING_START) {
133     gfx::Vector2dF distance = gesture->root_location() - drag_start_location_;
134     bool swipe_downwards = gesture->details().velocity_y() > 0;
135     EndTransition(
136         window,
137         swipe_downwards &&
138             (distance.y() >= kMinDragDistanceForSwitch ||
139              gesture->details().velocity_y() >= kMinDragVelocityForSwitch));
140     gesture->SetHandled();
141   }
142 }
143 
144 }  // namespace athena
145