summaryrefslogtreecommitdiffstats
path: root/OSX/Updater.m
diff options
context:
space:
mode:
authorSimon Rettberg2018-10-16 10:08:48 +0200
committerSimon Rettberg2018-10-16 10:08:48 +0200
commitd3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch)
treecbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /OSX/Updater.m
downloadxscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip
Original 5.40
Diffstat (limited to 'OSX/Updater.m')
-rw-r--r--OSX/Updater.m176
1 files changed, 176 insertions, 0 deletions
diff --git a/OSX/Updater.m b/OSX/Updater.m
new file mode 100644
index 0000000..1bf29fa
--- /dev/null
+++ b/OSX/Updater.m
@@ -0,0 +1,176 @@
+/* xscreensaver, Copyright (c) 2013 Jamie Zawinski <jwz@jwz.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * XScreenSaverUpdater.app -- downloads and installs XScreenSaver updates
+ * via Sparkle.framework.
+ *
+ * Created: 7-Dec-2013
+ *
+ * NOTE: This does not work with Sparkle 1.5b6 -- it requires the "HEAD"
+ * version 4-Dec-2013 or later.
+ */
+
+#import "Updater.h"
+#import "Sparkle/SUUpdater.h"
+
+@implementation XScreenSaverUpdater : NSObject
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
+{
+ NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
+ [defs registerDefaults:UPDATER_DEFAULTS];
+
+ // If it's not time to run the updater, then bail immediately.
+ // I'm not sure why this is necessary, but Sparkle seems to be
+ // checking too often.
+ //
+ if (! [self timeToCheck])
+ [[NSApplication sharedApplication] terminate:self];
+
+ // If the screen saver is not running, then launch the updater now.
+ // Otherwise, wait until the screen saver deactivates, and then do
+ // it. 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. You'd expect the dialog to just map below the
+ // screen saver window, but no.
+
+ if (! [self screenSaverActive]) {
+ [self runUpdater];
+ } else {
+ // Run the updater when the "screensaver.didstop" notification arrives.
+ [[NSDistributedNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(saverStoppedNotification:)
+ name:@"com.apple.screensaver.didstop"
+ object:nil];
+
+ // But I'm not sure I trust that, so also poll every couple minutes.
+ timer = [NSTimer scheduledTimerWithTimeInterval: 60 * 2
+ target:self
+ selector:@selector(pollSaverTermination:)
+ userInfo:nil
+ repeats:YES];
+ }
+}
+
+
+- (BOOL) timeToCheck
+{
+ NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
+ NSTimeInterval interval = [defs doubleForKey:@SUScheduledCheckIntervalKey];
+ NSDate *last = [defs objectForKey:@SULastCheckTimeKey];
+ if (!interval || !last)
+ return YES;
+ NSTimeInterval since = [[NSDate date] timeIntervalSinceDate:last];
+ return (since > interval);
+}
+
+
+// Whether ScreenSaverEngine is currently running, meaning screen is blanked.
+// There's no easy way to determine this other than scanning the process table.
+//
+- (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;
+}
+
+
+- (void) saverStoppedNotification:(NSNotification *)note
+{
+ [self runUpdater];
+}
+
+
+- (void) pollSaverTermination:(NSTimer *)t
+{
+ if (! [self screenSaverActive])
+ [self runUpdater];
+}
+
+
+- (void) runUpdater
+{
+ if (timer) {
+ [timer invalidate];
+ timer = nil;
+ }
+
+ 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(pollUpdaterTermination:)
+ userInfo:updater
+ repeats:YES];
+}
+
+
+// Delegate method that lets us append extra info to the system-info URL.
+//
+- (NSArray *) feedParametersForUpdater:(SUUpdater *)updater
+ sendingSystemProfile:(BOOL)sending
+{
+ // Get the name of the saver that invoked us, and include that in the
+ // system info.
+ NSString *saver = [[[NSProcessInfo processInfo] environment]
+ objectForKey:@"XSCREENSAVER_CLASSPATH"];
+ if (! saver) return @[];
+ NSString *head = @"org.jwz.xscreensaver.";
+ if ([saver hasPrefix:head])
+ saver = [saver substringFromIndex:[head length]];
+
+ return @[ @{ @"key": @"saver",
+ @"value": saver,
+ @"displayKey": @"Current Saver",
+ @"displayValue": saver
+ }
+ ];
+}
+
+
+- (void) pollUpdaterTermination:(NSTimer *)t
+{
+ SUUpdater *updater = [t userInfo];
+ if (![updater updateInProgress])
+ [[NSApplication sharedApplication] terminate:self];
+}
+
+
+- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)app
+{
+ return YES;
+}
+
+@end