123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- /*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2006 Graham Dennis. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- #import <Cocoa/Cocoa.h>
- #import "WebKitNightlyEnablerSparkle.h"
- static void enableWebKitNightlyBehaviour() __attribute__ ((constructor));
- static NSString *WKNERunState = @"WKNERunState";
- static NSString *WKNEShouldMonitorShutdowns = @"WKNEShouldMonitorShutdowns";
- typedef enum {
- RunStateShutDown,
- RunStateInitializing,
- RunStateRunning
- } WKNERunStates;
- static char *webKitAppPath;
- static bool extensionBundlesWereLoaded = NO;
- static NSSet *extensionPaths = nil;
- static int32_t systemVersion()
- {
- static SInt32 version = 0;
- if (!version)
- Gestalt(gestaltSystemVersion, &version);
- return version;
- }
- static void myBundleDidLoad(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
- {
- NSBundle *bundle = (NSBundle *)object;
- NSString *bundlePath = [[bundle bundlePath] stringByAbbreviatingWithTildeInPath];
- NSString *bundleFileName = [bundlePath lastPathComponent];
- // Explicitly ignore SIMBL.bundle, as its only purpose is to load extensions
- // on a per-application basis. It's presence indicates a user has application
- // extensions, but not that any will be loaded into Safari
- if ([bundleFileName isEqualToString:@"SIMBL.bundle"])
- return;
- // If the bundle lives inside a known extension path, flag it as an extension
- NSEnumerator *e = [extensionPaths objectEnumerator];
- NSString *path = nil;
- while ((path = [e nextObject])) {
- if ([bundlePath length] < [path length])
- continue;
- if ([[bundlePath substringToIndex:[path length]] isEqualToString:path]) {
- NSLog(@"Extension detected: %@", bundlePath);
- extensionBundlesWereLoaded = YES;
- break;
- }
- }
- }
- static void myApplicationWillFinishLaunching(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
- {
- CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), &myApplicationWillFinishLaunching, NULL, NULL);
- CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), &myBundleDidLoad, NULL, NULL);
- [extensionPaths release];
- extensionPaths = nil;
- NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
- [userDefaults setInteger:RunStateRunning forKey:WKNERunState];
- [userDefaults synchronize];
- if (extensionBundlesWereLoaded)
- NSRunInformationalAlertPanel(@"Safari extensions detected",
- @"Safari extensions were detected on your system. Extensions are incompatible with nightly builds of WebKit, and may cause crashes or incorrect behavior. Please disable them if you experience such behavior.", @"Continue",
- nil, nil);
- initializeSparkle();
- }
- static void myApplicationWillTerminate(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
- {
- NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
- [userDefaults setInteger:RunStateShutDown forKey:WKNERunState];
- [userDefaults synchronize];
- }
- NSBundle *webKitLauncherBundle()
- {
- NSString *executablePath = [NSString stringWithUTF8String:webKitAppPath];
- NSRange appLocation = [executablePath rangeOfString:@".app/" options:NSBackwardsSearch];
- NSString *appPath = [executablePath substringToIndex:appLocation.location + appLocation.length];
- return [NSBundle bundleWithPath:appPath];
- }
- extern char **_CFGetProcessPath() __attribute__((weak));
- extern OSStatus _RegisterApplication(CFDictionaryRef additionalAppInfoRef, ProcessSerialNumber* myPSN) __attribute__((weak));
- static void poseAsWebKitApp()
- {
- webKitAppPath = strdup(getenv("WebKitAppPath"));
- if (!webKitAppPath)
- return;
- unsetenv("WebKitAppPath");
- // Set up the main bundle early so it points at Safari.app
- CFBundleGetMainBundle();
- if (systemVersion() < 0x1060) {
- if (!_CFGetProcessPath)
- return;
- // Fiddle with CoreFoundation to have it pick up the executable path as being within WebKit.app
- char **processPath = _CFGetProcessPath();
- *processPath = NULL;
- setenv("CFProcessPath", webKitAppPath, 1);
- _CFGetProcessPath();
- unsetenv("CFProcessPath");
- } else {
- if (!_RegisterApplication)
- return;
- // Register the application with LaunchServices, passing a customized registration dictionary that
- // uses the WebKit launcher as the application bundle.
- NSBundle *bundle = webKitLauncherBundle();
- NSMutableDictionary *checkInDictionary = [[bundle infoDictionary] mutableCopy];
- [checkInDictionary setObject:[bundle bundlePath] forKey:@"LSBundlePath"];
- [checkInDictionary setObject:[checkInDictionary objectForKey:(NSString *)kCFBundleNameKey] forKey:@"LSDisplayName"];
- _RegisterApplication((CFDictionaryRef)checkInDictionary, 0);
- [checkInDictionary release];
- }
- }
- static BOOL insideSafari4OnTigerTrampoline()
- {
- // If we're not on Tiger then we can't be in the trampoline state.
- if ((systemVersion() & 0xFFF0) != 0x1040)
- return NO;
- // If we're running Safari < 4.0 then we can't be in the trampoline state.
- CFBundleRef safariBundle = CFBundleGetMainBundle();
- CFStringRef safariVersion = CFBundleGetValueForInfoDictionaryKey(safariBundle, CFSTR("CFBundleShortVersionString"));
- if ([(NSString *)safariVersion intValue] < 4)
- return NO;
- const char* frameworkPath = getenv("DYLD_FRAMEWORK_PATH");
- if (!frameworkPath)
- frameworkPath = "";
- // If the framework search path is empty or otherwise does not contain the Safari
- // framework's Frameworks directory then we are in the trampoline state.
- const char safariFrameworkSearchPath[] = "/System/Library/PrivateFrameworks/Safari.framework/Frameworks";
- return strstr(frameworkPath, safariFrameworkSearchPath) == 0;
- }
- static void enableWebKitNightlyBehaviour()
- {
- // If we're inside Safari in its trampoline state, it will very shortly relaunch itself.
- // We bail out here so that we'll be called again in the freshly-launched Safari process.
- if (insideSafari4OnTigerTrampoline())
- return;
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- unsetenv("DYLD_INSERT_LIBRARIES");
- poseAsWebKitApp();
- extensionPaths = [[NSSet alloc] initWithObjects:@"~/Library/InputManagers/", @"/Library/InputManagers/",
- @"~/Library/Application Support/SIMBL/Plugins/", @"/Library/Application Support/SIMBL/Plugins/",
- @"~/Library/Application Enhancers/", @"/Library/Application Enhancers/",
- nil];
- // As of 2008-11 attempting to load Saft would cause a crash on launch, so prevent it from being loaded.
- NSArray *disabledInputManagers = [NSArray arrayWithObjects:@"Saft", nil];
- NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
- NSDictionary *defaultPrefs = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:RunStateShutDown], WKNERunState,
- [NSNumber numberWithBool:YES], WKNEShouldMonitorShutdowns,
- disabledInputManagers, @"NSDisabledInputManagers", nil];
- [userDefaults registerDefaults:defaultPrefs];
- if ([userDefaults boolForKey:WKNEShouldMonitorShutdowns]) {
- WKNERunStates savedState = (WKNERunStates)[userDefaults integerForKey:WKNERunState];
- if (savedState == RunStateInitializing) {
- // Use CoreFoundation here as AppKit hasn't been initialized at this stage of Safari's lifetime
- CFOptionFlags responseFlags;
- CFUserNotificationDisplayAlert(0, kCFUserNotificationCautionAlertLevel,
- NULL, NULL, NULL,
- CFSTR("WebKit failed to open correctly"),
- CFSTR("WebKit failed to open correctly on your previous attempt. Please disable any Safari extensions that you may have installed. If the problem continues to occur, please file a bug report at http://webkit.org/quality/reporting.html"),
- CFSTR("Continue"), NULL, NULL, &responseFlags);
- }
- else if (savedState == RunStateRunning) {
- NSLog(@"WebKit failed to shut down cleanly. Checking for Safari extensions.");
- CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), &myBundleDidLoad,
- myBundleDidLoad, (CFStringRef) NSBundleDidLoadNotification,
- NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
- }
- }
- [userDefaults setInteger:RunStateInitializing forKey:WKNERunState];
- [userDefaults synchronize];
- CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), &myApplicationWillFinishLaunching,
- myApplicationWillFinishLaunching, (CFStringRef) NSApplicationWillFinishLaunchingNotification,
- NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
- CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), &myApplicationWillTerminate,
- myApplicationWillTerminate, (CFStringRef) NSApplicationWillTerminateNotification,
- NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
- NSLog(@"WebKit %@ initialized.", [webKitLauncherBundle() objectForInfoDictionaryKey:@"CFBundleShortVersionString"]);
- [pool release];
- }
|