| // Copyright 2013 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/common/wm/workspace_controller.h" |
| |
| #include <map> |
| |
| #include "ash/aura/wm_window_aura.h" |
| #include "ash/common/shelf/shelf_layout_manager.h" |
| #include "ash/common/shelf/shelf_widget.h" |
| #include "ash/common/shelf/wm_shelf.h" |
| #include "ash/common/system/status_area_widget.h" |
| #include "ash/common/test/test_shelf_delegate.h" |
| #include "ash/common/wm/panels/panel_layout_manager.h" |
| #include "ash/common/wm/window_state.h" |
| #include "ash/common/wm/workspace/workspace_window_resizer.h" |
| #include "ash/public/cpp/shell_window_ids.h" |
| #include "ash/screen_util.h" |
| #include "ash/shell.h" |
| #include "ash/test/ash_md_test_base.h" |
| #include "ash/test/shell_test_api.h" |
| #include "ash/wm/window_state_aura.h" |
| #include "ash/wm/window_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "ui/aura/client/aura_constants.h" |
| #include "ui/aura/test/test_window_delegate.h" |
| #include "ui/aura/test/test_windows.h" |
| #include "ui/aura/window.h" |
| #include "ui/aura/window_event_dispatcher.h" |
| #include "ui/base/hit_test.h" |
| #include "ui/base/ui_base_types.h" |
| #include "ui/compositor/layer.h" |
| #include "ui/compositor/scoped_animation_duration_scale_mode.h" |
| #include "ui/display/screen.h" |
| #include "ui/events/event_utils.h" |
| #include "ui/events/test/event_generator.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/wm/core/window_animations.h" |
| #include "ui/wm/core/window_util.h" |
| |
| using aura::Window; |
| |
| namespace ash { |
| |
| // Returns a string containing the names of all the children of |window| (in |
| // order). Each entry is separated by a space. |
| std::string GetWindowNames(const aura::Window* window) { |
| std::string result; |
| for (size_t i = 0; i < window->children().size(); ++i) { |
| if (i != 0) |
| result += " "; |
| result += window->children()[i]->name(); |
| } |
| return result; |
| } |
| |
| // Returns a string containing the names of windows corresponding to each of the |
| // child layers of |window|'s layer. Any layers that don't correspond to a child |
| // Window of |window| are ignored. The result is ordered based on the layer |
| // ordering. |
| std::string GetLayerNames(const aura::Window* window) { |
| typedef std::map<const ui::Layer*, std::string> LayerToWindowNameMap; |
| LayerToWindowNameMap window_names; |
| for (size_t i = 0; i < window->children().size(); ++i) { |
| window_names[window->children()[i]->layer()] = |
| window->children()[i]->name(); |
| } |
| |
| std::string result; |
| const std::vector<ui::Layer*>& layers(window->layer()->children()); |
| for (size_t i = 0; i < layers.size(); ++i) { |
| LayerToWindowNameMap::iterator layer_i = window_names.find(layers[i]); |
| if (layer_i != window_names.end()) { |
| if (!result.empty()) |
| result += " "; |
| result += layer_i->second; |
| } |
| } |
| return result; |
| } |
| |
| class WorkspaceControllerTest : public test::AshMDTestBase { |
| public: |
| WorkspaceControllerTest() {} |
| ~WorkspaceControllerTest() override {} |
| |
| aura::Window* CreateTestWindowUnparented() { |
| aura::Window* window = new aura::Window(NULL); |
| window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); |
| window->SetType(ui::wm::WINDOW_TYPE_NORMAL); |
| window->Init(ui::LAYER_TEXTURED); |
| return window; |
| } |
| |
| aura::Window* CreateTestWindow() { |
| aura::Window* window = new aura::Window(NULL); |
| window->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); |
| window->SetType(ui::wm::WINDOW_TYPE_NORMAL); |
| window->Init(ui::LAYER_TEXTURED); |
| ParentWindowInPrimaryRootWindow(window); |
| return window; |
| } |
| |
| aura::Window* CreateBrowserLikeWindow(const gfx::Rect& bounds) { |
| aura::Window* window = CreateTestWindow(); |
| window->SetBounds(bounds); |
| wm::WindowState* window_state = wm::GetWindowState(window); |
| window_state->set_window_position_managed(true); |
| window->Show(); |
| return window; |
| } |
| |
| aura::Window* CreatePopupLikeWindow(const gfx::Rect& bounds) { |
| aura::Window* window = CreateTestWindowInShellWithBounds(bounds); |
| window->Show(); |
| return window; |
| } |
| |
| aura::Window* CreateTestPanel(aura::WindowDelegate* delegate, |
| const gfx::Rect& bounds) { |
| aura::Window* window = CreateTestWindowInShellWithDelegateAndType( |
| delegate, ui::wm::WINDOW_TYPE_PANEL, 0, bounds); |
| WmWindow* wm_window = WmWindowAura::Get(window); |
| test::TestShelfDelegate::instance()->AddShelfItem(wm_window); |
| PanelLayoutManager::Get(wm_window)->Relayout(); |
| return window; |
| } |
| |
| aura::Window* GetDesktop() { |
| return Shell::GetContainer(Shell::GetPrimaryRootWindow(), |
| kShellWindowId_DefaultContainer); |
| } |
| |
| gfx::Rect GetFullscreenBounds(aura::Window* window) { |
| return display::Screen::GetScreen() |
| ->GetDisplayNearestWindow(window) |
| .bounds(); |
| } |
| |
| ShelfWidget* shelf_widget() { return GetPrimaryShelf()->shelf_widget(); } |
| |
| ShelfLayoutManager* shelf_layout_manager() { |
| return GetPrimaryShelf()->shelf_layout_manager(); |
| } |
| |
| bool GetWindowOverlapsShelf() { |
| return shelf_layout_manager()->window_overlaps_shelf(); |
| } |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(WorkspaceControllerTest); |
| }; |
| |
| INSTANTIATE_TEST_CASE_P( |
| /* prefix intentionally left blank due to only one parameterization */, |
| WorkspaceControllerTest, |
| testing::Values(MaterialDesignController::NON_MATERIAL, |
| MaterialDesignController::MATERIAL_NORMAL, |
| MaterialDesignController::MATERIAL_EXPERIMENTAL)); |
| |
| // Assertions around adding a normal window. |
| TEST_P(WorkspaceControllerTest, AddNormalWindowWhenEmpty) { |
| std::unique_ptr<Window> w1(CreateTestWindow()); |
| w1->SetBounds(gfx::Rect(0, 0, 250, 251)); |
| |
| wm::WindowState* window_state = wm::GetWindowState(w1.get()); |
| |
| EXPECT_FALSE(window_state->HasRestoreBounds()); |
| |
| w1->Show(); |
| |
| EXPECT_FALSE(window_state->HasRestoreBounds()); |
| |
| ASSERT_TRUE(w1->layer() != NULL); |
| EXPECT_TRUE(w1->layer()->visible()); |
| |
| EXPECT_EQ("0,0 250x251", w1->bounds().ToString()); |
| |
| EXPECT_EQ(w1.get(), GetDesktop()->children()[0]); |
| } |
| |
| // Assertions around maximizing/unmaximizing. |
| TEST_P(WorkspaceControllerTest, SingleMaximizeWindow) { |
| std::unique_ptr<Window> w1(CreateTestWindow()); |
| w1->SetBounds(gfx::Rect(0, 0, 250, 251)); |
| |
| w1->Show(); |
| wm::ActivateWindow(w1.get()); |
| |
| EXPECT_TRUE(wm::IsActiveWindow(w1.get())); |
| |
| ASSERT_TRUE(w1->layer() != NULL); |
| EXPECT_TRUE(w1->layer()->visible()); |
| |
| EXPECT_EQ("0,0 250x251", w1->bounds().ToString()); |
| |
| // Maximize the window. |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); |
| |
| EXPECT_TRUE(wm::IsActiveWindow(w1.get())); |
| |
| EXPECT_EQ(w1.get(), GetDesktop()->children()[0]); |
| EXPECT_EQ(ScreenUtil::GetMaximizedWindowBoundsInParent(w1.get()).width(), |
| w1->bounds().width()); |
| EXPECT_EQ(ScreenUtil::GetMaximizedWindowBoundsInParent(w1.get()).height(), |
| w1->bounds().height()); |
| |
| // Restore the window. |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); |
| |
| EXPECT_EQ(w1.get(), GetDesktop()->children()[0]); |
| EXPECT_EQ("0,0 250x251", w1->bounds().ToString()); |
| } |
| |
| // Assertions around two windows and toggling one to be fullscreen. |
| TEST_P(WorkspaceControllerTest, FullscreenWithNormalWindow) { |
| std::unique_ptr<Window> w1(CreateTestWindow()); |
| std::unique_ptr<Window> w2(CreateTestWindow()); |
| w1->SetBounds(gfx::Rect(0, 0, 250, 251)); |
| w1->Show(); |
| |
| ASSERT_TRUE(w1->layer() != NULL); |
| EXPECT_TRUE(w1->layer()->visible()); |
| |
| w2->SetBounds(gfx::Rect(0, 0, 50, 51)); |
| w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); |
| w2->Show(); |
| wm::ActivateWindow(w2.get()); |
| |
| // Both windows should be in the same workspace. |
| EXPECT_EQ(w1.get(), GetDesktop()->children()[0]); |
| EXPECT_EQ(w2.get(), GetDesktop()->children()[1]); |
| |
| gfx::Rect work_area(ScreenUtil::GetMaximizedWindowBoundsInParent(w1.get())); |
| EXPECT_EQ(work_area.width(), w2->bounds().width()); |
| EXPECT_EQ(work_area.height(), w2->bounds().height()); |
| |
| // Restore w2, which should then go back to one workspace. |
| w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); |
| EXPECT_EQ(50, w2->bounds().width()); |
| EXPECT_EQ(51, w2->bounds().height()); |
| EXPECT_TRUE(wm::IsActiveWindow(w2.get())); |
| } |
| |
| // Makes sure requests to change the bounds of a normal window go through. |
| TEST_P(WorkspaceControllerTest, ChangeBoundsOfNormalWindow) { |
| std::unique_ptr<Window> w1(CreateTestWindow()); |
| w1->Show(); |
| |
| // Setting the bounds should go through since the window is in the normal |
| // workspace. |
| w1->SetBounds(gfx::Rect(0, 0, 200, 500)); |
| EXPECT_EQ(200, w1->bounds().width()); |
| EXPECT_EQ(500, w1->bounds().height()); |
| } |
| |
| // Verifies the bounds is not altered when showing and grid is enabled. |
| TEST_P(WorkspaceControllerTest, SnapToGrid) { |
| std::unique_ptr<Window> w1(CreateTestWindowUnparented()); |
| w1->SetBounds(gfx::Rect(1, 6, 25, 30)); |
| ParentWindowInPrimaryRootWindow(w1.get()); |
| // We are not aligning this anymore this way. When the window gets shown |
| // the window is expected to be handled differently, but this cannot be |
| // tested with this test. So the result of this test should be that the |
| // bounds are exactly as passed in. |
| EXPECT_EQ("1,6 25x30", w1->bounds().ToString()); |
| } |
| |
| // Assertions around a fullscreen window. |
| TEST_P(WorkspaceControllerTest, SingleFullscreenWindow) { |
| std::unique_ptr<Window> w1(CreateTestWindow()); |
| w1->SetBounds(gfx::Rect(0, 0, 250, 251)); |
| // Make the window fullscreen. |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); |
| w1->Show(); |
| wm::ActivateWindow(w1.get()); |
| |
| EXPECT_EQ(w1.get(), GetDesktop()->children()[0]); |
| EXPECT_EQ(GetFullscreenBounds(w1.get()).width(), w1->bounds().width()); |
| EXPECT_EQ(GetFullscreenBounds(w1.get()).height(), w1->bounds().height()); |
| |
| // Restore the window. Use SHOW_STATE_DEFAULT as that is what we'll end up |
| // with when using views::Widget. |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_DEFAULT); |
| EXPECT_EQ("0,0 250x251", w1->bounds().ToString()); |
| |
| EXPECT_EQ(w1.get(), GetDesktop()->children()[0]); |
| EXPECT_EQ(250, w1->bounds().width()); |
| EXPECT_EQ(251, w1->bounds().height()); |
| |
| // Back to fullscreen. |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); |
| EXPECT_EQ(w1.get(), GetDesktop()->children()[0]); |
| EXPECT_EQ(GetFullscreenBounds(w1.get()).width(), w1->bounds().width()); |
| EXPECT_EQ(GetFullscreenBounds(w1.get()).height(), w1->bounds().height()); |
| wm::WindowState* window_state = wm::GetWindowState(w1.get()); |
| |
| ASSERT_TRUE(window_state->HasRestoreBounds()); |
| EXPECT_EQ("0,0 250x251", window_state->GetRestoreBoundsInScreen().ToString()); |
| } |
| |
| // Assertions around minimizing a single window. |
| TEST_P(WorkspaceControllerTest, MinimizeSingleWindow) { |
| std::unique_ptr<Window> w1(CreateTestWindow()); |
| |
| w1->Show(); |
| |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); |
| EXPECT_FALSE(w1->layer()->IsDrawn()); |
| EXPECT_TRUE(w1->layer()->GetTargetTransform().IsIdentity()); |
| |
| // Show the window. |
| w1->Show(); |
| EXPECT_TRUE(wm::GetWindowState(w1.get())->IsNormalStateType()); |
| EXPECT_TRUE(w1->layer()->IsDrawn()); |
| } |
| |
| // Assertions around minimizing a fullscreen window. |
| TEST_P(WorkspaceControllerTest, MinimizeFullscreenWindow) { |
| // Two windows, w1 normal, w2 fullscreen. |
| std::unique_ptr<Window> w1(CreateTestWindow()); |
| std::unique_ptr<Window> w2(CreateTestWindow()); |
| w1->Show(); |
| w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); |
| w2->Show(); |
| |
| wm::WindowState* w1_state = wm::GetWindowState(w1.get()); |
| wm::WindowState* w2_state = wm::GetWindowState(w2.get()); |
| |
| w2_state->Activate(); |
| |
| // Minimize w2. |
| w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); |
| EXPECT_TRUE(w1->layer()->IsDrawn()); |
| EXPECT_FALSE(w2->layer()->IsDrawn()); |
| |
| // Show the window, which should trigger unminimizing. |
| w2->Show(); |
| w2_state->Activate(); |
| |
| EXPECT_TRUE(w2_state->IsFullscreen()); |
| EXPECT_TRUE(w1->layer()->IsDrawn()); |
| EXPECT_TRUE(w2->layer()->IsDrawn()); |
| |
| // Minimize the window, which should hide the window. |
| EXPECT_TRUE(w2_state->IsActive()); |
| w2_state->Minimize(); |
| EXPECT_FALSE(w2_state->IsActive()); |
| EXPECT_FALSE(w2->layer()->IsDrawn()); |
| EXPECT_TRUE(w1_state->IsActive()); |
| EXPECT_EQ(w2.get(), GetDesktop()->children()[0]); |
| EXPECT_EQ(w1.get(), GetDesktop()->children()[1]); |
| |
| // Make the window normal. |
| w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); |
| // Setting back to normal doesn't change the activation. |
| EXPECT_FALSE(w2_state->IsActive()); |
| EXPECT_TRUE(w1_state->IsActive()); |
| EXPECT_EQ(w2.get(), GetDesktop()->children()[0]); |
| EXPECT_EQ(w1.get(), GetDesktop()->children()[1]); |
| EXPECT_TRUE(w2->layer()->IsDrawn()); |
| } |
| |
| // Verifies ShelfLayoutManager's visibility/auto-hide state is correctly |
| // updated. |
| TEST_P(WorkspaceControllerTest, ShelfStateUpdated) { |
| // Since ShelfLayoutManager queries for mouse location, move the mouse so |
| // it isn't over the shelf. |
| ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), |
| gfx::Point()); |
| generator.MoveMouseTo(0, 0); |
| |
| std::unique_ptr<Window> w1(CreateTestWindow()); |
| const gfx::Rect w1_bounds(0, 1, 101, 102); |
| WmShelf* shelf = GetPrimaryShelf(); |
| shelf->SetAutoHideBehavior(ash::SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); |
| const gfx::Rect touches_shelf_bounds( |
| 0, shelf_layout_manager()->GetIdealBounds().y() - 10, 101, 102); |
| // Move |w1| to overlap the shelf. |
| w1->SetBounds(touches_shelf_bounds); |
| EXPECT_FALSE(GetWindowOverlapsShelf()); |
| |
| // A visible ignored window should not trigger the overlap. |
| std::unique_ptr<Window> w_ignored(CreateTestWindow()); |
| w_ignored->SetBounds(touches_shelf_bounds); |
| wm::GetWindowState(&(*w_ignored))->set_ignored_by_shelf(true); |
| w_ignored->Show(); |
| EXPECT_FALSE(GetWindowOverlapsShelf()); |
| |
| // Make it visible, since visible shelf overlaps should be true. |
| w1->Show(); |
| EXPECT_TRUE(GetWindowOverlapsShelf()); |
| |
| wm::ActivateWindow(w1.get()); |
| w1->SetBounds(w1_bounds); |
| w1->Show(); |
| wm::ActivateWindow(w1.get()); |
| |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| |
| // Maximize the window. |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState()); |
| |
| // Restore. |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ("0,1 101x102", w1->bounds().ToString()); |
| |
| // Fullscreen. |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); |
| EXPECT_EQ(SHELF_HIDDEN, shelf->GetVisibilityState()); |
| |
| // Normal. |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ("0,1 101x102", w1->bounds().ToString()); |
| EXPECT_FALSE(GetWindowOverlapsShelf()); |
| |
| // Move window so it obscures shelf. |
| w1->SetBounds(touches_shelf_bounds); |
| EXPECT_TRUE(GetWindowOverlapsShelf()); |
| |
| // Move it back. |
| w1->SetBounds(w1_bounds); |
| EXPECT_FALSE(GetWindowOverlapsShelf()); |
| |
| // Maximize again. |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState()); |
| |
| // Minimize. |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| |
| // Since the restore from minimize will restore to the pre-minimize |
| // state (tested elsewhere), we abandon the current size and restore |
| // rect and set them to the window. |
| wm::WindowState* window_state = wm::GetWindowState(w1.get()); |
| |
| gfx::Rect restore = window_state->GetRestoreBoundsInScreen(); |
| EXPECT_EQ( |
| gfx::Rect(0, 0, 800, 597 + GetMdAutoHiddenShelfHeightOffset()).ToString(), |
| w1->bounds().ToString()); |
| EXPECT_EQ("0,1 101x102", restore.ToString()); |
| window_state->ClearRestoreBounds(); |
| w1->SetBounds(restore); |
| |
| // Restore. |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ("0,1 101x102", w1->bounds().ToString()); |
| |
| // Create another window, maximized. |
| std::unique_ptr<Window> w2(CreateTestWindow()); |
| w2->SetBounds(gfx::Rect(10, 11, 250, 251)); |
| w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); |
| w2->Show(); |
| wm::ActivateWindow(w2.get()); |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState()); |
| EXPECT_EQ("0,1 101x102", w1->bounds().ToString()); |
| EXPECT_EQ( |
| ScreenUtil::GetMaximizedWindowBoundsInParent(w2->parent()).ToString(), |
| w2->bounds().ToString()); |
| |
| // Switch to w1. |
| wm::ActivateWindow(w1.get()); |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ("0,1 101x102", w1->bounds().ToString()); |
| EXPECT_EQ( |
| ScreenUtil::GetMaximizedWindowBoundsInParent(w2->parent()).ToString(), |
| w2->bounds().ToString()); |
| |
| // Switch to w2. |
| wm::ActivateWindow(w2.get()); |
| EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); |
| EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState()); |
| EXPECT_EQ("0,1 101x102", w1->bounds().ToString()); |
| EXPECT_EQ(ScreenUtil::GetMaximizedWindowBoundsInParent(w2.get()).ToString(), |
| w2->bounds().ToString()); |
| |
| // Turn off auto-hide, switch back to w2 (maximized) and verify overlap. |
| shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); |
| wm::ActivateWindow(w2.get()); |
| EXPECT_FALSE(GetWindowOverlapsShelf()); |
| |
| // Move w1 to overlap shelf, it shouldn't change window overlaps shelf since |
| // the window isn't in the visible workspace. |
| w1->SetBounds(touches_shelf_bounds); |
| EXPECT_FALSE(GetWindowOverlapsShelf()); |
| |
| // Activate w1. Although w1 is visible, the overlap state is still false since |
| // w2 is maximized. |
| wm::ActivateWindow(w1.get()); |
| EXPECT_FALSE(GetWindowOverlapsShelf()); |
| |
| // Restore w2. |
| w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); |
| EXPECT_TRUE(GetWindowOverlapsShelf()); |
| } |
| |
| // Verifies going from maximized to minimized sets the right state for painting |
| // the background of the launcher. |
| TEST_P(WorkspaceControllerTest, MinimizeResetsVisibility) { |
| std::unique_ptr<Window> w1(CreateTestWindow()); |
| w1->Show(); |
| wm::ActivateWindow(w1.get()); |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); |
| EXPECT_EQ(SHELF_BACKGROUND_MAXIMIZED, shelf_widget()->GetBackgroundType()); |
| |
| w1->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); |
| EXPECT_EQ(SHELF_VISIBLE, GetPrimaryShelf()->GetVisibilityState()); |
| EXPECT_EQ(SHELF_BACKGROUND_DEFAULT, shelf_widget()->GetBackgroundType()); |
| } |
| |
| // Verifies window visibility during various workspace changes. |
| TEST_P(WorkspaceControllerTest, VisibilityTests) { |
| std::unique_ptr<Window> w1(CreateTestWindow()); |
| w1->Show(); |
| EXPECT_TRUE(w1->IsVisible()); |
| EXPECT_EQ(1.0f, w1->layer()->GetCombinedOpacity()); |
| |
| // Create another window, activate it and make it fullscreen. |
| std::unique_ptr<Window> w2(CreateTestWindow()); |
| w2->Show(); |
| wm::ActivateWindow(w2.get()); |
| w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); |
| EXPECT_TRUE(w2->IsVisible()); |
| EXPECT_EQ(1.0f, w2->layer()->GetCombinedOpacity()); |
| EXPECT_TRUE(w1->IsVisible()); |
| |
| // Switch to w1. |w1| should be visible on top of |w2|. |
| wm::ActivateWindow(w1.get()); |
| EXPECT_TRUE(w1->IsVisible()); |
| EXPECT_EQ(1.0f, w1->layer()->GetCombinedOpacity()); |
| EXPECT_TRUE(w2->IsVisible()); |
| |
| // Switch back to |w2|. |
| wm::ActivateWindow(w2.get()); |
| EXPECT_TRUE(w2->IsVisible()); |
| EXPECT_EQ(1.0f, w2->layer()->GetCombinedOpacity()); |
| EXPECT_TRUE(w1->IsVisible()); |
| |
| // Restore |w2|, both windows should be visible. |
| w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); |
| EXPECT_TRUE(w1->IsVisible()); |
| EXPECT_EQ(1.0f, w1->layer()->GetCombinedOpacity()); |
| EXPECT_TRUE(w2->IsVisible()); |
| EXPECT_EQ(1.0f, w2->layer()->GetCombinedOpacity()); |
| |
| // Make |w2| fullscreen again, then close it. |
| w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_FULLSCREEN); |
| w2->Hide(); |
| EXPECT_FALSE(w2->IsVisible()); |
| EXPECT_EQ(1.0f, w1->layer()->GetCombinedOpacity()); |
| EXPECT_TRUE(w1->IsVisible()); |
| |
| // Create |w2| and maximize it. |
| w2.reset(CreateTestWindow()); |
| w2->Show(); |
| wm::ActivateWindow(w2.get()); |
| w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); |
| EXPECT_TRUE(w2->IsVisible()); |
| EXPECT_EQ(1.0f, w2->layer()->GetCombinedOpacity()); |
| EXPECT_TRUE(w1->IsVisible()); |
| |
| // Close |w2|. |
| w2.reset(); |
| EXPECT_EQ(1.0f, w1->layer()->GetCombinedOpacity()); |
| EXPECT_TRUE(w1->IsVisible()); |
| } |
| |
| // Verifies windows that are offscreen don't move when switching workspaces. |
| TEST_P(WorkspaceControllerTest, DontMoveOnSwitch) { |
| ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), |
| gfx::Point()); |
| generator.MoveMouseTo(0, 0); |
| |
| std::unique_ptr<Window> w1(CreateTestWindow()); |
| const gfx::Rect touches_shelf_bounds( |
| 0, shelf_layout_manager()->GetIdealBounds().y() - 10, 101, 102); |
| // Move |w1| to overlap the shelf. |
| w1->SetBounds(touches_shelf_bounds); |
| w1->Show(); |
| wm::ActivateWindow(w1.get()); |
| |
| // Create another window and maximize it. |
| std::unique_ptr<Window> w2(CreateTestWindow()); |
| w2->SetBounds(gfx::Rect(10, 11, 250, 251)); |
| w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); |
| w2->Show(); |
| wm::ActivateWindow(w2.get()); |
| |
| // Switch to w1. |
| wm::ActivateWindow(w1.get()); |
| EXPECT_EQ(touches_shelf_bounds.ToString(), w1->bounds().ToString()); |
| } |
| |
| // Verifies that windows that are completely offscreen move when switching |
| // workspaces. |
| TEST_P(WorkspaceControllerTest, MoveOnSwitch) { |
| ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), |
| gfx::Point()); |
| generator.MoveMouseTo(0, 0); |
| |
| std::unique_ptr<Window> w1(CreateTestWindow()); |
| const gfx::Rect w1_bounds(0, shelf_layout_manager()->GetIdealBounds().y(), |
| 100, 200); |
| // Move |w1| so that the top edge is the same as the top edge of the shelf. |
| w1->SetBounds(w1_bounds); |
| w1->Show(); |
| wm::ActivateWindow(w1.get()); |
| EXPECT_EQ(w1_bounds.ToString(), w1->bounds().ToString()); |
| |
| // Create another window and maximize it. |
| std::unique_ptr<Window> w2(CreateTestWindow()); |
| w2->SetBounds(gfx::Rect(10, 11, 250, 251)); |
| w2->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MAXIMIZED); |
| w2->Show(); |
| wm::ActivateWindow(w2.get()); |
| |
| // Increase the size of the WorkAreaInsets. This would make |w1| fall |
| // completely out of the display work area. |
| gfx::Insets insets = |
| display::Screen::GetScreen()->GetPrimaryDisplay().GetWorkAreaInsets(); |
| insets.Set(0, 0, insets.bottom() + 30, 0); |
| Shell::GetInstance()->SetDisplayWorkAreaInsets(w1.get(), insets); |
| |
| // Switch to w1. The window should have moved. |
| wm::ActivateWindow(w1.get()); |
| EXPECT_NE(w1_bounds.ToString(), w1->bounds().ToString()); |
| } |
| |
| namespace { |
| |
| // WindowDelegate used by DontCrashOnChangeAndActivate. |
| class DontCrashOnChangeAndActivateDelegate |
| : public aura::test::TestWindowDelegate { |
| public: |
| DontCrashOnChangeAndActivateDelegate() : window_(NULL) {} |
| |
| void set_window(aura::Window* window) { window_ = window; } |
| |
| // WindowDelegate overrides: |
| void OnBoundsChanged(const gfx::Rect& old_bounds, |
| const gfx::Rect& new_bounds) override { |
| if (window_) { |
| wm::ActivateWindow(window_); |
| window_ = NULL; |
| } |
| } |
| |
| private: |
| aura::Window* window_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DontCrashOnChangeAndActivateDelegate); |
| }; |
| |
| } // namespace |
| |
| // Exercises possible crash in W2. Here's the sequence: |
| // . minimize a maximized window. |
| // . remove the window (which happens when switching displays). |
| // . add the window back. |
| // . show the window and during the bounds change activate it. |
| TEST_P(WorkspaceControllerTest, DontCrashOnChangeAndActivate) { |
| // Force the shelf |
| WmShelf* shelf = GetPrimaryShelf(); |
| shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); |
| |
| DontCrashOnChangeAndActivateDelegate delegate; |
| std::unique_ptr<Window> w1(CreateTestWindowInShellWithDelegate( |
| &delegate, 1000, gfx::Rect(10, 11, 250, 251))); |
| |
| w1->Show(); |
| wm::WindowState* w1_state = wm::GetWindowState(w1.get()); |
| w1_state->Activate(); |
| w1_state->Maximize(); |
| w1_state->Minimize(); |
| |
| w1->parent()->RemoveChild(w1.get()); |
| |
| // Do this so that when we Show() the window a resize occurs and we make the |
| // window active. |
| shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); |
| |
| ParentWindowInPrimaryRootWindow(w1.get()); |
| delegate.set_window(w1.get()); |
| w1->Show(); |
| } |
| |
| // Verifies a window with a transient parent not managed by workspace works. |
| TEST_P(WorkspaceControllerTest, TransientParent) { |
| // Normal window with no transient parent. |
| std::unique_ptr<Window> w2(CreateTestWindow()); |
| w2->SetBounds(gfx::Rect(10, 11, 250, 251)); |
| w2->Show(); |
| wm::ActivateWindow(w2.get()); |
| |
| // Window with a transient parent. We set the transient parent to the root, |
| // which would never happen but is enough to exercise the bug. |
| std::unique_ptr<Window> w1(CreateTestWindowUnparented()); |
| ::wm::AddTransientChild(Shell::GetInstance()->GetPrimaryRootWindow(), |
| w1.get()); |
| w1->SetBounds(gfx::Rect(10, 11, 250, 251)); |
| ParentWindowInPrimaryRootWindow(w1.get()); |
| w1->Show(); |
| wm::ActivateWindow(w1.get()); |
| |
| // The window with the transient parent should get added to the same parent as |
| // the normal window. |
| EXPECT_EQ(w2->parent(), w1->parent()); |
| } |
| |
| // Test the placement of newly created windows. |
| TEST_P(WorkspaceControllerTest, BasicAutoPlacingOnCreate) { |
| UpdateDisplay("1600x1200"); |
| // Creating a popup handler here to make sure it does not interfere with the |
| // existing windows. |
| gfx::Rect source_browser_bounds(16, 32, 640, 320); |
| std::unique_ptr<aura::Window> browser_window( |
| CreateBrowserLikeWindow(source_browser_bounds)); |
| |
| // Creating a popup to make sure it does not interfere with the positioning. |
| std::unique_ptr<aura::Window> browser_popup( |
| CreatePopupLikeWindow(gfx::Rect(16, 32, 128, 256))); |
| |
| browser_window->Show(); |
| browser_popup->Show(); |
| |
| { // With a shown window it's size should get returned. |
| std::unique_ptr<aura::Window> new_browser_window( |
| CreateBrowserLikeWindow(source_browser_bounds)); |
| // The position should be right flush. |
| EXPECT_EQ("960,32 640x320", new_browser_window->bounds().ToString()); |
| } |
| |
| { // With the window shown - but more on the right side then on the left |
| // side (and partially out of the screen), it should default to the other |
| // side and inside the screen. |
| gfx::Rect source_browser_bounds(gfx::Rect(1000, 600, 640, 320)); |
| browser_window->SetBounds(source_browser_bounds); |
| |
| std::unique_ptr<aura::Window> new_browser_window( |
| CreateBrowserLikeWindow(source_browser_bounds)); |
| // The position should be left & bottom flush. |
| EXPECT_EQ("0,600 640x320", new_browser_window->bounds().ToString()); |
| |
| // If the other window was already beyond the point to get right flush |
| // it will remain where it is. |
| EXPECT_EQ("1000,600 640x320", browser_window->bounds().ToString()); |
| } |
| |
| { // Make sure that popups do not get changed. |
| std::unique_ptr<aura::Window> new_popup_window( |
| CreatePopupLikeWindow(gfx::Rect(50, 100, 300, 150))); |
| EXPECT_EQ("50,100 300x150", new_popup_window->bounds().ToString()); |
| } |
| |
| browser_window->Hide(); |
| { // If a window is there but not shown the default should be centered. |
| std::unique_ptr<aura::Window> new_browser_window( |
| CreateBrowserLikeWindow(gfx::Rect(50, 100, 300, 150))); |
| EXPECT_EQ("650,100 300x150", new_browser_window->bounds().ToString()); |
| } |
| } |
| |
| // Test that adding a second window shifts both the first window and its |
| // transient child. |
| TEST_P(WorkspaceControllerTest, AutoPlacingMovesTransientChild) { |
| // Create an auto-positioned window. |
| std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0)); |
| gfx::Rect desktop_area = window1->parent()->bounds(); |
| wm::GetWindowState(window1.get())->set_window_position_managed(true); |
| // Hide and then show |window1| to trigger auto-positioning logic. |
| window1->Hide(); |
| window1->SetBounds(gfx::Rect(16, 32, 300, 300)); |
| window1->Show(); |
| |
| // |window1| should be horizontally centered. |
| int x_window1 = (desktop_area.width() - 300) / 2; |
| EXPECT_EQ(base::IntToString(x_window1) + ",32 300x300", |
| window1->bounds().ToString()); |
| |
| // Create a |child| window and make it a transient child of |window1|. |
| std::unique_ptr<Window> child(CreateTestWindowUnparented()); |
| ::wm::AddTransientChild(window1.get(), child.get()); |
| const int x_child = x_window1 + 50; |
| child->SetBounds(gfx::Rect(x_child, 20, 200, 200)); |
| ParentWindowInPrimaryRootWindow(child.get()); |
| child->Show(); |
| wm::ActivateWindow(child.get()); |
| |
| // The |child| should be where it was created. |
| EXPECT_EQ(base::IntToString(x_child) + ",20 200x200", |
| child->bounds().ToString()); |
| |
| // Create and show a second window forcing the first window and its child to |
| // move. |
| std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1)); |
| wm::GetWindowState(window2.get())->set_window_position_managed(true); |
| // Hide and then show |window2| to trigger auto-positioning logic. |
| window2->Hide(); |
| window2->SetBounds(gfx::Rect(32, 48, 250, 250)); |
| window2->Show(); |
| |
| // Check that both |window1| and |child| have moved left. |
| EXPECT_EQ("0,32 300x300", window1->bounds().ToString()); |
| int x = x_child - x_window1; |
| EXPECT_EQ(base::IntToString(x) + ",20 200x200", child->bounds().ToString()); |
| // Check that |window2| has moved right. |
| x = desktop_area.width() - window2->bounds().width(); |
| EXPECT_EQ(base::IntToString(x) + ",48 250x250", window2->bounds().ToString()); |
| } |
| |
| // Test the basic auto placement of one and or two windows in a "simulated |
| // session" of sequential window operations. |
| TEST_P(WorkspaceControllerTest, BasicAutoPlacingOnShowHide) { |
| // Test 1: In case there is no manageable window, no window should shift. |
| |
| std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0)); |
| window1->SetBounds(gfx::Rect(16, 32, 640, 320)); |
| gfx::Rect desktop_area = window1->parent()->bounds(); |
| |
| std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1)); |
| // Trigger the auto window placement function by making it visible. |
| // Note that the bounds are getting changed while it is invisible. |
| window2->Hide(); |
| window2->SetBounds(gfx::Rect(32, 48, 256, 512)); |
| window2->Show(); |
| |
| // Check the initial position of the windows is unchanged. |
| EXPECT_EQ("16,32 640x320", window1->bounds().ToString()); |
| EXPECT_EQ("32,48 256x512", window2->bounds().ToString()); |
| |
| // Remove the second window and make sure that the first window |
| // does NOT get centered. |
| window2.reset(); |
| EXPECT_EQ("16,32 640x320", window1->bounds().ToString()); |
| |
| wm::WindowState* window1_state = wm::GetWindowState(window1.get()); |
| // Test 2: Set up two managed windows and check their auto positioning. |
| window1_state->set_window_position_managed(true); |
| |
| std::unique_ptr<aura::Window> window3(CreateTestWindowInShellWithId(2)); |
| wm::GetWindowState(window3.get())->set_window_position_managed(true); |
| // To avoid any auto window manager changes due to SetBounds, the window |
| // gets first hidden and then shown again. |
| window3->Hide(); |
| window3->SetBounds(gfx::Rect(32, 48, 256, 512)); |
| window3->Show(); |
| // |window1| should be flush left and |window3| flush right. |
| EXPECT_EQ("0,32 640x320", window1->bounds().ToString()); |
| EXPECT_EQ( |
| base::IntToString(desktop_area.width() - window3->bounds().width()) + |
| ",48 256x512", |
| window3->bounds().ToString()); |
| |
| // After removing |window3|, |window1| should be centered again. |
| window3.reset(); |
| EXPECT_EQ(base::IntToString( |
| (desktop_area.width() - window1->bounds().width()) / 2) + |
| ",32 640x320", |
| window1->bounds().ToString()); |
| |
| // Test 3: Set up a manageable and a non manageable window and check |
| // positioning. |
| std::unique_ptr<aura::Window> window4(CreateTestWindowInShellWithId(3)); |
| // To avoid any auto window manager changes due to SetBounds, the window |
| // gets first hidden and then shown again. |
| window1->Hide(); |
| window1->SetBounds(gfx::Rect(16, 32, 640, 320)); |
| window4->SetBounds(gfx::Rect(32, 48, 256, 512)); |
| window1->Show(); |
| // |window1| should be centered and |window4| untouched. |
| EXPECT_EQ(base::IntToString( |
| (desktop_area.width() - window1->bounds().width()) / 2) + |
| ",32 640x320", |
| window1->bounds().ToString()); |
| EXPECT_EQ("32,48 256x512", window4->bounds().ToString()); |
| |
| // Test4: A single manageable window should get centered. |
| window4.reset(); |
| window1_state->set_bounds_changed_by_user(false); |
| // Trigger the auto window placement function by showing (and hiding) it. |
| window1->Hide(); |
| window1->Show(); |
| // |window1| should be centered. |
| EXPECT_EQ(base::IntToString( |
| (desktop_area.width() - window1->bounds().width()) / 2) + |
| ",32 640x320", |
| window1->bounds().ToString()); |
| } |
| |
| // Test the proper usage of user window movement interaction. |
| TEST_P(WorkspaceControllerTest, TestUserMovedWindowRepositioning) { |
| std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0)); |
| window1->SetBounds(gfx::Rect(16, 32, 640, 320)); |
| gfx::Rect desktop_area = window1->parent()->bounds(); |
| std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1)); |
| window2->SetBounds(gfx::Rect(32, 48, 256, 512)); |
| window1->Hide(); |
| window2->Hide(); |
| wm::WindowState* window1_state = wm::GetWindowState(window1.get()); |
| wm::WindowState* window2_state = wm::GetWindowState(window2.get()); |
| |
| window1_state->set_window_position_managed(true); |
| window2_state->set_window_position_managed(true); |
| EXPECT_FALSE(window1_state->bounds_changed_by_user()); |
| EXPECT_FALSE(window2_state->bounds_changed_by_user()); |
| |
| // Check that the current location gets preserved if the user has |
| // positioned it previously. |
| window1_state->set_bounds_changed_by_user(true); |
| window1->Show(); |
| EXPECT_EQ("16,32 640x320", window1->bounds().ToString()); |
| // Flag should be still set. |
| EXPECT_TRUE(window1_state->bounds_changed_by_user()); |
| EXPECT_FALSE(window2_state->bounds_changed_by_user()); |
| |
| // Turn on the second window and make sure that both windows are now |
| // positionable again (user movement cleared). |
| window2->Show(); |
| |
| // |window1| should be flush left and |window2| flush right. |
| EXPECT_EQ("0,32 640x320", window1->bounds().ToString()); |
| EXPECT_EQ( |
| base::IntToString(desktop_area.width() - window2->bounds().width()) + |
| ",48 256x512", |
| window2->bounds().ToString()); |
| // FLag should now be reset. |
| EXPECT_FALSE(window1_state->bounds_changed_by_user()); |
| EXPECT_FALSE(window2_state->bounds_changed_by_user()); |
| |
| // Going back to one shown window should keep the state. |
| window1_state->set_bounds_changed_by_user(true); |
| window2->Hide(); |
| EXPECT_EQ("0,32 640x320", window1->bounds().ToString()); |
| EXPECT_TRUE(window1_state->bounds_changed_by_user()); |
| } |
| |
| // Test if the single window will be restored at original position. |
| TEST_P(WorkspaceControllerTest, TestSingleWindowsRestoredBounds) { |
| std::unique_ptr<aura::Window> window1( |
| CreateTestWindowInShellWithBounds(gfx::Rect(100, 100, 100, 100))); |
| std::unique_ptr<aura::Window> window2( |
| CreateTestWindowInShellWithBounds(gfx::Rect(110, 110, 100, 100))); |
| std::unique_ptr<aura::Window> window3( |
| CreateTestWindowInShellWithBounds(gfx::Rect(120, 120, 100, 100))); |
| window1->Hide(); |
| window2->Hide(); |
| window3->Hide(); |
| wm::GetWindowState(window1.get())->set_window_position_managed(true); |
| wm::GetWindowState(window2.get())->set_window_position_managed(true); |
| wm::GetWindowState(window3.get())->set_window_position_managed(true); |
| |
| window1->Show(); |
| wm::ActivateWindow(window1.get()); |
| window2->Show(); |
| wm::ActivateWindow(window2.get()); |
| window3->Show(); |
| wm::ActivateWindow(window3.get()); |
| EXPECT_EQ(0, window1->bounds().x()); |
| EXPECT_EQ(window2->GetRootWindow()->bounds().right(), |
| window2->bounds().right()); |
| EXPECT_EQ(0, window3->bounds().x()); |
| |
| window1->Hide(); |
| EXPECT_EQ(window2->GetRootWindow()->bounds().right(), |
| window2->bounds().right()); |
| EXPECT_EQ(0, window3->bounds().x()); |
| |
| // Being a single window will retore the original location. |
| window3->Hide(); |
| wm::ActivateWindow(window2.get()); |
| EXPECT_EQ("110,110 100x100", window2->bounds().ToString()); |
| |
| // Showing the 3rd will push the 2nd window left. |
| window3->Show(); |
| wm::ActivateWindow(window3.get()); |
| EXPECT_EQ(0, window2->bounds().x()); |
| EXPECT_EQ(window3->GetRootWindow()->bounds().right(), |
| window3->bounds().right()); |
| |
| // Being a single window will retore the original location. |
| window2->Hide(); |
| EXPECT_EQ("120,120 100x100", window3->bounds().ToString()); |
| } |
| |
| // Test that user placed windows go back to their user placement after the user |
| // closes all other windows. |
| TEST_P(WorkspaceControllerTest, TestUserHandledWindowRestore) { |
| std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0)); |
| gfx::Rect user_pos = gfx::Rect(16, 42, 640, 320); |
| window1->SetBounds(user_pos); |
| wm::WindowState* window1_state = wm::GetWindowState(window1.get()); |
| |
| window1_state->SetPreAutoManageWindowBounds(user_pos); |
| gfx::Rect desktop_area = window1->parent()->bounds(); |
| |
| // Create a second window to let the auto manager kick in. |
| std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1)); |
| window2->SetBounds(gfx::Rect(32, 48, 256, 512)); |
| window1->Hide(); |
| window2->Hide(); |
| wm::GetWindowState(window1.get())->set_window_position_managed(true); |
| wm::GetWindowState(window2.get())->set_window_position_managed(true); |
| window1->Show(); |
| EXPECT_EQ(user_pos.ToString(), window1->bounds().ToString()); |
| window2->Show(); |
| |
| // |window1| should be flush left and |window2| flush right. |
| EXPECT_EQ("0," + base::IntToString(user_pos.y()) + " 640x320", |
| window1->bounds().ToString()); |
| EXPECT_EQ( |
| base::IntToString(desktop_area.width() - window2->bounds().width()) + |
| ",48 256x512", |
| window2->bounds().ToString()); |
| window2->Hide(); |
| |
| // After the other window get hidden the window has to move back to the |
| // previous position and the bounds should still be set and unchanged. |
| EXPECT_EQ(user_pos.ToString(), window1->bounds().ToString()); |
| ASSERT_TRUE(window1_state->pre_auto_manage_window_bounds()); |
| EXPECT_EQ(user_pos.ToString(), |
| window1_state->pre_auto_manage_window_bounds()->ToString()); |
| } |
| |
| // Solo window should be restored to the bounds where a user moved to. |
| TEST_P(WorkspaceControllerTest, TestRestoreToUserModifiedBounds) { |
| UpdateDisplay("400x300"); |
| gfx::Rect default_bounds(10, 0, 100, 100); |
| std::unique_ptr<aura::Window> window1( |
| CreateTestWindowInShellWithBounds(default_bounds)); |
| wm::WindowState* window1_state = wm::GetWindowState(window1.get()); |
| window1->Hide(); |
| window1_state->set_window_position_managed(true); |
| window1->Show(); |
| // First window is centered. |
| EXPECT_EQ("150,0 100x100", window1->bounds().ToString()); |
| std::unique_ptr<aura::Window> window2( |
| CreateTestWindowInShellWithBounds(default_bounds)); |
| wm::WindowState* window2_state = wm::GetWindowState(window2.get()); |
| window2->Hide(); |
| window2_state->set_window_position_managed(true); |
| window2->Show(); |
| |
| // Auto positioning pushes windows to each sides. |
| EXPECT_EQ("0,0 100x100", window1->bounds().ToString()); |
| EXPECT_EQ("300,0 100x100", window2->bounds().ToString()); |
| |
| window2->Hide(); |
| // Restores to the center. |
| EXPECT_EQ("150,0 100x100", window1->bounds().ToString()); |
| |
| // A user moved the window. |
| std::unique_ptr<WindowResizer> resizer( |
| CreateWindowResizer(WmWindowAura::Get(window1.get()), gfx::Point(), |
| HTCAPTION, aura::client::WINDOW_MOVE_SOURCE_MOUSE) |
| .release()); |
| gfx::Point location = resizer->GetInitialLocation(); |
| location.Offset(-50, 0); |
| resizer->Drag(location, 0); |
| resizer->CompleteDrag(); |
| |
| window1_state->set_bounds_changed_by_user(true); |
| window1->SetBounds(gfx::Rect(100, 0, 100, 100)); |
| |
| window2->Show(); |
| EXPECT_EQ("0,0 100x100", window1->bounds().ToString()); |
| EXPECT_EQ("300,0 100x100", window2->bounds().ToString()); |
| |
| // Window 1 should be restored to the user modified bounds. |
| window2->Hide(); |
| EXPECT_EQ("100,0 100x100", window1->bounds().ToString()); |
| } |
| |
| // Test that a window from normal to minimize will repos the remaining. |
| TEST_P(WorkspaceControllerTest, ToMinimizeRepositionsRemaining) { |
| std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0)); |
| wm::WindowState* window1_state = wm::GetWindowState(window1.get()); |
| window1_state->set_window_position_managed(true); |
| window1->SetBounds(gfx::Rect(16, 32, 640, 320)); |
| gfx::Rect desktop_area = window1->parent()->bounds(); |
| |
| std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1)); |
| wm::WindowState* window2_state = wm::GetWindowState(window2.get()); |
| window2_state->set_window_position_managed(true); |
| window2->SetBounds(gfx::Rect(32, 48, 256, 512)); |
| |
| window1_state->Minimize(); |
| |
| // |window2| should be centered now. |
| EXPECT_TRUE(window2->IsVisible()); |
| EXPECT_TRUE(window2_state->IsNormalStateType()); |
| EXPECT_EQ(base::IntToString( |
| (desktop_area.width() - window2->bounds().width()) / 2) + |
| ",48 256x512", |
| window2->bounds().ToString()); |
| |
| window1_state->Restore(); |
| // |window1| should be flush right and |window3| flush left. |
| EXPECT_EQ( |
| base::IntToString(desktop_area.width() - window1->bounds().width()) + |
| ",32 640x320", |
| window1->bounds().ToString()); |
| EXPECT_EQ("0,48 256x512", window2->bounds().ToString()); |
| } |
| |
| // Test that minimizing an initially maximized window will repos the remaining. |
| TEST_P(WorkspaceControllerTest, MaxToMinRepositionsRemaining) { |
| std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0)); |
| wm::WindowState* window1_state = wm::GetWindowState(window1.get()); |
| window1_state->set_window_position_managed(true); |
| gfx::Rect desktop_area = window1->parent()->bounds(); |
| |
| std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1)); |
| wm::WindowState* window2_state = wm::GetWindowState(window2.get()); |
| window2_state->set_window_position_managed(true); |
| window2->SetBounds(gfx::Rect(32, 48, 256, 512)); |
| |
| window1_state->Maximize(); |
| window1_state->Minimize(); |
| |
| // |window2| should be centered now. |
| EXPECT_TRUE(window2->IsVisible()); |
| EXPECT_TRUE(window2_state->IsNormalStateType()); |
| EXPECT_EQ(base::IntToString( |
| (desktop_area.width() - window2->bounds().width()) / 2) + |
| ",48 256x512", |
| window2->bounds().ToString()); |
| } |
| |
| // Test that nomral, maximize, minimizing will repos the remaining. |
| TEST_P(WorkspaceControllerTest, NormToMaxToMinRepositionsRemaining) { |
| std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0)); |
| window1->SetBounds(gfx::Rect(16, 32, 640, 320)); |
| wm::WindowState* window1_state = wm::GetWindowState(window1.get()); |
| window1_state->set_window_position_managed(true); |
| gfx::Rect desktop_area = window1->parent()->bounds(); |
| |
| std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1)); |
| wm::WindowState* window2_state = wm::GetWindowState(window2.get()); |
| window2_state->set_window_position_managed(true); |
| window2->SetBounds(gfx::Rect(32, 40, 256, 512)); |
| |
| // Trigger the auto window placement function by showing (and hiding) it. |
| window1->Hide(); |
| window1->Show(); |
| |
| // |window1| should be flush right and |window3| flush left. |
| EXPECT_EQ( |
| base::IntToString(desktop_area.width() - window1->bounds().width()) + |
| ",32 640x320", |
| window1->bounds().ToString()); |
| EXPECT_EQ("0,40 256x512", window2->bounds().ToString()); |
| |
| window1_state->Maximize(); |
| window1_state->Minimize(); |
| |
| // |window2| should be centered now. |
| EXPECT_TRUE(window2->IsVisible()); |
| EXPECT_TRUE(window2_state->IsNormalStateType()); |
| EXPECT_EQ(base::IntToString( |
| (desktop_area.width() - window2->bounds().width()) / 2) + |
| ",40 256x512", |
| window2->bounds().ToString()); |
| } |
| |
| // Test that nomral, maximize, normal will repos the remaining. |
| TEST_P(WorkspaceControllerTest, NormToMaxToNormRepositionsRemaining) { |
| std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0)); |
| window1->SetBounds(gfx::Rect(16, 32, 640, 320)); |
| wm::WindowState* window1_state = wm::GetWindowState(window1.get()); |
| window1_state->set_window_position_managed(true); |
| gfx::Rect desktop_area = window1->parent()->bounds(); |
| |
| std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1)); |
| wm::GetWindowState(window2.get())->set_window_position_managed(true); |
| window2->SetBounds(gfx::Rect(32, 40, 256, 512)); |
| |
| // Trigger the auto window placement function by showing (and hiding) it. |
| window1->Hide(); |
| window1->Show(); |
| |
| // |window1| should be flush right and |window3| flush left. |
| EXPECT_EQ( |
| base::IntToString(desktop_area.width() - window1->bounds().width()) + |
| ",32 640x320", |
| window1->bounds().ToString()); |
| EXPECT_EQ("0,40 256x512", window2->bounds().ToString()); |
| |
| window1_state->Maximize(); |
| window1_state->Restore(); |
| |
| // |window1| should be flush right and |window2| flush left. |
| EXPECT_EQ( |
| base::IntToString(desktop_area.width() - window1->bounds().width()) + |
| ",32 640x320", |
| window1->bounds().ToString()); |
| EXPECT_EQ("0,40 256x512", window2->bounds().ToString()); |
| } |
| |
| // Test that animations are triggered. |
| TEST_P(WorkspaceControllerTest, AnimatedNormToMaxToNormRepositionsRemaining) { |
| ui::ScopedAnimationDurationScaleMode test_duration_mode( |
| ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); |
| std::unique_ptr<aura::Window> window1(CreateTestWindowInShellWithId(0)); |
| window1->Hide(); |
| window1->SetBounds(gfx::Rect(16, 32, 640, 320)); |
| gfx::Rect desktop_area = window1->parent()->bounds(); |
| std::unique_ptr<aura::Window> window2(CreateTestWindowInShellWithId(1)); |
| window2->Hide(); |
| window2->SetBounds(gfx::Rect(32, 48, 256, 512)); |
| |
| wm::GetWindowState(window1.get())->set_window_position_managed(true); |
| wm::GetWindowState(window2.get())->set_window_position_managed(true); |
| // Make sure nothing is animating. |
| window1->layer()->GetAnimator()->StopAnimating(); |
| window2->layer()->GetAnimator()->StopAnimating(); |
| window2->Show(); |
| |
| // The second window should now animate. |
| EXPECT_FALSE(window1->layer()->GetAnimator()->is_animating()); |
| EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating()); |
| window2->layer()->GetAnimator()->StopAnimating(); |
| |
| window1->Show(); |
| EXPECT_TRUE(window1->layer()->GetAnimator()->is_animating()); |
| EXPECT_TRUE(window2->layer()->GetAnimator()->is_animating()); |
| |
| window1->layer()->GetAnimator()->StopAnimating(); |
| window2->layer()->GetAnimator()->StopAnimating(); |
| // |window1| should be flush right and |window2| flush left. |
| EXPECT_EQ( |
| base::IntToString(desktop_area.width() - window1->bounds().width()) + |
| ",32 640x320", |
| window1->bounds().ToString()); |
| EXPECT_EQ("0,48 256x512", window2->bounds().ToString()); |
| } |
| |
| // This tests simulates a browser and an app and verifies the ordering of the |
| // windows and layers doesn't get out of sync as various operations occur. Its |
| // really testing code in FocusController, but easier to simulate here. Just as |
| // with a real browser the browser here has a transient child window |
| // (corresponds to the status bubble). |
| TEST_P(WorkspaceControllerTest, VerifyLayerOrdering) { |
| std::unique_ptr<Window> browser(aura::test::CreateTestWindowWithDelegate( |
| NULL, ui::wm::WINDOW_TYPE_NORMAL, gfx::Rect(5, 6, 7, 8), NULL)); |
| browser->SetName("browser"); |
| ParentWindowInPrimaryRootWindow(browser.get()); |
| browser->Show(); |
| wm::ActivateWindow(browser.get()); |
| |
| // |status_bubble| is made a transient child of |browser| and as a result |
| // owned by |browser|. |
| aura::test::TestWindowDelegate* status_bubble_delegate = |
| aura::test::TestWindowDelegate::CreateSelfDestroyingDelegate(); |
| status_bubble_delegate->set_can_focus(false); |
| Window* status_bubble = aura::test::CreateTestWindowWithDelegate( |
| status_bubble_delegate, ui::wm::WINDOW_TYPE_POPUP, gfx::Rect(5, 6, 7, 8), |
| NULL); |
| ::wm::AddTransientChild(browser.get(), status_bubble); |
| ParentWindowInPrimaryRootWindow(status_bubble); |
| status_bubble->SetName("status_bubble"); |
| |
| std::unique_ptr<Window> app(aura::test::CreateTestWindowWithDelegate( |
| NULL, ui::wm::WINDOW_TYPE_NORMAL, gfx::Rect(5, 6, 7, 8), NULL)); |
| app->SetName("app"); |
| ParentWindowInPrimaryRootWindow(app.get()); |
| |
| aura::Window* parent = browser->parent(); |
| |
| app->Show(); |
| wm::ActivateWindow(app.get()); |
| EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent)); |
| |
| // Minimize the app, focus should go the browser. |
| app->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); |
| EXPECT_TRUE(wm::IsActiveWindow(browser.get())); |
| EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent)); |
| |
| // Minimize the browser (neither windows are focused). |
| browser->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_MINIMIZED); |
| EXPECT_FALSE(wm::IsActiveWindow(browser.get())); |
| EXPECT_FALSE(wm::IsActiveWindow(app.get())); |
| EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent)); |
| |
| // Show the browser (which should restore it). |
| browser->Show(); |
| EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent)); |
| |
| // Activate the browser. |
| ash::wm::ActivateWindow(browser.get()); |
| EXPECT_TRUE(wm::IsActiveWindow(browser.get())); |
| EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent)); |
| |
| // Restore the app. This differs from above code for |browser| as internally |
| // the app code does this. Restoring this way or using Show() should not make |
| // a difference. |
| app->SetProperty(aura::client::kShowStateKey, ui::SHOW_STATE_NORMAL); |
| EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent)); |
| |
| // Activate the app. |
| ash::wm::ActivateWindow(app.get()); |
| EXPECT_TRUE(wm::IsActiveWindow(app.get())); |
| EXPECT_EQ(GetWindowNames(parent), GetLayerNames(parent)); |
| } |
| |
| namespace { |
| |
| // Used by DragMaximizedNonTrackedWindow to track how many times the window |
| // hierarchy changes affecting the specified window. |
| class DragMaximizedNonTrackedWindowObserver : public aura::WindowObserver { |
| public: |
| DragMaximizedNonTrackedWindowObserver(aura::Window* window) |
| : change_count_(0), window_(window) {} |
| |
| // Number of times OnWindowHierarchyChanged() has been received. |
| void clear_change_count() { change_count_ = 0; } |
| int change_count() const { return change_count_; } |
| |
| // aura::WindowObserver overrides: |
| // Counts number of times a window is reparented. Ignores reparenting into and |
| // from a docked container which is expected when a tab is dragged. |
| void OnWindowHierarchyChanged(const HierarchyChangeParams& params) override { |
| if (params.target != window_ || |
| (params.old_parent->id() == kShellWindowId_DefaultContainer && |
| params.new_parent->id() == kShellWindowId_DockedContainer) || |
| (params.old_parent->id() == kShellWindowId_DockedContainer && |
| params.new_parent->id() == kShellWindowId_DefaultContainer)) { |
| return; |
| } |
| change_count_++; |
| } |
| |
| private: |
| int change_count_; |
| aura::Window* window_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DragMaximizedNonTrackedWindowObserver); |
| }; |
| |
| } // namespace |
| |
| // Verifies that a new maximized window becomes visible after its activation |
| // is requested, even though it does not become activated because a system |
| // modal window is active. |
| TEST_P(WorkspaceControllerTest, SwitchFromModal) { |
| std::unique_ptr<Window> modal_window(CreateTestWindowUnparented()); |
| modal_window->SetBounds(gfx::Rect(10, 11, 21, 22)); |
| modal_window->SetProperty(aura::client::kModalKey, ui::MODAL_TYPE_SYSTEM); |
| ParentWindowInPrimaryRootWindow(modal_window.get()); |
| modal_window->Show(); |
| wm::ActivateWindow(modal_window.get()); |
| |
| std::unique_ptr<Window> maximized_window(CreateTestWindow()); |
| maximized_window->SetProperty(aura::client::kShowStateKey, |
| ui::SHOW_STATE_MAXIMIZED); |
| maximized_window->Show(); |
| wm::ActivateWindow(maximized_window.get()); |
| EXPECT_TRUE(maximized_window->IsVisible()); |
| } |
| |
| namespace { |
| |
| // Subclass of WorkspaceControllerTest that runs tests with docked windows |
| // enabled and disabled. |
| class WorkspaceControllerTestDragging : public WorkspaceControllerTest { |
| public: |
| WorkspaceControllerTestDragging() {} |
| ~WorkspaceControllerTestDragging() override {} |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(WorkspaceControllerTestDragging); |
| }; |
| |
| } // namespace |
| |
| // Verifies that when dragging a window over the shelf overlap is detected |
| // during and after the drag. |
| TEST_P(WorkspaceControllerTestDragging, DragWindowOverlapShelf) { |
| aura::test::TestWindowDelegate delegate; |
| delegate.set_window_component(HTCAPTION); |
| std::unique_ptr<Window> w1(aura::test::CreateTestWindowWithDelegate( |
| &delegate, ui::wm::WINDOW_TYPE_NORMAL, gfx::Rect(5, 5, 100, 50), NULL)); |
| ParentWindowInPrimaryRootWindow(w1.get()); |
| |
| GetPrimaryShelf()->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_NEVER); |
| |
| // Drag near the shelf. |
| ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), |
| gfx::Point()); |
| generator.MoveMouseTo(10, 10); |
| generator.PressLeftButton(); |
| generator.MoveMouseTo(100, shelf_layout_manager()->GetIdealBounds().y() - 70); |
| |
| // Shelf should not be in overlapped state. |
| EXPECT_FALSE(GetWindowOverlapsShelf()); |
| |
| generator.MoveMouseTo(100, shelf_layout_manager()->GetIdealBounds().y() - 20); |
| |
| // Shelf should detect overlap. Overlap state stays after mouse is released. |
| EXPECT_TRUE(GetWindowOverlapsShelf()); |
| generator.ReleaseLeftButton(); |
| EXPECT_TRUE(GetWindowOverlapsShelf()); |
| } |
| |
| // Verifies that when dragging a window autohidden shelf stays hidden during |
| // and after the drag. |
| TEST_P(WorkspaceControllerTestDragging, DragWindowKeepsShelfAutohidden) { |
| aura::test::TestWindowDelegate delegate; |
| delegate.set_window_component(HTCAPTION); |
| std::unique_ptr<Window> w1(aura::test::CreateTestWindowWithDelegate( |
| &delegate, ui::wm::WINDOW_TYPE_NORMAL, gfx::Rect(5, 5, 100, 50), NULL)); |
| ParentWindowInPrimaryRootWindow(w1.get()); |
| |
| WmShelf* shelf = GetPrimaryShelf(); |
| shelf->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); |
| EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState()); |
| |
| // Drag very little. |
| ui::test::EventGenerator generator(Shell::GetPrimaryRootWindow(), |
| gfx::Point()); |
| generator.MoveMouseTo(10, 10); |
| generator.PressLeftButton(); |
| generator.MoveMouseTo(12, 12); |
| |
| // Shelf should be hidden during and after the drag. |
| EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState()); |
| generator.ReleaseLeftButton(); |
| EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf->GetAutoHideState()); |
| } |
| |
| // Verifies that events are targeted properly just outside the window edges. |
| TEST_P(WorkspaceControllerTest, WindowEdgeHitTest) { |
| aura::test::TestWindowDelegate d_first, d_second; |
| std::unique_ptr<Window> first(aura::test::CreateTestWindowWithDelegate( |
| &d_first, 123, gfx::Rect(20, 10, 100, 50), NULL)); |
| ParentWindowInPrimaryRootWindow(first.get()); |
| first->Show(); |
| |
| std::unique_ptr<Window> second(aura::test::CreateTestWindowWithDelegate( |
| &d_second, 234, gfx::Rect(30, 40, 40, 10), NULL)); |
| ParentWindowInPrimaryRootWindow(second.get()); |
| second->Show(); |
| |
| ui::EventTarget* root = first->GetRootWindow(); |
| ui::EventTargeter* targeter = root->GetEventTargeter(); |
| |
| // The windows overlap, and |second| is on top of |first|. Events targeted |
| // slightly outside the edges of the |second| window should still be targeted |
| // to |second| to allow resizing the windows easily. |
| |
| const int kNumPoints = 4; |
| struct { |
| const char* direction; |
| gfx::Point location; |
| } points[kNumPoints] = { |
| {"left", gfx::Point(28, 45)}, // outside the left edge. |
| {"top", gfx::Point(50, 38)}, // outside the top edge. |
| {"right", gfx::Point(72, 45)}, // outside the right edge. |
| {"bottom", gfx::Point(50, 52)}, // outside the bottom edge. |
| }; |
| // Do two iterations, first without any transform on |second|, and the second |
| // time after applying some transform on |second| so that it doesn't get |
| // targeted. |
| for (int times = 0; times < 2; ++times) { |
| SCOPED_TRACE(times == 0 ? "Without transform" : "With transform"); |
| aura::Window* expected_target = times == 0 ? second.get() : first.get(); |
| for (int i = 0; i < kNumPoints; ++i) { |
| SCOPED_TRACE(points[i].direction); |
| const gfx::Point& location = points[i].location; |
| ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, location, location, |
| ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE); |
| ui::EventTarget* target = targeter->FindTargetForEvent(root, &mouse); |
| EXPECT_EQ(expected_target, target); |
| |
| ui::TouchEvent touch(ui::ET_TOUCH_PRESSED, location, 0, |
| ui::EventTimeForNow()); |
| target = targeter->FindTargetForEvent(root, &touch); |
| EXPECT_EQ(expected_target, target); |
| } |
| // Apply a transform on |second|. After the transform is applied, the window |
| // should no longer be targeted. |
| gfx::Transform transform; |
| transform.Translate(70, 40); |
| second->SetTransform(transform); |
| } |
| } |
| |
| // Verifies mouse event targeting just outside the window edges for panels. |
| TEST_P(WorkspaceControllerTest, WindowEdgeMouseHitTestPanel) { |
| aura::test::TestWindowDelegate delegate; |
| std::unique_ptr<Window> window( |
| CreateTestPanel(&delegate, gfx::Rect(20, 10, 100, 50))); |
| ui::EventTarget* root = window->GetRootWindow(); |
| ui::EventTargeter* targeter = root->GetEventTargeter(); |
| const gfx::Rect bounds = window->bounds(); |
| const int kNumPoints = 5; |
| struct { |
| const char* direction; |
| gfx::Point location; |
| bool is_target_hit; |
| } points[kNumPoints] = { |
| {"left", gfx::Point(bounds.x() - 2, bounds.y() + 10), true}, |
| {"top", gfx::Point(bounds.x() + 10, bounds.y() - 2), true}, |
| {"right", gfx::Point(bounds.right() + 2, bounds.y() + 10), true}, |
| {"bottom", gfx::Point(bounds.x() + 10, bounds.bottom() + 2), true}, |
| {"outside", gfx::Point(bounds.x() + 10, bounds.y() - 31), false}, |
| }; |
| for (int i = 0; i < kNumPoints; ++i) { |
| SCOPED_TRACE(points[i].direction); |
| const gfx::Point& location = points[i].location; |
| ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, location, location, |
| ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE); |
| ui::EventTarget* target = targeter->FindTargetForEvent(root, &mouse); |
| if (points[i].is_target_hit) |
| EXPECT_EQ(window.get(), target); |
| else |
| EXPECT_NE(window.get(), target); |
| } |
| } |
| |
| // Verifies touch event targeting just outside the window edges for panels. |
| // The shelf is aligned to the bottom by default, and so touches just below |
| // the bottom edge of the panel should not target the panel itself because |
| // an AttachedPanelWindowTargeter is installed on the panel container. |
| TEST_P(WorkspaceControllerTest, WindowEdgeTouchHitTestPanel) { |
| aura::test::TestWindowDelegate delegate; |
| std::unique_ptr<Window> window( |
| CreateTestPanel(&delegate, gfx::Rect(20, 10, 100, 50))); |
| ui::EventTarget* root = window->GetRootWindow(); |
| ui::EventTargeter* targeter = root->GetEventTargeter(); |
| const gfx::Rect bounds = window->bounds(); |
| const int kNumPoints = 5; |
| struct { |
| const char* direction; |
| gfx::Point location; |
| bool is_target_hit; |
| } points[kNumPoints] = { |
| {"left", gfx::Point(bounds.x() - 2, bounds.y() + 10), true}, |
| {"top", gfx::Point(bounds.x() + 10, bounds.y() - 2), true}, |
| {"right", gfx::Point(bounds.right() + 2, bounds.y() + 10), true}, |
| {"bottom", gfx::Point(bounds.x() + 10, bounds.bottom() + 2), false}, |
| {"outside", gfx::Point(bounds.x() + 10, bounds.y() - 31), false}, |
| }; |
| for (int i = 0; i < kNumPoints; ++i) { |
| SCOPED_TRACE(points[i].direction); |
| const gfx::Point& location = points[i].location; |
| ui::TouchEvent touch(ui::ET_TOUCH_PRESSED, location, 0, |
| ui::EventTimeForNow()); |
| ui::EventTarget* target = targeter->FindTargetForEvent(root, &touch); |
| if (points[i].is_target_hit) |
| EXPECT_EQ(window.get(), target); |
| else |
| EXPECT_NE(window.get(), target); |
| } |
| } |
| |
| // Verifies events targeting just outside the window edges for docked windows. |
| TEST_P(WorkspaceControllerTest, WindowEdgeHitTestDocked) { |
| aura::test::TestWindowDelegate delegate; |
| // Make window smaller than the minimum docked area so that the window edges |
| // are exposed. |
| delegate.set_maximum_size(gfx::Size(180, 200)); |
| std::unique_ptr<Window> window(aura::test::CreateTestWindowWithDelegate( |
| &delegate, 123, gfx::Rect(20, 10, 100, 50), NULL)); |
| ParentWindowInPrimaryRootWindow(window.get()); |
| aura::Window* docked_container = Shell::GetContainer( |
| window->GetRootWindow(), kShellWindowId_DockedContainer); |
| docked_container->AddChild(window.get()); |
| window->Show(); |
| ui::EventTarget* root = window->GetRootWindow(); |
| ui::EventTargeter* targeter = root->GetEventTargeter(); |
| const gfx::Rect bounds = window->bounds(); |
| const int kNumPoints = 5; |
| struct { |
| const char* direction; |
| gfx::Point location; |
| bool is_target_hit; |
| } points[kNumPoints] = { |
| {"left", gfx::Point(bounds.x() - 2, bounds.y() + 10), true}, |
| {"top", gfx::Point(bounds.x() + 10, bounds.y() - 2), true}, |
| {"right", gfx::Point(bounds.right() + 2, bounds.y() + 10), true}, |
| {"bottom", gfx::Point(bounds.x() + 10, bounds.bottom() + 2), true}, |
| {"outside", gfx::Point(bounds.x() + 10, bounds.y() - 31), false}, |
| }; |
| for (int i = 0; i < kNumPoints; ++i) { |
| SCOPED_TRACE(points[i].direction); |
| const gfx::Point& location = points[i].location; |
| ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, location, location, |
| ui::EventTimeForNow(), ui::EF_NONE, ui::EF_NONE); |
| ui::EventTarget* target = targeter->FindTargetForEvent(root, &mouse); |
| if (points[i].is_target_hit) |
| EXPECT_EQ(window.get(), target); |
| else |
| EXPECT_NE(window.get(), target); |
| |
| ui::TouchEvent touch(ui::ET_TOUCH_PRESSED, location, 0, |
| ui::EventTimeForNow()); |
| target = targeter->FindTargetForEvent(root, &touch); |
| if (points[i].is_target_hit) |
| EXPECT_EQ(window.get(), target); |
| else |
| EXPECT_NE(window.get(), target); |
| } |
| } |
| |
| } // namespace ash |