- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / panels / base_panel_browser_test.cc
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 }