+
+# else // USE_IPHONE
+
+# if 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 (saverView) {
+ if ([saverView isAnimating])
+ [saverView stopAnimation];
+ [saverView removeFromSuperview];
+ [backgroundView removeFromSuperview];
+ [[NSNotificationCenter defaultCenter] removeObserver:saverView];
+ [saverView release];
+ }
+
+ UIScreen *screen = [UIScreen mainScreen];
+ NSSize size;
+ double scale;
+
+# ifndef __IPHONE_8_0 // iOS 7 SDK or earlier
+
+ size = [screen bounds].size; // points, not pixels
+ scale = [screen scale]; // available in iOS 4
+
+# else // iOS 8 SDK or later
+
+ if ([screen respondsToSelector:@selector(nativeBounds)]) {
+ size = [screen nativeBounds].size; // available in iOS 8
+ scale = 1; // nativeBounds is in pixels.
+
+ /* '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.
+ */
+
+ } else {
+ size = [screen bounds].size; // points, not pixels
+ scale = [screen scale]; // available in iOS 4
+ }
+# endif // iOS 8
+
+ size.width = ceilf (size.width / scale);
+ size.height = ceilf (size.height / scale);
+
+
+# if TARGET_IPHONE_SIMULATOR
+ 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
+
+
+ /* Our view must be full screen, and view sizes are measured in points,
+ not pixels. However, since our view is on a UINavigationController
+ that does not rotate, the size must be portrait-mode even if the
+ device is landscape.
+
+ On iOS 7, [screen bounds] always returned portrait-mode values.
+ On iOS 8, it rotates. So swap as necessary.
+ On iOS 8, [screen nativeBounds] is unrotated, in pixels not points.
+ */
+ size = [screen bounds].size;
+ if (size.width > size.height) {
+ double s = size.width;
+ size.width = size.height;
+ size.height = s;
+ }
+
+ NSLog(@"saverView: %.0fx%.0f", size.width, size.height);
+# endif // TARGET_IPHONE_SIMULATOR
+
+
+ saverView = [self makeSaverView:name withSize:size];
+
+ if (! saverView) {
+ [[[UIAlertView alloc] initWithTitle: name
+ message: @"Unable to load!"
+ delegate: nil
+ cancelButtonTitle: @"Bummer"
+ otherButtonTitles: nil]
+ show];
+ return;
+ }
+
+ [[NSNotificationCenter defaultCenter]
+ addObserver:saverView
+ selector:@selector(didRotate:)
+ name:UIDeviceOrientationDidChangeNotification object:nil];
+
+ /* LAUNCH: */
+
+ if (launch) {
+ [self saveScreenshot];
+ NSRect f;
+ f.origin.x = 0;
+ f.origin.y = 0;
+ f.size = [[UIScreen mainScreen] bounds].size;
+ if (f.size.width > f.size.height) { // Force portrait
+ double swap = f.size.width;
+ f.size.width = f.size.height;
+ f.size.height = swap;
+ }
+ [backgroundView setFrame:f];
+ [saverView setFrame:f];
+ [saverWindow addSubview: backgroundView];
+ [backgroundView addSubview: saverView];
+ [saverWindow setFrame:f];
+ [saverView setBackgroundColor:[NSColor blackColor]];
+
+ [saverWindow setHidden:NO];
+ [saverWindow makeKeyAndVisible];
+ [saverView startAnimation];
+ [self aboutPanel:nil];
+
+ // Tell the UILayoutContainerView to stop intercepting our events.
+ // [[saverWindow rootViewController] view].userInteractionEnabled = NO;
+ // saverView.userInteractionEnabled = YES;
+
+ // Tell the saverWindow that all events should go to saverView.
+ //
+ NSAssert ([saverWindow isKindOfClass:[EventCapturingWindow class]],
+ @"saverWindow is not an EventCapturingWindow");
+ ((EventCapturingWindow *) saverWindow).eventView = saverView;
+
+ // 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
+}
+
+
+- (void)loadSaver:(NSString *)name
+{
+ [self loadSaver:name launch:YES];