/* SDLMain.
m - main entry point
for our Cocoa-ized SDL app
Initial
Version: Darrell Walisser <dwaliss1@purdue.
edu>
Non-NIB-Code & other changes:
Max Horn <
max@quendi.
de>
Feel free to customize this file to suit your needs
*/
#import <Foundation/Foundation.
h>
#include <TargetConditionals.
h>
#if TARGET_OS_MAC
#import <AppKit/AppKit.
h>
#include "sdl_inc.
h"
#include "SDLMain.
h"
#include <sys/param.
h> /*
for MAXPATHLEN */
#include <unistd.
h>
/*
For some reason, 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 CPS
(docking
) or not */
#define SDL_USE_CPS
#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 id nsapp;
static NSString *getApplicationName
(void
)
{
const NSDictionary *dict;
NSString *appName =
0;
/* Determine the application name */
dict =
(const NSDictionary *
)CFBundleGetInfoDictionary
(CFBundleGetMainBundle
());
if (dict
)
appName =
[dict objectForKey: @"CFBundleName"
];
if (!
[appName
length])
appName =
[[NSProcessInfo processInfo
] processName
];
return appName;
}
@interface NSApplication
(SDLApplication
)
@
end
@implementation NSApplication
(SDLApplication
)
/* Invoked from the
Quit menu item */
-
(void
)terminateCall:
(id
)sender
{
/* Post a SDL_QUIT event */
SDL_Event event;
event.
type = SDL_QUIT;
SDL_PushEvent
(&event
);
}
@
end
@interface SDLMain
(NSObject
) <NSFileManagerDelegate>
@
end
/* The main
class of the application, the application's delegate */
@implementation SDLMain
(NSObject
)
/*
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,
1,
(UInt8 *
)parentdir, MAXPATHLEN
)) {
chdir
(parentdir
); /* chdir to the binary app's parent */
}
CFRelease
(url
);
CFRelease
(url2
);
}
}
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
(terminateCall:
) 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 */
nsapp =
[NSApplication 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
))
[NSApplication 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
];
}
/*
*
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
];
/* 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 =
(unichar *
)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;
}
CustomApplicationMain
(argc, argv
);
return 0;
}
#endif