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.
4
5#include "ui/aura/window_targeter.h"
6
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
16namespace aura {
17
18namespace {
19
20bool IsLocatedEvent(const ui::Event& event) {
21  return event.IsMouseEvent() || event.IsTouchEvent() ||
22         event.IsScrollEvent() || event.IsGestureEvent();
23}
24
25}  // namespace
26
27WindowTargeter::WindowTargeter() {}
28WindowTargeter::~WindowTargeter() {}
29
30ui::EventTarget* WindowTargeter::FindTargetForEvent(ui::EventTarget* root,
31                                                    ui::Event* event) {
32  Window* window = static_cast<Window*>(root);
33  Window* target = event->IsKeyEvent() ?
34      FindTargetForKeyEvent(window, *static_cast<ui::KeyEvent*>(event)) :
35      static_cast<Window*>(EventTargeter::FindTargetForEvent(root, event));
36  if (target && !window->parent() && !window->Contains(target)) {
37    // |window| is the root window, but |target| is not a descendent of
38    // |window|. So do not allow dispatching from here. Instead, dispatch the
39    // event through the WindowEventDispatcher that owns |target|.
40    aura::Window* new_root = target->GetRootWindow();
41    if (IsLocatedEvent(*event)) {
42      // The event has been transformed to be in |target|'s coordinate system.
43      // But dispatching the event through the EventProcessor requires the event
44      // to be in the host's coordinate system. So, convert the event to be in
45      // the root's coordinate space, and then to the host's coordinate space by
46      // applying the host's transform.
47      ui::LocatedEvent* located_event = static_cast<ui::LocatedEvent*>(event);
48      located_event->ConvertLocationToTarget(target, new_root);
49      located_event->UpdateForRootTransform(
50          new_root->GetHost()->GetRootTransform());
51    }
52    ui::EventDispatchDetails details ALLOW_UNUSED =
53        new_root->GetHost()->event_processor()->OnEventFromSource(event);
54    target = NULL;
55  }
56  return target;
57}
58
59bool WindowTargeter::SubtreeCanAcceptEvent(
60    ui::EventTarget* target,
61    const ui::LocatedEvent& event) const {
62  aura::Window* window = static_cast<aura::Window*>(target);
63  if (!window->IsVisible())
64    return false;
65  if (window->ignore_events())
66    return false;
67  client::EventClient* client = client::GetEventClient(window->GetRootWindow());
68  if (client && !client->CanProcessEventsWithinSubtree(window))
69    return false;
70
71  Window* parent = window->parent();
72  if (parent && parent->delegate_ && !parent->delegate_->
73      ShouldDescendIntoChildForEventHandling(window, event.location())) {
74    return false;
75  }
76  return true;
77}
78
79bool WindowTargeter::EventLocationInsideBounds(
80    ui::EventTarget* target,
81    const ui::LocatedEvent& event) const {
82  aura::Window* window = static_cast<aura::Window*>(target);
83  gfx::Point point = event.location();
84  if (window->parent())
85    aura::Window::ConvertPointToTarget(window->parent(), window, &point);
86  return gfx::Rect(window->bounds().size()).Contains(point);
87}
88
89ui::EventTarget* WindowTargeter::FindTargetForLocatedEvent(
90    ui::EventTarget* root,
91    ui::LocatedEvent* event) {
92  Window* window = static_cast<Window*>(root);
93  if (!window->parent()) {
94    Window* target = FindTargetInRootWindow(window, *event);
95    if (target) {
96      window->ConvertEventToTarget(target, event);
97      return target;
98    }
99  }
100  return EventTargeter::FindTargetForLocatedEvent(root, event);
101}
102
103Window* WindowTargeter::FindTargetForKeyEvent(Window* window,
104                                              const ui::KeyEvent& key) {
105  Window* root_window = window->GetRootWindow();
106  if (key.key_code() == ui::VKEY_UNKNOWN &&
107      (key.flags() & ui::EF_IME_FABRICATED_KEY) == 0 &&
108      key.GetCharacter() == 0)
109    return NULL;
110  client::FocusClient* focus_client = client::GetFocusClient(root_window);
111  Window* focused_window = focus_client->GetFocusedWindow();
112  if (!focused_window)
113    return window;
114
115  client::EventClient* event_client = client::GetEventClient(root_window);
116  if (event_client &&
117      !event_client->CanProcessEventsWithinSubtree(focused_window)) {
118    focus_client->FocusWindow(NULL);
119    return NULL;
120  }
121  return focused_window ? focused_window : window;
122}
123
124Window* WindowTargeter::FindTargetInRootWindow(Window* root_window,
125                                               const ui::LocatedEvent& event) {
126  DCHECK_EQ(root_window, root_window->GetRootWindow());
127
128  // Mouse events should be dispatched to the window that processed the
129  // mouse-press events (if any).
130  if (event.IsScrollEvent() || event.IsMouseEvent()) {
131    WindowEventDispatcher* dispatcher = root_window->GetHost()->dispatcher();
132    if (dispatcher->mouse_pressed_handler())
133      return dispatcher->mouse_pressed_handler();
134  }
135
136  // All events should be directed towards the capture window (if any).
137  Window* capture_window = client::GetCaptureWindow(root_window);
138  if (capture_window)
139    return capture_window;
140
141  if (event.IsTouchEvent()) {
142    // Query the gesture-recognizer to find targets for touch events.
143    const ui::TouchEvent& touch = static_cast<const ui::TouchEvent&>(event);
144    ui::GestureConsumer* consumer =
145        ui::GestureRecognizer::Get()->GetTouchLockedTarget(touch);
146    if (consumer)
147      return static_cast<Window*>(consumer);
148    consumer =
149        ui::GestureRecognizer::Get()->GetTargetForLocation(
150            event.location(), touch.source_device_id());
151    if (consumer)
152      return static_cast<Window*>(consumer);
153
154    // If the initial touch is outside the root window, target the root.
155    if (!root_window->bounds().Contains(event.location()))
156      return root_window;
157  }
158
159  return NULL;
160}
161
162}  // namespace aura
163