1 // Copyright 2015 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 "ash/display/unified_mouse_warp_controller.h"
9 #include "ash/display/display_manager.h"
10 #include "ash/display/display_util.h"
11 #include "ash/display/mirror_window_controller.h"
12 #include "ash/display/window_tree_host_manager.h"
13 #include "ash/host/ash_window_tree_host.h"
14 #include "ash/shell.h"
15 #include "ui/aura/client/cursor_client.h"
16 #include "ui/aura/window.h"
17 #include "ui/aura/window_tree_host.h"
18 #include "ui/base/layout.h"
19 #include "ui/events/event_utils.h"
20 #include "ui/gfx/screen.h"
21 #include "ui/wm/core/coordinate_conversion.h"
27 AshWindowTreeHost
* GetMirroringAshWindowTreeHostForDisplayId(int64 display_id
) {
28 return Shell::GetInstance()
29 ->window_tree_host_manager()
30 ->mirror_window_controller()
31 ->GetAshWindowTreeHostForDisplayId(display_id
);
34 #if defined(USE_OZONE)
35 // Find a WindowTreeHost used for mirroring displays that contains
36 // the |point_in_screen|. Returns nullptr if such WTH does not exist.
37 aura::WindowTreeHost
* FindMirroringWindowTreeHostFromScreenPoint(
38 const gfx::Point
& point_in_screen
) {
39 DisplayManager::DisplayList mirroring_display_list
=
42 ->software_mirroring_display_list();
44 FindDisplayIndexContainingPoint(mirroring_display_list
, point_in_screen
);
47 return GetMirroringAshWindowTreeHostForDisplayId(
48 mirroring_display_list
[index
].id())->AsWindowTreeHost();
54 UnifiedMouseWarpController::UnifiedMouseWarpController()
55 : current_cursor_display_id_(gfx::Display::kInvalidDisplayID
),
56 update_location_for_test_(false) {}
58 UnifiedMouseWarpController::~UnifiedMouseWarpController() {
61 bool UnifiedMouseWarpController::WarpMouseCursor(ui::MouseEvent
* event
) {
62 // Mirroring windows are created asynchronously, so compute the edge
63 // beounds when we received an event instead of in constructor.
64 if (first_edge_bounds_in_native_
.IsEmpty())
67 aura::Window
* target
= static_cast<aura::Window
*>(event
->target());
68 gfx::Point point_in_unified_host
= event
->location();
69 ::wm::ConvertPointToScreen(target
, &point_in_unified_host
);
70 // The display bounds of the mirroring windows isn't scaled, so
71 // transform back to the host coordinates.
72 target
->GetHost()->GetRootTransform().TransformPoint(&point_in_unified_host
);
74 if (current_cursor_display_id_
!= gfx::Display::kInvalidDisplayID
) {
75 aura::client::CursorClient
* cursor_client
=
76 aura::client::GetCursorClient(target
->GetRootWindow());
78 DisplayManager::DisplayList mirroring_display_list
=
81 ->software_mirroring_display_list();
82 int index
= FindDisplayIndexContainingPoint(mirroring_display_list
,
83 point_in_unified_host
);
85 const gfx::Display
& new_display
= mirroring_display_list
[index
];
86 if (current_cursor_display_id_
!= new_display
.id()) {
87 cursor_client
->SetDisplay(new_display
);
88 current_cursor_display_id_
= gfx::Display::kInvalidDisplayID
;
94 // A native event may not exist in unit test.
95 if (!event
->HasNativeEvent())
98 gfx::Point point_in_native
=
99 ui::EventSystemLocationFromNative(event
->native_event());
101 #if defined(USE_OZONE)
102 // TODO(dnicoara): crbug.com/415680 Move cursor warping into Ozone once Ozone
103 // has access to the logical display layout.
104 // Native events in Ozone are in the native window coordinate system. We need
105 // to translate them to get the global position.
106 aura::WindowTreeHost
* host
=
107 FindMirroringWindowTreeHostFromScreenPoint(point_in_unified_host
);
110 point_in_native
.Offset(host
->GetBounds().x(), host
->GetBounds().y());
113 return WarpMouseCursorInNativeCoords(point_in_native
, point_in_unified_host
,
114 update_location_for_test_
);
117 void UnifiedMouseWarpController::SetEnabled(bool enabled
) {
118 // Mouse warp shuld be always on in Unified mode.
121 void UnifiedMouseWarpController::ComputeBounds() {
122 DisplayManager::DisplayList display_list
=
125 ->software_mirroring_display_list();
127 if (display_list
.size() < 2) {
128 LOG(ERROR
) << "Mirroring Display lost during re-configuration";
131 LOG_IF(ERROR
, display_list
.size() > 2) << "Only two displays are supported";
133 const gfx::Display
& first
= display_list
[0];
134 const gfx::Display
& second
= display_list
[1];
135 ComputeBoundary(first
, second
, DisplayLayout::RIGHT
,
136 &first_edge_bounds_in_native_
,
137 &second_edge_bounds_in_native_
);
139 first_edge_bounds_in_native_
=
140 GetNativeEdgeBounds(GetMirroringAshWindowTreeHostForDisplayId(first
.id()),
141 first_edge_bounds_in_native_
);
143 second_edge_bounds_in_native_
= GetNativeEdgeBounds(
144 GetMirroringAshWindowTreeHostForDisplayId(second
.id()),
145 second_edge_bounds_in_native_
);
148 bool UnifiedMouseWarpController::WarpMouseCursorInNativeCoords(
149 const gfx::Point
& point_in_native
,
150 const gfx::Point
& point_in_unified_host
,
151 bool update_mouse_location_now
) {
152 bool in_first_edge
= first_edge_bounds_in_native_
.Contains(point_in_native
);
153 bool in_second_edge
= second_edge_bounds_in_native_
.Contains(point_in_native
);
154 if (!in_first_edge
&& !in_second_edge
)
156 DisplayManager::DisplayList display_list
=
159 ->software_mirroring_display_list();
160 // Wait updating the cursor until the cursor moves to the new display
161 // to avoid showing the wrong sized cursor at the source display.
162 current_cursor_display_id_
=
163 in_first_edge
? display_list
[0].id() : display_list
[1].id();
164 AshWindowTreeHost
* target_ash_host
=
165 GetMirroringAshWindowTreeHostForDisplayId(
166 in_first_edge
? display_list
[1].id() : display_list
[0].id());
167 MoveCursorTo(target_ash_host
, point_in_unified_host
,
168 update_mouse_location_now
);