blob: 1c911cf8677959a811dc0b5c39b28c4b21da8a68 [file] [log] [blame]
// 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 "ash/display/unified_mouse_warp_controller.h"
#include <cmath>
#include "ash/display/display_manager.h"
#include "ash/display/display_util.h"
#include "ash/display/mirror_window_controller.h"
#include "ash/display/window_tree_host_manager.h"
#include "ash/host/ash_window_tree_host.h"
#include "ash/shell.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/base/layout.h"
#include "ui/display/manager/display_layout.h"
#include "ui/display/screen.h"
#include "ui/events/event_utils.h"
#include "ui/wm/core/coordinate_conversion.h"
namespace ash {
namespace {
AshWindowTreeHost* GetMirroringAshWindowTreeHostForDisplayId(
int64_t display_id) {
return Shell::GetInstance()
->window_tree_host_manager()
->mirror_window_controller()
->GetAshWindowTreeHostForDisplayId(display_id);
}
#if defined(USE_OZONE)
// Find a WindowTreeHost used for mirroring displays that contains
// the |point_in_screen|. Returns nullptr if such WTH does not exist.
aura::WindowTreeHost* FindMirroringWindowTreeHostFromScreenPoint(
const gfx::Point& point_in_screen) {
display::DisplayList mirroring_display_list =
Shell::GetInstance()
->display_manager()
->software_mirroring_display_list();
int index =
FindDisplayIndexContainingPoint(mirroring_display_list, point_in_screen);
if (index < 0)
return nullptr;
return GetMirroringAshWindowTreeHostForDisplayId(
mirroring_display_list[index].id())
->AsWindowTreeHost();
}
#endif
} // namespace
UnifiedMouseWarpController::UnifiedMouseWarpController()
: current_cursor_display_id_(display::Display::kInvalidDisplayID),
update_location_for_test_(false) {}
UnifiedMouseWarpController::~UnifiedMouseWarpController() {}
bool UnifiedMouseWarpController::WarpMouseCursor(ui::MouseEvent* event) {
// Mirroring windows are created asynchronously, so compute the edge
// beounds when we received an event instead of in constructor.
if (first_edge_bounds_in_native_.IsEmpty())
ComputeBounds();
aura::Window* target = static_cast<aura::Window*>(event->target());
gfx::Point point_in_unified_host = event->location();
::wm::ConvertPointToScreen(target, &point_in_unified_host);
// The display bounds of the mirroring windows isn't scaled, so
// transform back to the host coordinates.
target->GetHost()->GetRootTransform().TransformPoint(&point_in_unified_host);
if (current_cursor_display_id_ != display::Display::kInvalidDisplayID) {
aura::client::CursorClient* cursor_client =
aura::client::GetCursorClient(target->GetRootWindow());
if (cursor_client) {
display::DisplayList mirroring_display_list =
Shell::GetInstance()
->display_manager()
->software_mirroring_display_list();
int index = FindDisplayIndexContainingPoint(mirroring_display_list,
point_in_unified_host);
if (index >= 0) {
const display::Display& new_display = mirroring_display_list[index];
if (current_cursor_display_id_ != new_display.id()) {
cursor_client->SetDisplay(new_display);
current_cursor_display_id_ = display::Display::kInvalidDisplayID;
}
}
}
}
// A native event may not exist in unit test.
if (!event->HasNativeEvent())
return false;
gfx::Point point_in_native =
ui::EventSystemLocationFromNative(event->native_event());
#if defined(USE_OZONE)
// TODO(dnicoara): crbug.com/415680 Move cursor warping into Ozone once Ozone
// has access to the logical display layout.
// Native events in Ozone are in the native window coordinate system. We need
// to translate them to get the global position.
aura::WindowTreeHost* host =
FindMirroringWindowTreeHostFromScreenPoint(point_in_unified_host);
if (!host)
return false;
point_in_native.Offset(host->GetBounds().x(), host->GetBounds().y());
#endif
return WarpMouseCursorInNativeCoords(point_in_native, point_in_unified_host,
update_location_for_test_);
}
void UnifiedMouseWarpController::SetEnabled(bool enabled) {
// Mouse warp shuld be always on in Unified mode.
}
void UnifiedMouseWarpController::ComputeBounds() {
display::DisplayList display_list = Shell::GetInstance()
->display_manager()
->software_mirroring_display_list();
if (display_list.size() < 2) {
LOG(ERROR) << "Mirroring Display lost during re-configuration";
return;
}
LOG_IF(ERROR, display_list.size() > 2) << "Only two displays are supported";
const display::Display& first = display_list[0];
const display::Display& second = display_list[1];
bool success = ComputeBoundary(first, second, &first_edge_bounds_in_native_,
&second_edge_bounds_in_native_);
DCHECK(success);
first_edge_bounds_in_native_ =
GetNativeEdgeBounds(GetMirroringAshWindowTreeHostForDisplayId(first.id()),
first_edge_bounds_in_native_);
second_edge_bounds_in_native_ = GetNativeEdgeBounds(
GetMirroringAshWindowTreeHostForDisplayId(second.id()),
second_edge_bounds_in_native_);
}
bool UnifiedMouseWarpController::WarpMouseCursorInNativeCoords(
const gfx::Point& point_in_native,
const gfx::Point& point_in_unified_host,
bool update_mouse_location_now) {
bool in_first_edge = first_edge_bounds_in_native_.Contains(point_in_native);
bool in_second_edge = second_edge_bounds_in_native_.Contains(point_in_native);
if (!in_first_edge && !in_second_edge)
return false;
display::DisplayList display_list = Shell::GetInstance()
->display_manager()
->software_mirroring_display_list();
// Wait updating the cursor until the cursor moves to the new display
// to avoid showing the wrong sized cursor at the source display.
current_cursor_display_id_ =
in_first_edge ? display_list[0].id() : display_list[1].id();
AshWindowTreeHost* target_ash_host =
GetMirroringAshWindowTreeHostForDisplayId(
in_first_edge ? display_list[1].id() : display_list[0].id());
MoveCursorTo(target_ash_host, point_in_unified_host,
update_mouse_location_now);
return true;
}
} // namespace ash