Commit 89230998 authored by oshima@chromium.org's avatar oshima@chromium.org

Don't move cursor location when rotation /ui scaling has changed

 Moved EnsurePointerInDisplays to DisplayController as it needs to access RootWindow.


BUG=226300
TEST=covered by test.

Review URL: https://chromiumcodereview.appspot.com/13466022

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@193008 0039d316-1c4b-4281-b951-d872f2087c98
parent fb1b37b3
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "base/stringprintf.h" #include "base/stringprintf.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/values.h" #include "base/values.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/client/screen_position_client.h" #include "ui/aura/client/screen_position_client.h"
#include "ui/aura/env.h" #include "ui/aura/env.h"
#include "ui/aura/root_window.h" #include "ui/aura/root_window.h"
...@@ -722,6 +723,76 @@ gfx::Display* DisplayController::GetSecondaryDisplay() { ...@@ -722,6 +723,76 @@ gfx::Display* DisplayController::GetSecondaryDisplay() {
display_manager->GetDisplayAt(1) : display_manager->GetDisplayAt(0); display_manager->GetDisplayAt(1) : display_manager->GetDisplayAt(0);
} }
void DisplayController::EnsurePointerInDisplays() {
// Don't try to move the pointer during the boot/startup.
if (!HasPrimaryDisplay())
return;
gfx::Point location_in_screen = Shell::GetScreen()->GetCursorScreenPoint();
gfx::Point target_location;
int64 closest_distance_squared = -1;
internal::DisplayManager* display_manager = GetDisplayManager();
aura::RootWindow* dst_root_window = NULL;
for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
const gfx::Display* display = display_manager->GetDisplayAt(i);
aura::RootWindow* root_window = GetRootWindowForDisplayId(display->id());
if (display->bounds().Contains(location_in_screen)) {
dst_root_window = root_window;
target_location = location_in_screen;
break;
}
gfx::Point center = display->bounds().CenterPoint();
// Use the distance squared from the center of the dislay. This is not
// exactly "closest" display, but good enough to pick one
// appropriate (and there are at most two displays).
// We don't care about actual distance, only relative to other displays, so
// using the LengthSquared() is cheaper than Length().
int64 distance_squared = (center - location_in_screen).LengthSquared();
if (closest_distance_squared < 0 ||
closest_distance_squared > distance_squared) {
dst_root_window = root_window;
target_location = center;
closest_distance_squared = distance_squared;
}
}
DCHECK(dst_root_window);
aura::client::ScreenPositionClient* client =
aura::client::GetScreenPositionClient(dst_root_window);
client->ConvertPointFromScreen(dst_root_window, &target_location);
dst_root_window->MoveCursorTo(target_location);
}
gfx::Point DisplayController::GetNativeMouseCursorLocation() const {
gfx::Point location = Shell::GetScreen()->GetCursorScreenPoint();
const gfx::Display& display =
Shell::GetScreen()->GetDisplayNearestPoint(location);
const aura::RootWindow* root_window =
root_windows_.find(display.id())->second;
aura::client::ScreenPositionClient* client =
aura::client::GetScreenPositionClient(root_window);
client->ConvertPointFromScreen(root_window, &location);
root_window->ConvertPointToNativeScreen(&location);
return location;
}
void DisplayController::UpdateMouseCursor(const gfx::Point& point_in_native) {
std::vector<aura::RootWindow*> root_windows = GetAllRootWindows();
for (std::vector<aura::RootWindow*>::iterator iter = root_windows.begin();
iter != root_windows.end();
++iter) {
aura::RootWindow* root_window = *iter;
gfx::Rect bounds_in_native(root_window->GetHostOrigin(),
root_window->GetHostSize());
if (bounds_in_native.Contains(point_in_native)) {
gfx::Point point(point_in_native);
root_window->ConvertPointFromNativeScreen(&point);
root_window->MoveCursorTo(point);
break;
}
}
}
void DisplayController::OnDisplayBoundsChanged(const gfx::Display& display) { void DisplayController::OnDisplayBoundsChanged(const gfx::Display& display) {
if (limiter_.get()) if (limiter_.get())
limiter_->SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs); limiter_->SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs);
......
...@@ -191,6 +191,16 @@ class ASH_EXPORT DisplayController : public gfx::DisplayObserver { ...@@ -191,6 +191,16 @@ class ASH_EXPORT DisplayController : public gfx::DisplayObserver {
// Returns the display layout registered for the given display id |pair|. // Returns the display layout registered for the given display id |pair|.
DisplayLayout GetRegisteredDisplayLayout(const DisplayIdPair& pair) const; DisplayLayout GetRegisteredDisplayLayout(const DisplayIdPair& pair) const;
// Checks if the mouse pointer is on one of displays, and moves to
// the center of the nearest display if it's outside of all displays.
void EnsurePointerInDisplays();
gfx::Point GetNativeMouseCursorLocation() const;
// Update the current cursor image that is sutable for the given
// |point_in_native|.
void UpdateMouseCursor(const gfx::Point& point_in_native);
// aura::DisplayObserver overrides: // aura::DisplayObserver overrides:
virtual void OnDisplayBoundsChanged( virtual void OnDisplayBoundsChanged(
const gfx::Display& display) OVERRIDE; const gfx::Display& display) OVERRIDE;
......
...@@ -358,6 +358,8 @@ void DisplayManager::UpdateDisplays( ...@@ -358,6 +358,8 @@ void DisplayManager::UpdateDisplays(
DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin(); DisplayInfoList::const_iterator new_info_iter = new_display_info_list.begin();
DisplayList new_displays; DisplayList new_displays;
bool update_mouse_location = false;
while (curr_iter != displays_.end() || while (curr_iter != displays_.end() ||
new_info_iter != new_display_info_list.end()) { new_info_iter != new_display_info_list.end()) {
if (curr_iter == displays_.end()) { if (curr_iter == displays_.end()) {
...@@ -371,6 +373,7 @@ void DisplayManager::UpdateDisplays( ...@@ -371,6 +373,7 @@ void DisplayManager::UpdateDisplays(
// more displays in current list. // more displays in current list.
removed_displays.push_back(*curr_iter); removed_displays.push_back(*curr_iter);
++curr_iter; ++curr_iter;
update_mouse_location = true;
} else if (curr_iter->id() == new_info_iter->id()) { } else if (curr_iter->id() == new_info_iter->id()) {
const gfx::Display& current_display = *curr_iter; const gfx::Display& current_display = *curr_iter;
// Copy the info because |CreateDisplayFromInfo| updates the instance. // Copy the info because |CreateDisplayFromInfo| updates the instance.
...@@ -380,17 +383,27 @@ void DisplayManager::UpdateDisplays( ...@@ -380,17 +383,27 @@ void DisplayManager::UpdateDisplays(
gfx::Display new_display = gfx::Display new_display =
CreateDisplayFromDisplayInfoById(new_info_iter->id()); CreateDisplayFromDisplayInfoById(new_info_iter->id());
const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id()); const DisplayInfo& new_display_info = GetDisplayInfo(new_display.id());
bool host_window_bounds_changed =
current_display_info.bounds_in_pixel() !=
new_display_info.bounds_in_pixel();
// TODO(oshima): Rotating square dislay doesn't work as the size // TODO(oshima): Rotating square dislay doesn't work as the size
// won't change. This doesn't cause a problem now as there is no // won't change. This doesn't cause a problem now as there is no
// such display. This will be fixed by comparing the rotation as // such display. This will be fixed by comparing the rotation as
// well when the rotation variable is added to gfx::Display. // well when the rotation variable is added to gfx::Display.
if (force_bounds_changed_ || if (force_bounds_changed_ ||
(current_display_info.bounds_in_pixel() != host_window_bounds_changed ||
new_display_info.bounds_in_pixel()) ||
(current_display.device_scale_factor() != (current_display.device_scale_factor() !=
new_display.device_scale_factor()) || new_display.device_scale_factor()) ||
(current_display_info.size_in_pixel() != (current_display_info.size_in_pixel() !=
new_display.GetSizeInPixel())) { new_display.GetSizeInPixel())) {
// Don't update mouse location if the display size has
// changed due to rotation or zooming.
if (host_window_bounds_changed)
update_mouse_location = true;
changed_display_indices.push_back(new_displays.size()); changed_display_indices.push_back(new_displays.size());
} }
...@@ -402,6 +415,7 @@ void DisplayManager::UpdateDisplays( ...@@ -402,6 +415,7 @@ void DisplayManager::UpdateDisplays(
// more displays in current list between ids, which means it is deleted. // more displays in current list between ids, which means it is deleted.
removed_displays.push_back(*curr_iter); removed_displays.push_back(*curr_iter);
++curr_iter; ++curr_iter;
update_mouse_location = true;
} else { } else {
// more displays in new list between ids, which means it is added. // more displays in new list between ids, which means it is added.
added_display_indices.push_back(new_displays.size()); added_display_indices.push_back(new_displays.size());
...@@ -420,6 +434,16 @@ void DisplayManager::UpdateDisplays( ...@@ -420,6 +434,16 @@ void DisplayManager::UpdateDisplays(
return; return;
} }
DisplayController* display_controller =
Shell::GetInstance()->display_controller();
gfx::Point mouse_location_in_native;
// |display_controller| is NULL during the bootstrap.
if (display_controller) {
display_controller->NotifyDisplayConfigurationChanging();
mouse_location_in_native =
display_controller->GetNativeMouseCursorLocation();
}
displays_ = new_displays; displays_ = new_displays;
base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false); base::AutoReset<bool> resetter(&change_display_upon_host_resize_, false);
...@@ -428,11 +452,6 @@ void DisplayManager::UpdateDisplays( ...@@ -428,11 +452,6 @@ void DisplayManager::UpdateDisplays(
// being removed are accessed during shutting down the root. // being removed are accessed during shutting down the root.
displays_.insert(displays_.end(), removed_displays.begin(), displays_.insert(displays_.end(), removed_displays.begin(),
removed_displays.end()); removed_displays.end());
DisplayController* display_controller =
Shell::GetInstance()->display_controller();
// |display_controller| is NULL during the bootstrap.
if (display_controller)
display_controller->NotifyDisplayConfigurationChanging();
for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin(); for (DisplayList::const_reverse_iterator iter = removed_displays.rbegin();
iter != removed_displays.rend(); ++iter) { iter != removed_displays.rend(); ++iter) {
...@@ -447,10 +466,13 @@ void DisplayManager::UpdateDisplays( ...@@ -447,10 +466,13 @@ void DisplayManager::UpdateDisplays(
iter != changed_display_indices.end(); ++iter) { iter != changed_display_indices.end(); ++iter) {
Shell::GetInstance()->screen()->NotifyBoundsChanged(displays_[*iter]); Shell::GetInstance()->screen()->NotifyBoundsChanged(displays_[*iter]);
} }
if (display_controller) if (display_controller) {
display_controller->NotifyDisplayConfigurationChanged(); display_controller->NotifyDisplayConfigurationChanged();
if (update_mouse_location)
EnsurePointerInDisplays(); display_controller->EnsurePointerInDisplays();
else
display_controller->UpdateMouseCursor(mouse_location_in_native);
}
#if defined(USE_X11) && defined(OS_CHROMEOS) #if defined(USE_X11) && defined(OS_CHROMEOS)
if (!changed_display_indices.empty() && base::chromeos::IsRunningOnChromeOS()) if (!changed_display_indices.empty() && base::chromeos::IsRunningOnChromeOS())
ui::ClearX11DefaultRootWindow(); ui::ClearX11DefaultRootWindow();
...@@ -655,44 +677,6 @@ void DisplayManager::AddDisplayFromSpec(const std::string& spec) { ...@@ -655,44 +677,6 @@ void DisplayManager::AddDisplayFromSpec(const std::string& spec) {
displays_.push_back(display); displays_.push_back(display);
} }
void DisplayManager::EnsurePointerInDisplays() {
// Don't try to move the pointer during the boot/startup.
if (!DisplayController::HasPrimaryDisplay())
return;
gfx::Point location_in_screen = Shell::GetScreen()->GetCursorScreenPoint();
gfx::Point target_location;
int64 closest_distance_squared = -1;
for (DisplayList::const_iterator iter = displays_.begin();
iter != displays_.end(); ++iter) {
const gfx::Rect& display_bounds = iter->bounds();
if (display_bounds.Contains(location_in_screen)) {
target_location = location_in_screen;
break;
}
gfx::Point center = display_bounds.CenterPoint();
// Use the distance squared from the center of the dislay. This is not
// exactly "closest" display, but good enough to pick one
// appropriate (and there are at most two displays).
// We don't care about actual distance, only relative to other displays, so
// using the LengthSquared() is cheaper than Length().
int64 distance_squared = (center - location_in_screen).LengthSquared();
if (closest_distance_squared < 0 ||
closest_distance_squared > distance_squared) {
target_location = center;
closest_distance_squared = distance_squared;
}
}
aura::RootWindow* root_window = Shell::GetPrimaryRootWindow();
aura::client::ScreenPositionClient* client =
aura::client::GetScreenPositionClient(root_window);
client->ConvertPointFromScreen(root_window, &target_location);
root_window->MoveCursorTo(target_location);
}
void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) { void DisplayManager::InsertAndUpdateDisplayInfo(const DisplayInfo& new_info) {
std::map<int64, DisplayInfo>::iterator info = std::map<int64, DisplayInfo>::iterator info =
display_info_.find(new_info.id()); display_info_.find(new_info.id());
......
...@@ -193,10 +193,6 @@ class ASH_EXPORT DisplayManager : public aura::RootWindowObserver { ...@@ -193,10 +193,6 @@ class ASH_EXPORT DisplayManager : public aura::RootWindowObserver {
// Refer to |CreateDisplayFromSpec| API for the format of |spec|. // Refer to |CreateDisplayFromSpec| API for the format of |spec|.
void AddDisplayFromSpec(const std::string& spec); void AddDisplayFromSpec(const std::string& spec);
// Checks if the mouse pointer is on one of displays, and moves to
// the center of the nearest display if it's outside of all displays.
void EnsurePointerInDisplays();
// Inserts and update the DisplayInfo according to the overscan // Inserts and update the DisplayInfo according to the overscan
// state. Note that The DisplayInfo stored in the |internal_display_info_| // state. Note that The DisplayInfo stored in the |internal_display_info_|
// can be different from |new_info| (due to overscan state), so // can be different from |new_info| (due to overscan state), so
......
...@@ -748,5 +748,48 @@ TEST_F(DisplayManagerTest, UIScale) { ...@@ -748,5 +748,48 @@ TEST_F(DisplayManagerTest, UIScale) {
EXPECT_EQ(0.5f, GetDisplayInfoAt(0).ui_scale()); EXPECT_EQ(0.5f, GetDisplayInfoAt(0).ui_scale());
} }
#if defined(OS_WIN)
// TODO(oshima): On Windows, we don't update the origin/size right away.
#define MAYBE_UpdateMouseCursorAfterRotateZoom DISABLED_UpdateMouseCursorAfterRotateZoom
#else
#define MAYBE_UpdateMouseCursorAfterRotateZoom UpdateMouseCursorAfterRotateZoom
#endif
TEST_F(DisplayManagerTest, MAYBE_UpdateMouseCursorAfterRotateZoom) {
// Make sure just rotating will not change native location.
UpdateDisplay("300x200,200x150");
Shell::RootWindowList root_windows = Shell::GetAllRootWindows();
aura::Env* env = aura::Env::GetInstance();
// Test on 1st display.
root_windows[0]->MoveCursorTo(gfx::Point(150, 50));
EXPECT_EQ("150,50", env->last_mouse_location().ToString());
UpdateDisplay("300x200/r,200x150");
EXPECT_EQ("50,149", env->last_mouse_location().ToString());
// Test on 2nd display.
root_windows[1]->MoveCursorTo(gfx::Point(50, 100));
EXPECT_EQ("250,100", env->last_mouse_location().ToString());
UpdateDisplay("300x200/r,200x150/l");
EXPECT_EQ("249,50", env->last_mouse_location().ToString());
// Make sure just zooming will not change native location.
UpdateDisplay("600x400*2,400x300");
// Test on 1st display.
root_windows[0]->MoveCursorTo(gfx::Point(100, 150));
EXPECT_EQ("100,150", env->last_mouse_location().ToString());
UpdateDisplay("600x400*2@1.5,400x300");
EXPECT_EQ("150,225", env->last_mouse_location().ToString());
// Test on 2nd display.
UpdateDisplay("600x400,400x300*2");
root_windows[1]->MoveCursorTo(gfx::Point(100, 50));
EXPECT_EQ("700,50", env->last_mouse_location().ToString());
UpdateDisplay("600x400,400x300*2@1.5");
EXPECT_EQ("750,75", env->last_mouse_location().ToString());
}
} // namespace internal } // namespace internal
} // namespace ash } // namespace ash
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment