+- (void) flagsChanged: (NSEvent *) e
+{
+ if (! [self doEvent:e type:KeyPress])
+ [super flagsChanged:e];
+}
+
+#else // USE_IPHONE
+
+
+/* Called after the device's orientation has changed.
+
+ Note: we could include a subclass of UIViewController which
+ contains a shouldAutorotateToInterfaceOrientation method that
+ returns YES, in which case Core Animation would auto-rotate our
+ View for us in response to rotation events... but, that interacts
+ badly with the EAGLContext -- if you introduce Core Animation into
+ the path, the OpenGL pipeline probably falls back on software
+ rendering and performance goes to hell. Also, the scaling and
+ rotation that Core Animation does interacts incorrectly with the GL
+ context anyway.
+
+ So, we have to hack the rotation animation manually, in the GL world.
+
+ Possibly XScreenSaverView should use Core Animation, and
+ XScreenSaverGLView should override that.
+*/
+- (void)didRotate:(NSNotification *)notification
+{
+ UIDeviceOrientation current = [[UIDevice currentDevice] orientation];
+
+ /* If the simulator starts up in the rotated position, sometimes
+ the UIDevice says we're in Portrait when we're not -- but it
+ turns out that the UINavigationController knows what's up!
+ So get it from there.
+ */
+ if (current == UIDeviceOrientationUnknown) {
+ switch ([[[self window] rootViewController] interfaceOrientation]) {
+ case UIInterfaceOrientationPortrait:
+ current = UIDeviceOrientationPortrait;
+ break;
+ case UIInterfaceOrientationPortraitUpsideDown:
+ current = UIDeviceOrientationPortraitUpsideDown;
+ break;
+ case UIInterfaceOrientationLandscapeLeft: // It's opposite day
+ current = UIDeviceOrientationLandscapeRight;
+ break;
+ case UIInterfaceOrientationLandscapeRight:
+ current = UIDeviceOrientationLandscapeLeft;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* On the iPad (but not iPhone 3GS, or the simulator) sometimes we get
+ an orientation change event with an unknown orientation. Those seem
+ to always be immediately followed by another orientation change with
+ a *real* orientation change, so let's try just ignoring those bogus
+ ones and hoping that the real one comes in shortly...
+ */
+ if (current == UIDeviceOrientationUnknown)
+ return;
+
+ if (rotation_ratio >= 0) return; // in the midst of rotation animation
+ if (orientation == current) return; // no change
+
+ new_orientation = current; // current animation target
+ rotation_ratio = 0; // start animating
+ rot_start_time = double_time();
+
+ switch (orientation) {
+ case UIInterfaceOrientationLandscapeRight: angle_from = 90; break;
+ case UIInterfaceOrientationLandscapeLeft: angle_from = 270; break;
+ case UIInterfaceOrientationPortraitUpsideDown: angle_from = 180; break;
+ default: angle_from = 0; break;
+ }
+
+ switch (new_orientation) {
+ case UIInterfaceOrientationLandscapeRight: angle_to = 90; break;
+ case UIInterfaceOrientationLandscapeLeft: angle_to = 270; break;
+ case UIInterfaceOrientationPortraitUpsideDown: angle_to = 180; break;
+ default: angle_to = 0; break;
+ }
+
+ NSRect ff = [self frame];
+
+ switch (orientation) {
+ case UIInterfaceOrientationLandscapeLeft: // from landscape
+ case UIInterfaceOrientationLandscapeRight:
+ rot_from.width = ff.size.height;
+ rot_from.height = ff.size.width;
+ break;
+ default: // from portrait
+ rot_from.width = ff.size.width;
+ rot_from.height = ff.size.height;
+ break;
+ }
+
+ switch (new_orientation) {
+ case UIInterfaceOrientationLandscapeLeft: // to landscape
+ case UIInterfaceOrientationLandscapeRight:
+ rot_to.width = ff.size.height;
+ rot_to.height = ff.size.width;
+ break;
+ default: // to portrait
+ rot_to.width = ff.size.width;
+ rot_to.height = ff.size.height;
+ break;
+ }
+
+ if (! initted_p) {
+ // If we've done a rotation but the saver hasn't been initialized yet,
+ // don't bother going through an X11 resize, but just do it now.
+ rot_start_time = 0; // dawn of time
+ [self hackRotation];
+ }
+}
+
+
+/* In the simulator, multi-touch sequences look like this:
+
+ touchesBegan [touchA, touchB]
+ touchesEnd [touchA, touchB]
+
+ But on real devices, sometimes you get that, but sometimes you get:
+
+ touchesBegan [touchA, touchB]
+ touchesEnd [touchB]
+ touchesEnd [touchA]
+
+ Or even
+
+ touchesBegan [touchA]
+ touchesBegan [touchB]
+ touchesEnd [touchA]
+ touchesEnd [touchB]
+
+ So the only way to properly detect a "pinch" gesture is to remember
+ the start-point of each touch as it comes in; and the end-point of
+ each touch as those come in; and only process the gesture once the
+ number of touchEnds matches the number of touchBegins.
+ */
+
+static void
+rotate_mouse (int *x, int *y, int w, int h, int rot)
+{
+ int ox = *x, oy = *y;
+ if (rot > 45 && rot < 135) { *x = oy; *y = w-ox; }
+ else if (rot < -45 && rot > -135) { *x = h-oy; *y = ox; }
+ else if (rot > 135 || rot < -135) { *x = w-ox; *y = h-oy; }
+}
+
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ if (xsft->event_cb && xwindow) {
+ double s = self.contentScaleFactor;
+ XEvent xe;
+ memset (&xe, 0, sizeof(xe));
+ int i = 0;
+ int w = s * [self frame].size.width;
+ int h = s * [self frame].size.height;
+ for (UITouch *touch in touches) {
+ CGPoint p = [touch locationInView:self];
+ xe.xany.type = ButtonPress;
+ xe.xbutton.button = i + 1;
+ xe.xbutton.button = i + 1;
+ xe.xbutton.x = s * p.x;
+ xe.xbutton.y = s * p.y;
+ rotate_mouse (&xe.xbutton.x, &xe.xbutton.y, w, h, rot_current_angle);
+ jwxyz_mouse_moved (xdpy, xwindow, xe.xbutton.x, xe.xbutton.y);
+ xsft->event_cb (xdpy, xwindow, xdata, &xe);
+ i++;
+ }
+ }
+}
+
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
+{
+
+ // Double-tap means "exit" and return to selection menu.
+ //
+ for (UITouch *touch in touches) {
+ if ([touch tapCount] >= 2) {
+ if ([self isAnimating])
+ [self stopAnimation];
+ [self removeFromSuperview];
+ return;
+ }
+ }
+
+ if (xsft->event_cb && xwindow) {
+ double s = self.contentScaleFactor;
+ XEvent xe;
+ memset (&xe, 0, sizeof(xe));
+ int i = 0;
+ int w = s * [self frame].size.width;
+ int h = s * [self frame].size.height;
+ for (UITouch *touch in touches) {
+ CGPoint p = [touch locationInView:self];
+ xe.xany.type = ButtonRelease;
+ xe.xbutton.button = i + 1;
+ xe.xbutton.x = s * p.x;
+ xe.xbutton.y = s * p.y;
+ rotate_mouse (&xe.xbutton.x, &xe.xbutton.y, w, h, rot_current_angle);
+ jwxyz_mouse_moved (xdpy, xwindow, xe.xbutton.x, xe.xbutton.y);
+ xsft->event_cb (xdpy, xwindow, xdata, &xe);
+ i++;
+ }
+ }
+}
+
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ if (xsft->event_cb && xwindow) {
+ double s = self.contentScaleFactor;
+ XEvent xe;
+ memset (&xe, 0, sizeof(xe));
+ int i = 0;
+ int w = s * [self frame].size.width;
+ int h = s * [self frame].size.height;
+ for (UITouch *touch in touches) {
+ CGPoint p = [touch locationInView:self];
+ xe.xany.type = MotionNotify;
+ xe.xmotion.x = s * p.x;
+ xe.xmotion.y = s * p.y;
+ rotate_mouse (&xe.xbutton.x, &xe.xbutton.y, w, h, rot_current_angle);
+ jwxyz_mouse_moved (xdpy, xwindow, xe.xmotion.x, xe.xmotion.y);
+ xsft->event_cb (xdpy, xwindow, xdata, &xe);
+ i++;
+ }
+ }
+}
+
+
+/* We need this to respond to "shake" gestures
+ */
+- (BOOL)canBecomeFirstResponder {
+ return YES;
+}
+
+
+- (void)setScreenLocked:(BOOL)locked
+{
+ if (screenLocked == locked) return;
+ screenLocked = locked;
+ if (locked) {
+ if ([self isAnimating])
+ [self stopAnimation];
+ } else {
+ if (! [self isAnimating])
+ [self startAnimation];
+ }
+}
+
+
+#endif // USE_IPHONE
+