From 22052f28695172a7c790f37aa827040c3bb2ec39 Mon Sep 17 00:00:00 2001 From: Stijn Buys Date: Mon, 23 Feb 2009 19:36:46 +0000 Subject: native Framework support on Mac OS X --- configure.in | 130 ++++++++++++------ src/Makefile.am | 6 +- src/SDLMain.h | 11 ++ src/SDLMain.m | 384 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/audio/audio.h | 6 + src/audio/buffers.h | 9 +- src/audio/sources.h | 9 +- src/osirion.cc | 6 +- src/render/gl.h | 6 + 9 files changed, 520 insertions(+), 47 deletions(-) create mode 100644 src/SDLMain.h create mode 100644 src/SDLMain.m diff --git a/configure.in b/configure.in index e4f6aff..1b3c803 100644 --- a/configure.in +++ b/configure.in @@ -77,28 +77,51 @@ dnl AC_MSG_CHECKING([host type]) case "$host" in + *-apple-darwin*) + HOST_LIBS="-lz" + HOST_GL_LIBS="-framework OpenGL" + HOST_AL_LIBS="-framework OpenAL" + HOST_SDL_LIBS="-framework SDL -framework Cocoa" + ICON_CLIENT="" + ICON_SERVER="" + SDLMAIN="SDLMain.o" + INSTALLTYPE="application bundle" + OS=OSX + AC_MSG_RESULT(OS X) + AC_DEFINE_UNQUOTED(_OSX, 1, [Define this if you're building for native OS X]) + AC_PROG_OBJC + ;; + *-*-mingw*) HOST_LIBS="-lws2_32 -lz" - HOST_GL_LIBS="-lopengl32 -lglu32" + HOST_GL_LIBS="-lopengl32" HOST_AL_LIBS="-lopenal32" ICON_CLIENT="osirion-res.o" ICON_SERVER="osiriond-res.o" + SDLMAIN="" INSTALLTYPE="single directory" + OS=WIN32 AC_MSG_RESULT(win32) ;; *) HOST_LIBS="-lz" - HOST_GL_LIBS="-lGL -lGLU" + HOST_GL_LIBS="-lGL" HOST_AL_LIBS="-lopenal" ICON_CLIENT="" ICON_SERVER="" + SDLMAIN="" INSTALLTYPE="standard" AC_MSG_RESULT(generic unix) + OS=UNIX ;; esac +AC_SUBST(OS) AC_SUBST(HOST_LIBS) AC_SUBST(ICON_CLIENT) AC_SUBST(ICON_SERVER) +AC_SUBST(SDLMAIN) + +AC_DEFINE(OS, $OS, [Operating System]) dnl ---------------------------------------------------------------- dnl enable compiler warnings or not @@ -220,33 +243,48 @@ if test "x${with_client}" = xno; then else AC_MSG_RESULT(yes) + LDFLAGS_save="$LDFLAGS" + dnl --------------------------------------------------------------- dnl OpenGL dnl - AC_CHECK_HEADER(GL/gl.h, - [], - [AC_MSG_ERROR([GL/gl.h not found])] - ) - - AC_CHECK_HEADER(GL/glu.h, - [], - [AC_MSG_ERROR([GL/glu.h not found])] - ) + if test "x${OS}" = "xOSX"; then + AC_CHECK_HEADER(OpenGL/gl.h, + [], + [AC_MSG_ERROR([OpenGL/gl.h not found])] + ) + else + AC_CHECK_HEADER(GL/gl.h, + [], + [AC_MSG_ERROR([GL/gl.h not found])] + ) + fi + LD_FLAGS="$LDFLAGS_save" GL_LIBS="$HOST_GL_LIBS" AC_SUBST(GL_LIBS) AC_SUBST(GL_CFLAGS) dnl --------------------------------------------------------------- dnl OpenAL - - AC_CHECK_HEADER(AL/al.h, - [], - [AC_MSG_ERROR([AL/al.h not found])] - ) + + if test "x${OS}" = "xOSX"; then + AC_CHECK_HEADER(OpenAL/al.h, + [], + [AC_MSG_ERROR([OpenAL/al.h not found])] + ) + else + AC_CHECK_HEADER(AL/al.h, + [], + [AC_MSG_ERROR([AL/al.h not found])] + ) + fi + + LD_FLAGS="$LDFLAGS_save" AL_LIBS="$HOST_AL_LIBS" AC_SUBST(AL_LIBS) + AC_SUBST(AL_CFLAGS) dnl --------------------------------------------------------------- dnl libpng @@ -284,31 +322,43 @@ else dnl SDL dnl - AC_MSG_CHECKING([looking for SDL]) - KDE_FIND_PATH(sdl-config, LIBSDL_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin], [ - AC_MSG_ERROR([SDL not found]) - ]) - - if test -n "$LIBSDL_CONFIG"; then - LIBSDL_LIBS="`$LIBSDL_CONFIG --libs`" - LIBSDL_RPATH= - for args in $LIBSDL_LIBS; do - case $args in - -L*) - LIBSDL_RPATH="$LIBSDL_RPATH $args" - ;; - esac - done - - LIBSDL_RPATH=`echo $LIBSDL_RPATH | sed -e "s/-L/-R/g"` - LIBSDL_CFLAGS="`$LIBSDL_CONFIG --cflags`" + if test "x${OS}" = "xOSX"; then + AC_CHECK_HEADER(SDL/SDL.h, + [], + [AC_MSG_ERROR([SDL/SDL.h not found])] + ) + + LIBSDL_LIBS="$HOST_SDL_LIBS" + LIBSDL_CFLAGS="$HOST_SDL_LIBS" + AC_SUBST(LIBSDL_LIBS) + AC_SUBST(LIBSDL_CFLAGS) + else + AC_MSG_CHECKING([looking for SDL]) + KDE_FIND_PATH(sdl-config, LIBSDL_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin], [ + AC_MSG_ERROR([SDL not found]) + ]) + + if test -n "$LIBSDL_CONFIG"; then + LIBSDL_LIBS="`$LIBSDL_CONFIG --libs`" + LIBSDL_RPATH= + for args in $LIBSDL_LIBS; do + case $args in + -L*) + LIBSDL_RPATH="$LIBSDL_RPATH $args" + ;; + esac + done + + LIBSDL_RPATH=`echo $LIBSDL_RPATH | sed -e "s/-L/-R/g"` + LIBSDL_CFLAGS="`$LIBSDL_CONFIG --cflags`" + fi + + AC_MSG_RESULT($HAVE_LIBSDL) + + AC_SUBST(LIBSDL_LIBS) + AC_SUBST(LIBSDL_CFLAGS) + AC_SUBST(LIBSDL_RPATH) fi - - AC_MSG_RESULT($HAVE_LIBSDL) - - AC_SUBST(LIBSDL_LIBS) - AC_SUBST(LIBSDL_CFLAGS) - AC_SUBST(LIBSDL_RPATH) BUILD_CLIENT=yes AC_DEFINE_UNQUOTED(BUILD_CLIENT, 1, [Define this to build the client]) diff --git a/src/Makefile.am b/src/Makefile.am index 3bd5adf..085f15f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,8 +30,8 @@ osiriond_LDADD = $(top_builddir)/src/auxiliary/libauxiliary.la \ # client osirion_SOURCES = osirion.cc -EXTRA_osirion_SOURCES = osirion-res.rc -osirion_DEPENDENCIES = $(ICON_CLIENT) $(top_builddir)/src/core/libcore.la \ +EXTRA_osirion_SOURCES = osirion-res.rc SDLMain.m +osirion_DEPENDENCIES = $(ICON_CLIENT) $(SDLMAIN) $(top_builddir)/src/core/libcore.la \ $(top_builddir)/src/audio/libaudio.la $(top_builddir)/src/render/librender.la \ $(top_builddir)/src/ui/libui.la $(top_builddir)/src/client/libclient.la \ $(top_builddir)/src/game/libgame.la @@ -43,5 +43,5 @@ osirion_LDADD = $(top_builddir)/src/game/libgame.la $(top_builddir)/src/ui/libui $(top_builddir)/src/math/libmath.la $(top_builddir)/src/auxiliary/libauxiliary.la \ $(top_builddir)/src/filesystem/libfilesystem.la $(top_builddir)/src/sys/libsys.la \ $(top_builddir)/src/auxiliary/libauxiliary.la \ - $(AL_LIBS) $(GL_LIBS) $(HOST_LIBS) $(LIBPNG_LIBS) $(LIBJPG_LIBS) $(ICON_CLIENT) + $(AL_LIBS) $(GL_LIBS) $(HOST_LIBS) $(LIBPNG_LIBS) $(LIBJPG_LIBS) $(ICON_CLIENT) $(SDLMAIN) osirion_LDFLAGS = $(LIBSDL_LIBS) diff --git a/src/SDLMain.h b/src/SDLMain.h new file mode 100644 index 0000000..4683df5 --- /dev/null +++ b/src/SDLMain.h @@ -0,0 +1,11 @@ +/* SDLMain.m - main entry point for our Cocoa-ized SDL app + Initial Version: Darrell Walisser + Non-NIB-Code & other changes: Max Horn + + Feel free to customize this file to suit your needs +*/ + +#import + +@interface SDLMain : NSObject +@end diff --git a/src/SDLMain.m b/src/SDLMain.m new file mode 100644 index 0000000..3f0a555 --- /dev/null +++ b/src/SDLMain.m @@ -0,0 +1,384 @@ +/* SDLMain.m - main entry point for our Cocoa-ized SDL app + Initial Version: Darrell Walisser + Non-NIB-Code & other changes: Max Horn + + Feel free to customize this file to suit your needs +*/ + +#import "SDL/SDL.h" +#import "SDLMain.h" +#import /* for MAXPATHLEN */ +#import + +/* For some reaon, Apple removed setAppleMenu from the headers in 10.4, + but the method still is there and works. To avoid warnings, we declare + it ourselves here. */ +@interface NSApplication(SDL_Missing_Methods) +- (void)setAppleMenu:(NSMenu *)menu; +@end + +/* Use this flag to determine whether we use SDLMain.nib or not */ +#define SDL_USE_NIB_FILE 0 + +/* Use this flag to determine whether we use CPS (docking) or not */ +#define SDL_USE_CPS 1 +#ifdef SDL_USE_CPS +/* Portions of CPS.h */ +typedef struct CPSProcessSerNum +{ + UInt32 lo; + UInt32 hi; +} CPSProcessSerNum; + +extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); +extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); +extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); + +#endif /* SDL_USE_CPS */ + +static int gArgc; +static char **gArgv; +static BOOL gFinderLaunch; +static BOOL gCalledAppMainline = FALSE; + +static NSString *getApplicationName(void) +{ + NSDictionary *dict; + NSString *appName = 0; + + /* Determine the application name */ + dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); + if (dict) + appName = [dict objectForKey: @"CFBundleName"]; + + if (![appName length]) + appName = [[NSProcessInfo processInfo] processName]; + + return appName; +} + +#if SDL_USE_NIB_FILE +/* A helper category for NSString */ +@interface NSString (ReplaceSubString) +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; +@end +#endif + +@interface SDLApplication : NSApplication +@end + +@implementation SDLApplication +/* Invoked from the Quit menu item */ +- (void)terminate:(id)sender +{ + /* Post a SDL_QUIT event */ + SDL_Event event; + event.type = SDL_QUIT; + SDL_PushEvent(&event); +} +@end + +/* The main class of the application, the application's delegate */ +@implementation SDLMain + +/* Set the working directory to the .app's parent directory */ +- (void) setupWorkingDirectory:(BOOL)shouldChdir +{ + if (shouldChdir) + { + char parentdir[MAXPATHLEN]; + CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); + if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) { + assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ + } + CFRelease(url); + CFRelease(url2); + } + +} + +#if SDL_USE_NIB_FILE + +/* Fix menu to contain the real app name instead of "SDL App" */ +- (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName +{ + NSRange aRange; + NSEnumerator *enumerator; + NSMenuItem *menuItem; + + aRange = [[aMenu title] rangeOfString:@"SDL App"]; + if (aRange.length != 0) + [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]]; + + enumerator = [[aMenu itemArray] objectEnumerator]; + while ((menuItem = [enumerator nextObject])) + { + aRange = [[menuItem title] rangeOfString:@"SDL App"]; + if (aRange.length != 0) + [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]]; + if ([menuItem hasSubmenu]) + [self fixMenu:[menuItem submenu] withAppName:appName]; + } + [ aMenu sizeToFit ]; +} + +#else + +static void setApplicationMenu(void) +{ + /* warning: this code is very odd */ + NSMenu *appleMenu; + NSMenuItem *menuItem; + NSString *title; + NSString *appName; + + appName = getApplicationName(); + appleMenu = [[NSMenu alloc] initWithTitle:@""]; + + /* Add menu items */ + title = [@"About " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Hide " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; + + menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; + + [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Quit " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; + + + /* Put menu into the menubar */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; + [menuItem setSubmenu:appleMenu]; + [[NSApp mainMenu] addItem:menuItem]; + + /* Tell the application object that this is now the application menu */ + [NSApp setAppleMenu:appleMenu]; + + /* Finally give up our references to the objects */ + [appleMenu release]; + [menuItem release]; +} + +/* Create a window menu */ +static void setupWindowMenu(void) +{ + NSMenu *windowMenu; + NSMenuItem *windowMenuItem; + NSMenuItem *menuItem; + + windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; + + /* "Minimize" item */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"]; + [windowMenu addItem:menuItem]; + [menuItem release]; + + /* Put menu into the menubar */ + windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""]; + [windowMenuItem setSubmenu:windowMenu]; + [[NSApp mainMenu] addItem:windowMenuItem]; + + /* Tell the application object that this is now the window menu */ + [NSApp setWindowsMenu:windowMenu]; + + /* Finally give up our references to the objects */ + [windowMenu release]; + [windowMenuItem release]; +} + +/* Replacement for NSApplicationMain */ +static void CustomApplicationMain (int argc, char **argv) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + SDLMain *sdlMain; + + /* Ensure the application object is initialised */ + [SDLApplication sharedApplication]; + +#ifdef SDL_USE_CPS + { + CPSProcessSerNum PSN; + /* Tell the dock about us */ + if (!CPSGetCurrentProcess(&PSN)) + if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) + if (!CPSSetFrontProcess(&PSN)) + [SDLApplication sharedApplication]; + } +#endif /* SDL_USE_CPS */ + + /* Set up the menubar */ + [NSApp setMainMenu:[[NSMenu alloc] init]]; + setApplicationMenu(); + setupWindowMenu(); + + /* Create SDLMain and make it the app delegate */ + sdlMain = [[SDLMain alloc] init]; + [NSApp setDelegate:sdlMain]; + + /* Start the main event loop */ + [NSApp run]; + + [sdlMain release]; + [pool release]; +} + +#endif + + +/* + * Catch document open requests...this lets us notice files when the app + * was launched by double-clicking a document, or when a document was + * dragged/dropped on the app's icon. You need to have a + * CFBundleDocumentsType section in your Info.plist to get this message, + * apparently. + * + * Files are added to gArgv, so to the app, they'll look like command line + * arguments. Previously, apps launched from the finder had nothing but + * an argv[0]. + * + * This message may be received multiple times to open several docs on launch. + * + * This message is ignored once the app's mainline has been called. + */ +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename +{ + const char *temparg; + size_t arglen; + char *arg; + char **newargv; + + if (!gFinderLaunch) /* MacOS is passing command line args. */ + return FALSE; + + if (gCalledAppMainline) /* app has started, ignore this document. */ + return FALSE; + + temparg = [filename UTF8String]; + arglen = SDL_strlen(temparg) + 1; + arg = (char *) SDL_malloc(arglen); + if (arg == NULL) + return FALSE; + + newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); + if (newargv == NULL) + { + SDL_free(arg); + return FALSE; + } + gArgv = newargv; + + SDL_strlcpy(arg, temparg, arglen); + gArgv[gArgc++] = arg; + gArgv[gArgc] = NULL; + return TRUE; +} + + +/* Called when the internal event loop has just started running */ +- (void) applicationDidFinishLaunching: (NSNotification *) note +{ + int status; + + /* Set the working directory to the .app's parent directory */ + [self setupWorkingDirectory:gFinderLaunch]; + +#if SDL_USE_NIB_FILE + /* Set the main menu to contain the real app name instead of "SDL App" */ + [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; +#endif + + /* Hand off to main application code */ + gCalledAppMainline = TRUE; + status = SDL_main (gArgc, gArgv); + + /* We're done, thank you for playing */ + exit(status); +} +@end + + +@implementation NSString (ReplaceSubString) + +- (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString +{ + unsigned int bufferSize; + unsigned int selfLen = [self length]; + unsigned int aStringLen = [aString length]; + unichar *buffer; + NSRange localRange; + NSString *result; + + bufferSize = selfLen + aStringLen - aRange.length; + buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar)); + + /* Get first part into buffer */ + localRange.location = 0; + localRange.length = aRange.location; + [self getCharacters:buffer range:localRange]; + + /* Get middle part into buffer */ + localRange.location = 0; + localRange.length = aStringLen; + [aString getCharacters:(buffer+aRange.location) range:localRange]; + + /* Get last part into buffer */ + localRange.location = aRange.location + aRange.length; + localRange.length = selfLen - localRange.location; + [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange]; + + /* Build output string */ + result = [NSString stringWithCharacters:buffer length:bufferSize]; + + NSDeallocateMemoryPages(buffer, bufferSize); + + return result; +} + +@end + + + +#ifdef main +# undef main +#endif + + +/* Main entry point to executable - should *not* be SDL_main! */ +int main (int argc, char **argv) +{ + /* Copy the arguments into a global variable */ + /* This is passed if we are launched by double-clicking */ + if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { + gArgv = (char **) SDL_malloc(sizeof (char *) * 2); + gArgv[0] = argv[0]; + gArgv[1] = NULL; + gArgc = 1; + gFinderLaunch = YES; + } else { + int i; + gArgc = argc; + gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); + for (i = 0; i <= argc; i++) + gArgv[i] = argv[i]; + gFinderLaunch = NO; + } + +#if SDL_USE_NIB_FILE + [SDLApplication poseAsClass:[NSApplication class]]; + NSApplicationMain (argc, argv); +#else + CustomApplicationMain (argc, argv); +#endif + return 0; +} + diff --git a/src/audio/audio.h b/src/audio/audio.h index 930edaf..2849013 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -8,13 +8,19 @@ #define __INCLUDED_AUDIO_AUDIO_H__ #include +#include "sys/sys.h" #ifdef _WIN32 #include #endif +#ifdef _OSX +#include "OpenAL/al.h" +#include "OpenAL/alc.h" +#else #include "AL/al.h" #include "AL/alc.h" +#endif #include "math/vector3f.h" #include "math/axis.h" diff --git a/src/audio/buffers.h b/src/audio/buffers.h index cc7a6c8..2b31089 100644 --- a/src/audio/buffers.h +++ b/src/audio/buffers.h @@ -7,8 +7,15 @@ #ifndef __INCLUDED_AUDIO_BUFFERS_H__ #define __INCLUDED_AUDIO_BUFFERS_H__ -#include "AL/al.h" +#include "sys/sys.h" + +#ifdef _OSX +#include "OpenAL/al.h" +#include "OpenAL/alc.h" +#else +#include "AL/al.h" #include "AL/alc.h" +#endif #include #include diff --git a/src/audio/sources.h b/src/audio/sources.h index 078c424..c9e38e2 100644 --- a/src/audio/sources.h +++ b/src/audio/sources.h @@ -7,8 +7,15 @@ #ifndef __INCLUDED_AUDIO_SOURCES_H__ #define __INCLUDED_AUDIO_SOURCES_H__ -#include "AL/al.h" +#include "sys/sys.h" + +#ifdef _OSX +#include "OpenAL/al.h" +#include "OpenAL/alc.h" +#else +#include "AL/al.h" #include "AL/alc.h" +#endif #include #include diff --git a/src/osirion.cc b/src/osirion.cc index 04218be..4db5e6f 100644 --- a/src/osirion.cc +++ b/src/osirion.cc @@ -4,15 +4,17 @@ the terms and conditions of the GNU General Public License version 2 */ +#include "SDL/SDL.h" + #include "client/client.h" #include "game/game.h" -int main(int count, char **arguments) +int main(int argc, char *argv[]) { // load the game modules register_modules(true); - client::run(count, arguments); + client::run(argc, argv); return 0; } diff --git a/src/render/gl.h b/src/render/gl.h index dc0b5a1..83241f9 100644 --- a/src/render/gl.h +++ b/src/render/gl.h @@ -7,7 +7,13 @@ #ifndef __INCLUDED_RENDER_GL_H__ #define __INCLUDED_RENDER_GL_H__ +#include "sys/sys.h" + +#ifdef _OSX +#include "OpenGL/gl.h" +#else #include "GL/gl.h" +#endif #include "math/vector2f.h" #include "math/vector3f.h" -- cgit v1.2.3