window_targeter.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  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. #include "ui/aura/window_targeter.h"
  5. #include <tuple>
  6. #include "build/chromeos_buildflags.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/client/screen_position_client.h"
  11. #include "ui/aura/env.h"
  12. #include "ui/aura/window.h"
  13. #include "ui/aura/window_delegate.h"
  14. #include "ui/aura/window_event_dispatcher.h"
  15. #include "ui/aura/window_tree_host.h"
  16. #include "ui/compositor/layer.h"
  17. #include "ui/display/display.h"
  18. #include "ui/display/screen.h"
  19. #include "ui/events/event_target.h"
  20. #include "ui/events/event_target_iterator.h"
  21. namespace aura {
  22. WindowTargeter::WindowTargeter() = default;
  23. WindowTargeter::~WindowTargeter() = default;
  24. bool WindowTargeter::SubtreeShouldBeExploredForEvent(
  25. Window* window,
  26. const ui::LocatedEvent& event) {
  27. return SubtreeCanAcceptEvent(window, event) &&
  28. EventLocationInsideBounds(window, event);
  29. }
  30. bool WindowTargeter::GetHitTestRects(Window* window,
  31. gfx::Rect* hit_test_rect_mouse,
  32. gfx::Rect* hit_test_rect_touch) const {
  33. DCHECK(hit_test_rect_mouse);
  34. DCHECK(hit_test_rect_touch);
  35. *hit_test_rect_mouse = *hit_test_rect_touch = window->bounds();
  36. if (ShouldUseExtendedBounds(window)) {
  37. hit_test_rect_mouse->Inset(mouse_extend_);
  38. hit_test_rect_touch->Inset(touch_extend_);
  39. }
  40. return true;
  41. }
  42. std::unique_ptr<WindowTargeter::HitTestRects>
  43. WindowTargeter::GetExtraHitTestShapeRects(Window* target) const {
  44. return nullptr;
  45. }
  46. void WindowTargeter::SetInsets(const gfx::Insets& mouse_and_touch_extend) {
  47. SetInsets(mouse_and_touch_extend, mouse_and_touch_extend);
  48. }
  49. void WindowTargeter::SetInsets(const gfx::Insets& mouse_extend,
  50. const gfx::Insets& touch_extend) {
  51. if (mouse_extend_ == mouse_extend && touch_extend_ == touch_extend)
  52. return;
  53. mouse_extend_ = mouse_extend;
  54. touch_extend_ = touch_extend;
  55. }
  56. Window* WindowTargeter::GetPriorityTargetInRootWindow(
  57. Window* root_window,
  58. const ui::LocatedEvent& event) {
  59. DCHECK_EQ(root_window, root_window->GetRootWindow());
  60. // Mouse events should be dispatched to the window that processed the
  61. // mouse-press events (if any).
  62. if (event.IsScrollEvent() || event.IsMouseEvent()) {
  63. WindowEventDispatcher* dispatcher = root_window->GetHost()->dispatcher();
  64. if (dispatcher->mouse_pressed_handler())
  65. return dispatcher->mouse_pressed_handler();
  66. }
  67. // All events should be directed towards the capture window (if any).
  68. Window* capture_window = client::GetCaptureWindow(root_window);
  69. if (capture_window)
  70. return capture_window;
  71. if (event.IsPinchEvent()) {
  72. DCHECK_EQ(event.AsGestureEvent()->details().device_type(),
  73. ui::GestureDeviceType::DEVICE_TOUCHPAD);
  74. WindowEventDispatcher* dispatcher = root_window->GetHost()->dispatcher();
  75. if (dispatcher->touchpad_pinch_handler())
  76. return dispatcher->touchpad_pinch_handler();
  77. }
  78. if (event.IsTouchEvent()) {
  79. // Query the gesture-recognizer to find targets for touch events.
  80. const ui::TouchEvent& touch = *event.AsTouchEvent();
  81. ui::GestureConsumer* consumer =
  82. Env::GetInstance()->gesture_recognizer()->GetTouchLockedTarget(touch);
  83. if (consumer)
  84. return static_cast<Window*>(consumer);
  85. }
  86. return nullptr;
  87. }
  88. Window* WindowTargeter::FindTargetInRootWindow(Window* root_window,
  89. const ui::LocatedEvent& event) {
  90. DCHECK_EQ(root_window, root_window->GetRootWindow());
  91. Window* priority_target = GetPriorityTargetInRootWindow(root_window, event);
  92. if (priority_target)
  93. return priority_target;
  94. if (event.IsTouchEvent()) {
  95. // Query the gesture-recognizer to find targets for touch events.
  96. const ui::TouchEvent& touch = *event.AsTouchEvent();
  97. // GetTouchLockedTarget() is handled in GetPriorityTargetInRootWindow().
  98. ui::GestureRecognizer* gesture_recognizer =
  99. Env::GetInstance()->gesture_recognizer();
  100. DCHECK(!gesture_recognizer->GetTouchLockedTarget(touch));
  101. ui::GestureConsumer* consumer = gesture_recognizer->GetTargetForLocation(
  102. event.location_f(), touch.source_device_id());
  103. if (consumer)
  104. return static_cast<Window*>(consumer);
  105. #if BUILDFLAG(IS_CHROMEOS_ASH)
  106. // If the initial touch is outside the window's display, target the root.
  107. // This is used for bezel gesture events (eg. swiping in from screen edge).
  108. display::Display display =
  109. display::Screen::GetScreen()->GetDisplayNearestWindow(root_window);
  110. // The window target may be null, so use the root's ScreenPositionClient.
  111. gfx::Point screen_location = event.root_location();
  112. if (client::GetScreenPositionClient(root_window)) {
  113. client::GetScreenPositionClient(root_window)
  114. ->ConvertPointToScreen(root_window, &screen_location);
  115. }
  116. if (!display.bounds().Contains(screen_location))
  117. return root_window;
  118. #else
  119. // If the initial touch is outside the root window, target the root.
  120. // TODO(lanwei): this code is likely not necessarily and will be removed.
  121. if (!root_window->bounds().Contains(event.location()))
  122. return root_window;
  123. #endif
  124. }
  125. return nullptr;
  126. }
  127. bool WindowTargeter::ProcessEventIfTargetsDifferentRootWindow(
  128. Window* root_window,
  129. Window* target,
  130. ui::Event* event) {
  131. if (root_window->Contains(target))
  132. return false;
  133. // |window| is the root window, but |target| is not a descendent of
  134. // |window|. So do not allow dispatching from here. Instead, dispatch the
  135. // event through the WindowEventDispatcher that owns |target|.
  136. Window* new_root = target->GetRootWindow();
  137. DCHECK(new_root);
  138. if (event->IsLocatedEvent()) {
  139. // The event has been transformed to be in |target|'s coordinate system.
  140. // But dispatching the event through the EventProcessor requires the event
  141. // to be in the host's coordinate system. So, convert the event to be in
  142. // the root's coordinate space, and then to the host's coordinate space by
  143. // applying the host's transform.
  144. ui::LocatedEvent* located_event = event->AsLocatedEvent();
  145. located_event->ConvertLocationToTarget(target, new_root);
  146. WindowTreeHost* window_tree_host = new_root->GetHost();
  147. located_event->UpdateForRootTransform(
  148. window_tree_host->GetRootTransform(),
  149. window_tree_host->GetRootTransformForLocalEventCoordinates());
  150. }
  151. std::ignore = new_root->GetHost()->GetEventSink()->OnEventFromSource(event);
  152. return true;
  153. }
  154. ui::EventTarget* WindowTargeter::FindTargetForEvent(ui::EventTarget* root,
  155. ui::Event* event) {
  156. Window* window = static_cast<Window*>(root);
  157. Window* target = event->IsKeyEvent()
  158. ? FindTargetForKeyEvent(window)
  159. : FindTargetForNonKeyEvent(window, event);
  160. if (target && !window->parent() &&
  161. ProcessEventIfTargetsDifferentRootWindow(window, target, event)) {
  162. return nullptr;
  163. }
  164. return target;
  165. }
  166. ui::EventTarget* WindowTargeter::FindNextBestTarget(
  167. ui::EventTarget* previous_target,
  168. ui::Event* event) {
  169. return nullptr;
  170. }
  171. Window* WindowTargeter::FindTargetForKeyEvent(Window* window) {
  172. Window* root_window = window->GetRootWindow();
  173. client::FocusClient* focus_client = client::GetFocusClient(root_window);
  174. if (!focus_client)
  175. return window;
  176. Window* focused_window = focus_client->GetFocusedWindow();
  177. if (!focused_window)
  178. return window;
  179. client::EventClient* event_client = client::GetEventClient(root_window);
  180. if (event_client &&
  181. !event_client->GetCanProcessEventsWithinSubtree(focused_window)) {
  182. focus_client->FocusWindow(nullptr);
  183. return nullptr;
  184. }
  185. return focused_window ? focused_window : window;
  186. }
  187. void WindowTargeter::OnInstalled(Window* window) {
  188. window_ = window;
  189. }
  190. Window* WindowTargeter::FindTargetForLocatedEvent(Window* window,
  191. ui::LocatedEvent* event) {
  192. if (!window->parent()) {
  193. Window* target = FindTargetInRootWindow(window, *event);
  194. if (target) {
  195. window->ConvertEventToTarget(target, event);
  196. #if BUILDFLAG(IS_CHROMEOS_ASH)
  197. if (window->IsRootWindow() && event->HasNativeEvent()) {
  198. // If window is root, and the target is in a different host, we need to
  199. // convert the native event to the target's host as well. This happens
  200. // while a widget is being dragged and when the majority of its bounds
  201. // reside in a different display. Setting the widget's bounds at this
  202. // point changes the window's root, and the event's target's root, but
  203. // the events are still being generated relative to the original
  204. // display. crbug.com/714578.
  205. ui::LocatedEvent* e =
  206. static_cast<ui::LocatedEvent*>(event->native_event());
  207. gfx::PointF native_point = e->location_f();
  208. aura::Window::ConvertNativePointToTargetHost(window, target,
  209. &native_point);
  210. e->set_location_f(native_point);
  211. }
  212. #endif
  213. return target;
  214. }
  215. }
  216. return FindTargetForLocatedEventRecursively(window, event);
  217. }
  218. bool WindowTargeter::SubtreeCanAcceptEvent(
  219. Window* window,
  220. const ui::LocatedEvent& event) const {
  221. if (!window->IsVisible())
  222. return false;
  223. if (window->event_targeting_policy() == EventTargetingPolicy::kNone ||
  224. window->event_targeting_policy() == EventTargetingPolicy::kTargetOnly) {
  225. return false;
  226. }
  227. client::EventClient* client = client::GetEventClient(window->GetRootWindow());
  228. if (client && !client->GetCanProcessEventsWithinSubtree(window))
  229. return false;
  230. Window* parent = window->parent();
  231. if (parent && parent->delegate_ &&
  232. !parent->delegate_->ShouldDescendIntoChildForEventHandling(
  233. window, event.location())) {
  234. return false;
  235. }
  236. return true;
  237. }
  238. bool WindowTargeter::EventLocationInsideBounds(
  239. Window* window,
  240. const ui::LocatedEvent& event) const {
  241. gfx::Point point = ConvertEventLocationToWindowCoordinates(window, event);
  242. BoundsType bounds_type = BoundsType::kMouse;
  243. if (event.IsTouchEvent())
  244. bounds_type = BoundsType::kTouch;
  245. else if (event.IsGestureEvent())
  246. bounds_type = BoundsType::kGesture;
  247. return PointInsideBounds(window, bounds_type, point);
  248. }
  249. bool WindowTargeter::ShouldUseExtendedBounds(const aura::Window* w) const {
  250. // window() is null when this is used as the default targeter (by
  251. // WindowEventDispatcher). Insets should never be set in this case, so the
  252. // return should not matter.
  253. if (!window()) {
  254. DCHECK(mouse_extend_.IsEmpty());
  255. DCHECK(touch_extend_.IsEmpty());
  256. return false;
  257. }
  258. // Insets should only apply to the window. Subclasses may enforce other
  259. // policies.
  260. return window() == w;
  261. }
  262. // static
  263. gfx::Point WindowTargeter::ConvertEventLocationToWindowCoordinates(
  264. Window* window,
  265. const ui::LocatedEvent& event) {
  266. gfx::Point point = event.location();
  267. if (window->parent())
  268. Window::ConvertPointToTarget(window->parent(), window, &point);
  269. return point;
  270. }
  271. Window* WindowTargeter::FindTargetForNonKeyEvent(Window* root_window,
  272. ui::Event* event) {
  273. if (!event->IsLocatedEvent())
  274. return root_window;
  275. return FindTargetForLocatedEvent(root_window,
  276. static_cast<ui::LocatedEvent*>(event));
  277. }
  278. Window* WindowTargeter::FindTargetForLocatedEventRecursively(
  279. Window* root_window,
  280. ui::LocatedEvent* event) {
  281. std::unique_ptr<ui::EventTargetIterator> iter =
  282. root_window->GetChildIterator();
  283. if (iter) {
  284. ui::EventTarget* target = root_window;
  285. for (ui::EventTarget* child = iter->GetNextTarget(); child;
  286. child = iter->GetNextTarget()) {
  287. WindowTargeter* targeter =
  288. static_cast<WindowTargeter*>(child->GetEventTargeter());
  289. if (!targeter)
  290. targeter = this;
  291. if (!targeter->SubtreeShouldBeExploredForEvent(
  292. static_cast<Window*>(child), *event)) {
  293. continue;
  294. }
  295. target->ConvertEventToTarget(child, event);
  296. target = child;
  297. Window* child_target_window =
  298. static_cast<Window*>(targeter->FindTargetForEvent(child, event));
  299. if (child_target_window)
  300. return child_target_window;
  301. }
  302. target->ConvertEventToTarget(root_window, event);
  303. }
  304. return root_window->CanAcceptEvent(*event) ? root_window : nullptr;
  305. }
  306. bool WindowTargeter::PointInsideBounds(Window* window,
  307. BoundsType bounds_type,
  308. const gfx::Point& point) const {
  309. gfx::Rect mouse_rect;
  310. gfx::Rect touch_rect;
  311. if (!GetHitTestRects(window, &mouse_rect, &touch_rect))
  312. return false;
  313. const gfx::Vector2d offset = -window->bounds().OffsetFromOrigin();
  314. mouse_rect.Offset(offset);
  315. touch_rect.Offset(offset);
  316. const bool point_in_rect =
  317. bounds_type == BoundsType::kTouch || bounds_type == BoundsType::kGesture
  318. ? touch_rect.Contains(point)
  319. : mouse_rect.Contains(point);
  320. if (point_in_rect) {
  321. auto shape_rects = GetExtraHitTestShapeRects(window);
  322. if (!shape_rects)
  323. return true;
  324. for (const gfx::Rect& shape_rect : *shape_rects) {
  325. if (shape_rect.Contains(point)) {
  326. return true;
  327. }
  328. }
  329. return false;
  330. }
  331. if (ShouldUseExtendedBounds(window) &&
  332. (!mouse_extend_.IsEmpty() || !touch_extend_.IsEmpty())) {
  333. // Insets take priority over child traversal, otherwise it's possible to
  334. // have a window that has a non-interactable region in the middle.
  335. return false;
  336. }
  337. if (window->layer()->GetMasksToBounds()) {
  338. // If the layer masks to bounds, children are clipped and shouldn't receive
  339. // input events.
  340. return false;
  341. }
  342. // Child windows are not always fully contained in the current window.
  343. std::unique_ptr<ui::EventTargetIterator> iter = window->GetChildIterator();
  344. if (!iter)
  345. return false;
  346. for (ui::EventTarget* child = iter->GetNextTarget(); child;
  347. child = iter->GetNextTarget()) {
  348. auto* child_window = static_cast<Window*>(child);
  349. gfx::Point child_point(point);
  350. Window::ConvertPointToTarget(window, child_window, &child_point);
  351. if (PointInsideBounds(child_window, bounds_type, child_point))
  352. return true;
  353. }
  354. return false;
  355. }
  356. } // namespace aura