- add sources.
[platform/framework/web/crosswalk.git] / src / ui / views / corewm / compound_event_filter.cc
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 "ui/views/corewm/compound_event_filter.h"
6
7 #include "base/containers/hash_tables.h"
8 #include "base/logging.h"
9 #include "ui/aura/client/activation_client.h"
10 #include "ui/aura/client/cursor_client.h"
11 #include "ui/aura/client/drag_drop_client.h"
12 #include "ui/aura/env.h"
13 #include "ui/aura/root_window.h"
14 #include "ui/aura/window_delegate.h"
15 #include "ui/aura/window_tracker.h"
16 #include "ui/base/hit_test.h"
17 #include "ui/events/event.h"
18
19 namespace views {
20 namespace corewm {
21
22 namespace {
23
24 bool ShouldHideCursorOnKeyEvent(const ui::KeyEvent& event) {
25 #if defined(OS_CHROMEOS)
26   // All alt and control key commands are ignored.
27   if (event.IsAltDown() || event.IsControlDown())
28     return false;
29
30   static bool inited = false;
31   static base::hash_set<int32> ignored_keys;
32   if (!inited) {
33     // Modifiers.
34     ignored_keys.insert(ui::VKEY_SHIFT);
35     ignored_keys.insert(ui::VKEY_CONTROL);
36     ignored_keys.insert(ui::VKEY_MENU);
37
38     // Search key == VKEY_LWIN.
39     ignored_keys.insert(ui::VKEY_LWIN);
40
41     // Function keys.
42     for (int key = ui::VKEY_F1; key <= ui::VKEY_F24; ++key)
43       ignored_keys.insert(key);
44
45     // Media keys.
46     for (int key = ui::VKEY_BROWSER_BACK; key <= ui::VKEY_MEDIA_LAUNCH_APP2;
47          ++key) {
48       ignored_keys.insert(key);
49     }
50
51 #if defined(OS_POSIX)
52     ignored_keys.insert(ui::VKEY_WLAN);
53     ignored_keys.insert(ui::VKEY_POWER);
54     ignored_keys.insert(ui::VKEY_BRIGHTNESS_DOWN);
55     ignored_keys.insert(ui::VKEY_BRIGHTNESS_UP);
56     ignored_keys.insert(ui::VKEY_KBD_BRIGHTNESS_DOWN);
57     ignored_keys.insert(ui::VKEY_KBD_BRIGHTNESS_UP);
58 #endif
59
60     inited = true;
61   }
62
63   if (ignored_keys.count(event.key_code()) > 0)
64     return false;
65
66   return true;
67 #else  // !defined(OS_CHROMEOS)
68   return false;
69 #endif  // defined(OS_CHROMEOS)
70 }
71
72 // Returns true if the cursor should be hidden on touch events.
73 bool ShouldHideCursorOnTouch() {
74 #if defined(OS_CHROMEOS)
75   return true;
76 #else
77   // Not necessary on windows as windows does it for us. If we do need this
78   // funcionality on linux (non-chromeos) we need to make sure
79   // CompoundEventFilter shows on the right root (it currently doesn't always).
80   return false;
81 #endif
82 }
83
84 }  // namespace
85
86 ////////////////////////////////////////////////////////////////////////////////
87 // CompoundEventFilter, public:
88
89 CompoundEventFilter::CompoundEventFilter() : cursor_hidden_by_filter_(false) {
90 }
91
92 CompoundEventFilter::~CompoundEventFilter() {
93   // Additional filters are not owned by CompoundEventFilter and they
94   // should all be removed when running here. |handlers_| has
95   // check_empty == true and will DCHECK failure if it is not empty.
96 }
97
98 // static
99 gfx::NativeCursor CompoundEventFilter::CursorForWindowComponent(
100     int window_component) {
101   switch (window_component) {
102     case HTBOTTOM:
103       return ui::kCursorSouthResize;
104     case HTBOTTOMLEFT:
105       return ui::kCursorSouthWestResize;
106     case HTBOTTOMRIGHT:
107       return ui::kCursorSouthEastResize;
108     case HTLEFT:
109       return ui::kCursorWestResize;
110     case HTRIGHT:
111       return ui::kCursorEastResize;
112     case HTTOP:
113       return ui::kCursorNorthResize;
114     case HTTOPLEFT:
115       return ui::kCursorNorthWestResize;
116     case HTTOPRIGHT:
117       return ui::kCursorNorthEastResize;
118     default:
119       return ui::kCursorNull;
120   }
121 }
122
123 void CompoundEventFilter::AddHandler(ui::EventHandler* handler) {
124   handlers_.AddObserver(handler);
125 }
126
127 void CompoundEventFilter::RemoveHandler(ui::EventHandler* handler) {
128   handlers_.RemoveObserver(handler);
129 }
130
131 ////////////////////////////////////////////////////////////////////////////////
132 // CompoundEventFilter, private:
133
134 void CompoundEventFilter::UpdateCursor(aura::Window* target,
135                                        ui::MouseEvent* event) {
136   // If drag and drop is in progress, let the drag drop client set the cursor
137   // instead of setting the cursor here.
138   aura::Window* root_window = target->GetRootWindow();
139   aura::client::DragDropClient* drag_drop_client =
140       aura::client::GetDragDropClient(root_window);
141   if (drag_drop_client && drag_drop_client->IsDragDropInProgress())
142     return;
143
144   aura::client::CursorClient* cursor_client =
145       aura::client::GetCursorClient(root_window);
146   if (cursor_client) {
147     gfx::NativeCursor cursor = target->GetCursor(event->location());
148     if (event->flags() & ui::EF_IS_NON_CLIENT) {
149       int window_component =
150           target->delegate()->GetNonClientComponent(event->location());
151       cursor = CursorForWindowComponent(window_component);
152     }
153
154     cursor_client->SetCursor(cursor);
155   }
156 }
157
158 void CompoundEventFilter::FilterKeyEvent(ui::KeyEvent* event) {
159   if (handlers_.might_have_observers()) {
160     ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
161     ui::EventHandler* handler;
162     while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
163       handler->OnKeyEvent(event);
164   }
165 }
166
167 void CompoundEventFilter::FilterMouseEvent(ui::MouseEvent* event) {
168   if (handlers_.might_have_observers()) {
169     ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
170     ui::EventHandler* handler;
171     while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
172       handler->OnMouseEvent(event);
173   }
174 }
175
176 void CompoundEventFilter::FilterTouchEvent(ui::TouchEvent* event) {
177   if (handlers_.might_have_observers()) {
178     ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
179     ui::EventHandler* handler;
180     while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
181       handler->OnTouchEvent(event);
182   }
183 }
184
185 void CompoundEventFilter::SetCursorVisibilityOnEvent(aura::Window* target,
186                                                      ui::Event* event,
187                                                      bool show) {
188   DCHECK(ShouldHideCursorOnTouch());
189   if (event->flags() & ui::EF_IS_SYNTHESIZED)
190     return;
191
192   aura::client::CursorClient* client =
193       aura::client::GetCursorClient(target->GetRootWindow());
194   if (!client)
195     return;
196
197   if (show && cursor_hidden_by_filter_) {
198     cursor_hidden_by_filter_ = false;
199     client->ShowCursor();
200   } else if (!show && !cursor_hidden_by_filter_) {
201     cursor_hidden_by_filter_ = true;
202     client->HideCursor();
203   } else if (show && !client->IsCursorVisible() && !client->IsCursorLocked()) {
204     // TODO(tdanderson): Remove this temporary logging once the issues related
205     // to a disappearing mouse cursor on the Pixel login screen / Pixel
206     // wakeup have been resolved. See crbug.com/275826.
207     LOG(ERROR) << "Event of type " << event->type() << " did not show cursor."
208                << " Mouse enabled state is " << client->IsMouseEventsEnabled();
209   }
210 }
211
212 void CompoundEventFilter::SetMouseEventsEnableStateOnEvent(aura::Window* target,
213                                                            ui::Event* event,
214                                                            bool enable) {
215   if (event->flags() & ui::EF_IS_SYNTHESIZED)
216     return;
217   aura::client::CursorClient* client =
218       aura::client::GetCursorClient(target->GetRootWindow());
219   if (!client)
220     return;
221
222   if (enable)
223     client->EnableMouseEvents();
224   else
225     client->DisableMouseEvents();
226 }
227
228 ////////////////////////////////////////////////////////////////////////////////
229 // CompoundEventFilter, ui::EventHandler implementation:
230
231 void CompoundEventFilter::OnKeyEvent(ui::KeyEvent* event) {
232   if (ShouldHideCursorOnKeyEvent(*event)) {
233     SetCursorVisibilityOnEvent(
234         static_cast<aura::Window*>(event->target()), event, false);
235   }
236
237   FilterKeyEvent(event);
238 }
239
240 void CompoundEventFilter::OnMouseEvent(ui::MouseEvent* event) {
241   aura::Window* window = static_cast<aura::Window*>(event->target());
242   aura::WindowTracker window_tracker;
243   window_tracker.Add(window);
244
245   // We must always update the cursor, otherwise the cursor can get stuck if an
246   // event filter registered with us consumes the event.
247   // It should also update the cursor for clicking and wheels for ChromeOS boot.
248   // When ChromeOS is booted, it hides the mouse cursor but immediate mouse
249   // operation will show the cursor.
250   // We also update the cursor for mouse enter in case a mouse cursor is sent to
251   // outside of the root window and moved back for some reasons (e.g. running on
252   // on Desktop for testing, or a bug in pointer barrier).
253   if (event->type() == ui::ET_MOUSE_ENTERED ||
254       event->type() == ui::ET_MOUSE_MOVED ||
255       event->type() == ui::ET_MOUSE_PRESSED ||
256       event->type() == ui::ET_MOUSEWHEEL) {
257     if (ShouldHideCursorOnTouch()) {
258       SetMouseEventsEnableStateOnEvent(window, event, true);
259       SetCursorVisibilityOnEvent(window, event, true);
260     }
261     UpdateCursor(window, event);
262   }
263
264   FilterMouseEvent(event);
265 }
266
267 void CompoundEventFilter::OnScrollEvent(ui::ScrollEvent* event) {
268 }
269
270 void CompoundEventFilter::OnTouchEvent(ui::TouchEvent* event) {
271   FilterTouchEvent(event);
272   if (ShouldHideCursorOnTouch() && !event->handled() &&
273       event->type() == ui::ET_TOUCH_PRESSED &&
274       !aura::Env::GetInstance()->IsMouseButtonDown()) {
275     SetMouseEventsEnableStateOnEvent(
276         static_cast<aura::Window*>(event->target()), event, false);
277   }
278 }
279
280 void CompoundEventFilter::OnGestureEvent(ui::GestureEvent* event) {
281   if (handlers_.might_have_observers()) {
282     ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
283     ui::EventHandler* handler;
284     while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
285       handler->OnGestureEvent(event);
286   }
287 }
288
289 }  // namespace corewm
290 }  // namespace views