Much improved multi-display support for iPad.
authorRyan C. Gordon
Sun, 02 May 2010 05:08:12 -0400
changeset 44468b03a20b320f
parent 4445 06becafcac89
child 4447 947201caa46e
Much improved multi-display support for iPad.

Fixes most issues and limitations, I think.
src/video/uikit/SDL_uikitappdelegate.h
src/video/uikit/SDL_uikitappdelegate.m
src/video/uikit/SDL_uikitopengles.m
src/video/uikit/SDL_uikitvideo.h
src/video/uikit/SDL_uikitvideo.m
src/video/uikit/SDL_uikitwindow.h
src/video/uikit/SDL_uikitwindow.m
     1.1 --- a/src/video/uikit/SDL_uikitappdelegate.h	Sat May 01 13:50:56 2010 -0400
     1.2 +++ b/src/video/uikit/SDL_uikitappdelegate.h	Sun May 02 05:08:12 2010 -0400
     1.3 @@ -25,13 +25,8 @@
     1.4  
     1.5  /* *INDENT-OFF* */
     1.6  @interface SDLUIKitDelegate:NSObject<UIApplicationDelegate> {
     1.7 -    SDL_Window *window;
     1.8 -    UIWindow *uiwindow;
     1.9  }
    1.10  
    1.11 -@property (readwrite, assign) SDL_Window *window;
    1.12 -@property (readwrite, retain) UIWindow *uiwindow;
    1.13 -
    1.14  +(SDLUIKitDelegate *)sharedAppDelegate;
    1.15  
    1.16  @end
     2.1 --- a/src/video/uikit/SDL_uikitappdelegate.m	Sat May 01 13:50:56 2010 -0400
     2.2 +++ b/src/video/uikit/SDL_uikitappdelegate.m	Sun May 02 05:08:12 2010 -0400
     2.3 @@ -20,6 +20,8 @@
     2.4   slouken@libsdl.org
     2.5  */
     2.6  
     2.7 +#import "../SDL_sysvideo.h"
     2.8 +
     2.9  #import "SDL_uikitappdelegate.h"
    2.10  #import "SDL_uikitopenglview.h"
    2.11  #import "SDL_events_c.h"
    2.12 @@ -55,9 +57,6 @@
    2.13  
    2.14  @implementation SDLUIKitDelegate
    2.15  
    2.16 -@synthesize window;
    2.17 -@synthesize uiwindow;
    2.18 -
    2.19  /* convenience method */
    2.20  +(SDLUIKitDelegate *)sharedAppDelegate {
    2.21  	/* the delegate is set in UIApplicationMain(), which is garaunteed to be called before this method */
    2.22 @@ -66,8 +65,6 @@
    2.23  
    2.24  - (id)init {
    2.25  	self = [super init];
    2.26 -	window = NULL;
    2.27 -	uiwindow = nil;
    2.28  	return self;
    2.29  }
    2.30  
    2.31 @@ -106,21 +103,42 @@
    2.32  
    2.33  - (void) applicationWillResignActive:(UIApplication*)application
    2.34  {
    2.35 -//	NSLog(@"%@", NSStringFromSelector(_cmd));
    2.36 -	SDL_SendWindowEvent(self.window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
    2.37 +    //NSLog(@"%@", NSStringFromSelector(_cmd));
    2.38 +
    2.39 +    // Send every window on every screen a MINIMIZED event.
    2.40 +    SDL_VideoDevice *_this = SDL_GetVideoDevice();
    2.41 +    if (!_this) {
    2.42 +        return;
    2.43 +    }
    2.44 +
    2.45 +    int i;
    2.46 +    for (i = 0; i < _this->num_displays; i++) {
    2.47 +        const SDL_VideoDisplay *display = &_this->displays[i];
    2.48 +        SDL_Window *window;
    2.49 +        for (window = display->windows; window != nil; window = window->next) {
    2.50 +            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
    2.51 +        }
    2.52 +    }
    2.53  }
    2.54  
    2.55  - (void) applicationDidBecomeActive:(UIApplication*)application
    2.56  {
    2.57 -//	NSLog(@"%@", NSStringFromSelector(_cmd));
    2.58 -	SDL_SendWindowEvent(self.window, SDL_WINDOWEVENT_RESTORED, 0, 0);
    2.59 -}
    2.60 +    //NSLog(@"%@", NSStringFromSelector(_cmd));
    2.61  
    2.62 +    // Send every window on every screen a RESTORED event.
    2.63 +    SDL_VideoDevice *_this = SDL_GetVideoDevice();
    2.64 +    if (!_this) {
    2.65 +        return;
    2.66 +    }
    2.67  
    2.68 -
    2.69 --(void)dealloc {
    2.70 -	[uiwindow release];
    2.71 -	[super dealloc];
    2.72 +    int i;
    2.73 +    for (i = 0; i < _this->num_displays; i++) {
    2.74 +        const SDL_VideoDisplay *display = &_this->displays[i];
    2.75 +        SDL_Window *window;
    2.76 +        for (window = display->windows; window != nil; window = window->next) {
    2.77 +            SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
    2.78 +        }
    2.79 +    }
    2.80  }
    2.81  
    2.82  @end
     3.1 --- a/src/video/uikit/SDL_uikitopengles.m	Sat May 01 13:50:56 2010 -0400
     3.2 +++ b/src/video/uikit/SDL_uikitopengles.m	Sun May 02 05:08:12 2010 -0400
     3.3 @@ -99,13 +99,13 @@
     3.4  
     3.5  SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window)
     3.6  {
     3.7 -	
     3.8  	SDL_uikitopenglview *view;
     3.9 +	SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
    3.10 +    UIScreen *uiscreen = (UIScreen *) window->display->driverdata;
    3.11 +	UIWindow *uiwindow = data->uiwindow;
    3.12  
    3.13 -	SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
    3.14 -	
    3.15 -	/* construct our view, passing in SDL's OpenGL configuration data */
    3.16 -	view = [[SDL_uikitopenglview alloc] initWithFrame: [[UIScreen mainScreen] applicationFrame] \
    3.17 +    /* construct our view, passing in SDL's OpenGL configuration data */
    3.18 +    view = [[SDL_uikitopenglview alloc] initWithFrame: [uiwindow bounds] \
    3.19  									retainBacking: _this->gl_config.retained_backing \
    3.20  									rBits: _this->gl_config.red_size \
    3.21  									gBits: _this->gl_config.green_size \
    3.22 @@ -116,7 +116,7 @@
    3.23  	data->view = view;
    3.24  	
    3.25  	/* add the view to our window */
    3.26 -	[data->uiwindow addSubview: view ];
    3.27 +	[uiwindow addSubview: view ];
    3.28  	
    3.29  	/* Don't worry, the window retained the view */
    3.30  	[view release];
     4.1 --- a/src/video/uikit/SDL_uikitvideo.h	Sat May 01 13:50:56 2010 -0400
     4.2 +++ b/src/video/uikit/SDL_uikitvideo.h	Sun May 02 05:08:12 2010 -0400
     4.3 @@ -26,6 +26,10 @@
     4.4  
     4.5  #include "../SDL_sysvideo.h"
     4.6  
     4.7 +#include <UIKit/UIKit.h>
     4.8 +
     4.9 +extern BOOL SDL_UIKit_supports_multiple_displays;
    4.10 +
    4.11  #endif /* _SDL_uikitvideo_h */
    4.12  
    4.13  /* vi: set ts=4 sw=4 expandtab: */
     5.1 --- a/src/video/uikit/SDL_uikitvideo.m	Sat May 01 13:50:56 2010 -0400
     5.2 +++ b/src/video/uikit/SDL_uikitvideo.m	Sun May 02 05:08:12 2010 -0400
     5.3 @@ -49,7 +49,7 @@
     5.4                                  SDL_DisplayMode * mode);
     5.5  static void UIKit_VideoQuit(_THIS);
     5.6  
     5.7 -static BOOL supports_multiple_displays = NO;
     5.8 +BOOL SDL_UIKit_supports_multiple_displays = NO;
     5.9  
    5.10  /* DUMMY driver bootstrap functions */
    5.11  
    5.12 @@ -124,14 +124,14 @@
    5.13  static void
    5.14  UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
    5.15  {
    5.16 -    const UIScreen *screen = (UIScreen *) display->driverdata;
    5.17 +    UIScreen *uiscreen = (UIScreen *) display->driverdata;
    5.18      SDL_DisplayMode mode;
    5.19      SDL_zero(mode);
    5.20  
    5.21      // availableModes showed up in 3.2 (the iPad and later). We should only
    5.22      //  land here for at least that version of the OS.
    5.23 -    if (!supports_multiple_displays) {
    5.24 -        const CGRect rect = [screen bounds];
    5.25 +    if (!SDL_UIKit_supports_multiple_displays) {
    5.26 +        const CGRect rect = [uiscreen bounds];
    5.27          mode.format = SDL_PIXELFORMAT_ABGR8888;
    5.28          mode.w = (int) rect.size.width;
    5.29          mode.h = (int) rect.size.height;
    5.30 @@ -141,7 +141,7 @@
    5.31          return;
    5.32      }
    5.33  
    5.34 -    const NSArray *modes = [screen availableModes];
    5.35 +    const NSArray *modes = [uiscreen availableModes];
    5.36      const NSUInteger mode_count = [modes count];
    5.37      NSUInteger i;
    5.38      for (i = 0; i < mode_count; i++) {
    5.39 @@ -159,11 +159,10 @@
    5.40  
    5.41  
    5.42  static void
    5.43 -UIKit_AddDisplay(UIScreen *screen, int w, int h)
    5.44 +UIKit_AddDisplay(UIScreen *uiscreen, int w, int h)
    5.45  {
    5.46      SDL_VideoDisplay display;
    5.47      SDL_DisplayMode mode;
    5.48 -
    5.49      SDL_zero(mode);
    5.50      mode.format = SDL_PIXELFORMAT_ABGR8888;
    5.51      mode.w = w;
    5.52 @@ -173,8 +172,9 @@
    5.53      SDL_zero(display);
    5.54      display.desktop_mode = mode;
    5.55      display.current_mode = mode;
    5.56 -    display.driverdata = screen;
    5.57 -    [screen retain];
    5.58 +
    5.59 +    [uiscreen retain];
    5.60 +    display.driverdata = uiscreen;
    5.61      SDL_AddVideoDisplay(&display);
    5.62  }
    5.63  
    5.64 @@ -187,25 +187,25 @@
    5.65      NSString *reqSysVer = @"3.2";
    5.66      NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
    5.67      if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
    5.68 -        supports_multiple_displays = YES;
    5.69 +        SDL_UIKit_supports_multiple_displays = YES;
    5.70  
    5.71      // If this is iPhoneOS < 3.2, all devices are one screen, 320x480 pixels.
    5.72      //  The iPad added both a larger main screen and the ability to use
    5.73      //  external displays.
    5.74 -    if (!supports_multiple_displays) {
    5.75 +    if (!SDL_UIKit_supports_multiple_displays) {
    5.76          // Just give 'em the whole main screen.
    5.77 -        UIScreen *screen = [UIScreen mainScreen];
    5.78 -        const CGRect rect = [screen bounds];
    5.79 -        UIKit_AddDisplay(screen, (int)rect.size.width, (int)rect.size.height);
    5.80 +        UIScreen *uiscreen = [UIScreen mainScreen];
    5.81 +        const CGRect rect = [uiscreen bounds];
    5.82 +        UIKit_AddDisplay(uiscreen, (int)rect.size.width, (int)rect.size.height);
    5.83      } else {
    5.84          const NSArray *screens = [UIScreen screens];
    5.85          const NSUInteger screen_count = [screens count];
    5.86          NSUInteger i;
    5.87          for (i = 0; i < screen_count; i++) {
    5.88              // the main screen is the first element in the array.
    5.89 -            UIScreen *screen = (UIScreen *) [screens objectAtIndex:i];
    5.90 -            const CGSize size = [[screen currentMode] size];
    5.91 -            UIKit_AddDisplay(screen, (int) size.width, (int) size.height);
    5.92 +            UIScreen *uiscreen = (UIScreen *) [screens objectAtIndex:i];
    5.93 +            const CGSize size = [[uiscreen currentMode] size];
    5.94 +            UIKit_AddDisplay(uiscreen, (int) size.width, (int) size.height);
    5.95          }
    5.96      }
    5.97  
    5.98 @@ -216,13 +216,13 @@
    5.99  static int
   5.100  UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
   5.101  {
   5.102 -    UIScreen *screen = (UIScreen *) display->driverdata;
   5.103 -    if (!supports_multiple_displays) {
   5.104 +    UIScreen *uiscreen = (UIScreen *) display->driverdata;
   5.105 +    if (!SDL_UIKit_supports_multiple_displays) {
   5.106          // Not on at least iPhoneOS 3.2 (versions prior to iPad).
   5.107          SDL_assert(mode->driverdata == NULL);
   5.108      } else {
   5.109          UIScreenMode *uimode = (UIScreenMode *) mode->driverdata;
   5.110 -        [screen setCurrentMode:uimode];
   5.111 +        [uiscreen setCurrentMode:uimode];
   5.112      }
   5.113  
   5.114      return 0;
   5.115 @@ -235,8 +235,8 @@
   5.116      int i, j;
   5.117      for (i = 0; i < _this->num_displays; i++) {
   5.118          SDL_VideoDisplay *display = &_this->displays[i];
   5.119 -        UIScreen *screen = (UIScreen *) display->driverdata;
   5.120 -        [((UIScreen *) display->driverdata) release];
   5.121 +        UIScreen *uiscreen = (UIScreen *) display->driverdata;
   5.122 +        [uiscreen release];
   5.123          display->driverdata = NULL;
   5.124          for (j = 0; j < display->num_display_modes; j++) {
   5.125              SDL_DisplayMode *mode = &display->display_modes[j];
     6.1 --- a/src/video/uikit/SDL_uikitwindow.h	Sat May 01 13:50:56 2010 -0400
     6.2 +++ b/src/video/uikit/SDL_uikitwindow.h	Sun May 02 05:08:12 2010 -0400
     6.3 @@ -36,7 +36,6 @@
     6.4  
     6.5  struct SDL_WindowData
     6.6  {
     6.7 -    SDL_Window *window;
     6.8      UIWindow *uiwindow;
     6.9      SDL_uikitopenglview *view;
    6.10  };
     7.1 --- a/src/video/uikit/SDL_uikitwindow.m	Sat May 01 13:50:56 2010 -0400
     7.2 +++ b/src/video/uikit/SDL_uikitwindow.m	Sun May 02 05:08:12 2010 -0400
     7.3 @@ -23,6 +23,7 @@
     7.4  
     7.5  #include "SDL_video.h"
     7.6  #include "SDL_mouse.h"
     7.7 +#include "SDL_assert.h"
     7.8  #include "../SDL_sysvideo.h"
     7.9  #include "../SDL_pixels_c.h"
    7.10  #include "../../events/SDL_events_c.h"
    7.11 @@ -38,8 +39,10 @@
    7.12  #include <UIKit/UIKit.h>
    7.13  #include <Foundation/Foundation.h>
    7.14  
    7.15 -static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created) {
    7.16 -
    7.17 +static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created)
    7.18 +{
    7.19 +    SDL_VideoDisplay *display = window->display;
    7.20 +    UIScreen *uiscreen = (UIScreen *) display->driverdata;
    7.21      SDL_WindowData *data;
    7.22          
    7.23      /* Allocate the window data */
    7.24 @@ -48,7 +51,6 @@
    7.25          SDL_OutOfMemory();
    7.26          return -1;
    7.27      }
    7.28 -    data->window = window;
    7.29      data->uiwindow = uiwindow;
    7.30      data->view = nil;
    7.31  
    7.32 @@ -68,12 +70,15 @@
    7.33      window->flags |= SDL_WINDOW_SHOWN;            /* only one window on iPod touch, always shown */
    7.34      window->flags |= SDL_WINDOW_INPUT_FOCUS;    /* always has input focus */    
    7.35  
    7.36 -    /* SDL_WINDOW_BORDERLESS controls whether status bar is hidden */
    7.37 -    if (window->flags & SDL_WINDOW_BORDERLESS) {
    7.38 -        [UIApplication sharedApplication].statusBarHidden = YES;
    7.39 -    }
    7.40 -    else {
    7.41 -        [UIApplication sharedApplication].statusBarHidden = NO;
    7.42 +    // SDL_WINDOW_BORDERLESS controls whether status bar is hidden.
    7.43 +    // This is only set if the window is on the main screen. Other screens
    7.44 +    //  just force the window to have the borderless flag.
    7.45 +    if ([UIScreen mainScreen] == uiscreen) {
    7.46 +        if (window->flags & SDL_WINDOW_BORDERLESS) {
    7.47 +            [UIApplication sharedApplication].statusBarHidden = YES;
    7.48 +        } else {
    7.49 +            [UIApplication sharedApplication].statusBarHidden = NO;
    7.50 +        }
    7.51      }
    7.52      
    7.53      return 0;
    7.54 @@ -82,41 +87,80 @@
    7.55  
    7.56  int UIKit_CreateWindow(_THIS, SDL_Window *window) {
    7.57          
    7.58 -    /* We currently only handle single window applications on iPhone */
    7.59 -    if (nil != [SDLUIKitDelegate sharedAppDelegate].window) {
    7.60 -        SDL_SetError("Window already exists, no multi-window support.");
    7.61 +    SDL_VideoDisplay *display = window->display;
    7.62 +    UIScreen *uiscreen = (UIScreen *) display->driverdata;
    7.63 +
    7.64 +    // SDL currently puts this window at the start of display's linked list. We rely on this.
    7.65 +    SDL_assert(display->windows == window);
    7.66 +
    7.67 +    /* We currently only handle a single window per display on iPhone */
    7.68 +    if (window->next != NULL) {
    7.69 +        SDL_SetError("Only one window allowed per display.");
    7.70          return -1;
    7.71      }
    7.72 -    
    7.73 +
    7.74 +    // Non-mainscreen windows must be force to borderless, as there's no
    7.75 +    //  status bar there, and we want to get the right dimensions later in
    7.76 +    //  this function.
    7.77 +    if ([UIScreen mainScreen] != uiscreen) {
    7.78 +        window->flags |= SDL_WINDOW_BORDERLESS;
    7.79 +    }
    7.80 +
    7.81 +    // If monitor has a resolution of 0x0 (hasn't been explicitly set by the
    7.82 +    //  user, so it's in standby), try to force the display to a resolution
    7.83 +    //  that most closely matches the desired window size.
    7.84 +    if (SDL_UIKit_supports_multiple_displays) {
    7.85 +        const CGSize origsize = [[uiscreen currentMode] size];
    7.86 +        if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
    7.87 +            if (display->num_display_modes == 0) {
    7.88 +                _this->GetDisplayModes(_this, display);
    7.89 +            }
    7.90 +
    7.91 +            int i;
    7.92 +            const SDL_DisplayMode *bestmode = NULL;
    7.93 +            for (i = display->num_display_modes; i >= 0; i--) {
    7.94 +                const SDL_DisplayMode *mode = &display->display_modes[i];
    7.95 +                if ((mode->w >= window->w) && (mode->h >= window->h))
    7.96 +                    bestmode = mode;
    7.97 +            }
    7.98 +
    7.99 +            if (bestmode) {
   7.100 +                UIScreenMode *uimode = (UIScreenMode *) bestmode->driverdata;
   7.101 +                [uiscreen setCurrentMode:uimode];
   7.102 +                display->desktop_mode = *bestmode;
   7.103 +                display->current_mode = *bestmode;
   7.104 +            }
   7.105 +        }
   7.106 +    }
   7.107 +
   7.108      /* ignore the size user requested, and make a fullscreen window */
   7.109 -    UIWindow *uiwindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
   7.110 -    
   7.111 +    // !!! FIXME: can we have a smaller view?
   7.112 +    UIWindow *uiwindow = [UIWindow alloc];
   7.113 +    if (window->flags & SDL_WINDOW_BORDERLESS)
   7.114 +        uiwindow = [uiwindow initWithFrame:[uiscreen bounds]];
   7.115 +    else
   7.116 +        uiwindow = [uiwindow initWithFrame:[uiscreen applicationFrame]];
   7.117 +
   7.118 +    if (SDL_UIKit_supports_multiple_displays) {
   7.119 +        [uiwindow setScreen:uiscreen];
   7.120 +    }
   7.121 +
   7.122      if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
   7.123          [uiwindow release];
   7.124          return -1;
   7.125      }    
   7.126      
   7.127 -    // This saves the main window in the app delegate so event callbacks can do stuff on the window.
   7.128 -    // This assumes a single window application design and needs to be fixed for multiple windows.
   7.129 -    [SDLUIKitDelegate sharedAppDelegate].window = window;
   7.130 -    [SDLUIKitDelegate sharedAppDelegate].uiwindow = uiwindow;
   7.131 -    [uiwindow release]; /* release the window (the app delegate has retained it) */
   7.132 -    
   7.133      return 1;
   7.134      
   7.135  }
   7.136  
   7.137  void UIKit_DestroyWindow(_THIS, SDL_Window * window) {
   7.138 -    /* don't worry, the delegate will automatically release the window */
   7.139 -    
   7.140      SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
   7.141      if (data) {
   7.142 -        SDL_free( window->driverdata );
   7.143 +        [data->uiwindow release];
   7.144 +        SDL_free(data);
   7.145 +        window->driverdata = NULL;
   7.146      }
   7.147 -
   7.148 -    /* this will also destroy the window */
   7.149 -    [SDLUIKitDelegate sharedAppDelegate].window = NULL;
   7.150 -    [SDLUIKitDelegate sharedAppDelegate].uiwindow = nil;
   7.151  }
   7.152  
   7.153  /* vi: set ts=4 sw=4 expandtab: */