Commit c5439135 authored by dimich@chromium.org's avatar dimich@chromium.org

Implement correct Panel closing sequence for Mac.

Enable PanelBrowserTest.CreatePanelOnOverflow on Mac.

Review URL: http://codereview.chromium.org/7694014

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97736 0039d316-1c4b-4281-b951-d872f2087c98
parent 2b8c0038
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10"> <archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
<data> <data>
<int key="IBDocument.SystemTarget">1050</int> <int key="IBDocument.SystemTarget">1050</int>
<string key="IBDocument.SystemVersion">10J869</string> <string key="IBDocument.SystemVersion">10K549</string>
<string key="IBDocument.InterfaceBuilderVersion">804</string> <string key="IBDocument.InterfaceBuilderVersion">804</string>
<string key="IBDocument.AppKitVersion">1038.35</string> <string key="IBDocument.AppKitVersion">1038.36</string>
<string key="IBDocument.HIToolboxVersion">461.00</string> <string key="IBDocument.HIToolboxVersion">461.00</string>
<object class="NSMutableDictionary" key="IBDocument.PluginVersions"> <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string> <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
<string key="NSClassName">NSApplication</string> <string key="NSClassName">NSApplication</string>
</object> </object>
<object class="NSWindowTemplate" id="1005"> <object class="NSWindowTemplate" id="1005">
<int key="NSWindowStyleMask">1</int> <int key="NSWindowStyleMask">3</int>
<int key="NSWindowBacking">2</int> <int key="NSWindowBacking">2</int>
<string key="NSWindowRect">{{196, 240}, {480, 270}}</string> <string key="NSWindowRect">{{196, 240}, {480, 270}}</string>
<int key="NSWTFlags">544736256</int> <int key="NSWTFlags">544736256</int>
......
...@@ -92,7 +92,14 @@ void Panel::SetBounds(const gfx::Rect& bounds) { ...@@ -92,7 +92,14 @@ void Panel::SetBounds(const gfx::Rect& bounds) {
// close on the first attempt. // close on the first attempt.
void Panel::Close() { void Panel::Close() {
native_panel_->ClosePanel(); native_panel_->ClosePanel();
// TODO(dimich): Only implemented fully async on Mac. Need to update other
// platforms. The panel should be removed from PanelManager when and if it
// was actually closed. The closing can be cancelled because of onbeforeunload
// handler on the web page.
#if !defined(OS_MACOSX)
manager()->Remove(this); manager()->Remove(this);
#endif
} }
void Panel::Activate() { void Panel::Activate() {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/file_path.h" #include "base/file_path.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
...@@ -15,6 +16,7 @@ ...@@ -15,6 +16,7 @@
#include "chrome/browser/ui/panels/panel_manager.h" #include "chrome/browser/ui/panels/panel_manager.h"
#include "chrome/common/chrome_switches.h" #include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
class PanelAppBrowserTest : public ExtensionBrowserTest { class PanelAppBrowserTest : public ExtensionBrowserTest {
...@@ -25,18 +27,45 @@ class PanelAppBrowserTest : public ExtensionBrowserTest { ...@@ -25,18 +27,45 @@ class PanelAppBrowserTest : public ExtensionBrowserTest {
} }
void LoadAndLaunchExtension(const char* name) { void LoadAndLaunchExtension(const char* name) {
ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(name))); // Opening panels on a Mac causes NSWindowController of the Panel window
// to be autoreleased. We need a pool drained after it's done so the test
// can close correctly. The NSWindowController of the Panel window controls
// lifetime of the Browser object so we want to release it as soon as
// possible. In real Chrome, this is done by message pump.
// On non-Mac platform, this is an empty class.
base::mac::ScopedNSAutoreleasePool autorelease_pool;
EXPECT_TRUE(LoadExtension(test_data_dir_.AppendASCII(name)));
ExtensionService* service = browser()->profile()->GetExtensionService(); ExtensionService* service = browser()->profile()->GetExtensionService();
const Extension* extension = service->GetExtensionById( const Extension* extension = service->GetExtensionById(
last_loaded_extension_id_, false); last_loaded_extension_id_, false);
ASSERT_TRUE(extension); EXPECT_TRUE(extension);
size_t browser_count = BrowserList::size();
Browser::OpenApplication( Browser::OpenApplication(
browser()->profile(), browser()->profile(),
extension, extension,
extension_misc::LAUNCH_PANEL, // Override manifest, open in panel. // Overriding manifest to open in a panel.
extension_misc::LAUNCH_PANEL,
NEW_WINDOW); NEW_WINDOW);
// Now we have a new browser instance.
EXPECT_EQ(browser_count + 1, BrowserList::size());
}
void CloseWindowAndWait(Browser* browser) {
// Closing a browser window may involve several async tasks. Need to use
// message pump and wait for the notification.
size_t browser_count = BrowserList::size();
ui_test_utils::WindowedNotificationObserver signal(
chrome::NOTIFICATION_BROWSER_CLOSED,
Source<Browser>(browser));
browser->CloseWindow();
signal.Wait();
// Now we have one less browser instance.
EXPECT_EQ(browser_count - 1, BrowserList::size());
} }
}; };
...@@ -46,7 +75,7 @@ IN_PROC_BROWSER_TEST_F(PanelAppBrowserTest, OpenAppInPanel) { ...@@ -46,7 +75,7 @@ IN_PROC_BROWSER_TEST_F(PanelAppBrowserTest, OpenAppInPanel) {
// No Panels initially. // No Panels initially.
PanelManager* panel_manager = PanelManager::GetInstance(); PanelManager* panel_manager = PanelManager::GetInstance();
EXPECT_EQ(0, panel_manager->num_panels()); // No panels initially. ASSERT_EQ(0, panel_manager->num_panels()); // No panels initially.
LoadAndLaunchExtension("app_with_panel_container"); LoadAndLaunchExtension("app_with_panel_container");
...@@ -67,6 +96,8 @@ IN_PROC_BROWSER_TEST_F(PanelAppBrowserTest, OpenAppInPanel) { ...@@ -67,6 +96,8 @@ IN_PROC_BROWSER_TEST_F(PanelAppBrowserTest, OpenAppInPanel) {
// Now also check that PanelManager has one new Panel under management. // Now also check that PanelManager has one new Panel under management.
EXPECT_EQ(1, panel_manager->num_panels()); EXPECT_EQ(1, panel_manager->num_panels());
new_browser->CloseWindow(); CloseWindowAndWait(new_browser);
EXPECT_EQ(0, panel_manager->num_panels()); EXPECT_EQ(0, panel_manager->num_panels());
EXPECT_EQ(1u, BrowserList::size());
} }
...@@ -56,6 +56,11 @@ class PanelBrowserWindowCocoa : public NativePanel { ...@@ -56,6 +56,11 @@ class PanelBrowserWindowCocoa : public NativePanel {
Panel* panel() { return panel_.get(); } Panel* panel() { return panel_.get(); }
Browser* browser() const { return browser_.get(); } Browser* browser() const { return browser_.get(); }
// Callback from PanelWindowControllerCocoa that native window was actually
// closed. The window may not close right away because of onbeforeunload
// handlers.
void didCloseNativeWindow();
private: private:
friend class PanelBrowserWindowCocoaTest; friend class PanelBrowserWindowCocoaTest;
FRIEND_TEST_ALL_PREFIXES(PanelBrowserWindowCocoaTest, CreateClose); FRIEND_TEST_ALL_PREFIXES(PanelBrowserWindowCocoaTest, CreateClose);
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h" #include "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h"
#include "chrome/browser/ui/panels/panel.h" #include "chrome/browser/ui/panels/panel.h"
#include "chrome/browser/ui/panels/panel_manager.h"
#import "chrome/browser/ui/panels/panel_window_controller_cocoa.h" #import "chrome/browser/ui/panels/panel_window_controller_cocoa.h"
#include "content/common/native_web_keyboard_event.h" #include "content/common/native_web_keyboard_event.h"
...@@ -103,13 +104,7 @@ void PanelBrowserWindowCocoa::ClosePanel() { ...@@ -103,13 +104,7 @@ void PanelBrowserWindowCocoa::ClosePanel() {
return; return;
NSWindow* window = [controller_ window]; NSWindow* window = [controller_ window];
NSRect frame = [window frame]; [window performClose:controller_];
frame.size.height = kMinimumWindowSize;
// TODO(dimich): make this async. Currently, multiple panels will serially
// (and annoyingly) close when user exits Chrome.
[window setFrame:frame display:YES animate:YES];
browser_->OnWindowClosing();
DestroyPanelBrowser(); // not immediately, though.
} }
void PanelBrowserWindowCocoa::ActivatePanel() { void PanelBrowserWindowCocoa::ActivatePanel() {
...@@ -176,9 +171,13 @@ Browser* PanelBrowserWindowCocoa::GetPanelBrowser() const { ...@@ -176,9 +171,13 @@ Browser* PanelBrowserWindowCocoa::GetPanelBrowser() const {
void PanelBrowserWindowCocoa::DestroyPanelBrowser() { void PanelBrowserWindowCocoa::DestroyPanelBrowser() {
[controller_ close]; [controller_ close];
controller_ = NULL;
} }
void PanelBrowserWindowCocoa::didCloseNativeWindow() {
DCHECK(!isClosed());
panel_->manager()->Remove(panel_.get());
controller_ = NULL;
}
// NativePanelTesting implementation. // NativePanelTesting implementation.
// static // static
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "base/command_line.h" #include "base/command_line.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
...@@ -45,6 +46,14 @@ class PanelBrowserTest : public InProcessBrowserTest { ...@@ -45,6 +46,14 @@ class PanelBrowserTest : public InProcessBrowserTest {
protected: protected:
Panel* CreatePanel(const std::string& name, const gfx::Rect& bounds) { Panel* CreatePanel(const std::string& name, const gfx::Rect& bounds) {
// Opening panels on a Mac causes NSWindowController of the Panel window
// to be autoreleased. We need a pool drained after it's done so the test
// can close correctly. The NSWindowController of the Panel window controls
// lifetime of the Browser object so we want to release it as soon as
// possible. In real Chrome, this is done by message pump.
// On non-Mac platform, this is an empty class.
base::mac::ScopedNSAutoreleasePool autorelease_pool;
Browser* panel_browser = Browser::CreateForApp(Browser::TYPE_PANEL, Browser* panel_browser = Browser::CreateForApp(Browser::TYPE_PANEL,
name, name,
bounds, bounds,
...@@ -62,6 +71,19 @@ class PanelBrowserTest : public InProcessBrowserTest { ...@@ -62,6 +71,19 @@ class PanelBrowserTest : public InProcessBrowserTest {
return panel; return panel;
} }
void CloseWindowAndWait(Browser* browser) {
// Closing a browser window may involve several async tasks. Need to use
// message pump and wait for the notification.
size_t browser_count = BrowserList::size();
ui_test_utils::WindowedNotificationObserver signal(
chrome::NOTIFICATION_BROWSER_CLOSED,
Source<Browser>(browser));
browser->CloseWindow();
signal.Wait();
// Now we have one less browser instance.
EXPECT_EQ(browser_count - 1, BrowserList::size());
}
// Creates a testing extension. // Creates a testing extension.
scoped_refptr<Extension> CreateExtension(const FilePath::StringType& path) { scoped_refptr<Extension> CreateExtension(const FilePath::StringType& path) {
#if defined(OS_WIN) #if defined(OS_WIN)
...@@ -281,7 +303,8 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserTest, CreatePanel) { ...@@ -281,7 +303,8 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserTest, CreatePanel) {
EXPECT_GT(bounds.width(), 0); EXPECT_GT(bounds.width(), 0);
EXPECT_GT(bounds.height(), 0); EXPECT_GT(bounds.height(), 0);
panel->Close(); CloseWindowAndWait(panel->browser());
EXPECT_EQ(0, panel_manager->num_panels()); EXPECT_EQ(0, panel_manager->num_panels());
} }
...@@ -293,14 +316,7 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserTest, FindBar) { ...@@ -293,14 +316,7 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserTest, FindBar) {
panel->Close(); panel->Close();
} }
// TODO(jianli): Investigate and enable it for Mac. IN_PROC_BROWSER_TEST_F(PanelBrowserTest, CreatePanelOnOverflow) {
#ifdef OS_MACOSX
#define MAYBE_CreatePanelOnOverflow DISABLED_CreatePanelOnOverflow
#else
#define MAYBE_CreatePanelOnOverflow CreatePanelOnOverflow
#endif
IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_CreatePanelOnOverflow) {
TestCreatePanelOnOverflow(); TestCreatePanelOnOverflow();
} }
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/mac/mac_util.h" #include "base/mac/mac_util.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#import "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h" #import "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h"
#import "chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h" #import "chrome/browser/ui/cocoa/find_bar/find_bar_cocoa_controller.h"
...@@ -96,14 +97,6 @@ const int kMinimumWindowSize = 1; ...@@ -96,14 +97,6 @@ const int kMinimumWindowSize = 1;
[findBarCocoaController positionFindBarViewAtMaxY:maxY maxWidth:maxWidth]; [findBarCocoaController positionFindBarViewAtMaxY:maxY maxWidth:maxWidth];
} }
- (void)closePanel {
windowShim_->panel()->Close();
}
- (void)windowWillClose:(NSNotification*)notification {
[self autorelease];
}
- (NSView*)tabContentsView { - (NSView*)tabContentsView {
TabContents* contents = windowShim_->browser()->GetSelectedTabContents(); TabContents* contents = windowShim_->browser()->GetSelectedTabContents();
CHECK(contents); CHECK(contents);
...@@ -115,4 +108,47 @@ const int kMinimumWindowSize = 1; ...@@ -115,4 +108,47 @@ const int kMinimumWindowSize = 1;
- (PanelTitlebarViewCocoa*)titlebarView { - (PanelTitlebarViewCocoa*)titlebarView {
return titlebar_view_; return titlebar_view_;
} }
// Handler for the custom Close button.
- (void)closePanel {
windowShim_->panel()->Close();
}
// Called when the user wants to close the panel or from the shutdown process.
// The Browser object is in control of whether or not we're allowed to close. It
// may defer closing due to several states, such as onbeforeUnload handlers
// needing to be fired. If closing is deferred, the Browser will handle the
// processing required to get us to the closing state and (by watching for
// all the tabs going away) will again call to close the window when it's
// finally ready.
// This callback is only called if the standard Close button is enabled in XIB.
- (BOOL)windowShouldClose:(id)sender {
Browser* browser = windowShim_->browser();
// Give beforeunload handlers the chance to cancel the close before we hide
// the window below.
if (!browser->ShouldCloseWindow())
return NO;
if (!browser->tabstrip_model()->empty()) {
// Tab strip isn't empty. Make browser to close all the tabs, allowing the
// renderer to shut down and call us back again.
// The tab strip of Panel is not visible and contains only one tab but
// it still has to be closed.
browser->OnWindowClosing();
return NO;
}
// the tab strip is empty, it's ok to close the window
return YES;
}
// When windowShouldClose returns YES (or if controller receives direct 'close'
// signal), window will be unconditionally closed. Clean up.
- (void)windowWillClose:(NSNotification*)notification {
DCHECK(windowShim_->browser()->tabstrip_model()->empty());
windowShim_->didCloseNativeWindow();
[self autorelease];
}
@end @end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment