/* =========================================================================== Doom 3 GPL Source Code Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code"). 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 . 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 #import #import #import #import #import #import #import #import #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" #define MAX_KEYS 256 static idStr savepath; extern bool key_overstrikeMode; #define TEST_FPU_EXCEPTIONS \ 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]; bool okPressed; WindowRef window; ControlRef regCode1EditText; }; static OSErr DoRegCodeDialog( char* ioRegCode1 ); @interface DOOMController (Private) - (void)quakeMain; - (BOOL)checkRegCodes; - (BOOL)checkOS; @end @implementation DOOMController /* + (void)initialize; { static bool initialized = NO; [super initialize]; if ( initialized ) { return; } initialized = YES; } */ #define MAX_ARGC 1024 - (void)applicationDidFinishLaunching:(NSNotification *)notification; { NS_DURING { NSAssert(sizeof(bool) == 1, @"sizeof(bool) should equal 1 byte"); [self quakeMain]; } NS_HANDLER { Sys_Error( (const char *)[ [ localException reason ] cString ] ); } NS_ENDHANDLER; Sys_Quit(); } - (void)applicationWillHide:(NSNotification *)notification; { Sys_ShutdownInput(); } - (void)applicationWillUnhide:(NSNotification *)notification; { Sys_InitInput(); } - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { common->Quit(); return NSTerminateLater; // we never reach this } #if 0 // Actions - (IBAction)paste:(id)sender; { 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; } extern void CL_Quit_f(void); //extern void SetProgramPath(const char *path); - (IBAction)requestTerminate:(id)sender; { //osxQuit(); common->Quit(); } - (void)showBanner; { static bool hasShownBanner = NO; if (!hasShownBanner) { //cvar_t *showBanner; hasShownBanner = YES; //showBanner = Cvar_Get("cl_showBanner", "1", 0); //if ( showBanner->integer != 0 ) { if ( true ) { 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]; } } } // Services - (void)connectToServer:(NSPasteboard *)pasteboard userData:(NSString *)data error:(NSString **)error; { 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"; } - (void)performCommand:(NSPasteboard *)pasteboard userData:(NSString *)data error:(NSString **)error; { 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"; } #endif // commented out all the banners and actions @end @implementation DOOMController (Private) - (void)quakeMain { NSAutoreleasePool *pool; int argc = 0; char *argv[MAX_ARGC]; 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); */ /* if (cddir && *cddir != '\0') { SetProgramPath([[[NSString stringWithCString:cddir] stringByAppendingPathComponent:@"/x"] cString]); } */ //Sys_FPU_EnableExceptions( TEST_FPU_EXCEPTIONS ); Posix_EarlyInit( ); #ifndef _DEBUG if ( [self checkOS] == FALSE) { common->Quit(); } if ( [self checkDVD] == FALSE) { common->Quit(); } #endif // 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 ) ) { common->Init( argc-1, &argv[1] ); } else { common->Init( 0, NULL ); } Posix_LateInit( ); [NSApp activateIgnoringOtherApps:YES]; while (1) { #ifdef OMNI_TIMER OTPeriodicTimerReset(); OTNodeStart(RootNode); #endif // maintain exceptions in case system calls are turning them off (is that needed) //Sys_FPU_EnableExceptions( TEST_FPU_EXCEPTIONS ); common->Frame(); // We should think about doing this less frequently than every frame [pool release]; pool = [[NSAutoreleasePool alloc] init]; #ifdef OMNI_TIMER OTNodeStop(RootNode); #endif } [pool release]; } - (BOOL)checkRegCodes { BOOL retval; NSString *cdKey; NSUserDefaults *userDefaults; userDefaults = [NSUserDefaults standardUserDefaults]; cdKey = [userDefaults stringForKey:kRegKey]; 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) ); #define fesetenvd(x) asm volatile( "mtfsf 255,%0" : : "f" (x) ); 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; 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 ); 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); cpuId = cpu; oldArchitecture = cpuId < gestaltCPU970; return true; } void OSX_GetVideoCard( int& outVendorId, int& outDeviceId ) { kern_return_t err; mach_port_t masterPort; io_iterator_t itThis; io_service_t service; outVendorId = -1; outDeviceId = -1; // Get a mach port for us and check for errors err = IOMasterPort(MACH_PORT_NULL, &masterPort); if(err) return; // Grab all the PCI devices out of the registry err = IOServiceGetMatchingServices(masterPort, IOServiceMatching("IOPCIDevice"), &itThis); if(err) return; // Yank everything out of the iterator // We could walk through all devices and try to determine the best card. But for now, // we'll just look at the first card. while(1) { service = IOIteratorNext(itThis); io_name_t dName; // 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); // Only accept devices that are // PCI Spec - 0x00030000 is a display device if((*(UInt32*)CFDataGetBytePtr(classCode) & 0x00ff0000) == 0x00030000) { // Get the name of the service (hw) IORegistryEntryGetName(service, dName); CFDataRef vendorID, deviceID; // 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); outVendorId = *((long*)CFDataGetBytePtr(vendorID)); outDeviceId = *((long*)CFDataGetBytePtr(deviceID)); CFRelease(vendorID); CFRelease(deviceID); } CFRelease(classCode); // Stop after finding the first device if (outVendorId != -1) break; } else break; } } /* =============== main =============== */ int main( int argc, char *argv[] ) { return NSApplicationMain( argc, (const char **)argv ); } bool FormatRegCode(const char* inRegCode, char* outRegCode) { // 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; // Reg codes are 18 characters in length return strlen(outRegCode) == 18; } /* =============== RegCodeHandler =============== */ static pascal OSStatus RegCodeHandler( EventHandlerCallRef, EventRef inEvent, void* inUserData ) { #if 1 // FIXME: the CD key API has changed for startup check support and expansion pack key support return noErr; #else HICommand cmd; OSStatus result = eventNotHandledErr; RegCodeInfo* regCodeInfo = (RegCodeInfo*)inUserData; GetEventParameter( inEvent, kEventParamDirectObject, typeHICommand, NULL, sizeof( cmd ), NULL, &cmd ); switch ( cmd.commandID ) { case kHICommandOK: bool fValid; Size actualSize; char cntrl[256]; char doomKey[256]; char strippedKey[256]; 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 { unsigned char theError[512]; 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 ) ); StandardAlert(kAlertStopAlert, theError, theExplanation, NULL, NULL); // 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); break; } regCodeInfo->okPressed = true; QuitAppModalLoopForWindow( regCodeInfo->window ); result = noErr; break; case kHICommandCancel: regCodeInfo->okPressed = false; QuitAppModalLoopForWindow( regCodeInfo->window ); result = noErr; break; } return result; #endif } /* =============== DoRegCodeDialog =============== */ static OSErr DoRegCodeDialog( char* ioRegCode1 ) { OSErr err; RegCodeInfo regCodeInfo; memset(®CodeInfo, 0, sizeof(regCodeInfo)); 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; 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); EventTypeSpec cmdEvent = { kEventClassCommand, kEventCommandProcess }; EventHandlerUPP handler = NewEventHandlerUPP( RegCodeHandler ); InstallWindowEventHandler( regCodeInfo.window, handler, 1, &cmdEvent, ®CodeInfo, NULL ); RepositionWindow( regCodeInfo.window, NULL, kWindowAlertPositionOnMainScreen ); ShowWindow( regCodeInfo.window ); RunAppModalLoopForWindow( regCodeInfo.window ); DisposeWindow( regCodeInfo.window ); if (regCodeInfo.okPressed) { strcpy(ioRegCode1, regCodeInfo.prefRegCode1); } return regCodeInfo.okPressed ? (OSErr)noErr : (OSErr)userCanceledErr; }