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