Skip to content

Commit

Permalink
Improved notification handling for otherwise UI-less background appli…
Browse files Browse the repository at this point in the history
…cations.
  • Loading branch information
mattstevens committed Jul 23, 2008
1 parent 32e014a commit cec9166
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 9 deletions.
2 changes: 2 additions & 0 deletions SUBasicUpdateDriver.h
Expand Up @@ -21,6 +21,8 @@
NSString *downloadPath;

NSString *relaunchPath;

BOOL isBackgroundApplication;
}

- (void)checkForUpdatesAtURL:(NSURL *)appcastURL hostBundle:(NSBundle *)hb;
Expand Down
3 changes: 2 additions & 1 deletion SUBasicUpdateDriver.m
Expand Up @@ -14,6 +14,7 @@ @implementation SUBasicUpdateDriver
- (void)checkForUpdatesAtURL:(NSURL *)appcastURL hostBundle:(NSBundle *)hb
{
hostBundle = [hb retain];
isBackgroundApplication = ([[hostBundle objectForInfoDictionaryKey:@"LSUIElement"] doubleValue]);

if ([hostBundle isRunningFromDiskImage])
{
Expand Down Expand Up @@ -165,7 +166,7 @@ - (BOOL)download:(NSURLDownload *)download shouldDecodeSourceDataOfMIMEType:(NSS
{
// We don't want the download system to extract our gzips.
// Note that we use a substring matching here instead of direct comparison because the docs say "application/gzip" but the system *uses* "application/x-gzip". This is a documentation bug.
return ([encodingType rangeOfString:@"gzip"].origin == NSNotFound);
return ([encodingType rangeOfString:@"gzip"].location == NSNotFound);
}

- (void)extractUpdate
Expand Down
2 changes: 2 additions & 0 deletions SUUIBasedUpdateDriver.h
Expand Up @@ -18,6 +18,8 @@
SUUpdateAlert *updateAlert;
}

- (void)showModalAlert:(NSAlert *)alert;

@end

#endif
27 changes: 21 additions & 6 deletions SUUIBasedUpdateDriver.m
Expand Up @@ -16,8 +16,15 @@ - (void)didFindValidUpdate
updateAlert = [[SUUpdateAlert alloc] initWithAppcastItem:updateItem hostBundle:hostBundle];
[updateAlert setDelegate:self];

// If the app is a menubar app or the like, we need to focus it first:
if ([[hostBundle objectForInfoDictionaryKey:@"LSUIElement"] doubleValue]) { [NSApp activateIgnoringOtherApps:YES]; }
// 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 (isBackgroundApplication)
{
[[updateAlert window] setHidesOnDeactivate:NO];
[[updateAlert window] setLevel:NSNormalWindowLevel];
[NSApp activateIgnoringOtherApps:YES];
}

// Only show the update alert if the app is active; otherwise, we'll wait until it is.
if ([NSApp isActive])
Expand All @@ -31,8 +38,7 @@ - (void)didNotFindUpdate
if ([delegate respondsToSelector:@selector(didNotFindUpdateToHostBundle:)])
[delegate didNotFindUpdateToHostBundle:hostBundle];
NSAlert *alert = [NSAlert alertWithMessageText:SULocalizedString(@"You're up to date!", nil) defaultButton:SULocalizedString(@"OK", nil) alternateButton:nil otherButton:nil informativeTextWithFormat:SULocalizedString(@"%@ %@ is currently the newest version available.", nil), [hostBundle name], [hostBundle displayVersion]];
[alert setIcon:[hostBundle icon]];
[alert runModal];
[self showModalAlert:alert];
[self abortUpdate];
}

Expand Down Expand Up @@ -138,8 +144,7 @@ - (void)installUpdate
- (void)abortUpdateWithError:(NSError *)error
{
NSAlert *alert = [NSAlert alertWithMessageText:SULocalizedString(@"Update Error!", nil) defaultButton:SULocalizedString(@"Cancel Update", nil) alternateButton:nil otherButton:nil informativeTextWithFormat:[error localizedDescription]];
[alert setIcon:[hostBundle icon]];
[alert runModal];
[self showModalAlert:alert];
[super abortUpdateWithError:error];
}

Expand All @@ -153,4 +158,14 @@ - (void)abortUpdate
[super abortUpdate];
}

- (void)showModalAlert:(NSAlert *)alert
{
// When showing a modal alert we need to ensure that background applications
// are focused to inform the user since there is no dock icon to notify them.
if (isBackgroundApplication) { [NSApp activateIgnoringOtherApps:YES]; }

[alert setIcon:[hostBundle icon]];
[alert runModal];
}

@end
7 changes: 6 additions & 1 deletion SUUpdatePermissionPrompt.m
Expand Up @@ -32,7 +32,12 @@ - (id)initWithHostBundle:(NSBundle *)hb delegate:(id)d

+ (void)promptWithHostBundle:(NSBundle *)hb delegate:(id)d
{
id prompt = [[[self class] alloc] initWithHostBundle:hb delegate:d];
// If this is a background application we need to focus it in order to bring the prompt
// to the user's attention. Otherwise the prompt would be hidden behind other applications and
// the user would not know why the application was paused.
if ([[hb objectForInfoDictionaryKey:@"LSUIElement"] doubleValue]) { [NSApp activateIgnoringOtherApps:YES]; }

id prompt = [[[self class] alloc] initWithHostBundle:hb delegate:d];
[NSApp runModalForWindow:[prompt window]];
}

Expand Down
9 changes: 8 additions & 1 deletion SUUserInitiatedUpdateDriver.m
Expand Up @@ -12,13 +12,20 @@
@implementation SUUserInitiatedUpdateDriver

- (void)checkForUpdatesAtURL:(NSURL *)appcastURL hostBundle:(NSBundle *)hb
{
{
checkingController = [[SUStatusController alloc] initWithHostBundle:hb];
[[checkingController window] center]; // Force the checking controller to load its window.
[checkingController beginActionWithTitle:SULocalizedString(@"Checking for updates\u2026", nil) maxProgressValue:0 statusText:nil];
[checkingController setButtonTitle:SULocalizedString(@"Cancel", nil) target:self action:@selector(cancelCheckForUpdates:) isDefault:NO];
[checkingController showWindow:self];
[super checkForUpdatesAtURL:appcastURL hostBundle:hb];

// For background applications, obtain focus.
// Useful if the update check is requested from another app like System Preferences.
if (isBackgroundApplication)
{
[NSApp activateIgnoringOtherApps:YES];
}
}

- (void)closeCheckingWindow
Expand Down

0 comments on commit cec9166

Please sign in to comment.