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. 4 5 #include "ash/wm/gestures/tray_gesture_handler.h" 6 7 #include "ash/shell.h" 8 #include "ash/system/tray/system_tray.h" 9 #include "ash/system/tray/system_tray_bubble.h" 10 #include "ui/aura/window.h" 11 #include "ui/compositor/layer.h" 12 #include "ui/events/event.h" 13 #include "ui/gfx/transform.h" 14 #include "ui/views/widget/widget.h" 15 16 const int kMinBubbleHeight = 13; 17 18 namespace ash { 19 TrayGestureHandler()20TrayGestureHandler::TrayGestureHandler() 21 : widget_(NULL), 22 gesture_drag_amount_(0) { 23 // TODO(oshima): Support multiple display case. 24 SystemTray* tray = Shell::GetInstance()->GetPrimarySystemTray(); 25 tray->ShowDefaultView(BUBBLE_CREATE_NEW); 26 SystemTrayBubble* bubble = tray->GetSystemBubble(); 27 if (!bubble) 28 return; 29 bubble->bubble_view()->set_gesture_dragging(true); 30 widget_ = bubble->bubble_view()->GetWidget(); 31 widget_->AddObserver(this); 32 33 gfx::Rect bounds = widget_->GetWindowBoundsInScreen(); 34 int height_change = bounds.height() - kMinBubbleHeight; 35 bounds.set_height(kMinBubbleHeight); 36 bounds.set_y(bounds.y() + height_change); 37 widget_->SetBounds(bounds); 38 } 39 ~TrayGestureHandler()40TrayGestureHandler::~TrayGestureHandler() { 41 if (widget_) 42 widget_->RemoveObserver(this); 43 } 44 UpdateGestureDrag(const ui::GestureEvent & event)45bool TrayGestureHandler::UpdateGestureDrag(const ui::GestureEvent& event) { 46 CHECK_EQ(ui::ET_GESTURE_SCROLL_UPDATE, event.type()); 47 if (!widget_) 48 return false; 49 50 gesture_drag_amount_ += event.details().scroll_y(); 51 if (gesture_drag_amount_ > 0 && gesture_drag_amount_ < kMinBubbleHeight) { 52 widget_->Close(); 53 return false; 54 } 55 56 gfx::Rect bounds = widget_->GetWindowBoundsInScreen(); 57 int new_height = std::min( 58 kMinBubbleHeight + std::max(0, static_cast<int>(-gesture_drag_amount_)), 59 widget_->GetContentsView()->GetPreferredSize().height()); 60 int height_change = bounds.height() - new_height; 61 bounds.set_height(new_height); 62 bounds.set_y(bounds.y() + height_change); 63 widget_->SetBounds(bounds); 64 return true; 65 } 66 CompleteGestureDrag(const ui::GestureEvent & event)67void TrayGestureHandler::CompleteGestureDrag(const ui::GestureEvent& event) { 68 if (!widget_) 69 return; 70 71 widget_->RemoveObserver(this); 72 73 // Close the widget if it hasn't been dragged enough. 74 bool should_close = false; 75 int height = widget_->GetWindowBoundsInScreen().height(); 76 int preferred_height = 77 widget_->GetContentsView()->GetPreferredSize().height(); 78 if (event.type() == ui::ET_GESTURE_SCROLL_END) { 79 const float kMinThresholdGestureDrag = 0.4f; 80 if (height < preferred_height * kMinThresholdGestureDrag) 81 should_close = true; 82 } else if (event.type() == ui::ET_SCROLL_FLING_START) { 83 const float kMinThresholdGestureDragExposeFling = 0.25f; 84 const float kMinThresholdGestureFling = 1000.f; 85 if (height < preferred_height * kMinThresholdGestureDragExposeFling && 86 event.details().velocity_y() > -kMinThresholdGestureFling) 87 should_close = true; 88 } else { 89 NOTREACHED(); 90 } 91 92 if (should_close) { 93 widget_->Close(); 94 } else { 95 SystemTrayBubble* bubble = 96 Shell::GetInstance()->GetPrimarySystemTray()->GetSystemBubble(); 97 if (bubble) 98 bubble->bubble_view()->set_gesture_dragging(false); 99 } 100 } 101 OnWidgetDestroying(views::Widget * widget)102void TrayGestureHandler::OnWidgetDestroying(views::Widget* widget) { 103 CHECK_EQ(widget_, widget); 104 widget_ = NULL; 105 } 106 107 } // namespace ash 108