forked from samdeane/Sparkle
-
Notifications
You must be signed in to change notification settings - Fork 1
/
SUAutomaticUpdateDriver.m
170 lines (141 loc) · 5.61 KB
/
SUAutomaticUpdateDriver.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//
// SUAutomaticUpdateDriver.m
// Sparkle
//
// Created by Andy Matuschak on 5/6/08.
// Copyright 2008 Andy Matuschak. All rights reserved.
//
#import "SUAutomaticUpdateDriver.h"
#import "SUAutomaticUpdateAlert.h"
#import "SUHost.h"
#import "SUConstants.h"
// If the user hasn't quit in a week, ask them if they want to relaunch to get the latest bits. It doesn't matter that this measure of "one day" is imprecise.
static const NSTimeInterval SUAutomaticUpdatePromptImpatienceTimer = 60 * 60 * 24 * 7;
@implementation SUAutomaticUpdateDriver
- (void)showUpdateAlert
{
isInterruptible = NO;
alert = [[SUAutomaticUpdateAlert alloc] initWithAppcastItem:updateItem host:host delegate:self];
// If the app is a menubar app or the like, we need to focus it first and alter the
// update prompt to behave like a normal window. Otherwise if the window were hidden
// there may be no way for the application to be activated to make it visible again.
if ([host isBackgroundApplication])
{
[[alert window] setHidesOnDeactivate:NO];
[NSApp activateIgnoringOtherApps:YES];
}
if ([NSApp isActive])
[[alert window] makeKeyAndOrderFront:self];
else
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:NSApplicationDidBecomeActiveNotification object:NSApp];
}
- (void)unarchiverDidFinish:(SUUnarchiver *)ua
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:NSApplicationWillTerminateNotification object:nil];
// Sudden termination is available on 10.6+
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
if ([processInfo respondsToSelector:@selector(disableSuddenTermination)]) {
[processInfo disableSuddenTermination];
}
willUpdateOnTermination = YES;
if ([[updater delegate] respondsToSelector:@selector(updater:willInstallUpdateOnQuit:immediateInstallationInvocation:)])
{
BOOL relaunch = YES;
BOOL showUI = NO;
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:@selector(installWithToolAndRelaunch:displayingUserInterface:)]];
[invocation setSelector:@selector(installWithToolAndRelaunch:displayingUserInterface:)];
[invocation setArgument:&relaunch atIndex:2];
[invocation setArgument:&showUI atIndex:3];
[invocation setTarget:self];
[[updater delegate] updater:updater willInstallUpdateOnQuit:updateItem immediateInstallationInvocation:invocation];
}
// If this is marked as a critical update, we'll prompt the user to install it right away.
if ([updateItem isCriticalUpdate])
{
[self showUpdateAlert];
}
else
{
showUpdateAlertTimer = [[NSTimer scheduledTimerWithTimeInterval:SUAutomaticUpdatePromptImpatienceTimer target:self selector:@selector(showUpdateAlert) userInfo:nil repeats:NO] retain];
// At this point the driver is idle, allow it to be interrupted for user-initiated update checks.
isInterruptible = YES;
}
}
- (void)stopUpdatingOnTermination
{
if (willUpdateOnTermination)
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationWillTerminateNotification object:nil];
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
if ([processInfo respondsToSelector:@selector(enableSuddenTermination)]) {
[processInfo enableSuddenTermination];
}
willUpdateOnTermination = NO;
if ([[updater delegate] respondsToSelector:@selector(updater:didCancelInstallUpdateOnQuit:)])
[[updater delegate] updater:updater didCancelInstallUpdateOnQuit:updateItem];
}
}
- (void)invalidateShowUpdateAlertTimer
{
[showUpdateAlertTimer invalidate];
[showUpdateAlertTimer release];
showUpdateAlertTimer = nil;
}
- (void)dealloc
{
[self stopUpdatingOnTermination];
[self invalidateShowUpdateAlertTimer];
[alert release];
[super dealloc];
}
- (void)abortUpdate
{
[self stopUpdatingOnTermination];
[self invalidateShowUpdateAlertTimer];
[super abortUpdate];
}
- (void)applicationDidBecomeActive:(NSNotification *)aNotification
{
[[alert window] makeKeyAndOrderFront:self];
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSApplicationDidBecomeActiveNotification" object:NSApp];
}
- (void)automaticUpdateAlert:(SUAutomaticUpdateAlert *)aua finishedWithChoice:(SUAutomaticInstallationChoice)choice;
{
switch (choice)
{
case SUInstallNowChoice:
[self stopUpdatingOnTermination];
[self installWithToolAndRelaunch:YES];
break;
case SUInstallLaterChoice:
postponingInstallation = YES;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:NSApplicationWillTerminateNotification object:nil];
// We're already waiting on quit, just indicate that we're idle.
isInterruptible = YES;
break;
case SUDoNotInstallChoice:
[host setObject:[updateItem versionString] forUserDefaultsKey:SUSkippedVersionKey];
[self abortUpdate];
break;
}
}
- (BOOL)shouldInstallSynchronously { return postponingInstallation; }
- (void)installWithToolAndRelaunch:(BOOL)relaunch displayingUserInterface:(BOOL)showUI
{
if (relaunch)
[self stopUpdatingOnTermination];
showErrors = YES;
[super installWithToolAndRelaunch:relaunch displayingUserInterface:showUI];
}
- (void)applicationWillTerminate:(NSNotification *)note
{
[self installWithToolAndRelaunch:NO];
}
- (void)abortUpdateWithError:(NSError *)error
{
if (showErrors)
[super abortUpdateWithError:error];
else
[self abortUpdate];
}
@end