diff -r 000000000000 -r 4f2f89ce4247 WebKitTools/WebKitLauncher/WebKitNightlyEnablerSparkle.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebKitTools/WebKitLauncher/WebKitNightlyEnablerSparkle.m Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2009 Apple Inc. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR + * 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. + */ + +#if !ENABLE_SPARKLE + +void initializeSparkle() +{ + // No-op. +} + +#else // ENABLE_SPARKLE + +#import +#import +#import +#import "WebKitNightlyEnabler.h" + +// We need to tweak the wording of the prompt to make sense in the context of WebKit and Safari. +static NSString* updatePermissionPromptDescription(id self, SEL _cmd) +{ + return @"Should WebKit automatically check for updates? You can always check for updates manually from the Safari menu."; +} + +static NSPanel *updateAlertPanel(id updateItem, id host) +{ + NSString *hostName = objc_msgSend(host, @selector(name)); + NSPanel *panel = NSGetInformationalAlertPanel([NSString stringWithFormat:@"Would you like to download and install %@ %@ now?", hostName, objc_msgSend(updateItem, @selector(displayVersionString))], + [NSString stringWithFormat:@"You are currently running %@ %@.", hostName, objc_msgSend(host, @selector(displayVersion))], + @"Install Update", @"Skip This Version", @"Remind Me Later"); + NSArray *subviews = [[panel contentView] subviews]; + NSEnumerator *e = [subviews objectEnumerator]; + NSView *view; + while ((view = [e nextObject])) { + if (![view isKindOfClass:[NSButton class]]) + continue; + + NSButton *button = (NSButton *)view; + [button setAction:@selector(webKitHandleButtonPress:)]; + if ([button tag] == NSAlertOtherReturn) + [button setKeyEquivalent:@"\033"]; + } + [panel center]; + return panel; +} + +// Sparkle's udpate alert panel looks odd with the release notes hidden, so we +// swap it out with a standard NSAlert-style panel instead. +static id updateAlertInitForAlertPanel(id self, SEL _cmd, id updateItem, id host) +{ + NSPanel *panel = updateAlertPanel(updateItem, host); + [panel setDelegate:self]; + + self = [self initWithWindow:panel]; + if (!self) + return nil; + + [updateItem retain]; + [host retain]; + + object_setInstanceVariable(self, "updateItem", (void*)updateItem); + object_setInstanceVariable(self, "host", (void*)host); + + [self setShouldCascadeWindows:NO]; + + return self; +} + +@implementation NSAlert (WebKitLauncherExtensions) + +- (void)webKitHandleButtonPress:(id)sender +{ + // We rely on the fact that NSAlertOtherReturn == -1, NSAlertAlternateReturn == 0 and NSAlertDefaultReturn == 1 + // to map the button tag to the corresponding selector + SEL selectors[] = { @selector(remindMeLater:), @selector(skipThisVersion:), @selector(installUpdate:) }; + SEL selector = selectors[[sender tag] + 1]; + + id delegate = [[sender window] delegate]; + objc_msgSend(delegate, selector, sender); +} + +@end + +#if __LP64__ + +#define setMethodImplementation method_setImplementation + +#else + +static void setMethodImplementation(Method m, IMP imp) +{ + m->method_imp = imp; +} + +#endif + +static NSString *userAgentStringForSparkle() +{ + NSBundle *safariBundle = [NSBundle mainBundle]; + NSString *safariVersion = [[safariBundle localizedInfoDictionary] valueForKey:@"CFBundleShortVersionString"]; + NSString *safariBuild = [[[safariBundle infoDictionary] valueForKey:(NSString *)kCFBundleVersionKey] substringFromIndex:1]; + NSString *webKitRevision = [[webKitLauncherBundle() infoDictionary] valueForKey:(NSString *)kCFBundleVersionKey]; + NSString *applicationName = [NSString stringWithFormat:@"Version/%@ Safari/%@ WebKitRevision/%@", safariVersion, safariBuild, webKitRevision]; + Class WebView = objc_lookUpClass("WebView"); + return objc_msgSend(WebView, @selector(_standardUserAgentWithApplicationName:), applicationName); +} + +void initializeSparkle() +{ + // Override some Sparkle behaviour + Method methodToPatch = class_getInstanceMethod(objc_getRequiredClass("SUUpdatePermissionPrompt"), @selector(promptDescription)); + setMethodImplementation(methodToPatch, (IMP)updatePermissionPromptDescription); + + methodToPatch = class_getInstanceMethod(objc_getRequiredClass("SUUpdateAlert"), @selector(initWithAppcastItem:host:)); + setMethodImplementation(methodToPatch, (IMP)updateAlertInitForAlertPanel); + + SUUpdater *updater = [SUUpdater updaterForBundle:webKitLauncherBundle()]; + [updater setUserAgentString:userAgentStringForSparkle()]; + + // Find the first separator on the Safari menu… + NSMenu *applicationSubmenu = [[[NSApp mainMenu] itemAtIndex:0] submenu]; + int i = 0; + for (; i < [applicationSubmenu numberOfItems]; i++) { + if ([[applicationSubmenu itemAtIndex:i] isSeparatorItem]) + break; + } + + // … and insert a menu item that can be used to manually trigger update checks. + NSMenuItem *updateMenuItem = [[NSMenuItem alloc] initWithTitle:@"Check for WebKit Updates…" action:@selector(checkForUpdates:) keyEquivalent:@""]; + [updateMenuItem setTarget:updater]; + [applicationSubmenu insertItem:updateMenuItem atIndex:i]; + [updateMenuItem release]; +} + +#endif // ENABLE_SPARKLE