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