| // 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/public/cpp/shell_window_ids.h" |
| #include "ash/root_window_controller.h" |
| #include "ash/shelf/shelf_layout_manager.h" |
| #include "ash/shell.h" |
| #include "ash/test/ash_test_base.h" |
| #include "ash/wm/cursor_manager_test_api.h" |
| #include "ash/wm/drag_window_controller.h" |
| #include "ash/wm/window_positioning_utils.h" |
| #include "ash/wm/window_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/test/test_window_delegate.h" |
| #include "ui/base/hit_test.h" |
| #include "ui/base/ui_base_types.h" |
| #include "ui/compositor/layer_delegate.h" |
| #include "ui/compositor/layer_tree_owner.h" |
| #include "ui/display/display_layout.h" |
| #include "ui/display/display_layout_builder.h" |
| #include "ui/display/manager/display_manager.h" |
| #include "ui/gfx/geometry/insets.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/wm/core/window_util.h" |
| |
| namespace ash { |
| namespace { |
| |
| const int kRootHeight = 600; |
| |
| // Used to test if the OnPaintLayer is called by DragWindowLayerDelegate. |
| class TestLayerDelegate : public ui::LayerDelegate { |
| public: |
| TestLayerDelegate() = default; |
| ~TestLayerDelegate() override = default; |
| |
| int paint_count() const { return paint_count_; } |
| |
| private: |
| // Paint content for the layer to the specified context. |
| void OnPaintLayer(const ui::PaintContext& context) override { |
| paint_count_++; |
| } |
| void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} |
| void OnDeviceScaleFactorChanged(float device_scale_factor) override {} |
| |
| int paint_count_ = 0; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestLayerDelegate); |
| }; |
| |
| } // namespace |
| |
| class DragWindowResizerTest : public AshTestBase { |
| public: |
| DragWindowResizerTest() : transient_child_(nullptr) {} |
| ~DragWindowResizerTest() override {} |
| |
| void SetUp() override { |
| AshTestBase::SetUp(); |
| |
| UpdateDisplay(base::StringPrintf("800x%d", kRootHeight)); |
| |
| aura::Window* root = Shell::GetPrimaryRootWindow(); |
| gfx::Rect root_bounds(root->bounds()); |
| EXPECT_EQ(kRootHeight, root_bounds.height()); |
| EXPECT_EQ(800, root_bounds.width()); |
| window_.reset(new aura::Window(&delegate_)); |
| window_->SetType(aura::client::WINDOW_TYPE_NORMAL); |
| window_->Init(ui::LAYER_NOT_DRAWN); |
| ParentWindowInPrimaryRootWindow(window_.get()); |
| window_->set_id(1); |
| |
| always_on_top_window_.reset(new aura::Window(&delegate2_)); |
| always_on_top_window_->SetType(aura::client::WINDOW_TYPE_NORMAL); |
| always_on_top_window_->SetProperty(aura::client::kAlwaysOnTopKey, true); |
| always_on_top_window_->Init(ui::LAYER_NOT_DRAWN); |
| ParentWindowInPrimaryRootWindow(always_on_top_window_.get()); |
| always_on_top_window_->set_id(2); |
| |
| system_modal_window_.reset(new aura::Window(&delegate3_)); |
| system_modal_window_->SetType(aura::client::WINDOW_TYPE_NORMAL); |
| system_modal_window_->SetProperty(aura::client::kModalKey, |
| ui::MODAL_TYPE_SYSTEM); |
| system_modal_window_->Init(ui::LAYER_NOT_DRAWN); |
| ParentWindowInPrimaryRootWindow(system_modal_window_.get()); |
| system_modal_window_->set_id(3); |
| |
| transient_child_ = new aura::Window(&delegate4_); |
| transient_child_->SetType(aura::client::WINDOW_TYPE_NORMAL); |
| transient_child_->Init(ui::LAYER_NOT_DRAWN); |
| ParentWindowInPrimaryRootWindow(transient_child_); |
| transient_child_->set_id(4); |
| |
| transient_parent_.reset(new aura::Window(&delegate5_)); |
| transient_parent_->SetType(aura::client::WINDOW_TYPE_NORMAL); |
| transient_parent_->Init(ui::LAYER_NOT_DRAWN); |
| ParentWindowInPrimaryRootWindow(transient_parent_.get()); |
| ::wm::AddTransientChild(transient_parent_.get(), transient_child_); |
| transient_parent_->set_id(5); |
| |
| panel_window_.reset(new aura::Window(&delegate6_)); |
| panel_window_->SetType(aura::client::WINDOW_TYPE_PANEL); |
| panel_window_->Init(ui::LAYER_NOT_DRAWN); |
| ParentWindowInPrimaryRootWindow(panel_window_.get()); |
| } |
| |
| void TearDown() override { |
| window_.reset(); |
| always_on_top_window_.reset(); |
| system_modal_window_.reset(); |
| transient_parent_.reset(); |
| panel_window_.reset(); |
| AshTestBase::TearDown(); |
| } |
| |
| protected: |
| gfx::Point CalculateDragPoint(const WindowResizer& resizer, |
| int delta_x, |
| int delta_y) const { |
| gfx::Point location = resizer.GetInitialLocation(); |
| location.set_x(location.x() + delta_x); |
| location.set_y(location.y() + delta_y); |
| return location; |
| } |
| |
| ShelfLayoutManager* shelf_layout_manager() { |
| return Shell::GetPrimaryRootWindowController()->GetShelfLayoutManager(); |
| } |
| |
| static WindowResizer* CreateDragWindowResizer( |
| aura::Window* window, |
| const gfx::Point& point_in_parent, |
| int window_component) { |
| return CreateWindowResizer(window, point_in_parent, window_component, |
| ::wm::WINDOW_MOVE_SOURCE_MOUSE) |
| .release(); |
| } |
| |
| bool TestIfMouseWarpsAt(const gfx::Point& point_in_screen) { |
| return AshTestBase::TestIfMouseWarpsAt(GetEventGenerator(), |
| point_in_screen); |
| } |
| |
| aura::test::TestWindowDelegate delegate_; |
| aura::test::TestWindowDelegate delegate2_; |
| aura::test::TestWindowDelegate delegate3_; |
| aura::test::TestWindowDelegate delegate4_; |
| aura::test::TestWindowDelegate delegate5_; |
| aura::test::TestWindowDelegate delegate6_; |
| |
| std::unique_ptr<aura::Window> window_; |
| std::unique_ptr<aura::Window> always_on_top_window_; |
| std::unique_ptr<aura::Window> system_modal_window_; |
| std::unique_ptr<aura::Window> panel_window_; |
| aura::Window* transient_child_; |
| std::unique_ptr<aura::Window> transient_parent_; |
| |
| 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,400x300"); |
| aura::Window::Windows root_windows = Shell::GetAllRootWindows(); |
| ASSERT_EQ(2U, root_windows.size()); |
| |
| window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), |
| display::Screen::GetScreen()->GetPrimaryDisplay()); |
| EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| { |
| // Grab (0, 0) of the window. |
| std::unique_ptr<WindowResizer> 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(); |
| // 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), |
| display::Screen::GetScreen()->GetPrimaryDisplay()); |
| EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| { |
| // Grab (0, 0) of the window and move the pointer to (775, 10). |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window_.get(), gfx::Point(), HTCAPTION)); |
| ASSERT_TRUE(resizer.get()); |
| resizer->Drag(CalculateDragPoint(*resizer, 795, 10), 0); |
| // Window should be adjusted for minimum visibility (25px) during the drag. |
| EXPECT_EQ("775,10 50x60", window_->bounds().ToString()); |
| resizer->CompleteDrag(); |
| // Since the pointer is still on the primary root window, the parent should |
| // not be changed. |
| // Window origin should be adjusted for minimum visibility (25px). |
| EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| EXPECT_EQ("775,10 50x60", window_->bounds().ToString()); |
| } |
| |
| window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), |
| display::Screen::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. |
| std::unique_ptr<WindowResizer> 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(); |
| // 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()); |
| // Window origin should be adjusted for minimum visibility (25px). |
| int expected_x = -50 + wm::kMinimumOnScreenArea; |
| |
| EXPECT_EQ(base::IntToString(expected_x) + ",10 50x60", |
| window_->bounds().ToString()); |
| } |
| // Dropping a window that is larger than the destination work area |
| // will shrink to fit to the work area. |
| window_->SetBoundsInScreen(gfx::Rect(0, 0, 700, 500), |
| display::Screen::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. |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window_.get(), gfx::Point(699, 0), HTCAPTION)); |
| ASSERT_TRUE(resizer.get()); |
| resizer->Drag(CalculateDragPoint(*resizer, 101, 10), ui::EF_CONTROL_DOWN); |
| resizer->CompleteDrag(); |
| EXPECT_EQ(root_windows[1], window_->GetRootWindow()); |
| // Window size should be adjusted to fit to the work area |
| EXPECT_EQ(gfx::Size(400, 252).ToString(), |
| window_->bounds().size().ToString()); |
| gfx::Rect window_bounds_in_screen = window_->GetBoundsInScreen(); |
| gfx::Rect intersect(window_->GetRootWindow()->GetBoundsInScreen()); |
| intersect.Intersect(window_bounds_in_screen); |
| |
| EXPECT_LE(10, intersect.width()); |
| EXPECT_LE(10, intersect.height()); |
| EXPECT_TRUE(window_bounds_in_screen.Contains(gfx::Point(800, 10))); |
| } |
| |
| // Dropping a window that is larger than the destination work area |
| // will shrink to fit to the work area. |
| window_->SetBoundsInScreen(gfx::Rect(0, 0, 700, 500), |
| display::Screen::GetScreen()->GetPrimaryDisplay()); |
| EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| { |
| // Grab the top-left edge of the window and move the pointer to (150, 10) |
| // in the secondary root window's coordinates. Make sure the window is |
| // shrink in such a way that it keeps the cursor within. |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window_.get(), gfx::Point(0, 0), HTCAPTION)); |
| ASSERT_TRUE(resizer.get()); |
| resizer->Drag(CalculateDragPoint(*resizer, 799, 10), ui::EF_CONTROL_DOWN); |
| resizer->Drag(CalculateDragPoint(*resizer, 850, 10), ui::EF_CONTROL_DOWN); |
| resizer->CompleteDrag(); |
| EXPECT_EQ(root_windows[1], window_->GetRootWindow()); |
| // Window size should be adjusted to fit to the work area |
| EXPECT_EQ(gfx::Size(400, 252).ToString(), |
| window_->bounds().size().ToString()); |
| gfx::Rect window_bounds_in_screen = window_->GetBoundsInScreen(); |
| gfx::Rect intersect(window_->GetRootWindow()->GetBoundsInScreen()); |
| intersect.Intersect(window_bounds_in_screen); |
| EXPECT_LE(10, intersect.width()); |
| EXPECT_LE(10, intersect.height()); |
| EXPECT_TRUE(window_bounds_in_screen.Contains(gfx::Point(850, 10))); |
| } |
| } |
| |
| // Verifies that dragging the active window to another display makes the new |
| // root window the active root window. |
| TEST_F(DragWindowResizerTest, WindowDragWithMultiDisplaysActiveRoot) { |
| // 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"); |
| aura::Window::Windows root_windows = Shell::GetAllRootWindows(); |
| ASSERT_EQ(2U, root_windows.size()); |
| |
| aura::test::TestWindowDelegate delegate; |
| std::unique_ptr<aura::Window> window(new aura::Window(&delegate)); |
| window->SetType(aura::client::WINDOW_TYPE_NORMAL); |
| window->Init(ui::LAYER_TEXTURED); |
| ParentWindowInPrimaryRootWindow(window.get()); |
| window->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), |
| display::Screen::GetScreen()->GetPrimaryDisplay()); |
| window->Show(); |
| EXPECT_TRUE(wm::CanActivateWindow(window.get())); |
| wm::ActivateWindow(window.get()); |
| EXPECT_EQ(root_windows[0], window->GetRootWindow()); |
| EXPECT_EQ(root_windows[0], Shell::GetRootWindowForNewWindows()); |
| { |
| // Grab (0, 0) of the window. |
| std::unique_ptr<WindowResizer> 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(); |
| // The whole window is on the secondary display now. The parent should be |
| // changed. |
| EXPECT_EQ(root_windows[1], window->GetRootWindow()); |
| EXPECT_EQ(root_windows[1], Shell::GetRootWindowForNewWindows()); |
| } |
| } |
| |
| // Verifies a window can be moved from the secondary display to primary. |
| TEST_F(DragWindowResizerTest, WindowDragWithMultiDisplaysRightToLeft) { |
| UpdateDisplay("800x600,800x600"); |
| aura::Window::Windows root_windows = Shell::GetAllRootWindows(); |
| ASSERT_EQ(2U, root_windows.size()); |
| |
| window_->SetBoundsInScreen( |
| gfx::Rect(800, 00, 50, 60), |
| display::Screen::GetScreen()->GetDisplayNearestWindow(root_windows[1])); |
| EXPECT_EQ(root_windows[1], window_->GetRootWindow()); |
| { |
| // Grab (0, 0) of the window. |
| std::unique_ptr<WindowResizer> 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(); |
| EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| // Window origin should be adjusted for minimum visibility (25px). |
| EXPECT_EQ("775,0 50x60", window_->bounds().ToString()); |
| } |
| } |
| |
| // Verifies the drag window is shown correctly. |
| TEST_F(DragWindowResizerTest, DragWindowController) { |
| UpdateDisplay("800x600,800x600"); |
| aura::Window::Windows root_windows = Shell::GetAllRootWindows(); |
| ASSERT_EQ(2U, root_windows.size()); |
| |
| TestLayerDelegate delegate; |
| window_->layer()->set_delegate(&delegate); |
| window_->SetBoundsInScreen(gfx::Rect(0, 0, 50, 60), |
| display::Screen::GetScreen()->GetPrimaryDisplay()); |
| EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); |
| { |
| // Hold the center of the window so that the window doesn't stick to the |
| // edge when dragging around the edge of the display. |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window_.get(), gfx::Point(25, 30), HTCAPTION)); |
| ASSERT_TRUE(resizer.get()); |
| DragWindowResizer* drag_resizer = DragWindowResizer::instance_; |
| ASSERT_TRUE(drag_resizer); |
| EXPECT_FALSE(drag_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); |
| DragWindowController* controller = |
| drag_resizer->drag_window_controller_.get(); |
| EXPECT_EQ(0, controller->GetDragWindowsCountForTest()); |
| |
| // The window spans both root windows. |
| resizer->Drag(CalculateDragPoint(*resizer, 773, 10), 0); |
| EXPECT_EQ(1, controller->GetDragWindowsCountForTest()); |
| const aura::Window* drag_window = controller->GetDragWindowForTest(0); |
| ASSERT_TRUE(drag_window); |
| |
| const ui::Layer* drag_layer = drag_window->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->GetDragLayerOwnerForTest(0)->root(), layers.back()); |
| |
| // The paint request on a drag window should reach the original delegate. |
| controller->RequestLayerPaintForTest(); |
| EXPECT_EQ(1, delegate.paint_count()); |
| |
| // Invalidating the delegate on the original layer should prevent |
| // calling the OnPaintLayer on the original delegate from new delegate. |
| window_->layer()->set_delegate(nullptr); |
| controller->RequestLayerPaintForTest(); |
| EXPECT_EQ(1, delegate.paint_count()); |
| |
| // |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()); |
| EXPECT_GT(1.0f, drag_layer->opacity()); |
| |
| // Enter the pointer to the secondary display. |
| resizer->Drag(CalculateDragPoint(*resizer, 775, 10), 0); |
| EXPECT_EQ(1, controller->GetDragWindowsCountForTest()); |
| // |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(); |
| 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), |
| display::Screen::GetScreen()->GetPrimaryDisplay()); |
| EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); |
| { |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window_.get(), gfx::Point(), HTCAPTION)); |
| ASSERT_TRUE(resizer.get()); |
| DragWindowResizer* drag_resizer = DragWindowResizer::instance_; |
| DragWindowController* controller = |
| drag_resizer->drag_window_controller_.get(); |
| ASSERT_TRUE(drag_resizer); |
| EXPECT_FALSE(controller); |
| |
| resizer->Drag(CalculateDragPoint(*resizer, 0, 610), 0); |
| resizer->RevertDrag(); |
| EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); |
| } |
| } |
| |
| TEST_F(DragWindowResizerTest, DragWindowControllerAcrossThreeDisplays) { |
| UpdateDisplay("400x600,400x600,800x600"); |
| aura::Window::Windows root_windows = Shell::GetAllRootWindows(); |
| |
| // Layout so that all three displays touch each other. |
| display::DisplayIdList list = display_manager()->GetCurrentDisplayIdList(); |
| ASSERT_EQ(3u, list.size()); |
| ASSERT_EQ(display::Screen::GetScreen()->GetPrimaryDisplay().id(), list[0]); |
| display::DisplayLayoutBuilder builder(list[0]); |
| builder.AddDisplayPlacement(list[1], list[0], |
| display::DisplayPlacement::RIGHT, 0); |
| builder.AddDisplayPlacement(list[2], list[0], |
| display::DisplayPlacement::BOTTOM, 0); |
| display_manager()->SetLayoutForCurrentDisplays(builder.Build()); |
| // Sanity check. |
| ASSERT_EQ(gfx::Rect(0, 000, 400, 600), |
| display_manager()->GetDisplayForId(list[0]).bounds()); |
| ASSERT_EQ(gfx::Rect(400, 0, 400, 600), |
| display_manager()->GetDisplayForId(list[1]).bounds()); |
| ASSERT_EQ(gfx::Rect(0, 600, 800, 600), |
| display_manager()->GetDisplayForId(list[2]).bounds()); |
| |
| // Create a window on 2nd display. |
| window_->SetBoundsInScreen(gfx::Rect(400, 0, 100, 100), |
| display_manager()->GetDisplayForId(list[1])); |
| ASSERT_EQ(root_windows[1], window_->GetRootWindow()); |
| |
| // Hold the center of the window so that the window doesn't stick to the edge |
| // when dragging around the edge of the display. |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window_.get(), gfx::Point(50, 50), HTCAPTION)); |
| ASSERT_TRUE(resizer.get()); |
| DragWindowResizer* drag_resizer = DragWindowResizer::instance_; |
| ASSERT_TRUE(drag_resizer); |
| EXPECT_FALSE(drag_resizer->drag_window_controller_.get()); |
| resizer->Drag(CalculateDragPoint(*resizer, -50, 0), 0); |
| DragWindowController* controller = |
| drag_resizer->drag_window_controller_.get(); |
| ASSERT_TRUE(controller); |
| ASSERT_EQ(1, controller->GetDragWindowsCountForTest()); |
| const aura::Window* drag_window0 = controller->GetDragWindowForTest(0); |
| ASSERT_TRUE(drag_window0); |
| const ui::Layer* drag_layer0 = drag_window0->layer(); |
| EXPECT_EQ(root_windows[0], drag_window0->GetRootWindow()); |
| |
| // |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()); |
| EXPECT_GT(1.0f, drag_layer0->opacity()); |
| |
| // The window spans across 3 displays, dragging to 3rd display. |
| resizer->Drag(CalculateDragPoint(*resizer, -50, 549), 0); |
| ASSERT_EQ(2, controller->GetDragWindowsCountForTest()); |
| drag_window0 = controller->GetDragWindowForTest(0); |
| const aura::Window* drag_window1 = controller->GetDragWindowForTest(1); |
| drag_layer0 = drag_window0->layer(); |
| const ui::Layer* drag_layer1 = drag_window1->layer(); |
| EXPECT_EQ(root_windows[0], drag_window0->GetRootWindow()); |
| EXPECT_EQ(root_windows[2], drag_window1->GetRootWindow()); |
| |
| // |window_| should be opaque since the pointer is still on the 2nd |
| // root window. The drag window should be semi-transparent. |
| EXPECT_FLOAT_EQ(1.0f, window_->layer()->opacity()); |
| EXPECT_GT(1.0f, drag_layer0->opacity()); |
| EXPECT_GT(1.0f, drag_layer1->opacity()); |
| |
| resizer->Drag(CalculateDragPoint(*resizer, -51, 549), 0); |
| ASSERT_EQ(2, controller->GetDragWindowsCountForTest()); |
| drag_window0 = controller->GetDragWindowForTest(0); |
| drag_window1 = controller->GetDragWindowForTest(1); |
| drag_layer0 = drag_window0->layer(); |
| drag_layer1 = drag_window1->layer(); |
| EXPECT_EQ(root_windows[0], drag_window0->GetRootWindow()); |
| EXPECT_EQ(root_windows[2], drag_window1->GetRootWindow()); |
| |
| // |window_| should be transparent since the pointer is still on the primary |
| // root window. The drag window should be semi-transparent. |
| EXPECT_GT(1.0f, window_->layer()->opacity()); |
| EXPECT_FLOAT_EQ(1.0f, drag_layer0->opacity()); |
| EXPECT_GT(1.0f, drag_layer1->opacity()); |
| |
| // Enter the pointer to the 3rd. Since it's bottom, the window snaps and |
| // no drag windwos are created. |
| resizer->Drag(CalculateDragPoint(*resizer, -51, 551), 0); |
| ASSERT_EQ(1, controller->GetDragWindowsCountForTest()); |
| drag_window0 = controller->GetDragWindowForTest(0); |
| drag_layer0 = drag_window0->layer(); |
| EXPECT_EQ(root_windows[2], drag_window0->GetRootWindow()); |
| |
| // |window_| should be transparent, and the drag window should be opaque. |
| EXPECT_FLOAT_EQ(0.0f, window_->layer()->opacity()); |
| EXPECT_FLOAT_EQ(1.0f, drag_layer0->opacity()); |
| |
| resizer->CompleteDrag(); |
| EXPECT_EQ(root_windows[2], 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::Get()->mouse_cursor_filter(); |
| ASSERT_TRUE(event_filter); |
| window_->SetBounds(gfx::Rect(0, 0, 50, 60)); |
| |
| EXPECT_TRUE(event_filter->mouse_warp_enabled_); |
| { |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window_.get(), gfx::Point(), HTCAPTION)); |
| // While dragging a window, warp should be allowed. |
| EXPECT_TRUE(event_filter->mouse_warp_enabled_); |
| resizer->CompleteDrag(); |
| } |
| EXPECT_TRUE(event_filter->mouse_warp_enabled_); |
| |
| { |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window_.get(), gfx::Point(), HTCAPTION)); |
| EXPECT_TRUE(event_filter->mouse_warp_enabled_); |
| resizer->RevertDrag(); |
| } |
| EXPECT_TRUE(event_filter->mouse_warp_enabled_); |
| |
| { |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window_.get(), gfx::Point(), HTRIGHT)); |
| // While resizing a window, warp should NOT be allowed. |
| EXPECT_FALSE(event_filter->mouse_warp_enabled_); |
| resizer->CompleteDrag(); |
| } |
| EXPECT_TRUE(event_filter->mouse_warp_enabled_); |
| |
| { |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window_.get(), gfx::Point(), HTRIGHT)); |
| EXPECT_FALSE(event_filter->mouse_warp_enabled_); |
| resizer->RevertDrag(); |
| } |
| EXPECT_TRUE(event_filter->mouse_warp_enabled_); |
| } |
| |
| // 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"); |
| aura::Window::Windows root_windows = Shell::GetAllRootWindows(); |
| ASSERT_EQ(2U, root_windows.size()); |
| |
| CursorManagerTestApi cursor_test_api(Shell::Get()->cursor_manager()); |
| // 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), |
| display::Screen::GetScreen()->GetPrimaryDisplay()); |
| EXPECT_EQ(root_windows[0], window_->GetRootWindow()); |
| // Grab (0, 0) of the window. |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window_.get(), gfx::Point(), HTCAPTION)); |
| EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor()); |
| ASSERT_TRUE(resizer.get()); |
| resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0); |
| TestIfMouseWarpsAt(gfx::Point(399, 200)); |
| EXPECT_EQ(2.0f, cursor_test_api.GetCurrentCursor().device_scale_factor()); |
| resizer->CompleteDrag(); |
| EXPECT_EQ(2.0f, cursor_test_api.GetCurrentCursor().device_scale_factor()); |
| } |
| |
| // Move window from the root window with 2.0 device scale factor to the root |
| // window with 1.0 device scale factor. |
| { |
| // Make sure the window is on the default container first. |
| aura::Window* default_container = |
| RootWindowController::ForWindow(root_windows[1]) |
| ->GetContainer(kShellWindowId_DefaultContainer); |
| default_container->AddChild(window_.get()); |
| window_->SetBoundsInScreen( |
| gfx::Rect(600, 0, 50, 60), |
| display::Screen::GetScreen()->GetDisplayNearestWindow(root_windows[1])); |
| EXPECT_EQ(root_windows[1], window_->GetRootWindow()); |
| // Grab (0, 0) of the window. |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window_.get(), gfx::Point(), HTCAPTION)); |
| EXPECT_EQ(2.0f, cursor_test_api.GetCurrentCursor().device_scale_factor()); |
| ASSERT_TRUE(resizer.get()); |
| resizer->Drag(CalculateDragPoint(*resizer, -200, 200), 0); |
| TestIfMouseWarpsAt(gfx::Point(400, 200)); |
| EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor()); |
| resizer->CompleteDrag(); |
| EXPECT_EQ(1.0f, cursor_test_api.GetCurrentCursor().device_scale_factor()); |
| } |
| } |
| |
| // Verifies several kinds of windows can be moved across displays. |
| TEST_F(DragWindowResizerTest, MoveWindowAcrossDisplays) { |
| // 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,400x400"); |
| |
| aura::Window::Windows root_windows = Shell::GetAllRootWindows(); |
| ASSERT_EQ(2U, root_windows.size()); |
| |
| // Normal window can be moved across display. |
| { |
| aura::Window* window = window_.get(); |
| window->SetBoundsInScreen( |
| gfx::Rect(0, 0, 50, 60), |
| display::Screen::GetScreen()->GetPrimaryDisplay()); |
| // Grab (0, 0) of the window. |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window, gfx::Point(), HTCAPTION)); |
| ASSERT_TRUE(resizer.get()); |
| resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0); |
| EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(399, 200))); |
| EXPECT_EQ("401,200", |
| aura::Env::GetInstance()->last_mouse_location().ToString()); |
| resizer->CompleteDrag(); |
| } |
| |
| // Always on top window can be moved across display. |
| { |
| aura::Window* window = always_on_top_window_.get(); |
| window->SetBoundsInScreen( |
| gfx::Rect(0, 0, 50, 60), |
| display::Screen::GetScreen()->GetPrimaryDisplay()); |
| // Grab (0, 0) of the window. |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window, gfx::Point(), HTCAPTION)); |
| ASSERT_TRUE(resizer.get()); |
| resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0); |
| EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(399, 200))); |
| EXPECT_EQ("401,200", |
| aura::Env::GetInstance()->last_mouse_location().ToString()); |
| resizer->CompleteDrag(); |
| } |
| |
| // System modal window can be moved across display. |
| { |
| aura::Window* window = system_modal_window_.get(); |
| window->SetBoundsInScreen( |
| gfx::Rect(0, 0, 50, 60), |
| display::Screen::GetScreen()->GetPrimaryDisplay()); |
| aura::Env::GetInstance()->set_last_mouse_location(gfx::Point(0, 0)); |
| // Grab (0, 0) of the window. |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window, gfx::Point(), HTCAPTION)); |
| ASSERT_TRUE(resizer.get()); |
| resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0); |
| EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(399, 200))); |
| EXPECT_EQ("401,200", |
| aura::Env::GetInstance()->last_mouse_location().ToString()); |
| resizer->CompleteDrag(); |
| } |
| |
| // Transient window cannot be moved across display. |
| { |
| aura::Window* window = transient_child_; |
| window->SetBoundsInScreen( |
| gfx::Rect(0, 0, 50, 60), |
| display::Screen::GetScreen()->GetPrimaryDisplay()); |
| // Grab (0, 0) of the window. |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window, gfx::Point(), HTCAPTION)); |
| ASSERT_TRUE(resizer.get()); |
| resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0); |
| EXPECT_FALSE(TestIfMouseWarpsAt(gfx::Point(399, 200))); |
| EXPECT_EQ("399,200", |
| aura::Env::GetInstance()->last_mouse_location().ToString()); |
| resizer->CompleteDrag(); |
| } |
| |
| // The parent of transient window can be moved across display. |
| { |
| aura::Window* window = transient_parent_.get(); |
| window->SetBoundsInScreen( |
| gfx::Rect(0, 0, 50, 60), |
| display::Screen::GetScreen()->GetPrimaryDisplay()); |
| // Grab (0, 0) of the window. |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window, gfx::Point(), HTCAPTION)); |
| ASSERT_TRUE(resizer.get()); |
| resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0); |
| EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(399, 200))); |
| EXPECT_EQ("401,200", |
| aura::Env::GetInstance()->last_mouse_location().ToString()); |
| resizer->CompleteDrag(); |
| } |
| |
| // Panel window can be moved across display. |
| { |
| aura::Window* window = panel_window_.get(); |
| window->SetBoundsInScreen( |
| gfx::Rect(0, 0, 50, 60), |
| display::Screen::GetScreen()->GetPrimaryDisplay()); |
| // Grab (0, 0) of the window. |
| std::unique_ptr<WindowResizer> resizer( |
| CreateDragWindowResizer(window, gfx::Point(), HTCAPTION)); |
| ASSERT_TRUE(resizer.get()); |
| resizer->Drag(CalculateDragPoint(*resizer, 399, 200), 0); |
| EXPECT_TRUE(TestIfMouseWarpsAt(gfx::Point(399, 200))); |
| EXPECT_EQ("401,200", |
| aura::Env::GetInstance()->last_mouse_location().ToString()); |
| resizer->CompleteDrag(); |
| } |
| } |
| |
| } // namespace ash |