From http://www.jwz.org/xscreensaver/xscreensaver-5.26.tar.gz
[xscreensaver] / OSX / Updater.m
index f7cd8c68097b572a15e2bdec8746e7d049972bdd..2e3ccbe1a2acf1b69b53e0bc65a915b36eea8851 100644 (file)
 
 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
 {
-  SUUpdater *updater = [SUUpdater updaterForBundle:
-                                    [NSBundle bundleForClass:[self class]]];
   NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
   [defs registerDefaults:UPDATER_DEFAULTS];
 
+  SUUpdater *updater = [SUUpdater updaterForBundle:
+                                    [NSBundle bundleForClass:[self class]]];
   [updater setDelegate:self];
 
-  // 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];
+  [self awaitScreenSaverTermination:updater];
 }
 
+
 // Delegate method that lets us append extra info to the system-info URL.
 //
 - (NSArray *) feedParametersForUpdater:(SUUpdater *)updater
 }
 
 
+// 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]];
+}
+
+
 - (void) exitWhenDone:(NSTimer *)timer
 {
   SUUpdater *updater = [timer userInfo];
     [[NSApplication sharedApplication] terminate:self];
 }
 
+
 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app
 {
   return YES;