Much improved multi-display support for iPad.
Fixes most issues and limitations, I think.
--- a/src/video/uikit/SDL_uikitappdelegate.h Sat May 01 13:50:56 2010 -0400
+++ b/src/video/uikit/SDL_uikitappdelegate.h Sun May 02 05:08:12 2010 -0400
@@ -25,13 +25,8 @@
/* *INDENT-OFF* */
@interface SDLUIKitDelegate:NSObject<UIApplicationDelegate> {
- SDL_Window *window;
- UIWindow *uiwindow;
}
-@property (readwrite, assign) SDL_Window *window;
-@property (readwrite, retain) UIWindow *uiwindow;
-
+(SDLUIKitDelegate *)sharedAppDelegate;
@end
--- a/src/video/uikit/SDL_uikitappdelegate.m Sat May 01 13:50:56 2010 -0400
+++ b/src/video/uikit/SDL_uikitappdelegate.m Sun May 02 05:08:12 2010 -0400
@@ -20,6 +20,8 @@
slouken@libsdl.org
*/
+#import "../SDL_sysvideo.h"
+
#import "SDL_uikitappdelegate.h"
#import "SDL_uikitopenglview.h"
#import "SDL_events_c.h"
@@ -55,9 +57,6 @@
@implementation SDLUIKitDelegate
-@synthesize window;
-@synthesize uiwindow;
-
/* convenience method */
+(SDLUIKitDelegate *)sharedAppDelegate {
/* the delegate is set in UIApplicationMain(), which is garaunteed to be called before this method */
@@ -66,8 +65,6 @@
- (id)init {
self = [super init];
- window = NULL;
- uiwindow = nil;
return self;
}
@@ -106,21 +103,42 @@
- (void) applicationWillResignActive:(UIApplication*)application
{
-// NSLog(@"%@", NSStringFromSelector(_cmd));
- SDL_SendWindowEvent(self.window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
+ //NSLog(@"%@", NSStringFromSelector(_cmd));
+
+ // Send every window on every screen a MINIMIZED event.
+ SDL_VideoDevice *_this = SDL_GetVideoDevice();
+ if (!_this) {
+ return;
+ }
+
+ int i;
+ for (i = 0; i < _this->num_displays; i++) {
+ const SDL_VideoDisplay *display = &_this->displays[i];
+ SDL_Window *window;
+ for (window = display->windows; window != nil; window = window->next) {
+ SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
+ }
+ }
}
- (void) applicationDidBecomeActive:(UIApplication*)application
{
-// NSLog(@"%@", NSStringFromSelector(_cmd));
- SDL_SendWindowEvent(self.window, SDL_WINDOWEVENT_RESTORED, 0, 0);
-}
+ //NSLog(@"%@", NSStringFromSelector(_cmd));
+ // Send every window on every screen a RESTORED event.
+ SDL_VideoDevice *_this = SDL_GetVideoDevice();
+ if (!_this) {
+ return;
+ }
-
--(void)dealloc {
- [uiwindow release];
- [super dealloc];
+ int i;
+ for (i = 0; i < _this->num_displays; i++) {
+ const SDL_VideoDisplay *display = &_this->displays[i];
+ SDL_Window *window;
+ for (window = display->windows; window != nil; window = window->next) {
+ SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
+ }
+ }
}
@end
--- a/src/video/uikit/SDL_uikitopengles.m Sat May 01 13:50:56 2010 -0400
+++ b/src/video/uikit/SDL_uikitopengles.m Sun May 02 05:08:12 2010 -0400
@@ -99,13 +99,13 @@
SDL_GLContext UIKit_GL_CreateContext(_THIS, SDL_Window * window)
{
-
SDL_uikitopenglview *view;
+ SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
+ UIScreen *uiscreen = (UIScreen *) window->display->driverdata;
+ UIWindow *uiwindow = data->uiwindow;
- SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
-
- /* construct our view, passing in SDL's OpenGL configuration data */
- view = [[SDL_uikitopenglview alloc] initWithFrame: [[UIScreen mainScreen] applicationFrame] \
+ /* construct our view, passing in SDL's OpenGL configuration data */
+ view = [[SDL_uikitopenglview alloc] initWithFrame: [uiwindow bounds] \
retainBacking: _this->gl_config.retained_backing \
rBits: _this->gl_config.red_size \
gBits: _this->gl_config.green_size \
@@ -116,7 +116,7 @@
data->view = view;
/* add the view to our window */
- [data->uiwindow addSubview: view ];
+ [uiwindow addSubview: view ];
/* Don't worry, the window retained the view */
[view release];
--- a/src/video/uikit/SDL_uikitvideo.h Sat May 01 13:50:56 2010 -0400
+++ b/src/video/uikit/SDL_uikitvideo.h Sun May 02 05:08:12 2010 -0400
@@ -26,6 +26,10 @@
#include "../SDL_sysvideo.h"
+#include <UIKit/UIKit.h>
+
+extern BOOL SDL_UIKit_supports_multiple_displays;
+
#endif /* _SDL_uikitvideo_h */
/* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/uikit/SDL_uikitvideo.m Sat May 01 13:50:56 2010 -0400
+++ b/src/video/uikit/SDL_uikitvideo.m Sun May 02 05:08:12 2010 -0400
@@ -49,7 +49,7 @@
SDL_DisplayMode * mode);
static void UIKit_VideoQuit(_THIS);
-static BOOL supports_multiple_displays = NO;
+BOOL SDL_UIKit_supports_multiple_displays = NO;
/* DUMMY driver bootstrap functions */
@@ -124,14 +124,14 @@
static void
UIKit_GetDisplayModes(_THIS, SDL_VideoDisplay * display)
{
- const UIScreen *screen = (UIScreen *) display->driverdata;
+ UIScreen *uiscreen = (UIScreen *) display->driverdata;
SDL_DisplayMode mode;
SDL_zero(mode);
// availableModes showed up in 3.2 (the iPad and later). We should only
// land here for at least that version of the OS.
- if (!supports_multiple_displays) {
- const CGRect rect = [screen bounds];
+ if (!SDL_UIKit_supports_multiple_displays) {
+ const CGRect rect = [uiscreen bounds];
mode.format = SDL_PIXELFORMAT_ABGR8888;
mode.w = (int) rect.size.width;
mode.h = (int) rect.size.height;
@@ -141,7 +141,7 @@
return;
}
- const NSArray *modes = [screen availableModes];
+ const NSArray *modes = [uiscreen availableModes];
const NSUInteger mode_count = [modes count];
NSUInteger i;
for (i = 0; i < mode_count; i++) {
@@ -159,11 +159,10 @@
static void
-UIKit_AddDisplay(UIScreen *screen, int w, int h)
+UIKit_AddDisplay(UIScreen *uiscreen, int w, int h)
{
SDL_VideoDisplay display;
SDL_DisplayMode mode;
-
SDL_zero(mode);
mode.format = SDL_PIXELFORMAT_ABGR8888;
mode.w = w;
@@ -173,8 +172,9 @@
SDL_zero(display);
display.desktop_mode = mode;
display.current_mode = mode;
- display.driverdata = screen;
- [screen retain];
+
+ [uiscreen retain];
+ display.driverdata = uiscreen;
SDL_AddVideoDisplay(&display);
}
@@ -187,25 +187,25 @@
NSString *reqSysVer = @"3.2";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];
if ([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
- supports_multiple_displays = YES;
+ SDL_UIKit_supports_multiple_displays = YES;
// If this is iPhoneOS < 3.2, all devices are one screen, 320x480 pixels.
// The iPad added both a larger main screen and the ability to use
// external displays.
- if (!supports_multiple_displays) {
+ if (!SDL_UIKit_supports_multiple_displays) {
// Just give 'em the whole main screen.
- UIScreen *screen = [UIScreen mainScreen];
- const CGRect rect = [screen bounds];
- UIKit_AddDisplay(screen, (int)rect.size.width, (int)rect.size.height);
+ UIScreen *uiscreen = [UIScreen mainScreen];
+ const CGRect rect = [uiscreen bounds];
+ UIKit_AddDisplay(uiscreen, (int)rect.size.width, (int)rect.size.height);
} else {
const NSArray *screens = [UIScreen screens];
const NSUInteger screen_count = [screens count];
NSUInteger i;
for (i = 0; i < screen_count; i++) {
// the main screen is the first element in the array.
- UIScreen *screen = (UIScreen *) [screens objectAtIndex:i];
- const CGSize size = [[screen currentMode] size];
- UIKit_AddDisplay(screen, (int) size.width, (int) size.height);
+ UIScreen *uiscreen = (UIScreen *) [screens objectAtIndex:i];
+ const CGSize size = [[uiscreen currentMode] size];
+ UIKit_AddDisplay(uiscreen, (int) size.width, (int) size.height);
}
}
@@ -216,13 +216,13 @@
static int
UIKit_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
{
- UIScreen *screen = (UIScreen *) display->driverdata;
- if (!supports_multiple_displays) {
+ UIScreen *uiscreen = (UIScreen *) display->driverdata;
+ if (!SDL_UIKit_supports_multiple_displays) {
// Not on at least iPhoneOS 3.2 (versions prior to iPad).
SDL_assert(mode->driverdata == NULL);
} else {
UIScreenMode *uimode = (UIScreenMode *) mode->driverdata;
- [screen setCurrentMode:uimode];
+ [uiscreen setCurrentMode:uimode];
}
return 0;
@@ -235,8 +235,8 @@
int i, j;
for (i = 0; i < _this->num_displays; i++) {
SDL_VideoDisplay *display = &_this->displays[i];
- UIScreen *screen = (UIScreen *) display->driverdata;
- [((UIScreen *) display->driverdata) release];
+ UIScreen *uiscreen = (UIScreen *) display->driverdata;
+ [uiscreen release];
display->driverdata = NULL;
for (j = 0; j < display->num_display_modes; j++) {
SDL_DisplayMode *mode = &display->display_modes[j];
--- a/src/video/uikit/SDL_uikitwindow.h Sat May 01 13:50:56 2010 -0400
+++ b/src/video/uikit/SDL_uikitwindow.h Sun May 02 05:08:12 2010 -0400
@@ -36,7 +36,6 @@
struct SDL_WindowData
{
- SDL_Window *window;
UIWindow *uiwindow;
SDL_uikitopenglview *view;
};
--- a/src/video/uikit/SDL_uikitwindow.m Sat May 01 13:50:56 2010 -0400
+++ b/src/video/uikit/SDL_uikitwindow.m Sun May 02 05:08:12 2010 -0400
@@ -23,6 +23,7 @@
#include "SDL_video.h"
#include "SDL_mouse.h"
+#include "SDL_assert.h"
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
#include "../../events/SDL_events_c.h"
@@ -38,8 +39,10 @@
#include <UIKit/UIKit.h>
#include <Foundation/Foundation.h>
-static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created) {
-
+static int SetupWindowData(_THIS, SDL_Window *window, UIWindow *uiwindow, SDL_bool created)
+{
+ SDL_VideoDisplay *display = window->display;
+ UIScreen *uiscreen = (UIScreen *) display->driverdata;
SDL_WindowData *data;
/* Allocate the window data */
@@ -48,7 +51,6 @@
SDL_OutOfMemory();
return -1;
}
- data->window = window;
data->uiwindow = uiwindow;
data->view = nil;
@@ -68,12 +70,15 @@
window->flags |= SDL_WINDOW_SHOWN; /* only one window on iPod touch, always shown */
window->flags |= SDL_WINDOW_INPUT_FOCUS; /* always has input focus */
- /* SDL_WINDOW_BORDERLESS controls whether status bar is hidden */
- if (window->flags & SDL_WINDOW_BORDERLESS) {
- [UIApplication sharedApplication].statusBarHidden = YES;
- }
- else {
- [UIApplication sharedApplication].statusBarHidden = NO;
+ // SDL_WINDOW_BORDERLESS controls whether status bar is hidden.
+ // This is only set if the window is on the main screen. Other screens
+ // just force the window to have the borderless flag.
+ if ([UIScreen mainScreen] == uiscreen) {
+ if (window->flags & SDL_WINDOW_BORDERLESS) {
+ [UIApplication sharedApplication].statusBarHidden = YES;
+ } else {
+ [UIApplication sharedApplication].statusBarHidden = NO;
+ }
}
return 0;
@@ -82,41 +87,80 @@
int UIKit_CreateWindow(_THIS, SDL_Window *window) {
- /* We currently only handle single window applications on iPhone */
- if (nil != [SDLUIKitDelegate sharedAppDelegate].window) {
- SDL_SetError("Window already exists, no multi-window support.");
+ SDL_VideoDisplay *display = window->display;
+ UIScreen *uiscreen = (UIScreen *) display->driverdata;
+
+ // SDL currently puts this window at the start of display's linked list. We rely on this.
+ SDL_assert(display->windows == window);
+
+ /* We currently only handle a single window per display on iPhone */
+ if (window->next != NULL) {
+ SDL_SetError("Only one window allowed per display.");
return -1;
}
-
+
+ // Non-mainscreen windows must be force to borderless, as there's no
+ // status bar there, and we want to get the right dimensions later in
+ // this function.
+ if ([UIScreen mainScreen] != uiscreen) {
+ window->flags |= SDL_WINDOW_BORDERLESS;
+ }
+
+ // If monitor has a resolution of 0x0 (hasn't been explicitly set by the
+ // user, so it's in standby), try to force the display to a resolution
+ // that most closely matches the desired window size.
+ if (SDL_UIKit_supports_multiple_displays) {
+ const CGSize origsize = [[uiscreen currentMode] size];
+ if ((origsize.width == 0.0f) && (origsize.height == 0.0f)) {
+ if (display->num_display_modes == 0) {
+ _this->GetDisplayModes(_this, display);
+ }
+
+ int i;
+ const SDL_DisplayMode *bestmode = NULL;
+ for (i = display->num_display_modes; i >= 0; i--) {
+ const SDL_DisplayMode *mode = &display->display_modes[i];
+ if ((mode->w >= window->w) && (mode->h >= window->h))
+ bestmode = mode;
+ }
+
+ if (bestmode) {
+ UIScreenMode *uimode = (UIScreenMode *) bestmode->driverdata;
+ [uiscreen setCurrentMode:uimode];
+ display->desktop_mode = *bestmode;
+ display->current_mode = *bestmode;
+ }
+ }
+ }
+
/* ignore the size user requested, and make a fullscreen window */
- UIWindow *uiwindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
-
+ // !!! FIXME: can we have a smaller view?
+ UIWindow *uiwindow = [UIWindow alloc];
+ if (window->flags & SDL_WINDOW_BORDERLESS)
+ uiwindow = [uiwindow initWithFrame:[uiscreen bounds]];
+ else
+ uiwindow = [uiwindow initWithFrame:[uiscreen applicationFrame]];
+
+ if (SDL_UIKit_supports_multiple_displays) {
+ [uiwindow setScreen:uiscreen];
+ }
+
if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
[uiwindow release];
return -1;
}
- // This saves the main window in the app delegate so event callbacks can do stuff on the window.
- // This assumes a single window application design and needs to be fixed for multiple windows.
- [SDLUIKitDelegate sharedAppDelegate].window = window;
- [SDLUIKitDelegate sharedAppDelegate].uiwindow = uiwindow;
- [uiwindow release]; /* release the window (the app delegate has retained it) */
-
return 1;
}
void UIKit_DestroyWindow(_THIS, SDL_Window * window) {
- /* don't worry, the delegate will automatically release the window */
-
SDL_WindowData *data = (SDL_WindowData *)window->driverdata;
if (data) {
- SDL_free( window->driverdata );
+ [data->uiwindow release];
+ SDL_free(data);
+ window->driverdata = NULL;
}
-
- /* this will also destroy the window */
- [SDLUIKitDelegate sharedAppDelegate].window = NULL;
- [SDLUIKitDelegate sharedAppDelegate].uiwindow = nil;
}
/* vi: set ts=4 sw=4 expandtab: */