Some more iOS orientation rotation fixes.
authorRyan C. Gordon <icculus@icculus.org>
Mon, 04 Apr 2011 23:38:15 -0400
changeset 55298c0d15077360
parent 5528 15c9c03a80cc
child 5530 4e46a7b6773d
Some more iOS orientation rotation fixes.

- Always use a UIViewController, even if window is not resizable.
- Let non-resizable windows still flip over, so user can hold device with the
correct orientation, but upside down, if that's more comfortable.
- Don't set the UIScreen unless we're forced to, as it resets some state.
- Minor correction with conventions for -[self init] tapdance.
src/video/uikit/SDL_uikitwindow.m
     1.1 --- a/src/video/uikit/SDL_uikitwindow.m	Mon Apr 04 09:29:13 2011 -0700
     1.2 +++ b/src/video/uikit/SDL_uikitwindow.m	Mon Apr 04 23:38:15 2011 -0400
     1.3 @@ -41,13 +41,35 @@
     1.4  @implementation SDL_uikitviewcontroller
     1.5  
     1.6  - (id)initWithSDLWindow:(SDL_Window *)_window {
     1.7 -    [self init];
     1.8 +    if ((self = [self init]) == nil) {
     1.9 +        return nil;
    1.10 +    }
    1.11      self->window = _window;
    1.12      return self;
    1.13  }
    1.14  
    1.15  - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orient {
    1.16 -    return YES;
    1.17 +    if (self->window->flags & SDL_WINDOW_RESIZABLE) {
    1.18 +        return YES;  // any orientation is okay.
    1.19 +    }
    1.20 +
    1.21 +    // If not resizable, allow device to orient to other matching sizes
    1.22 +    //  (that is, let the user turn the device upside down...same screen
    1.23 +    //   dimensions, but it lets the user place the device where it's most
    1.24 +    //   comfortable in relation to its physical buttons, headphone jack, etc).
    1.25 +    switch (orient) {
    1.26 +        case UIInterfaceOrientationLandscapeLeft:
    1.27 +        case UIInterfaceOrientationLandscapeRight:
    1.28 +            return (self->window->w >= self->window->h);
    1.29 +
    1.30 +        case UIInterfaceOrientationPortrait:
    1.31 +        case UIInterfaceOrientationPortraitUpsideDown:
    1.32 +            return (self->window->h >= self->window->w);
    1.33 +
    1.34 +        default: break;
    1.35 +    }
    1.36 +
    1.37 +    return NO;  // Nothing else is acceptable.
    1.38  }
    1.39  
    1.40  - (void)loadView  {
    1.41 @@ -56,10 +78,16 @@
    1.42  
    1.43  // Send a resized event when the orientation changes.
    1.44  - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
    1.45 +    if ((self->window->flags & SDL_WINDOW_RESIZABLE) == 0) {
    1.46 +        return;   // don't care, we're just flipping over in this case.
    1.47 +    }
    1.48 +
    1.49      const UIInterfaceOrientation toInterfaceOrientation = [self interfaceOrientation];
    1.50      SDL_WindowData *data = self->window->driverdata;
    1.51      UIWindow *uiwindow = data->uiwindow;
    1.52 -    CGRect frame = [uiwindow frame];
    1.53 +    UIScreen *uiscreen = [uiwindow screen];
    1.54 +    const int noborder = self->window->flags & SDL_WINDOW_BORDERLESS;
    1.55 +    CGRect frame = noborder ? [uiscreen bounds] : [uiscreen applicationFrame];
    1.56      const CGSize size = frame.size;
    1.57      int w, h;
    1.58  
    1.59 @@ -83,6 +111,9 @@
    1.60  
    1.61      frame.size.width = w;
    1.62      frame.size.height = h;
    1.63 +    frame.origin.x = 0;
    1.64 +    frame.origin.y = 0;
    1.65 +
    1.66      [uiwindow setFrame:frame];
    1.67      [data->view updateFrame];
    1.68      SDL_SendWindowEvent(self->window, SDL_WINDOWEVENT_RESIZED, w, h);
    1.69 @@ -139,31 +170,20 @@
    1.70              [UIApplication sharedApplication].statusBarHidden = NO;
    1.71          }
    1.72  
    1.73 -        const CGSize uisize = [[uiscreen currentMode] size];
    1.74          const UIDeviceOrientation o = [[UIDevice currentDevice] orientation];
    1.75          const BOOL landscape = (o == UIDeviceOrientationLandscapeLeft) ||
    1.76                                     (o == UIDeviceOrientationLandscapeRight);
    1.77          const BOOL rotate = ( ((window->w > window->h) && (!landscape)) ||
    1.78                                ((window->w < window->h) && (landscape)) );
    1.79  
    1.80 -        if (window->flags & SDL_WINDOW_RESIZABLE) {
    1.81 -            // The View Controller will handle rotating the view when the
    1.82 -            //  device orientation changes. We expose these as resize events.
    1.83 -            SDL_uikitviewcontroller *controller;
    1.84 -            controller = [SDL_uikitviewcontroller alloc];
    1.85 -            data->viewcontroller = [controller initWithSDLWindow:window];
    1.86 -            [data->viewcontroller setTitle:@"SDL App"];  // !!! FIXME: hook up SDL_SetWindowTitle()
    1.87 -            // !!! FIXME: if (rotate), force a "resize" right at the start
    1.88 -        } else {
    1.89 -            // Rotate the view if we have to, but only on the main screen
    1.90 -            //  (presumably, an external display doesn't report orientation).
    1.91 -            if (rotate) {
    1.92 -                #define D2R(x) (M_PI * (x) / 180.0)   // degrees to radians.
    1.93 -                [uiwindow setTransform:CGAffineTransformIdentity];
    1.94 -                [uiwindow setTransform:CGAffineTransformMakeRotation(D2R(90))];
    1.95 -                #undef D2R
    1.96 -            }
    1.97 -        }
    1.98 +        // The View Controller will handle rotating the view when the
    1.99 +        //  device orientation changes. This will trigger resize events, if
   1.100 +        //  appropriate.
   1.101 +        SDL_uikitviewcontroller *controller;
   1.102 +        controller = [SDL_uikitviewcontroller alloc];
   1.103 +        data->viewcontroller = [controller initWithSDLWindow:window];
   1.104 +        [data->viewcontroller setTitle:@"SDL App"];  // !!! FIXME: hook up SDL_SetWindowTitle()
   1.105 +        // !!! FIXME: if (rotate), force a "resize" right at the start
   1.106      }
   1.107  
   1.108      return 0;
   1.109 @@ -174,6 +194,7 @@
   1.110  {
   1.111      SDL_VideoDisplay *display = SDL_GetDisplayForWindow(window);
   1.112      UIScreen *uiscreen = (UIScreen *) display->driverdata;
   1.113 +    const BOOL external = ([UIScreen mainScreen] != uiscreen);
   1.114  
   1.115      // SDL currently puts this window at the start of display's linked list. We rely on this.
   1.116      SDL_assert(_this->windows == window);
   1.117 @@ -187,7 +208,7 @@
   1.118      // Non-mainscreen windows must be force to borderless, as there's no
   1.119      //  status bar there, and we want to get the right dimensions later in
   1.120      //  this function.
   1.121 -    if ([UIScreen mainScreen] != uiscreen) {
   1.122 +    if (external) {
   1.123          window->flags |= SDL_WINDOW_BORDERLESS;
   1.124      }
   1.125  
   1.126 @@ -225,8 +246,12 @@
   1.127          uiwindow = [uiwindow initWithFrame:[uiscreen bounds]];
   1.128      else
   1.129          uiwindow = [uiwindow initWithFrame:[uiscreen applicationFrame]];
   1.130 -
   1.131 -    if (SDL_UIKit_supports_multiple_displays) {
   1.132 +    
   1.133 +    // put the window on an external display if appropriate. This implicitly
   1.134 +    //  does [uiwindow setframe:[uiscreen bounds]], so don't do it on the
   1.135 +    //  main display, where we land by default, as that would eat the
   1.136 +    //  status bar real estate.
   1.137 +    if (external) {
   1.138          [uiwindow setScreen:uiscreen];
   1.139      }
   1.140