summaryrefslogtreecommitdiffstats
path: root/OSX/SaverRunner.m
diff options
context:
space:
mode:
Diffstat (limited to 'OSX/SaverRunner.m')
-rw-r--r--OSX/SaverRunner.m1646
1 files changed, 0 insertions, 1646 deletions
diff --git a/OSX/SaverRunner.m b/OSX/SaverRunner.m
deleted file mode 100644
index 8ab45c1..0000000
--- a/OSX/SaverRunner.m
+++ /dev/null
@@ -1,1646 +0,0 @@
-/* xscreensaver, Copyright (c) 2006-2018 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.
- */
-
-/* This program serves three purposes:
-
- First, It is a test harness for screen savers. When it launches, it
- looks around for .saver bundles (in the current directory, and then in
- the standard directories) and puts up a pair of windows that allow you
- to select the saver to run. This is less clicking than running them
- through System Preferences. This is the "SaverTester.app" program.
-
- Second, it can be used to transform any screen saver into a standalone
- program. Just put one (and only one) .saver bundle into the app
- bundle's Contents/Resources/ directory, and it will load and run that
- saver at start-up (without the saver-selection menu or other chrome).
- This is how the "Phosphor.app" and "Apple2.app" programs work.
-
- Third, it is the scaffolding which turns a set of screen savers into
- a single iPhone / iPad program. In that case, all of the savers are
- linked in to this executable, since iOS does not allow dynamic loading
- of bundles that have executable code in them. Bleh.
- */
-
-#import <TargetConditionals.h>
-#import "SaverRunner.h"
-#import "SaverListController.h"
-#import "XScreenSaverGLView.h"
-#import "yarandom.h"
-
-#ifdef USE_IPHONE
-
-# ifndef __IPHONE_8_0
-# define UIInterfaceOrientationUnknown UIDeviceOrientationUnknown
-# endif
-# ifndef NSFoundationVersionNumber_iOS_7_1
-# define NSFoundationVersionNumber_iOS_7_1 1047.25
-# endif
-# ifndef NSFoundationVersionNumber_iOS_8_0
-# define NSFoundationVersionNumber_iOS_8_0 1134.10
-# endif
-
-@interface RotateyViewController : UINavigationController
-{
- BOOL allowRotation;
-}
-@end
-
-@implementation RotateyViewController
-
-/* This subclass exists so that we can ask that the SaverListController and
- preferences panels be auto-rotated by the system. Note that the
- XScreenSaverView is not auto-rotated because it is on a different UIWindow.
- */
-
-- (id)initWithRotation:(BOOL)rotatep
-{
- self = [super init];
- allowRotation = rotatep;
- return self;
-}
-
-- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)o
-{
- return allowRotation; /* Deprecated in iOS 6 */
-}
-
-- (BOOL)shouldAutorotate /* Added in iOS 6 */
-{
- return allowRotation;
-}
-
-- (UIInterfaceOrientationMask)supportedInterfaceOrientations /* Added in iOS 6 */
-{
- return UIInterfaceOrientationMaskAll;
-}
-
-@end
-
-
-@implementation SaverViewController
-
-@synthesize saverName;
-
-- (id)initWithSaverRunner:(SaverRunner *)parent
- showAboutBox:(BOOL)showAboutBox
-{
- self = [super init];
- if (self) {
- _parent = parent;
- // _storedOrientation = UIInterfaceOrientationUnknown;
- _showAboutBox = showAboutBox;
-
- self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
-
-# ifndef __IPHONE_7_0
- self.wantsFullScreenLayout = YES; // Deprecated as of iOS 7
-# endif
- }
- return self;
-}
-
-- (BOOL) prefersStatusBarHidden
-{
- // Requires UIViewControllerBasedStatusBarAppearance = true in plist
- return YES;
-}
-
-- (void)dealloc
-{
- [_saverName release];
- // iOS: When a UIView deallocs, it doesn't do [UIView removeFromSuperView]
- // for its subviews, so the subviews end up with a dangling pointer in their
- // superview properties.
- [aboutBox removeFromSuperview];
- [aboutBox release];
- [_saverView removeFromSuperview];
- [_saverView release];
- [super dealloc];
-}
-
-
-- (void)loadView
-{
- // The UIViewController's view must never change, so it gets set here to
- // a plain black background.
-
- // This background view doesn't block the status bar, but that's probably
- // OK, because it's never on screen for more than a fraction of a second.
- UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectNull];
- backgroundView.backgroundColor = [UIColor blackColor];
- self.view = backgroundView;
- [backgroundView release];
-}
-
-
-- (void)aboutPanel:(UIView *)saverView
- orientation:(UIInterfaceOrientation)orient
-{
- if (!_showAboutBox)
- return;
-
- NSString *name = _saverName;
- NSString *year = [_parent makeDesc:_saverName yearOnly:YES];
-
-
- CGRect frame = [saverView frame];
- CGFloat rot;
- CGFloat pt1 = 24;
- CGFloat pt2 = 14;
- UIFont *font1 = [UIFont boldSystemFontOfSize: pt1];
- UIFont *font2 = [UIFont italicSystemFontOfSize:pt2];
-
-# ifdef __IPHONE_7_0
- CGSize s = CGSizeMake(frame.size.width, frame.size.height);
- CGSize tsize1 = [[[NSAttributedString alloc]
- initWithString: name
- attributes:@{ NSFontAttributeName: font1 }]
- boundingRectWithSize: s
- options: NSStringDrawingUsesLineFragmentOrigin
- context: nil].size;
- CGSize tsize2 = [[[NSAttributedString alloc]
- initWithString: name
- attributes:@{ NSFontAttributeName: font2 }]
- boundingRectWithSize: s
- options: NSStringDrawingUsesLineFragmentOrigin
- context: nil].size;
-# else // iOS 6 or Cocoa
- CGSize tsize1 = [name sizeWithFont:font1
- constrainedToSize:CGSizeMake(frame.size.width,
- frame.size.height)];
- CGSize tsize2 = [year sizeWithFont:font2
- constrainedToSize:CGSizeMake(frame.size.width,
- frame.size.height)];
-# endif
-
- CGSize tsize = CGSizeMake (tsize1.width > tsize2.width ?
- tsize1.width : tsize2.width,
- tsize1.height + tsize2.height);
-
- tsize.width = ceilf(tsize.width);
- tsize.height = ceilf(tsize.height);
-
- // Don't know how to find inner margin of UITextView.
- CGFloat margin = 10;
- tsize.width += margin * 4;
- tsize.height += margin * 2;
-
- if ([saverView frame].size.width >= 768)
- tsize.height += pt1 * 3; // extra bottom margin on iPad
-
- frame = CGRectMake (0, 0, tsize.width, tsize.height);
-
- /* Get the text oriented properly, and move it to the bottom of the
- screen, since many savers have action in the middle.
- */
- switch (orient) {
- case UIInterfaceOrientationLandscapeLeft:
- rot = -M_PI/2;
- frame.origin.x = ([saverView frame].size.width
- - (tsize.width - tsize.height) / 2
- - tsize.height);
- frame.origin.y = ([saverView frame].size.height - tsize.height) / 2;
- break;
- case UIInterfaceOrientationLandscapeRight:
- rot = M_PI/2;
- frame.origin.x = -(tsize.width - tsize.height) / 2;
- frame.origin.y = ([saverView frame].size.height - tsize.height) / 2;
- break;
- case UIInterfaceOrientationPortraitUpsideDown:
- rot = M_PI;
- frame.origin.x = ([saverView frame].size.width - tsize.width) / 2;
- frame.origin.y = 0;
- break;
- default:
- rot = 0;
- frame.origin.x = ([saverView frame].size.width - tsize.width) / 2;
- frame.origin.y = [saverView frame].size.height - tsize.height;
- break;
- }
-
- if (aboutBox) {
- [aboutBox removeFromSuperview];
- [aboutBox release];
- }
-
- aboutBox = [[UIView alloc] initWithFrame:frame];
-
- aboutBox.transform = CGAffineTransformMakeRotation (rot);
- aboutBox.backgroundColor = [UIColor clearColor];
-
- /* There seems to be no easy way to stroke the font, so instead draw
- it 5 times, 4 in black and 1 in yellow, offset by 1 pixel, and add
- a black shadow to each. (You'd think the shadow alone would be
- enough, but there's no way to make it dark enough to be legible.)
- */
- for (int i = 0; i < 5; i++) {
- UITextView *textview;
- int off = 1;
- frame.origin.x = frame.origin.y = 0;
- switch (i) {
- case 0: frame.origin.x = -off; break;
- case 1: frame.origin.x = off; break;
- case 2: frame.origin.y = -off; break;
- case 3: frame.origin.y = off; break;
- }
-
- for (int j = 0; j < 2; j++) {
-
- frame.origin.y = (j == 0 ? 0 : pt1);
- textview = [[UITextView alloc] initWithFrame:frame];
- textview.font = (j == 0 ? font1 : font2);
- textview.text = (j == 0 ? name : year);
- textview.textAlignment = NSTextAlignmentCenter;
- textview.showsHorizontalScrollIndicator = NO;
- textview.showsVerticalScrollIndicator = NO;
- textview.scrollEnabled = NO;
- textview.editable = NO;
- textview.userInteractionEnabled = NO;
- textview.backgroundColor = [UIColor clearColor];
- textview.textColor = (i == 4
- ? [UIColor yellowColor]
- : [UIColor blackColor]);
-
- CALayer *textLayer = (CALayer *)
- [textview.layer.sublayers objectAtIndex:0];
- textLayer.shadowColor = [UIColor blackColor].CGColor;
- textLayer.shadowOffset = CGSizeMake(0, 0);
- textLayer.shadowOpacity = 1;
- textLayer.shadowRadius = 2;
-
- [aboutBox addSubview:textview];
- }
- }
-
- CABasicAnimation *anim =
- [CABasicAnimation animationWithKeyPath:@"opacity"];
- anim.duration = 0.3;
- anim.repeatCount = 1;
- anim.autoreverses = NO;
- anim.fromValue = [NSNumber numberWithFloat:0.0];
- anim.toValue = [NSNumber numberWithFloat:1.0];
- [aboutBox.layer addAnimation:anim forKey:@"animateOpacity"];
-
- [saverView addSubview:aboutBox];
-
- if (splashTimer)
- [splashTimer invalidate];
-
- splashTimer =
- [NSTimer scheduledTimerWithTimeInterval: anim.duration + 2
- target:self
- selector:@selector(aboutOff)
- userInfo:nil
- repeats:NO];
-}
-
-
-- (void)aboutOff
-{
- [self aboutOff:FALSE];
-}
-
-- (void)aboutOff:(BOOL)fast
-{
- if (aboutBox) {
- if (splashTimer) {
- [splashTimer invalidate];
- splashTimer = 0;
- }
- if (fast) {
- aboutBox.layer.opacity = 0;
- return;
- }
-
- CABasicAnimation *anim =
- [CABasicAnimation animationWithKeyPath:@"opacity"];
- anim.duration = 0.3;
- anim.repeatCount = 1;
- anim.autoreverses = NO;
- anim.fromValue = [NSNumber numberWithFloat: 1];
- anim.toValue = [NSNumber numberWithFloat: 0];
- // anim.delegate = self;
- aboutBox.layer.opacity = 0;
- [aboutBox.layer addAnimation:anim forKey:@"animateOpacity"];
- }
-}
-
-
-- (void)createSaverView
-{
- UIView *parentView = self.view;
-
- if (_saverView) {
- [_saverView removeFromSuperview];
- [_saverView release];
- }
-
-# if 0
- if (_storedOrientation != UIInterfaceOrientationUnknown) {
- [[UIApplication sharedApplication]
- setStatusBarOrientation:_storedOrientation
- animated:NO];
- }
-# endif
-
- _saverView = [_parent newSaverView:_saverName
- withSize:parentView.bounds.size];
-
- if (! _saverView) {
- UIAlertController *c = [UIAlertController
- alertControllerWithTitle:@"Unable to load!"
- message:@""
- preferredStyle:UIAlertControllerStyleAlert];
- [c addAction: [UIAlertAction actionWithTitle: @"Bummer"
- style: UIAlertActionStyleDefault
- handler: ^(UIAlertAction *a) {
- // #### Should expose the SaverListController...
- }]];
- [self presentViewController:c animated:YES completion:nil];
-
- return;
- }
-
- _saverView.delegate = _parent;
- _saverView.autoresizingMask =
- UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-
- [self.view addSubview:_saverView];
-
- // The first responder must be set only after the view was placed in the view
- // heirarchy.
- [_saverView becomeFirstResponder]; // For shakes on iOS 6.
- [_saverView startAnimation];
- [self aboutPanel:_saverView
- orientation:/* _storedOrientation */ UIInterfaceOrientationPortrait];
-}
-
-
-- (void)viewDidAppear:(BOOL)animated
-{
- [super viewDidAppear:animated];
- [self createSaverView];
-}
-
-
-- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)o
-{
- return NO; /* Deprecated in iOS 6 */
-}
-
-
-- (BOOL)shouldAutorotate /* Added in iOS 6 */
-{
- return
- NSFoundationVersionNumber < NSFoundationVersionNumber_iOS_8_0 ?
- ![_saverView suppressRotationAnimation] :
- YES;
-}
-
-
-- (UIInterfaceOrientationMask)supportedInterfaceOrientations /* Added in iOS 6 */
-{
- // Lies from the iOS docs:
- // "This method is only called if the view controller's shouldAutorotate
- // method returns YES."
- return UIInterfaceOrientationMaskAll;
-}
-
-
-/*
-- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
-{
- return UIInterfaceOrientationPortrait;
-}
-*/
-
-
-- (void)setSaverName:(NSString *)name
-{
- [name retain];
- [_saverName release];
- _saverName = name;
- // _storedOrientation =
- // [UIApplication sharedApplication].statusBarOrientation;
-
- if (_saverView)
- [self createSaverView];
-}
-
-
-- (void)viewWillTransitionToSize: (CGSize)size
- withTransitionCoordinator:
- (id<UIViewControllerTransitionCoordinator>) coordinator
-{
- [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
-
- if (!_saverView)
- return;
-
- [CATransaction begin];
-
- // Completely suppress the rotation animation, since we
- // will not (visually) be rotating at all.
- if ([_saverView suppressRotationAnimation])
- [CATransaction setDisableActions:YES];
-
- [self aboutOff:TRUE]; // It does goofy things if we rotate while it's up
-
- [coordinator animateAlongsideTransition:^
- (id <UIViewControllerTransitionCoordinatorContext> context) {
- // This executes repeatedly during the rotation.
- } completion:^(id <UIViewControllerTransitionCoordinatorContext> context) {
- // This executes once when the rotation has finished.
- [CATransaction commit];
- [_saverView orientationChanged];
- }];
- // No code goes here, as it would execute before the above completes.
-}
-
-@end
-
-#endif // USE_IPHONE
-
-
-@implementation SaverRunner
-
-
-- (XScreenSaverView *) newSaverView: (NSString *) module
- withSize: (NSSize) size
-{
- Class new_class = 0;
-
-# ifndef USE_IPHONE
-
- // Load the XScreenSaverView subclass and code from a ".saver" bundle.
-
- NSString *name = [module stringByAppendingPathExtension:@"saver"];
- NSString *path = [saverDir stringByAppendingPathComponent:name];
-
- if (! [[NSFileManager defaultManager] fileExistsAtPath:path]) {
- NSLog(@"bundle \"%@\" does not exist", path);
- return 0;
- }
-
- NSLog(@"Loading %@", path);
-
- // NSBundle *obundle = saverBundle;
-
- saverBundle = [NSBundle bundleWithPath:path];
- if (saverBundle)
- new_class = [saverBundle principalClass];
-
- // Not entirely unsurprisingly, this tends to break the world.
- // if (obundle && obundle != saverBundle)
- // [obundle unload];
-
-# else // USE_IPHONE
-
- // Determine whether to create an X11 view or an OpenGL view by
- // looking for the "gl" tag in the xml file. This is kind of awful.
-
- NSString *path = [saverDir
- stringByAppendingPathComponent:
- [[[module lowercaseString]
- stringByReplacingOccurrencesOfString:@" "
- withString:@""]
- stringByAppendingPathExtension:@"xml"]];
- NSData *xmld = [NSData dataWithContentsOfFile:path];
- NSAssert (xmld, @"no XML: %@", path);
- NSString *xml = [XScreenSaverView decompressXML:xmld];
- Bool gl_p = (xml && [xml rangeOfString:@"gl=\"yes\""].length > 0);
-
- new_class = (gl_p
- ? [XScreenSaverGLView class]
- : [XScreenSaverView class]);
-
-# endif // USE_IPHONE
-
- if (! new_class)
- return 0;
-
- NSRect rect;
- rect.origin.x = rect.origin.y = 0;
- rect.size.width = size.width;
- rect.size.height = size.height;
-
- XScreenSaverView *instance =
- [(XScreenSaverView *) [new_class alloc]
- initWithFrame:rect
- saverName:module
- isPreview:YES];
- if (! instance) {
- NSLog(@"Failed to instantiate %@ for \"%@\"", new_class, module);
- return 0;
- }
-
-
- /* KLUGE: Inform the underlying program that we're in "standalone"
- mode, e.g. running as "Phosphor.app" rather than "Phosphor.saver".
- This is kind of horrible but I haven't thought of a more sensible
- way to make this work.
- */
-# ifndef USE_IPHONE
- if ([saverNames count] == 1) {
- setenv ("XSCREENSAVER_STANDALONE", "1", 1);
- }
-# endif
-
- return (XScreenSaverView *) instance;
-}
-
-
-#ifndef USE_IPHONE
-
-static ScreenSaverView *
-find_saverView_child (NSView *v)
-{
- NSArray *kids = [v subviews];
- NSUInteger nkids = [kids count];
- NSUInteger i;
- for (i = 0; i < nkids; i++) {
- NSObject *kid = [kids objectAtIndex:i];
- if ([kid isKindOfClass:[ScreenSaverView class]]) {
- return (ScreenSaverView *) kid;
- } else {
- ScreenSaverView *sv = find_saverView_child ((NSView *) kid);
- if (sv) return sv;
- }
- }
- return 0;
-}
-
-
-static ScreenSaverView *
-find_saverView (NSView *v)
-{
- while (1) {
- NSView *p = [v superview];
- if (p) v = p;
- else break;
- }
- return find_saverView_child (v);
-}
-
-
-/* Changes the contents of the menubar menus to correspond to
- the running saver. Desktop only.
- */
-static void
-relabel_menus (NSObject *v, NSString *old_str, NSString *new_str)
-{
- if ([v isKindOfClass:[NSMenu class]]) {
- NSMenu *m = (NSMenu *)v;
- [m setTitle: [[m title] stringByReplacingOccurrencesOfString:old_str
- withString:new_str]];
- NSArray *kids = [m itemArray];
- NSUInteger nkids = [kids count];
- NSUInteger i;
- for (i = 0; i < nkids; i++) {
- relabel_menus ([kids objectAtIndex:i], old_str, new_str);
- }
- } else if ([v isKindOfClass:[NSMenuItem class]]) {
- NSMenuItem *mi = (NSMenuItem *)v;
- [mi setTitle: [[mi title] stringByReplacingOccurrencesOfString:old_str
- withString:new_str]];
- NSMenu *m = [mi submenu];
- if (m) relabel_menus (m, old_str, new_str);
- }
-}
-
-
-- (void) openPreferences: (id) sender
-{
- ScreenSaverView *sv;
- if ([sender isKindOfClass:[NSView class]]) { // Sent from button
- sv = find_saverView ((NSView *) sender);
- } else {
- long i;
- NSWindow *w = 0;
- for (i = [windows count]-1; i >= 0; i--) { // Sent from menubar
- w = [windows objectAtIndex:i];
- if ([w isKeyWindow]) break;
- }
- sv = find_saverView ([w contentView]);
- }
-
- NSAssert (sv, @"no saver view");
- if (!sv) return;
- NSWindow *prefs = [sv configureSheet];
-
- [NSApp beginSheet:prefs
- modalForWindow:[sv window]
- modalDelegate:self
- didEndSelector:@selector(preferencesClosed:returnCode:contextInfo:)
- contextInfo:nil];
- NSUInteger code = [NSApp runModalForWindow:prefs];
-
- /* Restart the animation if the "OK" button was hit, but not if "Cancel".
- We have to restart *both* animations, because the xlockmore-style
- ones will blow up if one re-inits but the other doesn't.
- */
- if (code != NSCancelButton) {
- if ([sv isAnimating])
- [sv stopAnimation];
- [sv startAnimation];
- }
-}
-
-
-- (void) preferencesClosed: (NSWindow *) sheet
- returnCode: (int) returnCode
- contextInfo: (void *) contextInfo
-{
- [NSApp stopModalWithCode:returnCode];
-}
-
-#else // USE_IPHONE
-
-
-- (UIImage *) screenshot
-{
- return saved_screenshot;
-}
-
-- (void) saveScreenshot
-{
- // Most of this is from:
- // http://developer.apple.com/library/ios/#qa/qa1703/_index.html
- // The rotation stuff is by me.
-
- CGSize size = [[UIScreen mainScreen] bounds].size;
-
- // iOS 7: Needs to be [[window rootViewController] interfaceOrientation].
- // iOS 8: Needs to be UIInterfaceOrientationPortrait.
- // (interfaceOrientation deprecated in iOS 8)
-
- UIInterfaceOrientation orient = UIInterfaceOrientationPortrait;
- /* iOS 8 broke -[UIScreen bounds]. */
-
- if (orient == UIInterfaceOrientationLandscapeLeft ||
- orient == UIInterfaceOrientationLandscapeRight) {
- // Rotate the shape of the canvas 90 degrees.
- double s = size.width;
- size.width = size.height;
- size.height = s;
- }
-
-
- // Create a graphics context with the target size
- // On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to
- // take the scale into consideration
- // On iOS prior to 4, fall back to use UIGraphicsBeginImageContext
-
- UIGraphicsBeginImageContextWithOptions (size, NO, 0);
-
- CGContextRef ctx = UIGraphicsGetCurrentContext();
-
-
- // Rotate the graphics context to match current hardware rotation.
- //
- switch (orient) {
- case UIInterfaceOrientationPortraitUpsideDown:
- CGContextTranslateCTM (ctx, [window center].x, [window center].y);
- CGContextRotateCTM (ctx, M_PI);
- CGContextTranslateCTM (ctx, -[window center].x, -[window center].y);
- break;
- case UIInterfaceOrientationLandscapeLeft:
- case UIInterfaceOrientationLandscapeRight:
- CGContextTranslateCTM (ctx,
- ([window frame].size.height -
- [window frame].size.width) / 2,
- ([window frame].size.width -
- [window frame].size.height) / 2);
- CGContextTranslateCTM (ctx, [window center].x, [window center].y);
- CGContextRotateCTM (ctx,
- (orient == UIInterfaceOrientationLandscapeLeft
- ? M_PI/2
- : -M_PI/2));
- CGContextTranslateCTM (ctx, -[window center].x, -[window center].y);
- break;
- default:
- break;
- }
-
- // Iterate over every window from back to front
- //
- for (UIWindow *win in [[UIApplication sharedApplication] windows]) {
- if (![win respondsToSelector:@selector(screen)] ||
- [win screen] == [UIScreen mainScreen]) {
-
- // -renderInContext: renders in the coordinate space of the layer,
- // so we must first apply the layer's geometry to the graphics context
- CGContextSaveGState (ctx);
-
- // Center the context around the window's anchor point
- CGContextTranslateCTM (ctx, [win center].x, [win center].y);
-
- // Apply the window's transform about the anchor point
- CGContextConcatCTM (ctx, [win transform]);
-
- // Offset by the portion of the bounds left of and above anchor point
- CGContextTranslateCTM (ctx,
- -[win bounds].size.width * [[win layer] anchorPoint].x,
- -[win bounds].size.height * [[win layer] anchorPoint].y);
-
- // Render the layer hierarchy to the current context
- [[win layer] renderInContext:ctx];
-
- // Restore the context
- CGContextRestoreGState (ctx);
- }
- }
-
- if (saved_screenshot)
- [saved_screenshot release];
- saved_screenshot = [UIGraphicsGetImageFromCurrentImageContext() retain];
-
- UIGraphicsEndImageContext();
-}
-
-
-- (void) openPreferences: (NSString *) saver
-{
- XScreenSaverView *saverView = [self newSaverView:saver
- withSize:CGSizeMake(0, 0)];
- if (! saverView) return;
-
- NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
- [prefs setObject:saver forKey:@"selectedSaverName"];
- [prefs synchronize];
-
- [rotating_nav pushViewController: [saverView configureView]
- animated:YES];
-}
-
-
-#endif // USE_IPHONE
-
-
-
-- (void)loadSaver:(NSString *)name
-{
-# ifndef USE_IPHONE
-
- if (saverName && [saverName isEqualToString: name]) {
- for (NSWindow *win in windows) {
- ScreenSaverView *sv = find_saverView ([win contentView]);
- if (![sv isAnimating])
- [sv startAnimation];
- }
- return;
- }
-
- saverName = name;
-
- for (NSWindow *win in windows) {
- NSView *cv = [win contentView];
- NSString *old_title = [win title];
- if (!old_title) old_title = @"XScreenSaver";
- [win setTitle: name];
- relabel_menus (menubar, old_title, name);
-
- ScreenSaverView *old_view = find_saverView (cv);
- NSView *sup = old_view ? [old_view superview] : cv;
-
- if (old_view) {
- if ([old_view isAnimating])
- [old_view stopAnimation];
- [old_view removeFromSuperview];
- }
-
- NSSize size = [cv frame].size;
- ScreenSaverView *new_view = [self newSaverView:name withSize: size];
- NSAssert (new_view, @"unable to make a saver view");
-
- [new_view setFrame: (old_view ? [old_view frame] : [cv frame])];
- [sup addSubview: new_view];
- [win makeFirstResponder:new_view];
- [new_view setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
- [new_view startAnimation];
- [new_view release];
- }
-
- NSUserDefaultsController *ctl =
- [NSUserDefaultsController sharedUserDefaultsController];
- [ctl save:self];
-
-# else // USE_IPHONE
-
-# if !defined __OPTIMIZE__ || TARGET_IPHONE_SIMULATOR
- NSLog (@"selecting saver \"%@\"", name);
-# endif
-
- NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
- [prefs setObject:name forKey:@"selectedSaverName"];
- [prefs synchronize];
-
-/* Cacheing this screws up rotation when starting a saver twice in a row.
- if (saverName && [saverName isEqualToString: name]) {
- if ([saverView isAnimating])
- return;
- else
- goto LAUNCH;
- }
-*/
-
- saverName = name;
-
- if (nonrotating_controller) {
- nonrotating_controller.saverName = name;
- return;
- }
-
-# if !defined __OPTIMIZE__ || TARGET_IPHONE_SIMULATOR
- UIScreen *screen = [UIScreen mainScreen];
-
- /* 'nativeScale' is very confusing.
-
- iPhone 4s:
- bounds: 320x480 scale: 2
- nativeBounds: 640x960 nativeScale: 2
- iPhone 5s:
- bounds: 320x568 scale: 2
- nativeBounds: 640x1136 nativeScale: 2
- iPad 2:
- bounds: 768x1024 scale: 1
- nativeBounds: 768x1024 nativeScale: 1
- iPad Retina/Air:
- bounds: 768x1024 scale: 2
- nativeBounds: 1536x2048 nativeScale: 2
- iPhone 6:
- bounds: 320x568 scale: 2
- nativeBounds: 640x1136 nativeScale: 2
- iPhone 6+:
- bounds: 320x568 scale: 2
- nativeBounds: 960x1704 nativeScale: 3
-
- According to a StackOverflow comment:
-
- The iPhone 6+ renders internally using @3x assets at a virtual
- resolution of 2208x1242 (with 736x414 points), then samples that down
- for display. The same as using a scaled resolution on a Retina MacBook
- -- it lets them hit an integral multiple for pixel assets while still
- having e.g. 12pt text look the same size on the screen.
-
- The 6, the 5s, the 5, the 4s and the 4 are all 326 pixels per inch,
- and use @2x assets to stick to the approximately 160 points per inch
- of all previous devices.
-
- The 6+ is 401 pixels per inch. So it'd hypothetically need roughly
- @2.46x assets. Instead Apple uses @3x assets and scales the complete
- output down to about 84% of its natural size.
-
- In practice Apple has decided to go with more like 87%, turning the
- 1080 into 1242. No doubt that was to find something as close as
- possible to 84% that still produced integral sizes in both directions
- -- 1242/1080 = 2208/1920 exactly, whereas if you'd turned the 1080
- into, say, 1286, you'd somehow need to render 2286.22 pixels
- vertically to scale well.
- */
-
- NSLog(@"screen: %.0fx%0.f",
- [[screen currentMode] size].width,
- [[screen currentMode] size].height);
- NSLog(@"bounds: %.0fx%0.f x %.1f = %.0fx%0.f",
- [screen bounds].size.width,
- [screen bounds].size.height,
- [screen scale],
- [screen scale] * [screen bounds].size.width,
- [screen scale] * [screen bounds].size.height);
-
-# ifdef __IPHONE_8_0
- if ([screen respondsToSelector:@selector(nativeBounds)])
- NSLog(@"native: %.0fx%0.f / %.1f = %.0fx%0.f",
- [screen nativeBounds].size.width,
- [screen nativeBounds].size.height,
- [screen nativeScale],
- [screen nativeBounds].size.width / [screen nativeScale],
- [screen nativeBounds].size.height / [screen nativeScale]);
-# endif
-# endif // TARGET_IPHONE_SIMULATOR
-
- // Take the screen shot before creating the screen saver view, because this
- // can screw with the layout.
- [self saveScreenshot];
-
- // iOS 3.2. Before this were iPhones (and iPods) only, which always did modal
- // presentation full screen.
- rotating_nav.modalPresentationStyle = UIModalPresentationFullScreen;
-
- nonrotating_controller = [[SaverViewController alloc]
- initWithSaverRunner:self
- showAboutBox:[saverNames count] != 1];
- nonrotating_controller.saverName = name;
-
- /* LAUNCH: */
-
- [rotating_nav presentViewController:nonrotating_controller animated:NO completion:nil];
-
- // Doing this makes savers cut back to the list instead of fading,
- // even though [XScreenSaverView stopAndClose] does setHidden:NO first.
- // [window setHidden:YES];
-
-# endif // USE_IPHONE
-}
-
-
-#ifndef USE_IPHONE
-
-- (void)aboutPanel:(id)sender
-{
- NSDictionary *bd = [saverBundle infoDictionary];
- NSMutableDictionary *d = [NSMutableDictionary dictionaryWithCapacity:20];
-
- [d setValue:[bd objectForKey:@"CFBundleName"] forKey:@"ApplicationName"];
- [d setValue:[bd objectForKey:@"CFBundleVersion"] forKey:@"Version"];
- [d setValue:[bd objectForKey:@"CFBundleShortVersionString"]
- forKey:@"ApplicationVersion"];
- [d setValue:[bd objectForKey:@"NSHumanReadableCopyright"] forKey:@"Copy"];
- NSAttributedString *s = [[NSAttributedString alloc]
- initWithString: (NSString *)
- [bd objectForKey:@"CFBundleGetInfoString"]];
- [d setValue:s forKey:@"Credits"];
- [s release];
-
- [[NSApplication sharedApplication]
- orderFrontStandardAboutPanelWithOptions:d];
-}
-
-#endif // !USE_IPHONE
-
-
-
-- (void)selectedSaverDidChange:(NSDictionary *)change
-{
- NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
- NSString *name = [prefs stringForKey:@"selectedSaverName"];
-
- if (! name) return;
-
- if (! [saverNames containsObject:name]) {
- NSLog (@"saver \"%@\" does not exist", name);
- return;
- }
-
- [self loadSaver: name];
-}
-
-
-- (NSArray *) listSaverBundleNamesInDir:(NSString *)dir
-{
-# ifndef USE_IPHONE
- NSString *ext = @"saver";
-# else
- NSString *ext = @"xml";
-# endif
-
- NSArray *files = [[NSFileManager defaultManager]
- contentsOfDirectoryAtPath:dir error:nil];
- if (! files) return 0;
- NSMutableArray *result = [NSMutableArray arrayWithCapacity: [files count]+1];
-
- for (NSString *p in files) {
- if ([[p pathExtension] caseInsensitiveCompare: ext])
- continue;
-
- NSString *name = [[p lastPathComponent] stringByDeletingPathExtension];
-
-# ifdef USE_IPHONE
- // Get the saver name's capitalization right by reading the XML file.
-
- p = [dir stringByAppendingPathComponent: p];
- NSData *xmld = [NSData dataWithContentsOfFile:p];
- NSAssert (xmld, @"no XML: %@", p);
- NSString *xml = [XScreenSaverView decompressXML:xmld];
- NSRange r = [xml rangeOfString:@"_label=\"" options:0];
- NSAssert1 (r.length, @"no name in %@", p);
- if (r.length) {
- xml = [xml substringFromIndex: r.location + r.length];
- r = [xml rangeOfString:@"\"" options:0];
- if (r.length) name = [xml substringToIndex: r.location];
- }
-
-# endif // USE_IPHONE
-
- NSAssert1 (name, @"no name in %@", p);
- if (name) [result addObject: name];
- }
-
- if (result && [result count])
- return [result sortedArrayUsingSelector:
- @selector(localizedCaseInsensitiveCompare:)];
- else
- return 0;
-}
-
-
-
-- (NSArray *) listSaverBundleNames
-{
- NSMutableArray *dirs = [NSMutableArray arrayWithCapacity: 10];
-
-# ifndef USE_IPHONE
- // On MacOS, look in the "Contents/Resources/" and "Contents/PlugIns/"
- // directories in the bundle.
- [dirs addObject: [[[[NSBundle mainBundle] bundlePath]
- stringByAppendingPathComponent:@"Contents"]
- stringByAppendingPathComponent:@"Resources"]];
- [dirs addObject: [[NSBundle mainBundle] builtInPlugInsPath]];
-
- // Also look in the same directory as the executable.
- [dirs addObject: [[[NSBundle mainBundle] bundlePath]
- stringByDeletingLastPathComponent]];
-
- // Finally, look in standard MacOS screensaver directories.
-// [dirs addObject: @"~/Library/Screen Savers"];
-// [dirs addObject: @"/Library/Screen Savers"];
-// [dirs addObject: @"/System/Library/Screen Savers"];
-
-# else // USE_IPHONE
-
- // On iOS, only look in the bundle's root directory.
- [dirs addObject: [[NSBundle mainBundle] bundlePath]];
-
-# endif // USE_IPHONE
-
- int i;
- for (i = 0; i < [dirs count]; i++) {
- NSString *dir = [dirs objectAtIndex:i];
- NSArray *names = [self listSaverBundleNamesInDir:dir];
- if (! names) continue;
- saverDir = [dir retain];
- saverNames = [names retain];
- return names;
- }
-
- NSString *err = @"no .saver bundles found in: ";
- for (i = 0; i < [dirs count]; i++) {
- if (i) err = [err stringByAppendingString:@", "];
- err = [err stringByAppendingString:[[dirs objectAtIndex:i]
- stringByAbbreviatingWithTildeInPath]];
- err = [err stringByAppendingString:@"/"];
- }
- NSLog (@"%@", err);
- return [NSArray array];
-}
-
-
-/* Create the popup menu of available saver names.
- */
-#ifndef USE_IPHONE
-
-- (NSPopUpButton *) makeMenu
-{
- NSRect rect;
- rect.origin.x = rect.origin.y = 0;
- rect.size.width = 10;
- rect.size.height = 10;
- NSPopUpButton *popup = [[NSPopUpButton alloc] initWithFrame:rect
- pullsDown:NO];
- int i;
- float max_width = 0;
- for (i = 0; i < [saverNames count]; i++) {
- NSString *name = [saverNames objectAtIndex:i];
- [popup addItemWithTitle:name];
- [[popup itemWithTitle:name] setRepresentedObject:name];
- [popup sizeToFit];
- NSRect r = [popup frame];
- if (r.size.width > max_width) max_width = r.size.width;
- }
-
- // Bind the menu to preferences, and trigger a callback when an item
- // is selected.
- //
- NSString *key = @"values.selectedSaverName";
- NSUserDefaultsController *prefs =
- [NSUserDefaultsController sharedUserDefaultsController];
- [prefs addObserver:self
- forKeyPath:key
- options:0
- context:@selector(selectedSaverDidChange:)];
- [popup bind:@"selectedObject"
- toObject:prefs
- withKeyPath:key
- options:nil];
- [prefs setAppliesImmediately:YES];
-
- NSRect r = [popup frame];
- r.size.width = max_width;
- [popup setFrame:r];
- [popup autorelease];
- return popup;
-}
-
-#else // USE_IPHONE
-
-- (NSString *) makeDesc:(NSString *)saver
- yearOnly:(BOOL) yearp
-{
- NSString *desc = 0;
- NSString *path = [saverDir stringByAppendingPathComponent:
- [[saver lowercaseString]
- stringByReplacingOccurrencesOfString:@" "
- withString:@""]];
- NSRange r;
-
- path = [path stringByAppendingPathExtension:@"xml"];
- NSData *xmld = [NSData dataWithContentsOfFile:path];
- if (! xmld) goto FAIL;
- desc = [XScreenSaverView decompressXML:xmld];
- if (! desc) goto FAIL;
-
- r = [desc rangeOfString:@"<_description>"
- options:NSCaseInsensitiveSearch];
- if (r.length == 0) {
- desc = 0;
- goto FAIL;
- }
- desc = [desc substringFromIndex: r.location + r.length];
- r = [desc rangeOfString:@"</_description>"
- options:NSCaseInsensitiveSearch];
- if (r.length > 0)
- desc = [desc substringToIndex: r.location];
-
- // Leading and trailing whitespace.
- desc = [desc stringByTrimmingCharactersInSet:
- [NSCharacterSet whitespaceAndNewlineCharacterSet]];
-
- // Let's see if we can find a year on the last line.
- r = [desc rangeOfString:@"\n" options:NSBackwardsSearch];
- NSString *year = 0;
- for (NSString *word in
- [[desc substringFromIndex:r.location + r.length]
- componentsSeparatedByCharactersInSet:
- [NSCharacterSet characterSetWithCharactersInString:
- @" \t\n-."]]) {
- int n = [word doubleValue];
- if (n > 1970 && n < 2100)
- year = word;
- }
-
- // Delete everything after the first blank line.
- //
- r = [desc rangeOfString:@"\n\n" options:0];
- if (r.length > 0)
- desc = [desc substringToIndex: r.location];
-
- // Unwrap lines and compress whitespace.
- {
- NSString *result = @"";
- for (NSString *s in [desc componentsSeparatedByCharactersInSet:
- [NSCharacterSet whitespaceAndNewlineCharacterSet]]) {
- if ([result length] == 0)
- result = s;
- else if ([s length] > 0)
- result = [NSString stringWithFormat: @"%@ %@", result, s];
- desc = result;
- }
- }
-
- if (year)
- desc = [year stringByAppendingString:
- [@": " stringByAppendingString: desc]];
-
- if (yearp)
- desc = year ? year : @"";
-
-FAIL:
- if (! desc) {
- if ([saverNames count] > 1)
- desc = @"Oops, this module appears to be incomplete.";
- else
- desc = @"";
- }
-
- return desc;
-}
-
-- (NSString *) makeDesc:(NSString *)saver
-{
- return [self makeDesc:saver yearOnly:NO];
-}
-
-
-
-/* Create a dictionary of one-line descriptions of every saver,
- for display on the UITableView.
- */
-- (NSDictionary *)makeDescTable
-{
- NSMutableDictionary *dict =
- [NSMutableDictionary dictionaryWithCapacity:[saverNames count]];
- for (NSString *saver in saverNames) {
- [dict setObject:[self makeDesc:saver] forKey:saver];
- }
- return dict;
-}
-
-
-- (void) wantsFadeOut:(XScreenSaverView *)sender
-{
- rotating_nav.view.hidden = NO; // In case it was hidden during startup.
-
- /* The XScreenSaverView screws with the status bar orientation, mostly to
- keep the simulator oriented properly. But on iOS 8.1 (and maybe 8.0
- and/or 8.2), this confuses the UINavigationController, so put the
- orientation back to portrait before dismissing the SaverViewController.
- */
-# if 0
- [[UIApplication sharedApplication]
- setStatusBarOrientation:UIInterfaceOrientationPortrait
- animated:NO];
-# endif
-
- /* Make sure the most-recently-run saver is visible. Sometimes it ends
- up scrolled half a line off the bottom of the screen.
- */
- if (saverName) {
- for (UIViewController *v in [rotating_nav viewControllers]) {
- if ([v isKindOfClass:[SaverListController class]]) {
- [(SaverListController *)v scrollTo: saverName];
- break;
- }
- }
- }
-
- [rotating_nav dismissViewControllerAnimated:YES completion:^() {
- [nonrotating_controller release];
- nonrotating_controller = nil;
- [[rotating_nav view] becomeFirstResponder];
- }];
-}
-
-
-- (void) didShake:(XScreenSaverView *)sender
-{
-# if TARGET_IPHONE_SIMULATOR
- NSLog (@"simulating shake on saver list");
-# endif
- [[rotating_nav topViewController] motionEnded: UIEventSubtypeMotionShake
- withEvent: nil];
-}
-
-
-#endif // USE_IPHONE
-
-
-
-/* This is called when the "selectedSaverName" pref changes, e.g.,
- when a menu selection is made.
- */
-- (void)observeValueForKeyPath:(NSString *)keyPath
- ofObject:(id)object
- change:(NSDictionary *)change
- context:(void *)context
-{
- SEL dispatchSelector = (SEL)context;
- if (dispatchSelector != NULL) {
- [self performSelector:dispatchSelector withObject:change];
- } else {
- [super observeValueForKeyPath:keyPath
- ofObject:object
- change:change
- context:context];
- }
-}
-
-
-# ifndef USE_IPHONE
-
-/* Create the desktop window shell, possibly including a preferences button.
- */
-- (NSWindow *) makeWindow
-{
- NSRect rect;
- static int count = 0;
- Bool simple_p = ([saverNames count] == 1);
- NSButton *pb = 0;
- NSPopUpButton *menu = 0;
- NSBox *gbox = 0;
- NSBox *pbox = 0;
-
- NSRect sv_rect;
- sv_rect.origin.x = sv_rect.origin.y = 0;
- sv_rect.size.width = 320;
- sv_rect.size.height = 240;
- ScreenSaverView *sv = [[ScreenSaverView alloc] // dummy placeholder
- initWithFrame:sv_rect
- isPreview:YES];
-
- // make a "Preferences" button
- //
- if (! simple_p) {
- rect.origin.x = 0;
- rect.origin.y = 0;
- rect.size.width = rect.size.height = 10;
- pb = [[NSButton alloc] initWithFrame:rect];
- [pb setTitle:@"Preferences"];
- [pb setBezelStyle:NSRoundedBezelStyle];
- [pb sizeToFit];
-
- rect.origin.x = ([sv frame].size.width -
- [pb frame].size.width) / 2;
- [pb setFrameOrigin:rect.origin];
-
- // grab the click
- //
- [pb setTarget:self];
- [pb setAction:@selector(openPreferences:)];
-
- // Make a saver selection menu
- //
- menu = [self makeMenu];
- rect.origin.x = 2;
- rect.origin.y = 2;
- [menu setFrameOrigin:rect.origin];
-
- // make a box to wrap the saverView
- //
- rect = [sv frame];
- rect.origin.x = 0;
- rect.origin.y = [pb frame].origin.y + [pb frame].size.height;
- gbox = [[NSBox alloc] initWithFrame:rect];
- rect.size.width = rect.size.height = 10;
- [gbox setContentViewMargins:rect.size];
- [gbox setTitlePosition:NSNoTitle];
- [gbox addSubview:sv];
- [gbox sizeToFit];
-
- // make a box to wrap the other two boxes
- //
- rect.origin.x = rect.origin.y = 0;
- rect.size.width = [gbox frame].size.width;
- rect.size.height = [gbox frame].size.height + [gbox frame].origin.y;
- pbox = [[NSBox alloc] initWithFrame:rect];
- [pbox setTitlePosition:NSNoTitle];
- [pbox setBorderType:NSNoBorder];
- [pbox addSubview:gbox];
- [gbox release];
- if (menu) [pbox addSubview:menu];
- if (pb) [pbox addSubview:pb];
- [pb release];
- [pbox sizeToFit];
-
- [pb setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
- [menu setAutoresizingMask:NSViewMinXMargin|NSViewMaxXMargin];
- [gbox setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
- [pbox setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
- }
-
- [sv setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
-
-
- // and make a window to hold that.
- //
- NSScreen *screen = [NSScreen mainScreen];
- rect = pbox ? [pbox frame] : [sv frame];
- rect.origin.x = ([screen frame].size.width - rect.size.width) / 2;
- rect.origin.y = ([screen frame].size.height - rect.size.height) / 2;
-
- rect.origin.x += rect.size.width * (count ? 0.55 : -0.55);
-
- NSWindow *win = [[NSWindow alloc]
- initWithContentRect:rect
- styleMask:(NSTitledWindowMask |
- NSClosableWindowMask |
- NSMiniaturizableWindowMask |
- NSResizableWindowMask)
- backing:NSBackingStoreBuffered
- defer:YES
- screen:screen];
-// [win setMinSize:[win frameRectForContentRect:rect].size];
- [[win contentView] addSubview: (pbox ? (NSView *) pbox : (NSView *) sv)];
- [pbox release];
-
- [win makeKeyAndOrderFront:win];
-
- [sv startAnimation]; // this is the dummy saver
- [sv autorelease];
-
- count++;
-
- return win;
-}
-
-
-- (void) animTimer
-{
- for (NSWindow *win in windows) {
- ScreenSaverView *sv = find_saverView ([win contentView]);
- if ([sv isAnimating])
- [sv animateOneFrame];
- }
-}
-
-# endif // !USE_IPHONE
-
-
-- (void)applicationDidFinishLaunching:
-# ifndef USE_IPHONE
- (NSNotification *) notif
-# else // USE_IPHONE
- (UIApplication *) application
-# endif // USE_IPHONE
-{
- [self listSaverBundleNames];
-
- NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
-
-# ifndef USE_IPHONE
- int window_count = ([saverNames count] <= 1 ? 1 : 2);
- NSMutableArray *a = [[NSMutableArray arrayWithCapacity: window_count+1]
- retain];
- windows = a;
-
- int i;
- // Create either one window (for standalone, e.g. Phosphor.app)
- // or two windows for SaverTester.app.
- for (i = 0; i < window_count; i++) {
- NSWindow *win = [self makeWindow];
- [win setDelegate:self];
- // Get the last-saved window position out of preferences.
- [win setFrameAutosaveName:
- [NSString stringWithFormat:@"XScreenSaverWindow%d", i]];
- [win setFrameUsingName:[win frameAutosaveName]];
- [a addObject: win];
- // This prevents clicks from being seen by savers.
- // [win setMovableByWindowBackground:YES];
- win.releasedWhenClosed = NO;
- [win release];
- }
-# else // USE_IPHONE
-
-# undef ya_rand_init
- ya_rand_init (0); // Now's a good time.
-
-
- /* iOS docs say:
- "You must call this method before attempting to get orientation data from
- the receiver. This method enables the device's accelerometer hardware
- and begins the delivery of acceleration events to the receiver."
-
- Adding or removing this doesn't seem to make any difference. It's
- probably getting called by the UINavigationController. Still... */
- [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
-
- rotating_nav = [[[RotateyViewController alloc] initWithRotation:YES]
- retain];
-
- if ([prefs boolForKey:@"wasRunning"]) // Prevents menu flicker on startup.
- rotating_nav.view.hidden = YES;
-
- [window setRootViewController: rotating_nav];
- [window setAutoresizesSubviews:YES];
- [window setAutoresizingMask:
- (UIViewAutoresizingFlexibleWidth |
- UIViewAutoresizingFlexibleHeight)];
-
- SaverListController *menu = [[SaverListController alloc]
- initWithNames:saverNames
- descriptions:[self makeDescTable]];
- [rotating_nav pushViewController:menu animated:YES];
- [menu becomeFirstResponder];
- [menu autorelease];
-
- application.applicationSupportsShakeToEdit = YES;
-
-
-# endif // USE_IPHONE
-
- NSString *forced = 0;
- /* In the XCode project, each .saver scheme sets this env var when
- launching SaverTester.app so that it knows which one we are
- currently debugging. If this is set, it overrides the default
- selection in the popup menu. If unset, that menu persists to
- whatever it was last time.
- */
- const char *f = getenv ("SELECTED_SAVER");
- if (f && *f)
- forced = [NSString stringWithCString:(char *)f
- encoding:NSUTF8StringEncoding];
-
- if (forced && ![saverNames containsObject:forced]) {
- NSLog(@"forced saver \"%@\" does not exist", forced);
- forced = 0;
- }
-
- // If there's only one saver, run that.
- if (!forced && [saverNames count] == 1)
- forced = [saverNames objectAtIndex:0];
-
-# ifdef USE_IPHONE
- NSString *prev = [prefs stringForKey:@"selectedSaverName"];
-
- if (forced)
- prev = forced;
-
- // If nothing was selected (e.g., this is the first launch)
- // then scroll randomly instead of starting up at "A".
- //
- if (!prev)
- prev = [saverNames objectAtIndex: (random() % [saverNames count])];
-
- if (prev)
- [menu scrollTo: prev];
-# endif // USE_IPHONE
-
- if (forced)
- [prefs setObject:forced forKey:@"selectedSaverName"];
-
-# ifdef USE_IPHONE
- /* Don't auto-launch the saver unless it was running last time.
- XScreenSaverView manages this, on crash_timer.
- Unless forced.
- */
- if (!forced && ![prefs boolForKey:@"wasRunning"])
- return;
-# endif
-
- [self selectedSaverDidChange:nil];
-// [NSTimer scheduledTimerWithTimeInterval: 0
-// target:self
-// selector:@selector(selectedSaverDidChange:)
-// userInfo:nil
-// repeats:NO];
-
-
-
-# ifndef USE_IPHONE
- /* On 10.8 and earlier, [ScreenSaverView startAnimation] causes the
- ScreenSaverView to run its own timer calling animateOneFrame.
- On 10.9, that fails because the private class ScreenSaverModule
- is only initialized properly by ScreenSaverEngine, and in the
- context of SaverRunner, the null ScreenSaverEngine instance
- behaves as if [ScreenSaverEngine needsAnimationTimer] returned false.
- So, if it looks like this is the 10.9 version of ScreenSaverModule
- instead of the 10.8 version, we run our own timer here. This sucks.
- */
- if (!anim_timer) {
- Class ssm = NSClassFromString (@"ScreenSaverModule");
- if (ssm && [ssm instancesRespondToSelector:
- NSSelectorFromString(@"needsAnimationTimer")]) {
- NSWindow *win = [windows objectAtIndex:0];
- ScreenSaverView *sv = find_saverView ([win contentView]);
- anim_timer = [NSTimer scheduledTimerWithTimeInterval:
- [sv animationTimeInterval]
- target:self
- selector:@selector(animTimer)
- userInfo:nil
- repeats:YES];
- }
- }
-# endif // !USE_IPHONE
-}
-
-
-#ifndef USE_IPHONE
-
-/* When the window closes, exit (even if prefs still open.)
- */
-- (BOOL) applicationShouldTerminateAfterLastWindowClosed: (NSApplication *) n
-{
- return YES;
-}
-
-/* When the window is about to close, stop its animation.
- Without this, timers might fire after the window is dead.
- */
-- (void)windowWillClose:(NSNotification *)notification
-{
- NSWindow *win = [notification object];
- NSView *cv = win ? [win contentView] : 0;
- ScreenSaverView *sv = cv ? find_saverView (cv) : 0;
- if (sv && [sv isAnimating])
- [sv stopAnimation];
-}
-
-# else // USE_IPHONE
-
-- (void)applicationWillResignActive:(UIApplication *)app
-{
- [(XScreenSaverView *)view setScreenLocked:YES];
-}
-
-- (void)applicationDidBecomeActive:(UIApplication *)app
-{
- [(XScreenSaverView *)view setScreenLocked:NO];
-}
-
-- (void)applicationDidEnterBackground:(UIApplication *)application
-{
- [(XScreenSaverView *)view setScreenLocked:YES];
-}
-
-#endif // USE_IPHONE
-
-
-@end