1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file.
4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/aura/window_targeter.h"
6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ui/aura/client/capture_client.h"
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/aura/client/event_client.h"
9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/aura/client/focus_client.h"
10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/aura/window.h"
11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/aura/window_delegate.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "ui/aura/window_event_dispatcher.h"
1323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "ui/aura/window_tree_host.h"
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "ui/events/event_target.h"
15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace aura {
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
18116680a4aac90f2aa7413d9095a592090648e557Ben Murdochnamespace {
19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
20116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool IsLocatedEvent(const ui::Event& event) {
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return event.IsMouseEvent() || event.IsTouchEvent() ||
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch         event.IsScrollEvent() || event.IsGestureEvent();
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}  // namespace
26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)WindowTargeter::WindowTargeter() {}
28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)WindowTargeter::~WindowTargeter() {}
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)ui::EventTarget* WindowTargeter::FindTargetForEvent(ui::EventTarget* root,
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                    ui::Event* event) {
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Window* window = static_cast<Window*>(root);
33a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Window* target = event->IsKeyEvent() ?
34a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      FindTargetForKeyEvent(window, *static_cast<ui::KeyEvent*>(event)) :
35a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      static_cast<Window*>(EventTargeter::FindTargetForEvent(root, event));
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (target && !window->parent() && !window->Contains(target)) {
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // |window| is the root window, but |target| is not a descendent of
38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // |window|. So do not allow dispatching from here. Instead, dispatch the
39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    // event through the WindowEventDispatcher that owns |target|.
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    aura::Window* new_root = target->GetRootWindow();
41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (IsLocatedEvent(*event)) {
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // The event has been transformed to be in |target|'s coordinate system.
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // But dispatching the event through the EventProcessor requires the event
44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // to be in the host's coordinate system. So, convert the event to be in
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // the root's coordinate space, and then to the host's coordinate space by
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // applying the host's transform.
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      ui::LocatedEvent* located_event = static_cast<ui::LocatedEvent*>(event);
48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      located_event->ConvertLocationToTarget(target, new_root);
49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      located_event->UpdateForRootTransform(
50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          new_root->GetHost()->GetRootTransform());
51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    ui::EventDispatchDetails details ALLOW_UNUSED =
53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        new_root->GetHost()->event_processor()->OnEventFromSource(event);
54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    target = NULL;
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
56a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return target;
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool WindowTargeter::SubtreeCanAcceptEvent(
60010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    ui::EventTarget* target,
61010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const ui::LocatedEvent& event) const {
62010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  aura::Window* window = static_cast<aura::Window*>(target);
63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (!window->IsVisible())
64010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return false;
65010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (window->ignore_events())
66010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return false;
67010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  client::EventClient* client = client::GetEventClient(window->GetRootWindow());
68010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (client && !client->CanProcessEventsWithinSubtree(window))
69010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return false;
70010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
71010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  Window* parent = window->parent();
72010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (parent && parent->delegate_ && !parent->delegate_->
73010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)      ShouldDescendIntoChildForEventHandling(window, event.location())) {
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return false;
75010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
76010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return true;
77010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
79010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool WindowTargeter::EventLocationInsideBounds(
80010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    ui::EventTarget* target,
81010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    const ui::LocatedEvent& event) const {
82010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  aura::Window* window = static_cast<aura::Window*>(target);
83010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  gfx::Point point = event.location();
84010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (window->parent())
85010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    aura::Window::ConvertPointToTarget(window->parent(), window, &point);
86010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return gfx::Rect(window->bounds().size()).Contains(point);
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ui::EventTarget* WindowTargeter::FindTargetForLocatedEvent(
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ui::EventTarget* root,
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ui::LocatedEvent* event) {
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Window* window = static_cast<Window*>(root);
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!window->parent()) {
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    Window* target = FindTargetInRootWindow(window, *event);
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (target) {
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      window->ConvertEventToTarget(target, event);
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return target;
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return EventTargeter::FindTargetForLocatedEvent(root, event);
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
103a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)Window* WindowTargeter::FindTargetForKeyEvent(Window* window,
104a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                              const ui::KeyEvent& key) {
105a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Window* root_window = window->GetRootWindow();
1065c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  if (key.key_code() == ui::VKEY_UNKNOWN &&
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      (key.flags() & ui::EF_IME_FABRICATED_KEY) == 0 &&
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      key.GetCharacter() == 0)
109a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return NULL;
110a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  client::FocusClient* focus_client = client::GetFocusClient(root_window);
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Window* focused_window = focus_client->GetFocusedWindow();
112a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (!focused_window)
113a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return window;
114a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
115a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  client::EventClient* event_client = client::GetEventClient(root_window);
116a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (event_client &&
117a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      !event_client->CanProcessEventsWithinSubtree(focused_window)) {
118a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    focus_client->FocusWindow(NULL);
119a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return NULL;
120a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
121a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return focused_window ? focused_window : window;
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)Window* WindowTargeter::FindTargetInRootWindow(Window* root_window,
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               const ui::LocatedEvent& event) {
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK_EQ(root_window, root_window->GetRootWindow());
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Mouse events should be dispatched to the window that processed the
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // mouse-press events (if any).
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (event.IsScrollEvent() || event.IsMouseEvent()) {
131a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    WindowEventDispatcher* dispatcher = root_window->GetHost()->dispatcher();
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (dispatcher->mouse_pressed_handler())
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return dispatcher->mouse_pressed_handler();
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // All events should be directed towards the capture window (if any).
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Window* capture_window = client::GetCaptureWindow(root_window);
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (capture_window)
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return capture_window;
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (event.IsTouchEvent()) {
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Query the gesture-recognizer to find targets for touch events.
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ui::TouchEvent& touch = static_cast<const ui::TouchEvent&>(event);
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ui::GestureConsumer* consumer =
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ui::GestureRecognizer::Get()->GetTouchLockedTarget(touch);
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (consumer)
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return static_cast<Window*>(consumer);
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    consumer =
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ui::GestureRecognizer::Get()->GetTargetForLocation(
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            event.location(), touch.source_device_id());
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (consumer)
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return static_cast<Window*>(consumer);
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // If the initial touch is outside the root window, target the root.
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!root_window->bounds().Contains(event.location()))
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return root_window;
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return NULL;
160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace aura
163