blob: 672fa4aeafc4435ab7c0de4bdce0ce371df1cd49 [file] [log] [blame]
mrowe@apple.com66498512009-05-24 05:14:44 +00001/*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#if !ENABLE_SPARKLE
27
28void initializeSparkle()
29{
30 // No-op.
31}
32
33#else // ENABLE_SPARKLE
34
35#import <Cocoa/Cocoa.h>
36#import <Sparkle/SUUpdater.h>
37#import <objc/objc-runtime.h>
38#import "WebKitNightlyEnabler.h"
39
40// We need to tweak the wording of the prompt to make sense in the context of WebKit and Safari.
41static NSString* updatePermissionPromptDescription(id self, SEL _cmd)
42{
43 return @"Should WebKit automatically check for updates? You can always check for updates manually from the Safari menu.";
44}
45
mrowe@apple.com66498512009-05-24 05:14:44 +000046static NSPanel *updateAlertPanel(id updateItem, id host)
47{
48 NSString *hostName = objc_msgSend(host, @selector(name));
49 NSPanel *panel = NSGetInformationalAlertPanel([NSString stringWithFormat:@"Would you like to download and install %@ %@ now?", hostName, objc_msgSend(updateItem, @selector(displayVersionString))],
lforschler@apple.com4b3be902015-09-04 20:47:33 +000050 @"%@",
51 @"Install Update", @"Skip This Version", @"Remind Me Later",
52 [NSString stringWithFormat:@"You are currently running %@ %@.", hostName, objc_msgSend(host, @selector(displayVersion))]);
mrowe@apple.com66498512009-05-24 05:14:44 +000053 NSArray *subviews = [[panel contentView] subviews];
54 NSEnumerator *e = [subviews objectEnumerator];
55 NSView *view;
56 while ((view = [e nextObject])) {
57 if (![view isKindOfClass:[NSButton class]])
58 continue;
59
60 NSButton *button = (NSButton *)view;
61 [button setAction:@selector(webKitHandleButtonPress:)];
62 if ([button tag] == NSAlertOtherReturn)
63 [button setKeyEquivalent:@"\033"];
64 }
65 [panel center];
66 return panel;
67}
68
69// Sparkle's udpate alert panel looks odd with the release notes hidden, so we
70// swap it out with a standard NSAlert-style panel instead.
71static id updateAlertInitForAlertPanel(id self, SEL _cmd, id updateItem, id host)
72{
73 NSPanel *panel = updateAlertPanel(updateItem, host);
74 [panel setDelegate:self];
75
76 self = [self initWithWindow:panel];
77 if (!self)
78 return nil;
79
80 [updateItem retain];
81 [host retain];
82
83 object_setInstanceVariable(self, "updateItem", (void*)updateItem);
84 object_setInstanceVariable(self, "host", (void*)host);
85
86 [self setShouldCascadeWindows:NO];
87
88 return self;
89}
90
91@implementation NSAlert (WebKitLauncherExtensions)
92
93- (void)webKitHandleButtonPress:(id)sender
94{
95 // We rely on the fact that NSAlertOtherReturn == -1, NSAlertAlternateReturn == 0 and NSAlertDefaultReturn == 1
96 // to map the button tag to the corresponding selector
97 SEL selectors[] = { @selector(remindMeLater:), @selector(skipThisVersion:), @selector(installUpdate:) };
98 SEL selector = selectors[[sender tag] + 1];
99
100 id delegate = [[sender window] delegate];
101 objc_msgSend(delegate, selector, sender);
102}
103
104@end
105
mrowe@apple.comee326582009-06-22 00:03:43 +0000106static NSString *userAgentStringForSparkle()
107{
108 NSBundle *safariBundle = [NSBundle mainBundle];
109 NSString *safariVersion = [[safariBundle localizedInfoDictionary] valueForKey:@"CFBundleShortVersionString"];
110 NSString *safariBuild = [[[safariBundle infoDictionary] valueForKey:(NSString *)kCFBundleVersionKey] substringFromIndex:1];
111 NSString *webKitRevision = [[webKitLauncherBundle() infoDictionary] valueForKey:(NSString *)kCFBundleVersionKey];
112 NSString *applicationName = [NSString stringWithFormat:@"Version/%@ Safari/%@ WebKitRevision/%@", safariVersion, safariBuild, webKitRevision];
113 Class WebView = objc_lookUpClass("WebView");
114 return objc_msgSend(WebView, @selector(_standardUserAgentWithApplicationName:), applicationName);
115}
116
mrowe@apple.com66498512009-05-24 05:14:44 +0000117void initializeSparkle()
118{
119 // Override some Sparkle behaviour
120 Method methodToPatch = class_getInstanceMethod(objc_getRequiredClass("SUUpdatePermissionPrompt"), @selector(promptDescription));
dfarler@apple.com0b050652013-06-28 20:38:55 +0000121 method_setImplementation(methodToPatch, (IMP)updatePermissionPromptDescription);
mrowe@apple.com66498512009-05-24 05:14:44 +0000122
mrowe@apple.com66498512009-05-24 05:14:44 +0000123 methodToPatch = class_getInstanceMethod(objc_getRequiredClass("SUUpdateAlert"), @selector(initWithAppcastItem:host:));
dfarler@apple.com0b050652013-06-28 20:38:55 +0000124 method_setImplementation(methodToPatch, (IMP)updateAlertInitForAlertPanel);
mrowe@apple.com66498512009-05-24 05:14:44 +0000125
126 SUUpdater *updater = [SUUpdater updaterForBundle:webKitLauncherBundle()];
mrowe@apple.comee326582009-06-22 00:03:43 +0000127 [updater setUserAgentString:userAgentStringForSparkle()];
mrowe@apple.com66498512009-05-24 05:14:44 +0000128
129 // Find the first separator on the Safari menu…
130 NSMenu *applicationSubmenu = [[[NSApp mainMenu] itemAtIndex:0] submenu];
131 int i = 0;
132 for (; i < [applicationSubmenu numberOfItems]; i++) {
133 if ([[applicationSubmenu itemAtIndex:i] isSeparatorItem])
134 break;
135 }
136
137 // … and insert a menu item that can be used to manually trigger update checks.
138 NSMenuItem *updateMenuItem = [[NSMenuItem alloc] initWithTitle:@"Check for WebKit Updates…" action:@selector(checkForUpdates:) keyEquivalent:@""];
139 [updateMenuItem setTarget:updater];
140 [applicationSubmenu insertItem:updateMenuItem atIndex:i];
141 [updateMenuItem release];
142}
143
144#endif // ENABLE_SPARKLE