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