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