1 // Copyright (c) 2012 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 "chrome/browser/ui/panels/base_panel_browser_test.h" 6 7 #include "base/bind.h" 8 #include "base/command_line.h" 9 #include "base/memory/weak_ptr.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/path_service.h" 12 #include "base/strings/string_number_conversions.h" 13 #include "chrome/browser/chrome_notification_types.h" 14 #include "chrome/browser/extensions/extension_service.h" 15 #include "chrome/browser/profiles/profile.h" 16 #include "chrome/browser/ui/browser.h" 17 #include "chrome/browser/ui/browser_window.h" 18 #include "chrome/browser/ui/panels/detached_panel_collection.h" 19 #include "chrome/browser/ui/panels/native_panel.h" 20 #include "chrome/browser/ui/panels/panel_collection.h" 21 #include "chrome/browser/ui/panels/panel_mouse_watcher.h" 22 #include "chrome/browser/ui/panels/stacked_panel_collection.h" 23 #include "chrome/browser/ui/panels/test_panel_active_state_observer.h" 24 #include "chrome/browser/ui/panels/test_panel_mouse_watcher.h" 25 #include "chrome/common/chrome_paths.h" 26 #include "chrome/common/chrome_switches.h" 27 #include "chrome/test/base/interactive_test_utils.h" 28 #include "chrome/test/base/ui_test_utils.h" 29 #include "content/public/browser/notification_service.h" 30 #include "content/public/common/url_constants.h" 31 #include "content/public/test/web_contents_tester.h" 32 #include "extensions/browser/extension_prefs.h" 33 #include "extensions/browser/install_flag.h" 34 #include "extensions/common/manifest_constants.h" 35 #include "sync/api/string_ordinal.h" 36 37 #if defined(OS_LINUX) 38 #include "chrome/browser/ui/browser_window.h" 39 #include "ui/base/x/x11_util.h" 40 #endif 41 42 #if defined(OS_MACOSX) 43 #include "base/mac/scoped_nsautorelease_pool.h" 44 #include "chrome/browser/ui/cocoa/run_loop_testing.h" 45 #endif 46 47 using content::WebContentsTester; 48 using extensions::Extension; 49 50 namespace { 51 52 const gfx::Rect kTestingPrimaryDisplayArea = gfx::Rect(0, 0, 800, 600); 53 const gfx::Rect kTestingPrimaryWorkArea = gfx::Rect(0, 0, 800, 580); 54 55 struct MockDesktopBar { 56 bool auto_hiding_enabled; 57 DisplaySettingsProvider::DesktopBarVisibility visibility; 58 int thickness; 59 }; 60 61 class MockDisplaySettingsProviderImpl : 62 public BasePanelBrowserTest::MockDisplaySettingsProvider { 63 public: 64 explicit MockDisplaySettingsProviderImpl(); 65 virtual ~MockDisplaySettingsProviderImpl() { } 66 67 // Overridden from DisplaySettingsProvider: 68 virtual gfx::Rect GetPrimaryDisplayArea() const OVERRIDE; 69 virtual gfx::Rect GetPrimaryWorkArea() const OVERRIDE; 70 virtual gfx::Rect GetDisplayAreaMatching( 71 const gfx::Rect& bounds) const OVERRIDE; 72 virtual gfx::Rect GetWorkAreaMatching( 73 const gfx::Rect& bounds) const OVERRIDE; 74 virtual bool IsAutoHidingDesktopBarEnabled( 75 DesktopBarAlignment alignment) OVERRIDE; 76 virtual int GetDesktopBarThickness( 77 DesktopBarAlignment alignment) const OVERRIDE; 78 virtual DesktopBarVisibility GetDesktopBarVisibility( 79 DesktopBarAlignment alignment) const OVERRIDE; 80 virtual bool IsFullScreen() OVERRIDE; 81 82 // Overridden from MockDisplaySettingsProvider: 83 virtual void SetPrimaryDisplay( 84 const gfx::Rect& display_area, const gfx::Rect& work_area) OVERRIDE; 85 virtual void SetSecondaryDisplay( 86 const gfx::Rect& display_area, const gfx::Rect& work_area) OVERRIDE; 87 virtual void EnableAutoHidingDesktopBar(DesktopBarAlignment alignment, 88 bool enabled, 89 int thickness) OVERRIDE; 90 virtual void SetDesktopBarVisibility( 91 DesktopBarAlignment alignment, DesktopBarVisibility visibility) OVERRIDE; 92 virtual void SetDesktopBarThickness(DesktopBarAlignment alignment, 93 int thickness) OVERRIDE; 94 virtual void EnableFullScreenMode(bool enabled) OVERRIDE; 95 96 private: 97 gfx::Rect primary_display_area_; 98 gfx::Rect primary_work_area_; 99 gfx::Rect secondary_display_area_; 100 gfx::Rect secondary_work_area_; 101 MockDesktopBar mock_desktop_bars[3]; 102 bool full_screen_enabled_; 103 104 DISALLOW_COPY_AND_ASSIGN(MockDisplaySettingsProviderImpl); 105 }; 106 107 108 MockDisplaySettingsProviderImpl::MockDisplaySettingsProviderImpl() 109 : full_screen_enabled_(false) { 110 memset(mock_desktop_bars, 0, sizeof(mock_desktop_bars)); 111 } 112 113 gfx::Rect MockDisplaySettingsProviderImpl::GetPrimaryDisplayArea() const { 114 return primary_display_area_; 115 } 116 117 gfx::Rect MockDisplaySettingsProviderImpl::GetPrimaryWorkArea() const { 118 return primary_work_area_; 119 } 120 121 gfx::Rect MockDisplaySettingsProviderImpl::GetDisplayAreaMatching( 122 const gfx::Rect& bounds) const { 123 if (secondary_display_area_.IsEmpty()) 124 return primary_display_area_; 125 126 gfx::Rect primary_intersection = 127 gfx::IntersectRects(bounds, primary_display_area_); 128 int primary_intersection_size = 129 primary_intersection.width() * primary_intersection.height(); 130 131 gfx::Rect secondary_intersection = 132 gfx::IntersectRects(bounds, secondary_display_area_); 133 int secondary_intersection_size = 134 secondary_intersection.width() * secondary_intersection.height(); 135 136 return primary_intersection_size >= secondary_intersection_size ? 137 primary_display_area_ : secondary_display_area_; 138 } 139 140 gfx::Rect MockDisplaySettingsProviderImpl::GetWorkAreaMatching( 141 const gfx::Rect& bounds) const { 142 if (secondary_work_area_.IsEmpty()) 143 return primary_work_area_; 144 145 gfx::Rect primary_intersection = 146 gfx::IntersectRects(bounds, primary_work_area_); 147 int primary_intersection_size = 148 primary_intersection.width() * primary_intersection.height(); 149 150 gfx::Rect secondary_intersection = 151 gfx::IntersectRects(bounds, secondary_work_area_); 152 int secondary_intersection_size = 153 secondary_intersection.width() * secondary_intersection.height(); 154 155 return primary_intersection_size >= secondary_intersection_size ? 156 primary_work_area_ : secondary_work_area_; 157 } 158 159 bool MockDisplaySettingsProviderImpl::IsAutoHidingDesktopBarEnabled( 160 DesktopBarAlignment alignment) { 161 return mock_desktop_bars[static_cast<int>(alignment)].auto_hiding_enabled; 162 } 163 164 int MockDisplaySettingsProviderImpl::GetDesktopBarThickness( 165 DesktopBarAlignment alignment) const { 166 return mock_desktop_bars[static_cast<int>(alignment)].thickness; 167 } 168 169 DisplaySettingsProvider::DesktopBarVisibility 170 MockDisplaySettingsProviderImpl::GetDesktopBarVisibility( 171 DesktopBarAlignment alignment) const { 172 return mock_desktop_bars[static_cast<int>(alignment)].visibility; 173 } 174 175 bool MockDisplaySettingsProviderImpl::IsFullScreen() { 176 return full_screen_enabled_; 177 } 178 179 void MockDisplaySettingsProviderImpl::EnableAutoHidingDesktopBar( 180 DesktopBarAlignment alignment, bool enabled, int thickness) { 181 MockDesktopBar* bar = &(mock_desktop_bars[static_cast<int>(alignment)]); 182 bar->auto_hiding_enabled = enabled; 183 bar->thickness = thickness; 184 } 185 186 void MockDisplaySettingsProviderImpl::SetPrimaryDisplay( 187 const gfx::Rect& display_area, const gfx::Rect& work_area) { 188 DCHECK(display_area.Contains(work_area)); 189 primary_display_area_ = display_area; 190 primary_work_area_ = work_area; 191 OnDisplaySettingsChanged(); 192 } 193 194 void MockDisplaySettingsProviderImpl::SetSecondaryDisplay( 195 const gfx::Rect& display_area, const gfx::Rect& work_area) { 196 DCHECK(display_area.Contains(work_area)); 197 secondary_display_area_ = display_area; 198 secondary_work_area_ = work_area; 199 OnDisplaySettingsChanged(); 200 } 201 202 void MockDisplaySettingsProviderImpl::SetDesktopBarVisibility( 203 DesktopBarAlignment alignment, DesktopBarVisibility visibility) { 204 MockDesktopBar* bar = &(mock_desktop_bars[static_cast<int>(alignment)]); 205 if (!bar->auto_hiding_enabled) 206 return; 207 if (visibility == bar->visibility) 208 return; 209 bar->visibility = visibility; 210 FOR_EACH_OBSERVER( 211 DesktopBarObserver, 212 desktop_bar_observers(), 213 OnAutoHidingDesktopBarVisibilityChanged(alignment, visibility)); 214 } 215 216 void MockDisplaySettingsProviderImpl::SetDesktopBarThickness( 217 DesktopBarAlignment alignment, int thickness) { 218 MockDesktopBar* bar = &(mock_desktop_bars[static_cast<int>(alignment)]); 219 if (!bar->auto_hiding_enabled) 220 return; 221 if (thickness == bar->thickness) 222 return; 223 bar->thickness = thickness; 224 FOR_EACH_OBSERVER( 225 DesktopBarObserver, 226 desktop_bar_observers(), 227 OnAutoHidingDesktopBarThicknessChanged(alignment, thickness)); 228 } 229 230 void MockDisplaySettingsProviderImpl::EnableFullScreenMode(bool enabled) { 231 full_screen_enabled_ = enabled; 232 CheckFullScreenMode(PERFORM_FULLSCREEN_CHECK); 233 } 234 235 } // namespace 236 237 const base::FilePath::CharType* BasePanelBrowserTest::kTestDir = 238 FILE_PATH_LITERAL("panels"); 239 240 BasePanelBrowserTest::BasePanelBrowserTest() 241 : InProcessBrowserTest(), 242 mock_display_settings_enabled_(true) { 243 } 244 245 BasePanelBrowserTest::~BasePanelBrowserTest() { 246 } 247 248 bool BasePanelBrowserTest::SkipTestIfIceWM() { 249 #if defined(OS_LINUX) 250 return ui::GuessWindowManager() == ui::WM_ICE_WM; 251 #else 252 return false; 253 #endif 254 } 255 256 bool BasePanelBrowserTest::SkipTestIfCompizWM() { 257 #if defined(OS_LINUX) 258 return ui::GuessWindowManager() == ui::WM_COMPIZ; 259 #else 260 return false; 261 #endif 262 } 263 264 void BasePanelBrowserTest::SetUpCommandLine(CommandLine* command_line) { 265 command_line->AppendSwitch(switches::kEnablePanels); 266 } 267 268 void BasePanelBrowserTest::SetUpOnMainThread() { 269 InProcessBrowserTest::SetUpOnMainThread(); 270 271 // Setup the work area and desktop bar so that we have consistent testing 272 // environment for all panel related tests. 273 if (mock_display_settings_enabled_) { 274 mock_display_settings_provider_ = new MockDisplaySettingsProviderImpl(); 275 mock_display_settings_provider_->SetPrimaryDisplay( 276 kTestingPrimaryDisplayArea, kTestingPrimaryWorkArea); 277 PanelManager::SetDisplaySettingsProviderForTesting( 278 mock_display_settings_provider_); 279 } 280 281 PanelManager* panel_manager = PanelManager::GetInstance(); 282 panel_manager->enable_auto_sizing(false); 283 284 PanelManager::shorten_time_intervals_for_testing(); 285 286 // Simulate the mouse movement so that tests are not affected by actual mouse 287 // events. 288 PanelMouseWatcher* mouse_watcher = new TestPanelMouseWatcher(); 289 panel_manager->SetMouseWatcherForTesting(mouse_watcher); 290 291 // This is needed so the subsequently created panels can be activated. 292 // On a Mac, it transforms background-only test process into foreground one. 293 ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); 294 } 295 296 void BasePanelBrowserTest::WaitForPanelActiveState( 297 Panel* panel, ActiveState expected_state) { 298 DCHECK(expected_state == SHOW_AS_ACTIVE || 299 expected_state == SHOW_AS_INACTIVE); 300 301 #if defined(OS_MACOSX) 302 scoped_ptr<NativePanelTesting> panel_testing( 303 CreateNativePanelTesting(panel)); 304 ASSERT_TRUE(panel_testing->EnsureApplicationRunOnForeground()) << 305 "Failed to bring application to foreground. Bail out."; 306 #endif 307 308 PanelActiveStateObserver signal(panel, expected_state == SHOW_AS_ACTIVE); 309 signal.Wait(); 310 } 311 312 void BasePanelBrowserTest::WaitForWindowSizeAvailable(Panel* panel) { 313 scoped_ptr<NativePanelTesting> panel_testing( 314 CreateNativePanelTesting(panel)); 315 content::WindowedNotificationObserver signal( 316 chrome::NOTIFICATION_PANEL_WINDOW_SIZE_KNOWN, 317 content::Source<Panel>(panel)); 318 if (panel_testing->IsWindowSizeKnown()) 319 return; 320 signal.Wait(); 321 EXPECT_TRUE(panel_testing->IsWindowSizeKnown()); 322 } 323 324 void BasePanelBrowserTest::WaitForBoundsAnimationFinished(Panel* panel) { 325 scoped_ptr<NativePanelTesting> panel_testing( 326 CreateNativePanelTesting(panel)); 327 // Sometimes there are several animations in sequence due to content 328 // auto resizing. Wait for all animations to finish. 329 while (panel_testing->IsAnimatingBounds()) { 330 content::WindowedNotificationObserver signal( 331 chrome::NOTIFICATION_PANEL_BOUNDS_ANIMATIONS_FINISHED, 332 content::Source<Panel>(panel)); 333 if (!panel_testing->IsAnimatingBounds()) 334 return; 335 signal.Wait(); 336 } 337 } 338 339 BasePanelBrowserTest::CreatePanelParams::CreatePanelParams( 340 const std::string& name, 341 const gfx::Rect& bounds, 342 ActiveState show_flag) 343 : name(name), 344 bounds(bounds), 345 show_flag(show_flag), 346 wait_for_fully_created(true), 347 expected_active_state(show_flag), 348 create_mode(PanelManager::CREATE_AS_DOCKED), 349 profile(NULL) { 350 } 351 352 Panel* BasePanelBrowserTest::CreatePanelWithParams( 353 const CreatePanelParams& params) { 354 #if defined(OS_MACOSX) 355 // Opening panels on a Mac causes NSWindowController of the Panel window 356 // to be autoreleased. We need a pool drained after it's done so the test 357 // can close correctly. The NSWindowController of the Panel window controls 358 // lifetime of the Panel object so we want to release it as soon as 359 // possible. In real Chrome, this is done by message pump. 360 // On non-Mac platform, this is an empty class. 361 base::mac::ScopedNSAutoreleasePool autorelease_pool; 362 #endif 363 364 content::WindowedNotificationObserver observer( 365 content::NOTIFICATION_LOAD_STOP, 366 content::NotificationService::AllSources()); 367 368 PanelManager* manager = PanelManager::GetInstance(); 369 Panel* panel = manager->CreatePanel( 370 params.name, 371 params.profile ? params.profile : browser()->profile(), 372 params.url, 373 params.bounds, 374 params.create_mode); 375 376 if (!params.url.is_empty()) 377 observer.Wait(); 378 379 if (!manager->auto_sizing_enabled() || 380 params.bounds.width() || params.bounds.height()) { 381 EXPECT_FALSE(panel->auto_resizable()); 382 } else { 383 EXPECT_TRUE(panel->auto_resizable()); 384 } 385 386 if (params.show_flag == SHOW_AS_ACTIVE) { 387 panel->Show(); 388 } else { 389 panel->ShowInactive(); 390 } 391 392 if (params.wait_for_fully_created) { 393 base::MessageLoopForUI::current()->RunUntilIdle(); 394 395 #if defined(OS_LINUX) 396 // On bots, we might have a simple window manager which always activates new 397 // windows, and can't always deactivate them. Re-activate the main tabbed 398 // browser to "deactivate" the newly created panel. 399 if (params.expected_active_state == SHOW_AS_INACTIVE && 400 ui::GuessWindowManager() == ui::WM_ICE_WM) { 401 // Wait for new panel to become active before deactivating to ensure 402 // the activated notification is consumed before we wait for the panel 403 // to become inactive. 404 WaitForPanelActiveState(panel, SHOW_AS_ACTIVE); 405 browser()->window()->Activate(); 406 } 407 #endif 408 // More waiting, because gaining or losing focus may require inter-process 409 // asynchronous communication, and it is not enough to just run the local 410 // message loop to make sure this activity has completed. 411 WaitForPanelActiveState(panel, params.expected_active_state); 412 413 // On Linux, window size is not available right away and we should wait 414 // before moving forward with the test. 415 WaitForWindowSizeAvailable(panel); 416 417 // Wait for the bounds animations on creation to finish. 418 WaitForBoundsAnimationFinished(panel); 419 } 420 421 return panel; 422 } 423 424 Panel* BasePanelBrowserTest::CreatePanelWithBounds( 425 const std::string& panel_name, const gfx::Rect& bounds) { 426 CreatePanelParams params(panel_name, bounds, SHOW_AS_ACTIVE); 427 return CreatePanelWithParams(params); 428 } 429 430 Panel* BasePanelBrowserTest::CreatePanel(const std::string& panel_name) { 431 CreatePanelParams params(panel_name, gfx::Rect(), SHOW_AS_ACTIVE); 432 return CreatePanelWithParams(params); 433 } 434 435 Panel* BasePanelBrowserTest::CreateDockedPanel(const std::string& name, 436 const gfx::Rect& bounds) { 437 Panel* panel = CreatePanelWithBounds(name, bounds); 438 EXPECT_EQ(PanelCollection::DOCKED, panel->collection()->type()); 439 return panel; 440 } 441 442 Panel* BasePanelBrowserTest::CreateDetachedPanel(const std::string& name, 443 const gfx::Rect& bounds) { 444 Panel* panel = CreatePanelWithBounds(name, bounds); 445 PanelManager* panel_manager = panel->manager(); 446 panel_manager->MovePanelToCollection(panel, 447 panel_manager->detached_collection(), 448 PanelCollection::DEFAULT_POSITION); 449 EXPECT_EQ(PanelCollection::DETACHED, panel->collection()->type()); 450 // The panel is first created as docked panel, which ignores the specified 451 // origin in |bounds|. We need to reposition the panel after it becomes 452 // detached. 453 panel->SetPanelBounds(bounds); 454 WaitForBoundsAnimationFinished(panel); 455 return panel; 456 } 457 458 Panel* BasePanelBrowserTest::CreateStackedPanel(const std::string& name, 459 const gfx::Rect& bounds, 460 StackedPanelCollection* stack) { 461 Panel* panel = CreateDetachedPanel(name, bounds); 462 panel->manager()->MovePanelToCollection( 463 panel, 464 stack, 465 static_cast<PanelCollection::PositioningMask>( 466 PanelCollection::DEFAULT_POSITION | 467 PanelCollection::COLLAPSE_TO_FIT)); 468 EXPECT_EQ(PanelCollection::STACKED, panel->collection()->type()); 469 WaitForBoundsAnimationFinished(panel); 470 return panel; 471 } 472 473 Panel* BasePanelBrowserTest::CreateInactivePanel(const std::string& name) { 474 // Create an active panel first, instead of inactive panel. This is because 475 // certain window managers on Linux, like icewm, will always activate the 476 // new window. 477 Panel* panel = CreatePanel(name); 478 479 DeactivatePanel(panel); 480 WaitForPanelActiveState(panel, SHOW_AS_INACTIVE); 481 482 return panel; 483 } 484 485 Panel* BasePanelBrowserTest::CreateInactiveDockedPanel( 486 const std::string& name, const gfx::Rect& bounds) { 487 // Create an active panel first, instead of inactive panel. This is because 488 // certain window managers on Linux, like icewm, will always activate the 489 // new window. 490 Panel* panel = CreateDockedPanel(name, bounds); 491 492 DeactivatePanel(panel); 493 WaitForPanelActiveState(panel, SHOW_AS_INACTIVE); 494 495 return panel; 496 } 497 498 Panel* BasePanelBrowserTest::CreateInactiveDetachedPanel( 499 const std::string& name, const gfx::Rect& bounds) { 500 // Create an active panel first, instead of inactive panel. This is because 501 // certain window managers on Linux, like icewm, will always activate the 502 // new window. 503 Panel* panel = CreateDetachedPanel(name, bounds); 504 505 DeactivatePanel(panel); 506 WaitForPanelActiveState(panel, SHOW_AS_INACTIVE); 507 508 return panel; 509 } 510 511 void BasePanelBrowserTest::ActivatePanel(Panel* panel) { 512 // For certain window managers on Linux, the window activation/deactivation 513 // signals might not be sent. To work around this, we explicitly deactivate 514 // all other panels first. 515 #if defined(OS_LINUX) 516 std::vector<Panel*> panels = PanelManager::GetInstance()->panels(); 517 for (std::vector<Panel*>::const_iterator iter = panels.begin(); 518 iter != panels.end(); ++iter) { 519 Panel* current_panel = *iter; 520 if (panel != current_panel) 521 current_panel->Deactivate(); 522 } 523 #endif 524 525 panel->Activate(); 526 } 527 528 void BasePanelBrowserTest::DeactivatePanel(Panel* panel) { 529 #if defined(OS_LINUX) 530 // For certain window managers on Linux, like icewm, panel activation and 531 // deactivation notification might not get tiggered when non-panel window is 532 // activated or deactivated. So we deactivate the panel directly. 533 panel->Deactivate(); 534 #else 535 // Make the panel lose focus by activating the browser window. This is 536 // because: 537 // 1) On Windows, deactivating the panel window might cause the application 538 // to lose the foreground status. When this occurs, trying to activate 539 // the panel window again will not be allowed by the system. 540 // 2) On MacOS, deactivating a window is not supported by Cocoa. 541 browser()->window()->Activate(); 542 #endif 543 } 544 545 // static 546 NativePanelTesting* BasePanelBrowserTest::CreateNativePanelTesting( 547 Panel* panel) { 548 return panel->native_panel()->CreateNativePanelTesting(); 549 } 550 551 scoped_refptr<Extension> BasePanelBrowserTest::CreateExtension( 552 const base::FilePath::StringType& path, 553 extensions::Manifest::Location location, 554 const base::DictionaryValue& extra_value) { 555 extensions::ExtensionPrefs* extension_prefs = 556 extensions::ExtensionPrefs::Get(browser()->profile()); 557 base::FilePath full_path = extension_prefs->install_directory().Append(path); 558 559 scoped_ptr<base::DictionaryValue> input_value(extra_value.DeepCopy()); 560 input_value->SetString(extensions::manifest_keys::kVersion, "1.0.0.0"); 561 input_value->SetString(extensions::manifest_keys::kName, "Sample Extension"); 562 563 std::string error; 564 scoped_refptr<Extension> extension = Extension::Create( 565 full_path, location, *input_value, Extension::NO_FLAGS, &error); 566 EXPECT_TRUE(extension.get()); 567 EXPECT_STREQ("", error.c_str()); 568 browser()->profile()->GetExtensionService()->OnExtensionInstalled( 569 extension.get(), 570 syncer::StringOrdinal(), 571 extensions::kInstallFlagInstallImmediately); 572 return extension; 573 } 574 575 void BasePanelBrowserTest::CloseWindowAndWait(Panel* panel) { 576 // Closing a panel may involve several async tasks. Need to use 577 // message pump and wait for the notification. 578 PanelManager* manager = PanelManager::GetInstance(); 579 int panel_count = manager->num_panels(); 580 content::WindowedNotificationObserver signal( 581 chrome::NOTIFICATION_PANEL_CLOSED, 582 content::Source<Panel>(panel)); 583 panel->Close(); 584 signal.Wait(); 585 // Now we have one less panel. 586 EXPECT_EQ(panel_count - 1, manager->num_panels()); 587 588 #if defined(OS_MACOSX) 589 // Mac window controllers may be autoreleased, and in the non-test 590 // environment, may actually depend on the autorelease pool being recycled 591 // with the run loop in order to perform important work. Replicate this in 592 // the test environment. 593 AutoreleasePool()->Recycle(); 594 595 // Make sure that everything has a chance to run. 596 chrome::testing::NSRunLoopRunAllPending(); 597 #endif // OS_MACOSX 598 } 599 600 void BasePanelBrowserTest::MoveMouseAndWaitForExpansionStateChange( 601 Panel* panel, 602 const gfx::Point& position) { 603 content::WindowedNotificationObserver signal( 604 chrome::NOTIFICATION_PANEL_CHANGED_EXPANSION_STATE, 605 content::Source<Panel>(panel)); 606 MoveMouse(position); 607 signal.Wait(); 608 } 609 610 void BasePanelBrowserTest::MoveMouse(const gfx::Point& position) { 611 PanelManager::GetInstance()->mouse_watcher()->NotifyMouseMovement(position); 612 } 613 614 std::string BasePanelBrowserTest::MakePanelName(int index) { 615 std::string panel_name("Panel"); 616 return panel_name + base::IntToString(index); 617 } 618 619 bool BasePanelBrowserTest::WmSupportWindowActivation() { 620 return true; 621 } 622