1 // Copyright (c) 2013 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 "ui/aura/window_targeter.h"
7 #include "ui/aura/client/capture_client.h"
8 #include "ui/aura/client/event_client.h"
9 #include "ui/aura/client/focus_client.h"
10 #include "ui/aura/window.h"
11 #include "ui/aura/window_delegate.h"
12 #include "ui/aura/window_event_dispatcher.h"
13 #include "ui/aura/window_tree_host.h"
14 #include "ui/events/event_target.h"
15 #include "ui/events/event_target_iterator.h"
19 WindowTargeter::WindowTargeter() {}
20 WindowTargeter::~WindowTargeter() {}
22 Window
* WindowTargeter::FindTargetForLocatedEvent(Window
* window
,
23 ui::LocatedEvent
* event
) {
24 if (!window
->parent()) {
25 Window
* target
= FindTargetInRootWindow(window
, *event
);
27 window
->ConvertEventToTarget(target
, event
);
31 return FindTargetForLocatedEventRecursively(window
, event
);
34 bool WindowTargeter::SubtreeCanAcceptEvent(
36 const ui::LocatedEvent
& event
) const {
37 if (!window
->IsVisible())
39 if (window
->ignore_events())
41 client::EventClient
* client
= client::GetEventClient(window
->GetRootWindow());
42 if (client
&& !client
->CanProcessEventsWithinSubtree(window
))
45 Window
* parent
= window
->parent();
46 if (parent
&& parent
->delegate_
&& !parent
->delegate_
->
47 ShouldDescendIntoChildForEventHandling(window
, event
.location())) {
53 bool WindowTargeter::EventLocationInsideBounds(
55 const ui::LocatedEvent
& event
) const {
56 gfx::Point point
= event
.location();
58 Window::ConvertPointToTarget(window
->parent(), window
, &point
);
59 return gfx::Rect(window
->bounds().size()).Contains(point
);
62 ui::EventTarget
* WindowTargeter::FindTargetForEvent(ui::EventTarget
* root
,
64 Window
* window
= static_cast<Window
*>(root
);
67 ? FindTargetForKeyEvent(window
, *static_cast<ui::KeyEvent
*>(event
))
68 : FindTargetForNonKeyEvent(window
, event
);
69 if (target
&& !window
->parent() && !window
->Contains(target
)) {
70 // |window| is the root window, but |target| is not a descendent of
71 // |window|. So do not allow dispatching from here. Instead, dispatch the
72 // event through the WindowEventDispatcher that owns |target|.
73 Window
* new_root
= target
->GetRootWindow();
74 if (event
->IsLocatedEvent()) {
75 // The event has been transformed to be in |target|'s coordinate system.
76 // But dispatching the event through the EventProcessor requires the event
77 // to be in the host's coordinate system. So, convert the event to be in
78 // the root's coordinate space, and then to the host's coordinate space by
79 // applying the host's transform.
80 ui::LocatedEvent
* located_event
= static_cast<ui::LocatedEvent
*>(event
);
81 located_event
->ConvertLocationToTarget(target
, new_root
);
82 located_event
->UpdateForRootTransform(
83 new_root
->GetHost()->GetRootTransform());
86 new_root
->GetHost()->event_processor()->OnEventFromSource(event
));
93 ui::EventTarget
* WindowTargeter::FindNextBestTarget(
94 ui::EventTarget
* previous_target
,
99 bool WindowTargeter::SubtreeShouldBeExploredForEvent(
101 const ui::LocatedEvent
& event
) {
102 return SubtreeCanAcceptEvent(window
, event
) &&
103 EventLocationInsideBounds(window
, event
);
106 Window
* WindowTargeter::FindTargetForKeyEvent(Window
* window
,
107 const ui::KeyEvent
& key
) {
108 Window
* root_window
= window
->GetRootWindow();
109 client::FocusClient
* focus_client
= client::GetFocusClient(root_window
);
110 Window
* focused_window
= focus_client
->GetFocusedWindow();
114 client::EventClient
* event_client
= client::GetEventClient(root_window
);
116 !event_client
->CanProcessEventsWithinSubtree(focused_window
)) {
117 focus_client
->FocusWindow(nullptr);
120 return focused_window
? focused_window
: window
;
123 Window
* WindowTargeter::FindTargetForNonKeyEvent(Window
* root_window
,
125 if (!event
->IsLocatedEvent())
127 return FindTargetForLocatedEvent(root_window
,
128 static_cast<ui::LocatedEvent
*>(event
));
131 Window
* WindowTargeter::FindTargetInRootWindow(Window
* root_window
,
132 const ui::LocatedEvent
& event
) {
133 DCHECK_EQ(root_window
, root_window
->GetRootWindow());
135 // Mouse events should be dispatched to the window that processed the
136 // mouse-press events (if any).
137 if (event
.IsScrollEvent() || event
.IsMouseEvent()) {
138 WindowEventDispatcher
* dispatcher
= root_window
->GetHost()->dispatcher();
139 if (dispatcher
->mouse_pressed_handler())
140 return dispatcher
->mouse_pressed_handler();
143 // All events should be directed towards the capture window (if any).
144 Window
* capture_window
= client::GetCaptureWindow(root_window
);
146 return capture_window
;
148 if (event
.IsTouchEvent()) {
149 // Query the gesture-recognizer to find targets for touch events.
150 const ui::TouchEvent
& touch
= static_cast<const ui::TouchEvent
&>(event
);
151 ui::GestureConsumer
* consumer
=
152 ui::GestureRecognizer::Get()->GetTouchLockedTarget(touch
);
154 return static_cast<Window
*>(consumer
);
156 ui::GestureRecognizer::Get()->GetTargetForLocation(
157 event
.location(), touch
.source_device_id());
159 return static_cast<Window
*>(consumer
);
161 // If the initial touch is outside the root window, target the root.
162 if (!root_window
->bounds().Contains(event
.location()))
169 Window
* WindowTargeter::FindTargetForLocatedEventRecursively(
171 ui::LocatedEvent
* event
) {
172 scoped_ptr
<ui::EventTargetIterator
> iter
= root_window
->GetChildIterator();
174 ui::EventTarget
* target
= root_window
;
175 for (ui::EventTarget
* child
= iter
->GetNextTarget(); child
;
176 child
= iter
->GetNextTarget()) {
177 WindowTargeter
* targeter
=
178 static_cast<WindowTargeter
*>(child
->GetEventTargeter());
181 if (!targeter
->SubtreeShouldBeExploredForEvent(
182 static_cast<Window
*>(child
), *event
)) {
185 target
->ConvertEventToTarget(child
, event
);
187 Window
* child_target_window
=
188 static_cast<Window
*>(targeter
->FindTargetForEvent(child
, event
));
189 if (child_target_window
)
190 return child_target_window
;
192 target
->ConvertEventToTarget(root_window
, event
);
194 return root_window
->CanAcceptEvent(*event
) ? root_window
: nullptr;