OLD | NEW |
| (Empty) |
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/aura/root_window.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/command_line.h" | |
11 #include "base/debug/trace_event.h" | |
12 #include "base/logging.h" | |
13 #include "base/message_loop/message_loop.h" | |
14 #include "ui/aura/client/capture_client.h" | |
15 #include "ui/aura/client/cursor_client.h" | |
16 #include "ui/aura/client/event_client.h" | |
17 #include "ui/aura/client/focus_client.h" | |
18 #include "ui/aura/client/screen_position_client.h" | |
19 #include "ui/aura/env.h" | |
20 #include "ui/aura/root_window_observer.h" | |
21 #include "ui/aura/window.h" | |
22 #include "ui/aura/window_delegate.h" | |
23 #include "ui/aura/window_targeter.h" | |
24 #include "ui/aura/window_tracker.h" | |
25 #include "ui/aura/window_tree_host.h" | |
26 #include "ui/base/hit_test.h" | |
27 #include "ui/base/view_prop.h" | |
28 #include "ui/compositor/dip_util.h" | |
29 #include "ui/compositor/layer.h" | |
30 #include "ui/compositor/layer_animator.h" | |
31 #include "ui/events/event.h" | |
32 #include "ui/events/gestures/gesture_recognizer.h" | |
33 #include "ui/events/gestures/gesture_types.h" | |
34 #include "ui/gfx/screen.h" | |
35 | |
36 using std::vector; | |
37 | |
38 typedef ui::EventDispatchDetails DispatchDetails; | |
39 | |
40 namespace aura { | |
41 | |
42 namespace { | |
43 | |
44 const char kRootWindowForAcceleratedWidget[] = | |
45 "__AURA_ROOT_WINDOW_ACCELERATED_WIDGET__"; | |
46 | |
47 // Returns true if |target| has a non-client (frame) component at |location|, | |
48 // in window coordinates. | |
49 bool IsNonClientLocation(Window* target, const gfx::Point& location) { | |
50 if (!target->delegate()) | |
51 return false; | |
52 int hit_test_code = target->delegate()->GetNonClientComponent(location); | |
53 return hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE; | |
54 } | |
55 | |
56 Window* ConsumerToWindow(ui::GestureConsumer* consumer) { | |
57 return consumer ? static_cast<Window*>(consumer) : NULL; | |
58 } | |
59 | |
60 void SetLastMouseLocation(const Window* root_window, | |
61 const gfx::Point& location_in_root) { | |
62 client::ScreenPositionClient* client = | |
63 client::GetScreenPositionClient(root_window); | |
64 if (client) { | |
65 gfx::Point location_in_screen = location_in_root; | |
66 client->ConvertPointToScreen(root_window, &location_in_screen); | |
67 Env::GetInstance()->set_last_mouse_location(location_in_screen); | |
68 } else { | |
69 Env::GetInstance()->set_last_mouse_location(location_in_root); | |
70 } | |
71 } | |
72 | |
73 WindowTreeHost* CreateHost(WindowEventDispatcher* dispatcher, | |
74 const WindowEventDispatcher::CreateParams& params) { | |
75 WindowTreeHost* host = params.host ? | |
76 params.host : WindowTreeHost::Create(params.initial_bounds); | |
77 host->set_delegate(dispatcher); | |
78 return host; | |
79 } | |
80 | |
81 bool IsEventCandidateForHold(const ui::Event& event) { | |
82 if (event.type() == ui::ET_TOUCH_MOVED) | |
83 return true; | |
84 if (event.type() == ui::ET_MOUSE_DRAGGED) | |
85 return true; | |
86 if (event.IsMouseEvent() && (event.flags() & ui::EF_IS_SYNTHESIZED)) | |
87 return true; | |
88 return false; | |
89 } | |
90 | |
91 } // namespace | |
92 | |
93 WindowEventDispatcher::CreateParams::CreateParams( | |
94 const gfx::Rect& a_initial_bounds) | |
95 : initial_bounds(a_initial_bounds), | |
96 host(NULL) { | |
97 } | |
98 | |
99 //////////////////////////////////////////////////////////////////////////////// | |
100 // WindowEventDispatcher, public: | |
101 | |
102 WindowEventDispatcher::WindowEventDispatcher(const CreateParams& params) | |
103 : window_(new Window(NULL)), | |
104 host_(CreateHost(this, params)), | |
105 touch_ids_down_(0), | |
106 mouse_pressed_handler_(NULL), | |
107 mouse_moved_handler_(NULL), | |
108 event_dispatch_target_(NULL), | |
109 old_dispatch_target_(NULL), | |
110 synthesize_mouse_move_(false), | |
111 move_hold_count_(0), | |
112 dispatching_held_event_(false), | |
113 repost_event_factory_(this), | |
114 held_event_factory_(this) { | |
115 window()->set_dispatcher(this); | |
116 window()->SetName("RootWindow"); | |
117 window()->SetEventTargeter( | |
118 scoped_ptr<ui::EventTargeter>(new WindowTargeter())); | |
119 | |
120 prop_.reset(new ui::ViewProp(host_->GetAcceleratedWidget(), | |
121 kRootWindowForAcceleratedWidget, | |
122 this)); | |
123 ui::GestureRecognizer::Get()->AddGestureEventHelper(this); | |
124 } | |
125 | |
126 WindowEventDispatcher::~WindowEventDispatcher() { | |
127 TRACE_EVENT0("shutdown", "WindowEventDispatcher::Destructor"); | |
128 | |
129 ui::GestureRecognizer::Get()->RemoveGestureEventHelper(this); | |
130 | |
131 // An observer may have been added by an animation on the | |
132 // WindowEventDispatcher. | |
133 window()->layer()->GetAnimator()->RemoveObserver(this); | |
134 | |
135 // Destroy child windows while we're still valid. This is also done by | |
136 // ~Window, but by that time any calls to virtual methods overriden here (such | |
137 // as GetRootWindow()) result in Window's implementation. By destroying here | |
138 // we ensure GetRootWindow() still returns this. | |
139 window()->RemoveOrDestroyChildren(); | |
140 | |
141 // Destroying/removing child windows may try to access |host_| (eg. | |
142 // GetAcceleratedWidget()) | |
143 host_.reset(NULL); | |
144 | |
145 window()->set_dispatcher(NULL); | |
146 } | |
147 | |
148 // static | |
149 WindowEventDispatcher* WindowEventDispatcher::GetForAcceleratedWidget( | |
150 gfx::AcceleratedWidget widget) { | |
151 return reinterpret_cast<WindowEventDispatcher*>( | |
152 ui::ViewProp::GetValue(widget, kRootWindowForAcceleratedWidget)); | |
153 } | |
154 | |
155 void WindowEventDispatcher::PrepareForShutdown() { | |
156 host_->PrepareForShutdown(); | |
157 // discard synthesize event request as well. | |
158 synthesize_mouse_move_ = false; | |
159 } | |
160 | |
161 void WindowEventDispatcher::RepostEvent(const ui::LocatedEvent& event) { | |
162 DCHECK(event.type() == ui::ET_MOUSE_PRESSED || | |
163 event.type() == ui::ET_GESTURE_TAP_DOWN); | |
164 // We allow for only one outstanding repostable event. This is used | |
165 // in exiting context menus. A dropped repost request is allowed. | |
166 if (event.type() == ui::ET_MOUSE_PRESSED) { | |
167 held_repostable_event_.reset( | |
168 new ui::MouseEvent( | |
169 static_cast<const ui::MouseEvent&>(event), | |
170 static_cast<aura::Window*>(event.target()), | |
171 window())); | |
172 base::MessageLoop::current()->PostNonNestableTask( | |
173 FROM_HERE, base::Bind( | |
174 base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents), | |
175 repost_event_factory_.GetWeakPtr())); | |
176 } else { | |
177 DCHECK(event.type() == ui::ET_GESTURE_TAP_DOWN); | |
178 held_repostable_event_.reset(); | |
179 // TODO(rbyers): Reposing of gestures is tricky to get | |
180 // right, so it's not yet supported. crbug.com/170987. | |
181 } | |
182 } | |
183 | |
184 WindowTreeHostDelegate* WindowEventDispatcher::AsWindowTreeHostDelegate() { | |
185 return this; | |
186 } | |
187 | |
188 void WindowEventDispatcher::OnMouseEventsEnableStateChanged(bool enabled) { | |
189 // Send entered / exited so that visual state can be updated to match | |
190 // mouse events state. | |
191 PostMouseMoveEventAfterWindowChange(); | |
192 // TODO(mazda): Add code to disable mouse events when |enabled| == false. | |
193 } | |
194 | |
195 Window* WindowEventDispatcher::GetGestureTarget(ui::GestureEvent* event) { | |
196 Window* target = NULL; | |
197 if (!event->IsEndingEvent()) { | |
198 // The window that received the start event (e.g. scroll begin) needs to | |
199 // receive the end event (e.g. scroll end). | |
200 target = client::GetCaptureWindow(window()); | |
201 } | |
202 if (!target) { | |
203 target = ConsumerToWindow( | |
204 ui::GestureRecognizer::Get()->GetTargetForGestureEvent(*event)); | |
205 } | |
206 | |
207 return target; | |
208 } | |
209 | |
210 void WindowEventDispatcher::DispatchGestureEvent(ui::GestureEvent* event) { | |
211 DispatchDetails details = DispatchHeldEvents(); | |
212 if (details.dispatcher_destroyed) | |
213 return; | |
214 | |
215 Window* target = GetGestureTarget(event); | |
216 if (target) { | |
217 event->ConvertLocationToTarget(window(), target); | |
218 DispatchDetails details = DispatchEvent(target, event); | |
219 if (details.dispatcher_destroyed) | |
220 return; | |
221 } | |
222 } | |
223 | |
224 void WindowEventDispatcher::OnWindowDestroying(Window* window) { | |
225 DispatchMouseExitToHidingWindow(window); | |
226 if (window->IsVisible() && | |
227 window->ContainsPointInRoot(GetLastMouseLocationInRoot())) { | |
228 PostMouseMoveEventAfterWindowChange(); | |
229 } | |
230 | |
231 // Hiding the window releases capture which can implicitly destroy the window | |
232 // so the window may no longer be valid after this call. | |
233 OnWindowHidden(window, WINDOW_DESTROYED); | |
234 } | |
235 | |
236 void WindowEventDispatcher::OnWindowBoundsChanged(Window* window, | |
237 bool contained_mouse_point) { | |
238 if (contained_mouse_point || | |
239 (window->IsVisible() && | |
240 window->ContainsPointInRoot(GetLastMouseLocationInRoot()))) { | |
241 PostMouseMoveEventAfterWindowChange(); | |
242 } | |
243 } | |
244 | |
245 void WindowEventDispatcher::DispatchMouseExitToHidingWindow(Window* window) { | |
246 // The mouse capture is intentionally ignored. Think that a mouse enters | |
247 // to a window, the window sets the capture, the mouse exits the window, | |
248 // and then it releases the capture. In that case OnMouseExited won't | |
249 // be called. So it is natural not to emit OnMouseExited even though | |
250 // |window| is the capture window. | |
251 gfx::Point last_mouse_location = GetLastMouseLocationInRoot(); | |
252 if (window->Contains(mouse_moved_handler_) && | |
253 window->ContainsPointInRoot(last_mouse_location)) | |
254 DispatchMouseExitAtPoint(last_mouse_location); | |
255 } | |
256 | |
257 void WindowEventDispatcher::DispatchMouseExitAtPoint(const gfx::Point& point) { | |
258 ui::MouseEvent event(ui::ET_MOUSE_EXITED, point, point, ui::EF_NONE, | |
259 ui::EF_NONE); | |
260 DispatchDetails details = | |
261 DispatchMouseEnterOrExit(event, ui::ET_MOUSE_EXITED); | |
262 if (details.dispatcher_destroyed) | |
263 return; | |
264 } | |
265 | |
266 void WindowEventDispatcher::OnWindowVisibilityChanged(Window* window, | |
267 bool is_visible) { | |
268 if (window->ContainsPointInRoot(GetLastMouseLocationInRoot())) | |
269 PostMouseMoveEventAfterWindowChange(); | |
270 | |
271 // Hiding the window releases capture which can implicitly destroy the window | |
272 // so the window may no longer be valid after this call. | |
273 if (!is_visible) | |
274 OnWindowHidden(window, WINDOW_HIDDEN); | |
275 } | |
276 | |
277 void WindowEventDispatcher::OnWindowTransformed(Window* window, | |
278 bool contained_mouse) { | |
279 if (contained_mouse || | |
280 (window->IsVisible() && | |
281 window->ContainsPointInRoot(GetLastMouseLocationInRoot()))) { | |
282 PostMouseMoveEventAfterWindowChange(); | |
283 } | |
284 } | |
285 | |
286 void WindowEventDispatcher::OnKeyboardMappingChanged() { | |
287 FOR_EACH_OBSERVER(RootWindowObserver, observers_, | |
288 OnKeyboardMappingChanged(this)); | |
289 } | |
290 | |
291 void WindowEventDispatcher::OnWindowTreeHostCloseRequested() { | |
292 FOR_EACH_OBSERVER(RootWindowObserver, observers_, | |
293 OnWindowTreeHostCloseRequested(this)); | |
294 } | |
295 | |
296 void WindowEventDispatcher::AddRootWindowObserver( | |
297 RootWindowObserver* observer) { | |
298 observers_.AddObserver(observer); | |
299 } | |
300 | |
301 void WindowEventDispatcher::RemoveRootWindowObserver( | |
302 RootWindowObserver* observer) { | |
303 observers_.RemoveObserver(observer); | |
304 } | |
305 | |
306 void WindowEventDispatcher::ProcessedTouchEvent(ui::TouchEvent* event, | |
307 Window* window, | |
308 ui::EventResult result) { | |
309 scoped_ptr<ui::GestureRecognizer::Gestures> gestures; | |
310 gestures.reset(ui::GestureRecognizer::Get()-> | |
311 ProcessTouchEventForGesture(*event, result, window)); | |
312 DispatchDetails details = ProcessGestures(gestures.get()); | |
313 if (details.dispatcher_destroyed) | |
314 return; | |
315 } | |
316 | |
317 void WindowEventDispatcher::HoldPointerMoves() { | |
318 if (!move_hold_count_) | |
319 held_event_factory_.InvalidateWeakPtrs(); | |
320 ++move_hold_count_; | |
321 TRACE_EVENT_ASYNC_BEGIN0("ui", "WindowEventDispatcher::HoldPointerMoves", | |
322 this); | |
323 } | |
324 | |
325 void WindowEventDispatcher::ReleasePointerMoves() { | |
326 --move_hold_count_; | |
327 DCHECK_GE(move_hold_count_, 0); | |
328 if (!move_hold_count_ && held_move_event_) { | |
329 // We don't want to call DispatchHeldEvents directly, because this might be | |
330 // called from a deep stack while another event, in which case dispatching | |
331 // another one may not be safe/expected. Instead we post a task, that we | |
332 // may cancel if HoldPointerMoves is called again before it executes. | |
333 base::MessageLoop::current()->PostNonNestableTask( | |
334 FROM_HERE, base::Bind( | |
335 base::IgnoreResult(&WindowEventDispatcher::DispatchHeldEvents), | |
336 held_event_factory_.GetWeakPtr())); | |
337 } | |
338 TRACE_EVENT_ASYNC_END0("ui", "WindowEventDispatcher::HoldPointerMoves", this); | |
339 } | |
340 | |
341 gfx::Point WindowEventDispatcher::GetLastMouseLocationInRoot() const { | |
342 gfx::Point location = Env::GetInstance()->last_mouse_location(); | |
343 client::ScreenPositionClient* client = | |
344 client::GetScreenPositionClient(window()); | |
345 if (client) | |
346 client->ConvertPointFromScreen(window(), &location); | |
347 return location; | |
348 } | |
349 | |
350 //////////////////////////////////////////////////////////////////////////////// | |
351 // WindowEventDispatcher, private: | |
352 | |
353 void WindowEventDispatcher::TransformEventForDeviceScaleFactor( | |
354 ui::LocatedEvent* event) { | |
355 event->UpdateForRootTransform(host()->GetInverseRootTransform()); | |
356 } | |
357 | |
358 ui::EventDispatchDetails WindowEventDispatcher::DispatchMouseEnterOrExit( | |
359 const ui::MouseEvent& event, | |
360 ui::EventType type) { | |
361 if (event.type() != ui::ET_MOUSE_CAPTURE_CHANGED && | |
362 !(event.flags() & ui::EF_IS_SYNTHESIZED)) { | |
363 SetLastMouseLocation(window(), event.root_location()); | |
364 } | |
365 | |
366 if (!mouse_moved_handler_ || !mouse_moved_handler_->delegate()) | |
367 return DispatchDetails(); | |
368 | |
369 // |event| may be an event in the process of being dispatched to a target (in | |
370 // which case its locations will be in the event's target's coordinate | |
371 // system), or a synthetic event created in root-window (in which case, the | |
372 // event's target will be NULL, and the event will be in the root-window's | |
373 // coordinate system. | |
374 aura::Window* target = static_cast<Window*>(event.target()); | |
375 if (!target) | |
376 target = window(); | |
377 ui::MouseEvent translated_event(event, | |
378 target, | |
379 mouse_moved_handler_, | |
380 type, | |
381 event.flags() | ui::EF_IS_SYNTHESIZED); | |
382 return DispatchEvent(mouse_moved_handler_, &translated_event); | |
383 } | |
384 | |
385 ui::EventDispatchDetails WindowEventDispatcher::ProcessGestures( | |
386 ui::GestureRecognizer::Gestures* gestures) { | |
387 DispatchDetails details; | |
388 if (!gestures || gestures->empty()) | |
389 return details; | |
390 | |
391 Window* target = GetGestureTarget(gestures->get().at(0)); | |
392 for (size_t i = 0; i < gestures->size(); ++i) { | |
393 ui::GestureEvent* event = gestures->get().at(i); | |
394 event->ConvertLocationToTarget(window(), target); | |
395 details = DispatchEvent(target, event); | |
396 if (details.dispatcher_destroyed || details.target_destroyed) | |
397 break; | |
398 } | |
399 return details; | |
400 } | |
401 | |
402 void WindowEventDispatcher::OnWindowAddedToRootWindow(Window* attached) { | |
403 if (attached->IsVisible() && | |
404 attached->ContainsPointInRoot(GetLastMouseLocationInRoot())) { | |
405 PostMouseMoveEventAfterWindowChange(); | |
406 } | |
407 } | |
408 | |
409 void WindowEventDispatcher::OnWindowRemovedFromRootWindow(Window* detached, | |
410 Window* new_root) { | |
411 DCHECK(aura::client::GetCaptureWindow(window()) != window()); | |
412 | |
413 DispatchMouseExitToHidingWindow(detached); | |
414 if (detached->IsVisible() && | |
415 detached->ContainsPointInRoot(GetLastMouseLocationInRoot())) { | |
416 PostMouseMoveEventAfterWindowChange(); | |
417 } | |
418 | |
419 // Hiding the window releases capture which can implicitly destroy the window | |
420 // so the window may no longer be valid after this call. | |
421 OnWindowHidden(detached, new_root ? WINDOW_MOVING : WINDOW_HIDDEN); | |
422 } | |
423 | |
424 void WindowEventDispatcher::OnWindowHidden(Window* invisible, | |
425 WindowHiddenReason reason) { | |
426 // If the window the mouse was pressed in becomes invisible, it should no | |
427 // longer receive mouse events. | |
428 if (invisible->Contains(mouse_pressed_handler_)) | |
429 mouse_pressed_handler_ = NULL; | |
430 if (invisible->Contains(mouse_moved_handler_)) | |
431 mouse_moved_handler_ = NULL; | |
432 | |
433 CleanupGestureState(invisible); | |
434 | |
435 // Do not clear the capture, and the |event_dispatch_target_| if the | |
436 // window is moving across root windows, because the target itself | |
437 // is actually still visible and clearing them stops further event | |
438 // processing, which can cause unexpected behaviors. See | |
439 // crbug.com/157583 | |
440 if (reason != WINDOW_MOVING) { | |
441 Window* capture_window = aura::client::GetCaptureWindow(window()); | |
442 | |
443 if (invisible->Contains(event_dispatch_target_)) | |
444 event_dispatch_target_ = NULL; | |
445 | |
446 if (invisible->Contains(old_dispatch_target_)) | |
447 old_dispatch_target_ = NULL; | |
448 | |
449 // If the ancestor of the capture window is hidden, release the capture. | |
450 // Note that this may delete the window so do not use capture_window | |
451 // after this. | |
452 if (invisible->Contains(capture_window) && invisible != window()) | |
453 capture_window->ReleaseCapture(); | |
454 } | |
455 } | |
456 | |
457 void WindowEventDispatcher::CleanupGestureState(Window* window) { | |
458 ui::GestureRecognizer::Get()->CancelActiveTouches(window); | |
459 ui::GestureRecognizer::Get()->CleanupStateForConsumer(window); | |
460 const Window::Windows& windows = window->children(); | |
461 for (Window::Windows::const_iterator iter = windows.begin(); | |
462 iter != windows.end(); | |
463 ++iter) { | |
464 CleanupGestureState(*iter); | |
465 } | |
466 } | |
467 | |
468 //////////////////////////////////////////////////////////////////////////////// | |
469 // WindowEventDispatcher, aura::client::CaptureDelegate implementation: | |
470 | |
471 void WindowEventDispatcher::UpdateCapture(Window* old_capture, | |
472 Window* new_capture) { | |
473 // |mouse_moved_handler_| may have been set to a Window in a different root | |
474 // (see below). Clear it here to ensure we don't end up referencing a stale | |
475 // Window. | |
476 if (mouse_moved_handler_ && !window()->Contains(mouse_moved_handler_)) | |
477 mouse_moved_handler_ = NULL; | |
478 | |
479 if (old_capture && old_capture->GetRootWindow() == window() && | |
480 old_capture->delegate()) { | |
481 // Send a capture changed event with bogus location data. | |
482 ui::MouseEvent event(ui::ET_MOUSE_CAPTURE_CHANGED, gfx::Point(), | |
483 gfx::Point(), 0, 0); | |
484 | |
485 DispatchDetails details = DispatchEvent(old_capture, &event); | |
486 if (details.dispatcher_destroyed) | |
487 return; | |
488 | |
489 old_capture->delegate()->OnCaptureLost(); | |
490 } | |
491 | |
492 if (new_capture) { | |
493 // Make all subsequent mouse events go to the capture window. We shouldn't | |
494 // need to send an event here as OnCaptureLost() should take care of that. | |
495 if (mouse_moved_handler_ || Env::GetInstance()->IsMouseButtonDown()) | |
496 mouse_moved_handler_ = new_capture; | |
497 } else { | |
498 // Make sure mouse_moved_handler gets updated. | |
499 DispatchDetails details = SynthesizeMouseMoveEvent(); | |
500 if (details.dispatcher_destroyed) | |
501 return; | |
502 } | |
503 mouse_pressed_handler_ = NULL; | |
504 } | |
505 | |
506 void WindowEventDispatcher::OnOtherRootGotCapture() { | |
507 mouse_moved_handler_ = NULL; | |
508 mouse_pressed_handler_ = NULL; | |
509 } | |
510 | |
511 void WindowEventDispatcher::SetNativeCapture() { | |
512 host_->SetCapture(); | |
513 } | |
514 | |
515 void WindowEventDispatcher::ReleaseNativeCapture() { | |
516 host_->ReleaseCapture(); | |
517 } | |
518 | |
519 //////////////////////////////////////////////////////////////////////////////// | |
520 // WindowEventDispatcher, ui::EventProcessor implementation: | |
521 ui::EventTarget* WindowEventDispatcher::GetRootTarget() { | |
522 return window(); | |
523 } | |
524 | |
525 void WindowEventDispatcher::PrepareEventForDispatch(ui::Event* event) { | |
526 if (dispatching_held_event_) { | |
527 // The held events are already in |window()|'s coordinate system. So it is | |
528 // not necessary to apply the transform to convert from the host's | |
529 // coordinate system to |window()|'s coordinate system. | |
530 return; | |
531 } | |
532 if (event->IsMouseEvent() || | |
533 event->IsScrollEvent() || | |
534 event->IsTouchEvent() || | |
535 event->IsGestureEvent()) { | |
536 TransformEventForDeviceScaleFactor(static_cast<ui::LocatedEvent*>(event)); | |
537 } | |
538 } | |
539 | |
540 //////////////////////////////////////////////////////////////////////////////// | |
541 // WindowEventDispatcher, ui::EventDispatcherDelegate implementation: | |
542 | |
543 bool WindowEventDispatcher::CanDispatchToTarget(ui::EventTarget* target) { | |
544 return event_dispatch_target_ == target; | |
545 } | |
546 | |
547 ui::EventDispatchDetails WindowEventDispatcher::PreDispatchEvent( | |
548 ui::EventTarget* target, | |
549 ui::Event* event) { | |
550 if (!dispatching_held_event_) { | |
551 bool can_be_held = IsEventCandidateForHold(*event); | |
552 if (!move_hold_count_ || !can_be_held) { | |
553 if (can_be_held) | |
554 held_move_event_.reset(); | |
555 DispatchDetails details = DispatchHeldEvents(); | |
556 if (details.dispatcher_destroyed || details.target_destroyed) | |
557 return details; | |
558 } | |
559 } | |
560 | |
561 Window* target_window = static_cast<Window*>(target); | |
562 if (event->IsMouseEvent()) { | |
563 PreDispatchMouseEvent(target_window, static_cast<ui::MouseEvent*>(event)); | |
564 } else if (event->IsScrollEvent()) { | |
565 PreDispatchLocatedEvent(target_window, | |
566 static_cast<ui::ScrollEvent*>(event)); | |
567 } else if (event->IsTouchEvent()) { | |
568 PreDispatchTouchEvent(target_window, static_cast<ui::TouchEvent*>(event)); | |
569 } | |
570 old_dispatch_target_ = event_dispatch_target_; | |
571 event_dispatch_target_ = static_cast<Window*>(target); | |
572 return DispatchDetails(); | |
573 } | |
574 | |
575 ui::EventDispatchDetails WindowEventDispatcher::PostDispatchEvent( | |
576 ui::EventTarget* target, | |
577 const ui::Event& event) { | |
578 DispatchDetails details; | |
579 if (target != event_dispatch_target_) | |
580 details.target_destroyed = true; | |
581 event_dispatch_target_ = old_dispatch_target_; | |
582 old_dispatch_target_ = NULL; | |
583 #ifndef NDEBUG | |
584 DCHECK(!event_dispatch_target_ || window()->Contains(event_dispatch_target_)); | |
585 #endif | |
586 | |
587 if (event.IsTouchEvent() && !details.target_destroyed) { | |
588 // Do not let 'held' touch events contribute to any gestures. | |
589 if (!held_move_event_ || !held_move_event_->IsTouchEvent()) { | |
590 ui::TouchEvent orig_event(static_cast<const ui::TouchEvent&>(event), | |
591 static_cast<Window*>(event.target()), window()); | |
592 // Get the list of GestureEvents from GestureRecognizer. | |
593 scoped_ptr<ui::GestureRecognizer::Gestures> gestures; | |
594 gestures.reset(ui::GestureRecognizer::Get()-> | |
595 ProcessTouchEventForGesture(orig_event, event.result(), | |
596 static_cast<Window*>(target))); | |
597 return ProcessGestures(gestures.get()); | |
598 } | |
599 } | |
600 | |
601 return details; | |
602 } | |
603 | |
604 //////////////////////////////////////////////////////////////////////////////// | |
605 // WindowEventDispatcher, ui::GestureEventHelper implementation: | |
606 | |
607 bool WindowEventDispatcher::CanDispatchToConsumer( | |
608 ui::GestureConsumer* consumer) { | |
609 Window* consumer_window = ConsumerToWindow(consumer);; | |
610 return (consumer_window && consumer_window->GetRootWindow() == window()); | |
611 } | |
612 | |
613 void WindowEventDispatcher::DispatchPostponedGestureEvent( | |
614 ui::GestureEvent* event) { | |
615 DispatchGestureEvent(event); | |
616 } | |
617 | |
618 void WindowEventDispatcher::DispatchCancelTouchEvent(ui::TouchEvent* event) { | |
619 DispatchDetails details = OnEventFromSource(event); | |
620 if (details.dispatcher_destroyed) | |
621 return; | |
622 } | |
623 | |
624 //////////////////////////////////////////////////////////////////////////////// | |
625 // WindowEventDispatcher, ui::LayerAnimationObserver implementation: | |
626 | |
627 void WindowEventDispatcher::OnLayerAnimationEnded( | |
628 ui::LayerAnimationSequence* animation) { | |
629 host()->UpdateRootWindowSize(host_->GetBounds().size()); | |
630 } | |
631 | |
632 void WindowEventDispatcher::OnLayerAnimationScheduled( | |
633 ui::LayerAnimationSequence* animation) { | |
634 } | |
635 | |
636 void WindowEventDispatcher::OnLayerAnimationAborted( | |
637 ui::LayerAnimationSequence* animation) { | |
638 } | |
639 | |
640 //////////////////////////////////////////////////////////////////////////////// | |
641 // WindowEventDispatcher, WindowTreeHostDelegate implementation: | |
642 | |
643 void WindowEventDispatcher::OnHostCancelMode() { | |
644 ui::CancelModeEvent event; | |
645 Window* focused_window = client::GetFocusClient(window())->GetFocusedWindow(); | |
646 DispatchDetails details = | |
647 DispatchEvent(focused_window ? focused_window : window(), &event); | |
648 if (details.dispatcher_destroyed) | |
649 return; | |
650 } | |
651 | |
652 void WindowEventDispatcher::OnHostActivated() { | |
653 Env::GetInstance()->RootWindowActivated(this); | |
654 } | |
655 | |
656 void WindowEventDispatcher::OnHostLostWindowCapture() { | |
657 Window* capture_window = client::GetCaptureWindow(window()); | |
658 if (capture_window && capture_window->GetRootWindow() == window()) | |
659 capture_window->ReleaseCapture(); | |
660 } | |
661 | |
662 void WindowEventDispatcher::OnHostLostMouseGrab() { | |
663 mouse_pressed_handler_ = NULL; | |
664 mouse_moved_handler_ = NULL; | |
665 } | |
666 | |
667 void WindowEventDispatcher::OnHostMoved(const gfx::Point& origin) { | |
668 TRACE_EVENT1("ui", "WindowEventDispatcher::OnHostMoved", | |
669 "origin", origin.ToString()); | |
670 | |
671 FOR_EACH_OBSERVER(RootWindowObserver, observers_, | |
672 OnWindowTreeHostMoved(this, origin)); | |
673 } | |
674 | |
675 void WindowEventDispatcher::OnHostResized(const gfx::Size& size) { | |
676 TRACE_EVENT1("ui", "WindowEventDispatcher::OnHostResized", | |
677 "size", size.ToString()); | |
678 | |
679 DispatchDetails details = DispatchHeldEvents(); | |
680 if (details.dispatcher_destroyed) | |
681 return; | |
682 FOR_EACH_OBSERVER(RootWindowObserver, observers_, | |
683 OnWindowTreeHostResized(this)); | |
684 | |
685 // Constrain the mouse position within the new root Window size. | |
686 gfx::Point point; | |
687 if (host_->QueryMouseLocation(&point)) { | |
688 SetLastMouseLocation(window(), | |
689 ui::ConvertPointToDIP(window()->layer(), point)); | |
690 } | |
691 synthesize_mouse_move_ = false; | |
692 } | |
693 | |
694 void WindowEventDispatcher::OnCursorMovedToRootLocation( | |
695 const gfx::Point& root_location) { | |
696 SetLastMouseLocation(window(), root_location); | |
697 synthesize_mouse_move_ = false; | |
698 } | |
699 | |
700 WindowEventDispatcher* WindowEventDispatcher::AsDispatcher() { | |
701 return this; | |
702 } | |
703 | |
704 const WindowEventDispatcher* WindowEventDispatcher::AsDispatcher() const { | |
705 return this; | |
706 } | |
707 | |
708 ui::EventProcessor* WindowEventDispatcher::GetEventProcessor() { | |
709 return this; | |
710 } | |
711 | |
712 //////////////////////////////////////////////////////////////////////////////// | |
713 // WindowEventDispatcher, private: | |
714 | |
715 ui::EventDispatchDetails WindowEventDispatcher::DispatchHeldEvents() { | |
716 if (!held_repostable_event_ && !held_move_event_) | |
717 return DispatchDetails(); | |
718 | |
719 CHECK(!dispatching_held_event_); | |
720 dispatching_held_event_ = true; | |
721 | |
722 DispatchDetails dispatch_details; | |
723 if (held_repostable_event_) { | |
724 if (held_repostable_event_->type() == ui::ET_MOUSE_PRESSED) { | |
725 scoped_ptr<ui::MouseEvent> mouse_event( | |
726 static_cast<ui::MouseEvent*>(held_repostable_event_.release())); | |
727 dispatch_details = OnEventFromSource(mouse_event.get()); | |
728 } else { | |
729 // TODO(rbyers): GESTURE_TAP_DOWN not yet supported: crbug.com/170987. | |
730 NOTREACHED(); | |
731 } | |
732 if (dispatch_details.dispatcher_destroyed) | |
733 return dispatch_details; | |
734 } | |
735 | |
736 if (held_move_event_) { | |
737 // If a mouse move has been synthesized, the target location is suspect, | |
738 // so drop the held mouse event. | |
739 if (held_move_event_->IsTouchEvent() || | |
740 (held_move_event_->IsMouseEvent() && !synthesize_mouse_move_)) { | |
741 dispatch_details = OnEventFromSource(held_move_event_.get()); | |
742 } | |
743 if (!dispatch_details.dispatcher_destroyed) | |
744 held_move_event_.reset(); | |
745 } | |
746 | |
747 if (!dispatch_details.dispatcher_destroyed) | |
748 dispatching_held_event_ = false; | |
749 return dispatch_details; | |
750 } | |
751 | |
752 void WindowEventDispatcher::PostMouseMoveEventAfterWindowChange() { | |
753 if (synthesize_mouse_move_) | |
754 return; | |
755 synthesize_mouse_move_ = true; | |
756 base::MessageLoop::current()->PostNonNestableTask( | |
757 FROM_HERE, | |
758 base::Bind(base::IgnoreResult( | |
759 &WindowEventDispatcher::SynthesizeMouseMoveEvent), | |
760 held_event_factory_.GetWeakPtr())); | |
761 } | |
762 | |
763 ui::EventDispatchDetails WindowEventDispatcher::SynthesizeMouseMoveEvent() { | |
764 DispatchDetails details; | |
765 if (!synthesize_mouse_move_) | |
766 return details; | |
767 synthesize_mouse_move_ = false; | |
768 gfx::Point root_mouse_location = GetLastMouseLocationInRoot(); | |
769 if (!window()->bounds().Contains(root_mouse_location)) | |
770 return details; | |
771 gfx::Point host_mouse_location = root_mouse_location; | |
772 host()->ConvertPointToHost(&host_mouse_location); | |
773 ui::MouseEvent event(ui::ET_MOUSE_MOVED, | |
774 host_mouse_location, | |
775 host_mouse_location, | |
776 ui::EF_IS_SYNTHESIZED, | |
777 0); | |
778 return OnEventFromSource(&event); | |
779 } | |
780 | |
781 void WindowEventDispatcher::PreDispatchLocatedEvent(Window* target, | |
782 ui::LocatedEvent* event) { | |
783 int flags = event->flags(); | |
784 if (IsNonClientLocation(target, event->location())) | |
785 flags |= ui::EF_IS_NON_CLIENT; | |
786 event->set_flags(flags); | |
787 | |
788 if (!dispatching_held_event_ && | |
789 (event->IsMouseEvent() || event->IsScrollEvent()) && | |
790 !(event->flags() & ui::EF_IS_SYNTHESIZED)) { | |
791 if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) | |
792 SetLastMouseLocation(window(), event->root_location()); | |
793 synthesize_mouse_move_ = false; | |
794 } | |
795 } | |
796 | |
797 void WindowEventDispatcher::PreDispatchMouseEvent(Window* target, | |
798 ui::MouseEvent* event) { | |
799 client::CursorClient* cursor_client = client::GetCursorClient(window()); | |
800 if (cursor_client && | |
801 !cursor_client->IsMouseEventsEnabled() && | |
802 (event->flags() & ui::EF_IS_SYNTHESIZED)) { | |
803 event->SetHandled(); | |
804 return; | |
805 } | |
806 | |
807 if (IsEventCandidateForHold(*event) && !dispatching_held_event_) { | |
808 if (move_hold_count_) { | |
809 if (!(event->flags() & ui::EF_IS_SYNTHESIZED) && | |
810 event->type() != ui::ET_MOUSE_CAPTURE_CHANGED) { | |
811 SetLastMouseLocation(window(), event->root_location()); | |
812 } | |
813 held_move_event_.reset(new ui::MouseEvent(*event, target, window())); | |
814 event->SetHandled(); | |
815 return; | |
816 } else { | |
817 // We may have a held event for a period between the time move_hold_count_ | |
818 // fell to 0 and the DispatchHeldEvents executes. Since we're going to | |
819 // dispatch the new event directly below, we can reset the old one. | |
820 held_move_event_.reset(); | |
821 } | |
822 } | |
823 | |
824 const int kMouseButtonFlagMask = ui::EF_LEFT_MOUSE_BUTTON | | |
825 ui::EF_MIDDLE_MOUSE_BUTTON | | |
826 ui::EF_RIGHT_MOUSE_BUTTON; | |
827 switch (event->type()) { | |
828 case ui::ET_MOUSE_EXITED: | |
829 if (!target || target == window()) { | |
830 DispatchDetails details = | |
831 DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED); | |
832 if (details.dispatcher_destroyed) { | |
833 event->SetHandled(); | |
834 return; | |
835 } | |
836 mouse_moved_handler_ = NULL; | |
837 } | |
838 break; | |
839 case ui::ET_MOUSE_MOVED: | |
840 // Send an exit to the current |mouse_moved_handler_| and an enter to | |
841 // |target|. Take care that both us and |target| aren't destroyed during | |
842 // dispatch. | |
843 if (target != mouse_moved_handler_) { | |
844 aura::Window* old_mouse_moved_handler = mouse_moved_handler_; | |
845 WindowTracker live_window; | |
846 live_window.Add(target); | |
847 DispatchDetails details = | |
848 DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_EXITED); | |
849 if (details.dispatcher_destroyed) { | |
850 event->SetHandled(); | |
851 return; | |
852 } | |
853 // If the |mouse_moved_handler_| changes out from under us, assume a | |
854 // nested message loop ran and we don't need to do anything. | |
855 if (mouse_moved_handler_ != old_mouse_moved_handler) { | |
856 event->SetHandled(); | |
857 return; | |
858 } | |
859 if (!live_window.Contains(target) || details.target_destroyed) { | |
860 mouse_moved_handler_ = NULL; | |
861 event->SetHandled(); | |
862 return; | |
863 } | |
864 live_window.Remove(target); | |
865 | |
866 mouse_moved_handler_ = target; | |
867 details = DispatchMouseEnterOrExit(*event, ui::ET_MOUSE_ENTERED); | |
868 if (details.dispatcher_destroyed || details.target_destroyed) { | |
869 event->SetHandled(); | |
870 return; | |
871 } | |
872 } | |
873 break; | |
874 case ui::ET_MOUSE_PRESSED: | |
875 // Don't set the mouse pressed handler for non client mouse down events. | |
876 // These are only sent by Windows and are not always followed with non | |
877 // client mouse up events which causes subsequent mouse events to be | |
878 // sent to the wrong target. | |
879 if (!(event->flags() & ui::EF_IS_NON_CLIENT) && !mouse_pressed_handler_) | |
880 mouse_pressed_handler_ = target; | |
881 Env::GetInstance()->set_mouse_button_flags( | |
882 event->flags() & kMouseButtonFlagMask); | |
883 break; | |
884 case ui::ET_MOUSE_RELEASED: | |
885 mouse_pressed_handler_ = NULL; | |
886 Env::GetInstance()->set_mouse_button_flags(event->flags() & | |
887 kMouseButtonFlagMask & ~event->changed_button_flags()); | |
888 break; | |
889 default: | |
890 break; | |
891 } | |
892 | |
893 PreDispatchLocatedEvent(target, event); | |
894 } | |
895 | |
896 void WindowEventDispatcher::PreDispatchTouchEvent(Window* target, | |
897 ui::TouchEvent* event) { | |
898 switch (event->type()) { | |
899 case ui::ET_TOUCH_PRESSED: | |
900 touch_ids_down_ |= (1 << event->touch_id()); | |
901 Env::GetInstance()->set_touch_down(touch_ids_down_ != 0); | |
902 break; | |
903 | |
904 // Handle ET_TOUCH_CANCELLED only if it has a native event. | |
905 case ui::ET_TOUCH_CANCELLED: | |
906 if (!event->HasNativeEvent()) | |
907 break; | |
908 // fallthrough | |
909 case ui::ET_TOUCH_RELEASED: | |
910 touch_ids_down_ = (touch_ids_down_ | (1 << event->touch_id())) ^ | |
911 (1 << event->touch_id()); | |
912 Env::GetInstance()->set_touch_down(touch_ids_down_ != 0); | |
913 break; | |
914 | |
915 case ui::ET_TOUCH_MOVED: | |
916 if (move_hold_count_ && !dispatching_held_event_) { | |
917 held_move_event_.reset(new ui::TouchEvent(*event, target, window())); | |
918 event->SetHandled(); | |
919 return; | |
920 } | |
921 break; | |
922 | |
923 default: | |
924 NOTREACHED(); | |
925 break; | |
926 } | |
927 PreDispatchLocatedEvent(target, event); | |
928 } | |
929 | |
930 } // namespace aura | |
OLD | NEW |