1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/ui/ws/window_finder.h"
#include "base/containers/adapters.h"
#include "services/ui/ws/server_window.h"
#include "services/ui/ws/server_window_delegate.h"
#include "services/ui/ws/window_coordinate_conversions.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/transform.h"
namespace ui {
namespace ws {
namespace {
bool IsLocationInNonclientArea(const ServerWindow* target,
const gfx::Point& location) {
if (!target->parent() || target->bounds().size().IsEmpty())
return false;
gfx::Rect client_area(target->bounds().size());
client_area.Inset(target->client_area());
if (client_area.Contains(location))
return false;
for (const auto& rect : target->additional_client_areas()) {
if (rect.Contains(location))
return false;
}
return true;
}
bool FindDeepestVisibleWindowForEventsImpl(ServerWindow* window,
const gfx::Point& location,
DeepestWindow* deepest_window) {
// The non-client area takes precedence over descendants, as otherwise the
// user would likely not be able to hit the non-client area as it's common
// for descendants to go into the non-client area.
if (IsLocationInNonclientArea(window, location)) {
deepest_window->window = window;
deepest_window->in_non_client_area = true;
return true;
}
const mojom::EventTargetingPolicy event_targeting_policy =
window->event_targeting_policy();
if (event_targeting_policy == ui::mojom::EventTargetingPolicy::NONE)
return false;
if (event_targeting_policy ==
mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS ||
event_targeting_policy == mojom::EventTargetingPolicy::DESCENDANTS_ONLY) {
const ServerWindow::Windows& children = window->children();
for (ServerWindow* child : base::Reversed(children)) {
if (!child->visible())
continue;
// TODO(sky): support transform.
gfx::Point location_in_child(location.x() - child->bounds().x(),
location.y() - child->bounds().y());
gfx::Rect child_bounds(child->bounds().size());
child_bounds.Inset(-child->extended_hit_test_region().left(),
-child->extended_hit_test_region().top(),
-child->extended_hit_test_region().right(),
-child->extended_hit_test_region().bottom());
if (!child_bounds.Contains(location_in_child) ||
(child->hit_test_mask() &&
!child->hit_test_mask()->Contains(location_in_child))) {
continue;
}
if (FindDeepestVisibleWindowForEventsImpl(child, location_in_child,
deepest_window)) {
return true;
}
}
}
if (event_targeting_policy == mojom::EventTargetingPolicy::DESCENDANTS_ONLY)
return false;
deepest_window->window = window;
deepest_window->in_non_client_area = false;
return true;
}
} // namespace
DeepestWindow FindDeepestVisibleWindowForEvents(ServerWindow* root_window,
const gfx::Point& location) {
DeepestWindow result;
FindDeepestVisibleWindowForEventsImpl(root_window, location, &result);
return result;
}
gfx::Transform GetTransformToWindow(ServerWindow* window) {
gfx::Transform transform;
ServerWindow* current = window;
while (current->parent()) {
transform.Translate(-current->bounds().x(), -current->bounds().y());
current = current->parent();
}
return transform;
}
} // namespace ws
} // namespace ui
|