• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // Returns true if the cursor should be hidden on touch events.
29 // TODO(tdanderson|rsadam): Move this function into CursorClient.
ShouldHideCursorOnTouch(const ui::TouchEvent & event)30 bool ShouldHideCursorOnTouch(const ui::TouchEvent& event) {
31 #if defined(OS_WIN)
32   return true;
33 #elif defined(OS_CHROMEOS)
34 #if defined(USE_X11)
35   int device_id = event.source_device_id();
36   if (device_id >= 0 &&
37       !ui::TouchFactory::GetInstance()->IsMultiTouchDevice(device_id)) {
38     // If the touch event is coming from a mouse-device (i.e. not a real
39     // touch-device), then do not hide the cursor.
40     return false;
41   }
42 #endif  // defined(USE_X11)
43   return true;
44 #else
45   // Linux Aura does not hide the cursor on touch by default.
46   // TODO(tdanderson): Change this if having consistency across
47   // all platforms which use Aura is desired.
48   return false;
49 #endif
50 }
51 
52 }  // namespace
53 
54 ////////////////////////////////////////////////////////////////////////////////
55 // CompoundEventFilter, public:
56 
CompoundEventFilter()57 CompoundEventFilter::CompoundEventFilter() {
58 }
59 
~CompoundEventFilter()60 CompoundEventFilter::~CompoundEventFilter() {
61   // Additional filters are not owned by CompoundEventFilter and they
62   // should all be removed when running here. |handlers_| has
63   // check_empty == true and will DCHECK failure if it is not empty.
64 }
65 
66 // static
CursorForWindowComponent(int window_component)67 gfx::NativeCursor CompoundEventFilter::CursorForWindowComponent(
68     int window_component) {
69   switch (window_component) {
70     case HTBOTTOM:
71       return ui::kCursorSouthResize;
72     case HTBOTTOMLEFT:
73       return ui::kCursorSouthWestResize;
74     case HTBOTTOMRIGHT:
75       return ui::kCursorSouthEastResize;
76     case HTLEFT:
77       return ui::kCursorWestResize;
78     case HTRIGHT:
79       return ui::kCursorEastResize;
80     case HTTOP:
81       return ui::kCursorNorthResize;
82     case HTTOPLEFT:
83       return ui::kCursorNorthWestResize;
84     case HTTOPRIGHT:
85       return ui::kCursorNorthEastResize;
86     default:
87       return ui::kCursorNull;
88   }
89 }
90 
AddHandler(ui::EventHandler * handler)91 void CompoundEventFilter::AddHandler(ui::EventHandler* handler) {
92   handlers_.AddObserver(handler);
93 }
94 
RemoveHandler(ui::EventHandler * handler)95 void CompoundEventFilter::RemoveHandler(ui::EventHandler* handler) {
96   handlers_.RemoveObserver(handler);
97 }
98 
99 ////////////////////////////////////////////////////////////////////////////////
100 // CompoundEventFilter, private:
101 
UpdateCursor(aura::Window * target,ui::MouseEvent * event)102 void CompoundEventFilter::UpdateCursor(aura::Window* target,
103                                        ui::MouseEvent* event) {
104   // If drag and drop is in progress, let the drag drop client set the cursor
105   // instead of setting the cursor here.
106   aura::Window* root_window = target->GetRootWindow();
107   aura::client::DragDropClient* drag_drop_client =
108       aura::client::GetDragDropClient(root_window);
109   if (drag_drop_client && drag_drop_client->IsDragDropInProgress())
110     return;
111 
112   aura::client::CursorClient* cursor_client =
113       aura::client::GetCursorClient(root_window);
114   if (cursor_client) {
115     gfx::NativeCursor cursor = target->GetCursor(event->location());
116     if ((event->flags() & ui::EF_IS_NON_CLIENT)) {
117       if (target->delegate()) {
118         int window_component =
119             target->delegate()->GetNonClientComponent(event->location());
120         cursor = CursorForWindowComponent(window_component);
121       } else {
122         // Allow the OS to handle non client cursors if we don't have a
123         // a delegate to handle the non client hittest.
124         return;
125       }
126     }
127     cursor_client->SetCursor(cursor);
128   }
129 }
130 
FilterKeyEvent(ui::KeyEvent * event)131 void CompoundEventFilter::FilterKeyEvent(ui::KeyEvent* event) {
132   if (handlers_.might_have_observers()) {
133     ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
134     ui::EventHandler* handler;
135     while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
136       handler->OnKeyEvent(event);
137   }
138 }
139 
FilterMouseEvent(ui::MouseEvent * event)140 void CompoundEventFilter::FilterMouseEvent(ui::MouseEvent* event) {
141   if (handlers_.might_have_observers()) {
142     ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
143     ui::EventHandler* handler;
144     while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
145       handler->OnMouseEvent(event);
146   }
147 }
148 
FilterTouchEvent(ui::TouchEvent * event)149 void CompoundEventFilter::FilterTouchEvent(ui::TouchEvent* event) {
150   if (handlers_.might_have_observers()) {
151     ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
152     ui::EventHandler* handler;
153     while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
154       handler->OnTouchEvent(event);
155   }
156 }
157 
SetCursorVisibilityOnEvent(aura::Window * target,ui::Event * event,bool show)158 void CompoundEventFilter::SetCursorVisibilityOnEvent(aura::Window* target,
159                                                      ui::Event* event,
160                                                      bool show) {
161   if (event->flags() & ui::EF_IS_SYNTHESIZED)
162     return;
163 
164   aura::client::CursorClient* client =
165       aura::client::GetCursorClient(target->GetRootWindow());
166   if (!client)
167     return;
168 
169   if (show)
170     client->ShowCursor();
171   else
172     client->HideCursor();
173 }
174 
SetMouseEventsEnableStateOnEvent(aura::Window * target,ui::Event * event,bool enable)175 void CompoundEventFilter::SetMouseEventsEnableStateOnEvent(aura::Window* target,
176                                                            ui::Event* event,
177                                                            bool enable) {
178   if (event->flags() & ui::EF_IS_SYNTHESIZED)
179     return;
180   aura::client::CursorClient* client =
181       aura::client::GetCursorClient(target->GetRootWindow());
182   if (!client)
183     return;
184 
185   if (enable)
186     client->EnableMouseEvents();
187   else
188     client->DisableMouseEvents();
189 }
190 
191 ////////////////////////////////////////////////////////////////////////////////
192 // CompoundEventFilter, ui::EventHandler implementation:
193 
OnKeyEvent(ui::KeyEvent * event)194 void CompoundEventFilter::OnKeyEvent(ui::KeyEvent* event) {
195   aura::Window* target = static_cast<aura::Window*>(event->target());
196   aura::client::CursorClient* client =
197       aura::client::GetCursorClient(target->GetRootWindow());
198   if (client && client->ShouldHideCursorOnKeyEvent(*event))
199     SetCursorVisibilityOnEvent(target, event, false);
200 
201   FilterKeyEvent(event);
202 }
203 
OnMouseEvent(ui::MouseEvent * event)204 void CompoundEventFilter::OnMouseEvent(ui::MouseEvent* event) {
205   aura::Window* window = static_cast<aura::Window*>(event->target());
206   aura::WindowTracker window_tracker;
207   window_tracker.Add(window);
208 
209   // We must always update the cursor, otherwise the cursor can get stuck if an
210   // event filter registered with us consumes the event.
211   // It should also update the cursor for clicking and wheels for ChromeOS boot.
212   // When ChromeOS is booted, it hides the mouse cursor but immediate mouse
213   // operation will show the cursor.
214   // We also update the cursor for mouse enter in case a mouse cursor is sent to
215   // outside of the root window and moved back for some reasons (e.g. running on
216   // on Desktop for testing, or a bug in pointer barrier).
217   if (!(event->flags() & ui::EF_FROM_TOUCH) &&
218        (event->type() == ui::ET_MOUSE_ENTERED ||
219         event->type() == ui::ET_MOUSE_MOVED ||
220         event->type() == ui::ET_MOUSE_PRESSED ||
221         event->type() == ui::ET_MOUSEWHEEL)) {
222     SetMouseEventsEnableStateOnEvent(window, event, true);
223     SetCursorVisibilityOnEvent(window, event, true);
224     UpdateCursor(window, event);
225   }
226 
227   FilterMouseEvent(event);
228 }
229 
OnScrollEvent(ui::ScrollEvent * event)230 void CompoundEventFilter::OnScrollEvent(ui::ScrollEvent* event) {
231 }
232 
OnTouchEvent(ui::TouchEvent * event)233 void CompoundEventFilter::OnTouchEvent(ui::TouchEvent* event) {
234   FilterTouchEvent(event);
235   if (!event->handled() && event->type() == ui::ET_TOUCH_PRESSED &&
236       ShouldHideCursorOnTouch(*event) &&
237       !aura::Env::GetInstance()->IsMouseButtonDown()) {
238     SetMouseEventsEnableStateOnEvent(
239         static_cast<aura::Window*>(event->target()), event, false);
240   }
241 }
242 
OnGestureEvent(ui::GestureEvent * event)243 void CompoundEventFilter::OnGestureEvent(ui::GestureEvent* event) {
244   if (handlers_.might_have_observers()) {
245     ObserverListBase<ui::EventHandler>::Iterator it(handlers_);
246     ui::EventHandler* handler;
247     while (!event->stopped_propagation() && (handler = it.GetNext()) != NULL)
248       handler->OnGestureEvent(event);
249   }
250 
251 #if defined(OS_WIN)
252   // A Win8 edge swipe event is a special event that does not have location
253   // information associated with it, and is not preceeded by an ET_TOUCH_PRESSED
254   // event.  So we treat it specially here.
255   if (!event->handled() && event->type() == ui::ET_GESTURE_WIN8_EDGE_SWIPE &&
256       !aura::Env::GetInstance()->IsMouseButtonDown()) {
257     SetMouseEventsEnableStateOnEvent(
258         static_cast<aura::Window*>(event->target()), event, false);
259   }
260 #endif
261 }
262 
263 }  // namespace wm
264