diff options
author | mazda@chromium.org <mazda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-06 23:03:42 +0000 |
---|---|---|
committer | mazda@chromium.org <mazda@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-12-06 23:03:42 +0000 |
commit | 309d43a835d5cee3d197e6a463191cb75dbd7833 (patch) | |
tree | 6d4ad1ac00946764f6ce0ad8de57ff0bc4dabfae /ash | |
parent | 19646afca54936d548c7d520aa78211d22d036df (diff) | |
download | chromium_src-309d43a835d5cee3d197e6a463191cb75dbd7833.zip chromium_src-309d43a835d5cee3d197e6a463191cb75dbd7833.tar.gz chromium_src-309d43a835d5cee3d197e6a463191cb75dbd7833.tar.bz2 |
Extract the code for supporing extended desktop from WorkspaceWindowResizer into DragWindowResizer.
DragWindowResizer decorates another WindowResizer and adds the ability to
move a window across displays.
This CL depends on
https://codereview.chromium.org/11280283/.
BUG=156519
Review URL: https://chromiumcodereview.appspot.com/11411344
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@171624 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r-- | ash/ash.gyp | 3 | ||||
-rw-r--r-- | ash/display/mouse_cursor_event_filter.h | 4 | ||||
-rw-r--r-- | ash/wm/drag_window_controller.h | 2 | ||||
-rw-r--r-- | ash/wm/drag_window_resizer.cc | 196 | ||||
-rw-r--r-- | ash/wm/drag_window_resizer.h | 77 | ||||
-rw-r--r-- | ash/wm/drag_window_resizer_unittest.cc | 354 | ||||
-rw-r--r-- | ash/wm/window_resizer.h | 2 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_window_resizer.cc | 152 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_window_resizer.h | 35 | ||||
-rw-r--r-- | ash/wm/workspace/workspace_window_resizer_unittest.cc | 293 |
10 files changed, 656 insertions, 462 deletions
diff --git a/ash/ash.gyp b/ash/ash.gyp index d888b3f..69a4917 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp @@ -301,6 +301,8 @@ 'wm/dialog_frame_view.h', 'wm/drag_window_controller.cc', 'wm/drag_window_controller.h', + 'wm/drag_window_resizer.cc', + 'wm/drag_window_resizer.h', 'wm/event_client_impl.cc', 'wm/event_client_impl.h', 'wm/event_rewriter_event_filter.cc', @@ -566,6 +568,7 @@ 'wm/base_layout_manager_unittest.cc', 'wm/cursor_manager_unittest.cc', 'wm/custom_frame_view_ash_unittest.cc', + 'wm/drag_window_resizer_unittest.cc', 'wm/frame_painter_unittest.cc', 'wm/panel_layout_manager_unittest.cc', 'wm/power_button_controller_unittest.cc', diff --git a/ash/display/mouse_cursor_event_filter.h b/ash/display/mouse_cursor_event_filter.h index a1be91c..27835bb 100644 --- a/ash/display/mouse_cursor_event_filter.h +++ b/ash/display/mouse_cursor_event_filter.h @@ -61,8 +61,8 @@ class ASH_EXPORT MouseCursorEventFilter : public ui::EventHandler { FRIEND_TEST_ALL_PREFIXES(MouseCursorEventFilterTest, IndicatorBoundsTestOnTopBottom); FRIEND_TEST_ALL_PREFIXES(MouseCursorEventFilterTest, CursorDeviceScaleFactor); - FRIEND_TEST_ALL_PREFIXES(WorkspaceWindowResizerTest, WarpMousePointer); - FRIEND_TEST_ALL_PREFIXES(WorkspaceWindowResizerTest, CursorDeviceScaleFactor); + FRIEND_TEST_ALL_PREFIXES(DragWindowResizerTest, WarpMousePointer); + FRIEND_TEST_ALL_PREFIXES(DragWindowResizerTest, CursorDeviceScaleFactor); // Warps the mouse cursor to an alternate root window when the // |point_in_screen|, which is the location of the mouse cursor, diff --git a/ash/wm/drag_window_controller.h b/ash/wm/drag_window_controller.h index 41eebd9..08e115d 100644 --- a/ash/wm/drag_window_controller.h +++ b/ash/wm/drag_window_controller.h @@ -54,7 +54,7 @@ class ASH_EXPORT DragWindowController { void SetOpacity(float opacity); private: - FRIEND_TEST_ALL_PREFIXES(WorkspaceWindowResizerTest, DragWindowController); + FRIEND_TEST_ALL_PREFIXES(DragWindowResizerTest, DragWindowController); // Creates and shows the |drag_widget_| at |bounds|. // |layer| is shown on top of the drag window if it is non-NULL. diff --git a/ash/wm/drag_window_resizer.cc b/ash/wm/drag_window_resizer.cc new file mode 100644 index 0000000..cbe8fe4 --- /dev/null +++ b/ash/wm/drag_window_resizer.cc @@ -0,0 +1,196 @@ +// Copyright (c) 2012 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/wm/drag_window_resizer.h" + +#include "ash/display/mouse_cursor_event_filter.h" +#include "ash/screen_ash.h" +#include "ash/shell.h" +#include "ash/wm/coordinate_conversion.h" +#include "ash/wm/cursor_manager.h" +#include "ash/wm/drag_window_controller.h" +#include "ash/wm/property_util.h" +#include "ui/aura/client/aura_constants.h" +#include "ui/aura/env.h" +#include "ui/aura/root_window.h" +#include "ui/aura/window.h" +#include "ui/aura/window_delegate.h" +#include "ui/base/hit_test.h" +#include "ui/base/ui_base_types.h" +#include "ui/gfx/screen.h" + +namespace ash { +namespace internal { + +namespace { + +// The maximum opacity of the drag phantom window. +const float kMaxOpacity = 0.8f; + +// Returns true if Ash has more than one root window. +bool HasSecondaryRootWindow() { + return Shell::GetAllRootWindows().size() > 1; +} + +// When there are two root windows, returns one of the root windows which is not +// |root_window|. Returns NULL if only one root window exists. +aura::RootWindow* GetAnotherRootWindow(aura::RootWindow* root_window) { + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + if (root_windows.size() < 2) + return NULL; + DCHECK_EQ(2U, root_windows.size()); + if (root_windows[0] == root_window) + return root_windows[1]; + return root_windows[0]; +} + +} + +DragWindowResizer::~DragWindowResizer() { + Shell* shell = Shell::GetInstance(); + shell->mouse_cursor_filter()->set_mouse_warp_mode( + MouseCursorEventFilter::WARP_ALWAYS); + shell->mouse_cursor_filter()->HideSharedEdgeIndicator(); + + if (destroyed_) + *destroyed_ = true; +} + +// static +DragWindowResizer* DragWindowResizer::Create(WindowResizer* window_resizer, + aura::Window* window, + const gfx::Point& location, + int window_component) { + Details details(window, location, window_component); + return details.is_resizable ? + new DragWindowResizer(window_resizer, details) : NULL; +} + +void DragWindowResizer::Drag(const gfx::Point& location, int event_flags) { + bool destroyed = false; + destroyed_ = &destroyed; + window_resizer_->Drag(location, event_flags); + if (destroyed) + return; + destroyed_ = NULL; + last_mouse_location_ = location; + + // Show a phantom window for dragging in another root window. + if (HasSecondaryRootWindow()) { + gfx::Point location_in_screen = location; + wm::ConvertPointToScreen(GetTarget()->parent(), &location_in_screen); + const bool in_original_root = + wm::GetRootWindowAt(location_in_screen) == GetTarget()->GetRootWindow(); + UpdateDragWindow(GetTarget()->bounds(), in_original_root); + } else { + drag_window_controller_.reset(); + } +} + +void DragWindowResizer::CompleteDrag(int event_flags) { + window_resizer_->CompleteDrag(event_flags); + + GetTarget()->layer()->SetOpacity(details_.initial_opacity); + drag_window_controller_.reset(); + + // Check if the destination is another display. + gfx::Point last_mouse_location_in_screen = last_mouse_location_; + wm::ConvertPointToScreen(GetTarget()->parent(), + &last_mouse_location_in_screen); + gfx::Screen* screen = Shell::GetScreen(); + const gfx::Display dst_display = + screen->GetDisplayNearestPoint(last_mouse_location_in_screen); + + if (dst_display.id() != + screen->GetDisplayNearestWindow(GetTarget()->GetRootWindow()).id()) { + const gfx::Rect dst_bounds = + ScreenAsh::ConvertRectToScreen(GetTarget()->parent(), + GetTarget()->bounds()); + GetTarget()->SetBoundsInScreen(dst_bounds, dst_display); + } +} + +void DragWindowResizer::RevertDrag() { + window_resizer_->RevertDrag(); + + drag_window_controller_.reset(); + GetTarget()->layer()->SetOpacity(details_.initial_opacity); +} + +aura::Window* DragWindowResizer::GetTarget() { + return window_resizer_->GetTarget(); +} + +DragWindowResizer::DragWindowResizer(WindowResizer* window_resizer, + const Details& details) + : window_resizer_(window_resizer), + details_(details), + destroyed_(NULL) { + // The pointer should be confined in one display during resizing a window + // because the window cannot span two displays at the same time anyway. The + // exception is window/tab dragging operation. During that operation, + // |mouse_warp_mode_| should be set to WARP_DRAG so that the user could move a + // window/tab to another display. + MouseCursorEventFilter* mouse_cursor_filter = + Shell::GetInstance()->mouse_cursor_filter(); + mouse_cursor_filter->set_mouse_warp_mode( + ShouldAllowMouseWarp() ? + MouseCursorEventFilter::WARP_DRAG : MouseCursorEventFilter::WARP_NONE); + if (ShouldAllowMouseWarp()) { + mouse_cursor_filter->ShowSharedEdgeIndicator( + details.window->GetRootWindow()); + } +} + +void DragWindowResizer::UpdateDragWindow(const gfx::Rect& bounds, + bool in_original_root) { + if (details_.window_component != HTCAPTION || !ShouldAllowMouseWarp()) + return; + + // It's available. Show a phantom window on the display if needed. + aura::RootWindow* another_root = + GetAnotherRootWindow(GetTarget()->GetRootWindow()); + const gfx::Rect root_bounds_in_screen(another_root->GetBoundsInScreen()); + const gfx::Rect bounds_in_screen = + ScreenAsh::ConvertRectToScreen(GetTarget()->parent(), bounds); + gfx::Rect bounds_in_another_root = + gfx::IntersectRects(root_bounds_in_screen, bounds_in_screen); + const float fraction_in_another_window = + (bounds_in_another_root.width() * bounds_in_another_root.height()) / + static_cast<float>(bounds.width() * bounds.height()); + + if (fraction_in_another_window > 0) { + if (!drag_window_controller_.get()) { + drag_window_controller_.reset( + new DragWindowController(GetTarget())); + // Always show the drag phantom on the |another_root| window. + drag_window_controller_->SetDestinationDisplay( + Shell::GetScreen()->GetDisplayMatching( + another_root->GetBoundsInScreen())); + drag_window_controller_->Show(); + } else { + // No animation. + drag_window_controller_->SetBounds(bounds_in_screen); + } + const float phantom_opacity = + !in_original_root ? 1 : (kMaxOpacity * fraction_in_another_window); + const float window_opacity = + in_original_root ? 1 : (kMaxOpacity * (1 - fraction_in_another_window)); + drag_window_controller_->SetOpacity(phantom_opacity); + GetTarget()->layer()->SetOpacity(window_opacity); + } else { + drag_window_controller_.reset(); + GetTarget()->layer()->SetOpacity(1.0f); + } +} + +bool DragWindowResizer::ShouldAllowMouseWarp() { + return (details_.window_component == HTCAPTION) && + (GetTarget()->GetProperty(aura::client::kModalKey) == + ui::MODAL_TYPE_NONE) && + (GetTarget()->type() == aura::client::WINDOW_TYPE_NORMAL); +} + +} // namespace internal +} // namespace ash diff --git a/ash/wm/drag_window_resizer.h b/ash/wm/drag_window_resizer.h new file mode 100644 index 0000000..3705bac --- /dev/null +++ b/ash/wm/drag_window_resizer.h @@ -0,0 +1,77 @@ +// Copyright (c) 2012 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. + +#ifndef ASH_WM_DRAG_WINDOW_RESIZER_H_ +#define ASH_WM_DRAG_WINDOW_RESIZER_H_ + +#include "ash/wm/window_resizer.h" +#include "base/compiler_specific.h" +#include "base/gtest_prod_util.h" +#include "ui/gfx/point.h" + +namespace ash { +namespace internal { + +class DragWindowController; + +// DragWindowResizer is a decorator of WindowResizer and adds the ability to +// drag windows across displays. +class ASH_EXPORT DragWindowResizer : public WindowResizer { + public: + virtual ~DragWindowResizer(); + + // Creates a new DragWindowResizer. The caller takes ownership of the + // returned object. The ownership of |window_resizer| is taken by the + // returned object. Returns NULL if not resizable. + static DragWindowResizer* Create(WindowResizer* window_resizer, + aura::Window* window, + const gfx::Point& location, + int window_component); + + // WindowResizer overides: + virtual void Drag(const gfx::Point& location, int event_flags) OVERRIDE; + virtual void CompleteDrag(int event_flags) OVERRIDE; + virtual void RevertDrag() OVERRIDE; + virtual aura::Window* GetTarget() OVERRIDE; + + const gfx::Point& GetInitialLocationInParentForTest() const { + return details_.initial_location_in_parent; + } + + private: + FRIEND_TEST_ALL_PREFIXES(DragWindowResizerTest, DragWindowController); + + // Creates DragWindowResizer that adds the ability of dragging windows across + // displays to |window_resizer|. This object takes the ownership of + // |window_resizer|. + explicit DragWindowResizer(WindowResizer* window_resizer, + const Details& details); + + // Updates the bounds of the phantom window for window dragging. Set true on + // |in_original_root| if the pointer is still in |window()->GetRootWindow()|. + void UpdateDragWindow(const gfx::Rect& bounds, bool in_original_root); + + // Returns true if we should allow the mouse pointer to warp. + bool ShouldAllowMouseWarp(); + + scoped_ptr<WindowResizer> window_resizer_; + + // Shows a semi-transparent image of the window being dragged. + scoped_ptr<DragWindowController> drag_window_controller_; + + const Details details_; + + gfx::Point last_mouse_location_; + + // If non-NULL the destructor sets this to true. Used to determine if this has + // been deleted. + bool* destroyed_; + + DISALLOW_COPY_AND_ASSIGN(DragWindowResizer); +}; + +} // namespace internal +} // namespace aura + +#endif // ASH_WM_DRAG_WINDOW_RESIZER_H_ diff --git a/ash/wm/drag_window_resizer_unittest.cc b/ash/wm/drag_window_resizer_unittest.cc new file mode 100644 index 0000000..2877bc5 --- /dev/null +++ b/ash/wm/drag_window_resizer_unittest.cc @@ -0,0 +1,354 @@ +// Copyright (c) 2012 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/wm/drag_window_resizer.h" + +#include "ash/display/mouse_cursor_event_filter.h" +#include "ash/root_window_controller.h" +#include "ash/shell.h" +#include "ash/shell_window_ids.h" +#include "ash/test/ash_test_base.h" +#include "ash/test/cursor_manager_test_api.h" +#include "ash/wm/cursor_manager.h" +#include "ash/wm/drag_window_controller.h" +#include "ash/wm/shelf_layout_manager.h" +#include "base/stringprintf.h" +#include "ui/aura/root_window.h" +#include "ui/aura/test/test_window_delegate.h" +#include "ui/base/hit_test.h" +#include "ui/gfx/insets.h" +#include "ui/gfx/screen.h" +#include "ui/views/widget/widget.h" + +namespace ash { +namespace internal { +namespace { + +const int kRootHeight = 600; + +} // namespace + +class DragWindowResizerTest : public test::AshTestBase { + public: + DragWindowResizerTest() : window_(NULL) {} + virtual ~DragWindowResizerTest() {} + + virtual void SetUp() OVERRIDE { + AshTestBase::SetUp(); + UpdateDisplay(StringPrintf("800x%d", kRootHeight)); + + aura::RootWindow* root = Shell::GetPrimaryRootWindow(); + gfx::Rect root_bounds(root->bounds()); + EXPECT_EQ(kRootHeight, root_bounds.height()); + EXPECT_EQ(800, root_bounds.width()); + Shell::GetInstance()->SetDisplayWorkAreaInsets(root, gfx::Insets()); + window_.reset(new aura::Window(&delegate_)); + window_->SetType(aura::client::WINDOW_TYPE_NORMAL); + window_->Init(ui::LAYER_NOT_DRAWN); + SetDefaultParentByPrimaryRootWindow(window_.get()); + window_->set_id(1); + } + + virtual void TearDown() OVERRIDE { + window_.reset(); + AshTestBase::TearDown(); + } + + protected: + gfx::Point CalculateDragPoint(const DragWindowResizer& resizer, + int delta_x, + int delta_y) const { + gfx::Point location = resizer.GetInitialLocationInParentForTest(); + location.set_x(location.x() + delta_x); + location.set_y(location.y() + delta_y); + return location; + } + + internal::ShelfLayoutManager* shelf_layout_manager() { + return Shell::GetPrimaryRootWindowController()->shelf(); + } + + static DragWindowResizer* CreateDragWindowResizer( + aura::Window* window, + const gfx::Point& point_in_parent, + int window_component) { + return static_cast<DragWindowResizer*>(CreateWindowResizer( + window, point_in_parent, window_component).release()); + } + + aura::test::TestWindowDelegate delegate_; + scoped_ptr<aura::Window> window_; + + private: + DISALLOW_COPY_AND_ASSIGN(DragWindowResizerTest); +}; + +// Verifies a window can be moved from the primary display to another. +TEST_F(DragWindowResizerTest, WindowDragWithMultiDisplays) { + // The secondary display is logically on the right, but on the system (e.g. X) + // layer, it's below the primary one. See UpdateDisplay() in ash_test_base.cc. + UpdateDisplay("800x600,800x600"); + shelf_layout_manager()->LayoutShelf(); + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + ASSERT_EQ(2U, root_windows.size()); + + window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), + Shell::GetScreen()->GetPrimaryDisplay()); + EXPECT_EQ(root_windows[0], window_->GetRootWindow()); + { + // Grab (0, 0) of the window. + scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( + window_.get(), gfx::Point(), HTCAPTION)); + ASSERT_TRUE(resizer.get()); + // Drag the pointer to the right. Once it reaches the right edge of the + // primary display, it warps to the secondary. + resizer->Drag(CalculateDragPoint(*resizer, 800, 10), 0); + resizer->CompleteDrag(0); + // The whole window is on the secondary display now. The parent should be + // changed. + EXPECT_EQ(root_windows[1], window_->GetRootWindow()); + EXPECT_EQ("0,10 50x60", window_->bounds().ToString()); + } + + window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), + Shell::GetScreen()->GetPrimaryDisplay()); + EXPECT_EQ(root_windows[0], window_->GetRootWindow()); + { + // Grab (0, 0) of the window and move the pointer to (790, 10). + scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( + window_.get(), gfx::Point(), HTCAPTION)); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 790, 10), 0); + resizer->CompleteDrag(0); + // Since the pointer is still on the primary root window, the parent should + // not be changed. + EXPECT_EQ(root_windows[0], window_->GetRootWindow()); + EXPECT_EQ("790,10 50x60", window_->bounds().ToString()); + } + + window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), + Shell::GetScreen()->GetPrimaryDisplay()); + EXPECT_EQ(root_windows[0], window_->GetRootWindow()); + { + // Grab the top-right edge of the window and move the pointer to (0, 10) + // in the secondary root window's coordinates. + scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( + window_.get(), gfx::Point(49, 0), HTCAPTION)); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 751, 10), ui::EF_CONTROL_DOWN); + resizer->CompleteDrag(0); + // Since the pointer is on the secondary, the parent should be changed + // even though only small fraction of the window is within the secondary + // root window's bounds. + EXPECT_EQ(root_windows[1], window_->GetRootWindow()); + EXPECT_EQ("-49,10 50x60", window_->bounds().ToString()); + } +} + +// Verifies a window can be moved from the secondary display to primary. +TEST_F(DragWindowResizerTest, WindowDragWithMultiDisplaysRightToLeft) { + UpdateDisplay("800x600,800x600"); + shelf_layout_manager()->LayoutShelf(); + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + ASSERT_EQ(2U, root_windows.size()); + + window_->SetBoundsInScreen( + gfx::Rect(800, 00, 50, 60), + Shell::GetScreen()->GetDisplayNearestWindow(root_windows[1])); + EXPECT_EQ(root_windows[1], window_->GetRootWindow()); + { + // Grab (0, 0) of the window. + scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( + window_.get(), gfx::Point(), HTCAPTION)); + ASSERT_TRUE(resizer.get()); + // Move the mouse near the right edge, (798, 0), of the primary display. + resizer->Drag(CalculateDragPoint(*resizer, -2, 0), ui::EF_CONTROL_DOWN); + resizer->CompleteDrag(0); + EXPECT_EQ(root_windows[0], window_->GetRootWindow()); + EXPECT_EQ("798,0 50x60", window_->bounds().ToString()); + } +} + +// Verifies the drag window is shown correctly. +TEST_F(DragWindowResizerTest, DragWindowController) { + UpdateDisplay("800x600,800x600"); + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + ASSERT_EQ(2U, root_windows.size()); + + window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), + Shell::GetScreen()->GetPrimaryDisplay()); + EXPECT_EQ(root_windows[0], window_->GetRootWindow()); + EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); + { + scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( + window_.get(), gfx::Point(), HTCAPTION)); + ASSERT_TRUE(resizer.get()); + EXPECT_FALSE(resizer->drag_window_controller_.get()); + + // The pointer is inside the primary root. The drag window controller + // should be NULL. + resizer->Drag(CalculateDragPoint(*resizer, 10, 10), 0); + EXPECT_FALSE(resizer->drag_window_controller_.get()); + + // The window spans both root windows. + resizer->Drag(CalculateDragPoint(*resizer, 798, 10), 0); + DragWindowController* controller = + resizer->drag_window_controller_.get(); + ASSERT_TRUE(controller); + + ASSERT_TRUE(controller->drag_widget_); + ui::Layer* drag_layer = + controller->drag_widget_->GetNativeWindow()->layer(); + ASSERT_TRUE(drag_layer); + // Check if |resizer->layer_| is properly set to the drag widget. + const std::vector<ui::Layer*>& layers = drag_layer->children(); + EXPECT_FALSE(layers.empty()); + EXPECT_EQ(controller->layer_, layers.back()); + + // |window_| should be opaque since the pointer is still on the primary + // root window. The drag window should be semi-transparent. + EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); + ASSERT_TRUE(controller->drag_widget_); + EXPECT_GT(1.0f, drag_layer->opacity()); + + // Enter the pointer to the secondary display. + resizer->Drag(CalculateDragPoint(*resizer, 800, 10), 0); + controller = resizer->drag_window_controller_.get(); + ASSERT_TRUE(controller); + // |window_| should be transparent, and the drag window should be opaque. + EXPECT_GT(1.0f, window_->layer()->opacity()); + EXPECT_FLOAT_EQ(1.0f, drag_layer->opacity()); + + resizer->CompleteDrag(0); + EXPECT_EQ(root_windows[1], window_->GetRootWindow()); + EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); + } + + // Do the same test with RevertDrag(). + window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), + Shell::GetScreen()->GetPrimaryDisplay()); + EXPECT_EQ(root_windows[0], window_->GetRootWindow()); + EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); + { + scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( + window_.get(), gfx::Point(), HTCAPTION)); + ASSERT_TRUE(resizer.get()); + EXPECT_FALSE(resizer->drag_window_controller_.get()); + + resizer->Drag(CalculateDragPoint(*resizer, 0, 610), 0); + resizer->RevertDrag(); + EXPECT_EQ(root_windows[0], window_->GetRootWindow()); + EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); + } +} + +// Verifies if the resizer sets and resets +// MouseCursorEventFilter::mouse_warp_mode_ as expected. +TEST_F(DragWindowResizerTest, WarpMousePointer) { + MouseCursorEventFilter* event_filter = + Shell::GetInstance()->mouse_cursor_filter(); + ASSERT_TRUE(event_filter); + window_->SetBounds(gfx::Rect(0, 0, 50, 60)); + + EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, + event_filter->mouse_warp_mode_); + { + scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( + window_.get(), gfx::Point(), HTCAPTION)); + // While dragging a window, warp should be allowed. + EXPECT_EQ(MouseCursorEventFilter::WARP_DRAG, + event_filter->mouse_warp_mode_); + resizer->CompleteDrag(0); + } + EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, + event_filter->mouse_warp_mode_); + + { + scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( + window_.get(), gfx::Point(), HTCAPTION)); + EXPECT_EQ(MouseCursorEventFilter::WARP_DRAG, + event_filter->mouse_warp_mode_); + resizer->RevertDrag(); + } + EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, + event_filter->mouse_warp_mode_); + + { + scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( + window_.get(), gfx::Point(), HTRIGHT)); + // While resizing a window, warp should NOT be allowed. + EXPECT_EQ(MouseCursorEventFilter::WARP_NONE, + event_filter->mouse_warp_mode_); + resizer->CompleteDrag(0); + } + EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, + event_filter->mouse_warp_mode_); + + { + scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( + window_.get(), gfx::Point(), HTRIGHT)); + EXPECT_EQ(MouseCursorEventFilter::WARP_NONE, + event_filter->mouse_warp_mode_); + resizer->RevertDrag(); + } + EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, + event_filter->mouse_warp_mode_); +} + +// Verifies cursor's device scale factor is updated whe a window is moved across +// root windows with different device scale factors (http://crbug.com/154183). +TEST_F(DragWindowResizerTest, CursorDeviceScaleFactor) { + // The secondary display is logically on the right, but on the system (e.g. X) + // layer, it's below the primary one. See UpdateDisplay() in ash_test_base.cc. + UpdateDisplay("400x400,800x800*2"); + shelf_layout_manager()->LayoutShelf(); + Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); + ASSERT_EQ(2U, root_windows.size()); + + test::CursorManagerTestApi cursor_test_api( + Shell::GetInstance()->cursor_manager()); + MouseCursorEventFilter* event_filter = + Shell::GetInstance()->mouse_cursor_filter(); + // Move window from the root window with 1.0 device scale factor to the root + // window with 2.0 device scale factor. + { + window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), + Shell::GetScreen()->GetPrimaryDisplay()); + EXPECT_EQ(root_windows[0], window_->GetRootWindow()); + // Grab (0, 0) of the window. + scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( + window_.get(), gfx::Point(), HTCAPTION)); + EXPECT_EQ(1.0f, cursor_test_api.GetDeviceScaleFactor()); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0); + event_filter->WarpMouseCursorIfNecessary(root_windows[0], + gfx::Point(399, 200)); + EXPECT_EQ(2.0f, cursor_test_api.GetDeviceScaleFactor()); + resizer->CompleteDrag(0); + EXPECT_EQ(2.0f, cursor_test_api.GetDeviceScaleFactor()); + } + + // Move window from the root window with 2.0 device scale factor to the root + // window with 1.0 device scale factor. + { + window_->SetBoundsInScreen( + gfx::Rect(600, 0, 50, 60), + Shell::GetScreen()->GetDisplayNearestWindow(root_windows[1])); + EXPECT_EQ(root_windows[1], window_->GetRootWindow()); + // Grab (0, 0) of the window. + scoped_ptr<DragWindowResizer> resizer(CreateDragWindowResizer( + window_.get(), gfx::Point(), HTCAPTION)); + EXPECT_EQ(2.0f, cursor_test_api.GetDeviceScaleFactor()); + ASSERT_TRUE(resizer.get()); + resizer->Drag(CalculateDragPoint(*resizer, -200, 200), 0); + event_filter->WarpMouseCursorIfNecessary(root_windows[1], + gfx::Point(400, 200)); + EXPECT_EQ(1.0f, cursor_test_api.GetDeviceScaleFactor()); + resizer->CompleteDrag(0); + EXPECT_EQ(1.0f, cursor_test_api.GetDeviceScaleFactor()); + } +} + +} // namespace internal +} // namespace ash diff --git a/ash/wm/window_resizer.h b/ash/wm/window_resizer.h index d8c398f..bc46df8 100644 --- a/ash/wm/window_resizer.h +++ b/ash/wm/window_resizer.h @@ -124,7 +124,7 @@ class ASH_EXPORT WindowResizer { // Creates a WindowResizer for |window|. This can return a scoped_ptr // initialized with NULL if |window| should not be resized nor dragged. -scoped_ptr<WindowResizer> CreateWindowResizer( +ASH_EXPORT scoped_ptr<WindowResizer> CreateWindowResizer( aura::Window* window, const gfx::Point& point_in_parent, int window_component); diff --git a/ash/wm/workspace/workspace_window_resizer.cc b/ash/wm/workspace/workspace_window_resizer.cc index 76b8e5a..62ef772 100644 --- a/ash/wm/workspace/workspace_window_resizer.cc +++ b/ash/wm/workspace/workspace_window_resizer.cc @@ -10,14 +10,13 @@ #include <vector> #include "ash/display/display_controller.h" -#include "ash/display/mouse_cursor_event_filter.h" #include "ash/screen_ash.h" #include "ash/shell.h" #include "ash/shell_window_ids.h" #include "ash/wm/coordinate_conversion.h" #include "ash/wm/cursor_manager.h" #include "ash/wm/default_window_resizer.h" -#include "ash/wm/drag_window_controller.h" +#include "ash/wm/drag_window_resizer.h" #include "ash/wm/property_util.h" #include "ash/wm/window_util.h" #include "ash/wm/workspace/phantom_window_controller.h" @@ -41,6 +40,7 @@ scoped_ptr<WindowResizer> CreateWindowResizer(aura::Window* window, if (!wm::CanResizeWindow(window) && window_component != HTCAPTION) return scoped_ptr<WindowResizer>(); + WindowResizer* window_resizer = NULL; if (window->parent() && window->parent()->id() == internal::kShellWindowId_WorkspaceContainer) { // Allow dragging maximized windows if it's not tracked by workspace. This @@ -48,19 +48,20 @@ scoped_ptr<WindowResizer> CreateWindowResizer(aura::Window* window, if (!wm::IsWindowNormal(window) && (window_component != HTCAPTION || GetTrackedByWorkspace(window))) return scoped_ptr<WindowResizer>(); - return make_scoped_ptr<WindowResizer>( - internal::WorkspaceWindowResizer::Create(window, - point_in_parent, - window_component, - std::vector<aura::Window*>())); - } else if (wm::IsWindowNormal(window)) { - return make_scoped_ptr<WindowResizer>(DefaultWindowResizer::Create( + window_resizer = internal::WorkspaceWindowResizer::Create( window, point_in_parent, - window_component)); - } else { - return scoped_ptr<WindowResizer>(); + window_component, + std::vector<aura::Window*>()); + } else if (wm::IsWindowNormal(window)) { + window_resizer = DefaultWindowResizer::Create( + window, point_in_parent, window_component); + } + if (window_resizer) { + window_resizer = internal::DragWindowResizer::Create( + window_resizer, window, point_in_parent, window_component); } + return make_scoped_ptr<WindowResizer>(window_resizer); } namespace internal { @@ -70,32 +71,12 @@ namespace { // Duration of the animation when snapping the window into place. const int kSnapDurationMS = 100; -// The maximum opacity of the drag phantom window. -const float kMaxOpacity = 0.8f; - // Returns true if should snap to the edge. bool ShouldSnapToEdge(int distance_from_edge, int grid_size) { return distance_from_edge < grid_size && distance_from_edge > -grid_size * 2; } -// Returns true if Ash has more than one root window. -bool HasSecondaryRootWindow() { - return Shell::GetAllRootWindows().size() > 1; -} - -// When there are two root windows, returns one of the root windows which is not -// |root_window|. Returns NULL if only one root window exists. -aura::RootWindow* GetAnotherRootWindow(aura::RootWindow* root_window) { - Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); - if (root_windows.size() < 2) - return NULL; - DCHECK_EQ(2U, root_windows.size()); - if (root_windows[0] == root_window) - return root_windows[1]; - return root_windows[0]; -} - // Returns the coordinate along the secondary axis to snap to. int CoordinateAlongSecondaryAxis(SecondaryMagnetismEdge edge, int leading, @@ -307,13 +288,7 @@ class WindowSize { WorkspaceWindowResizer::~WorkspaceWindowResizer() { Shell* shell = Shell::GetInstance(); - shell->mouse_cursor_filter()->set_mouse_warp_mode( - MouseCursorEventFilter::WARP_ALWAYS); - shell->mouse_cursor_filter()->HideSharedEdgeIndicator(); shell->cursor_manager()->UnlockCursor(); - - if (destroyed_) - *destroyed_ = true; } // static @@ -362,26 +337,12 @@ void WorkspaceWindowResizer::Drag(const gfx::Point& location_in_parent, if (!attached_windows_.empty()) LayoutAttachedWindows(&bounds); - if (bounds != window()->bounds()) { - bool destroyed = false; - destroyed_ = &destroyed; + if (bounds != window()->bounds()) window()->SetBounds(bounds); - if (destroyed) - return; - destroyed_ = NULL; - } - // Show a phantom window for dragging in another root window. - if (HasSecondaryRootWindow()) - UpdateDragWindow(bounds, in_original_root); - else - drag_window_controller_.reset(); - } void WorkspaceWindowResizer::CompleteDrag(int event_flags) { wm::SetUserHasChangedWindowPositionOrSize(details_.window, true); - window()->layer()->SetOpacity(details_.initial_opacity); - drag_window_controller_.reset(); snap_phantom_window_controller_.reset(); if (!did_move_or_resize_ || details_.window_component != HTCAPTION) return; @@ -403,29 +364,10 @@ void WorkspaceWindowResizer::CompleteDrag(int event_flags) { window()->SetBounds(snap_sizer_->target_bounds()); return; } - gfx::Rect bounds(GetFinalBounds(window()->bounds())); - - // Check if the destination is another display. - gfx::Point last_mouse_location_in_screen = last_mouse_location_; - wm::ConvertPointToScreen(window()->parent(), &last_mouse_location_in_screen); - gfx::Screen* screen = Shell::GetScreen(); - const gfx::Display dst_display = - screen->GetDisplayNearestPoint(last_mouse_location_in_screen); - - if (dst_display.id() != - screen->GetDisplayNearestWindow(window()->GetRootWindow()).id()) { - // Don't animate when moving to another display. - const gfx::Rect dst_bounds = - ScreenAsh::ConvertRectToScreen(window()->parent(), bounds); - window()->SetBoundsInScreen(dst_bounds, dst_display); - } } void WorkspaceWindowResizer::RevertDrag() { - window()->layer()->SetOpacity(details_.initial_opacity); - drag_window_controller_.reset(); snap_phantom_window_controller_.reset(); - Shell::GetInstance()->mouse_cursor_filter()->HideSharedEdgeIndicator(); if (!did_move_or_resize_) return; @@ -469,27 +411,12 @@ WorkspaceWindowResizer::WorkspaceWindowResizer( total_initial_size_(0), snap_type_(SNAP_NONE), num_mouse_moves_since_bounds_change_(0), - destroyed_(NULL), magnetism_window_(NULL) { DCHECK(details_.is_resizable); Shell* shell = Shell::GetInstance(); shell->cursor_manager()->LockCursor(); - // The pointer should be confined in one display during resizing a window - // because the window cannot span two displays at the same time anyway. The - // exception is window/tab dragging operation. During that operation, - // |mouse_warp_mode_| should be set to WARP_DRAG so that the user could move a - // window/tab to another display. - MouseCursorEventFilter* mouse_cursor_filter = shell->mouse_cursor_filter(); - mouse_cursor_filter->set_mouse_warp_mode( - ShouldAllowMouseWarp() ? - MouseCursorEventFilter::WARP_DRAG : MouseCursorEventFilter::WARP_NONE); - if (ShouldAllowMouseWarp()) { - mouse_cursor_filter->ShowSharedEdgeIndicator( - details.window->GetRootWindow()); - } - // Only support attaching to the right/bottom. DCHECK(attached_windows_.empty() || (details.window_component == HTRIGHT || @@ -823,51 +750,6 @@ int WorkspaceWindowResizer::PrimaryAxisCoordinate(int x, int y) const { return 0; } -void WorkspaceWindowResizer::UpdateDragWindow(const gfx::Rect& bounds, - bool in_original_root) { - if (!did_move_or_resize_ || details_.window_component != HTCAPTION || - !ShouldAllowMouseWarp()) { - return; - } - - // It's available. Show a phantom window on the display if needed. - aura::RootWindow* another_root = - GetAnotherRootWindow(window()->GetRootWindow()); - const gfx::Rect root_bounds_in_screen(another_root->GetBoundsInScreen()); - const gfx::Rect bounds_in_screen = - ScreenAsh::ConvertRectToScreen(window()->parent(), bounds); - gfx::Rect bounds_in_another_root = - gfx::IntersectRects(root_bounds_in_screen, bounds_in_screen); - - const float fraction_in_another_window = - (bounds_in_another_root.width() * bounds_in_another_root.height()) / - static_cast<float>(bounds.width() * bounds.height()); - const float phantom_opacity = - !in_original_root ? 1 : (kMaxOpacity * fraction_in_another_window); - const float window_opacity = - in_original_root ? 1 : (kMaxOpacity * (1 - fraction_in_another_window)); - - if (fraction_in_another_window > 0) { - if (!drag_window_controller_.get()) { - drag_window_controller_.reset( - new DragWindowController(window())); - // Always show the drag phantom on the |another_root| window. - drag_window_controller_->SetDestinationDisplay( - Shell::GetScreen()->GetDisplayMatching( - another_root->GetBoundsInScreen())); - drag_window_controller_->Show(); - } else { - // No animation. - drag_window_controller_->SetBounds(bounds_in_screen); - } - drag_window_controller_->SetOpacity(phantom_opacity); - window()->layer()->SetOpacity(window_opacity); - } else { - drag_window_controller_.reset(); - window()->layer()->SetOpacity(1.0f); - } -} - void WorkspaceWindowResizer::UpdateSnapPhantomWindow(const gfx::Point& location, const gfx::Rect& bounds) { if (!did_move_or_resize_ || details_.window_component != HTCAPTION) @@ -945,11 +827,5 @@ WorkspaceWindowResizer::SnapType WorkspaceWindowResizer::GetSnapType( return SNAP_NONE; } -bool WorkspaceWindowResizer::ShouldAllowMouseWarp() const { - return (details_.window_component == HTCAPTION) && - (window()->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_NONE) && - (window()->type() == aura::client::WINDOW_TYPE_NORMAL); -} - } // namespace internal } // namespace ash diff --git a/ash/wm/workspace/workspace_window_resizer.h b/ash/wm/workspace/workspace_window_resizer.h index f234a9e..4c71285 100644 --- a/ash/wm/workspace/workspace_window_resizer.h +++ b/ash/wm/workspace/workspace_window_resizer.h @@ -14,18 +14,9 @@ #include "base/memory/scoped_ptr.h" #include "ui/aura/window_tracker.h" -namespace aura { -class RootWindow; -} // namespace aura - -namespace ui { -class Layer; -} // namespace ui - namespace ash { namespace internal { -class DragWindowController; class PhantomWindowController; class SnapSizer; class WindowSize; @@ -58,13 +49,6 @@ class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer { int window_component, const std::vector<aura::Window*>& attached_windows); - // Returns true if the drag will result in changing the window in anyway. - bool is_resizable() const { return details_.is_resizable; } - - const gfx::Point& initial_location_in_parent() const { - return details_.initial_location_in_parent; - } - // Overridden from WindowResizer: virtual void Drag(const gfx::Point& location_in_parent, int event_flags) OVERRIDE; @@ -72,12 +56,15 @@ class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer { virtual void RevertDrag() OVERRIDE; virtual aura::Window* GetTarget() OVERRIDE; + const gfx::Point& GetInitialLocationInParentForTest() const { + return details_.initial_location_in_parent; + } + private: WorkspaceWindowResizer(const Details& details, const std::vector<aura::Window*>& attached_windows); private: - FRIEND_TEST_ALL_PREFIXES(WorkspaceWindowResizerTest, DragWindowController); FRIEND_TEST_ALL_PREFIXES(WorkspaceWindowResizerTest, CancelSnapPhantom); FRIEND_TEST_ALL_PREFIXES(WorkspaceWindowResizerTest, PhantomSnapMaxSize); @@ -167,10 +154,6 @@ class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer { void UpdateSnapPhantomWindow(const gfx::Point& location, const gfx::Rect& bounds); - // Updates the bounds of the phantom window for window dragging. Set true on - // |in_original_root| if the pointer is still in |window()->GetRootWindow()|. - void UpdateDragWindow(const gfx::Rect& bounds, bool in_original_root); - // Restacks the windows z-order position so that one of the windows is at the // top of the z-order, and the rest directly underneath it. void RestackWindows(); @@ -179,9 +162,6 @@ class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer { // snapping should be used. SnapType GetSnapType(const gfx::Point& location) const; - // Returns true if we should allow the mouse pointer to warp. - bool ShouldAllowMouseWarp() const; - aura::Window* window() const { return details_.window; } const Details details_; @@ -205,9 +185,6 @@ class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer { // is a grid and the caption is being dragged. scoped_ptr<PhantomWindowController> snap_phantom_window_controller_; - // Shows a semi-transparent image of the window being dragged. - scoped_ptr<DragWindowController> drag_window_controller_; - // Used to determine the target position of a snap. scoped_ptr<SnapSizer> snap_sizer_; @@ -222,10 +199,6 @@ class ASH_EXPORT WorkspaceWindowResizer : public WindowResizer { // The mouse location passed to Drag(). gfx::Point last_mouse_location_; - // If non-NULL the destructor sets this to true. Used to determine if this has - // been deleted. - bool* destroyed_; - // Window the drag has magnetically attached to. aura::Window* magnetism_window_; diff --git a/ash/wm/workspace/workspace_window_resizer_unittest.cc b/ash/wm/workspace/workspace_window_resizer_unittest.cc index 8e9aac1..668db96 100644 --- a/ash/wm/workspace/workspace_window_resizer_unittest.cc +++ b/ash/wm/workspace/workspace_window_resizer_unittest.cc @@ -5,15 +5,11 @@ #include "ash/wm/workspace/workspace_window_resizer.h" #include "ash/display/display_controller.h" -#include "ash/display/mouse_cursor_event_filter.h" #include "ash/root_window_controller.h" #include "ash/screen_ash.h" #include "ash/shell.h" #include "ash/shell_window_ids.h" #include "ash/test/ash_test_base.h" -#include "ash/test/cursor_manager_test_api.h" -#include "ash/wm/cursor_manager.h" -#include "ash/wm/drag_window_controller.h" #include "ash/wm/property_util.h" #include "ash/wm/shelf_layout_manager.h" #include "ash/wm/window_util.h" @@ -135,7 +131,7 @@ class WorkspaceWindowResizerTest : public test::AshTestBase { gfx::Point CalculateDragPoint(const WorkspaceWindowResizer& resizer, int delta_x, int delta_y) const { - gfx::Point location = resizer.initial_location_in_parent(); + gfx::Point location = resizer.GetInitialLocationInParentForTest(); location.set_x(location.x() + delta_x); location.set_y(location.y() + delta_y); return location; @@ -521,170 +517,6 @@ TEST_F(WorkspaceWindowResizerTest, NonResizableWindows) { EXPECT_EQ("0,30 50x60", window_->bounds().ToString()); } -// Verifies a window can be moved from the primary display to another. -TEST_F(WorkspaceWindowResizerTest, WindowDragWithMultiDisplays) { - // The secondary display is logically on the right, but on the system (e.g. X) - // layer, it's below the primary one. See UpdateDisplay() in ash_test_base.cc. - UpdateDisplay("800x600,800x600"); - shelf_layout_manager()->LayoutShelf(); - Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); - ASSERT_EQ(2U, root_windows.size()); - - window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), - Shell::GetScreen()->GetPrimaryDisplay()); - EXPECT_EQ(root_windows[0], window_->GetRootWindow()); - { - // Grab (0, 0) of the window. - scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( - window_.get(), gfx::Point(), HTCAPTION, empty_windows())); - ASSERT_TRUE(resizer.get()); - // Drag the pointer to the right. Once it reaches the right edge of the - // primary display, it warps to the secondary. - resizer->Drag(CalculateDragPoint(*resizer, 800, 10), 0); - resizer->CompleteDrag(0); - // The whole window is on the secondary display now. The parent should be - // changed. - EXPECT_EQ(root_windows[1], window_->GetRootWindow()); - EXPECT_EQ("0,10 50x60", window_->bounds().ToString()); - } - - window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), - Shell::GetScreen()->GetPrimaryDisplay()); - EXPECT_EQ(root_windows[0], window_->GetRootWindow()); - { - // Grab (0, 0) of the window and move the pointer to (790, 10). - scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( - window_.get(), gfx::Point(), HTCAPTION, empty_windows())); - ASSERT_TRUE(resizer.get()); - resizer->Drag(CalculateDragPoint(*resizer, 790, 10), 0); - resizer->CompleteDrag(0); - // Since the pointer is still on the primary root window, the parent should - // not be changed. - EXPECT_EQ(root_windows[0], window_->GetRootWindow()); - EXPECT_EQ("790,10 50x60", window_->bounds().ToString()); - } - - window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), - Shell::GetScreen()->GetPrimaryDisplay()); - EXPECT_EQ(root_windows[0], window_->GetRootWindow()); - { - // Grab the top-right edge of the window and move the pointer to (0, 10) - // in the secondary root window's coordinates. - scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( - window_.get(), gfx::Point(49, 0), HTCAPTION, empty_windows())); - ASSERT_TRUE(resizer.get()); - resizer->Drag(CalculateDragPoint(*resizer, 751, 10), ui::EF_CONTROL_DOWN); - resizer->CompleteDrag(0); - // Since the pointer is on the secondary, the parent should be changed - // even though only small fraction of the window is within the secondary - // root window's bounds. - EXPECT_EQ(root_windows[1], window_->GetRootWindow()); - EXPECT_EQ("-49,10 50x60", window_->bounds().ToString()); - } -} - -// Verifies a window can be moved from the secondary display to primary. -TEST_F(WorkspaceWindowResizerTest, - WindowDragWithMultiDisplaysRightToLeft) { - UpdateDisplay("800x600,800x600"); - shelf_layout_manager()->LayoutShelf(); - Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); - ASSERT_EQ(2U, root_windows.size()); - - window_->SetBoundsInScreen( - gfx::Rect(800, 00, 50, 60), - Shell::GetScreen()->GetDisplayNearestWindow(root_windows[1])); - EXPECT_EQ(root_windows[1], window_->GetRootWindow()); - { - // Grab (0, 0) of the window. - scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( - window_.get(), gfx::Point(), HTCAPTION, empty_windows())); - ASSERT_TRUE(resizer.get()); - // Move the mouse near the right edge, (798, 0), of the primary display. - resizer->Drag(CalculateDragPoint(*resizer, -2, 0), ui::EF_CONTROL_DOWN); - resizer->CompleteDrag(0); - EXPECT_EQ(root_windows[0], window_->GetRootWindow()); - EXPECT_EQ("798,0 50x60", window_->bounds().ToString()); - } -} - -// Verifies the drag window controller is instanciated appropriately. -TEST_F(WorkspaceWindowResizerTest, DragWindowController) { - UpdateDisplay("800x600,800x600"); - Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); - ASSERT_EQ(2U, root_windows.size()); - - window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), - Shell::GetScreen()->GetPrimaryDisplay()); - EXPECT_EQ(root_windows[0], window_->GetRootWindow()); - EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); - { - scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( - window_.get(), gfx::Point(), HTCAPTION, empty_windows())); - ASSERT_TRUE(resizer.get()); - EXPECT_FALSE(resizer->snap_phantom_window_controller_.get()); - EXPECT_FALSE(resizer->drag_window_controller_.get()); - - // The pointer is inside the primary root. Both phantoms should be NULL. - resizer->Drag(CalculateDragPoint(*resizer, 10, 10), 0); - EXPECT_FALSE(resizer->snap_phantom_window_controller_.get()); - EXPECT_FALSE(resizer->drag_window_controller_.get()); - - // The window spans both root windows. - resizer->Drag(CalculateDragPoint(*resizer, 798, 10), 0); - EXPECT_FALSE(resizer->snap_phantom_window_controller_.get()); - DragWindowController* controller = - resizer->drag_window_controller_.get(); - ASSERT_TRUE(controller); - ASSERT_TRUE(controller->drag_widget_); - ui::Layer* drag_layer = - controller->drag_widget_->GetNativeWindow()->layer(); - ASSERT_TRUE(drag_layer); - - // Check if |resizer->layer_| is properly set to the phantom widget. - const std::vector<ui::Layer*>& layers = drag_layer->children(); - EXPECT_FALSE(layers.empty()); - EXPECT_EQ(controller->layer_, layers.back()); - - // |window_| should be opaque since the pointer is still on the primary - // root window. The phantom should be semi-transparent. - EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); - EXPECT_GT(1.0f, drag_layer->opacity()); - - // Enter the pointer to the secondary display. - resizer->Drag(CalculateDragPoint(*resizer, 800, 10), 0); - EXPECT_FALSE(resizer->snap_phantom_window_controller_.get()); - controller = resizer->drag_window_controller_.get(); - ASSERT_TRUE(controller); - // |window_| should be transparent, and the phantom should be opaque. - EXPECT_GT(1.0f, window_->layer()->opacity()); - EXPECT_FLOAT_EQ(1.0f, drag_layer->opacity()); - - resizer->CompleteDrag(0); - EXPECT_EQ(root_windows[1], window_->GetRootWindow()); - EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); - } - - // Do the same test with RevertDrag(). - window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), - Shell::GetScreen()->GetPrimaryDisplay()); - EXPECT_EQ(root_windows[0], window_->GetRootWindow()); - EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); - { - scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( - window_.get(), gfx::Point(), HTCAPTION, empty_windows())); - ASSERT_TRUE(resizer.get()); - EXPECT_FALSE(resizer->snap_phantom_window_controller_.get()); - EXPECT_FALSE(resizer->drag_window_controller_.get()); - - resizer->Drag(CalculateDragPoint(*resizer, 0, 610), 0); - resizer->RevertDrag(); - EXPECT_EQ(root_windows[0], window_->GetRootWindow()); - EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); - } -} - -// Verifies the style of the drag phantom window is correct. TEST_F(WorkspaceWindowResizerTest, CancelSnapPhantom) { UpdateDisplay("800x600,800x600"); Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); @@ -699,82 +531,19 @@ TEST_F(WorkspaceWindowResizerTest, CancelSnapPhantom) { window_.get(), gfx::Point(), HTCAPTION, empty_windows())); ASSERT_TRUE(resizer.get()); EXPECT_FALSE(resizer->snap_phantom_window_controller_.get()); - EXPECT_FALSE(resizer->drag_window_controller_.get()); - EXPECT_EQ(WorkspaceWindowResizer::SNAP_NONE, resizer->snap_type_); - // The pointer is on the edge but not shared. Both controllers should be - // non-NULL. + // The pointer is on the edge but not shared. The snap phantom window + // controller should be non-NULL. resizer->Drag(CalculateDragPoint(*resizer, 799, 0), 0); EXPECT_TRUE(resizer->snap_phantom_window_controller_.get()); - EXPECT_EQ(WorkspaceWindowResizer::SNAP_RIGHT_EDGE, resizer->snap_type_); - DragWindowController* controller = - resizer->drag_window_controller_.get(); - ASSERT_TRUE(controller); - // Move the cursor across the edge. Now the snap phantom controller + // Move the cursor across the edge. Now the snap phantom window controller // should be canceled. resizer->Drag(CalculateDragPoint(*resizer, 800, 0), 0); EXPECT_FALSE(resizer->snap_phantom_window_controller_.get()); - EXPECT_EQ(WorkspaceWindowResizer::SNAP_NONE, resizer->snap_type_); - controller = - resizer->drag_window_controller_.get(); - ASSERT_TRUE(controller); } } -// Verifies if the resizer sets and resets -// MouseCursorEventFilter::mouse_warp_mode_ as expected. -TEST_F(WorkspaceWindowResizerTest, WarpMousePointer) { - MouseCursorEventFilter* event_filter = - Shell::GetInstance()->mouse_cursor_filter(); - ASSERT_TRUE(event_filter); - window_->SetBounds(gfx::Rect(0, 0, 50, 60)); - - EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, - event_filter->mouse_warp_mode_); - { - scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( - window_.get(), gfx::Point(), HTCAPTION, empty_windows())); - // While dragging a window, warp should be allowed. - EXPECT_EQ(MouseCursorEventFilter::WARP_DRAG, - event_filter->mouse_warp_mode_); - resizer->CompleteDrag(0); - } - EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, - event_filter->mouse_warp_mode_); - - { - scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( - window_.get(), gfx::Point(), HTCAPTION, empty_windows())); - EXPECT_EQ(MouseCursorEventFilter::WARP_DRAG, - event_filter->mouse_warp_mode_); - resizer->RevertDrag(); - } - EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, - event_filter->mouse_warp_mode_); - - { - scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( - window_.get(), gfx::Point(), HTRIGHT, empty_windows())); - // While resizing a window, warp should NOT be allowed. - EXPECT_EQ(MouseCursorEventFilter::WARP_NONE, - event_filter->mouse_warp_mode_); - resizer->CompleteDrag(0); - } - EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, - event_filter->mouse_warp_mode_); - - { - scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( - window_.get(), gfx::Point(), HTRIGHT, empty_windows())); - EXPECT_EQ(MouseCursorEventFilter::WARP_NONE, - event_filter->mouse_warp_mode_); - resizer->RevertDrag(); - } - EXPECT_EQ(MouseCursorEventFilter::WARP_ALWAYS, - event_filter->mouse_warp_mode_); -} - // Verifies windows are correctly restacked when reordering multiple windows. TEST_F(WorkspaceWindowResizerTest, RestackAttached) { window_->SetBounds(gfx::Rect( 0, 0, 200, 300)); @@ -1369,60 +1138,6 @@ TEST_F(WorkspaceWindowResizerTest, MagneticallyResize_LEFT) { EXPECT_EQ("99,200 21x30", window_->bounds().ToString()); } -// Verifies cursor's device scale factor is updated whe a window is moved across -// root windows with different device scale factors (http://crbug.com/154183). -TEST_F(WorkspaceWindowResizerTest, CursorDeviceScaleFactor) { - // The secondary display is logically on the right, but on the system (e.g. X) - // layer, it's below the primary one. See UpdateDisplay() in ash_test_base.cc. - UpdateDisplay("400x400,800x800*2"); - shelf_layout_manager()->LayoutShelf(); - Shell::RootWindowList root_windows = Shell::GetAllRootWindows(); - ASSERT_EQ(2U, root_windows.size()); - - test::CursorManagerTestApi cursor_test_api( - Shell::GetInstance()->cursor_manager()); - MouseCursorEventFilter* event_filter = - Shell::GetInstance()->mouse_cursor_filter(); - // Move window from the root window with 1.0 device scale factor to the root - // window with 2.0 device scale factor. - { - window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), - Shell::GetScreen()->GetPrimaryDisplay()); - EXPECT_EQ(root_windows[0], window_->GetRootWindow()); - // Grab (0, 0) of the window. - scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( - window_.get(), gfx::Point(), HTCAPTION, empty_windows())); - EXPECT_EQ(1.0f, cursor_test_api.GetDeviceScaleFactor()); - ASSERT_TRUE(resizer.get()); - resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0); - event_filter->WarpMouseCursorIfNecessary(root_windows[0], - gfx::Point(399, 200)); - EXPECT_EQ(2.0f, cursor_test_api.GetDeviceScaleFactor()); - resizer->CompleteDrag(0); - EXPECT_EQ(2.0f, cursor_test_api.GetDeviceScaleFactor()); - } - - // Move window from the root window with 2.0 device scale factor to the root - // window with 1.0 device scale factor. - { - window_->SetBoundsInScreen( - gfx::Rect(600, 0, 50, 60), - Shell::GetScreen()->GetDisplayNearestWindow(root_windows[1])); - EXPECT_EQ(root_windows[1], window_->GetRootWindow()); - // Grab (0, 0) of the window. - scoped_ptr<WorkspaceWindowResizer> resizer(WorkspaceWindowResizer::Create( - window_.get(), gfx::Point(), HTCAPTION, empty_windows())); - EXPECT_EQ(2.0f, cursor_test_api.GetDeviceScaleFactor()); - ASSERT_TRUE(resizer.get()); - resizer->Drag(CalculateDragPoint(*resizer, -200, 200), 0); - event_filter->WarpMouseCursorIfNecessary(root_windows[1], - gfx::Point(400, 200)); - EXPECT_EQ(1.0f, cursor_test_api.GetDeviceScaleFactor()); - resizer->CompleteDrag(0); - EXPECT_EQ(1.0f, cursor_test_api.GetDeviceScaleFactor()); - } -} - // Test that the user user moved window flag is getting properly set. TEST_F(WorkspaceWindowResizerTest, CheckUserWindowMangedFlags) { window_->SetBounds(gfx::Rect( 0, 50, 400, 200)); |