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