1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ash/shelf/shelf_widget.h" 6 7 #include "ash/root_window_controller.h" 8 #include "ash/shelf/shelf.h" 9 #include "ash/shelf/shelf_button.h" 10 #include "ash/shelf/shelf_layout_manager.h" 11 #include "ash/shelf/shelf_model.h" 12 #include "ash/shelf/shelf_view.h" 13 #include "ash/shell.h" 14 #include "ash/test/ash_test_base.h" 15 #include "ash/test/shelf_test_api.h" 16 #include "ash/test/shelf_view_test_api.h" 17 #include "ash/wm/window_util.h" 18 #include "ui/aura/window_event_dispatcher.h" 19 #include "ui/events/event_utils.h" 20 #include "ui/gfx/display.h" 21 #include "ui/gfx/screen.h" 22 #include "ui/views/view.h" 23 #include "ui/views/widget/widget.h" 24 25 namespace ash { 26 27 namespace { 28 29 ShelfWidget* GetShelfWidget() { 30 return Shelf::ForPrimaryDisplay()->shelf_widget(); 31 } 32 33 ShelfLayoutManager* GetShelfLayoutManager() { 34 return GetShelfWidget()->shelf_layout_manager(); 35 } 36 37 } // namespace 38 39 typedef test::AshTestBase ShelfWidgetTest; 40 41 void TestLauncherAlignment(aura::Window* root, 42 ShelfAlignment alignment, 43 const std::string& expected) { 44 Shell::GetInstance()->SetShelfAlignment(alignment, root); 45 gfx::Screen* screen = gfx::Screen::GetScreenFor(root); 46 EXPECT_EQ(expected, 47 screen->GetDisplayNearestWindow(root).work_area().ToString()); 48 } 49 50 TEST_F(ShelfWidgetTest, TestAlignment) { 51 Shelf* shelf = Shelf::ForPrimaryDisplay(); 52 UpdateDisplay("400x400"); 53 ASSERT_TRUE(shelf); 54 { 55 SCOPED_TRACE("Single Bottom"); 56 TestLauncherAlignment(Shell::GetPrimaryRootWindow(), 57 SHELF_ALIGNMENT_BOTTOM, 58 "0,0 400x353"); 59 } 60 { 61 SCOPED_TRACE("Single Right"); 62 TestLauncherAlignment(Shell::GetPrimaryRootWindow(), 63 SHELF_ALIGNMENT_RIGHT, 64 "0,0 353x400"); 65 } 66 { 67 SCOPED_TRACE("Single Left"); 68 TestLauncherAlignment(Shell::GetPrimaryRootWindow(), 69 SHELF_ALIGNMENT_LEFT, 70 "47,0 353x400"); 71 } 72 if (!SupportsMultipleDisplays()) 73 return; 74 75 UpdateDisplay("300x300,500x500"); 76 aura::Window::Windows root_windows = Shell::GetAllRootWindows(); 77 { 78 SCOPED_TRACE("Primary Bottom"); 79 TestLauncherAlignment(root_windows[0], 80 SHELF_ALIGNMENT_BOTTOM, 81 "0,0 300x253"); 82 } 83 { 84 SCOPED_TRACE("Primary Right"); 85 TestLauncherAlignment(root_windows[0], 86 SHELF_ALIGNMENT_RIGHT, 87 "0,0 253x300"); 88 } 89 { 90 SCOPED_TRACE("Primary Left"); 91 TestLauncherAlignment(root_windows[0], 92 SHELF_ALIGNMENT_LEFT, 93 "47,0 253x300"); 94 } 95 { 96 SCOPED_TRACE("Secondary Bottom"); 97 TestLauncherAlignment(root_windows[1], 98 SHELF_ALIGNMENT_BOTTOM, 99 "300,0 500x453"); 100 } 101 { 102 SCOPED_TRACE("Secondary Right"); 103 TestLauncherAlignment(root_windows[1], 104 SHELF_ALIGNMENT_RIGHT, 105 "300,0 453x500"); 106 } 107 { 108 SCOPED_TRACE("Secondary Left"); 109 TestLauncherAlignment(root_windows[1], 110 SHELF_ALIGNMENT_LEFT, 111 "347,0 453x500"); 112 } 113 } 114 115 // Makes sure the shelf is initially sized correctly. 116 TEST_F(ShelfWidgetTest, LauncherInitiallySized) { 117 ShelfWidget* shelf_widget = GetShelfWidget(); 118 Shelf* shelf = shelf_widget->shelf(); 119 ASSERT_TRUE(shelf); 120 ShelfLayoutManager* shelf_layout_manager = GetShelfLayoutManager(); 121 ASSERT_TRUE(shelf_layout_manager); 122 ASSERT_TRUE(shelf_widget->status_area_widget()); 123 int status_width = shelf_widget->status_area_widget()-> 124 GetWindowBoundsInScreen().width(); 125 // Test only makes sense if the status is > 0, which it better be. 126 EXPECT_GT(status_width, 0); 127 EXPECT_EQ(status_width, shelf_widget->GetContentsView()->width() - 128 test::ShelfTestAPI(shelf).shelf_view()->width()); 129 } 130 131 // Verifies when the shell is deleted with a full screen window we don't crash. 132 TEST_F(ShelfWidgetTest, DontReferenceShelfAfterDeletion) { 133 views::Widget* widget = new views::Widget; 134 views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); 135 params.bounds = gfx::Rect(0, 0, 200, 200); 136 params.context = CurrentContext(); 137 // Widget is now owned by the parent window. 138 widget->Init(params); 139 widget->SetFullscreen(true); 140 } 141 142 #if defined(OS_CHROMEOS) 143 // Verifies shelf is created with correct size after user login and when its 144 // container and status widget has finished sizing. 145 // See http://crbug.com/252533 146 TEST_F(ShelfWidgetTest, ShelfInitiallySizedAfterLogin) { 147 SetUserLoggedIn(false); 148 UpdateDisplay("300x200,400x300"); 149 150 ShelfWidget* shelf_widget = NULL; 151 Shell::RootWindowControllerList controllers( 152 Shell::GetAllRootWindowControllers()); 153 for (Shell::RootWindowControllerList::const_iterator i = controllers.begin(); 154 i != controllers.end(); 155 ++i) { 156 if (!(*i)->shelf()->shelf()) { 157 shelf_widget = (*i)->shelf(); 158 break; 159 } 160 } 161 ASSERT_TRUE(shelf_widget != NULL); 162 163 SetUserLoggedIn(true); 164 Shell::GetInstance()->CreateShelf(); 165 166 Shelf* shelf = shelf_widget->shelf(); 167 ASSERT_TRUE(shelf != NULL); 168 169 const int status_width = 170 shelf_widget->status_area_widget()->GetWindowBoundsInScreen().width(); 171 EXPECT_GT(status_width, 0); 172 EXPECT_EQ(status_width, 173 shelf_widget->GetContentsView()->width() - 174 test::ShelfTestAPI(shelf).shelf_view()->width()); 175 } 176 #endif // defined(OS_CHROMEOS) 177 178 // Tests that the shelf lets mouse-events close to the edge fall through to the 179 // window underneath. 180 TEST_F(ShelfWidgetTest, ShelfEdgeOverlappingWindowHitTestMouse) { 181 ShelfWidget* shelf_widget = GetShelfWidget(); 182 gfx::Rect shelf_bounds = shelf_widget->GetWindowBoundsInScreen(); 183 EXPECT_TRUE(!shelf_bounds.IsEmpty()); 184 ShelfLayoutManager* shelf_layout_manager = 185 shelf_widget->shelf_layout_manager(); 186 ASSERT_TRUE(shelf_layout_manager); 187 EXPECT_EQ(SHELF_VISIBLE, shelf_layout_manager->visibility_state()); 188 189 // Create a Widget which overlaps with the shelf in the top edge. 190 const int kOverlapSize = 15; 191 const int kWindowHeight = 200; 192 views::Widget* widget = new views::Widget; 193 views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); 194 params.bounds = gfx::Rect(0, shelf_bounds.y() - kWindowHeight + kOverlapSize, 195 200, kWindowHeight); 196 params.context = CurrentContext(); 197 // Widget is now owned by the parent window. 198 widget->Init(params); 199 widget->Show(); 200 gfx::Rect widget_bounds = widget->GetWindowBoundsInScreen(); 201 EXPECT_TRUE(widget_bounds.Intersects(shelf_bounds)); 202 203 204 ui::EventTarget* root = widget->GetNativeWindow()->GetRootWindow(); 205 ui::EventTargeter* targeter = root->GetEventTargeter(); 206 { 207 // Create a mouse-event targetting the top of the shelf widget. The 208 // window-targeter should find |widget| as the target (instead of the 209 // shelf). 210 gfx::Point event_location(20, shelf_bounds.y() + 1); 211 ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, 212 ui::EF_NONE, ui::EF_NONE); 213 ui::EventTarget* target = targeter->FindTargetForEvent(root, &mouse); 214 EXPECT_EQ(widget->GetNativeWindow(), target); 215 } 216 217 // Now auto-hide (hidden) the shelf. 218 shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); 219 shelf_layout_manager->LayoutShelf(); 220 EXPECT_EQ(SHELF_AUTO_HIDE, shelf_layout_manager->visibility_state()); 221 EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_layout_manager->auto_hide_state()); 222 shelf_bounds = shelf_widget->GetWindowBoundsInScreen(); 223 EXPECT_TRUE(!shelf_bounds.IsEmpty()); 224 225 // Move |widget| so it still overlaps the shelf. 226 widget->SetBounds(gfx::Rect(0, shelf_bounds.y() - kWindowHeight + 227 kOverlapSize, 200, kWindowHeight)); 228 widget_bounds = widget->GetWindowBoundsInScreen(); 229 EXPECT_TRUE(widget_bounds.Intersects(shelf_bounds)); 230 { 231 // Create a mouse-event targetting the top of the shelf widget. This time, 232 // window-target should find the shelf as the target. 233 gfx::Point event_location(20, shelf_bounds.y() + 1); 234 ui::MouseEvent mouse(ui::ET_MOUSE_MOVED, event_location, event_location, 235 ui::EF_NONE, ui::EF_NONE); 236 ui::EventTarget* target = targeter->FindTargetForEvent(root, &mouse); 237 EXPECT_EQ(shelf_widget->GetNativeWindow(), target); 238 } 239 } 240 241 // Tests that the shelf has a slightly larger hit-region for touch-events when 242 // it's in the auto-hidden state. 243 TEST_F(ShelfWidgetTest, HiddenShelfHitTestTouch) { 244 ShelfWidget* shelf_widget = GetShelfWidget(); 245 gfx::Rect shelf_bounds = shelf_widget->GetWindowBoundsInScreen(); 246 EXPECT_TRUE(!shelf_bounds.IsEmpty()); 247 ShelfLayoutManager* shelf_layout_manager = 248 shelf_widget->shelf_layout_manager(); 249 ASSERT_TRUE(shelf_layout_manager); 250 EXPECT_EQ(SHELF_VISIBLE, shelf_layout_manager->visibility_state()); 251 252 // Create a widget to make sure that the shelf does auto-hide. 253 views::Widget* widget = new views::Widget; 254 views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); 255 params.bounds = gfx::Rect(0, 0, 200, 200); 256 params.context = CurrentContext(); 257 // Widget is now owned by the parent window. 258 widget->Init(params); 259 widget->Show(); 260 261 ui::EventTarget* root = shelf_widget->GetNativeWindow()->GetRootWindow(); 262 ui::EventTargeter* targeter = root->GetEventTargeter(); 263 // Touch just over the shelf. Since the shelf is visible, the window-targeter 264 // should not find the shelf as the target. 265 { 266 gfx::Point event_location(20, shelf_bounds.y() - 1); 267 ui::TouchEvent touch(ui::ET_TOUCH_PRESSED, event_location, 0, 268 ui::EventTimeForNow()); 269 EXPECT_NE(shelf_widget->GetNativeWindow(), 270 targeter->FindTargetForEvent(root, &touch)); 271 } 272 273 // Now auto-hide (hidden) the shelf. 274 shelf_layout_manager->SetAutoHideBehavior(SHELF_AUTO_HIDE_BEHAVIOR_ALWAYS); 275 shelf_layout_manager->LayoutShelf(); 276 EXPECT_EQ(SHELF_AUTO_HIDE, shelf_layout_manager->visibility_state()); 277 EXPECT_EQ(SHELF_AUTO_HIDE_HIDDEN, shelf_layout_manager->auto_hide_state()); 278 shelf_bounds = shelf_widget->GetWindowBoundsInScreen(); 279 EXPECT_TRUE(!shelf_bounds.IsEmpty()); 280 281 // Touch just over the shelf again. This time, the targeter should find the 282 // shelf as the target. 283 { 284 gfx::Point event_location(20, shelf_bounds.y() - 1); 285 ui::TouchEvent touch(ui::ET_TOUCH_PRESSED, event_location, 0, 286 ui::EventTimeForNow()); 287 EXPECT_EQ(shelf_widget->GetNativeWindow(), 288 targeter->FindTargetForEvent(root, &touch)); 289 } 290 } 291 292 } // namespace ash 293