summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/chrome_browser_application_mac.h15
-rw-r--r--chrome/browser/chrome_browser_application_mac.mm43
-rw-r--r--chrome/browser/chrome_browser_main.cc13
-rw-r--r--chrome/browser/chrome_browser_main_mac.mm29
-rw-r--r--chrome/browser/mac/dock.mm17
-rw-r--r--chrome/browser/mac/keystone_glue.mm13
-rw-r--r--chrome/browser/ui/panels/base_panel_browser_test.cc12
-rw-r--r--chrome/browser/ui/panels/base_panel_browser_test.h2
-rw-r--r--chrome/browser/ui/panels/panel_browsertest.cc11
-rw-r--r--chrome/chrome_tests.gypi4
-rw-r--r--chrome/test/base/in_process_browser_test.cc9
-rw-r--r--chrome/test/base/in_process_browser_test.h19
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_