Clean up ChunkedUpdateDrawingAreaProxy
[WebKit-https.git] / Tools / WebKitLauncher / WebKitNightlyEnablerSparkle.m
1 /*
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
28 void 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.
41 static 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
46 static 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))],
50                                                   [NSString stringWithFormat:@"You are currently running %@ %@.", hostName, objc_msgSend(host, @selector(displayVersion))],
51                                                   @"Install Update", @"Skip This Version", @"Remind Me Later");
52     NSArray *subviews = [[panel contentView] subviews];
53     NSEnumerator *e = [subviews objectEnumerator];
54     NSView *view;
55     while ((view = [e nextObject])) {
56         if (![view isKindOfClass:[NSButton class]])
57             continue;
58
59         NSButton *button = (NSButton *)view;
60         [button setAction:@selector(webKitHandleButtonPress:)];
61         if ([button tag] == NSAlertOtherReturn)
62             [button setKeyEquivalent:@"\033"];
63     }
64     [panel center];
65     return panel;
66 }
67
68 // Sparkle's udpate alert panel looks odd with the release notes hidden, so we
69 // swap it out with a standard NSAlert-style panel instead.
70 static id updateAlertInitForAlertPanel(id self, SEL _cmd, id updateItem, id host)
71 {
72     NSPanel *panel = updateAlertPanel(updateItem, host);
73     [panel setDelegate:self];
74
75     self = [self initWithWindow:panel];
76     if (!self)
77         return nil;
78
79     [updateItem retain];
80     [host retain];
81
82     object_setInstanceVariable(self, "updateItem", (void*)updateItem);
83     object_setInstanceVariable(self, "host", (void*)host);
84
85     [self setShouldCascadeWindows:NO];
86
87     return self;
88 }
89
90 @implementation NSAlert (WebKitLauncherExtensions)
91
92 - (void)webKitHandleButtonPress:(id)sender
93 {
94     // We rely on the fact that NSAlertOtherReturn == -1, NSAlertAlternateReturn == 0 and NSAlertDefaultReturn == 1
95     // to map the button tag to the corresponding selector
96     SEL selectors[] = { @selector(remindMeLater:), @selector(skipThisVersion:), @selector(installUpdate:) };
97     SEL selector = selectors[[sender tag] + 1];
98
99     id delegate = [[sender window] delegate];
100     objc_msgSend(delegate, selector, sender);
101 }
102
103 @end
104
105 #if __LP64__
106
107 #define setMethodImplementation method_setImplementation
108
109 #else
110
111 static void setMethodImplementation(Method m, IMP imp)
112 {
113     m->method_imp = imp;
114 }
115
116 #endif
117
118 static NSString *userAgentStringForSparkle()
119 {
120     NSBundle *safariBundle = [NSBundle mainBundle];
121     NSString *safariVersion = [[safariBundle localizedInfoDictionary] valueForKey:@"CFBundleShortVersionString"];
122     NSString *safariBuild = [[[safariBundle infoDictionary] valueForKey:(NSString *)kCFBundleVersionKey] substringFromIndex:1];
123     NSString *webKitRevision = [[webKitLauncherBundle() infoDictionary] valueForKey:(NSString *)kCFBundleVersionKey];
124     NSString *applicationName = [NSString stringWithFormat:@"Version/%@ Safari/%@ WebKitRevision/%@", safariVersion, safariBuild, webKitRevision];
125     Class WebView = objc_lookUpClass("WebView");
126     return objc_msgSend(WebView, @selector(_standardUserAgentWithApplicationName:), applicationName);
127 }
128
129 void initializeSparkle()
130 {
131     // Override some Sparkle behaviour
132     Method methodToPatch = class_getInstanceMethod(objc_getRequiredClass("SUUpdatePermissionPrompt"), @selector(promptDescription));
133     setMethodImplementation(methodToPatch, (IMP)updatePermissionPromptDescription);
134
135     methodToPatch = class_getInstanceMethod(objc_getRequiredClass("SUUpdateAlert"), @selector(initWithAppcastItem:host:));
136     setMethodImplementation(methodToPatch, (IMP)updateAlertInitForAlertPanel);
137
138     SUUpdater *updater = [SUUpdater updaterForBundle:webKitLauncherBundle()];
139     [updater setUserAgentString:userAgentStringForSparkle()];
140
141     // Find the first separator on the Safari menu…
142     NSMenu *applicationSubmenu = [[[NSApp mainMenu] itemAtIndex:0] submenu];
143     int i = 0;
144     for (; i < [applicationSubmenu numberOfItems]; i++) {
145         if ([[applicationSubmenu itemAtIndex:i] isSeparatorItem])
146             break;
147     }
148
149     // … and insert a menu item that can be used to manually trigger update checks.
150     NSMenuItem *updateMenuItem = [[NSMenuItem alloc] initWithTitle:@"Check for WebKit Updates…" action:@selector(checkForUpdates:) keyEquivalent:@""];
151     [updateMenuItem setTarget:updater];
152     [applicationSubmenu insertItem:updateMenuItem atIndex:i];
153     [updateMenuItem release];
154 }
155
156 #endif // ENABLE_SPARKLE