diff options
-rw-r--r-- | chrome/browser/chrome_browser_application_mac.h | 15 | ||||
-rw-r--r-- | chrome/browser/chrome_browser_application_mac.mm | 43 | ||||
-rw-r--r-- | chrome/browser/chrome_browser_main.cc | 13 | ||||
-rw-r--r-- | chrome/browser/chrome_browser_main_mac.mm | 29 | ||||
-rw-r--r-- | chrome/browser/mac/dock.mm | 17 | ||||
-rw-r--r-- | chrome/browser/mac/keystone_glue.mm | 13 | ||||
-rw-r--r-- | chrome/browser/ui/panels/base_panel_browser_test.cc | 12 | ||||
-rw-r--r-- | chrome/browser/ui/panels/base_panel_browser_test.h | 2 | ||||
-rw-r--r-- | chrome/browser/ui/panels/panel_browsertest.cc | 11 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 4 | ||||
-rw-r--r-- | chrome/test/base/in_process_browser_test.cc | 9 | ||||
-rw-r--r-- | chrome/test/base/in_process_browser_test.h | 19 |
12 files changed, 138 insertions, 49 deletions
diff --git a/chrome/browser/chrome_browser_application_mac.h b/chrome/browser/chrome_browser_application_mac.h index 52c6be3..0801fbb 100644 --- a/chrome/browser/chrome_browser_application_mac.h +++ b/chrome/browser/chrome_browser_application_mac.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -10,9 +10,12 @@ #import <AppKit/AppKit.h> +#include <vector> + #import "base/mac/scoped_sending_event.h" #import "base/memory/scoped_nsobject.h" #import "base/message_pump_mac.h" +#include "base/synchronization/lock.h" // Event hooks must implement this protocol. @protocol CrApplicationEventHookProtocol @@ -29,8 +32,12 @@ scoped_nsobject<NSMutableArray> eventHooks_; // App's previous key windows. Most recent key window is last. - // Does not include current key window. - scoped_nsobject<NSMutableArray> previousKeyWindows_; + // Does not include current key window. Elements of this vector are weak + // references. + std::vector<NSWindow*> previousKeyWindows_; + + // Guards previousKeyWindows_. + base::Lock previousKeyWindowsLock_; } // Our implementation of |-terminate:| only attempts to terminate the @@ -52,7 +59,7 @@ // Keep track of the previous key windows and whether windows are being // cycled for use in determining whether a Panel window can become the // key window. -- (id)previousKeyWindow; +- (NSWindow*)previousKeyWindow; - (BOOL)isCyclingWindows; @end diff --git a/chrome/browser/chrome_browser_application_mac.mm b/chrome/browser/chrome_browser_application_mac.mm index 76c1660..765cec2 100644 --- a/chrome/browser/chrome_browser_application_mac.mm +++ b/chrome/browser/chrome_browser_application_mac.mm @@ -211,8 +211,15 @@ void SwizzleInit() { // Used to determine when a Panel window can become the key window. @interface NSApplication (PanelsCanBecomeKey) - (void)_cycleWindowsReversed:(BOOL)arg1; -- (id)_removeWindow:(id)window; -- (id)_setKeyWindow:(id)window; +- (id)_removeWindow:(NSWindow*)window; +- (id)_setKeyWindow:(NSWindow*)window; +@end + +@interface BrowserCrApplication (PrivateInternal) + +// This must be called under the protection of previousKeyWindowsLock_. +- (void)removePreviousKeyWindow:(NSWindow*)window; + @end @implementation BrowserCrApplication @@ -227,7 +234,6 @@ void SwizzleInit() { SwizzleInit(); if ((self = [super init])) { eventHooks_.reset([[NSMutableArray alloc] init]); - previousKeyWindows_.reset([[NSMutableArray alloc] init]); } // Sanity check to alert if overridden methods are not supported. @@ -516,8 +522,11 @@ void SwizzleInit() { return cyclingWindows_; } -- (id)_removeWindow:(id)window { - [previousKeyWindows_ removeObject:window]; +- (id)_removeWindow:(NSWindow*)window { + { + base::AutoLock lock(previousKeyWindowsLock_); + [self removePreviousKeyWindow:window]; + } id result = [super _removeWindow:window]; // Ensure app has a key window after a window is removed. @@ -537,21 +546,35 @@ void SwizzleInit() { return result; } -- (id)_setKeyWindow:(id)window { +- (id)_setKeyWindow:(NSWindow*)window { // |window| is nil when the current key window is being closed. // A separate call follows with a new value when a new key window is set. // Closed windows are not tracked in previousKeyWindows_. if (window != nil) { - [previousKeyWindows_ removeObject:window]; + base::AutoLock lock(previousKeyWindowsLock_); + [self removePreviousKeyWindow:window]; NSWindow* currentKeyWindow = [self keyWindow]; if (currentKeyWindow != nil && currentKeyWindow != window) - [previousKeyWindows_ addObject:currentKeyWindow]; + previousKeyWindows_.push_back(window); } return [super _setKeyWindow:window]; } -- (id)previousKeyWindow { - return [previousKeyWindows_ lastObject]; +- (NSWindow*)previousKeyWindow { + base::AutoLock lock(previousKeyWindowsLock_); + return previousKeyWindows_.empty() ? nil : previousKeyWindows_.back(); } + +- (void)removePreviousKeyWindow:(NSWindow*)window { + previousKeyWindowsLock_.AssertAcquired(); + std::vector<NSWindow*>::iterator window_iterator = + std::find(previousKeyWindows_.begin(), + previousKeyWindows_.end(), + window); + if (window_iterator != previousKeyWindows_.end()) { + previousKeyWindows_.erase(window_iterator); + } +} + @end diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index 6413b349..a6a5667 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc @@ -163,7 +163,6 @@ #include <Security/Security.h> #include "base/mac/scoped_nsautorelease_pool.h" -#include "chrome/browser/mac/install_from_dmg.h" #include "chrome/browser/mac/keystone_glue.h" #endif @@ -1552,18 +1551,6 @@ int ChromeBrowserMainParts::PreMainMessageLoopRunImpl() { translate_manager_ = TranslateManager::GetInstance(); DCHECK(translate_manager_ != NULL); -#if defined(OS_MACOSX) - if (!parsed_command_line().HasSwitch(switches::kNoFirstRun)) { - // Disk image installation is sort of a first-run task, so it shares the - // kNoFirstRun switch. - if (MaybeInstallFromDiskImage()) { - // The application was installed and the installed copy has been - // launched. This process is now obsolete. Exit. - return content::RESULT_CODE_NORMAL_EXIT; - } - } -#endif - // TODO(stevenjb): Move WIN and MACOSX specific code to apprpriate Parts. // (requires supporting early exit). PostProfileInit(); diff --git a/chrome/browser/chrome_browser_main_mac.mm b/chrome/browser/chrome_browser_main_mac.mm index 493f8ea..8264490 100644 --- a/chrome/browser/chrome_browser_main_mac.mm +++ b/chrome/browser/chrome_browser_main_mac.mm @@ -16,6 +16,7 @@ #include "chrome/app/breakpad_mac.h" #import "chrome/browser/app_controller_mac.h" #import "chrome/browser/chrome_browser_application_mac.h" +#include "chrome/browser/mac/install_from_dmg.h" #import "chrome/browser/mac/keystone_glue.h" #include "chrome/browser/metrics/metrics_service.h" #include "chrome/common/chrome_paths.h" @@ -94,6 +95,30 @@ void ChromeBrowserMainPartsMac::PreMainMessageLoopStart() { ResourceBundle::AddDataPackToSharedInstance(resources_pack_path); } + // This is a no-op if the KeystoneRegistration framework is not present. + // The framework is only distributed with branded Google Chrome builds. + [[KeystoneGlue defaultKeystoneGlue] registerWithKeystone]; + + // Disk image installation is sort of a first-run task, so it shares the + // kNoFirstRun switch. + // + // This needs to be done after the resource bundle is initialized (for + // access to localizations in the UI) and after Keystone is initialized + // (because the installation may need to promote Keystone) but before the + // app controller is set up (and thus before MainMenu.nib is loaded, because + // the app controller assumes that a browser has been set up and will crash + // upon receipt of certain notifications if no browser exists), before + // anyone tries doing anything silly like firing off an import job, and + // before anything creating preferences like Local State in order for the + // relaunched installed application to still consider itself as first-run. + if (!parsed_command_line().HasSwitch(switches::kNoFirstRun)) { + if (MaybeInstallFromDiskImage()) { + // The application was installed and the installed copy has been + // launched. This process is now obsolete. Exit. + exit(0); + } + } + // Now load the nib (from the right bundle). scoped_nsobject<NSNib> nib([[NSNib alloc] initWithNibNamed:@"MainMenu" @@ -104,10 +129,6 @@ void ChromeBrowserMainPartsMac::PreMainMessageLoopStart() { // Make sure the app controller has been created. DCHECK([NSApp delegate]); - // This is a no-op if the KeystoneRegistration framework is not present. - // The framework is only distributed with branded Google Chrome builds. - [[KeystoneGlue defaultKeystoneGlue] registerWithKeystone]; - // Prevent Cocoa from turning command-line arguments into // |-application:openFiles:|, since we already handle them directly. [[NSUserDefaults standardUserDefaults] diff --git a/chrome/browser/mac/dock.mm b/chrome/browser/mac/dock.mm index 0c52150..39c33b9 100644 --- a/chrome/browser/mac/dock.mm +++ b/chrome/browser/mac/dock.mm @@ -243,24 +243,15 @@ void AddIcon(NSString* installed_path, NSString* dmg_app_path) { return; } - // Directories in the Dock's plist are given with trailing slashes. Since - // installed_path and dmg_app_path both refer to application bundles, - // they're directories and will show up with trailing slashes. This is an - // artifact of the Dock's internal use of CFURL. Look for paths that match, - // and when adding an item to the Dock's plist, keep it in the form that the - // Dock likes. - NSString* installed_path_dock = [installed_path stringByAppendingString:@"/"]; - NSString* dmg_app_path_dock = [dmg_app_path stringByAppendingString:@"/"]; - NSUInteger already_installed_app_index = NSNotFound; NSUInteger app_index = NSNotFound; for (NSUInteger index = 0; index < [persistent_apps count]; ++index) { NSString* app_path = [persistent_app_paths objectAtIndex:index]; - if ([app_path isEqualToString:installed_path_dock]) { + if ([app_path isEqualToString:installed_path]) { // If the Dock already contains a reference to the newly installed // application, don't add another one. already_installed_app_index = index; - } else if ([app_path isEqualToString:dmg_app_path_dock]) { + } else if ([app_path isEqualToString:dmg_app_path]) { // If the Dock contains a reference to the application on the disk // image, replace it with a reference to the newly installed // application. However, if the Dock contains a reference to both the @@ -364,7 +355,7 @@ void AddIcon(NSString* installed_path, NSString* dmg_app_path) { } // Set up the new Dock tile. - NSURL* url = [NSURL fileURLWithPath:installed_path_dock]; + NSURL* url = [NSURL fileURLWithPath:installed_path isDirectory:YES]; NSDictionary* url_dict = NSURLCopyDictionary(url); if (!url_dict) { LOG(ERROR) << "couldn't create url_dict"; @@ -380,7 +371,7 @@ void AddIcon(NSString* installed_path, NSString* dmg_app_path) { // Add the new tile to the Dock. [persistent_apps insertObject:new_tile atIndex:app_index]; - [persistent_app_paths insertObject:installed_path_dock atIndex:app_index]; + [persistent_app_paths insertObject:installed_path atIndex:app_index]; made_change = true; } diff --git a/chrome/browser/mac/keystone_glue.mm b/chrome/browser/mac/keystone_glue.mm index 8b00373..4236206 100644 --- a/chrome/browser/mac/keystone_glue.mm +++ b/chrome/browser/mac/keystone_glue.mm @@ -892,6 +892,12 @@ NSString* const kVersionKey = @"KSVersion"; // Upon completion, ksr::KSRegistrationPromotionDidCompleteNotification will // be posted, and -promotionComplete: will be called. + + // If synchronous, see to it that this happens immediately. Give it a + // 10-second deadline. + if (synchronous) { + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, false); + } } - (void)promotionComplete:(NSNotification*)notification { @@ -910,6 +916,13 @@ NSString* const kVersionKey = @"KSVersion"; authorization_.reset(); [self updateStatus:kAutoupdatePromoteFailed version:nil]; } + + if (synchronousPromotion_) { + // The run loop doesn't need to wait for this any longer. + CFRunLoopRef runLoop = CFRunLoopGetCurrent(); + CFRunLoopStop(runLoop); + CFRunLoopWakeUp(runLoop); + } } - (void)changePermissionsForPromotionAsync { diff --git a/chrome/browser/ui/panels/base_panel_browser_test.cc b/chrome/browser/ui/panels/base_panel_browser_test.cc index 4beaf60..0e72d67 100644 --- a/chrome/browser/ui/panels/base_panel_browser_test.cc +++ b/chrome/browser/ui/panels/base_panel_browser_test.cc @@ -36,6 +36,7 @@ #if defined(OS_MACOSX) #include "base/mac/scoped_nsautorelease_pool.h" #include "chrome/browser/ui/cocoa/find_bar/find_bar_bridge.h" +#include "chrome/browser/ui/cocoa/run_loop_testing.h" #endif using content::WebContentsTester; @@ -489,6 +490,17 @@ void BasePanelBrowserTest::CloseWindowAndWait(Browser* browser) { signal.Wait(); // Now we have one less browser instance. EXPECT_EQ(browser_count - 1, BrowserList::size()); + +#if defined(OS_MACOSX) + // Mac window controllers may be autoreleased, and in the non-test + // environment, may actually depend on the autorelease pool being recycled + // with the run loop in order to perform important work. Replicate this in + // the test environment. + AutoreleasePool()->Recycle(); + + // Make sure that everything has a chance to run. + chrome::testing::NSRunLoopRunAllPending(); +#endif // OS_MACOSX } void BasePanelBrowserTest::MoveMouse(const gfx::Point& position) { diff --git a/chrome/browser/ui/panels/base_panel_browser_test.h b/chrome/browser/ui/panels/base_panel_browser_test.h index e7b6cb0..7cd500c 100644 --- a/chrome/browser/ui/panels/base_panel_browser_test.h +++ b/chrome/browser/ui/panels/base_panel_browser_test.h @@ -102,7 +102,7 @@ class BasePanelBrowserTest : public InProcessBrowserTest { const DictionaryValue& extra_value); static void MoveMouse(const gfx::Point& position); - static void CloseWindowAndWait(Browser* browser); + void CloseWindowAndWait(Browser* browser); static std::string MakePanelName(int index); gfx::Rect GetTestingWorkArea() const; diff --git a/chrome/browser/ui/panels/panel_browsertest.cc b/chrome/browser/ui/panels/panel_browsertest.cc index 08dd669..6dd8883 100644 --- a/chrome/browser/ui/panels/panel_browsertest.cc +++ b/chrome/browser/ui/panels/panel_browsertest.cc @@ -737,7 +737,16 @@ IN_PROC_BROWSER_TEST_F(PanelBrowserTest, ToggleMinimizeAll) { PanelManager::GetInstance()->CloseAll(); } -IN_PROC_BROWSER_TEST_F(PanelBrowserTest, ActivatePanelOrTabbedWindow) { +#if defined(OS_MACOSX) +// This test doesn't pass on Snow Leopard (10.6), although it works just +// fine on Lion (10.7). The problem is not having a real run loop around +// the window close is at fault, given how window controllers in Chrome +// autorelease themselves on a -performSelector:withObject:afterDelay: +#define MAYBE_ActivatePanelOrTabbedWindow DISABLED_ActivatePanelOrTabbedWindow +#else +#define MAYBE_ActivatePanelOrTabbedWindow ActivatePanelOrTabbedWindow +#endif +IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_ActivatePanelOrTabbedWindow) { CreatePanelParams params1("Panel1", gfx::Rect(), SHOW_AS_ACTIVE); Panel* panel1 = CreatePanelWithParams(params1); CreatePanelParams params2("Panel2", gfx::Rect(), SHOW_AS_ACTIVE); diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 0ed1af8..427a232 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -180,6 +180,8 @@ 'browser/sync/profile_sync_service_mock.cc', 'browser/sync/profile_sync_service_mock.h', 'browser/ui/browser.h', + 'browser/ui/cocoa/run_loop_testing.h', + 'browser/ui/cocoa/run_loop_testing.mm', 'browser/ui/panels/base_panel_browser_test.cc', 'browser/ui/panels/base_panel_browser_test.h', 'browser/ui/panels/test_panel_mouse_watcher.cc', @@ -1901,8 +1903,6 @@ 'browser/ui/cocoa/one_click_signin_dialog_controller_unittest.mm', 'browser/ui/cocoa/page_info_bubble_controller_unittest.mm', 'browser/ui/cocoa/profile_menu_controller_unittest.mm', - 'browser/ui/cocoa/run_loop_testing.h', - 'browser/ui/cocoa/run_loop_testing.mm', 'browser/ui/cocoa/run_loop_testing_unittest.mm', 'browser/ui/cocoa/status_bubble_mac_unittest.mm', 'browser/ui/cocoa/status_icons/status_icon_mac_unittest.mm', diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc index 48e2607..75db280 100644 --- a/chrome/test/base/in_process_browser_test.cc +++ b/chrome/test/base/in_process_browser_test.cc @@ -4,6 +4,7 @@ #include "chrome/test/base/in_process_browser_test.h" +#include "base/auto_reset.h" #include "base/bind.h" #include "base/command_line.h" #include "base/debug/stack_trace.h" @@ -55,7 +56,11 @@ InProcessBrowserTest::InProcessBrowserTest() show_window_(false), initial_window_required_(true), dom_automation_enabled_(false), - tab_closeable_state_watcher_enabled_(false) { + tab_closeable_state_watcher_enabled_(false) +#if defined(OS_MACOSX) + , autorelease_pool_(NULL) +#endif // OS_MACOSX + { #if defined(OS_MACOSX) // TODO(phajdan.jr): Make browser_tests self-contained on Mac, remove this. // Before we run the browser, we have to hack the path to the exe to match @@ -290,6 +295,8 @@ void InProcessBrowserTest::RunTestOnMainThreadLoop() { // browser shutdown). To avoid this, the following pool is recycled after each // time code is directly executed. base::mac::ScopedNSAutoreleasePool pool; + AutoReset<base::mac::ScopedNSAutoreleasePool*> autorelease_pool_reset( + &autorelease_pool_, &pool); #endif // Pump startup related events. diff --git a/chrome/test/base/in_process_browser_test.h b/chrome/test/base/in_process_browser_test.h index 3638b57..a44c981 100644 --- a/chrome/test/base/in_process_browser_test.h +++ b/chrome/test/base/in_process_browser_test.h @@ -20,6 +20,14 @@ #include "chrome/browser/chromeos/cros/cros_library.h" #endif // defined(OS_CHROMEOS) +#if defined(OS_MACOSX) +namespace base { +namespace mac { +class ScopedNSAutoreleasePool; +} // namespace mac +} // namespace base +#endif // OS_MACOSX + class Browser; class CommandLine; class Profile; @@ -167,6 +175,13 @@ class InProcessBrowserTest : public BrowserTestBase { tab_closeable_state_watcher_enabled_ = true; } +#if defined(OS_MACOSX) + // Returns the autorelease pool in use inside RunTestOnMainThreadLoop(). + base::mac::ScopedNSAutoreleasePool* AutoreleasePool() const { + return autorelease_pool_; + } +#endif // OS_MACOSX + private: // Creates a user data directory for the test if one is needed. Returns true // if successful. @@ -212,6 +227,10 @@ class InProcessBrowserTest : public BrowserTestBase { #if defined(OS_CHROMEOS) chromeos::ScopedStubCrosEnabler stub_cros_enabler_; #endif // defined(OS_CHROMEOS) + +#if defined(OS_MACOSX) + base::mac::ScopedNSAutoreleasePool* autorelease_pool_; +#endif // OS_MACOSX }; #endif // CHROME_TEST_BASE_IN_PROCESS_BROWSER_TEST_H_ |