• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/system_pinch_handler.h"
6 
7 #include "ash/launcher/launcher.h"
8 #include "ash/screen_ash.h"
9 #include "ash/shelf/shelf_widget.h"
10 #include "ash/shell.h"
11 #include "ash/wm/window_animations.h"
12 #include "ash/wm/window_state.h"
13 #include "ash/wm/window_util.h"
14 #include "ash/wm/workspace/snap_sizer.h"
15 #include "ui/aura/window.h"
16 #include "ui/compositor/scoped_layer_animation_settings.h"
17 #include "ui/events/event_constants.h"
18 #include "ui/events/gestures/gesture_types.h"
19 #include "ui/gfx/rect.h"
20 #include "ui/views/widget/widget.h"
21 #include "ui/views/widget/widget_delegate.h"
22 
23 const double kPinchThresholdForMaximize = 1.5;
24 const double kPinchThresholdForMinimize = 0.7;
25 
26 namespace ash {
27 namespace internal {
28 
29 const int SystemPinchHandler::kSystemGesturePoints = 4;
30 
SystemPinchHandler(aura::Window * target)31 SystemPinchHandler::SystemPinchHandler(aura::Window* target)
32     : target_(target),
33       phantom_(target),
34       phantom_state_(PHANTOM_WINDOW_NORMAL),
35       pinch_factor_(1.) {
36   widget_ = views::Widget::GetWidgetForNativeWindow(target_);
37 }
38 
~SystemPinchHandler()39 SystemPinchHandler::~SystemPinchHandler() {
40 }
41 
ProcessGestureEvent(const ui::GestureEvent & event)42 SystemGestureStatus SystemPinchHandler::ProcessGestureEvent(
43     const ui::GestureEvent& event) {
44   // The target has changed, somehow. Let's bale.
45   if (!widget_ || !widget_->widget_delegate()->CanResize())
46     return SYSTEM_GESTURE_END;
47   wm::WindowState* window_state = wm::GetWindowState(target_);
48   switch (event.type()) {
49     case ui::ET_GESTURE_END: {
50       if (event.details().touch_points() > kSystemGesturePoints)
51         break;
52 
53       if (phantom_state_ == PHANTOM_WINDOW_MAXIMIZED) {
54         if (!window_state->IsMaximizedOrFullscreen())
55           window_state->Maximize();
56       } else if (phantom_state_ == PHANTOM_WINDOW_MINIMIZED) {
57         if (window_state->IsMaximizedOrFullscreen()) {
58           window_state->Restore();
59         } else {
60           window_state->Minimize();
61 
62           // NOTE: Minimizing the window will cause this handler to be
63           // destroyed. So do not access anything from |this| from here.
64           return SYSTEM_GESTURE_END;
65         }
66       }
67       return SYSTEM_GESTURE_END;
68     }
69 
70     case ui::ET_GESTURE_PINCH_UPDATE: {
71       // The PINCH_UPDATE events contain incremental scaling updates.
72       pinch_factor_ *= event.details().scale();
73       gfx::Rect bounds =
74           GetPhantomWindowScreenBounds(target_, event.location());
75       if (phantom_state_ != PHANTOM_WINDOW_NORMAL || phantom_.IsShowing())
76         phantom_.Show(bounds);
77       break;
78     }
79 
80     case ui::ET_GESTURE_MULTIFINGER_SWIPE: {
81       phantom_.Hide();
82       pinch_factor_ = 1.0;
83       phantom_state_ = PHANTOM_WINDOW_NORMAL;
84 
85       if (event.details().swipe_left() || event.details().swipe_right()) {
86         // Snap for left/right swipes.
87         ui::ScopedLayerAnimationSettings settings(
88             target_->layer()->GetAnimator());
89         internal::SnapSizer::SnapWindow(window_state,
90             event.details().swipe_left() ? internal::SnapSizer::LEFT_EDGE :
91                                            internal::SnapSizer::RIGHT_EDGE);
92       } else if (event.details().swipe_up()) {
93         if (!window_state->IsMaximizedOrFullscreen())
94           window_state->Maximize();
95       } else if (event.details().swipe_down()) {
96         window_state->Minimize();
97       } else {
98         NOTREACHED() << "Swipe happened without a direction.";
99       }
100       break;
101     }
102 
103     default:
104       break;
105   }
106 
107   return SYSTEM_GESTURE_PROCESSED;
108 }
109 
GetPhantomWindowScreenBounds(aura::Window * window,const gfx::Point & point)110 gfx::Rect SystemPinchHandler::GetPhantomWindowScreenBounds(
111     aura::Window* window,
112     const gfx::Point& point) {
113   if (pinch_factor_ > kPinchThresholdForMaximize) {
114     phantom_state_ = PHANTOM_WINDOW_MAXIMIZED;
115     return ScreenAsh::ConvertRectToScreen(
116         target_->parent(),
117         ScreenAsh::GetMaximizedWindowBoundsInParent(target_));
118   }
119 
120   if (pinch_factor_ < kPinchThresholdForMinimize) {
121     wm::WindowState* window_state = wm::GetWindowState(window);
122     if (window_state->IsMaximizedOrFullscreen()) {
123       if (window_state->HasRestoreBounds()) {
124         phantom_state_ = PHANTOM_WINDOW_MINIMIZED;
125         return  window_state->GetRestoreBoundsInScreen();
126       }
127       return window->bounds();
128     }
129 
130     gfx::Rect rect = GetMinimizeAnimationTargetBoundsInScreen(target_);
131     if (!rect.IsEmpty())
132       rect.Inset(-8, -8);
133     phantom_state_ = PHANTOM_WINDOW_MINIMIZED;
134     return rect;
135   }
136 
137   phantom_state_ = PHANTOM_WINDOW_NORMAL;
138   return window->bounds();
139 }
140 
141 }  // namespace internal
142 }  // namespace ash
143