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.
5 #include "athena/wm/bezel_controller.h"
7 #include "ui/aura/window.h"
8 #include "ui/events/event_handler.h"
9 #include "ui/gfx/display.h"
10 #include "ui/gfx/geometry/point_conversions.h"
11 #include "ui/gfx/screen.h"
12 #include "ui/wm/core/coordinate_conversion.h"
17 // Using bezel swipes, the first touch that is registered is usually within
18 // 5-10 pixels from the edge, but sometimes as far as 29 pixels away.
19 // So setting this width fairly high for now.
20 const float kBezelWidth
= 20.0f
;
22 const float kScrollDeltaNone
= 0;
24 bool ShouldProcessGesture(ui::EventType event_type
) {
25 return event_type
== ui::ET_GESTURE_SCROLL_UPDATE
||
26 event_type
== ui::ET_GESTURE_SCROLL_BEGIN
||
27 event_type
== ui::ET_GESTURE_BEGIN
||
28 event_type
== ui::ET_GESTURE_END
;
31 gfx::Display
GetDisplay(aura::Window
* window
) {
32 gfx::Screen
* screen
= gfx::Screen::GetScreenFor(window
);
33 return screen
->GetDisplayNearestWindow(window
);
36 float GetDistance(const gfx::PointF
& location
,
38 BezelController::Bezel bezel
) {
39 DCHECK(bezel
== BezelController::BEZEL_LEFT
||
40 bezel
== BezelController::BEZEL_RIGHT
);
41 // Convert location from window coordinates to screen coordinates.
42 gfx::Point
point_in_screen(gfx::ToRoundedPoint(location
));
43 wm::ConvertPointToScreen(window
, &point_in_screen
);
44 return bezel
== BezelController::BEZEL_LEFT
46 : point_in_screen
.x() - GetDisplay(window
).bounds().width();
51 BezelController::BezelController(aura::Window
* container
)
52 : container_(container
),
54 scroll_bezel_(BEZEL_NONE
),
56 left_right_delegate_(NULL
) {
59 void BezelController::SetState(BezelController::State state
) {
60 // Use SetState(State, float) if |state| is one of the BEZEL_SCROLLING states.
61 DCHECK_NE(state
, BEZEL_SCROLLING_TWO_FINGERS
);
62 DCHECK_NE(state
, BEZEL_SCROLLING_ONE_FINGER
);
63 SetState(state
, kScrollDeltaNone
);
66 void BezelController::SetState(BezelController::State state
,
68 if (!left_right_delegate_
|| state
== state_
)
71 if (state
== BEZEL_SCROLLING_TWO_FINGERS
)
72 left_right_delegate_
->ScrollBegin(scroll_bezel_
, scroll_delta
);
73 else if (state_
== BEZEL_SCROLLING_TWO_FINGERS
)
74 left_right_delegate_
->ScrollEnd();
77 scroll_bezel_
= BEZEL_NONE
;
78 scroll_target_
= NULL
;
82 // Only implemented for LEFT and RIGHT bezels ATM.
83 BezelController::Bezel
BezelController::GetBezel(const gfx::PointF
& location
) {
84 int screen_width
= GetDisplay(container_
).bounds().width();
85 if (location
.x() < kBezelWidth
) {
87 } else if (location
.x() > screen_width
- kBezelWidth
) {
94 void BezelController::OnGestureEvent(ui::GestureEvent
* event
) {
95 // TODO(mfomitchev): Currently we aren't retargetting or consuming any of the
96 // touch events. This means that content can prevent the generation of gesture
97 // events and two-finger scroll won't work. Possible solution to this problem
98 // is hosting our own gesture recognizer or retargetting touch events at the
101 if (!left_right_delegate_
)
104 ui::EventType type
= event
->type();
105 if (!ShouldProcessGesture(type
))
108 if (scroll_target_
&& event
->target() != scroll_target_
)
111 const gfx::PointF
& event_location
= event
->location_f();
112 const ui::GestureEventDetails
& event_details
= event
->details();
113 int num_touch_points
= event_details
.touch_points();
114 float scroll_delta
= kScrollDeltaNone
;
115 if (scroll_bezel_
!= BEZEL_NONE
) {
116 aura::Window
* target_window
= static_cast<aura::Window
*>(event
->target());
117 scroll_delta
= GetDistance(event_location
, target_window
, scroll_bezel_
);
120 if (type
== ui::ET_GESTURE_BEGIN
) {
121 if (num_touch_points
> 2) {
122 SetState(IGNORE_CURRENT_SCROLL
);
125 BezelController::Bezel event_bezel
= GetBezel(event
->location_f());
128 scroll_bezel_
= event_bezel
;
129 scroll_target_
= event
->target();
130 if (event_bezel
!= BEZEL_LEFT
&& event_bezel
!= BEZEL_RIGHT
)
131 SetState(IGNORE_CURRENT_SCROLL
);
133 SetState(BEZEL_GESTURE_STARTED
);
135 case IGNORE_CURRENT_SCROLL
:
137 case BEZEL_GESTURE_STARTED
:
138 case BEZEL_SCROLLING_ONE_FINGER
:
139 DCHECK_EQ(num_touch_points
, 2);
140 DCHECK(scroll_target_
);
141 DCHECK_NE(scroll_bezel_
, BEZEL_NONE
);
143 if (event_bezel
!= scroll_bezel_
) {
144 SetState(IGNORE_CURRENT_SCROLL
);
147 if (state_
== BEZEL_SCROLLING_ONE_FINGER
)
148 SetState(BEZEL_SCROLLING_TWO_FINGERS
);
150 case BEZEL_SCROLLING_TWO_FINGERS
:
151 // Should've exited above
155 } else if (type
== ui::ET_GESTURE_END
) {
159 CHECK(scroll_target_
);
160 if (num_touch_points
== 1) {
163 SetState(IGNORE_CURRENT_SCROLL
);
165 } else if (type
== ui::ET_GESTURE_SCROLL_BEGIN
) {
166 DCHECK(state_
== IGNORE_CURRENT_SCROLL
|| state_
== BEZEL_GESTURE_STARTED
);
167 if (state_
!= BEZEL_GESTURE_STARTED
)
170 if (num_touch_points
== 1) {
171 SetState(BEZEL_SCROLLING_ONE_FINGER
, scroll_delta
);
175 DCHECK_EQ(num_touch_points
, 2);
176 SetState(BEZEL_SCROLLING_TWO_FINGERS
, scroll_delta
);
177 if (left_right_delegate_
->CanScroll())
179 } else if (type
== ui::ET_GESTURE_SCROLL_UPDATE
) {
180 if (state_
!= BEZEL_SCROLLING_TWO_FINGERS
)
183 left_right_delegate_
->ScrollUpdate(scroll_delta
);
184 if (left_right_delegate_
->CanScroll())
189 } // namespace athena