922 lines
24 KiB
C++
922 lines
24 KiB
C++
#include <OpenGL/gl.h>
|
|
#include <AmbrosiaTools/platform.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <pthread.h>
|
|
#include <unistd.h>
|
|
|
|
#include <curl/curl.h>
|
|
#include <curl/types.h> /* new for v7 */
|
|
#include <curl/easy.h> /* new for v7 */
|
|
|
|
#include "controls.h"
|
|
#include "initexit.h"
|
|
#include "config.h"
|
|
#include "screen.h"
|
|
#include "textures.h"
|
|
#include "renderframe.h"
|
|
#include "environment.h"
|
|
#include "gameinitexit.h"
|
|
#include "gametime.h"
|
|
#include "gameframe.h"
|
|
#include "error.h"
|
|
#include "network.h"
|
|
#include "interfaceutil.h"
|
|
#include "models.h"
|
|
#include "text.h"
|
|
#include "GetPID.h"
|
|
#include "gamesound.h"
|
|
|
|
|
|
int gSystemSuspended=false;
|
|
int gInGame=false;
|
|
pthread_mutex_t gASMutex;
|
|
|
|
// http://developer.apple.com/qa/qa2001/qa1111.html
|
|
// Creates an AppleEvent with one text parameter. We leave it up to the AppleScript
|
|
// to further parse the text parameter into potentially more parameters.
|
|
static OSStatus CreateMessageEvent( AppleEvent *theEvent, char *parameter )
|
|
{
|
|
OSStatus err;
|
|
ProcessSerialNumber psn = {0, kCurrentProcess};
|
|
|
|
err = AEBuildAppleEvent( 'ascr', kASSubroutineEvent, typeProcessSerialNumber, (Ptr) &psn, sizeof(psn), kAutoGenerateReturnID, kAnyTransactionID,
|
|
theEvent,
|
|
NULL,
|
|
"'----':[TEXT(@)]," // One TEXT pointer parameter
|
|
"'snam':TEXT(@)", // The keyASSubroutineName ('snam') parameter must contain the name of the subroutine that is being called with every letter converted to lowercase. For example, if name of the subroutine in your script is "GetDocumentSize", then the string provided in the keyASSubroutineName parameter should be "getdocumentsize".
|
|
parameter, "applescriptentry"); // The entry routine whithin the AppleScript
|
|
|
|
return( err );
|
|
}
|
|
|
|
/*****************************************************
|
|
*
|
|
* ExecuteCompiledAppleScriptEvent( AEDesc *scriptData, AppleEvent *theEvent, AEDesc *resultData )
|
|
*
|
|
* Purpose: Generic routine to execute our AppleScriptEvent, passing parameters to an
|
|
* AppleScript running inside my application
|
|
*
|
|
* Notes: http://developer.apple.com/qa/qa2001/qa1111.html
|
|
*
|
|
* Inputs: scriptData - Reference to the AppleScript to be executed
|
|
* theEvent - text parameter to our AppleScript as an AppleEvent
|
|
* resultData - result from script
|
|
*
|
|
* Returns: OSStatus - error code (0 == no error)
|
|
*/
|
|
typedef struct{
|
|
int inited;
|
|
ComponentInstance theComponent;
|
|
OSAID contextID;
|
|
} tScriptData;
|
|
|
|
OSStatus ExecuteCompiledAppleScriptEvent( AEDesc *scriptData, AppleEvent *theEvent, AEDesc *resultData,tScriptData *scriptStore)
|
|
{
|
|
OSStatus err;
|
|
ComponentInstance theComponent = NULL;
|
|
OSAID contextID = kOSANullScript;
|
|
OSAID resultID = kOSANullScript;
|
|
int inited=false;
|
|
|
|
if(scriptStore)
|
|
if(scriptStore->inited)
|
|
{
|
|
theComponent=scriptStore->theComponent;
|
|
contextID=scriptStore->contextID;
|
|
inited=true;
|
|
}
|
|
if(!inited)
|
|
{
|
|
theComponent = OpenDefaultComponent( kOSAComponentType, typeAppleScript ); // Open the scripting component
|
|
if ( theComponent == NULL ) { err = paramErr; goto Bail; }
|
|
|
|
err = OSALoad( theComponent, scriptData, kOSAModeNull, &contextID ); // Compile the script into a new context
|
|
require_noerr( err, Bail );
|
|
}
|
|
|
|
err = OSAExecuteEvent( theComponent, theEvent, contextID, kOSAModeNull, &resultID ); // Run the script
|
|
if ( resultData != NULL ) // Collect the results - if any
|
|
{
|
|
AECreateDesc( typeNull, NULL, 0, resultData );
|
|
/*if ( err == errOSAScriptError )
|
|
OSAScriptError( theComponent, kOSAErrorMessage, typeChar, resultData );
|
|
else*/ if ( (err == noErr) && (resultID != kOSANullScript) )
|
|
OSADisplay(theComponent, resultID, typeChar, kOSAModeNull, resultData);
|
|
}
|
|
|
|
Bail:
|
|
if ( resultID != kOSANullScript ) OSADispose( theComponent, resultID );
|
|
if(!scriptStore)
|
|
{
|
|
if ( contextID != kOSANullScript ) OSADispose( theComponent, contextID );
|
|
if ( theComponent != NULL ) CloseComponent( theComponent );
|
|
}
|
|
else
|
|
{
|
|
scriptStore->inited=true;
|
|
scriptStore->theComponent=theComponent;
|
|
scriptStore->contextID=contextID;
|
|
}
|
|
return( err );
|
|
}
|
|
|
|
/*****************************************************
|
|
*
|
|
* RunAppleScript( FSRef *scriptFSRef, char *textParameter )
|
|
*
|
|
* Purpose: Runs an AppleScript with one text parameter as input.
|
|
* CreateMessageEvent, and therefore RunAppleScript, assumes the AppleScript has a
|
|
* subroutine entry titled "applescriptentry" and accepts one TEXT parameter.
|
|
*
|
|
* Inputs: scriptFSRef - FSRef to our AppleScript
|
|
* textParameter - text parameter to our AppleScript
|
|
*
|
|
* Returns: OSStatus - error code (0 == no error)
|
|
*/
|
|
static OSStatus RunAppleScript( FSRef *scriptFSRef, char *textParameter, char *textReply,int textsize,tScriptData *d)
|
|
{
|
|
OSStatus err;
|
|
AppleEvent aeParameter;
|
|
AEDesc scriptData;
|
|
short refNum;
|
|
FSCatalogInfo catalogInfo;
|
|
Handle h = NULL;
|
|
|
|
pthread_mutex_lock(&gASMutex);
|
|
|
|
refNum = FSOpenResFile( scriptFSRef, fsRdPerm ); // Older (Mac OS 8/9) scripts store their data in the 'scpt' (1) resource
|
|
if ( refNum != -1 )
|
|
{
|
|
h = Get1IndResource( 'scpt', 1 );
|
|
if( h != NULL ) DetachResource( h ); // Detach the handle before closing the resource
|
|
CloseResFile( refNum );
|
|
}
|
|
if ( h == NULL )
|
|
{
|
|
err = FSGetCatalogInfo( scriptFSRef, kFSCatInfoDataSizes, &catalogInfo, NULL, NULL, NULL ); // Get the size of the script
|
|
require_noerr( err, Bail );
|
|
|
|
err = FSOpenFork( scriptFSRef, 0, NULL, fsRdPerm, &refNum ); // Open the data fork read only
|
|
require_noerr( err, Bail );
|
|
|
|
h = NewHandle( catalogInfo.dataLogicalSize );
|
|
err = FSReadFork( refNum, fsFromStart, 0, catalogInfo.dataLogicalSize, *h, NULL ); // Read the script into our handle
|
|
(void) FSCloseFork( refNum ); // Close the file reference
|
|
}
|
|
|
|
err = CreateMessageEvent( &aeParameter, textParameter ); // Create the AppleEvent, and use the Apple event to call the script's subroutine
|
|
require_noerr( err, Bail );
|
|
|
|
err = AECreateDesc( typeOSAGenericStorage, *h, GetHandleSize(h), &scriptData ); // Load the compiled script into an AEDesc of type typeOSAGenericStorage
|
|
require_noerr( err, Bail );
|
|
|
|
AEDesc result;
|
|
err = ExecuteCompiledAppleScriptEvent( &scriptData, &aeParameter, &result,d); // "Generic" routine to execute our AppleScript
|
|
if(textReply)
|
|
{
|
|
int size=AEGetDescDataSize(&result);
|
|
AEGetDescData(&result,textReply,textsize-1);
|
|
textReply[textsize]='\0';
|
|
if(size<textsize)
|
|
textReply[size]='\0';
|
|
}
|
|
Bail:
|
|
if ( h != NULL ) DisposeHandle( h );
|
|
pthread_mutex_unlock(&gASMutex);
|
|
return( err );
|
|
}
|
|
|
|
int IsITunesEnabled()
|
|
{
|
|
return GetPIDForProcessName("iTunes")!=-1;
|
|
/* ProcessSerialNumber psn,noproc={0,kNoProcess};
|
|
psn=noproc;
|
|
Boolean result;
|
|
do{
|
|
CFStringRef name;
|
|
GetNextProcess(&psn);
|
|
CopyProcessName(&psn,&name);
|
|
if(CFStringCompare(name,CFSTR("iTunes"),0)==kCFCompareEqualTo)
|
|
return true;
|
|
SameProcess(&psn,&noproc,&result);
|
|
}while(!result);
|
|
return false;*/
|
|
}
|
|
|
|
void *ITunesNext(void *)
|
|
{
|
|
// See the Core Foundation URL Services chapter for details.
|
|
// get app bundle (even for a CFM app!)
|
|
CFBundleRef refMainBundle = CFBundleGetMainBundle();
|
|
if (!refMainBundle)
|
|
return NULL;
|
|
|
|
// create a URL to the app bundle
|
|
CFURLRef refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
|
|
if (!refMainBundleURL)
|
|
return NULL;
|
|
|
|
// create a URL to the HID library bundle
|
|
CFURLRef skriptURL = CFURLCreateCopyAppendingPathComponent (NULL, refMainBundleURL, CFSTR("Contents/Resources/Next Track.scpt"), true);
|
|
if (!skriptURL)
|
|
return NULL;
|
|
|
|
FSRef scriptFSRef;
|
|
if(CFURLGetFSRef(skriptURL,&scriptFSRef))
|
|
RunAppleScript(&scriptFSRef,"",NULL,0,NULL);
|
|
}
|
|
|
|
void *ITunesPrev(void *)
|
|
{
|
|
// See the Core Foundation URL Services chapter for details.
|
|
// get app bundle (even for a CFM app!)
|
|
CFBundleRef refMainBundle = CFBundleGetMainBundle();
|
|
if (!refMainBundle)
|
|
return NULL;
|
|
|
|
// create a URL to the app bundle
|
|
CFURLRef refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
|
|
if (!refMainBundleURL)
|
|
return NULL;
|
|
|
|
// create a URL to the HID library bundle
|
|
CFURLRef skriptURL = CFURLCreateCopyAppendingPathComponent (NULL, refMainBundleURL, CFSTR("Contents/Resources/Prev Track.scpt"), true);
|
|
if (!skriptURL)
|
|
return NULL;
|
|
|
|
FSRef scriptFSRef;
|
|
if(CFURLGetFSRef(skriptURL,&scriptFSRef))
|
|
RunAppleScript(&scriptFSRef,"",NULL,0,NULL);
|
|
}
|
|
|
|
void *ITunesPlay(void *)
|
|
{
|
|
// See the Core Foundation URL Services chapter for details.
|
|
// get app bundle (even for a CFM app!)
|
|
CFBundleRef refMainBundle = CFBundleGetMainBundle();
|
|
if (!refMainBundle)
|
|
return NULL;
|
|
|
|
// create a URL to the app bundle
|
|
CFURLRef refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
|
|
if (!refMainBundleURL)
|
|
return NULL;
|
|
|
|
// create a URL to the HID library bundle
|
|
CFURLRef skriptURL = CFURLCreateCopyAppendingPathComponent (NULL, refMainBundleURL, CFSTR("Contents/Resources/PlayPause.scpt"), true);
|
|
if (!skriptURL)
|
|
return NULL;
|
|
|
|
FSRef scriptFSRef;
|
|
if(CFURLGetFSRef(skriptURL,&scriptFSRef))
|
|
RunAppleScript(&scriptFSRef,"",NULL,0,NULL);
|
|
// system("osascript /Users/jechter/Documents/proj/glLandscape/deliverable/gamexcode/build/Release/PlayPause.scpt");
|
|
}
|
|
|
|
|
|
char giTunesSong[1024],giTunesArtist[1024];
|
|
int giTunesPlaying=false;
|
|
float giTunesLastStatusUpdate=-10;
|
|
|
|
|
|
void ITunesGetStatus()
|
|
{
|
|
static int inited=false;
|
|
static float lastStatus=0;
|
|
static tScriptData data={0,0,0};
|
|
|
|
// if(TimeGetSeconds()<lastStatus+1)
|
|
// return;
|
|
if(!IsITunesEnabled())
|
|
return;
|
|
lastStatus=TimeGetSeconds();
|
|
// See the Core Foundation URL Services chapter for details.
|
|
// get app bundle (even for a CFM app!)
|
|
CFBundleRef refMainBundle = CFBundleGetMainBundle();
|
|
if (!refMainBundle)
|
|
return;
|
|
|
|
// create a URL to the app bundle
|
|
CFURLRef refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
|
|
if (!refMainBundleURL)
|
|
return;
|
|
|
|
// create a URL to the HID library bundle
|
|
CFURLRef skriptURL = CFURLCreateCopyAppendingPathComponent (NULL, refMainBundleURL, CFSTR("Contents/Resources/Status.scpt"), true);
|
|
if (!skriptURL)
|
|
return;
|
|
|
|
FSRef scriptFSRef;
|
|
if(CFURLGetFSRef(skriptURL,&scriptFSRef))
|
|
{
|
|
char status[1024];
|
|
RunAppleScript(&scriptFSRef,"",status,1024,&data);
|
|
|
|
char* str=strchr(status,'"');
|
|
if(str)str++;
|
|
else return;
|
|
char* end=strchr(str,'"');
|
|
if(end)*end='\0';
|
|
StripDiacritics(str,strlen(str),smSystemScript);
|
|
if(strcmp(str,giTunesSong))
|
|
{
|
|
strcpy(giTunesSong,str);
|
|
if(inited)
|
|
giTunesLastStatusUpdate=lastStatus;
|
|
}
|
|
|
|
str=strchr(end+1,'"');
|
|
if(str)str++;
|
|
else return;
|
|
end=strchr(str,'"');
|
|
if(end)*end='\0';
|
|
StripDiacritics(str,strlen(str),smSystemScript);
|
|
if(strcmp(str,giTunesArtist))
|
|
{
|
|
strcpy(giTunesArtist,str);
|
|
if(inited)
|
|
giTunesLastStatusUpdate=lastStatus;
|
|
}
|
|
|
|
str=end+1;
|
|
if(giTunesPlaying)
|
|
{
|
|
if(!strstr(str,"true"))
|
|
{
|
|
giTunesPlaying=false;
|
|
if(inited)
|
|
giTunesLastStatusUpdate=lastStatus;
|
|
}
|
|
}
|
|
else if(strstr(str,"true"))
|
|
{
|
|
giTunesPlaying=true;
|
|
if(inited)
|
|
giTunesLastStatusUpdate=lastStatus;
|
|
}
|
|
}
|
|
inited=true;
|
|
}
|
|
|
|
int IsInFront()
|
|
{
|
|
ProcessSerialNumber currentProc,frontProc;
|
|
GetFrontProcess(&frontProc);
|
|
GetCurrentProcess(¤tProc);
|
|
Boolean same;
|
|
SameProcess(¤tProc,&frontProc,&same);
|
|
return same;
|
|
}
|
|
|
|
/*void IChatStatus(char *status)
|
|
{
|
|
// See the Core Foundation URL Services chapter for details.
|
|
// get app bundle (even for a CFM app!)
|
|
CFBundleRef refMainBundle = CFBundleGetMainBundle();
|
|
if (!refMainBundle)
|
|
return;
|
|
|
|
// create a URL to the app bundle
|
|
CFURLRef refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
|
|
if (!refMainBundleURL)
|
|
return;
|
|
|
|
// create a URL to the HID library bundle
|
|
CFURLRef skriptURL = CFURLCreateCopyAppendingPathComponent (NULL, refMainBundleURL, CFSTR("Contents/Resources/PlayPause.scpt"), true);
|
|
if (!skriptURL)
|
|
return;
|
|
|
|
FSRef scriptFSRef;
|
|
if(CFURLGetFSRef(skriptURL,&scriptFSRef))
|
|
RunAppleScript(&scriptFSRef,status);
|
|
}*/
|
|
|
|
static OSStatus LoadFrameworkBundle(CFBundleRef *bundlePtr)
|
|
{
|
|
Boolean didLoad = false; // Flag that indicates the status returned when attempting to load a bundle's executable code.
|
|
CFBundleRef refMainBundle = NULL;
|
|
CFURLRef refMainBundleURL = NULL, refPathBundleURL = NULL;
|
|
|
|
CFURLRef bundleURL = NULL;
|
|
CFBundleRef bundle = NULL;
|
|
|
|
// See the Core Foundation URL Services chapter for details.
|
|
// get app bundle (even for a CFM app!)
|
|
refMainBundle = CFBundleGetMainBundle();
|
|
if (!refMainBundle)
|
|
{
|
|
DebugStr ("\pCould open main bundle");
|
|
return paramErr;
|
|
}
|
|
// create a URL to the app bundle
|
|
refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
|
|
if (!refMainBundleURL)
|
|
{
|
|
DebugStr ("\pCould not copy main bundle URL");
|
|
return paramErr;
|
|
}
|
|
// create a URL that points to the app's directory
|
|
// create a URL to the HID library bundle
|
|
bundleURL = CFURLCreateCopyAppendingPathComponent (NULL, refMainBundleURL, CFSTR("Contents/MacOS/FpuExceptions.bundle"), true);
|
|
// release created URLs
|
|
if (refMainBundleURL != NULL)
|
|
CFRelease (refMainBundleURL);
|
|
if (refPathBundleURL != NULL)
|
|
CFRelease (refPathBundleURL);
|
|
// did we actaully get a bundle URL
|
|
if (!bundleURL)
|
|
{
|
|
DebugStr ("\pCould create HID bundle URL");
|
|
return paramErr;
|
|
}
|
|
// get the actual bundle for the HID library
|
|
bundle = CFBundleCreate (NULL, bundleURL);
|
|
if (!bundle)
|
|
{
|
|
DebugStr ("\pCould not create HID MachO library bundle");
|
|
return paramErr;
|
|
}
|
|
if (!CFBundleLoadExecutable (bundle)) // If the code was successfully loaded, look for our function.
|
|
{
|
|
DebugStr ("\pCould not load MachO executable");
|
|
return paramErr;
|
|
}
|
|
*bundlePtr=bundle;
|
|
}
|
|
|
|
pascal OSErr myQUIT(const AppleEvent *theAE,AppleEvent *reply,long refCon)
|
|
{
|
|
if(!gInGame||gReplay||gInputEscMode==kInputEscModeNormal)
|
|
Exit();
|
|
else
|
|
{
|
|
gInputEscMode=kInputEscModeQuit;
|
|
gInputEscSelection=1;
|
|
if(!gGameInfo->network)
|
|
PauseGame();
|
|
}
|
|
return noErr;
|
|
}
|
|
|
|
#define kMaxURLSize 256
|
|
|
|
pascal OSErr myGURL(const AppleEvent *theAE,AppleEvent *reply,long refCon)
|
|
{
|
|
DescType type;
|
|
char theURL[kMaxURLSize];
|
|
Size urlSize;
|
|
HandleError(AEGetParamPtr(theAE,keyDirectObject,typeChar,&type,theURL,kMaxURLSize,&urlSize));
|
|
|
|
if(type!=typeChar)
|
|
return paramErr;
|
|
|
|
if(urlSize>=kMaxURLSize)
|
|
return paramErr;
|
|
|
|
theURL[urlSize]='\0';
|
|
|
|
//PrintConsoleString("Opening URL \"%s\"....",theURL);
|
|
|
|
if(theURL[strlen(theURL)-1]=='>')
|
|
theURL[strlen(theURL)-1]='\0';
|
|
if(theURL[strlen(theURL)-1]=='/')
|
|
theURL[strlen(theURL)-1]='\0';
|
|
sscanf(theURL,"<%s",theURL);
|
|
sscanf(theURL,"URL:%s",theURL);
|
|
sscanf(theURL,"redline://%s",gJoinHost);
|
|
|
|
gJoinFlag=true;
|
|
gGameEnd=kEndGameNoReplay;
|
|
|
|
return noErr;
|
|
}
|
|
|
|
void InitAE()
|
|
{
|
|
AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,NewAEEventHandlerUPP(&myQUIT),0,false);
|
|
AEInstallEventHandler(kInternetEventClass,kAEGetURL,NewAEEventHandlerUPP(&myGURL),0,false);
|
|
}
|
|
|
|
//#define kBetaExpiration (3232976085+4000000)
|
|
#define kBetaExpiration (0)
|
|
|
|
void* ITunesPollThread(void * arg)
|
|
{
|
|
while(1){
|
|
ITunesGetStatus();
|
|
sleep(1);
|
|
}
|
|
}
|
|
|
|
void InitITunesNotifications();
|
|
|
|
void SystemInit()
|
|
{
|
|
long resp;
|
|
short hit;
|
|
|
|
AlertStdAlertParamRec alertParam={
|
|
false,false,nil,
|
|
"\pExit",
|
|
nil,
|
|
nil,
|
|
kAlertStdAlertOKButton,
|
|
0,
|
|
kWindowDefaultPosition};
|
|
|
|
HandleError(Gestalt(gestaltSystemVersion,&resp));
|
|
if(resp<0x00001020)
|
|
{
|
|
StandardAlert(kAlertStopAlert,
|
|
"\pMac OS 10.2 or higher is required.",
|
|
"\p",
|
|
&alertParam,
|
|
&hit);
|
|
ExitToShell();
|
|
}
|
|
|
|
unsigned long dateTime;
|
|
GetDateTime(&dateTime);
|
|
|
|
//PrintConsoleString("%u",dateTime);
|
|
if(kBetaExpiration&&dateTime>kBetaExpiration)
|
|
{
|
|
StandardAlert(kAlertStopAlert,
|
|
"\pThis beta of Redline has expired.",
|
|
"\p",
|
|
&alertParam,
|
|
&hit);
|
|
ExitToShell();
|
|
}
|
|
|
|
InitAE();
|
|
|
|
ITunesGetStatus();
|
|
InitITunesNotifications();
|
|
|
|
pthread_mutex_init(&gASMutex,0);
|
|
//pthread_t thread;
|
|
//pthread_create(&thread,NULL,ITunesPollThread,NULL);
|
|
// CallOmniEnableFloatExceptions();
|
|
}
|
|
|
|
#define kInputBufferSize 16
|
|
UInt32 gInputBuffer[kInputBufferSize];
|
|
int gInputBufferPos=0;
|
|
float gLastCursorHideTime;
|
|
extern int gInterfaceKeys[kInterfaceNumKeys];
|
|
UInt32 gLastSwitch=0;
|
|
int iTunesPress=false;
|
|
int gSystemInstalling=false;
|
|
float gInstallStartTime=0;
|
|
|
|
|
|
void SystemPoll(int inGame)
|
|
{
|
|
EventRecord evt;
|
|
gInGame=inGame;
|
|
while(WaitNextEvent(everyEvent,&evt,0,nil))
|
|
{
|
|
switch(evt.what)
|
|
{
|
|
case mouseDown:
|
|
WindowPtr win;
|
|
switch(FindWindow(evt.where,&win))
|
|
{
|
|
case inDrag:
|
|
{
|
|
Rect dragRect={0,0,32767,32767};
|
|
DragWindow(win,evt.where,&dragRect);
|
|
Point pt={0,0};
|
|
LocalToGlobal(&pt);
|
|
gConfig->windowX=pt.h;
|
|
gConfig->windowY=pt.v;
|
|
}
|
|
break;
|
|
case inMenuBar:
|
|
MenuSelect(evt.where);
|
|
break;
|
|
case inContent:
|
|
if(evt.when>gLastSwitch+20)
|
|
if(gInputBufferPos<kInputBufferSize)
|
|
gInputBuffer[gInputBufferPos++]=gInterfaceKeys[kInterfaceMouseDown]<<8;
|
|
break;
|
|
}
|
|
break;
|
|
case osEvt:
|
|
if(((evt.message&osEvtMessageMask)>>24)==suspendResumeMessage)
|
|
{
|
|
gSystemSuspended=!(evt.message&resumeFlag);
|
|
if(!gSystemSuspended)
|
|
BringToFront(FrontWindow());
|
|
if(inGame)
|
|
{
|
|
if(gSystemSuspended&&inGame)
|
|
if((!gGameInfo->network)&&(!gReplay))
|
|
PauseGame();
|
|
}
|
|
else
|
|
if(gSystemSuspended)
|
|
PauseGame();
|
|
else
|
|
UnPauseGame();
|
|
gLastSwitch=evt.when;
|
|
if(!gPaused)
|
|
SoundReInit();
|
|
}
|
|
break;
|
|
case kHighLevelEvent :
|
|
AEProcessAppleEvent(&evt);
|
|
break;
|
|
case keyDown:
|
|
case autoKey:
|
|
if(evt.modifiers&cmdKey)
|
|
switch(evt.message&charCodeMask)
|
|
{
|
|
case 'f':
|
|
if(!ScreenNoWindow())
|
|
{
|
|
float pauseTime=TimeGetSeconds();
|
|
gConfig->fullscreen=!gConfig->fullscreen;
|
|
|
|
ScreenReInit();
|
|
if(inGame)
|
|
{
|
|
gClipEnable=false;
|
|
RenderFrame(false);
|
|
gClipEnable=true;
|
|
|
|
if(!gPaused&&!gGameInfo->network)
|
|
gStartTime+=TimeGetSeconds()-pauseTime;
|
|
}
|
|
}
|
|
break;
|
|
/* case 'q':
|
|
if((!inGame)||gInputEscMode==kInputEscModeNormal)
|
|
Exit();
|
|
break;*/
|
|
}
|
|
else
|
|
if(gInputBufferPos<kInputBufferSize)
|
|
{
|
|
MemoryMove(gInputBuffer+1,gInputBuffer,sizeof(UInt32)*gInputBufferPos);
|
|
gInputBufferPos++;
|
|
gInputBuffer[0]=evt.message;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(TimeGetSeconds()>gLastCursorHideTime+1&&!gSystemInstalling)
|
|
{
|
|
gLastCursorHideTime=TimeGetSeconds();
|
|
if(gConfig->fullscreen)
|
|
HideCursor();
|
|
else
|
|
ObscureCursor();
|
|
}
|
|
|
|
if(((!gInterfaceType||GetInterfaceKey(kInterfaceKeyCmd))||inGame)&&!gSystemSuspended)
|
|
{
|
|
pthread_t thread;
|
|
if(GetButtonInput(kInputITunesNext))
|
|
{
|
|
if(!iTunesPress)
|
|
// ITunesNext(NULL);
|
|
pthread_create(&thread,NULL,ITunesNext,NULL);
|
|
iTunesPress=true;
|
|
}
|
|
else if(GetButtonInput(kInputITunesPrev))
|
|
{
|
|
if(!iTunesPress)
|
|
// ITunesPrev(NULL);
|
|
pthread_create(&thread,NULL,ITunesPrev,NULL);
|
|
iTunesPress=true;
|
|
}
|
|
else if(GetButtonInput(kInputITunesPlay))
|
|
{
|
|
if(!iTunesPress)
|
|
// ITunesPlay(NULL);
|
|
pthread_create(&thread,NULL,ITunesPlay,NULL);
|
|
iTunesPress=true;
|
|
}
|
|
else
|
|
iTunesPress=false;
|
|
}
|
|
|
|
RT3_Idle();
|
|
NetworkIdle();
|
|
SystemIdle();
|
|
}
|
|
|
|
void SystemYieldTime(float till)
|
|
{
|
|
while(TimeGetSeconds()<till)
|
|
SystemYield();
|
|
}
|
|
|
|
|
|
void SystemNotify()
|
|
{
|
|
if(gSystemSuspended)
|
|
{
|
|
NMRec n;
|
|
n.qType=nmType;
|
|
n.nmMark=1;
|
|
n.nmIcon=NULL;
|
|
n.nmSound=NULL;
|
|
n.nmStr=NULL;
|
|
n.nmResp=NULL;
|
|
HandleError(NMInstall(&n));
|
|
}
|
|
}
|
|
|
|
void FlushKeys()
|
|
{
|
|
// SystemPoll(false);
|
|
FlushEvents(keyDownMask+mDownMask,0);
|
|
gInputBufferPos=0;
|
|
}
|
|
|
|
char GetKeyInput(int *key)
|
|
{
|
|
if(key)
|
|
*key=kInterfaceKeyNone;
|
|
if(gInputBufferPos)
|
|
{
|
|
gInputBufferPos--;
|
|
if(key)
|
|
for(int i=kInterfaceKeyUp;i<kInterfaceNumKeys;i++)
|
|
if((gInputBuffer[gInputBufferPos]&keyCodeMask)>>8==gInterfaceKeys[i])
|
|
*key=i;
|
|
if(gInputBuffer[gInputBufferPos]&charCodeMask)
|
|
return gInputBuffer[gInputBufferPos]&charCodeMask;
|
|
else
|
|
return 0xff;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char PeekKeyInput(int *key)
|
|
{
|
|
if(key)
|
|
*key=kInterfaceKeyNone;
|
|
if(gInputBufferPos)
|
|
{
|
|
if(key)
|
|
for(int i=kInterfaceKeyUp;i<kInterfaceNumKeys;i++)
|
|
if((gInputBuffer[gInputBufferPos-1]&keyCodeMask)>>8==gInterfaceKeys[i])
|
|
*key=i;
|
|
if(gInputBuffer[gInputBufferPos-1]&charCodeMask)
|
|
return gInputBuffer[gInputBufferPos-1]&charCodeMask;
|
|
else
|
|
return 0xff;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
float TimeGetSeconds()
|
|
{
|
|
static UInt64 startTime=0;
|
|
if(startTime==0)
|
|
Microseconds((UnsignedWide*)&startTime);
|
|
UInt64 w;
|
|
Microseconds((UnsignedWide*)&w);
|
|
return (float)((double)(w-startTime)*(double)0.000001);
|
|
}
|
|
|
|
size_t my_write_func(void *ptr, size_t size, size_t nmemb, FILE *stream)
|
|
{
|
|
return fwrite(ptr, size, nmemb, stream);
|
|
}
|
|
|
|
size_t my_read_func(void *ptr, size_t size, size_t nmemb, FILE *stream)
|
|
{
|
|
return fread(ptr, size, nmemb, stream);
|
|
}
|
|
|
|
int my_progress_func(void *v,
|
|
double t, /* dltotal */
|
|
double d, /* dlnow */
|
|
double ultotal,
|
|
double ulnow)
|
|
{
|
|
char status[1024];
|
|
float time=TimeGetSeconds()-gInstallStartTime;
|
|
if(d>0)
|
|
{
|
|
time*=(t-d)/d;
|
|
sprintf(status,"%3.1f of %3.1fMB - about %d:%02d:%02d remaining",d/(1024*1024),t/(1024*1024),(int)(time/3600),((int)(time/60))%60,((int)time)%60);
|
|
}
|
|
else
|
|
sprintf(status,"%3.1f of %3.1fMB");
|
|
|
|
InterfaceDrawStatusBar("Downloading new version",status,d/t);
|
|
SystemPoll(false);
|
|
return 0;
|
|
}
|
|
|
|
int CurlGetFile(char *url,char *filename,char *failStr)
|
|
{
|
|
#ifndef __TARGET_TOOLAPP
|
|
CURL *curl;
|
|
CURLcode res;
|
|
FILE *outfile;
|
|
if(!curl_easy_init)
|
|
{
|
|
strcpy(failStr,"libcurl not available");
|
|
return false;
|
|
}
|
|
|
|
curl = curl_easy_init();
|
|
if(curl)
|
|
{
|
|
outfile = fopen(filename, "w");
|
|
if(!outfile)
|
|
{
|
|
strcpy(failStr,"Couldn't create file.\nMake sure that Redline and the Redline directory is writable and that you have free space on your disk.");
|
|
return false;
|
|
}
|
|
gSystemInstalling=true;
|
|
gInstallStartTime=TimeGetSeconds();
|
|
|
|
res = curl_easy_setopt(curl, CURLOPT_URL, url);
|
|
if(res==CURLE_OK) res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile);
|
|
if(res==CURLE_OK) res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_write_func);
|
|
if(res==CURLE_OK) res = curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_read_func);
|
|
if(res==CURLE_OK) res = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);
|
|
if(res==CURLE_OK) res = curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, my_progress_func);
|
|
|
|
if(res==CURLE_OK) res = curl_easy_perform(curl);
|
|
|
|
fclose(outfile);
|
|
/* always cleanup */
|
|
curl_easy_cleanup(curl);
|
|
}
|
|
switch(res)
|
|
{
|
|
case CURLE_OK: break;
|
|
case 22: strcpy(failStr,"curl: HTTP error"); break;
|
|
case CURLE_WRITE_ERROR: strcpy(failStr,"curl: Error writing to disk"); break;
|
|
case CURLE_URL_MALFORMAT: strcpy(failStr,"curl: Invalid Update URL"); break;
|
|
case CURLE_COULDNT_RESOLVE_HOST: strcpy(failStr,"curl: Couldn't resolve host"); break;
|
|
case CURLE_COULDNT_CONNECT: strcpy(failStr,"curl: Connection failed"); break;
|
|
case CURLE_OPERATION_TIMEOUTED: strcpy(failStr,"curl: Connection timed out"); break;
|
|
case CURLE_RECV_ERROR: strcpy(failStr,"curl: Error receiving data"); break;
|
|
default: strcpy(failStr,"curl: Error downloading URL"); break;
|
|
}
|
|
return res==CURLE_OK;
|
|
#endif
|
|
}
|
|
|
|
void SystemExit()
|
|
{
|
|
if(gSystemInstalling)
|
|
system("rm redlineupdatearchive.zip");
|
|
}
|
|
|
|
int AutoUpdateRedline(char *updateURL,char *failStr)
|
|
{
|
|
CFBundleRef refMainBundle = CFBundleGetMainBundle();
|
|
if (!refMainBundle)
|
|
{
|
|
sprintf(failStr,"Couldn't get Redline bundle location");
|
|
return false;
|
|
}
|
|
// create a URL to the app bundle
|
|
CFURLRef refMainBundleURL = CFBundleCopyBundleURL (refMainBundle);
|
|
if(!refMainBundleURL)
|
|
{
|
|
sprintf(failStr,"Couldn't get Redline bundle location");
|
|
return false;
|
|
}
|
|
|
|
char path[512];
|
|
if(!CFURLGetFileSystemRepresentation(refMainBundleURL,true,(UInt8*)path,512))
|
|
{
|
|
sprintf(failStr,"Couldn't get Redline bundle location");
|
|
return false;
|
|
}
|
|
|
|
// char cmd[512];
|
|
sprintf(path,"%s/../",path);
|
|
chdir(path);
|
|
system("pwd");
|
|
// printf(cmd);
|
|
// system(cmd);
|
|
|
|
int retval=true;
|
|
InitCursor();
|
|
if(!CurlGetFile(updateURL,"redlineupdatearchive.zip",failStr)) retval=false;
|
|
InterfaceDrawStrings("Installing new version","Please wait a moment...",-1);
|
|
if(retval)
|
|
if(system("unzip -o redlineupdatearchive.zip"))
|
|
{
|
|
retval=false;
|
|
sprintf(failStr,"Couldn't unzip update archive.\nMake sure that Redline and the Redline directory is writable and that you have free space on your disk.");
|
|
}
|
|
if(system("rm redlineupdatearchive.zip")) retval=false;
|
|
gSystemInstalling=false;
|
|
return retval;
|
|
} |