Elim cr-checkbox
[chromium-blink-merge.git] / ash / display / extended_mouse_warp_controller.cc
bloba28de78d3d73cb15f8af5c7040a1cc4fb18f09d6
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/extended_mouse_warp_controller.h"
7 #include <cmath>
9 #include "ash/display/display_manager.h"
10 #include "ash/display/display_util.h"
11 #include "ash/display/shared_display_edge_indicator.h"
12 #include "ash/root_window_controller.h"
13 #include "ash/screen_util.h"
14 #include "ash/shell.h"
15 #include "ui/aura/window.h"
16 #include "ui/events/event_utils.h"
17 #include "ui/gfx/screen.h"
18 #include "ui/wm/core/coordinate_conversion.h"
20 namespace ash {
22 namespace {
24 // Maximum size on the display edge that initiate snapping phantom window,
25 // from the corner of the display.
26 const int kMaximumSnapHeight = 16;
28 // Minimum height of an indicator on the display edge that allows
29 // dragging a window. If two displays shares the edge smaller than
30 // this, entire edge will be used as a draggable space.
31 const int kMinimumIndicatorHeight = 200;
33 const int kIndicatorThickness = 1;
35 } // namespace
37 ExtendedMouseWarpController::ExtendedMouseWarpController(
38 aura::Window* drag_source)
39 : drag_source_root_(drag_source),
40 shared_display_edge_indicator_(new SharedDisplayEdgeIndicator),
41 allow_non_native_event_(false) {
42 DisplayLayout::Position position = Shell::GetInstance()
43 ->display_manager()
44 ->GetCurrentDisplayLayout()
45 .position;
46 // TODO(oshima): Use ComputeBondary instead.
47 if (position == DisplayLayout::TOP || position == DisplayLayout::BOTTOM)
48 UpdateHorizontalEdgeBounds();
49 else
50 UpdateVerticalEdgeBounds();
51 if (drag_source) {
52 shared_display_edge_indicator_->Show(src_indicator_bounds_,
53 dst_indicator_bounds_);
57 ExtendedMouseWarpController::~ExtendedMouseWarpController() {
60 bool ExtendedMouseWarpController::WarpMouseCursor(ui::MouseEvent* event) {
61 if (Shell::GetScreen()->GetNumDisplays() <= 1 || !enabled_)
62 return false;
64 aura::Window* target = static_cast<aura::Window*>(event->target());
65 gfx::Point point_in_screen = event->location();
66 ::wm::ConvertPointToScreen(target, &point_in_screen);
68 // A native event may not exist in unit test. Generate the native point
69 // from the screen point instead.
70 if (!event->HasNativeEvent()) {
71 if (!allow_non_native_event_)
72 return false;
73 aura::Window* target_root = target->GetRootWindow();
74 gfx::Point point_in_native = point_in_screen;
75 ::wm::ConvertPointFromScreen(target_root, &point_in_native);
76 target_root->GetHost()->ConvertPointToNativeScreen(&point_in_native);
77 return WarpMouseCursorInNativeCoords(point_in_native, point_in_screen,
78 true);
81 gfx::Point point_in_native =
82 ui::EventSystemLocationFromNative(event->native_event());
84 #if defined(USE_OZONE)
85 // TODO(dnicoara): crbug.com/415680 Move cursor warping into Ozone once Ozone
86 // has access to the logical display layout.
87 // Native events in Ozone are in the native window coordinate system. We need
88 // to translate them to get the global position.
89 point_in_native.Offset(target->GetHost()->GetBounds().x(),
90 target->GetHost()->GetBounds().y());
91 #endif
93 return WarpMouseCursorInNativeCoords(point_in_native, point_in_screen, false);
96 void ExtendedMouseWarpController::SetEnabled(bool enabled) {
97 enabled_ = enabled;
100 bool ExtendedMouseWarpController::WarpMouseCursorInNativeCoords(
101 const gfx::Point& point_in_native,
102 const gfx::Point& point_in_screen,
103 bool update_mouse_location_now) {
104 bool in_src_edge = src_edge_bounds_in_native_.Contains(point_in_native);
105 bool in_dst_edge = dst_edge_bounds_in_native_.Contains(point_in_native);
106 if (!in_src_edge && !in_dst_edge)
107 return false;
109 // The mouse must move.
110 aura::Window* src_root = nullptr;
111 aura::Window* dst_root = nullptr;
112 GetSrcAndDstRootWindows(&src_root, &dst_root);
113 AshWindowTreeHost* target_ash_host =
114 GetRootWindowController(in_src_edge ? dst_root : src_root)->ash_host();
116 MoveCursorTo(target_ash_host, point_in_screen, update_mouse_location_now);
117 return true;
120 void ExtendedMouseWarpController::UpdateHorizontalEdgeBounds() {
121 bool from_primary = Shell::GetPrimaryRootWindow() == drag_source_root_;
122 // GetPrimaryDisplay returns an object on stack, so copy the bounds
123 // instead of using reference.
124 const gfx::Rect primary_bounds =
125 Shell::GetScreen()->GetPrimaryDisplay().bounds();
126 const gfx::Rect secondary_bounds = ScreenUtil::GetSecondaryDisplay().bounds();
127 DisplayLayout::Position position = Shell::GetInstance()
128 ->display_manager()
129 ->GetCurrentDisplayLayout()
130 .position;
132 src_indicator_bounds_.set_x(
133 std::max(primary_bounds.x(), secondary_bounds.x()));
134 src_indicator_bounds_.set_width(
135 std::min(primary_bounds.right(), secondary_bounds.right()) -
136 src_indicator_bounds_.x());
137 src_indicator_bounds_.set_height(kIndicatorThickness);
138 src_indicator_bounds_.set_y(
139 position == DisplayLayout::TOP
140 ? primary_bounds.y() - (from_primary ? 0 : kIndicatorThickness)
141 : primary_bounds.bottom() - (from_primary ? kIndicatorThickness : 0));
143 dst_indicator_bounds_ = src_indicator_bounds_;
144 dst_indicator_bounds_.set_height(kIndicatorThickness);
145 dst_indicator_bounds_.set_y(
146 position == DisplayLayout::TOP
147 ? primary_bounds.y() - (from_primary ? kIndicatorThickness : 0)
148 : primary_bounds.bottom() - (from_primary ? 0 : kIndicatorThickness));
150 aura::Window* src_root = nullptr;
151 aura::Window* dst_root = nullptr;
152 GetSrcAndDstRootWindows(&src_root, &dst_root);
154 src_edge_bounds_in_native_ = GetNativeEdgeBounds(
155 GetRootWindowController(src_root)->ash_host(), src_indicator_bounds_);
156 dst_edge_bounds_in_native_ = GetNativeEdgeBounds(
157 GetRootWindowController(dst_root)->ash_host(), dst_indicator_bounds_);
160 void ExtendedMouseWarpController::UpdateVerticalEdgeBounds() {
161 int snap_height = drag_source_root_ ? kMaximumSnapHeight : 0;
162 bool in_primary = Shell::GetPrimaryRootWindow() == drag_source_root_;
163 // GetPrimaryDisplay returns an object on stack, so copy the bounds
164 // instead of using reference.
165 const gfx::Rect primary_bounds =
166 Shell::GetScreen()->GetPrimaryDisplay().bounds();
167 const gfx::Rect secondary_bounds = ScreenUtil::GetSecondaryDisplay().bounds();
168 DisplayLayout::Position position = Shell::GetInstance()
169 ->display_manager()
170 ->GetCurrentDisplayLayout()
171 .position;
173 int upper_shared_y = std::max(primary_bounds.y(), secondary_bounds.y());
174 int lower_shared_y =
175 std::min(primary_bounds.bottom(), secondary_bounds.bottom());
176 int shared_height = lower_shared_y - upper_shared_y;
178 int dst_x =
179 position == DisplayLayout::LEFT
180 ? primary_bounds.x() - (in_primary ? kIndicatorThickness : 0)
181 : primary_bounds.right() - (in_primary ? 0 : kIndicatorThickness);
182 dst_indicator_bounds_.SetRect(dst_x, upper_shared_y, kIndicatorThickness,
183 shared_height);
185 // The indicator on the source display.
186 src_indicator_bounds_.set_width(kIndicatorThickness);
187 src_indicator_bounds_.set_x(
188 position == DisplayLayout::LEFT
189 ? primary_bounds.x() - (in_primary ? 0 : kIndicatorThickness)
190 : primary_bounds.right() - (in_primary ? kIndicatorThickness : 0));
192 const gfx::Rect& source_bounds =
193 in_primary ? primary_bounds : secondary_bounds;
194 int upper_indicator_y = source_bounds.y() + snap_height;
195 int lower_indicator_y = std::min(source_bounds.bottom(), lower_shared_y);
197 // This gives a hight that can be used without sacrifying the snap space.
198 int available_space =
199 lower_indicator_y - std::max(upper_shared_y, upper_indicator_y);
201 if (shared_height < kMinimumIndicatorHeight) {
202 // If the shared height is smaller than minimum height, use the
203 // entire height.
204 upper_indicator_y = upper_shared_y;
205 } else if (available_space < kMinimumIndicatorHeight) {
206 // Snap to the bottom.
207 upper_indicator_y =
208 std::max(upper_shared_y, lower_indicator_y + kMinimumIndicatorHeight);
209 } else {
210 upper_indicator_y = std::max(upper_indicator_y, upper_shared_y);
212 src_indicator_bounds_.set_y(upper_indicator_y);
213 src_indicator_bounds_.set_height(lower_indicator_y - upper_indicator_y);
215 aura::Window* src_root = nullptr;
216 aura::Window* dst_root = nullptr;
217 GetSrcAndDstRootWindows(&src_root, &dst_root);
219 // Native
220 src_edge_bounds_in_native_ = GetNativeEdgeBounds(
221 GetRootWindowController(src_root)->ash_host(), src_indicator_bounds_);
222 dst_edge_bounds_in_native_ = GetNativeEdgeBounds(
223 GetRootWindowController(dst_root)->ash_host(), dst_indicator_bounds_);
226 void ExtendedMouseWarpController::GetSrcAndDstRootWindows(
227 aura::Window** src_root,
228 aura::Window** dst_root) {
229 aura::Window::Windows root_windows = Shell::GetAllRootWindows();
230 *src_root = drag_source_root_ ? drag_source_root_
231 : Shell::GetInstance()->GetPrimaryRootWindow();
232 *dst_root = root_windows[0] == *src_root ? root_windows[1] : root_windows[0];
235 } // namespace ash