llappviewermacosx.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #if !defined LL_DARWIN
00035         #error "Use only with Mac OS X"
00036 #endif
00037 
00038 #include "llappviewermacosx.h"
00039 #include "llcommandlineparser.h"
00040 
00041 #include "llmemtype.h"
00042 
00043 #include "llviewernetwork.h"
00044 #include "llviewercontrol.h"
00045 #include "llmd5.h"
00046 #include "llurlsimstring.h"
00047 #include "llfloaterworldmap.h"
00048 #include "llurldispatcher.h"
00049 #include <Carbon/Carbon.h>
00050 #include "lldir.h"
00051 namespace 
00052 {
00053         // The command line args stored.
00054         // They are not used immediately by the app.
00055         int gArgC;
00056         char** gArgV;
00057 }
00058 
00059 int main( int argc, char **argv ) 
00060 {
00061         LLMemType mt1(LLMemType::MTYPE_STARTUP);
00062 
00063 #if LL_SOLARIS && defined(__sparc)
00064         asm ("ta\t6");           // NOTE:  Make sure memory alignment is enforced on SPARC
00065 #endif
00066 
00067         // Set the working dir to <bundle>/Contents/Resources
00068         (void) chdir(gDirUtilp->getAppRODataDir().c_str());
00069 
00070         LLAppViewerMacOSX* viewer_app_ptr = new LLAppViewerMacOSX();
00071 
00072         viewer_app_ptr->setErrorHandler(LLAppViewer::handleViewerCrash);
00073 
00074         // Store off the command line args for use later.
00075         gArgC = argc;
00076         gArgV = argv;
00077         
00078         bool ok = viewer_app_ptr->init();
00079         if(!ok)
00080         {
00081                 llwarns << "Application init failed." << llendl;
00082                 return -1;
00083         }
00084 
00085                 // Run the application main loop
00086         if(!LLApp::isQuitting()) 
00087         {
00088                 viewer_app_ptr->mainLoop();
00089         }
00090 
00091         if (!LLApp::isError())
00092         {
00093                 //
00094                 // We don't want to do cleanup here if the error handler got called -
00095                 // the assumption is that the error handler is responsible for doing
00096                 // app cleanup if there was a problem.
00097                 //
00098                 viewer_app_ptr->cleanup();
00099         }
00100         delete viewer_app_ptr;
00101         viewer_app_ptr = NULL;
00102         return 0;
00103 }
00104 
00105 LLAppViewerMacOSX::LLAppViewerMacOSX()
00106 {
00107 }
00108 
00109 LLAppViewerMacOSX::~LLAppViewerMacOSX()
00110 {
00111 }
00112 
00113 bool LLAppViewerMacOSX::init()
00114 {
00115         return LLAppViewer::init();
00116 }
00117 
00118 // MacOSX may add and addition command line arguement for the process serial number.
00119 // The option takes a form like '-psn_0_12345'. The following method should be able to recognize
00120 // and either ignore or return a pair of values for the option.
00121 // look for this method to be added to the parser in parseAndStoreResults.
00122 std::pair<std::string, std::string> parse_psn(const std::string& s)
00123 {
00124     if (s.find("-psn_") == 0) 
00125         {
00126                 // *FIX:Mani Not sure that the value makes sense.
00127                 // fix it once the actual -psn_XXX syntax is known.
00128                 return std::make_pair("psn", s.substr(5));
00129     }
00130         else 
00131         {
00132         return std::make_pair(std::string(), std::string());
00133     }
00134 }
00135 
00136 bool LLAppViewerMacOSX::initParseCommandLine(LLCommandLineParser& clp)
00137 {
00138         // The next two lines add the support for parsing the mac -psn_XXX arg.
00139         clp.addOptionDesc("psn", NULL, 1, "MacOSX process serial number");
00140         clp.setCustomParser(parse_psn);
00141         
00142         // First parse the command line, not often used on the mac.
00143         if(clp.parseCommandLine(gArgC, gArgV) == false)
00144         {
00145                 return false;
00146         }
00147     
00148     // Now read in the args from arguments txt.
00149     // Succesive calls to clp.parse... will NOT override earlier 
00150     // options. 
00151     const char* filename = "arguments.txt";
00152         llifstream ifs(filename, llifstream::binary);
00153         if (!ifs.is_open())
00154         {
00155                 llwarns << "Unable to open file" << filename << llendl;
00156                 return false;
00157         }
00158         
00159         if(clp.parseCommandLineFile(ifs) == false)
00160         {
00161                 return false;
00162         }
00163         
00164         // Get the user's preferred language string based on the Mac OS localization mechanism.
00165         // To add a new localization:
00166                 // go to the "Resources" section of the project
00167                 // get info on "language.txt"
00168                 // in the "General" tab, click the "Add Localization" button
00169                 // create a new localization for the language you're adding
00170                 // set the contents of the new localization of the file to the string corresponding to our localization
00171                 //   (i.e. "en-us", "ja", etc.  Use the existing ones as a guide.)
00172         CFURLRef url = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("language"), CFSTR("txt"), NULL);
00173         char path[MAX_PATH];
00174         if(CFURLGetFileSystemRepresentation(url, false, (UInt8 *)path, sizeof(path)))
00175         {
00176                 LLString lang;
00177                 if(_read_file_into_string(lang, path))          /* Flawfinder: ignore*/
00178                 {
00179             LLControlVariable* c = gSavedSettings.getControl("SystemLanguage");
00180             if(c)
00181             {
00182                 c->setValue(lang, false);
00183             }
00184                 }
00185         }
00186         CFRelease(url);
00187         
00188     return true;
00189 }
00190 
00191 void LLAppViewerMacOSX::handleSyncCrashTrace()
00192 {
00193         // do nothing
00194 }
00195 
00196 void LLAppViewerMacOSX::handleCrashReporting()
00197 {
00198         // Macintosh
00199         LLString command_str;
00200         command_str += "open crashreporter.app";        
00201         
00202         clear_signals();
00203         llinfos << "Launching crash reporter using: '" << command_str << "'" << llendl;
00204         system(command_str.c_str());            /* Flawfinder: ignore */
00205         llinfos << "returned from crash reporter... dying" << llendl;   
00206         _exit(1);
00207 }
00208 
00209 std::string LLAppViewerMacOSX::generateSerialNumber()
00210 {
00211         char serial_md5[MD5HEX_STR_SIZE];               // Flawfinder: ignore
00212         serial_md5[0] = 0;
00213 
00214         // JC: Sample code from http://developer.apple.com/technotes/tn/tn1103.html
00215         CFStringRef serialNumber = NULL;
00216         io_service_t    platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
00217                                                                                                                                  IOServiceMatching("IOPlatformExpertDevice"));
00218         if (platformExpert) {
00219                 serialNumber = (CFStringRef) IORegistryEntryCreateCFProperty(platformExpert,
00220                                                                                                                                          CFSTR(kIOPlatformSerialNumberKey),
00221                                                                                                                                          kCFAllocatorDefault, 0);               
00222                 IOObjectRelease(platformExpert);
00223         }
00224         
00225         if (serialNumber)
00226         {
00227                 char buffer[MAX_STRING];                // Flawfinder: ignore
00228                 if (CFStringGetCString(serialNumber, buffer, MAX_STRING, kCFStringEncodingASCII))
00229                 {
00230                         LLMD5 md5( (unsigned char*)buffer );
00231                         md5.hex_digest(serial_md5);
00232                 }
00233                 CFRelease(serialNumber);
00234         }
00235 
00236         return serial_md5;
00237 }
00238 
00239 OSErr AEGURLHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn)
00240 {
00241         OSErr result = noErr;
00242         DescType actualType;
00243         char buffer[1024];              // Flawfinder: ignore
00244         Size size;
00245         
00246         result = AEGetParamPtr (
00247                 messagein,
00248                 keyDirectObject,
00249                 typeCString,
00250                 &actualType,
00251                 (Ptr)buffer,
00252                 sizeof(buffer),
00253                 &size); 
00254         
00255         if(result == noErr)
00256         {
00257                 std::string url = buffer;
00258                 const bool from_external_browser = true;
00259                 LLURLDispatcher::dispatch(url, from_external_browser);
00260         }
00261         
00262         return(result);
00263 }
00264 
00265 OSErr AEQuitHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn)
00266 {
00267         OSErr result = noErr;
00268         
00269         LLAppViewer::instance()->userQuit();
00270         
00271         return(result);
00272 }
00273 
00274 OSStatus simpleDialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata)
00275 {
00276         OSStatus result = eventNotHandledErr;
00277         OSStatus err;
00278         UInt32 evtClass = GetEventClass(event);
00279         UInt32 evtKind = GetEventKind(event);
00280         WindowRef window = (WindowRef)userdata;
00281         
00282         if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess))
00283         {
00284                 HICommand cmd;
00285                 err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd);
00286                 
00287                 if(err == noErr)
00288                 {
00289                         switch(cmd.commandID)
00290                         {
00291                                 case kHICommandOK:
00292                                         QuitAppModalLoopForWindow(window);
00293                                         result = noErr;
00294                                 break;
00295                                 
00296                                 case kHICommandCancel:
00297                                         QuitAppModalLoopForWindow(window);
00298                                         result = userCanceledErr;
00299                                 break;
00300                         }
00301                 }
00302         }
00303         
00304         return(result);
00305 }
00306 
00307 OSStatus DisplayReleaseNotes(void)
00308 {
00309         OSStatus err;
00310         IBNibRef nib = NULL;
00311         WindowRef window = NULL;
00312         
00313         err = CreateNibReference(CFSTR("SecondLife"), &nib);
00314         
00315         if(err == noErr)
00316         {
00317                 CreateWindowFromNib(nib, CFSTR("Release Notes"), &window);
00318         }
00319                 
00320         if(err == noErr)
00321         {
00322                 // Get the text view control
00323                 HIViewRef textView;
00324                 ControlID id;
00325 
00326                 id.signature = 'text';
00327                 id.id = 0;
00328 
00329                 LLString releaseNotesText;
00330                 
00331                 _read_file_into_string(releaseNotesText, "releasenotes.txt");           // Flawfinder: ignore
00332 
00333                 err = HIViewFindByID(HIViewGetRoot(window), id, &textView);
00334                 
00335                 if(err == noErr)
00336                 {
00337                         // Convert from the encoding used in the release notes.
00338                         CFStringRef str = CFStringCreateWithBytes(
00339                                 NULL, 
00340                                 (const UInt8*)releaseNotesText.c_str(), 
00341                                 releaseNotesText.size(), 
00342                                 kCFStringEncodingWindowsLatin1,                 // This matches the way the Windows version displays the release notes.
00343                                 FALSE);
00344                         
00345                         if(str != NULL)
00346                         {
00347                                 int size = CFStringGetLength(str);
00348 
00349                                 if(size > 0)
00350                                 {
00351                                         UniChar *chars = new UniChar[size + 1];
00352                                         CFStringGetCharacters(str, CFRangeMake(0, size), chars);
00353                                 
00354                                         err = TXNSetData(HITextViewGetTXNObject(textView), kTXNUnicodeTextData, chars, size * sizeof(UniChar), kTXNStartOffset, kTXNStartOffset);
00355                                         
00356                                         delete[] chars;
00357                                 }
00358                                 
00359                                 CFRelease(str);
00360                         }
00361                         else
00362                         {
00363                                 // Creating the string failed.  Probably an encoding problem.  Display SOMETHING...
00364                                 err = TXNSetData(HITextViewGetTXNObject(textView), kTXNTextData, releaseNotesText.c_str(), releaseNotesText.size(), kTXNStartOffset, kTXNStartOffset);
00365                         }
00366                 }
00367                 
00368                 // Set the selection to the beginning of the text and scroll it into view.
00369                 if(err == noErr)
00370                 {
00371                         err = TXNSetSelection(HITextViewGetTXNObject(textView), kTXNStartOffset, kTXNStartOffset);
00372                 }
00373                 
00374                 if(err == noErr)
00375                 {
00376                         // This function returns void.
00377                         TXNShowSelection(HITextViewGetTXNObject(textView), false);
00378                 }
00379         }
00380 
00381         if(err == noErr)
00382         {
00383                 ShowWindow(window);
00384         }
00385 
00386         if(err == noErr)
00387         {
00388                 // Set up an event handler for the window.
00389                 EventHandlerRef handler = NULL;
00390                 EventTypeSpec handlerEvents[] = 
00391                 {
00392                         { kEventClassCommand, kEventCommandProcess }
00393                 };
00394 
00395                 InstallWindowEventHandler(
00396                                 window, 
00397                                 NewEventHandlerUPP(simpleDialogHandler), 
00398                                 GetEventTypeCount (handlerEvents), 
00399                                 handlerEvents, 
00400                                 (void*)window, 
00401                                 &handler);
00402         }
00403                         
00404         if(err == noErr)
00405         {
00406                 RunAppModalLoopForWindow(window);
00407         }
00408                         
00409         if(window != NULL)
00410         {
00411                 DisposeWindow(window);
00412         }
00413         
00414         if(nib != NULL)
00415         {
00416                 DisposeNibReference(nib);
00417         }
00418 
00419         return(err);
00420 }
00421 
00422 void init_apple_menu(const char* product)
00423 {
00424         // Load up a proper menu bar.
00425         {
00426                 OSStatus err;
00427                 IBNibRef nib = NULL;
00428                 // NOTE: DO NOT translate or brand this string.  It's an internal name in the .nib file, and MUST match exactly.
00429                 err = CreateNibReference(CFSTR("SecondLife"), &nib);
00430                 
00431                 if(err == noErr)
00432                 {
00433                         // NOTE: DO NOT translate or brand this string.  It's an internal name in the .nib file, and MUST match exactly.
00434                         SetMenuBarFromNib(nib, CFSTR("MenuBar"));
00435                 }
00436 
00437                 if(nib != NULL)
00438                 {
00439                         DisposeNibReference(nib);
00440                 }
00441         }
00442         
00443         // Install a handler for 'gurl' AppleEvents.  This is how secondlife:// URLs get passed to the viewer.
00444         
00445         if(AEInstallEventHandler('GURL', 'GURL', NewAEEventHandlerUPP(AEGURLHandler),0, false) != noErr)
00446         {
00447                 // Couldn't install AppleEvent handler.  This error shouldn't be fatal.
00448                 llinfos << "Couldn't install 'GURL' AppleEvent handler.  Continuing..." << llendl;
00449         }
00450 
00451         // Install a handler for 'quit' AppleEvents.  This makes quitting the application from the dock work.
00452         if(AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(AEQuitHandler),0, false) != noErr)
00453         {
00454                 // Couldn't install AppleEvent handler.  This error shouldn't be fatal.
00455                 llinfos << "Couldn't install Quit AppleEvent handler.  Continuing..." << llendl;
00456         }
00457 }

Generated on Fri May 16 08:33:15 2008 for SecondLife by  doxygen 1.5.5