Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
macx_init.m
/* Copyright (c) Mark J. Kilgard, 1994. */ |
/* Copyright (c) Dietmar Planitzer, 1998, 2002 - 2003 */ |
/* This program is freely distributable without licensing fees |
and is provided without guarantee or warrantee expressed or |
implied. This program is -not- in the public domain. */ |
#import <unistd.h> |
#import "macx_glut.h" |
#import "GLUTApplication.h" |
// HID device stuff |
#import "HID_Utilities_External.h" |
#import <IOKit/hid/IOHIDLib.h> |
#import <Kernel/IOKit/hidsystem/IOHIDUsageTables.h> |
/* GLUT globals */ |
int __glutArgc = 0; |
char ** __glutArgv = NULL; |
int __glutScreenHeight; |
int __glutScreenWidth; |
BOOL __glutIconic = kIconic; |
BOOL __glutDebug = kDebug; |
unsigned int __glutDisplayMode = (GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH); |
int __glutInitWidth = kInitWidth; |
int __glutInitHeight = kInitHeight; |
int __glutInitX = kInitX; |
int __glutInitY = kInitY; |
BOOL __glutDisableGrabbing = NO; |
BOOL __glutDisablePrinting = NO; |
NSTimeInterval __glutStartupTime = 0.0; |
int __glutDefaultColorSize = 16; // Default is ARGB1555. |
BOOL __glutUseInitWD = kUseInitWD; |
BOOL __glutInitWindowSizeCalled = NO; |
BOOL __glutInitWindowPositionCalled = NO; |
static void removeArgs(int *argcp, char **argv, int numToRemove); |
static int ReadInteger(char *string, char **NextString); |
static int XParseGeometry(char *string, int *x, int *y, unsigned int *width, unsigned int *height); |
/* |
* Bitmask returned by XParseGeometry(). Each bit tells if the corresponding |
* value (x, y, width, height) was found in the parsed string. |
*/ |
#define NoValue 0x0000 |
#define XValue 0x0001 |
#define YValue 0x0002 |
#define WidthValue 0x0004 |
#define HeightValue 0x0008 |
#define AllValues 0x000F |
#define XNegative 0x0010 |
#define YNegative 0x0020 |
/* GLUT's central atexit() handler */ |
static void __glutShutdown(void) |
{ |
// the following is needed to ensure auto-release pools work for releasing existing objects |
GLUTAPI_DECLARATIONS |
GLUTAPI_BEGIN |
__glutCloseDownGameMode(); |
__glutForgetInputDevices(); |
__glutResetKeyboard(); |
GLUTAPI_END |
} |
/* CENTRY */ |
void APIENTRY glutInit(int *argcp, char **argv) |
{ |
char * geometry = NULL; |
int i; |
int preserveSuppliedX = 0, preserveSuppliedY = 0; |
int preserveSuppliedWidth = 0, preserveSuppliedHeight = 0; |
GLUTAPI_DECLARATIONS |
if (NSApp != nil) { |
__glutWarning("glutInit being called a second time."); |
return; |
} |
atexit(__glutShutdown); // set up shutdown routine |
__glutSetForeground (); |
GLUTAPI_BEGIN |
/* Initialize our application instance */ |
NSApp = [GLUTApplication sharedApplication]; |
if (![NSBundle loadNibNamed:@"GLUT" owner:NSApp]) { |
__glutFatalError("glutInit can't open GLUT.nib"); // will exit |
} |
/* Jump through a couple hoops to preserve any user-specified initial |
* position or size because the call to __glutLoadPrefs will overwrite |
* them. Although the GLUT spec does not specifically require this, there |
* isn't any reason that we shouldn't support it, as this is the behavior |
* on most other platforms (and it makes sense to try and use the desired |
* size). Futhermore, note that doing this here still allows the user to |
* override the window size with a -geometry and also doesn't preclude a |
* forced window size if the glutInitWindow*() functions are called after |
* the glutInit() call. */ |
if ( __glutInitWindowPositionCalled == YES ) { |
preserveSuppliedX = __glutInitX; |
preserveSuppliedY = __glutInitY; |
} |
if ( __glutInitWindowSizeCalled == YES ) { |
preserveSuppliedWidth = __glutInitWidth; |
preserveSuppliedHeight = __glutInitHeight; |
} |
__glutLoadPrefs (); // ensure prefs are loaded from file |
/* Light the hoops on fire this time (restore program specified |
* parameters). */ |
if ( __glutInitWindowPositionCalled == YES ) { |
__glutInitX = preserveSuppliedX; |
__glutInitY = preserveSuppliedY; |
__glutInitWindowPositionCalled = NO; |
} |
if ( __glutInitWindowSizeCalled == YES ) { |
__glutInitWidth = preserveSuppliedWidth; |
__glutInitHeight = preserveSuppliedHeight; |
__glutInitWindowSizeCalled = NO; |
} |
/* Make private copy of command line arguments. */ |
__glutArgc = *argcp; |
__glutArgv = (char **) malloc(__glutArgc * sizeof(char *)); |
if(!__glutArgv) |
__glutFatalError("out of memory."); // will exit |
for(i = 0; i < __glutArgc; i++) { |
__glutArgv[i] = __glutStrdup(argv[i]); |
if(!__glutArgv[i]) |
__glutFatalError("out of memory."); // will exit |
} |
/* parse arguments for standard options */ |
for(i = 1; i < __glutArgc; i++) { |
if(!strcmp(__glutArgv[i], "-useMacOSCoords")) { |
__glutUseMacOSCoords = YES; |
removeArgs(argcp, &argv[1], 1); |
} else if(!strcmp(__glutArgv[i], "-useWorkingDir")) { |
__glutUseInitWD = YES; |
removeArgs(argcp, &argv[1], 1); |
} else if(!strcmp(__glutArgv[i], "-useExtendedDesktop")) { |
__glutUseExtendedDesktop = YES; |
removeArgs(argcp, &argv[1], 1); |
} else if(!strcmp(__glutArgv[i], "-display")) { |
__glutWarning("-display option invalid for MacOS X glut (X Windows only)."); |
if(__glutArgv[i + 1][0] != '-') |
i++; |
removeArgs(argcp, &argv[1], 2); |
} else if(!strcmp(__glutArgv[i], "-geometry")) { |
if(++i >= __glutArgc) |
__glutFatalError("follow -geometry option with geometry parameter."); |
geometry = __glutArgv[i]; |
removeArgs(argcp, &argv[1], 2); |
} else if(!strcmp(__glutArgv[i], "-direct")) { |
__glutWarning("-direct option invalid for MacOS X glut."); |
removeArgs(argcp, &argv[1], 1); |
} else if(!strcmp(__glutArgv[i], "-indirect")) { |
__glutWarning("-indirect option invalid for MacOS X glut."); |
removeArgs(argcp, &argv[1], 1); |
} else if(!strcmp(__glutArgv[i], "-iconic")) { |
__glutIconic = YES; |
removeArgs(argcp, &argv[1], 1); |
} else if(!strcmp(__glutArgv[i], "-gldebug")) { |
__glutDebug = GL_TRUE; |
removeArgs(argcp, &argv[1], 1); |
} else if(!strcmp(__glutArgv[i], "-sync")) { // X protocal syncing |
__glutWarning("-sync option invalid for MacOS X glut."); |
removeArgs(argcp, &argv[1], 1); |
} else if(!strcmp(__glutArgv[i], "-nograb")) { |
__glutDisableGrabbing = YES; |
removeArgs(argcp, &argv[1], 1); |
} else if(!strcmp(__glutArgv[i], "-noprint")) { |
__glutDisablePrinting = YES; |
removeArgs(argcp, &argv[1], 1); |
} else if(!strcmp(__glutArgv[i], "-menuIdleInterval")) { |
__glutIdleTimeInterval = strtod(__glutArgv[++i], NULL); |
if(__glutIdleTimeInterval == 0.0) { |
__glutIdleTimeInterval = GLUT_DEFAULT_IDLE_INTERVAL; |
} else if(__glutIdleTimeInterval < 0.001) { |
__glutIdleTimeInterval = 0.001; // 1000Hz |
} else if(__glutIdleTimeInterval > 1.0) { |
__glutIdleTimeInterval = 1.0; // 1Hz |
} |
removeArgs(argcp, &argv[1], 2); |
} else if(!strcmp(__glutArgv[i], "-fadeInterval")) { |
__glutGameModeFadeInterval = strtod(__glutArgv[++i], NULL); |
if(__glutGameModeFadeInterval == 0.0) { |
__glutGameModeFadeInterval = GLUT_DEFAULT_FADE_INTERVAL; |
} else if(__glutGameModeFadeInterval < 0.1) { |
__glutGameModeFadeInterval = 0.1; // 1/4 second |
} else if(__glutGameModeFadeInterval > 5.0) { |
__glutGameModeFadeInterval = 5.0; // 5 seconds |
} |
removeArgs(argcp, &argv[1], 2); |
} else if(!strcmp(__glutArgv[i], "-captureSingleDisplay")) { |
__glutCaptureAllDisplays = NO; |
} else if(!strcmp(__glutArgv[i], "-syncToVBL")) { |
__glutSyncToVBL = YES; |
} else if (!strncmp(__glutArgv[i], "-psn_", 5)) { |
// Some funky Finder thing. |
removeArgs(argcp, &argv[1], 1); |
} else { |
/* Stop processing args when you hit an unknown one. */ |
break; |
} |
} |
// Try and determine if this is an app with a full bundle structure that contains resources. |
// If so, chdir to that resource directory so normal fopen() and the like functions will work |
// without having to find the resource path explicitly. |
if (NO == __glutUseInitWD) { |
NSString * bundlePath = [[NSBundle mainBundle] bundlePath]; |
NSArray * bundlePathArray = [[NSFileManager defaultManager] directoryContentsAtPath:bundlePath]; |
if ((nil != bundlePathArray) && ([bundlePathArray containsObject:@"Contents"])) { |
NSString * contentsPath = [bundlePath stringByAppendingPathComponent:@"Contents"]; |
NSArray * contentsPathArray = [[NSFileManager defaultManager] directoryContentsAtPath:contentsPath]; |
if ((nil != contentsPath) && ([contentsPathArray containsObject:@"MacOS"]) && ([contentsPathArray containsObject:@"Resources"])) { |
NSString * finalResourcesPath = [contentsPath stringByAppendingPathComponent:@"Resources"]; |
NSArray * finalResourcesPathArray = [[NSFileManager defaultManager] directoryContentsAtPath:finalResourcesPath]; |
if ((nil != finalResourcesPath) && (0 < [finalResourcesPathArray count]) && ((1 < [finalResourcesPathArray count]) || (![[finalResourcesPathArray objectAtIndex:0] isEqual:@"English.lproj"]))) { |
chdir([[[NSBundle mainBundle] resourcePath] fileSystemRepresentation]); |
} |
} |
} |
} |
/* Force the creation of our input device list now. Doing this at a |
latter time screws up mouse down detection... */ |
if (__glutGetNumberOfMouseButtons() < 3) { /* if we have less than a 3 button mouse we should emulate one */ |
__glutEmulateMouseButtons = YES; |
} |
/* set default window management options */ |
if (NO == __glutUseExtendedDesktop) { |
NSScreen * screenWithMenubar = [[NSScreen screens] objectAtIndex: 0]; |
__glutScreenWidth = (int) [screenWithMenubar frame].size.width; |
__glutScreenHeight = (int) [screenWithMenubar frame].size.height; |
__glutDefaultColorSize = NSBitsPerPixelFromDepth([screenWithMenubar depth]); |
// Pick the closest depth to 16 or 32. |
if (__glutDefaultColorSize <= 16) |
__glutDefaultColorSize = 16; |
else |
__glutDefaultColorSize = 32; |
} else { // look at all screens |
NSEnumerator *enumerator = [[NSScreen screens] objectEnumerator]; |
NSScreen * screen = nil; |
float left = 0, right = 0, top = 0, bottom = 0, colorSize = 16; |
while (nil != (screen = (NSScreen *)[enumerator nextObject])) { |
if([screen frame].origin.x < left) |
left = [screen frame].origin.x; |
if([screen frame].origin.y < top) |
top = [screen frame].origin.y; |
if(([screen frame].origin.x + [screen frame].size.width) > right) |
right = ([screen frame].origin.x + [screen frame].size.width); |
if(([screen frame].origin.y + [screen frame].size.height) > bottom) |
bottom = ([screen frame].origin.y + [screen frame].size.height); |
if (NSBitsPerPixelFromDepth([screen depth]) > colorSize) // pick deepest depth ggs: this does not support deep displays currently |
colorSize = 32; |
} |
__glutScreenWidth = right - left; |
__glutScreenHeight = bottom - top; |
__glutDefaultColorSize = colorSize; |
} |
if(geometry) { |
int flags, x = 0, y = 0, width = 0, height = 0; |
flags = XParseGeometry(geometry, &x, &y, (unsigned int *) &width, (unsigned int *) &height); |
if(WidthValue & flags) { |
/* Careful because X does not allow zero or negative width windows */ |
if(width > 0) |
__glutInitWidth = width; |
} |
if(HeightValue & flags) { |
/* Careful because X does not allow zero or negative height windows */ |
if(height > 0) |
__glutInitHeight = height; |
} |
glutInitWindowSize(__glutInitWidth, __glutInitHeight); |
if(XValue & flags) { |
if (NO == __glutUseMacOSCoords) { |
if(XNegative & flags) |
x = __glutScreenWidth + x - __glutInitWidth; |
if(x >= 0) |
__glutInitX = x; |
} else |
__glutInitX = x; |
} |
if(YValue & flags) { |
if (NO == __glutUseMacOSCoords) { |
if(YNegative & flags) |
y = __glutScreenHeight + y - __glutInitHeight; |
if(y >= 0) |
__glutInitY = y; |
} else |
__glutInitY = y; |
} |
glutInitWindowPosition(__glutInitX, __glutInitY); |
} |
__glutStartupTime = [NSDate timeIntervalSinceReferenceDate]; |
/* check if GLUT_FPS env var is set */ |
{ |
const char *fps = getenv("GLUT_FPS"); |
if (fps) { |
sscanf(fps, "%d", (int *) &__glutFPS); |
if (__glutFPS <= 0) |
__glutFPS = 5000; /* 5000 milliseconds */ |
} |
} |
GLUTAPI_END |
} |
void __glutEngineInit (void) // inits glut engine based on current values |
{ |
// only thing that needs to be reset |
if (NO == __glutUseInitWD) { |
NSArray * fileArray = [[NSFileManager defaultManager] directoryContentsAtPath:[[NSBundle mainBundle] resourcePath]]; |
// if there is a directory and it has more than one item or the only item is NOT named Contents |
if ((nil != fileArray) && (0 < [fileArray count]) && ((1 < [fileArray count]) || (![[fileArray objectAtIndex:0] isEqual:@"Contents"]))) |
chdir([[[NSBundle mainBundle] resourcePath] fileSystemRepresentation]); |
} |
// reset screen width height and depth |
if (NO == __glutUseExtendedDesktop) { |
NSScreen * screenWithMenubar = [[NSScreen screens] objectAtIndex: 0]; |
__glutScreenWidth = (int) [screenWithMenubar frame].size.width; |
__glutScreenHeight = (int) [screenWithMenubar frame].size.height; |
__glutDefaultColorSize = NSBitsPerPixelFromDepth([screenWithMenubar depth]); |
// Pick the closest depth to 16 or 32. |
if (__glutDefaultColorSize <= 16) |
__glutDefaultColorSize = 16; |
else |
__glutDefaultColorSize = 32; |
} else { // look at all screens |
NSEnumerator *enumerator = [[NSScreen screens] objectEnumerator]; |
NSScreen * screen = nil; |
float left = 0, right = 0, top = 0, bottom = 0, colorSize = 16; |
while (nil != (screen = (NSScreen *)[enumerator nextObject])) { |
if([screen frame].origin.x < left) |
left = [screen frame].origin.x; |
if([screen frame].origin.y < top) |
top = [screen frame].origin.y; |
if(([screen frame].origin.x + [screen frame].size.width) > right) |
right = ([screen frame].origin.x + [screen frame].size.width); |
if(([screen frame].origin.y + [screen frame].size.height) > bottom) |
bottom = ([screen frame].origin.y + [screen frame].size.height); |
if (NSBitsPerPixelFromDepth([screen depth]) > colorSize) // pick deepest depth ggs: this does not support deep displays currently |
colorSize = 32; |
} |
__glutInitWindowSizeCalled = true; |
__glutScreenWidth = right - left; |
__glutScreenHeight = bottom - top; |
__glutDefaultColorSize = colorSize; |
} |
} |
void APIENTRY glutInitWindowPosition(int x, int y) |
{ |
__glutInitX = x; |
__glutInitY = y; |
__glutInitWindowPositionCalled = true; |
} |
void APIENTRY glutInitWindowSize(int width, int height) |
{ |
__glutInitWidth = width; |
__glutInitHeight = height; |
if(width <= 0) |
__glutInitWidth = 300; |
if(height <= 0) |
__glutInitHeight = 300; |
__glutInitWindowSizeCalled = true; |
} |
void APIENTRY glutInitDisplayMode(unsigned int mask) |
{ |
__glutDisplayMode = mask; |
} |
/* ENDCENTRY */ |
static void removeArgs(int *argcp, char **argv, int numToRemove) |
{ |
int i, j; |
for(i = 0, j = numToRemove; argv[j]; i++, j++) |
argv[i] = argv[j]; |
argv[i] = NULL; |
*argcp -= numToRemove; |
} |
/* the following function was lifted from the X sources as indicated. */ |
/* Copyright Massachusetts Institute of Technology 1985, 1986, 1987 */ |
/* $XConsortium: XParseGeom.c,v 11.18 91/02/21 17:23:05 rws Exp $ */ |
/* |
Permission to use, copy, modify, distribute, and sell this software and its |
documentation for any purpose is hereby granted without fee, provided that |
the above copyright notice appear in all copies and that both that |
copyright notice and this permission notice appear in supporting |
documentation, and that the name of M.I.T. not be used in advertising or |
publicity pertaining to distribution of the software without specific, |
written prior permission. M.I.T. makes no representations about the |
suitability of this software for any purpose. It is provided "as is" |
without express or implied warranty. |
*/ |
/* |
* XParseGeometry parses strings of the form |
* "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where |
* width, height, xoffset, and yoffset are unsigned integers. |
* Example: "=80x24+300-49" |
* The equal sign is optional. |
* It returns a bitmask that indicates which of the four values |
* were actually found in the string. For each value found, |
* the corresponding argument is updated; for each value |
* not found, the corresponding argument is left unchanged. |
*/ |
static int ReadInteger(char *string, char **NextString) |
{ |
register int Result = 0; |
int Sign = 1; |
if (*string == '+') |
string++; |
else if (*string == '-') |
{ |
string++; |
Sign = -1; |
} |
for (; (*string >= '0') && (*string <= '9'); string++) |
{ |
Result = (Result * 10) + (*string - '0'); |
} |
*NextString = string; |
if (Sign >= 0) |
return (Result); |
else |
return (-Result); |
} |
static int XParseGeometry(char *string, int *x, int *y, unsigned int *width, unsigned int *height) |
{ |
int mask = NoValue; |
register char * strind; |
unsigned int tempWidth = 0, tempHeight = 0; |
int tempX = 0, tempY = 0; |
char * nextCharacter; |
if ( (string == NULL) || (*string == '\0')) return(mask); |
if (*string == '=') |
string++; /* ignore possible '=' at beg of geometry spec */ |
strind = (char *)string; |
if (*strind != '+' && *strind != '-' && *strind != 'x') { |
tempWidth = ReadInteger(strind, &nextCharacter); |
if (strind == nextCharacter) |
return (0); |
strind = nextCharacter; |
mask |= WidthValue; |
} |
if (*strind == 'x' || *strind == 'X') { |
strind++; |
tempHeight = ReadInteger(strind, &nextCharacter); |
if (strind == nextCharacter) |
return (0); |
strind = nextCharacter; |
mask |= HeightValue; |
} |
if ((*strind == '+') || (*strind == '-')) { |
if (*strind == '-') { |
strind++; |
tempX = -ReadInteger(strind, &nextCharacter); |
if (strind == nextCharacter) |
return (0); |
strind = nextCharacter; |
mask |= XNegative; |
} |
else |
{ strind++; |
tempX = ReadInteger(strind, &nextCharacter); |
if (strind == nextCharacter) |
return(0); |
strind = nextCharacter; |
} |
mask |= XValue; |
if ((*strind == '+') || (*strind == '-')) { |
if (*strind == '-') { |
strind++; |
tempY = -ReadInteger(strind, &nextCharacter); |
if (strind == nextCharacter) |
return(0); |
strind = nextCharacter; |
mask |= YNegative; |
} |
else |
{ |
strind++; |
tempY = ReadInteger(strind, &nextCharacter); |
if (strind == nextCharacter) |
return(0); |
strind = nextCharacter; |
} |
mask |= YValue; |
} |
} |
/* If strind isn't at the end of the string the it's an invalid |
geometry specification. */ |
if (*strind != '\0') return (0); |
if (mask & XValue) |
*x = tempX; |
if (mask & YValue) |
*y = tempY; |
if (mask & WidthValue) |
*width = tempWidth; |
if (mask & HeightValue) |
*height = tempHeight; |
return (mask); |
} |
Copyright © 2008 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2008-02-08