2011-11-22 21:28:15 +00:00
/*
===========================================================================
Doom 3 GPL Source Code
2011-12-06 18:20:15 +00:00
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
2011-11-22 21:28:15 +00:00
2011-12-06 16:14:59 +00:00
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
2011-11-22 21:28:15 +00:00
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
// -*- mode: objc -*-
#import <unistd.h>
#import <Foundation/Foundation.h>
#import <Carbon/Carbon.h>
#import <AppKit/AppKit.h>
#import <OpenGL/gl.h>
#import <fenv.h>
#import <ucontext.h>
#import <mach/thread_status.h>
2011-12-20 15:12:17 +00:00
#import <SDL_main.h>
2011-12-16 22:28:29 +00:00
#import "sys/platform.h"
#import "idlib/Str.h"
#import "framework/Licensee.h"
#import "framework/Common.h"
#import "sys/osx/macosx_common.h"
#import "sys/osx/macosx_local.h"
#import "sys/osx/macosx_sys.h"
#import "DOOMController.h"
2011-11-22 21:28:15 +00:00
#define MAX_KEYS 256
static idStr savepath;
extern bool key_overstrikeMode;
2011-12-06 18:20:15 +00:00
#define TEST_FPU_EXCEPTIONS \
2011-11-22 21:28:15 +00:00
FPU_EXCEPTION_INVALID_OPERATION | \
FPU_EXCEPTION_DENORMALIZED_OPERAND | \
FPU_EXCEPTION_DIVIDE_BY_ZERO | \
/* FPU_EXCEPTION_NUMERIC_OVERFLOW | */ \
/* FPU_EXCEPTION_NUMERIC_UNDERFLOW | */ \
/* FPU_EXCEPTION_INEXACT_RESULT | */ \
0
#define kRegKey @"RegCode"
static const ControlID kRegCode1EditText = { 'RegC', 1 };
struct RegCodeInfo
{
char prefRegCode1[256];
2011-12-06 18:20:15 +00:00
bool okPressed;
2011-11-22 21:28:15 +00:00
WindowRef window;
ControlRef regCode1EditText;
};
static OSErr DoRegCodeDialog( char* ioRegCode1 );
@interface DOOMController (Private)
- (void)quakeMain;
- (BOOL)checkRegCodes;
- (BOOL)checkOS;
@end
@implementation DOOMController
/*
+ (void)initialize;
{
2011-12-06 18:20:15 +00:00
static bool initialized = NO;
2011-11-22 21:28:15 +00:00
2011-12-06 18:20:15 +00:00
[super initialize];
if ( initialized ) {
return;
2011-11-22 21:28:15 +00:00
}
2011-12-06 18:20:15 +00:00
initialized = YES;
2011-11-22 21:28:15 +00:00
}
*/
#define MAX_ARGC 1024
- (void)applicationDidFinishLaunching:(NSNotification *)notification;
{
2011-12-06 18:20:15 +00:00
NS_DURING {
2011-11-22 21:28:15 +00:00
NSAssert(sizeof(bool) == 1, @"sizeof(bool) should equal 1 byte");
2011-12-06 18:20:15 +00:00
[self quakeMain];
} NS_HANDLER {
Sys_Error( (const char *)[ [ localException reason ] cString ] );
} NS_ENDHANDLER;
Sys_Quit();
2011-11-22 21:28:15 +00:00
}
- (void)applicationWillHide:(NSNotification *)notification;
{
2011-12-06 18:20:15 +00:00
Sys_ShutdownInput();
2011-11-22 21:28:15 +00:00
}
- (void)applicationWillUnhide:(NSNotification *)notification;
{
2011-12-06 18:20:15 +00:00
Sys_InitInput();
2011-11-22 21:28:15 +00:00
}
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
common->Quit();
return NSTerminateLater; // we never reach this
}
#if 0
// Actions
- (IBAction)paste:(id)sender;
{
2011-12-06 18:20:15 +00:00
int shiftWasDown, insertWasDown;
unsigned int currentTime;
currentTime = Sys_Milliseconds();
// Save the original keyboard state
shiftWasDown = keys[K_SHIFT].down;
insertWasDown = keys[K_INS].down;
// Fake a Shift-Insert keyboard event
keys[K_SHIFT].down = true;
Posix_QueEvent(currentTime, SE_KEY, K_INS, true, 0, NULL);
Posix_QueEvent(currentTime, SE_KEY, K_INS, false, 0, NULL);
// Restore the original keyboard state
keys[K_SHIFT].down = shiftWasDown;
keys[K_INS].down = insertWasDown;
2011-11-22 21:28:15 +00:00
}
extern void CL_Quit_f(void);
//extern void SetProgramPath(const char *path);
- (IBAction)requestTerminate:(id)sender;
{
2011-12-06 18:20:15 +00:00
//osxQuit();
2011-11-22 21:28:15 +00:00
common->Quit();
}
- (void)showBanner;
{
2011-12-06 18:20:15 +00:00
static bool hasShownBanner = NO;
2011-11-22 21:28:15 +00:00
2011-12-06 18:20:15 +00:00
if (!hasShownBanner) {
//cvar_t *showBanner;
2011-11-22 21:28:15 +00:00
2011-12-06 18:20:15 +00:00
hasShownBanner = YES;
//showBanner = Cvar_Get("cl_showBanner", "1", 0);
//if ( showBanner->integer != 0 ) {
2011-11-22 21:28:15 +00:00
if ( true ) {
2011-12-06 18:20:15 +00:00
NSPanel *splashPanel;
NSImage *bannerImage;
NSRect bannerRect;
NSImageView *bannerImageView;
bannerImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:@"banner.jpg"]];
bannerRect = NSMakeRect(0.0, 0.0, [bannerImage size].width, [bannerImage size].height);
splashPanel = [[NSPanel alloc] initWithContentRect:bannerRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO];
bannerImageView = [[NSImageView alloc] initWithFrame:bannerRect];
[bannerImageView setImage:bannerImage];
[splashPanel setContentView:bannerImageView];
[bannerImageView release];
[splashPanel center];
[splashPanel setHasShadow:YES];
[splashPanel orderFront: nil];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.5]];
[splashPanel close];
[bannerImage release];
}
}
2011-11-22 21:28:15 +00:00
}
// Services
- (void)connectToServer:(NSPasteboard *)pasteboard userData:(NSString *)data error:(NSString **)error;
{
2011-12-06 18:20:15 +00:00
NSArray *pasteboardTypes;
pasteboardTypes = [pasteboard types];
if ([pasteboardTypes containsObject:NSStringPboardType]) {
NSString *requestedServer;
requestedServer = [pasteboard stringForType:NSStringPboardType];
if (requestedServer) {
Cbuf_AddText( va( "connect %s\n", [requestedServer cString]));
return;
}
}
*error = @"Unable to connect to server: could not find string on pasteboard";
2011-11-22 21:28:15 +00:00
}
- (void)performCommand:(NSPasteboard *)pasteboard userData:(NSString *)data error:(NSString **)error;
{
2011-12-06 18:20:15 +00:00
NSArray *pasteboardTypes;
pasteboardTypes = [pasteboard types];
if ([pasteboardTypes containsObject:NSStringPboardType]) {
NSString *requestedCommand;
requestedCommand = [pasteboard stringForType:NSStringPboardType];
if (requestedCommand) {
Cbuf_AddText(va("%s\n", [requestedCommand cString]));
return;
}
}
*error = @"Unable to perform command: could not find string on pasteboard";
2011-11-22 21:28:15 +00:00
}
#endif // commented out all the banners and actions
@end
@implementation DOOMController (Private)
- (void)quakeMain
{
2011-12-06 18:20:15 +00:00
NSAutoreleasePool *pool;
int argc = 0;
2011-12-20 15:12:17 +00:00
char *argv[MAX_ARGC];
2011-12-06 18:20:15 +00:00
NSProcessInfo *processInfo;
NSArray *arguments;
unsigned int argumentIndex, argumentCount;
//const char *cddir;
//NSFileManager *defaultManager;
//bool tryAgain;
pool = [[NSAutoreleasePool alloc] init];
[NSApp setServicesProvider:self];
processInfo = [NSProcessInfo processInfo];
arguments = [processInfo arguments];
argumentCount = [arguments count];
for (argumentIndex = 0; argumentIndex < argumentCount; argumentIndex++) {
argv[argc++] = strdup([[arguments objectAtIndex:argumentIndex] cString]);
}
if (![[NSFileManager defaultManager] changeCurrentDirectoryPath:[[NSBundle mainBundle] resourcePath]]) {
Sys_Error("Could not access application resources");
}
//cddir = macosx_scanForLibraryDirectory();
/*
do {
tryAgain = NO;
defaultManager = [NSFileManager defaultManager];
if (![defaultManager fileExistsAtPath:@"./base/default.cfg"] && (!cddir || *cddir == '\0' || ![defaultManager fileExistsAtPath:[NSString stringWithFormat:@"%s/baseq3/pak0.pk3", cddir]])) {
NSString *message;
if (!cddir || *cddir == '\0') {
message = [NSString stringWithFormat:@"Could not find DOOM levels."];
} else if (![defaultManager fileExistsAtPath:[NSString stringWithFormat:@"%s", cddir]]) {
message = [NSString stringWithFormat:@"Could not find DOOM levels: '%s' does not exist.", cddir];
} else {
message = [NSString stringWithFormat:@"Could not find DOOM levels: '%s' is not a complete DOOM installation.", cddir];
}
switch (NSRunAlertPanel(@"DOOM", @"%@", @"Quit", @"Find...", nil, message)) {
case NSAlertDefaultReturn:
default:
Sys_Quit();
break;
case NSAlertAlternateReturn:
tryAgain = YES;
break;
}
if (tryAgain) {
NSOpenPanel *openPanel;
int result;
openPanel = [NSOpenPanel openPanel];
[openPanel setAllowsMultipleSelection:NO];
[openPanel setCanChooseDirectories:YES];
[openPanel setCanChooseFiles:NO];
result = [openPanel runModalForDirectory:nil file:nil];
if (result == NSOKButton) {
NSArray *filenames;
filenames = [openPanel filenames];
if ([filenames count] == 1) {
NSString *cdPath;
cdPath = [filenames objectAtIndex:0];
[[NSUserDefaults standardUserDefaults] setObject:cdPath forKey:@"CDPath"];
cddir = strdup([cdPath cString]);
}
}
}
}
} while (tryAgain);
*/
2011-11-22 21:28:15 +00:00
/*
2011-12-06 18:20:15 +00:00
if (cddir && *cddir != '\0') {
SetProgramPath([[[NSString stringWithCString:cddir] stringByAppendingPathComponent:@"/x"] cString]);
}
2011-11-22 21:28:15 +00:00
*/
//Sys_FPU_EnableExceptions( TEST_FPU_EXCEPTIONS );
Posix_EarlyInit( );
#ifndef _DEBUG
if ( [self checkOS] == FALSE) {
common->Quit();
}
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
if ( [self checkDVD] == FALSE) {
common->Quit();
}
#endif
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// need strncmp, can't use idlib before init
#undef strncmp
// Finder passes the process serial number as only argument after the program path
// nuke it if we see it
if ( argc > 1 && strncmp( argv[ 1 ], "-psn", 4 ) ) {
2011-12-20 15:12:17 +00:00
common->Init( argc-1, &argv[1] );
2011-11-22 21:28:15 +00:00
} else {
2011-12-20 15:12:17 +00:00
common->Init( 0, NULL );
2011-11-22 21:28:15 +00:00
}
Posix_LateInit( );
2011-12-06 18:20:15 +00:00
[NSApp activateIgnoringOtherApps:YES];
2011-11-22 21:28:15 +00:00
2011-12-06 18:20:15 +00:00
while (1) {
2011-11-22 21:28:15 +00:00
#ifdef OMNI_TIMER
2011-12-06 18:20:15 +00:00
OTPeriodicTimerReset();
OTNodeStart(RootNode);
2011-11-22 21:28:15 +00:00
#endif
// maintain exceptions in case system calls are turning them off (is that needed)
//Sys_FPU_EnableExceptions( TEST_FPU_EXCEPTIONS );
common->Frame();
2011-12-06 18:20:15 +00:00
// We should think about doing this less frequently than every frame
[pool release];
pool = [[NSAutoreleasePool alloc] init];
2011-11-22 21:28:15 +00:00
#ifdef OMNI_TIMER
2011-12-06 18:20:15 +00:00
OTNodeStop(RootNode);
2011-11-22 21:28:15 +00:00
#endif
2011-12-06 18:20:15 +00:00
}
2011-11-22 21:28:15 +00:00
2011-12-06 18:20:15 +00:00
[pool release];
2011-11-22 21:28:15 +00:00
}
- (BOOL)checkRegCodes
{
BOOL retval;
NSString *cdKey;
NSUserDefaults *userDefaults;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
userDefaults = [NSUserDefaults standardUserDefaults];
cdKey = [userDefaults stringForKey:kRegKey];
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
retval = TRUE;
if ( cdKey == nil || [cdKey length] == 0 ) {
char regCode[256];
if ( DoRegCodeDialog( regCode ) != noErr ) {
retval = FALSE;
}
else {
[userDefaults setObject:[NSString stringWithCString: regCode] forKey:kRegKey];
[userDefaults synchronize];
}
}
return retval;
}
- (BOOL)checkOS
{
OSErr err;
long gestaltOSVersion;
err = Gestalt(gestaltSystemVersion, &gestaltOSVersion);
if ( err || gestaltOSVersion < 0x1038 ) {
NSBundle *thisBundle = [ NSBundle mainBundle ];
NSString *messsage = [ thisBundle localizedStringForKey:@"InsufficientOS" value:@"No translation" table:nil ];
NSRunAlertPanel(@GAME_NAME, messsage, nil, nil, nil);
return FALSE;
}
return TRUE;
}
- (BOOL)checkDVD
{
return TRUE;
}
@end
/*
==============
Sys_EXEPath
==============
*/
const char *Sys_EXEPath( void ) {
static char exepath[ 1024 ];
strncpy( exepath, [ [ [ NSBundle mainBundle ] bundlePath ] cString ], 1024 );
return exepath;
}
/*
==========
Sys_DefaultSavePath
==========
*/
const char *Sys_DefaultSavePath(void) {
#if defined( ID_DEMO_BUILD )
sprintf( savepath, "%s/Library/Application Support/Doom 3 Demo", [NSHomeDirectory() cString] );
#else
sprintf( savepath, "%s/Library/Application Support/Doom 3", [NSHomeDirectory() cString] );
#endif
return savepath.c_str();
}
/*
==========
Sys_DefaultBasePath
==========
*/
const char *Sys_DefaultBasePath(void) {
static char basepath[ 1024 ];
strncpy( basepath, [ [ [ NSBundle mainBundle ] bundlePath ] cString ], 1024 );
char *snap = strrchr( basepath, '/' );
if ( snap ) {
*snap = '\0';
}
return basepath;
}
/*
===============
Sys_Shutdown
===============
*/
void Sys_Shutdown( void ) {
savepath.Clear();
Posix_Shutdown();
}
/*
===============
Sys_FPU_EnableExceptions
http://developer.apple.com/documentation/mac/PPCNumerics/PPCNumerics-154.html
http://developer.apple.com/documentation/Performance/Conceptual/Mac_OSX_Numerics/Mac_OSX_Numerics.pdf
===============
*/
#define fegetenvd(x) asm volatile( "mffs %0" : "=f" (x) );
2011-12-06 18:20:15 +00:00
#define fesetenvd(x) asm volatile( "mtfsf 255,%0" : : "f" (x) );
2011-11-22 21:28:15 +00:00
enum {
FE_ENABLE_INEXACT = 0x8,
FE_ENABLE_DIVBYZERO = 0x10,
FE_ENABLE_UNDERFLOW = 0x20,
FE_ENABLE_OVERFLOW = 0x40,
FE_ENABLE_INVALID = 0x80,
FE_ENABLE_ALL_EXCEPT = 0xF8
};
typedef union {
struct {
unsigned long hi;
unsigned long lo;
} i;
double d;
} hexdouble;
static int exception_mask = 0;
void Sys_FPU_EnableExceptions( int exceptions ) {
#if 0
if ( exceptions & ( FPU_EXCEPTION_INVALID_OPERATION | FPU_EXCEPTION_DENORMALIZED_OPERAND ) ) {
// clear the flag before enabling the exception
asm( "mtfsb0 2" );
asm( "mtfsb0 7" );
asm( "mtfsb0 8" );
asm( "mtfsb0 9" );
asm( "mtfsb0 10" );
asm( "mtfsb0 11" );
asm( "mtfsb0 12" );
asm( "mtfsb0 21" );
asm( "mtfsb0 22" );
asm( "mtfsb0 23" );
// enable
asm( "mtfsb1 24" );
} else {
asm( "mtfsb0 24" );
}
if ( exceptions & FPU_EXCEPTION_DIVIDE_BY_ZERO ) {
asm( "mtfsb0 5" );
asm( "mtfsb1 27" );
} else {
asm( "mtfsb0 27" );
}
if ( exceptions & FPU_EXCEPTION_NUMERIC_OVERFLOW ) {
asm( "mtfsb0 3" );
asm( "mtfsb1 25" );
} else {
asm( "mtfsb0 25" );
}
if ( exceptions & FPU_EXCEPTION_NUMERIC_UNDERFLOW ) {
asm( "mtfsb0 4" );
asm( "mtfsb1 26" );
} else {
asm( "mtfsb0 26" );
}
if ( exceptions & FPU_EXCEPTION_INEXACT_RESULT ) {
asm( "mtfsb0 6" );
asm( "mtfsb0 13" );
asm( "mtfsb0 14" );
asm( "mtfsb1 28" );
} else {
asm( "mtfsb0 28" );
}
#elif defined(__ppc__)
hexdouble t;
exception_mask = 0;
if ( exceptions & ( FPU_EXCEPTION_INVALID_OPERATION | FPU_EXCEPTION_DENORMALIZED_OPERAND ) ) {
exception_mask |= FE_ENABLE_INVALID;
}
if ( exceptions & FPU_EXCEPTION_DIVIDE_BY_ZERO ) {
exception_mask |= FE_ENABLE_DIVBYZERO;
}
if ( exceptions & FPU_EXCEPTION_NUMERIC_OVERFLOW ) {
exception_mask |= FE_ENABLE_OVERFLOW;
}
if ( exceptions & FPU_EXCEPTION_NUMERIC_UNDERFLOW ) {
exception_mask |= FE_ENABLE_UNDERFLOW;
}
if ( exceptions & FPU_EXCEPTION_INEXACT_RESULT ) {
exception_mask |= FE_ENABLE_INVALID;
}
Sys_Printf( "Sys_FPUEnableExceptions: 0x%x\n", exception_mask );
// clear the exception flags
feclearexcept( FE_ALL_EXCEPT );
// set the enable flags on the exceptions we want
fegetenvd( t.d );
t.i.lo &= ~FE_ENABLE_ALL_EXCEPT;
t.i.lo |= exception_mask;
fesetenvd( t.d );
Sys_Printf( "done\n" );
#endif
}
/*
===============
Sys_FPE_handler
===============
*/
void Sys_FPE_handler( int signum, siginfo_t *info, void *context ) {
#if defined(__ppc__)
int ret;
ppc_float_state_t *fs;
ppc_thread_state_t *ss;
fs = &( (struct ucontext *)context )->uc_mcontext->fs;
ss = &( (struct ucontext *)context )->uc_mcontext->ss;
Sys_Printf( "FPE at 0x%x:\n", info->si_addr );
ret = fetestexcept( FE_ALL_EXCEPT );
if ( ret & FE_INEXACT ) {
Sys_Printf( "FE_INEXACT " );
}
if ( ret & FE_DIVBYZERO ) {
Sys_Printf( "FE_DIVBYZERO " );
}
if ( ret & FE_UNDERFLOW ) {
Sys_Printf( "FE_UNDERFLOW " );
}
if ( ret & FE_OVERFLOW ) {
Sys_Printf( "FE_OVERFLOW " );
}
if ( ret & FE_INVALID ) {
Sys_Printf( "FE_INVALID " );
}
Sys_Printf( "\n" );
// clear the exception flags
feclearexcept( FE_ALL_EXCEPT );
// re-arm
fs->fpscr &= exception_mask;
ss->srr0 += 4;
#endif
}
/*
================
Sys_GetSystemRam
returns in megabytes
================
*/
int Sys_GetSystemRam( void ) {
long ramSize;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
if ( Gestalt( gestaltPhysicalRAMSize, &ramSize ) == noErr ) {
return ramSize / (1024*1024);
}
else
return 1024;
}
/*
================
Sys_GetVideoRam
returns in megabytes
================
*/
int Sys_GetVideoRam( void ) {
unsigned int i;
CFTypeRef typeCode;
long vramStorage = 64;
const short MAXDISPLAYS = 8;
CGDisplayCount displayCount;
io_service_t dspPorts[MAXDISPLAYS];
CGDirectDisplayID displays[MAXDISPLAYS];
CGGetOnlineDisplayList( MAXDISPLAYS, displays, &displayCount );
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
for ( i = 0; i < displayCount; i++ ) {
if ( Sys_DisplayToUse() == displays[i] ) {
dspPorts[i] = CGDisplayIOServicePort(displays[i]);
typeCode = IORegistryEntryCreateCFProperty( dspPorts[i], CFSTR("IOFBMemorySize"), kCFAllocatorDefault, kNilOptions );
if( typeCode && CFGetTypeID( typeCode ) == CFNumberGetTypeID() ) {
CFNumberGetValue( ( CFNumberRef )typeCode, kCFNumberSInt32Type, &vramStorage );
vramStorage /= (1024*1024);
}
}
}
return vramStorage;
}
bool OSX_GetCPUIdentification( int& cpuId, bool& oldArchitecture )
{
long cpu;
Gestalt(gestaltNativeCPUtype, &cpu);
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
cpuId = cpu;
oldArchitecture = cpuId < gestaltCPU970;
return true;
}
void OSX_GetVideoCard( int& outVendorId, int& outDeviceId )
{
2011-12-06 18:20:15 +00:00
kern_return_t err;
mach_port_t masterPort;
io_iterator_t itThis;
io_service_t service;
2011-11-22 21:28:15 +00:00
outVendorId = -1;
outDeviceId = -1;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// Get a mach port for us and check for errors
2011-12-06 18:20:15 +00:00
err = IOMasterPort(MACH_PORT_NULL, &masterPort);
if(err)
2011-11-22 21:28:15 +00:00
return;
2011-12-06 18:20:15 +00:00
// Grab all the PCI devices out of the registry
err = IOServiceGetMatchingServices(masterPort, IOServiceMatching("IOPCIDevice"), &itThis);
if(err)
2011-11-22 21:28:15 +00:00
return;
2011-12-06 18:20:15 +00:00
// Yank everything out of the iterator
2011-11-22 21:28:15 +00:00
// We could walk through all devices and try to determine the best card. But for now,
// we'll just look at the first card.
2011-12-06 18:20:15 +00:00
while(1)
{
2011-11-22 21:28:15 +00:00
service = IOIteratorNext(itThis);
io_name_t dName;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// Make sure we have a valid service
if(service)
{
// Get the classcode so we know what we're looking at
CFDataRef classCode = (CFDataRef)IORegistryEntryCreateCFProperty(service,CFSTR("class-code"),kCFAllocatorDefault,0);
2011-12-06 18:20:15 +00:00
// Only accept devices that are
2011-11-22 21:28:15 +00:00
// PCI Spec - 0x00030000 is a display device
if((*(UInt32*)CFDataGetBytePtr(classCode) & 0x00ff0000) == 0x00030000)
{
// Get the name of the service (hw)
IORegistryEntryGetName(service, dName);
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
CFDataRef vendorID, deviceID;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// Get the information for the device we've selected from the list
vendorID = (CFDataRef)IORegistryEntryCreateCFProperty(service, CFSTR("vendor-id"),kCFAllocatorDefault,0);
deviceID = (CFDataRef)IORegistryEntryCreateCFProperty(service, CFSTR("device-id"),kCFAllocatorDefault,0);
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
outVendorId = *((long*)CFDataGetBytePtr(vendorID));
outDeviceId = *((long*)CFDataGetBytePtr(deviceID));
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
CFRelease(vendorID);
CFRelease(deviceID);
}
CFRelease(classCode);
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// Stop after finding the first device
if (outVendorId != -1)
break;
}
else
break;
}
}
/*
===============
main
===============
*/
2011-12-20 15:12:17 +00:00
int main( int argc, char *argv[] ) {
return NSApplicationMain( argc, (const char **)argv );
2011-11-22 21:28:15 +00:00
}
bool FormatRegCode(const char* inRegCode, char* outRegCode)
2011-12-06 18:20:15 +00:00
{
2011-11-22 21:28:15 +00:00
// Clean up the reg code. Remove spaces. Accept only numbers/letters.
char* dst = outRegCode;
const char* src = inRegCode;
while (*src)
{
if (isalnum(*src))
*dst++ = *src;
else if (*src != ' ')
return false;
src++;
}
*dst = 0;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// Reg codes are 18 characters in length
return strlen(outRegCode) == 18;
}
/*
===============
RegCodeHandler
===============
*/
2011-12-13 15:03:27 +00:00
static pascal OSStatus RegCodeHandler( EventHandlerCallRef, EventRef inEvent, void* inUserData )
2011-11-22 21:28:15 +00:00
{
#if 1
// FIXME: the CD key API has changed for startup check support and expansion pack key support
return noErr;
2011-12-06 18:20:15 +00:00
#else
2011-11-22 21:28:15 +00:00
HICommand cmd;
OSStatus result = eventNotHandledErr;
RegCodeInfo* regCodeInfo = (RegCodeInfo*)inUserData;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
GetEventParameter( inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof( cmd ), NULL, &cmd );
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
switch ( cmd.commandID ) {
case kHICommandOK:
bool fValid;
Size actualSize;
char cntrl[256];
char doomKey[256];
char strippedKey[256];
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
fValid = false;
strippedKey[0] = doomKey[0] = NULL;
GetControlData ( regCodeInfo->regCode1EditText, kControlEntireControl, kControlEditTextTextTag, 256, cntrl, &actualSize );
cntrl[actualSize] = NULL;
if ( FormatRegCode( cntrl, strippedKey ) ) {
strncat( doomKey, strippedKey, 16 );
strcat( doomKey, " " );
strncat( doomKey, strippedKey + 16, 2 );
fValid = session->CheckKey( doomKey );
}
if ( fValid ) {
strcpy( regCodeInfo->prefRegCode1, doomKey );
session->SetCDKey( doomKey );
}
else {
2011-12-06 18:20:15 +00:00
unsigned char theError[512];
2011-11-22 21:28:15 +00:00
unsigned char theExplanation[512];
CFStringRef theErrorStr = CFCopyLocalizedString( CFSTR("DVD_KEY_ERROR"), "" );
CFStringRef theExplanationStr = CFCopyLocalizedString( CFSTR("DVD_KEY_EXPLANATION"), "" );
c2pstrcpy( theError, CFStringGetCStringPtr( theErrorStr, kCFStringEncodingMacRoman ) );
c2pstrcpy( theExplanation, CFStringGetCStringPtr( theExplanationStr, kCFStringEncodingMacRoman ) );
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
StandardAlert(kAlertStopAlert, theError, theExplanation, NULL, NULL);
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
// Highlight the invalid reg code
ClearKeyboardFocus(regCodeInfo->window);
SetKeyboardFocus( regCodeInfo->window, regCodeInfo->regCode1EditText, kControlEditTextPart );
ControlEditTextSelectionRec sel = {0, 32000};
SetControlData (regCodeInfo->regCode1EditText, kControlEntireControl, kControlEditTextSelectionTag, sizeof(sel), &sel);
2011-12-06 18:20:15 +00:00
break;
2011-11-22 21:28:15 +00:00
}
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
regCodeInfo->okPressed = true;
QuitAppModalLoopForWindow( regCodeInfo->window );
result = noErr;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
break;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
case kHICommandCancel:
regCodeInfo->okPressed = false;
QuitAppModalLoopForWindow( regCodeInfo->window );
result = noErr;
break;
2011-12-06 18:20:15 +00:00
}
2011-11-22 21:28:15 +00:00
return result;
#endif
}
/*
===============
DoRegCodeDialog
===============
*/
static OSErr DoRegCodeDialog( char* ioRegCode1 )
{
OSErr err;
RegCodeInfo regCodeInfo;
memset(®CodeInfo, 0, sizeof(regCodeInfo));
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
IBNibRef aslNib;
CFBundleRef theBundle = CFBundleGetMainBundle();
err = CreateNibReferenceWithCFBundle( theBundle, CFSTR("ASLCore"), &aslNib );
err = ::CreateWindowFromNib( aslNib, CFSTR("Reg Code Sheet"), ®CodeInfo.window );
if (err != noErr)
return err;
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
GetControlByID( regCodeInfo.window, &kRegCode1EditText, ®CodeInfo.regCode1EditText );
assert( regCodeInfo.regCode1EditText );
SetKeyboardFocus( regCodeInfo.window, regCodeInfo.regCode1EditText, kControlEditTextPart );
ControlEditTextSelectionRec sel = {0, 32000};
SetControlData (regCodeInfo.regCode1EditText, kControlEntireControl, kControlEditTextSelectionTag, sizeof(sel), &sel);
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
EventTypeSpec cmdEvent = { kEventClassCommand, kEventCommandProcess };
EventHandlerUPP handler = NewEventHandlerUPP( RegCodeHandler );
InstallWindowEventHandler( regCodeInfo.window, handler, 1, &cmdEvent, ®CodeInfo, NULL );
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
RepositionWindow( regCodeInfo.window, NULL, kWindowAlertPositionOnMainScreen );
ShowWindow( regCodeInfo.window );
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
RunAppModalLoopForWindow( regCodeInfo.window );
2011-12-06 18:20:15 +00:00
2011-11-22 21:28:15 +00:00
DisposeWindow( regCodeInfo.window );
2011-12-06 18:20:15 +00:00
if (regCodeInfo.okPressed) {
2011-11-22 21:28:15 +00:00
strcpy(ioRegCode1, regCodeInfo.prefRegCode1);
}
2011-12-06 18:20:15 +00:00
return regCodeInfo.okPressed ? (OSErr)noErr : (OSErr)userCanceledErr;
2011-11-22 21:28:15 +00:00
}