This code is a work in progress and does not currently work.

This commit is contained in:
Steve Checkoway
2006-01-14 01:09:33 +00:00
parent b362a5969f
commit 3a820b1c76
3 changed files with 370 additions and 42 deletions
@@ -2,6 +2,7 @@
#define LOW_LEVEL_WINDOW_COCOA_H
#include "LowLevelWindow.h"
#include "RageDisplay.h"
#ifndef __OBJC__
typedef void *id;
@@ -9,25 +10,32 @@ typedef void *id;
class LowLevelWindow_Cocoa : public LowLevelWindow
{
RageDisplay::VideoModeParams mCurrentParams;
VideoModeParams mCurrentParams;
id mWindow;
id mView;
id mFullScreenContext;
bool mSharingContexts;
public:
LowLevelWindow_Cocoa();
~LowLevelWindow_Cocoa();
void *GetProcAddress( CString s );
CString TryVideoMode( RageDisplay::VideoModeParams p, bool& newDeviceOut );
CString TryVideoMode( const VideoModeParams& p, bool& newDeviceOut );
void GetDisplayResolutions( DisplayResolutions &dr ) const;
void SwapBuffers();
void Update();
RageDisplay::VideoModeParams GetVideoModeParams() const { return mCurrentParams; }
VideoModeParams GetActualVideoModeParams() const { return mCurrentParams; }
};
#ifdef ARCH_LOW_LEVEL_WINDOW
#error "More than one LowLevelWindow selected!"
#endif
#define ARCH_LOW_LEVEL_WINDOW LowLevelWindow_Cocoa
#endif
/*
* (c) 2005 Steve Checkoway
* (c) 2005-2006 Steve Checkoway
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
@@ -1,61 +1,75 @@
#import "global.h"
#import "LowLevelWindow_Cocoa.h"
#import "DisplayResolutions.h"
#import "RageLog.h"
#import "RageUtil.h"
#import <Cocoa/Cocoa.h>
#import <mach-o/dyld.h>
@interface SMView : NSOpenGLView
{
}
- (id) initWithFrame:(NSRect)frameRect colorSize:(int)size;
@end
@implementation SMView
- (id) initWithFrame:(NSRect)frameRect colorSize:(int)size
static const int g_iStyleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask;
// Simple helper class
class AutoreleasePool
{
NSAutoreleasePool *mPool;
public:
AutoreleasePool() { mPool = [[NSAutoreleasePool alloc] init]; }
~AutoreleasePool() { [mPool release]; }
};
// These can nest.
#define POOL2(x) AutoreleasePool pool ## x
#define POOL1(x) POOL2(x)
#define POOL POOL1(__LINE__)
static NSOpenGLPixelFormat *CreatePixelFormat( int bbp, bool windowed )
{
NSOpenGLPixelFormatAttribute attrs[] = {
NSOpenGLPFANoRecovery, // so we can share with the full screen context
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAAccelerated,
NSOpenGLPFADepthSize, NSOpenGLPixelFormatAttribute(16),
NSOpenGLPFAColorSize, NSOpenGLPixelFormatAttribute(size),
NSOpenGLPFAColorSize, NSOpenGLPixelFormatAttribute(bbp == 16 ? 16 : 24),
windowed ? NSOpenGLPixelFormatAttribute(0) : NSOpenGLPFAFullScreen,
NSOpenGLPixelFormatAttribute(0)
};
NSOpenGLPixelFormat *pixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
[super initWithFrame:frameRect pixelFormat:pixelFormat];
return self;
return [[[NSOpenGLPixelFormat alloc] initWithAttributes:attrs] autorelease];
}
// Put this here because I always forget about it and it might be needed later.
- (void) dealloc
{
[super dealloc];
}
@end
LowLevelWindow_Cocoa::LowLevelWindow_Cocoa()
LowLevelWindow_Cocoa::LowLevelWindow_Cocoa() : mView(nil), mFullScreenContext(nil)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSRect rect = { 0, 0, 0, 0 };
int mask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask;
POOL;
NSRect rect = { {0, 0}, {0, 0} };
mWindow = [[NSWindow alloc] initWithContentRect:rect
styleMask:mask
styleMask:g_iStyleMask
backing:NSBackingStoreNonretained
defer:YES];
[pool release];
[mWindow setExcludedFromWindowsMenu:YES];
[mWindow useOptimizedDrawing:YES];
}
LowLevelWindow_Cocoa::~LowLevelWindow_Cocoa()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
POOL;
if( mWindow )
{
[mWindow orderOut:nil];
[mWindow release];
}
[pool release];
if( mFullScreenContext )
{
if( !mCurrentParams.windowed )
{
[mFullScreenContext clearDrawable]; // Exit full screen.
CGReleaseAllDisplays();
}
[mFullScreenContext release];
}
}
void *LowLevelWindow_Cocoa::GetProcAddress( CString s )
@@ -69,20 +83,324 @@ void *LowLevelWindow_Cocoa::GetProcAddress( CString s )
return symbol ? NSAddressOfSymbol( symbol ) : NULL;
}
CString LowLevelWindow_Cocoa::TryVideoMode( RageDisplay::VideoModeParams p, bool& newDeviceOut )
CString LowLevelWindow_Cocoa::TryVideoMode( const VideoModeParams& p, bool& newDeviceOut )
{
return "XXX";
POOL;
newDeviceOut = false;
NSRect contentRect = { { 0, 0 }, { p.width, p.height } };
const bool changedWindowed = p.windowed != mCurrentParams.windowed;
const bool changedView = p.bpp != mCurrentParams.bpp || !mView;
LOG->Trace( "changedWindowed = %d; changedView = %d;", int(changedWindowed), int(changedView) );
if( changedWindowed )
{
if( p.windowed )
{
// No need to reset the size if it changes here.
[mWindow setContentSize:contentRect.size];
[mWindow setTitle:[NSString stringWithUTF8String:p.sWindowTitle.c_str()]];
if( changedView )
{
// Create view.
NSOpenGLPixelFormat *pixelFormat = CreatePixelFormat( p.bpp, true );
if( pixelFormat == nil )
return "Failed to set Pixel Format";
id nextView = [[NSOpenGLView alloc] initWithFrame:contentRect pixelFormat:pixelFormat];
if( nextView == nil )
return "Failed to create OGL context.";
mView = nextView;
[mWindow setContentView:mView]; // This retains the view and releases the old one.
[mView release];
newDeviceOut = true;
}
// Shut down full screen. Nothing else should fail.
if( mFullScreenContext )
{
[mFullScreenContext clearDrawable];
CGDisplayErr err = CGReleaseAllDisplays();
ASSERT( err = kCGErrorSuccess );
if( changedView )
{
[mFullScreenContext release];
mFullScreenContext = nil;
}
newDeviceOut = !mSharingContexts;
}
// Set the current context
[[mView openGLContext] makeCurrentContext];
[mWindow center];
[mWindow performSelectorOnMainThread:@selector(makeKeyAndOrderFront:)
withObject:nil waitUntilDone:YES];
return CString();
}
// Okay, we're going full screen here.
// If the bpp has changed (or nothing has been created) we need to recreate everything.
id nextView = changedView ? nil : mView;
if( changedView )
{
NSOpenGLPixelFormat *pixelFormat = CreatePixelFormat( p.bpp, true );
if( pixelFormat == nil )
return "Failed to set pixel format.";
nextView = [[NSOpenGLView alloc] initWithFrame:contentRect pixelFormat:pixelFormat];
if( nextView == nil )
return "Failed to create OGL context.";
newDeviceOut = true;
// We need to recreate the full screen context.
[mFullScreenContext release];
mFullScreenContext = nil;
// Autorelease nextView in case we fail later on.
[nextView autorelease];
}
id newContext = mFullScreenContext;
if( newContext == nil )
{
NSOpenGLPixelFormat *pixelFormat = CreatePixelFormat( p.bpp, false );
if( pixelFormat == nil )
return "Failed to set pixel format.";
newContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
shareContext:[nextView openGLContext]];
if( !(mSharingContexts = newContext != nil) )
{
LOG->Warn( "Failed to share openGL contexts." );
newContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
if( !mFullScreenContext )
return "Failed to create full screen openGL context.";
newDeviceOut = true;
}
// Autorelease to aid cleanup in case of failure
[newContext autorelease];
}
// Now we need to actually go full screen.
CGDisplayErr err = CGCaptureAllDisplays();
if( err != kCGErrorSuccess )
return ssprintf( "Failed to capture all displays: %d.", int(err) );
// We have the display, change the screen size if possible.
CFDictionaryRef params;
if( p.rate == REFRESH_DEFAULT )
params = CGDisplayBestModeForParameters( kCGDirectMainDisplay, p.bpp, p.width, p.height, NULL );
else
params = CGDisplayBestModeForParametersAndRefreshRate( kCGDirectMainDisplay, p.bpp,
p.width, p.height, p.rate, NULL );
err = CGDisplaySwitchToMode( kCGDirectMainDisplay, params );
// XXX the docs don't show releasing params...
if( err != kCGErrorSuccess )
{
CGDisplayErr e = CGReleaseAllDisplays();
ASSERT( e == kCGErrorSuccess );
return ssprintf( "Failed to switch mode: %d.", int(err) );
}
// We've succeeded!
mView = nextView;
[mWindow setContentView:mView];
if( !mFullScreenContext )
mFullScreenContext = [newContext retain]; // We autoreleased above so retain here.
[mFullScreenContext setFullScreen];
[mFullScreenContext makeCurrentContext];
return CString();
}
// We're not changing windowed here
if( p.windowed )
{
if( changedView )
{
// Create view.
NSOpenGLPixelFormat *pixelFormat = CreatePixelFormat( p.bpp, true );
if( pixelFormat == nil )
return "Failed to set Pixel Format";
id nextView = [[NSOpenGLView alloc] initWithFrame:contentRect pixelFormat:pixelFormat];
if( nextView == nil )
return "Failed to create OGL context.";
mView = [nextView autorelease];
newDeviceOut = true;
[mFullScreenContext release];
mFullScreenContext = nil;
}
[mWindow setContentSize:contentRect.size];
[mWindow setTitle:[NSString stringWithUTF8String:p.sWindowTitle.c_str()]];
[mWindow setContentView:mView]; // This retains the view and releases the old one.
[[mView openGLContext] makeCurrentContext];
[mWindow center];
[mWindow performSelectorOnMainThread:@selector(makeKeyAndOrderFront:)
withObject:nil waitUntilDone:YES];
return CString();
}
// Just full screen left here.
// If the bpp has changed (or nothing has been created) we need to recreate everything.
id nextView = changedView ? nil : mView;
if( changedView )
{
NSOpenGLPixelFormat *pixelFormat = CreatePixelFormat( p.bpp, true );
if( pixelFormat == nil )
return "Failed to set pixel format.";
nextView = [[NSOpenGLView alloc] initWithFrame:contentRect pixelFormat:pixelFormat];
if( nextView == nil )
return "Failed to create OGL context.";
newDeviceOut = true;
// We need to recreate the full screen context.
[mFullScreenContext release];
mFullScreenContext = nil;
// Autorelease nextView in case we fail later on.
[nextView autorelease];
}
id newContext = mFullScreenContext;
if( newContext == nil )
{
NSOpenGLPixelFormat *pixelFormat = CreatePixelFormat( p.bpp, false );
if( pixelFormat == nil )
return "Failed to set pixel format.";
newContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
shareContext:[nextView openGLContext]];
if( !(mSharingContexts = newContext != nil) )
{
LOG->Warn( "Failed to share openGL contexts." );
newContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
if( !mFullScreenContext )
return "Failed to create full screen openGL context.";
newDeviceOut = true;
}
// Autorelease to aid cleanup in case of failure
[newContext autorelease];
}
CFDictionaryRef params;
if( p.rate == REFRESH_DEFAULT )
params = CGDisplayBestModeForParameters( kCGDirectMainDisplay, p.bpp, p.width, p.height, NULL );
else
params = CGDisplayBestModeForParametersAndRefreshRate( kCGDirectMainDisplay, p.bpp,
p.width, p.height, p.rate, NULL );
CGDisplayErr err = CGDisplaySwitchToMode( kCGDirectMainDisplay, params );
// XXX the docs don't show releasing params...
if( err != kCGErrorSuccess )
return ssprintf( "Failed to switch mode: %d.", int(err) );
// We've succeeded!
mView = nextView;
[mWindow setContentSize:contentRect.size];
[mWindow setContentView:mView];
if( !mFullScreenContext )
{
mFullScreenContext = [newContext retain]; // We autoreleased above so retain here.
[mFullScreenContext setFullScreen];
[mFullScreenContext makeCurrentContext];
}
else
{
[mFullScreenContext update];
}
return CString();
}
#if 0
if( changedBpp )
{
mView = nil; // Create a new one, setContentView: will release it
if( mFullScreenContext )
{
[mFullScreenContext clearDrawable];
[mFullScreenContext release];
mFullScreenContext = nil;
CGReleaseAllDisplays();
}
}
if( p.windowed )
{
if( !mCurrentParams.windowed )
{
[mFullScreenContext clearDrawable];
CGReleaseAllDisplays();
}
[[mView openGLContext] makeCurrentContext];
[mWindow setTitle:[NSString stringWithUTF8String:p.sWindowTitle.c_str()]];
[mWindow center];
[mWindow performSelectorOnMainThread:@selector(makeKeyAndOrderFront:)
withObject:nil waitUntilDone:YES];
}
else
{
if( !mFullScreenContext )
{
NSOpenGLPixelFormat *pixelFormat = CreatePixelFormat( p.bpp, false );
ASSERT( pixelFormat );
mFullScreenContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat
shareContext:[mView openGLContext]];
if( !mFullScreenContext )
{
LOG->Warn( "Failed to share openGL contexts." );
mFullScreenContext = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil];
ASSERT( mFullScreenContext );
newDeviceOut = true;
}
}
else if( changedSize )
{
[mFullScreenContext update];
}
if( mCurrentParams.windowed )
{
CGCaptureAllDisplays(); // Do not notify other apps of any changes.
[mFullScreenContext setFullScreen];
[mFullScreenContext makeCurrentContext];
}
}
mCurrentParams = p;
return "";
}
#endif
void LowLevelWindow_Cocoa::GetDisplayResolutions( DisplayResolutions &dr ) const
{
CFArrayRef modes = CGDisplayAvailableModes( kCGDirectMainDisplay );
ASSERT( modes );
const CFIndex count = CFArrayGetCount( modes );
for( CFIndex i = 0; i < count; ++i )
{
CFDictionaryRef dict = (CFDictionaryRef)CFArrayGetValueAtIndex( modes, i );
CFNumberRef num = (CFNumberRef)CFDictionaryGetValue( dict, CFSTR("Width") );
SInt32 width, height;
if( !num || !CFNumberGetValue(num, kCFNumberSInt32Type, &width) )
continue;
num = (CFNumberRef)CFDictionaryGetValue( dict, CFSTR("Height") );
if( !num || !CFNumberGetValue(num, kCFNumberSInt32Type, &height) )
continue;
DisplayResolution res = { width, height };
dr.s.insert( res );
}
// Do not release modes! We don't own it here.
}
void LowLevelWindow_Cocoa::SwapBuffers()
{
// XXX I'm not sure if this is needed yet.
//NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//POOL;
[[NSOpenGLContext currentContext] flushBuffer];
//[pool release];
}
void LowLevelWindow_Cocoa::Update()
{
}
@@ -6,6 +6,8 @@
#include "LowLevelWindow_Win32.h"
#elif defined(HAVE_X11)
#include "LowLevelWindow_X11.h"
#elif defined(MACOSX)
#include "LowLevelWindow_Cocoa.h"
#elif defined(HAVE_SDL)
#include "LowLevelWindow_SDL.h"
#else