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.
5 #include "ash/wm/workspace/workspace_cycler.h"
10 #include "ash/wm/workspace/workspace_cycler_configuration.h"
11 #include "ash/wm/workspace/workspace_manager.h"
12 #include "ui/base/events/event.h"
13 #include "ui/base/events/event_utils.h"
15 typedef ash::WorkspaceCyclerConfiguration Config
;
22 // Returns true if cycling is allowed.
23 bool IsCyclingAllowed() {
24 // Cycling is disabled if the screen is locked or a modal dialog is open.
25 return !Shell::GetInstance()->IsScreenLocked() &&
26 !Shell::GetInstance()->IsSystemModalWindowOpen();
31 WorkspaceCycler::WorkspaceCycler(WorkspaceManager
* workspace_manager
)
32 : workspace_manager_(workspace_manager
),
37 ash::Shell::GetInstance()->AddPreTargetHandler(this);
40 WorkspaceCycler::~WorkspaceCycler() {
41 SetState(NOT_CYCLING
);
42 ash::Shell::GetInstance()->RemovePreTargetHandler(this);
45 void WorkspaceCycler::AbortCycling() {
46 SetState(NOT_CYCLING
);
49 void WorkspaceCycler::SetState(State new_state
) {
50 if (state_
== NOT_CYCLING_TRACKING_SCROLL
&& new_state
== STOPPING_CYCLING
)
51 new_state
= NOT_CYCLING
;
53 if (state_
== new_state
|| !IsValidNextState(new_state
))
58 if (new_state
== STARTING_CYCLING
) {
59 animator_
.reset(new WorkspaceCyclerAnimator(this));
60 workspace_manager_
->InitWorkspaceCyclerAnimatorWithCurrentState(
62 animator_
->AnimateStartingCycler();
63 } else if (new_state
== STOPPING_CYCLING
) {
65 animator_
->AnimateStoppingCycler();
66 } else if (new_state
== NOT_CYCLING
) {
69 if (animator_
.get()) {
70 animator_
->AbortAnimations();
76 bool WorkspaceCycler::IsValidNextState(State next_state
) const {
77 if (state_
== next_state
)
83 case NOT_CYCLING_TRACKING_SCROLL
:
84 return state_
== NOT_CYCLING
;
85 case STARTING_CYCLING
:
86 return state_
== NOT_CYCLING_TRACKING_SCROLL
;
88 return state_
== STARTING_CYCLING
;
89 case STOPPING_CYCLING
:
90 return (state_
== STARTING_CYCLING
|| state_
== CYCLING
);
97 void WorkspaceCycler::OnEvent(ui::Event
* event
) {
98 if (!IsCyclingAllowed())
99 SetState(NOT_CYCLING
);
101 if (state_
!= NOT_CYCLING
) {
102 if (event
->type() == ui::ET_SCROLL_FLING_START
||
103 event
->type() == ui::ET_MOUSE_PRESSED
||
104 event
->type() == ui::ET_MOUSE_RELEASED
||
105 event
->IsKeyEvent()) {
106 SetState(STOPPING_CYCLING
);
107 event
->StopPropagation();
111 ui::EventHandler::OnEvent(event
);
114 void WorkspaceCycler::OnScrollEvent(ui::ScrollEvent
* event
) {
115 if (event
->finger_count() != 3 ||
116 event
->type() != ui::ET_SCROLL
) {
117 if (state_
!= NOT_CYCLING
)
118 event
->StopPropagation();
122 if (!IsCyclingAllowed() ||
123 !workspace_manager_
->CanStartCyclingThroughWorkspaces()) {
124 DCHECK_EQ(NOT_CYCLING
, state_
);
128 if (state_
== NOT_CYCLING
)
129 SetState(NOT_CYCLING_TRACKING_SCROLL
);
131 if (ui::IsNaturalScrollEnabled()) {
132 scroll_x_
+= event
->x_offset_ordinal();
133 scroll_y_
+= event
->y_offset_ordinal();
135 scroll_x_
-= event
->x_offset_ordinal();
136 scroll_y_
-= event
->y_offset_ordinal();
139 if (state_
== NOT_CYCLING_TRACKING_SCROLL
) {
140 double distance_to_initiate_cycling
= Config::GetDouble(
141 Config::DISTANCE_TO_INITIATE_CYCLING
);
143 if (fabs(scroll_x_
) > distance_to_initiate_cycling
) {
144 // Only initiate workspace cycling if there recently was a significant
145 // amount of vertical movement as opposed to vertical movement
146 // accumulated over a long horizontal three finger scroll.
151 if (fabs(scroll_y_
) >= distance_to_initiate_cycling
)
152 SetState(STARTING_CYCLING
);
155 if (state_
== CYCLING
&& event
->y_offset_ordinal() != 0.0f
) {
156 DCHECK(animator_
.get());
157 animator_
->AnimateCyclingByScrollDelta(event
->y_offset_ordinal());
162 void WorkspaceCycler::StartWorkspaceCyclerAnimationFinished() {
163 DCHECK_EQ(STARTING_CYCLING
, state_
);
167 void WorkspaceCycler::StopWorkspaceCyclerAnimationFinished() {
168 DCHECK_EQ(STOPPING_CYCLING
, state_
);
169 Workspace
* workspace_to_activate
= animator_
->get_selected_workspace();
171 SetState(NOT_CYCLING
);
173 // Activate the workspace after updating the state so that a call to
174 // AbortCycling() as a result of SetActiveWorkspaceFromCycler() is a noop.
175 workspace_manager_
->SetActiveWorkspaceFromCycler(workspace_to_activate
);
178 } // namespace internal