+// Whether ScreenSaverEngine is currently running, meaning screen is blanked.
+//
+- (BOOL) screenSaverActive
+{
+ BOOL found = NO;
+ NSString *target = @"/ScreenSaverEngine.app";
+ ProcessSerialNumber psn = { kNoProcess, kNoProcess };
+ while (GetNextProcess(&psn) == noErr) {
+ CFDictionaryRef cfdict =
+ ProcessInformationCopyDictionary (&psn,
+ kProcessDictionaryIncludeAllInformationMask);
+ if (cfdict) {
+ NSDictionary *dict = (NSDictionary *) cfdict;
+ NSString *path = [dict objectForKey:@"BundlePath"];
+ if (path && [path hasSuffix:target])
+ found = YES;
+ CFRelease (cfdict);
+ }
+ if (found)
+ break;
+ }
+ return found;
+}
+
+
+// If the screen saver is not running, then launch the updater.
+// Otherwise, wait a while and try again. This is because if the
+// updater tries to pop up a dialog box while the screen saver is
+// active, everything goes to hell and it never shows up.
+//
+- (void) awaitScreenSaverTermination:(SUUpdater *)updater
+{
+ if ([self screenSaverActive]) {
+ static float delay = 1;
+ [NSTimer scheduledTimerWithTimeInterval: delay
+ target:self
+ selector:@selector(awaitScreenSaverTerminationTimer:)
+ userInfo:updater
+ repeats:NO];
+ // slightly exponential back-off
+ delay *= 1.3;
+ if (delay > 120)
+ delay = 120;
+ } else {
+ // Launch the updater thread.
+ [updater checkForUpdatesInBackground];
+
+ // Now we need to wait for the Sparkle thread to finish before we can
+ // exit, so just poll waiting for it.
+ //
+ [NSTimer scheduledTimerWithTimeInterval:1
+ target:self
+ selector:@selector(exitWhenDone:)
+ userInfo:updater
+ repeats:YES];
+ }
+}
+
+
+- (void) awaitScreenSaverTerminationTimer:(NSTimer *)timer
+{
+ [self awaitScreenSaverTermination:[timer userInfo]];
+}
+
+