llappviewer.cpp

Go to the documentation of this file.
00001 
00033 #include "llviewerprecompiledheaders.h"
00034 #include "llappviewer.h"
00035 #include "llprimitive.h"
00036 
00037 #include "llversionviewer.h"
00038 #include "llfeaturemanager.h"
00039 #include "lluictrlfactory.h"
00040 #include "llalertdialog.h"
00041 #include "llerrorcontrol.h"
00042 #include "llviewerimagelist.h"
00043 #include "llgroupmgr.h"
00044 #include "llagent.h"
00045 #include "llwindow.h"
00046 #include "llviewerstats.h"
00047 #include "llmd5.h"
00048 #include "llpumpio.h"
00049 #include "llimpanel.h"
00050 #include "llmimetypes.h"
00051 #include "llstartup.h"
00052 #include "llfocusmgr.h"
00053 #include "llviewerjoystick.h"
00054 #include "llfloaterjoystick.h"
00055 #include "llares.h" 
00056 #include "llcurl.h"
00057 #include "llfloatersnapshot.h"
00058 #include "llviewerwindow.h"
00059 #include "llviewerdisplay.h"
00060 #include "llviewermessage.h"
00061 #include "llviewerobjectlist.h"
00062 #include "llworldmap.h"
00063 #include "llmutelist.h"
00064 #include "llurldispatcher.h"
00065 #include "llurlhistory.h"
00066 #include "llfirstuse.h"
00067 #include "llglimmediate.h"
00068 
00069 #include "llweb.h"
00070 #include "llsecondlifeurls.h"
00071 
00072 #include <boost/bind.hpp>
00073 
00074 #if LL_WINDOWS
00075         #include "llwindebug.h"
00076 #endif
00077 
00078 #if LL_WINDOWS
00079 #       include <share.h> // For _SH_DENYWR in initMarkerFile
00080 #else
00081 #   include <sys/file.h> // For initMarkerFile support
00082 #endif
00083 
00084 
00085 
00086 #include "llnotify.h"
00087 #include "llviewerkeyboard.h"
00088 #include "lllfsthread.h"
00089 #include "llworkerthread.h"
00090 #include "lltexturecache.h"
00091 #include "lltexturefetch.h"
00092 #include "llimageworker.h"
00093 
00094 // The files below handle dependencies from cleanup.
00095 #include "llkeyframemotion.h"
00096 #include "llworldmap.h"
00097 #include "llhudmanager.h"
00098 #include "lltoolmgr.h"
00099 #include "llassetstorage.h"
00100 #include "llpolymesh.h"
00101 #include "llcachename.h"
00102 #include "audioengine.h"
00103 #include "llviewermenu.h"
00104 #include "llselectmgr.h"
00105 #include "lltrans.h"
00106 #include "lltracker.h"
00107 #include "llviewerparcelmgr.h"
00108 #include "llworldmapview.h"
00109 #include "llpostprocess.h"
00110 #include "llwlparammanager.h"
00111 #include "llwaterparammanager.h"
00112 
00113 #include "lldebugview.h"
00114 #include "llconsole.h"
00115 #include "llcontainerview.h"
00116 #include "llfloaterstats.h"
00117 #include "llhoverview.h"
00118 
00119 #include "llsdserialize.h"
00120 
00121 #include "llworld.h"
00122 #include "llhudeffecttrail.h"
00123 #include "llvectorperfoptions.h"
00124 #include "llurlsimstring.h"
00125 #include "llwatchdog.h"
00126 
00127 // Included so that constants/settings might be initialized
00128 // in save_settings_to_globals()
00129 #include "llbutton.h"
00130 #include "llcombobox.h"
00131 #include "llstatusbar.h"
00132 #include "llsurface.h"
00133 #include "llvosky.h"
00134 #include "llvotree.h"
00135 #include "llvoavatar.h"
00136 #include "llfolderview.h"
00137 #include "lltoolbar.h"
00138 #include "llframestats.h"
00139 #include "llagentpilot.h"
00140 #include "llsrv.h"
00141 #include "llvovolume.h"
00142 #include "llflexibleobject.h" 
00143 #include "llvosurfacepatch.h"
00144 
00145 // includes for idle() idleShutdown()
00146 #include "llviewercontrol.h"
00147 #include "lleventnotifier.h"
00148 #include "llcallbacklist.h"
00149 #include "pipeline.h"
00150 #include "llgesturemgr.h"
00151 #include "llsky.h"
00152 #include "llvlmanager.h"
00153 #include "llviewercamera.h"
00154 #include "lldrawpoolbump.h"
00155 #include "llvieweraudio.h"
00156 #include "llimview.h"
00157 #include "llviewerthrottle.h"
00158 #include "llparcel.h"
00159 // 
00160 
00161 #include "llinventoryview.h"
00162 
00163 #include "llcommandlineparser.h"
00164 
00165 // annoying detail to determine whether font prefs are over-ridden
00166 #if LL_LINUX
00167 # define LL_DYNAMIC_FONT_DISCOVERY 1
00168 #else
00169 # define LL_DYNAMIC_FONT_DISCOVERY 0
00170 #endif
00171 
00172 // *FIX: These extern globals should be cleaned up.
00173 // The globals either represent state/config/resource-storage of either 
00174 // this app, or another 'component' of the viewer. App globals should be 
00175 // moved into the app class, where as the other globals should be 
00176 // moved out of here.
00177 // If a global symbol reference seems valid, it will be included
00178 // via header files above.
00179 
00180 //----------------------------------------------------------------------------
00181 // llviewernetwork.h
00182 #include "llviewernetwork.h"
00183 
00184 
00186 //
00187 #if LL_WINDOWS && LL_LCD_COMPILE
00188         #include "lllcd.h"
00189 #endif
00190 
00191 //----------------------------------------------------------------------------
00192 // viewer.cpp - these are only used in viewer, should be easily moved.
00193 extern void disable_win_error_reporting();
00194 
00195 //#define APPLE_PREVIEW // Define this if you're doing a preview build on the Mac
00196 #if LL_RELEASE_FOR_DOWNLOAD
00197 // Default userserver for production builds is agni
00198 #ifndef APPLE_PREVIEW
00199 static EGridInfo GridDefaultChoice = GRID_INFO_AGNI;
00200 #else
00201 static EGridInfo GridDefaultChoice = GRID_INFO_ADITI;
00202 #endif
00203 #else
00204 // Default userserver for development builds is none
00205 static EGridInfo GridDefaultChoice = GRID_INFO_NONE;
00206 #endif
00207 
00208 #if LL_WINDOWS
00209 extern void create_console();
00210 #endif
00211 
00212 
00213 #if LL_DARWIN
00214 #include <Carbon/Carbon.h>
00215 extern void init_apple_menu(const char* product);
00216 extern OSErr AEGURLHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn);
00217 extern OSErr AEQuitHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn);
00218 extern OSStatus simpleDialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata);
00219 extern OSStatus DisplayReleaseNotes(void);
00220 #include <boost/tokenizer.hpp>
00221 #endif // LL_DARWIN
00222 
00223 
00224 extern BOOL gRandomizeFramerate;
00225 extern BOOL gPeriodicSlowFrame;
00226 extern BOOL gDebugGL;
00227 
00229 // All from the last globals push...
00230 BOOL gHandleKeysAsync = FALSE;
00231 
00232 const F32 DEFAULT_AFK_TIMEOUT = 5.f * 60.f; // time with no input before user flagged as Away From Keyboard
00233 
00234 F32 gSimLastTime; // Used in LLAppViewer::init and send_stats()
00235 F32 gSimFrames;
00236 
00237 LLString gDisabledMessage; // Set in LLAppViewer::initConfiguration used in idle_startup
00238 
00239 BOOL gHideLinks = FALSE; // Set in LLAppViewer::initConfiguration, used externally
00240 
00241 BOOL                            gAllowIdleAFK = TRUE;
00242 BOOL                            gAllowTapTapHoldRun = TRUE;
00243 BOOL                            gShowObjectUpdates = FALSE;
00244 BOOL gUseQuickTime = TRUE;
00245 
00246 BOOL gAcceptTOS = FALSE;
00247 BOOL gAcceptCriticalMessage = FALSE;
00248 
00249 eLastExecEvent gLastExecEvent = LAST_EXEC_NORMAL;
00250 
00251 LLSD gDebugInfo;
00252 
00253 U32     gFrameCount = 0;
00254 U32 gForegroundFrameCount = 0; // number of frames that app window was in foreground
00255 LLPumpIO*                       gServicePump = NULL;
00256 
00257 BOOL gPacificDaylightTime = FALSE;
00258 
00259 U64 gFrameTime = 0;
00260 F32 gFrameTimeSeconds = 0.f;
00261 F32 gFrameIntervalSeconds = 0.f;
00262 F32             gFPSClamped = 10.f;                                             // Pretend we start at target rate.
00263 F32             gFrameDTClamped = 0.f;                                  // Time between adjacent checks to network for packets
00264 U64     gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds
00265 
00266 LLTimer gRenderStartTime;
00267 LLFrameTimer gForegroundTime;
00268 LLTimer                         gLogoutTimer;
00269 static const F32                        LOGOUT_REQUEST_TIME = 6.f;  // this will be cut short by the LogoutReply msg.
00270 F32                                     gLogoutMaxTime = LOGOUT_REQUEST_TIME;
00271 
00272 LLUUID gInventoryLibraryOwner;
00273 LLUUID gInventoryLibraryRoot;
00274 
00275 BOOL                            gDisconnected = FALSE;
00276 
00277 // Map scale in pixels per region
00278 F32                             gMapScale = 128.f;
00279 F32                             gMiniMapScale = 128.f;
00280 
00281 // used to restore texture state after a mode switch
00282 LLFrameTimer    gRestoreGLTimer;
00283 BOOL                    gRestoreGL = FALSE;
00284 BOOL                            gUseWireframe = FALSE;
00285 
00286 // VFS globals - see llappviewer.h
00287 LLVFS* gStaticVFS = NULL;
00288 
00289 LLMemoryInfo gSysMemory;
00290 
00291 LLString gLastVersionChannel;
00292 
00293 LLVector3                       gWindVec(3.0, 3.0, 0.0);
00294 LLVector3                       gRelativeWindVec(0.0, 0.0, 0.0);
00295 
00296 U32             gPacketsIn = 0;
00297 
00298 BOOL                            gPrintMessagesThisFrame = FALSE;
00299 
00300 BOOL gRandomizeFramerate = FALSE;
00301 BOOL gPeriodicSlowFrame = FALSE;
00302 
00303 BOOL gCrashOnStartup = FALSE;
00304 BOOL gLLErrorActivated = FALSE;
00305 BOOL gLogoutInProgress = FALSE;
00307 // Internal globals... that should be removed.
00308 static LLString gArgs;
00309 
00310 const char* MARKER_FILE_NAME = "SecondLife.exec_marker";
00311 const char* ERROR_MARKER_FILE_NAME = "SecondLife.error_marker";
00312 const char* LLERROR_MARKER_FILE_NAME = "SecondLife.llerror_marker";
00313 const char* LOGOUT_MARKER_FILE_NAME = "SecondLife.logout_marker";
00314 static BOOL gDoDisconnect = FALSE;
00315 static LLString gLaunchFileOnQuit;
00316 
00317 //----------------------------------------------------------------------------
00318 // File scope definitons
00319 const char *VFS_DATA_FILE_BASE = "data.db2.x.";
00320 const char *VFS_INDEX_FILE_BASE = "index.db2.x.";
00321 
00322 static LLString gSecondLife;
00323 static LLString gWindowTitle;
00324 #ifdef LL_WINDOWS
00325         static char sWindowClass[] = "Second Life";
00326 #endif
00327 
00328 std::string gLoginPage;
00329 std::vector<std::string> gLoginURIs;
00330 static std::string gHelperURI;
00331 
00332 void idle_afk_check()
00333 {
00334         // check idle timers
00335         if (gAllowIdleAFK && (gAwayTriggerTimer.getElapsedTimeF32() > gSavedSettings.getF32("AFKTimeout")))
00336         {
00337                 gAgent.setAFK();
00338         }
00339 }
00340 
00341 // A callback set in LLAppViewer::init()
00342 static void ui_audio_callback(const LLUUID& uuid)
00343 {
00344         if (gAudiop)
00345         {
00346                 F32 volume = gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI");
00347                 gAudiop->triggerSound(uuid, gAgent.getID(), volume);
00348         }
00349 }
00350 
00351 void request_initial_instant_messages()
00352 {
00353         static BOOL requested = FALSE;
00354         if (!requested
00355                 && gMessageSystem
00356                 && LLMuteList::getInstance()->isLoaded()
00357                 && gAgent.getAvatarObject())
00358         {
00359                 // Auto-accepted inventory items may require the avatar object
00360                 // to build a correct name.  Likewise, inventory offers from
00361                 // muted avatars require the mute list to properly mute.
00362                 LLMessageSystem* msg = gMessageSystem;
00363                 msg->newMessageFast(_PREHASH_RetrieveInstantMessages);
00364                 msg->nextBlockFast(_PREHASH_AgentData);
00365                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
00366                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
00367                 gAgent.sendReliableMessage();
00368                 requested = TRUE;
00369         }
00370 }
00371 
00372 // Use these strictly for things that are constructed at startup,
00373 // or for things that are performance critical.  JC
00374 static void settings_to_globals()
00375 {
00376         LLBUTTON_H_PAD          = gSavedSettings.getS32("ButtonHPad");
00377         LLBUTTON_V_PAD          = gSavedSettings.getS32("ButtonVPad");
00378         BTN_HEIGHT_SMALL        = gSavedSettings.getS32("ButtonHeightSmall");
00379         BTN_HEIGHT                      = gSavedSettings.getS32("ButtonHeight");
00380 
00381         MENU_BAR_HEIGHT         = gSavedSettings.getS32("MenuBarHeight");
00382         MENU_BAR_WIDTH          = gSavedSettings.getS32("MenuBarWidth");
00383         STATUS_BAR_HEIGHT       = gSavedSettings.getS32("StatusBarHeight");
00384 
00385         LLCOMBOBOX_HEIGHT       = BTN_HEIGHT - 2;
00386         LLCOMBOBOX_WIDTH        = 128;
00387 
00388         LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
00389         
00390         LLImageGL::sGlobalUseAnisotropic        = gSavedSettings.getBOOL("RenderAnisotropic");
00391         LLVOVolume::sLODFactor                          = gSavedSettings.getF32("RenderVolumeLODFactor");
00392         LLVOVolume::sDistanceFactor                     = 1.f-LLVOVolume::sLODFactor * 0.1f;
00393         LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor");
00394         LLVOTree::sTreeFactor                           = gSavedSettings.getF32("RenderTreeLODFactor");
00395         LLVOAvatar::sLODFactor                          = gSavedSettings.getF32("RenderAvatarLODFactor");
00396         LLVOAvatar::sMaxVisible                         = gSavedSettings.getS32("RenderAvatarMaxVisible");
00397         LLVOAvatar::sVisibleInFirstPerson       = gSavedSettings.getBOOL("FirstPersonAvatarVisible");
00398         // clamp auto-open time to some minimum usable value
00399         LLFolderView::sAutoOpenTime                     = llmax(0.25f, gSavedSettings.getF32("FolderAutoOpenDelay"));
00400         LLToolBar::sInventoryAutoOpenTime       = gSavedSettings.getF32("InventoryAutoOpenDelay");
00401         LLSelectMgr::sRectSelectInclusive       = gSavedSettings.getBOOL("RectangleSelectInclusive");
00402         LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections");
00403         LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius");
00404 
00405         gFrameStats.setTrackStats(gSavedSettings.getBOOL("StatsSessionTrackFrameStats"));
00406         gAgentPilot.mNumRuns            = gSavedSettings.getS32("StatsNumRuns");
00407         gAgentPilot.mQuitAfterRuns      = gSavedSettings.getBOOL("StatsQuitAfterRuns");
00408         gAgent.mHideGroupTitle          = gSavedSettings.getBOOL("RenderHideGroupTitle");
00409 
00410         gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc");
00411         gAllowIdleAFK = gSavedSettings.getBOOL("AllowIdleAFK");
00412         gAllowTapTapHoldRun = gSavedSettings.getBOOL("AllowTapTapHoldRun");
00413         gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates");
00414         gMapScale = gSavedSettings.getF32("MapScale");
00415         gMiniMapScale = gSavedSettings.getF32("MiniMapScale");
00416         gHandleKeysAsync = gSavedSettings.getBOOL("AsyncKeyboard");
00417         LLHoverView::sShowHoverTips = gSavedSettings.getBOOL("ShowHoverTips");
00418 }
00419 
00420 static void settings_modify()
00421 {
00422         LLRenderTarget::sUseFBO                         = gSavedSettings.getBOOL("RenderUseFBO");
00423         LLVOAvatar::sUseImpostors                       = gSavedSettings.getBOOL("RenderUseImpostors");
00424         LLVOSurfacePatch::sLODFactor            = gSavedSettings.getF32("RenderTerrainLODFactor");
00425         LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //sqaure lod factor to get exponential range of [1,4]
00426         gDebugGL = gSavedSettings.getBOOL("RenderDebugGL");
00427         gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
00428         
00429 #if LL_VECTORIZE
00430         if (gSysCPU.hasAltivec())
00431         {
00432                 gSavedSettings.setBOOL("VectorizeEnable", TRUE );
00433                 gSavedSettings.setU32("VectorizeProcessor", 0 );
00434         }
00435         else
00436         if (gSysCPU.hasSSE2())
00437         {
00438                 gSavedSettings.setBOOL("VectorizeEnable", TRUE );
00439                 gSavedSettings.setU32("VectorizeProcessor", 2 );
00440         }
00441         else
00442         if (gSysCPU.hasSSE())
00443         {
00444                 gSavedSettings.setBOOL("VectorizeEnable", TRUE );
00445                 gSavedSettings.setU32("VectorizeProcessor", 1 );
00446         }
00447         else
00448         {
00449                 // Don't bother testing or running if CPU doesn't support it. JC
00450                 gSavedSettings.setBOOL("VectorizePerfTest", FALSE );
00451                 gSavedSettings.setBOOL("VectorizeEnable", FALSE );
00452                 gSavedSettings.setU32("VectorizeProcessor", 0 );
00453                 gSavedSettings.setBOOL("VectorizeSkin", FALSE);
00454         }
00455 #else
00456         // This build target doesn't support SSE, don't test/run.
00457         gSavedSettings.setBOOL("VectorizePerfTest", FALSE );
00458         gSavedSettings.setBOOL("VectorizeEnable", FALSE );
00459         gSavedSettings.setU32("VectorizeProcessor", 0 );
00460         gSavedSettings.setBOOL("VectorizeSkin", FALSE);
00461 #endif
00462 
00463         // propagate push to talk preference to current status
00464         gSavedSettings.setBOOL("PTTCurrentlyEnabled", TRUE); //gSavedSettings.getBOOL("EnablePushToTalk"));
00465 }
00466 
00467 void initGridChoice()
00468 {
00469     LLString gridChoice = gSavedSettings.getString("GridChoice");
00470     if(!gridChoice.empty())
00471                 // Used to show first chunk of each argument passed in the 
00472                 // window title.
00473     {
00474         // find the grid choice from the user setting.
00475         int gridIndex = GRID_INFO_NONE; 
00476         for(;gridIndex < GRID_INFO_OTHER; ++gridIndex )
00477         {
00478             if(0 == LLString::compareInsensitive(gGridInfo[gridIndex].mLabel, gridChoice.c_str()))
00479             {
00480                 gGridChoice = (EGridInfo)gridIndex;
00481 
00482                 if(GRID_INFO_LOCAL == gGridChoice)
00483                 {
00484                     gGridName = LOOPBACK_ADDRESS_STRING;
00485                     break;
00486                 }
00487                 else
00488                 {
00489                     gGridName = gGridInfo[gGridChoice].mName;
00490                     break;
00491                 }
00492             }
00493         }
00494 
00495         if(GRID_INFO_OTHER == gridIndex)
00496         {
00497                 // *FIX:MEP Can and should we validate that this is an IP address?
00498                 gGridChoice = (EGridInfo)gridIndex;
00499                 gGridName = llformat("%s", gSavedSettings.getString("GridChoice").c_str());
00500 
00501         }
00502     }
00503 
00504 
00505 #if !LL_RELEASE_FOR_DOWNLOAD
00506         if (gGridChoice == GRID_INFO_NONE)
00507         {
00508                 // Development version: load last server choice by default (overridden by cmd line args)
00509                 S32 server = gSavedSettings.getS32("ServerChoice");
00510                 if (server != 0)
00511                         gGridChoice = (EGridInfo)llclamp(server, 0, (S32)GRID_INFO_COUNT - 1);
00512                 if (server == GRID_INFO_OTHER)
00513                 {
00514                         LLString custom_server = gSavedSettings.getString("CustomServer");
00515                         if (custom_server.empty())
00516                         {
00517                                 gGridName = "none";
00518                         }
00519                         else
00520                         {
00521                                 gGridName = custom_server.c_str();
00522                         }
00523                 }
00524 
00525         gSavedSettings.setString("GridChoice", gGridInfo[gGridChoice].mLabel);
00526         }
00527 #endif
00528 
00529         if (gGridChoice == GRID_INFO_NONE)
00530         {
00531                 gGridChoice = GridDefaultChoice;
00532         gSavedSettings.setString("GridChoice", gGridInfo[gGridChoice].mLabel);
00533         }
00534 }
00535 
00536 bool send_url_to_other_instance(const std::string& url)
00537 {
00538 #if LL_WINDOWS
00539         wchar_t window_class[256]; /* Flawfinder: ignore */   // Assume max length < 255 chars.
00540         mbstowcs(window_class, sWindowClass, 255);
00541         window_class[255] = 0;
00542         // Use the class instead of the window name.
00543         HWND other_window = FindWindow(window_class, NULL);
00544 
00545         if (other_window != NULL)
00546         {
00547                 lldebugs << "Found other window with the name '" << gWindowTitle << "'" << llendl;
00548                 COPYDATASTRUCT cds;
00549                 const S32 SLURL_MESSAGE_TYPE = 0;
00550                 cds.dwData = SLURL_MESSAGE_TYPE;
00551                 cds.cbData = url.length() + 1;
00552                 cds.lpData = (void*)url.c_str();
00553 
00554                 LRESULT msg_result = SendMessage(other_window, WM_COPYDATA, NULL, (LPARAM)&cds);
00555                 lldebugs << "SendMessage(WM_COPYDATA) to other window '" 
00556                                  << gWindowTitle << "' returned " << msg_result << llendl;
00557                 return true;
00558         }
00559 #endif
00560         return false;
00561 }
00562 
00563 //----------------------------------------------------------------------------
00564 // LLAppViewer definition
00565 
00566 // Static members.
00567 // The single viewer app.
00568 LLAppViewer* LLAppViewer::sInstance = NULL;
00569 
00570 const std::string LLAppViewer::sGlobalSettingsName = "Global"; 
00571 const std::string LLAppViewer::sPerAccountSettingsName = "PerAccount"; 
00572 const std::string LLAppViewer::sCrashSettingsName = "CrashSettings"; 
00573 
00574 LLTextureCache* LLAppViewer::sTextureCache = NULL; 
00575 LLWorkerThread* LLAppViewer::sImageDecodeThread = NULL; 
00576 LLTextureFetch* LLAppViewer::sTextureFetch = NULL; 
00577 
00578 LLAppViewer::LLAppViewer() : 
00579         mMarkerFile(NULL),
00580         mCrashBehavior(CRASH_BEHAVIOR_ASK),
00581         mReportedCrash(false),
00582         mNumSessions(0),
00583         mPurgeCache(false),
00584         mPurgeOnExit(false),
00585         mSecondInstance(false),
00586         mSavedFinalSnapshot(false),
00587         mQuitRequested(false),
00588         mLogoutRequestSent(false),
00589         mYieldTime(-1)
00590 {
00591         if(NULL != sInstance)
00592         {
00593                 llerrs << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << llendl;
00594         }
00595 
00596         sInstance = this;
00597 
00598         // Initialize the mainloop timeout. 
00599         mMainloopTimeout = new LLWatchdogTimeout();
00600 }
00601 
00602 LLAppViewer::~LLAppViewer()
00603 {
00604         // Initialize the mainloop timeout. 
00605         delete mMainloopTimeout;
00606 
00607         // If we got to this destructor somehow, the app didn't hang.
00608         removeMarkerFile();
00609 }
00610 
00611 bool LLAppViewer::init()
00612 {
00613     // *NOTE:Mani - LLCurl::initClass is not thread safe. 
00614     // Called before threads are created.
00615     LLCurl::initClass();
00616 
00617     initThreads();
00618 
00619 
00620         //
00621         // Start of the application
00622         //
00623         // IMPORTANT! Do NOT put anything that will write
00624         // into the log files during normal startup until AFTER
00625         // we run the "program crashed last time" error handler below.
00626         //
00627 
00628         // Need to do this initialization before we do anything else, since anything
00629         // that touches files should really go through the lldir API
00630         gDirUtilp->initAppDirs("SecondLife");
00631 
00632 
00633         initLogging();
00634         
00635         //
00636         // OK to write stuff to logs now, we've now crash reported if necessary
00637         //
00638     if (!initConfiguration())
00639                 return false;
00640 
00641     writeSystemInfo();
00642 
00643         // Build a string representing the current version number.
00644     gCurrentVersion = llformat("%s %d.%d.%d.%d", 
00645         gSavedSettings.getString("VersionChannelName").c_str(), 
00646         LL_VERSION_MAJOR, 
00647         LL_VERSION_MINOR, 
00648         LL_VERSION_PATCH, 
00649         LL_VERSION_BUILD );
00650 
00655         // *FIX: The following code isn't grouped into functions yet.
00656 
00657         //
00658         // Various introspection concerning the libs we're using.
00659         //
00660         LL_DEBUGS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL;
00661 
00662         // Get the single value from the crash settings file, if it exists
00663         std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
00664         gCrashSettings.loadFromFile(crash_settings_filename.c_str());
00665 
00667         // OS-specific login dialogs
00669 #if LL_WINDOWS
00670         /*
00671         // Display initial login screen, comes up quickly. JC
00672         {
00673                 LLSplashScreen::hide();
00674 
00675                 INT_PTR result = DialogBox(hInstance, L"CONNECTBOX", NULL, login_dialog_func);
00676                 if (result < 0)
00677                 {
00678                         llwarns << "Connect dialog box failed, returned " << result << llendl;
00679                         return 1;
00680                 }
00681                 // success, result contains which button user clicked
00682                 llinfos << "Connect dialog box clicked " << result << llendl;
00683 
00684                 LLSplashScreen::show();
00685         }
00686         */
00687 #endif
00688 
00689         // track number of times that app has run
00690         mNumSessions = gSavedSettings.getS32("NumSessions");
00691         mNumSessions++;
00692         gSavedSettings.setS32("NumSessions", mNumSessions);
00693 
00694         gSavedSettings.setString("HelpLastVisitedURL",gSavedSettings.getString("HelpHomeURL"));
00695 
00696         if (gSavedSettings.getBOOL("VerboseLogs"))
00697         {
00698                 LLError::setPrintLocation(true);
00699         }
00700         
00701         // Load art UUID information, don't require these strings to be declared in code.
00702         LLString colors_base_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "colors_base.xml");
00703         LL_DEBUGS("InitInfo") << "Loading base colors from " << colors_base_filename << LL_ENDL;
00704         gColors.loadFromFileLegacy(colors_base_filename.c_str(), FALSE, TYPE_COL4U);
00705 
00706         // Load overrides from user colors file
00707         LLString user_colors_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "colors.xml");
00708         LL_DEBUGS("InitInfo") << "Loading user colors from " << user_colors_filename << LL_ENDL;
00709         if (gColors.loadFromFileLegacy(user_colors_filename.c_str(), FALSE, TYPE_COL4U) == 0)
00710         {
00711                 LL_DEBUGS("InitInfo") << "Cannot load user colors from " << user_colors_filename << LL_ENDL;
00712         }
00713 
00714         // Widget construction depends on LLUI being initialized
00715         LLUI::initClass(&gSavedSettings, 
00716                                         &gColors, 
00717                                         LLUIImageList::getInstance(),
00718                                         ui_audio_callback,
00719                                         &LLUI::sGLScaleFactor);
00720 
00721         LLWeb::initClass();                       // do this after LLUI
00722         LLUICtrlFactory::getInstance()->setupPaths(); // update paths with correct language set
00723         
00725         //
00726         // Load settings files
00727         //
00728         //
00729         LLGroupMgr::parseRoleActions("role_actions.xml");
00730 
00731         LLAgent::parseTeleportMessages("teleport_strings.xml");
00732 
00733         LLViewerJointMesh::updateVectorize();
00734 
00735         // load MIME type -> media impl mappings
00736         LLMIMETypes::parseMIMETypes( "mime_types.xml" ); 
00737 
00738 
00739         // Copy settings to globals. *TODO: Remove or move to appropriage class initializers
00740         settings_to_globals();
00741         // Setup settings listeners
00742         settings_setup_listeners();
00743         // Modify settings based on system configuration and compile options
00744         settings_modify();
00745 
00746         // Find partition serial number (Windows) or hardware serial (Mac)
00747         mSerialNumber = generateSerialNumber();
00748 
00749         if(false == initHardwareTest())
00750         {
00751                 // Early out from user choice.
00752                 return false;
00753         }
00754 
00755         // Always fetch the Ethernet MAC address, needed both for login
00756         // and password load.
00757         LLUUID::getNodeID(gMACAddress);
00758 
00759         // Prepare for out-of-memory situations, during which we will crash on
00760         // purpose and save a dump.
00761 #if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
00762         MemSetErrorHandler(first_mem_error_handler);
00763 #endif // LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
00764 
00765         // *Note: this is where gViewerStats used to be created.
00766 
00767         //
00768         // Initialize the VFS, and gracefully handle initialization errors
00769         //
00770 
00771         if (!initCache())
00772         {
00773                 std::ostringstream msg;
00774                 msg <<
00775                         gSecondLife << " is unable to access a file that it needs.\n"
00776                         "\n"
00777                         "This can be because you somehow have multiple copies running, "
00778                         "or your system incorrectly thinks a file is open. "
00779                         "If this message persists, restart your computer and try again. "
00780                         "If it continues to persist, you may need to completely uninstall " <<
00781                         gSecondLife << " and reinstall it.";
00782                 OSMessageBox(
00783                         msg.str().c_str(),
00784                         NULL,
00785                         OSMB_OK);
00786                 return 1;
00787         }
00788         
00789         //
00790         // Initialize the window
00791         //
00792         initWindow();
00793 
00794         #if LL_WINDOWS && LL_LCD_COMPILE
00795                 // start up an LCD window on a logitech keyboard, if there is one
00796                 HINSTANCE hInstance = GetModuleHandle(NULL);
00797                 gLcdScreen = new LLLCD(hInstance);
00798                 CreateLCDDebugWindows();
00799         #endif
00800 
00801         gGLManager.getGLInfo(gDebugInfo);
00802         gGLManager.printGLInfoString();
00803 
00804         //load key settings
00805         bind_keyboard_functions();
00806 
00807         // Load Default bindings
00808         if (!gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"keys.ini").c_str()))
00809         {
00810                 LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL;
00811         }
00812         // Load Custom bindings (override defaults)
00813         gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"custom_keys.ini").c_str());
00814 
00815         // If we don't have the right GL requirements, exit.
00816         if (!gGLManager.mHasRequirements && !gNoRender)
00817         {       
00818                 // can't use an alert here since we're existing and
00819                 // all hell breaks lose.
00820                 OSMessageBox(
00821                         LLAlertDialog::getTemplateMessage("UnsupportedGLRequirements").c_str(),
00822                         NULL,
00823                         OSMB_OK);
00824                 return 0;
00825         }
00826 
00827 
00828         bool unsupported = false;
00829         LLString::format_map_t args;
00830         LLString minSpecs;
00831                 
00832         // get cpu data from xml
00833         std::stringstream minCPUString(LLAlertDialog::getTemplateMessage("UnsupportedCPUAmount"));
00834         S32 minCPU = 0;
00835         minCPUString >> minCPU;
00836 
00837         // get RAM data from XML
00838         std::stringstream minRAMString(LLAlertDialog::getTemplateMessage("UnsupportedRAMAmount"));
00839         U64 minRAM = 0;
00840         minRAMString >> minRAM;
00841         minRAM = minRAM * 1024 * 1024;
00842 
00843         if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN)
00844         {
00845                 minSpecs += LLAlertDialog::getTemplateMessage("UnsupportedGPU");
00846                 minSpecs += "\n";
00847                 unsupported = true;
00848         }
00849         if(gSysCPU.getMhz() < minCPU)
00850         {
00851                 minSpecs += LLAlertDialog::getTemplateMessage("UnsupportedCPU");
00852                 minSpecs += "\n";
00853                 unsupported = true;
00854         }
00855         if(gSysMemory.getPhysicalMemoryClamped() < minRAM)
00856         {
00857                 minSpecs += LLAlertDialog::getTemplateMessage("UnsupportedRAM");
00858                 minSpecs += "\n";
00859                 unsupported = true;
00860         }
00861 
00862         if (LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_UNKNOWN)
00863         {
00864                 gViewerWindow->alertXml("UnknownGPU");
00865         } 
00866                 
00867         if(unsupported)
00868         {
00869                 if(!gSavedSettings.controlExists("WarnUnsupportedHardware") 
00870                         || gSavedSettings.getBOOL("WarnUnsupportedHardware"))
00871                 {
00872                         args["MINSPECS"] = minSpecs;
00873                         gViewerWindow->alertXml("UnsupportedHardware", args );
00874                 }
00875 
00876         }
00877         
00878         // Save the current version to the prefs file
00879         gSavedSettings.setString("LastRunVersion", gCurrentVersion);
00880 
00881         gSimLastTime = gRenderStartTime.getElapsedTimeF32();
00882         gSimFrames = (F32)gFrameCount;
00883 
00884         LLViewerJoystick::getInstance()->init(false);
00885 
00886         return true;
00887 }
00888 
00889 bool LLAppViewer::mainLoop()
00890 {
00891         mMainloopTimeout = new LLWatchdogTimeout();
00892         // *FIX:Mani - Make this a setting, once new settings exist in this branch.
00893         mMainloopTimeout->setTimeout(5);
00894         
00895         //-------------------------------------------
00896         // Run main loop until time to quit
00897         //-------------------------------------------
00898 
00899         // Create IO Pump to use for HTTP Requests.
00900         gServicePump = new LLPumpIO(gAPRPoolp);
00901         LLHTTPClient::setPump(*gServicePump);
00902         LLCurl::setCAFile(gDirUtilp->getCAFile());
00903         
00904         // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
00905 
00906         LLVoiceChannel::initClass();
00907         LLVoiceClient::init(gServicePump);
00908                                 
00909         LLMemType mt1(LLMemType::MTYPE_MAIN);
00910         LLTimer frameTimer,idleTimer;
00911         LLTimer debugTime;
00912         LLViewerJoystick* joystick(LLViewerJoystick::getInstance());
00913         joystick->setNeedsReset(true);
00914         
00915         // Handle messages
00916         while (!LLApp::isExiting())
00917         {
00918                 LLFastTimer::reset(); // Should be outside of any timer instances
00919                 try
00920                 {
00921                         LLFastTimer t(LLFastTimer::FTM_FRAME);
00922                         
00923                         {
00924                                 LLFastTimer t2(LLFastTimer::FTM_MESSAGES);
00925                         #if LL_WINDOWS
00926                                 if (!LLWinDebug::checkExceptionHandler())
00927                                 {
00928                                         llwarns << " Someone took over my exception handler (post messagehandling)!" << llendl;
00929                                 }
00930                         #endif
00931 
00932                                 gViewerWindow->mWindow->gatherInput();
00933                         }
00934 
00935 #if 1 && !LL_RELEASE_FOR_DOWNLOAD
00936                         // once per second debug info
00937                         if (debugTime.getElapsedTimeF32() > 1.f)
00938                         {
00939                                 debugTime.reset();
00940                         }
00941 #endif
00942 
00943                         if (!LLApp::isExiting())
00944                         {
00945                                 // Scan keyboard for movement keys.  Command keys and typing
00946                                 // are handled by windows callbacks.  Don't do this until we're
00947                                 // done initializing.  JC
00948                                 if (gViewerWindow->mWindow->getVisible() 
00949                                         && gViewerWindow->getActive()
00950                                         && !gViewerWindow->mWindow->getMinimized()
00951                                         && LLStartUp::getStartupState() == STATE_STARTED
00952                                         && !gViewerWindow->getShowProgress()
00953                                         && !gFocusMgr.focusLocked())
00954                                 {
00955                                         joystick->scanJoystick();
00956                                         gKeyboard->scanKeyboard();
00957                                 }
00958 
00959                                 // Update state based on messages, user input, object idle.
00960                                 {
00961                                         LLFastTimer t3(LLFastTimer::FTM_IDLE);
00962                                         idle();
00963 
00964                                         {
00965                                                 LLFastTimer t4(LLFastTimer::FTM_PUMP);
00966                                                 gAres->process();
00967                                                 // this pump is necessary to make the login screen show up
00968                                                 gServicePump->pump();
00969                                                 gServicePump->callback();
00970                                         }
00971                                 }
00972 
00973                                 if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
00974                                 {
00975                                         saveFinalSnapshot();
00976                                         disconnectViewer();
00977                                 }
00978 
00979                                 // Render scene.
00980                                 if (!LLApp::isExiting())
00981                                 {
00982                                         display();
00983 
00984                                         LLFloaterSnapshot::update(); // take snapshots
00985                                         
00986 #if LL_WINDOWS && LL_LCD_COMPILE
00987                                         // update LCD Screen
00988                                         gLcdScreen->UpdateDisplay();
00989 #endif
00990                                 }
00991 
00992                         }
00993 
00994                         // Sleep and run background threads
00995                         {
00996                                 LLFastTimer t2(LLFastTimer::FTM_SLEEP);
00997                                 bool run_multiple_threads = gSavedSettings.getBOOL("RunMultipleThreads");
00998 
00999                                 // yield some time to the os based on command line option
01000                                 if(mYieldTime >= 0)
01001                                 {
01002                                         ms_sleep(mYieldTime);
01003                                 }
01004 
01005                                 // yield cooperatively when not running as foreground window
01006                                 if (   gNoRender
01007                                                 || !gViewerWindow->mWindow->getVisible()
01008                                                 || !gFocusMgr.getAppHasFocus())
01009                                 {
01010                                         // Sleep if we're not rendering, or the window is minimized.
01011                                         S32 milliseconds_to_sleep = llclamp(gSavedSettings.getS32("BackgroundYieldTime"), 0, 1000);
01012                                         // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads
01013                                         // of equal priority on Windows
01014                                         if (milliseconds_to_sleep > 0)
01015                                         {
01016                                                 ms_sleep(milliseconds_to_sleep);
01017                                                 // also pause worker threads during this wait period
01018                                                 LLAppViewer::getTextureCache()->pause();
01019                                                 LLAppViewer::getImageDecodeThread()->pause();
01020                                         }
01021                                 }
01022                                 
01023                                 if (gRandomizeFramerate)
01024                                 {
01025                                         ms_sleep(rand() % 200);
01026                                 }
01027 
01028                                 if (gPeriodicSlowFrame
01029                                         && (gFrameCount % 10 == 0))
01030                                 {
01031                                         llinfos << "Periodic slow frame - sleeping 500 ms" << llendl;
01032                                         ms_sleep(500);
01033                                 }
01034 
01035 
01036                                 const F64 min_frame_time = 0.0; //(.0333 - .0010); // max video frame rate = 30 fps
01037                                 const F64 min_idle_time = 0.0; //(.0010); // min idle time = 1 ms
01038                                 const F64 max_idle_time = run_multiple_threads ? min_idle_time : llmin(.005*10.0*gFrameTimeSeconds, 0.005); // 5 ms a second
01039                                 idleTimer.reset();
01040                                 while(1)
01041                                 {
01042                                         S32 work_pending = 0;
01043                                         S32 io_pending = 0;
01044                                         work_pending += LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
01045                                         work_pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
01046                                         work_pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
01047                                         io_pending += LLVFSThread::updateClass(1);
01048                                         io_pending += LLLFSThread::updateClass(1);
01049                                         if (io_pending > 1000)
01050                                         {
01051                                                 ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up
01052                                         }
01053 
01054                                         F64 frame_time = frameTimer.getElapsedTimeF64();
01055                                         F64 idle_time = idleTimer.getElapsedTimeF64();
01056                                         if (frame_time >= min_frame_time &&
01057                                                 idle_time >= min_idle_time &&
01058                                                 (!work_pending || idle_time >= max_idle_time))
01059                                         {
01060                                                 break;
01061                                         }
01062                                 }
01063                                 frameTimer.reset();
01064 
01065                                  // Prevent the worker threads from running while rendering.
01066                                 // if (LLThread::processorCount()==1) //pause() should only be required when on a single processor client...
01067                                 if (run_multiple_threads == FALSE)
01068                                 {
01069                                         LLAppViewer::getTextureCache()->pause();
01070                                         LLAppViewer::getImageDecodeThread()->pause();
01071                                         // LLAppViewer::getTextureFetch()->pause(); // Don't pause the fetch (IO) thread
01072                                 }
01073                                 //LLVFSThread::sLocal->pause(); // Prevent the VFS thread from running while rendering.
01074                                 //LLLFSThread::sLocal->pause(); // Prevent the LFS thread from running while rendering.
01075 
01076                                 mMainloopTimeout->ping();
01077                         }
01078                                                 
01079                 }
01080                 catch(std::bad_alloc)
01081                 {
01082                         llwarns << "Bad memory allocation in LLAppViewer::mainLoop()!" << llendl ;
01083                 }
01084         }
01085 
01086         // Save snapshot for next time, if we made it through initialization
01087         if (STATE_STARTED == LLStartUp::getStartupState())
01088         {
01089                 try
01090                 {
01091                         saveFinalSnapshot();
01092                 }
01093                 catch(std::bad_alloc)
01094                 {
01095                         llwarns << "Bad memory allocation when saveFinalSnapshot() is called!" << llendl ;
01096                 }
01097         }
01098         
01099         delete gServicePump;
01100 
01101         mMainloopTimeout->stop();
01102 
01103         llinfos << "Exiting main_loop" << llendflush;
01104 
01105         return true;
01106 }
01107 
01108 bool LLAppViewer::cleanup()
01109 {
01110         //flag all elements as needing to be destroyed immediately
01111         // to ensure shutdown order
01112         LLMortician::setZealous(TRUE);
01113 
01114         LLVoiceClient::terminate();
01115         
01116         disconnectViewer();
01117 
01118         llinfos << "Viewer disconnected" << llendflush;
01119 
01120         display_cleanup(); 
01121 
01122         release_start_screen(); // just in case
01123 
01124         LLError::logToFixedBuffer(NULL);
01125 
01126         llinfos << "Cleaning Up" << llendflush;
01127 
01128         LLKeyframeDataCache::clear();
01129         
01130         // Must clean up texture references before viewer window is destroyed.
01131         LLHUDObject::cleanupHUDObjects();
01132         llinfos << "HUD Objects cleaned up" << llendflush;
01133 
01134         // End TransferManager before deleting systems it depends on (Audio, VFS, AssetStorage)
01135 #if 0 // this seems to get us stuck in an infinite loop...
01136         gTransferManager.cleanup();
01137 #endif
01138         
01139         // Note: this is where gWorldMap used to be deleted.
01140 
01141         // Note: this is where gHUDManager used to be deleted.
01142         LLHUDManager::getInstance()->shutdownClass();
01143         
01144 
01145         delete gAssetStorage;
01146         gAssetStorage = NULL;
01147 
01148         LLPolyMesh::freeAllMeshes();
01149 
01150         delete gCacheName;
01151         gCacheName = NULL;
01152 
01153         // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted.
01154 
01155         LLNotifyBox::cleanup();
01156 
01157         LLWorldMap::getInstance()->reset(); // release any images
01158         
01159         llinfos << "Global stuff deleted" << llendflush;
01160 
01161 #if !LL_RELEASE_FOR_DOWNLOAD
01162         if (gAudiop)
01163         {
01164                 gAudiop->shutdown();
01165         }
01166 #else
01167         // This hack exists because fmod likes to occasionally hang forever
01168         // when shutting down for no apparent reason.
01169         llwarns << "Hack, skipping audio engine cleanup" << llendflush;
01170 #endif
01171 
01172         // Note: this is where LLFeatureManager::getInstance()-> used to be deleted.
01173 
01174         // Patch up settings for next time
01175         // Must do this before we delete the viewer window,
01176         // such that we can suck rectangle information out of
01177         // it.
01178         cleanupSavedSettings();
01179         llinfos << "Settings patched up" << llendflush;
01180 
01181         delete gAudiop;
01182         gAudiop = NULL;
01183 
01184         // delete some of the files left around in the cache.
01185         removeCacheFiles("*.wav");
01186         removeCacheFiles("*.tmp");
01187         removeCacheFiles("*.lso");
01188         removeCacheFiles("*.out");
01189         removeCacheFiles("*.dsf");
01190         removeCacheFiles("*.bodypart");
01191         removeCacheFiles("*.clothing");
01192 
01193         llinfos << "Cache files removed" << llendflush;
01194 
01195 
01196         cleanup_menus();
01197 
01198         // Wait for any pending VFS IO
01199         while (1)
01200         {
01201                 S32 pending = LLVFSThread::updateClass(0);
01202                 pending += LLLFSThread::updateClass(0);
01203                 if (!pending)
01204                 {
01205                         break;
01206                 }
01207                 llinfos << "Waiting for pending IO to finish: " << pending << llendflush;
01208                 ms_sleep(100);
01209         }
01210         llinfos << "Shutting down." << llendflush;
01211         
01212         // Destroy Windows(R) window, and make sure we're not fullscreen
01213         // This may generate window reshape and activation events.
01214         // Therefore must do this before destroying the message system.
01215         delete gViewerWindow;
01216         gViewerWindow = NULL;
01217         llinfos << "ViewerWindow deleted" << llendflush;
01218 
01219         // viewer UI relies on keyboard so keep it aound until viewer UI isa gone
01220         delete gKeyboard;
01221         gKeyboard = NULL;
01222 
01223         // Clean up selection managers after UI is destroyed, as UI
01224         // may be observing them.
01225         LLSelectMgr::cleanupGlobals();
01226 
01227         LLViewerObject::cleanupVOClasses();
01228 
01229         LLWaterParamManager::cleanupClass();
01230         LLWLParamManager::cleanupClass();
01231         LLPostProcess::cleanupClass();
01232 
01233         LLTracker::cleanupInstance();
01234         
01235         // *FIX: This is handled in LLAppViewerWin32::cleanup().
01236         // I'm keeping the comment to remember its order in cleanup,
01237         // in case of unforseen dependency.
01238         //#if LL_WINDOWS
01239         //      gDXHardware.cleanup();
01240         //#endif // LL_WINDOWS
01241 
01242 #if LL_WINDOWS && LL_LCD_COMPILE
01243         // shut down the LCD window on a logitech keyboard, if there is one
01244         delete gLcdScreen;
01245         gLcdScreen = NULL;
01246 #endif
01247 
01248         LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager();
01249         if (!volume_manager->cleanup())
01250         {
01251                 llwarns << "Remaining references in the volume manager!" << llendflush;
01252         }
01253         LLPrimitive::cleanupVolumeManager();
01254 
01255         LLViewerParcelMgr::cleanupGlobals();
01256 
01257         // *Note: this is where gViewerStats used to be deleted.
01258 
01259         //end_messaging_system();
01260 
01261         LLFollowCamMgr::cleanupClass();
01262         //LLVolumeMgr::cleanupClass();
01263         LLPrimitive::cleanupVolumeManager();
01264         LLWorldMapView::cleanupClass();
01265         LLUI::cleanupClass();
01266         
01267         //
01268         // Shut down the VFS's AFTER the decode manager cleans up (since it cleans up vfiles).
01269         // Also after viewerwindow is deleted, since it may have image pointers (which have vfiles)
01270         // Also after shutting down the messaging system since it has VFS dependencies
01271         //
01272         LLVFile::cleanupClass();
01273         llinfos << "VFS cleaned up" << llendflush;
01274 
01275         // Store the time of our current logoff
01276         gSavedPerAccountSettings.setU32("LastLogoff", time_corrected());
01277 
01278         // Must do this after all panels have been deleted because panels that have persistent rects
01279         // save their rects on delete.
01280         gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);        
01281 
01282         // PerAccountSettingsFile should be empty if no use has been logged on.
01283         // *FIX:Mani This should get really saved in a "logoff" mode. 
01284         gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);
01285         llinfos << "Saved settings" << llendflush;
01286 
01287         std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
01288         // save all settings, even if equals defaults
01289         gCrashSettings.saveToFile(crash_settings_filename.c_str(), FALSE);
01290 
01291         gSavedSettings.cleanup();
01292         gColors.cleanup();
01293         gCrashSettings.cleanup();
01294 
01295         // Save URL history file
01296         LLURLHistory::saveFile("url_history.xml");
01297 
01298         // save mute list. gMuteList used to also be deleted here too.
01299         LLMuteList::getInstance()->cache(gAgent.getID());
01300 
01301         if (mPurgeOnExit)
01302         {
01303                 llinfos << "Purging all cache files on exit" << llendflush;
01304                 char mask[LL_MAX_PATH];         /* Flawfinder: ignore */
01305                 snprintf(mask, LL_MAX_PATH, "%s*.*", gDirUtilp->getDirDelimiter().c_str());             /* Flawfinder: ignore */
01306                 gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"").c_str(),mask);
01307         }
01308 
01309         removeMarkerFile(); // Any crashes from here on we'll just have to ignore
01310         
01311         closeDebug();
01312 
01313         // Let threads finish
01314         LLTimer idleTimer;
01315         idleTimer.reset();
01316         const F64 max_idle_time = 5.f; // 5 seconds
01317         while(1)
01318         {
01319                 S32 pending = 0;
01320                 pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread
01321                 pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
01322                 pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
01323                 pending += LLVFSThread::updateClass(0);
01324                 pending += LLLFSThread::updateClass(0);
01325                 F64 idle_time = idleTimer.getElapsedTimeF64();
01326                 if (!pending || idle_time >= max_idle_time)
01327                 {
01328                         llwarns << "Quitting with pending background tasks." << llendl;
01329                         break;
01330                 }
01331         }
01332         
01333         // Delete workers first
01334         // shotdown all worker threads before deleting them in case of co-dependencies
01335         sTextureCache->shutdown();
01336         sTextureFetch->shutdown();
01337         sImageDecodeThread->shutdown();
01338         delete sTextureCache;
01339     sTextureCache = NULL;
01340         delete sTextureFetch;
01341     sTextureFetch = NULL;
01342         delete sImageDecodeThread;
01343     sImageDecodeThread = NULL;
01344 
01345         gImageList.shutdown(); // shutdown again in case a callback added something
01346         
01347         // This should eventually be done in LLAppViewer
01348         LLImageJ2C::closeDSO();
01349         LLImageFormatted::cleanupClass();
01350         LLVFSThread::cleanupClass();
01351         LLLFSThread::cleanupClass();
01352 
01353         llinfos << "VFS Thread finished" << llendflush;
01354 
01355 #ifndef LL_RELEASE_FOR_DOWNLOAD
01356         llinfos << "Auditing VFS" << llendl;
01357         gVFS->audit();
01358 #endif
01359 
01360         // For safety, the LLVFS has to be deleted *after* LLVFSThread. This should be cleaned up.
01361         // (LLVFS doesn't know about LLVFSThread so can't kill pending requests) -Steve
01362         delete gStaticVFS;
01363         gStaticVFS = NULL;
01364         delete gVFS;
01365         gVFS = NULL;
01366 
01367         LLWatchdog::getInstance()->cleanup();
01368 
01369         end_messaging_system();
01370 
01371         // *NOTE:Mani - The following call is not thread safe. 
01372         LLCurl::cleanupClass();
01373 
01374         // If we're exiting to launch an URL, do that here so the screen
01375         // is at the right resolution before we launch IE.
01376         if (!gLaunchFileOnQuit.empty())
01377         {
01378 #if LL_WINDOWS
01379                 // Indicate an application is starting.
01380                 SetCursor(LoadCursor(NULL, IDC_WAIT));
01381 #endif
01382 
01383                 // HACK: Attempt to wait until the screen res. switch is complete.
01384                 ms_sleep(1000);
01385 
01386                 LLWeb::loadURLExternal( gLaunchFileOnQuit );
01387         }
01388 
01389 
01390     llinfos << "Goodbye" << llendflush;
01391         // return 0;
01392         return true;
01393 }
01394 
01395 bool LLAppViewer::initThreads()
01396 {
01397 #if MEM_TRACK_MEM
01398         static const bool enable_threads = false;
01399 #else
01400         static const bool enable_threads = true;
01401 #endif
01402 
01403         LLWatchdog::getInstance()->init();
01404 
01405         LLVFSThread::initClass(enable_threads && true);
01406         LLLFSThread::initClass(enable_threads && true);
01407 
01408         // Image decoding
01409         LLAppViewer::sImageDecodeThread = new LLWorkerThread("ImageDecode", enable_threads && true);
01410         LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true);
01411         LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), enable_threads && false);
01412         LLImageWorker::initClass(LLAppViewer::getImageDecodeThread());
01413         LLImageJ2C::openDSO();
01414 
01415         // *FIX: no error handling here!
01416         return true;
01417 }
01418 
01419 void errorCallback(const std::string &error_string)
01420 {
01421 #ifndef LL_RELEASE_FOR_DOWNLOAD
01422         OSMessageBox(error_string.c_str(), "Fatal Error", OSMB_OK);
01423 #endif
01424 
01425         //Set the ErrorActivated global so we know to create a marker file
01426         gLLErrorActivated = true;
01427         
01428         LLError::crashAndLoop(error_string);
01429 }
01430 
01431 bool LLAppViewer::initLogging()
01432 {
01433         //
01434         // Set up logging defaults for the viewer
01435         //
01436         LLError::initForApplication(
01437                                 gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
01438         LLError::setFatalFunction(errorCallback);
01439         
01440         // Remove the last ".old" log file.
01441         std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
01442                                                              "SecondLife.old");
01443         LLFile::remove(old_log_file.c_str());
01444 
01445         // Rename current log file to ".old"
01446         std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
01447                                                              "SecondLife.log");
01448         LLFile::rename(log_file.c_str(), old_log_file.c_str());
01449 
01450         // Set the log file to SecondLife.log
01451 
01452         LLError::logToFile(log_file);
01453 
01454         // *FIX:Mani no error handling here!
01455         return true;
01456 }
01457 
01458 void LLAppViewer::loadSettingsFromDirectory(ELLPath path_index)
01459 {       
01460         for(LLSD::map_iterator itr = mSettingsFileList.beginMap(); itr != mSettingsFileList.endMap(); ++itr)
01461         {
01462                 LLString settings_name = (*itr).first;
01463                 LLString settings_file = mSettingsFileList[settings_name].asString();
01464 
01465                 LLString full_settings_path = gDirUtilp->getExpandedFilename(path_index, settings_file);
01466 
01467                 if(settings_name == sGlobalSettingsName 
01468                         && path_index == LL_PATH_USER_SETTINGS)
01469                 {
01470                         // The non-persistent setting, ClientSettingsFile, specifies a 
01471                         // custom name to use for the global settings file.
01472                         // Only apply this setting if this method is setting the 'Global' 
01473                         // settings from the user_settings path.
01474                         std::string custom_path;
01475                         if(gSettings[sGlobalSettingsName]->controlExists("ClientSettingsFile"))
01476                         {
01477                                 custom_path = 
01478                                         gSettings[sGlobalSettingsName]->getString("ClientSettingsFile");
01479                         }
01480                         if(!custom_path.empty())
01481                         {
01482                                 full_settings_path = custom_path;
01483                         }
01484                 }
01485 
01486                 if(gSettings.find(settings_name) == gSettings.end())
01487                 {
01488                         llwarns << "Cannot load " << settings_file << " - No matching settings group for name " << settings_name << llendl;
01489                         continue;
01490                 }
01491                 if(!gSettings[settings_name]->loadFromFile(full_settings_path))
01492                 {
01493                         llwarns << "Cannot load " << full_settings_path << " - No settings found." << llendl;
01494                 }
01495                 else
01496                 {
01497                         llinfos << "Loaded settings file " << full_settings_path << llendl;
01498                 }
01499         }
01500 }
01501 
01502 std::string LLAppViewer::getSettingsFileName(const std::string& file)
01503 {
01504         if(mSettingsFileList.has(file))
01505         {
01506                 return mSettingsFileList[file].asString();
01507         }
01508         return std::string();
01509 }
01510 
01511 bool LLAppViewer::initConfiguration()
01512 {       
01513         //Set up internal pointers      
01514         gSettings[sGlobalSettingsName] = &gSavedSettings;
01515         gSettings[sPerAccountSettingsName] = &gSavedPerAccountSettings;
01516         gSettings[sCrashSettingsName] = &gCrashSettings;
01517 
01518         //Load settings files list
01519         std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml");
01520         LLControlGroup settings_control;
01521         llinfos << "Loading settings file list" << settings_file_list << llendl;
01522         if (0 == settings_control.loadFromFile(settings_file_list))
01523         {
01524         llerrs << "Cannot load default configuration file " << settings_file_list << llendl;
01525         }
01526 
01527         mSettingsFileList = settings_control.getLLSD("Files");
01528         
01529         // The settings and command line parsing have a fragile
01530         // order-of-operation:
01531         // - load defaults from app_settings
01532         // - set procedural settings values
01533         // - read command line settings
01534         // - selectively apply settings needed to load user settings.
01535     // - load overrides from user_settings 
01536         // - apply command line settings (to override the overrides)
01537         // - load per account settings (happens in llstartup
01538         
01539         // - load defaults
01540         loadSettingsFromDirectory(LL_PATH_APP_SETTINGS);
01541 
01542         // - set procedural settings 
01543         gSavedSettings.setString("ClientSettingsFile", 
01544         gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFileName("Global")));
01545 
01546         gSavedSettings.setString("VersionChannelName", LL_CHANNEL);
01547 
01548 #ifndef LL_RELEASE_FOR_DOWNLOAD
01549         gSavedSettings.setBOOL("ShowConsoleWindow", TRUE);
01550         gSavedSettings.setBOOL("AllowMultipleViewers", TRUE);
01551 #endif
01552 
01553 #if !LL_DYNAMIC_FONT_DISCOVERY
01554         // static font discovery - user settings can override.
01555         gSavedSettings.setString("FontSansSerifFallback",
01556                                  LLWindow::getFontListSans());
01557 #endif
01558 
01559         // These are warnings that appear on the first experience of that condition.
01560         // They are already set in the settings_default.xml file, but still need to be added to LLFirstUse
01561         // for disable/reset ability
01562         LLFirstUse::addConfigVariable("FirstBalanceIncrease");
01563         LLFirstUse::addConfigVariable("FirstBalanceDecrease");
01564         LLFirstUse::addConfigVariable("FirstSit");
01565         LLFirstUse::addConfigVariable("FirstMap");
01566         LLFirstUse::addConfigVariable("FirstGoTo");
01567         LLFirstUse::addConfigVariable("FirstBuild");
01568         LLFirstUse::addConfigVariable("FirstLeftClickNoHit");
01569         LLFirstUse::addConfigVariable("FirstTeleport");
01570         LLFirstUse::addConfigVariable("FirstOverrideKeys");
01571         LLFirstUse::addConfigVariable("FirstAttach");
01572         LLFirstUse::addConfigVariable("FirstAppearance");
01573         LLFirstUse::addConfigVariable("FirstInventory");
01574         LLFirstUse::addConfigVariable("FirstSandbox");
01575         LLFirstUse::addConfigVariable("FirstFlexible");
01576         LLFirstUse::addConfigVariable("FirstDebugMenus");
01577         LLFirstUse::addConfigVariable("FirstStreamingMusic");
01578         LLFirstUse::addConfigVariable("FirstStreamingVideo");
01579         LLFirstUse::addConfigVariable("FirstSculptedPrim");
01580         LLFirstUse::addConfigVariable("FirstVoice");
01581         LLFirstUse::addConfigVariable("FirstMedia");
01582                 
01584     // *FIX:Mani - Find a way to remove the gUICtrlFactory and
01585     // LLAlertDialog::parseAlerts dependecies on the being loaded
01586     // *before* the user settings. Having to do this init here
01587     // seems odd. 
01588 
01589         // This is where gUICtrlFactory used to be instantiated with a new LLUICtrlFactory
01590         // which needed to happen before calling parseAlerts below.
01591         // TODO: That method is still dependant upon the base LLUICtrlFactory constructor being called
01592         // which registers some callbacks so I'm leaving in a call to getInstance here to cause that to
01593         // still happen. This needs to be cleaned up later when the base and derived classes
01594         // are planned to be combined. -MG
01595         LLUICtrlFactory::getInstance();
01596         
01597 
01598         // Pre-load alerts.xml to define the warnings settings (always loads from skins/xui/en-us/)
01599         // Do this *before* loading the settings file
01600         LLAlertDialog::parseAlerts("alerts.xml", &gSavedSettings, TRUE);
01601 
01602 #if LL_DYNAMIC_FONT_DISCOVERY
01603         // Linux does *dynamic* font discovery which is preferable to
01604         // whatever got written-out into the config file last time.  This
01605         // does remove the ability of the user to hand-define the fallbacks
01606         // though, so from a config-management point of view this is hacky.
01607         gSavedSettings.setString("FontSansSerifFallback",
01608                                  LLWindow::getFontListSans());
01609 #endif
01610 
01611         // - read command line settings.
01612         LLControlGroupCLP clp;
01613         std::string     cmd_line_config = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,
01614                                                                                                                   "cmd_line.xml");
01615         clp.configure(cmd_line_config, &gSavedSettings);
01616 
01617         if(!initParseCommandLine(clp))
01618         {
01619                 llwarns 
01620                         << "Error parsing command line options. Command Line options ignored." 
01621                         << llendl;
01622 
01623                 llinfos << "Command     line usage:\n" << clp << llendl;
01624 
01625                 std::ostringstream msg;
01626                 msg << "Second Life found an error parsing the command line. \n" 
01627                         << "Please see: http://wiki.secondlife.com/wiki/Client_parameters \n"
01628                         << "Error: " << clp.getErrorMessage();
01629 
01630                 OSMessageBox(
01631                         msg.str().c_str(),
01632                         NULL,
01633                         OSMB_OK);
01634 
01635                 return false;
01636         }
01637         
01638         // - selectively apply settings 
01639 
01640         // If the user has specified a alternate settings file name.
01641         // Load it now before loading the user_settings/settings.xml
01642         if(clp.hasOption("settings"))
01643         {
01644                 std::string     user_settings_filename = 
01645                         gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, 
01646                                                                                    clp.getOption("settings")[0]);               
01647                 gSavedSettings.setString("ClientSettingsFile", user_settings_filename);
01648                 llinfos << "Using command line specified settings filename: " 
01649                         << user_settings_filename << llendl;
01650         }
01651 
01652         // - load overrides from user_settings 
01653         loadSettingsFromDirectory(LL_PATH_USER_SETTINGS);
01654 
01655         // - apply command line settings 
01656         clp.notify(); 
01657 
01658         // Handle initialization from settings.
01659         // Start up     the     debugging console before handling other options.
01660         if (gSavedSettings.getBOOL("ShowConsoleWindow"))
01661         {
01662                 initConsole();
01663         }
01664 
01665         if(clp.hasOption("help"))
01666         {
01667                 std::ostringstream msg;
01668                 msg << "Command line usage:\n" << clp;
01669                 llinfos << msg.str() << llendl;
01670 
01671                 OSMessageBox(
01672                         msg.str().c_str(),
01673                         NULL,
01674                         OSMB_OK);
01675 
01676                 return false;
01677         }
01678 
01680     // Apply settings...
01681     if(clp.hasOption("setdefault"))
01682     {
01683         //const LLCommandLineParser::token_vector_t& setdefault = clp.getOption("setdefault");
01684         //if(0x1 & setdefault.size())
01685         //{
01686         //    llwarns << "Invalid '--setdefault' parameter count." << llendl;
01687         //}
01688         //else
01689         //{
01690         //    LLCommandLineParser::token_vector_t::const_iterator itr = setdefault.begin();
01691         //    for(; itr != setdefault.end(); ++itr)
01692         //    {
01693         //        const std::string& name = *itr;
01694         //        const std::string& value = *(++itr);
01695         //        LLControlVariable* c = gSettings[sGlobalSettingsName]->getControl(name);
01696         //        if(c)
01697         //        {
01698         //            c->setDefault(value);
01699         //        }
01700         //        else
01701         //        {
01702         //            llwarns << "'--setdefault' specified with unknown setting: '"
01703         //                << name << "'." << llendl;
01704         //        }
01705         //    }
01706         //}
01707     }
01708 
01709     if(clp.hasOption("set"))
01710     {
01711         const LLCommandLineParser::token_vector_t& set_values = clp.getOption("set");
01712         if(0x1 & set_values.size())
01713         {
01714             llwarns << "Invalid '--set' parameter count." << llendl;
01715         }
01716         else
01717         {
01718             LLCommandLineParser::token_vector_t::const_iterator itr = set_values.begin();
01719             for(; itr != set_values.end(); ++itr)
01720             {
01721                 const std::string& name = *itr;
01722                 const std::string& value = *(++itr);
01723                 LLControlVariable* c = gSettings[sGlobalSettingsName]->getControl(name);
01724                 if(c)
01725                 {
01726                     c->setValue(value, false);
01727                 }
01728                 else
01729                 {
01730                     llwarns << "'--set' specified with unknown setting: '"
01731                         << name << "'." << llendl;
01732                 }
01733             }
01734         }
01735     }
01736 
01737     initGridChoice();
01738 
01739         // If we have specified crash on startup, set the global so we'll trigger the crash at the right time
01740         if(clp.hasOption("crashonstartup"))
01741         {
01742                 gCrashOnStartup = TRUE;
01743         }
01744 
01745         // Handle slurl use. NOTE: Don't let SL-55321 reappear.
01746 
01747     // *FIX: This init code should be made more robust to prevent 
01748     // the issue SL-55321 from returning. One thought is to allow 
01749     // only select options to be set from command line when a slurl 
01750     // is specified. More work on the settings system is needed to 
01751     // achieve this. For now...
01752 
01753     // *NOTE:Mani The command line parser parses tokens and is 
01754     // setup to bail after parsing the '--url' option or the 
01755     // first option specified without a '--option' flag (or
01756     // any other option that uses the 'last_option' setting - 
01757     // see LLControlGroupCLP::configure())
01758 
01759     // What can happen is that someone can use IE (or potentially 
01760     // other browsers) and do the rough equivalent of command 
01761     // injection and steal passwords. Phoenix. SL-55321
01762     if(clp.hasOption("url"))
01763     {
01764         std::string slurl = clp.getOption("url")[0];
01765         if (LLURLDispatcher::isSLURLCommand(slurl))
01766         {
01767                 LLStartUp::sSLURLCommand = slurl;
01768         }
01769         else
01770         {
01771                 LLURLSimString::setString(slurl);
01772         }
01773     }
01774     else if(clp.hasOption("slurl"))
01775     {
01776         std::string slurl = clp.getOption("slurl")[0];
01777         if(LLURLDispatcher::isSLURL(slurl))
01778         {
01779             if (LLURLDispatcher::isSLURLCommand(slurl))
01780             {
01781                     LLStartUp::sSLURLCommand = slurl;
01782             }
01783             else
01784             {
01785                     LLURLSimString::setString(slurl);
01786             }
01787         }
01788     }
01789 
01790     const LLControlVariable* loginuri = gSavedSettings.getControl("LoginURI");
01791     if(loginuri && LLString::null != loginuri->getValue().asString())
01792     {   
01793         addLoginURI(loginuri->getValue().asString());
01794     }
01795 
01796     const LLControlVariable* helperuri = gSavedSettings.getControl("HelperURI");
01797     if(helperuri && LLString::null != helperuri->getValue().asString())
01798     {   
01799         setHelperURI(helperuri->getValue().asString());
01800     }
01801 
01802     const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinFolder");
01803     if(skinfolder && LLString::null != skinfolder->getValue().asString())
01804     {   
01805         gDirUtilp->setSkinFolder(skinfolder->getValue().asString());
01806     }
01807 
01808     mYieldTime = gSavedSettings.getS32("YieldTime");
01809              
01810         // XUI:translate
01811         gSecondLife = "Second Life";
01812 
01813         // Read skin/branding settings if specified.
01814         if (! gDirUtilp->getSkinDir().empty() )
01815         {
01816                 std::string skin_def_file = gDirUtilp->getExpandedFilename(LL_PATH_TOP_SKIN, "skin.xml");
01817                 LLXmlTree skin_def_tree;
01818 
01819                 if (!skin_def_tree.parseFile(skin_def_file))
01820                 {
01821                         llerrs << "Failed to parse skin definition." << llendl;
01822                 }
01823 
01824                 LLXmlTreeNode* rootp = skin_def_tree.getRoot();
01825                 LLXmlTreeNode* disabled_message_node = rootp->getChildByName("disabled_message");       
01826                 if (disabled_message_node)
01827                 {
01828                         gDisabledMessage = disabled_message_node->getContents();
01829                 }
01830 
01831                 static LLStdStringHandle hide_links_string = LLXmlTree::addAttributeString("hide_links");
01832                 rootp->getFastAttributeBOOL(hide_links_string, gHideLinks);
01833 
01834                 // Legacy string.  This flag really meant we didn't want to expose references to "Second Life".
01835                 // Just set gHideLinks instead.
01836                 static LLStdStringHandle silent_string = LLXmlTree::addAttributeString("silent_update");
01837                 BOOL silent_update;
01838                 rootp->getFastAttributeBOOL(silent_string, silent_update);
01839                 gHideLinks = (gHideLinks || silent_update);
01840         }
01841 
01842 #if LL_DARWIN
01843         // Initialize apple menubar and various callbacks
01844         init_apple_menu(gSecondLife.c_str());
01845 
01846 #if __ppc__
01847         // If the CPU doesn't have Altivec (i.e. it's not at least a G4), don't go any further.
01848         // Only test PowerPC - all Intel Macs have SSE.
01849         if(!gSysCPU.hasAltivec())
01850         {
01851                 std::ostringstream msg;
01852                 msg << gSecondLife << " requires a processor with AltiVec (G4 or later).";
01853                 OSMessageBox(
01854                         msg.str().c_str(),
01855                         NULL,
01856                         OSMB_OK);
01857                 removeMarkerFile();
01858                 return false;
01859         }
01860 #endif
01861         
01862 #endif // LL_DARWIN
01863 
01864         // Display splash screen.  Must be after above check for previous
01865         // crash as this dialog is always frontmost.
01866         std::ostringstream splash_msg;
01867         splash_msg << "Loading " << gSecondLife << "...";
01868         LLSplashScreen::show();
01869         LLSplashScreen::update(splash_msg.str().c_str());
01870 
01871         //LLVolumeMgr::initClass();
01872         LLVolumeMgr* volume_manager = new LLVolumeMgr();
01873         volume_manager->useMutex();     // LLApp and LLMutex magic must be manually enabled
01874         LLPrimitive::setVolumeManager(volume_manager);
01875 
01876         // Note: this is where we used to initialize LLFeatureManager::getInstance()->.
01877 
01878         gStartTime = totalTime();
01879 
01880         //
01881         // Set the name of the window
01882         //
01883 #if LL_RELEASE_FOR_DOWNLOAD
01884         gWindowTitle = gSecondLife;
01885 #elif LL_DEBUG
01886         gWindowTitle = gSecondLife + LLString(" [DEBUG] ") + gArgs;
01887 #else
01888         gWindowTitle = gSecondLife + LLString(" ") + gArgs;
01889 #endif
01890         LLString::truncate(gWindowTitle, 255);
01891 
01892         //RN: if we received a URL, hand it off to the existing instance
01893         // don't call anotherInstanceRunning() when doing URL handoff, as
01894         // it relies on checking a marker file which will not work when running
01895         // out of different directories
01896         std::string slurl;
01897         if (!LLStartUp::sSLURLCommand.empty())
01898         {
01899                 slurl = LLStartUp::sSLURLCommand;
01900         }
01901         else if (LLURLSimString::parse())
01902         {
01903                 slurl = LLURLSimString::getURL();
01904         }
01905         if (!slurl.empty())
01906         {
01907                 if (send_url_to_other_instance(slurl))
01908                 {
01909                         // successfully handed off URL to existing instance, exit
01910                         return false;
01911                 }
01912         }
01913 
01914         if (!gSavedSettings.getBOOL("AllowMultipleViewers"))
01915         {
01916             //
01917             // Check for another instance of the app running
01918             //
01919 
01920                 mSecondInstance = anotherInstanceRunning();
01921                 
01922                 if (mSecondInstance)
01923                 {
01924                         std::ostringstream msg;
01925                         msg << 
01926                                 gSecondLife << " is already running.\n"
01927                                 "\n"
01928                                 "Check your task bar for a minimized copy of the program.\n"
01929                                 "If this message persists, restart your computer.",
01930                         OSMessageBox(
01931                                 msg.str().c_str(),
01932                                 NULL,
01933                                 OSMB_OK);
01934                         return false;
01935                 }
01936 
01937                 initMarkerFile();
01938 
01939 #if LL_SEND_CRASH_REPORTS
01940                 if (gLastExecEvent == LAST_EXEC_FROZE)
01941                 {
01942                         llinfos << "Last execution froze, requesting to send crash report." << llendl;
01943                         //
01944                         // Pop up a freeze or crash warning dialog
01945                         //
01946                         std::ostringstream msg;
01947                         msg << gSecondLife
01948                                 << " appears to have frozen or crashed on the previous run.\n"
01949                                 << "Would you like to send a crash report?";
01950                         std::string alert;
01951                         alert = gSecondLife;
01952                         alert += " Alert";
01953                         S32 choice = OSMessageBox(msg.str().c_str(),
01954                                 alert.c_str(),
01955                                 OSMB_YESNO);
01956                         if (OSBTN_YES == choice)
01957                         {
01958                                 llinfos << "Sending crash report." << llendl;
01959 
01960 #if LL_WINDOWS
01961                                 std::string exe_path = gDirUtilp->getAppRODataDir();
01962                                 exe_path += gDirUtilp->getDirDelimiter();
01963                                 exe_path += "win_crash_logger.exe";
01964 
01965                                 std::string arg_string = "-previous ";
01966                                 // Spawn crash logger.
01967                                 // NEEDS to wait until completion, otherwise log files will get smashed.
01968                                 _spawnl(_P_WAIT, exe_path.c_str(), exe_path.c_str(), arg_string.c_str(), NULL);
01969 #elif LL_DARWIN
01970                                 std::string command_str;
01971                                 command_str = "crashreporter.app/Contents/MacOS/crashreporter ";
01972                                 command_str += "-previous";
01973                                 // XXX -- We need to exit fullscreen mode for this to work.
01974                                 // XXX -- system() also doesn't wait for completion.  Hmm...
01975                                 system(command_str.c_str());            /* Flawfinder: Ignore */
01976 #elif LL_LINUX || LL_SOLARIS
01977                                 std::string cmd =gDirUtilp->getAppRODataDir();
01978                                 cmd += gDirUtilp->getDirDelimiter();
01979 #if LL_LINUX
01980                                 cmd += "linux-crash-logger.bin";
01981 #else // LL_SOLARIS
01982                                 cmd += "bin/solaris-crash-logger";
01983 #endif
01984                                 char* const cmdargv[] =
01985                                         {(char*)cmd.c_str(),
01986                                          (char*)"-previous",
01987                                          NULL};
01988                                 pid_t pid = fork();
01989                                 if (pid == 0)
01990                                 { // child
01991                                         execv(cmd.c_str(), cmdargv);            /* Flawfinder: Ignore */
01992                                         llwarns << "execv failure when trying to start " << cmd << llendl;
01993                                         _exit(1); // avoid atexit()
01994                                 } else {
01995                                         if (pid > 0)
01996                                         {
01997                                                 // wait for child proc to die
01998                                                 int childExitStatus;
01999                                                 waitpid(pid, &childExitStatus, 0);
02000                                         } else {
02001                                                 llwarns << "fork failure." << llendl;
02002                                         }
02003                                 }
02004 #endif
02005                         }
02006                         else
02007                         {
02008                                 llinfos << "Not sending crash report." << llendl;
02009                         }
02010                 }
02011 #endif // #if LL_SEND_CRASH_REPORTS
02012         }
02013         else
02014         {
02015                 mSecondInstance = anotherInstanceRunning();
02016                 
02017                 if (mSecondInstance)
02018                 {
02019                         // This is the second instance of SL. Turn off voice support,
02020                         // but make sure the setting is *not* persisted.
02021                         LLControlVariable* disable_voice = gSavedSettings.getControl("CmdLineDisableVoice");
02022                         if(disable_voice)
02023                         {
02024                                 const BOOL DO_NOT_PERSIST = FALSE;
02025                                 disable_voice->setValue(LLSD(TRUE), DO_NOT_PERSIST);
02026                         }
02027                 }
02028 
02029                 initMarkerFile();
02030         }
02031 
02032         // need to do this here - need to have initialized global settings first
02033         LLString nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" );
02034         if ( nextLoginLocation.length() )
02035         {
02036                 LLURLSimString::setString( nextLoginLocation.c_str() );
02037         };
02038 
02039         gLastRunVersion = gSavedSettings.getString("LastRunVersion");
02040 
02041         return true; // Config was successful.
02042 }
02043 
02044 bool LLAppViewer::initWindow()
02045 {
02046         LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL;
02047 
02048         // store setting in a global for easy access and modification
02049         gNoRender = gSavedSettings.getBOOL("DisableRendering");
02050 
02051         // Hide the splash screen
02052         LLSplashScreen::hide();
02053 
02054         // HACK: Need a non-const char * for stupid window name (propagated deep down)
02055         char window_title_str[256];             /* Flawfinder: ignore */
02056         strncpy(window_title_str, gWindowTitle.c_str(), sizeof(window_title_str) - 1);          /* Flawfinder: ignore */
02057         window_title_str[sizeof(window_title_str) - 1] = '\0';
02058 
02059         // always start windowed
02060         BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth");
02061         gViewerWindow = new LLViewerWindow(window_title_str, "Second Life",
02062                 gSavedSettings.getS32("WindowX"), gSavedSettings.getS32("WindowY"),
02063                 gSavedSettings.getS32("WindowWidth"), gSavedSettings.getS32("WindowHeight"),
02064                 FALSE, ignorePixelDepth);
02065                 
02066         if (gSavedSettings.getBOOL("FullScreen"))
02067         {
02068                 gViewerWindow->toggleFullscreen(FALSE);
02069                         // request to go full screen... which will be delayed until login
02070         }
02071         
02072         if (gSavedSettings.getBOOL("WindowMaximized"))
02073         {
02074                 gViewerWindow->mWindow->maximize();
02075                 gViewerWindow->getWindow()->setNativeAspectRatio(gSavedSettings.getF32("FullScreenAspectRatio"));
02076         }
02077 
02078         if (!gNoRender)
02079         {
02080                 //
02081                 // Initialize GL stuff
02082                 //
02083 
02084                 // Set this flag in case we crash while initializing GL
02085                 gSavedSettings.setBOOL("RenderInitError", TRUE);
02086                 gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
02087         
02088                 gPipeline.init();
02089                 stop_glerror();
02090                 gViewerWindow->initGLDefaults();
02091 
02092                 gSavedSettings.setBOOL("RenderInitError", FALSE);
02093                 gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
02094         }
02095 
02096         //If we have a startup crash, it's usually near GL initialization, so simulate that.
02097         if(gCrashOnStartup)
02098         {
02099                 LLAppViewer::instance()->forceErrorLLError();
02100         }
02101 
02102         LLUI::sWindow = gViewerWindow->getWindow();
02103 
02104         LLAlertDialog::parseAlerts("alerts.xml");
02105         LLNotifyBox::parseNotify("notify.xml");
02106         LLTrans::parseStrings("strings.xml");
02107 
02108         // Show watch cursor
02109         gViewerWindow->setCursor(UI_CURSOR_WAIT);
02110 
02111         // Finish view initialization
02112         gViewerWindow->initBase();
02113 
02114         // show viewer window
02115         gViewerWindow->mWindow->show();
02116 
02117         
02118         return true;
02119 }
02120 
02121 void LLAppViewer::closeDebug()
02122 {
02123         std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log");
02124         llinfos << "Opening debug file " << debug_filename << llendl;
02125         std::ofstream out_file(debug_filename.c_str());
02126         LLSDSerialize::toPrettyXML(gDebugInfo, out_file);
02127         out_file.close();
02128 }
02129 
02130 void LLAppViewer::cleanupSavedSettings()
02131 {
02132         gSavedSettings.setBOOL("MouseSun", FALSE);
02133 
02134         gSavedSettings.setBOOL("FlyBtnState", FALSE);
02135 
02136         gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
02137         gSavedSettings.setBOOL("ThirdPersonBtnState", TRUE);
02138         gSavedSettings.setBOOL("BuildBtnState", FALSE);
02139 
02140         gSavedSettings.setBOOL("UseEnergy", TRUE);                              // force toggle to turn off, since sends message to simulator
02141 
02142         gSavedSettings.setBOOL("DebugWindowProc", gDebugWindowProc);
02143                 
02144         gSavedSettings.setBOOL("AllowIdleAFK", gAllowIdleAFK);
02145         gSavedSettings.setBOOL("AllowTapTapHoldRun", gAllowTapTapHoldRun);
02146         gSavedSettings.setBOOL("ShowObjectUpdates", gShowObjectUpdates);
02147         
02148         if (!gNoRender)
02149         {
02150                 if (gDebugView)
02151                 {
02152                         gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible());
02153                         gSavedSettings.setBOOL("ShowDebugStats", gDebugView->mFloaterStatsp->getVisible());
02154                 }
02155         }
02156 
02157         // save window position if not fullscreen
02158         // as we don't track it in callbacks
02159         BOOL fullscreen = gViewerWindow->mWindow->getFullscreen();
02160         BOOL maximized = gViewerWindow->mWindow->getMaximized();
02161         if (!fullscreen && !maximized)
02162         {
02163                 LLCoordScreen window_pos;
02164 
02165                 if (gViewerWindow->mWindow->getPosition(&window_pos))
02166                 {
02167                         gSavedSettings.setS32("WindowX", window_pos.mX);
02168                         gSavedSettings.setS32("WindowY", window_pos.mY);
02169                 }
02170         }
02171 
02172         gSavedSettings.setF32("MapScale", gMapScale );
02173         gSavedSettings.setF32("MiniMapScale", gMiniMapScale );
02174         gSavedSettings.setBOOL("AsyncKeyboard", gHandleKeysAsync);
02175         gSavedSettings.setBOOL("ShowHoverTips", LLHoverView::sShowHoverTips);
02176 
02177         // Some things are cached in LLAgent.
02178         if (gAgent.mInitialized)
02179         {
02180                 gSavedSettings.setF32("RenderFarClip", gAgent.mDrawDistance);
02181         }
02182 
02183         // *REMOVE: This is now done via LLAppViewer::setCrashBehavior()
02184         // Left vestigially in case I borked it.
02185         // gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, gCrashBehavior);
02186 }
02187 
02188 void LLAppViewer::removeCacheFiles(const char* file_mask)
02189 {
02190         char mask[LL_MAX_PATH];         /* Flawfinder: ignore */
02191         snprintf(mask, LL_MAX_PATH, "%s%s", gDirUtilp->getDirDelimiter().c_str(), file_mask);           /* Flawfinder: ignore */
02192         gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "").c_str(), mask);
02193 }
02194 
02195 void LLAppViewer::writeSystemInfo()
02196 {
02197         gDebugInfo["SLLog"] = LLError::logFileName();
02198 
02199         gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName");
02200         gDebugInfo["ClientInfo"]["MajorVersion"] = LL_VERSION_MAJOR;
02201         gDebugInfo["ClientInfo"]["MinorVersion"] = LL_VERSION_MINOR;
02202         gDebugInfo["ClientInfo"]["PatchVersion"] = LL_VERSION_PATCH;
02203         gDebugInfo["ClientInfo"]["BuildVersion"] = LL_VERSION_BUILD;
02204 
02205         gDebugInfo["CPUInfo"]["CPUString"] = gSysCPU.getCPUString();
02206         gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily();
02207         gDebugInfo["CPUInfo"]["CPUMhz"] = gSysCPU.getMhz();
02208         gDebugInfo["CPUInfo"]["CPUAltivec"] = gSysCPU.hasAltivec();
02209         gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE();
02210         gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2();
02211         
02212         gDebugInfo["RAMInfo"] = llformat("%u", gSysMemory.getPhysicalMemoryKB());
02213         gDebugInfo["OSInfo"] = getOSInfo().getOSStringSimple();
02214 
02215         // Dump some debugging info
02216         LL_INFOS("SystemInfo") << gSecondLife
02217                         << " version " << LL_VERSION_MAJOR << "." << LL_VERSION_MINOR << "." << LL_VERSION_PATCH
02218                         << LL_ENDL;
02219 
02220         // Dump the local time and time zone
02221         time_t now;
02222         time(&now);
02223         char tbuffer[256];              /* Flawfinder: ignore */
02224         strftime(tbuffer, 256, "%Y-%m-%dT%H:%M:%S %Z", localtime(&now));
02225         LL_INFOS("SystemInfo") << "Local time: " << tbuffer << LL_ENDL;
02226 
02227         // query some system information
02228         LL_INFOS("SystemInfo") << "CPU info:\n" << gSysCPU << LL_ENDL;
02229         LL_INFOS("SystemInfo") << "Memory info:\n" << gSysMemory << LL_ENDL;
02230         LL_INFOS("SystemInfo") << "OS: " << getOSInfo().getOSStringSimple() << LL_ENDL;
02231         LL_INFOS("SystemInfo") << "OS info: " << getOSInfo() << LL_ENDL;
02232 }
02233 
02234 void LLAppViewer::handleSyncViewerCrash()
02235 {
02236         LLAppViewer* pApp = LLAppViewer::instance();
02237         // Call to pure virtual, handled by platform specific llappviewer instance.
02238         pApp->handleSyncCrashTrace(); 
02239 }
02240 
02241 void LLAppViewer::handleViewerCrash()
02242 {
02243         llinfos << "Handle viewer crash entry." << llendl;
02244         
02245         LLAppViewer* pApp = LLAppViewer::instance();
02246         if (pApp->beingDebugged())
02247         {
02248                 // This will drop us into the debugger.
02249                 abort();
02250         }
02251 
02252         // Returns whether a dialog was shown.
02253         // Only do the logic in here once
02254         if (pApp->mReportedCrash)
02255         {
02256                 return;
02257         }
02258         pApp->mReportedCrash = TRUE;
02259 
02260         //We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version
02261         //to check against no matter what
02262         gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName");
02263 
02264         gDebugInfo["ClientInfo"]["MajorVersion"] = LL_VERSION_MAJOR;
02265         gDebugInfo["ClientInfo"]["MinorVersion"] = LL_VERSION_MINOR;
02266         gDebugInfo["ClientInfo"]["PatchVersion"] = LL_VERSION_PATCH;
02267         gDebugInfo["ClientInfo"]["BuildVersion"] = LL_VERSION_BUILD;
02268 
02269         LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
02270         if ( parcel && parcel->getMusicURL()[0])
02271         {
02272                 gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL();
02273         }       
02274         if ( parcel && parcel->getMediaURL()[0])
02275         {
02276                 gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL();
02277         }
02278         
02279         
02280         gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile");
02281         gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
02282         gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName().c_str();
02283         gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath().c_str();
02284         if(gLogoutInProgress)
02285         {
02286                 gDebugInfo["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH;
02287         }
02288         else
02289         {
02290                 gDebugInfo["LastExecEvent"] = gLLErrorActivated ? LAST_EXEC_LLERROR_CRASH : LAST_EXEC_OTHER_CRASH;
02291         }
02292 
02293         if(gAgent.getRegion())
02294         {
02295                 gDebugInfo["CurrentSimHost"] = gAgent.getRegionHost().getHostName();
02296                 gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName();
02297         }
02298 
02299         //Write out the crash status file
02300         //Use marker file style setup, as that's the simplest, especially since
02301         //we're already in a crash situation    
02302         if (gDirUtilp)
02303         {
02304                 LLString crash_file_name;
02305                 if(gLLErrorActivated) crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LLERROR_MARKER_FILE_NAME);
02306                 else crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,ERROR_MARKER_FILE_NAME);
02307                 llinfos << "Creating crash marker file " << crash_file_name << llendl;
02308                 apr_file_t* crash_file =  ll_apr_file_open(crash_file_name, LL_APR_W);
02309                 if (crash_file)
02310                 {
02311                         LL_INFOS("MarkerFile") << "Created crash marker file " << crash_file_name << LL_ENDL;
02312                 }
02313                 else
02314                 {
02315                         LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_file_name << LL_ENDL;
02316                 }
02317                 apr_file_close(crash_file);
02318         }
02319         
02320         if (gMessageSystem && gDirUtilp)
02321         {
02322                 std::string filename;
02323                 filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "stats.log");
02324                 llofstream file(filename.c_str(), llofstream::binary);
02325                 if(file.good())
02326                 {
02327                         llinfos << "Handle viewer crash generating stats log." << llendl;
02328                         gMessageSystem->summarizeLogs(file);
02329                         file.close();
02330                 }
02331         }
02332 
02333         if (gMessageSystem)
02334         {
02335                 gMessageSystem->getCircuitInfo(gDebugInfo["CircuitInfo"]);
02336                 gMessageSystem->stopLogging();
02337         }
02338 
02339         LLWorld::getInstance()->getInfo(gDebugInfo);
02340 
02341         // Close the debug file
02342         pApp->closeDebug();
02343 
02344         LLError::logToFile("");
02345 
02346         // Remove the marker file, since otherwise we'll spawn a process that'll keep it locked
02347         if(gDebugInfo["LastExecEvent"].asInteger() == LAST_EXEC_LOGOUT_CRASH)
02348         {
02349                 pApp->removeMarkerFile(true);
02350         }
02351         else
02352         {
02353                 pApp->removeMarkerFile(false);
02354         }
02355         
02356         // Call to pure virtual, handled by platform specific llappviewer instance.
02357         pApp->handleCrashReporting(); 
02358 
02359         return;
02360 }
02361 
02362 void LLAppViewer::setCrashBehavior(S32 cb) 
02363 { 
02364         mCrashBehavior = cb; 
02365         gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, mCrashBehavior);
02366 } 
02367 
02368 bool LLAppViewer::anotherInstanceRunning()
02369 {
02370         // We create a marker file when the program starts and remove the file when it finishes.
02371         // If the file is currently locked, that means another process is already running.
02372 
02373         std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, MARKER_FILE_NAME);
02374         LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;
02375 
02376         //Freeze case checks
02377         apr_file_t* fMarker = ll_apr_file_open(marker_file, LL_APR_RB);         
02378         if (fMarker != NULL)
02379         {
02380                 // File exists, try opening with write permissions
02381                 apr_file_close(fMarker);
02382                 fMarker = ll_apr_file_open(marker_file, LL_APR_WB);
02383                 if (fMarker == NULL)
02384                 {
02385                         // Another instance is running. Skip the rest of these operations.
02386                         LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
02387                         return TRUE;
02388                 }
02389                 if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) //flock(fileno(fMarker), LOCK_EX | LOCK_NB) == -1)
02390                 {
02391                         apr_file_close(fMarker);
02392                         LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
02393                         return TRUE;
02394                 }
02395                 // No other instances; we'll lock this file now & delete on quit.
02396                 apr_file_close(fMarker);
02397         }
02398         LL_DEBUGS("MarkerFile") << "Marker file isn't locked." << LL_ENDL;
02399         return FALSE;
02400 }
02401 
02402 void LLAppViewer::initMarkerFile()
02403 {
02404 
02405         //First, check for the existence of other files.
02406         //There are marker files for two different types of crashes
02407         
02408         mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME);
02409         LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;
02410 
02411         //We've got 4 things to test for here
02412         // - Other Process Running (SecondLife.exec_marker present, locked)
02413         // - Freeze (SecondLife.exec_marker present, not locked)
02414         // - LLError Crash (SecondLife.llerror_marker present)
02415         // - Other Crash (SecondLife.error_marker present)
02416         // These checks should also remove these files for the last 2 cases if they currently exist
02417 
02418         //LLError/Error checks. Only one of these should ever happen at a time.
02419         LLString logout_marker_file =  gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME);
02420         LLString llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);
02421         LLString error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
02422 
02423         apr_file_t* fMarker = ll_apr_file_open(logout_marker_file, LL_APR_RB);
02424         if(fMarker != NULL)
02425         {
02426                 apr_file_close(fMarker);
02427                 LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << LL_ENDL;
02428                 gLastExecEvent = LAST_EXEC_LOGOUT_FROZE;
02429         }       
02430         fMarker = ll_apr_file_open(llerror_marker_file, LL_APR_RB);
02431         if(fMarker != NULL)
02432         {
02433                 apr_file_close(fMarker);
02434                 llinfos << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << llendl;
02435                 if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
02436                 else gLastExecEvent = LAST_EXEC_LLERROR_CRASH;
02437         }
02438         fMarker = ll_apr_file_open(error_marker_file, LL_APR_RB);
02439         if(fMarker != NULL)
02440         {
02441                 apr_file_close(fMarker);
02442                 LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << LAST_EXEC_OTHER_CRASH << LL_ENDL;
02443                 if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
02444                 else gLastExecEvent = LAST_EXEC_OTHER_CRASH;
02445         }
02446 
02447         ll_apr_file_remove(logout_marker_file);
02448         ll_apr_file_remove(llerror_marker_file);
02449         ll_apr_file_remove(error_marker_file);
02450         
02451         //Freeze case checks
02452         if(anotherInstanceRunning()) 
02453         {
02454                 return;
02455         }
02456         
02457         fMarker = ll_apr_file_open(mMarkerFileName, LL_APR_RB);         
02458         if (fMarker != NULL)
02459         {
02460                 apr_file_close(fMarker);
02461                 gLastExecEvent = LAST_EXEC_FROZE;
02462                 LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL;
02463         }
02464 
02465         // Create the marker file for this execution & lock it
02466         mMarkerFile =  ll_apr_file_open(mMarkerFileName, LL_APR_W);
02467         if (mMarkerFile)
02468         {
02469                 LL_DEBUGS("MarkerFile") << "Marker file created." << LL_ENDL;
02470         }
02471         else
02472         {
02473                 LL_INFOS("MarkerFile") << "Failed to create marker file." << LL_ENDL;
02474                 return;
02475         }
02476         if (apr_file_lock(mMarkerFile, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) 
02477         {
02478                 apr_file_close(mMarkerFile);
02479                 LL_INFOS("MarkerFile") << "Marker file cannot be locked." << LL_ENDL;
02480                 return;
02481         }
02482 
02483         LL_DEBUGS("MarkerFile") << "Marker file locked." << LL_ENDL;
02484 }
02485 
02486 void LLAppViewer::removeMarkerFile(bool leave_logout_marker)
02487 {
02488         LL_DEBUGS("MarkerFile") << "removeMarkerFile()" << LL_ENDL;
02489         if (mMarkerFile != NULL)
02490         {
02491                 ll_apr_file_remove( mMarkerFileName );
02492                 mMarkerFile = NULL;
02493         }
02494         if (mLogoutMarkerFile != NULL && !leave_logout_marker)
02495         {
02496                 ll_apr_file_remove( mLogoutMarkerFileName );
02497                 mLogoutMarkerFile = NULL;
02498         }
02499 }
02500 
02501 void LLAppViewer::forceQuit()
02502 { 
02503         LLApp::setQuitting(); 
02504 }
02505 
02506 void LLAppViewer::requestQuit()
02507 {
02508         llinfos << "requestQuit" << llendl;
02509 
02510         LLViewerRegion* region = gAgent.getRegion();
02511         
02512         if( (LLStartUp::getStartupState() < STATE_STARTED) || !region )
02513         {
02514                 // Quit immediately
02515                 forceQuit();
02516                 return;
02517         }
02518 
02519         LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
02520         effectp->setPositionGlobal(gAgent.getPositionGlobal());
02521         effectp->setColor(LLColor4U(gAgent.getEffectColor()));
02522         LLHUDManager::getInstance()->sendEffects();
02523 
02524         // Attempt to close all floaters that might be
02525         // editing things.
02526         if (gFloaterView)
02527         {
02528                 // application is quitting
02529                 gFloaterView->closeAllChildren(true);
02530         }
02531 
02532         send_stats();
02533 
02534         gLogoutTimer.reset();
02535         mQuitRequested = true;
02536 }
02537 
02538 static void finish_quit(S32 option, void *userdata)
02539 {
02540         if (option == 0)
02541         {
02542                 LLAppViewer::instance()->requestQuit();
02543         }
02544 }
02545 
02546 void LLAppViewer::userQuit()
02547 {
02548         gViewerWindow->alertXml("ConfirmQuit", finish_quit, NULL);
02549 }
02550 
02551 static void finish_early_exit(S32 option, void* userdata)
02552 {
02553         LLAppViewer::instance()->forceQuit();
02554 }
02555 
02556 void LLAppViewer::earlyExit(const LLString& msg)
02557 {
02558         llwarns << "app_early_exit: " << msg << llendl;
02559         gDoDisconnect = TRUE;
02560 //      LLStringBase<char>::format_map_t args;
02561 //      args["[MESSAGE]"] = mesg;
02562 //      gViewerWindow->alertXml("AppEarlyExit", args, finish_early_exit);
02563         LLAlertDialog::showCritical(msg, finish_early_exit, NULL);
02564 }
02565 
02566 void LLAppViewer::forceExit(S32 arg)
02567 {
02568     removeMarkerFile();
02569     
02570     // *FIX:Mani - This kind of exit hardly seems appropriate.
02571     exit(arg);
02572 }
02573 
02574 void LLAppViewer::abortQuit()
02575 {
02576     llinfos << "abortQuit()" << llendl;
02577         mQuitRequested = false;
02578 }
02579 
02580 bool LLAppViewer::initCache()
02581 {
02582         mPurgeCache = false;
02583         // Purge cache if user requested it
02584         if (gSavedSettings.getBOOL("PurgeCacheOnStartup") ||
02585                 gSavedSettings.getBOOL("PurgeCacheOnNextStartup"))
02586         {
02587                 gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false);
02588                 mPurgeCache = true;
02589         }
02590         // Purge cache if it belongs to an old version
02591         else
02592         {
02593                 static const S32 cache_version = 5;
02594                 if (gSavedSettings.getS32("LocalCacheVersion") != cache_version)
02595                 {
02596                         mPurgeCache = true;
02597                         gSavedSettings.setS32("LocalCacheVersion", cache_version);
02598                 }
02599         }
02600         
02601         // Setup and verify the cache location
02602         LLString cache_location = gSavedSettings.getString("CacheLocation");
02603         LLString new_cache_location = gSavedSettings.getString("NewCacheLocation");
02604         if (new_cache_location != cache_location)
02605         {
02606                 gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"));
02607                 purgeCache(); // purge old cache
02608                 gSavedSettings.setString("CacheLocation", new_cache_location);
02609         }
02610         
02611         if (!gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")))
02612         {
02613                 LL_WARNS("AppCache") << "Unable to set cache location" << LL_ENDL;
02614                 gSavedSettings.setString("CacheLocation", "");
02615         }
02616         
02617         if (mPurgeCache)
02618         {
02619                 LLSplashScreen::update("Clearing cache...");
02620                 purgeCache();
02621         }
02622 
02623         LLSplashScreen::update("Initializing Texture Cache...");
02624         
02625         // Init the texture cache
02626         // Allocate 80% of the cache size for textures
02627         BOOL read_only = mSecondInstance ? true : false;
02628         const S32 MB = 1024*1024;
02629         S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB;
02630         const S64 MAX_CACHE_SIZE = 1024*MB;
02631         cache_size = llmin(cache_size, MAX_CACHE_SIZE);
02632         S64 texture_cache_size = ((cache_size * 8)/10);
02633         S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, read_only);
02634         texture_cache_size -= extra;
02635 
02636         LLSplashScreen::update("Initializing VFS...");
02637         
02638         // Init the VFS
02639         S64 vfs_size = cache_size - texture_cache_size;
02640         const S64 MAX_VFS_SIZE = 1024 * MB; // 1 GB
02641         vfs_size = llmin(vfs_size, MAX_VFS_SIZE);
02642         vfs_size = (vfs_size / MB) * MB; // make sure it is MB aligned
02643         U32 vfs_size_u32 = (U32)vfs_size;
02644         U32 old_vfs_size = gSavedSettings.getU32("VFSOldSize") * MB;
02645         bool resize_vfs = (vfs_size_u32 != old_vfs_size);
02646         if (resize_vfs)
02647         {
02648                 gSavedSettings.setU32("VFSOldSize", vfs_size_u32/MB);
02649         }
02650         LL_INFOS("AppCache") << "VFS CACHE SIZE: " << vfs_size/(1024*1024) << " MB" << LL_ENDL;
02651         
02652         // This has to happen BEFORE starting the vfs
02653         //time_t        ltime;
02654         srand(time(NULL));              // Flawfinder: ignore
02655         U32 old_salt = gSavedSettings.getU32("VFSSalt");
02656         U32 new_salt;
02657         char old_vfs_data_file[LL_MAX_PATH];            // Flawfinder: ignore
02658         char old_vfs_index_file[LL_MAX_PATH];   // Flawfinder: ignore           
02659         char new_vfs_data_file[LL_MAX_PATH];            // Flawfinder: ignore
02660         char new_vfs_index_file[LL_MAX_PATH];   // Flawfinder: ignore
02661         char static_vfs_index_file[LL_MAX_PATH];        // Flawfinder: ignore
02662         char static_vfs_data_file[LL_MAX_PATH]; // Flawfinder: ignore
02663 
02664         if (gSavedSettings.getBOOL("AllowMultipleViewers"))
02665         {
02666                 // don't mess with renaming the VFS in this case
02667                 new_salt = old_salt;
02668         }
02669         else
02670         {
02671                 do
02672                 {
02673                         new_salt = rand();
02674                 } while( new_salt == old_salt );
02675         }
02676 
02677         snprintf(old_vfs_data_file,  LL_MAX_PATH, "%s%u",               // Flawfinder: ignore
02678                 gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE).c_str(),
02679                 old_salt);
02680 
02681         // make sure this file exists
02682         llstat s;
02683         S32 stat_result = LLFile::stat(old_vfs_data_file, &s);
02684         if (stat_result)
02685         {
02686                 // doesn't exist, look for a data file
02687                 std::string mask;
02688                 mask = gDirUtilp->getDirDelimiter();
02689                 mask += VFS_DATA_FILE_BASE;
02690                 mask += "*";
02691 
02692                 std::string dir;
02693                 dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");
02694 
02695                 std::string found_file;
02696                 if (gDirUtilp->getNextFileInDir(dir, mask, found_file, false))
02697                 {
02698                         snprintf(old_vfs_data_file, LL_MAX_PATH, "%s%s%s", dir.c_str(), gDirUtilp->getDirDelimiter().c_str(), found_file.c_str());              // Flawfinder: ignore
02699 
02700                         S32 start_pos;
02701                         S32 length = strlen(found_file.c_str());                /* Flawfinder: ignore*/
02702                         for (start_pos = length - 1; start_pos >= 0; start_pos--)
02703                         {
02704                                 if (found_file[start_pos] == '.')
02705                                 {
02706                                         start_pos++;
02707                                         break;
02708                                 }
02709                         }
02710                         if (start_pos > 0)
02711                         {
02712                                 sscanf(found_file.c_str() + start_pos, "%d", &old_salt);
02713                         }
02714                         LL_DEBUGS("AppCache") << "Default vfs data file not present, found: " << old_vfs_data_file << " Old salt: " << old_salt << llendl;
02715                 }
02716         }
02717 
02718         snprintf(old_vfs_index_file, LL_MAX_PATH, "%s%u",               // Flawfinder: ignore
02719                         gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_INDEX_FILE_BASE).c_str(),
02720                         old_salt);
02721 
02722         stat_result = LLFile::stat(old_vfs_index_file, &s);
02723         if (stat_result)
02724         {
02725                 // We've got a bad/missing index file, nukem!
02726                 LL_WARNS("AppCache") << "Bad or missing vfx index file " << old_vfs_index_file << LL_ENDL;
02727                 LL_WARNS("AppCache") << "Removing old vfs data file " << old_vfs_data_file << LL_ENDL;
02728                 LLFile::remove(old_vfs_data_file);
02729                 LLFile::remove(old_vfs_index_file);
02730                 
02731                 // Just in case, nuke any other old cache files in the directory.
02732                 std::string dir;
02733                 dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");
02734 
02735                 std::string mask;
02736                 mask = gDirUtilp->getDirDelimiter();
02737                 mask += VFS_DATA_FILE_BASE;
02738                 mask += "*";
02739 
02740                 gDirUtilp->deleteFilesInDir(dir, mask);
02741 
02742                 mask = gDirUtilp->getDirDelimiter();
02743                 mask += VFS_INDEX_FILE_BASE;
02744                 mask += "*";
02745 
02746                 gDirUtilp->deleteFilesInDir(dir, mask);
02747         }
02748 
02749         snprintf(new_vfs_data_file, LL_MAX_PATH, "%s%u",                // Flawfinder: ignore
02750                 gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE).c_str(),
02751                 new_salt);
02752 
02753         snprintf(new_vfs_index_file, LL_MAX_PATH, "%s%u", gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_INDEX_FILE_BASE).c_str(),           // Flawfinder: ignore
02754                 new_salt);
02755 
02756 
02757         strncpy(static_vfs_data_file, gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_data.db2").c_str(), LL_MAX_PATH -1);          // Flawfinder: ignore
02758         static_vfs_data_file[LL_MAX_PATH -1] = '\0';
02759         strncpy(static_vfs_index_file, gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_index.db2").c_str(), LL_MAX_PATH -1);                // Flawfinder: ignore
02760         static_vfs_index_file[LL_MAX_PATH -1] = '\0';
02761 
02762         if (resize_vfs)
02763         {
02764                 LL_DEBUGS("AppCache") << "Removing old vfs and re-sizing" << LL_ENDL;
02765                 
02766                 LLFile::remove(old_vfs_data_file);
02767                 LLFile::remove(old_vfs_index_file);
02768         }
02769         else if (old_salt != new_salt)
02770         {
02771                 // move the vfs files to a new name before opening
02772                 LL_DEBUGS("AppCache") << "Renaming " << old_vfs_data_file << " to " << new_vfs_data_file << LL_ENDL;
02773                 LL_DEBUGS("AppCache") << "Renaming " << old_vfs_index_file << " to " << new_vfs_index_file << LL_ENDL;
02774                 LLFile::rename(old_vfs_data_file, new_vfs_data_file);
02775                 LLFile::rename(old_vfs_index_file, new_vfs_index_file);
02776         }
02777 
02778         // Startup the VFS...
02779         gSavedSettings.setU32("VFSSalt", new_salt);
02780 
02781         // Don't remove VFS after viewer crashes.  If user has corrupt data, they can reinstall. JC
02782         gVFS = new LLVFS(new_vfs_index_file, new_vfs_data_file, false, vfs_size_u32, false);
02783         if( VFSVALID_BAD_CORRUPT == gVFS->getValidState() )
02784         {
02785                 // Try again with fresh files 
02786                 // (The constructor deletes corrupt files when it finds them.)
02787                 LL_WARNS("AppCache") << "VFS corrupt, deleted.  Making new VFS." << LL_ENDL;
02788                 delete gVFS;
02789                 gVFS = new LLVFS(new_vfs_index_file, new_vfs_data_file, false, vfs_size_u32, false);
02790         }
02791 
02792         gStaticVFS = new LLVFS(static_vfs_index_file, static_vfs_data_file, true, 0, false);
02793 
02794         BOOL success = gVFS->isValid() && gStaticVFS->isValid();
02795         if( !success )
02796         {
02797                 return false;
02798         }
02799         else
02800         {
02801                 LLVFile::initClass();
02802                 return true;
02803         }
02804 }
02805 
02806 void LLAppViewer::purgeCache()
02807 {
02808         LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << llendl;
02809         LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE);
02810         std::string mask = gDirUtilp->getDirDelimiter() + "*.*";
02811         gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"").c_str(),mask);
02812 }
02813 
02814 const LLString& LLAppViewer::getSecondLifeTitle() const
02815 {
02816         return gSecondLife;
02817 }
02818 
02819 const LLString& LLAppViewer::getWindowTitle() const 
02820 {
02821         return gWindowTitle;
02822 }
02823 
02824 void LLAppViewer::resetURIs() const
02825 {
02826     // Clear URIs when picking a new server
02827         gLoginURIs.clear();
02828         gHelperURI.clear();
02829 }
02830 
02831 const std::vector<std::string>& LLAppViewer::getLoginURIs() const
02832 {
02833         if (gLoginURIs.empty())
02834         {
02835                 // not specified on the command line, use value from table
02836                 gLoginURIs.push_back(gGridInfo[gGridChoice].mLoginURI);
02837         }
02838         return gLoginURIs;
02839 }
02840 
02841 const std::string& LLAppViewer::getHelperURI() const
02842 {
02843         if (gHelperURI.empty())
02844         {
02845                 // not specified on the command line, use value from table
02846                 gHelperURI = gGridInfo[gGridChoice].mHelperURI;
02847         }
02848         return gHelperURI;
02849 }
02850 
02851 void LLAppViewer::addLoginURI(const std::string& uri)
02852 {
02853         // *NOTE:Mani - login uri trumps the --grid (gGridChoice) setting.
02854         // Update gGridChoice to reflect the loginURI setting.
02855     gLoginURIs.push_back(uri);
02856         
02857         const std::string& top_uri = getLoginURIs()[0];
02858         int i = 0;
02859         for(; i < GRID_INFO_COUNT; ++i)
02860         {
02861                 if(top_uri == gGridInfo[i].mLoginURI)
02862                 {
02863                         gGridChoice = (EGridInfo)i;
02864                         break;
02865                 }
02866         }
02867 
02868         if(GRID_INFO_COUNT == i)
02869         {
02870                 gGridChoice = GRID_INFO_OTHER;
02871         }
02872 }
02873 
02874 void LLAppViewer::setHelperURI(const std::string& uri)
02875 {
02876     gHelperURI = uri;
02877 }
02878 
02879 // Callback from a dialog indicating user was logged out.  
02880 void finish_disconnect(S32 option, void* userdata)
02881 {
02882         if (1 == option)
02883         {
02884         LLAppViewer::instance()->forceQuit();
02885         }
02886 }
02887 
02888 // Callback from an early disconnect dialog, force an exit
02889 void finish_forced_disconnect(S32 /* option */, void* /* userdata */)
02890 {
02891         LLAppViewer::instance()->forceQuit();
02892 }
02893 
02894 
02895 void LLAppViewer::forceDisconnect(const LLString& mesg)
02896 {
02897         if (gDoDisconnect)
02898     {
02899                 // Already popped up one of these dialogs, don't
02900                 // do this again.
02901                 return;
02902     }
02903         
02904         // Translate the message if possible
02905         LLString big_reason = LLAgent::sTeleportErrorMessages[mesg];
02906         if ( big_reason.size() == 0 )
02907         {
02908                 big_reason = mesg;
02909         }
02910 
02911         LLStringBase<char>::format_map_t args;
02912         gDoDisconnect = TRUE;
02913 
02914         if (LLStartUp::getStartupState() < STATE_STARTED)
02915         {
02916                 // Tell users what happened
02917                 args["[ERROR_MESSAGE]"] = big_reason;
02918                 gViewerWindow->alertXml("ErrorMessage", args, finish_forced_disconnect);
02919         }
02920         else
02921         {
02922                 args["[MESSAGE]"] = big_reason;
02923                 gViewerWindow->alertXml("YouHaveBeenLoggedOut", args, finish_disconnect );
02924         }
02925 }
02926 
02927 void LLAppViewer::badNetworkHandler()
02928 {
02929         // Dump the packet
02930         gMessageSystem->dumpPacketToLog();
02931 
02932         // Flush all of our caches on exit in the case of disconnect due to
02933         // invalid packets.
02934 
02935         mPurgeOnExit = TRUE;
02936 
02937 #if LL_WINDOWS
02938         // Generates the minidump.
02939         LLWinDebug::generateCrashStacks(NULL);
02940 #endif
02941         LLAppViewer::handleSyncViewerCrash();
02942         LLAppViewer::handleViewerCrash();
02943 
02944         std::ostringstream message;
02945         message <<
02946                 "The viewer has detected mangled network data indicative\n"
02947                 "of a bad upstream network connection or an incomplete\n"
02948                 "local installation of " << LLAppViewer::instance()->getSecondLifeTitle() << ". \n"
02949                 " \n"
02950                 "Try uninstalling and reinstalling to see if this resolves \n"
02951                 "the issue. \n"
02952                 " \n"
02953                 "If the problem continues, see the Tech Support FAQ at: \n"
02954                 "www.secondlife.com/support";
02955         forceDisconnect(message.str());
02956 }
02957 
02958 // This routine may get called more than once during the shutdown process.
02959 // This can happen because we need to get the screenshot before the window
02960 // is destroyed.
02961 void LLAppViewer::saveFinalSnapshot()
02962 {
02963         if (!mSavedFinalSnapshot && !gNoRender)
02964         {
02965                 gSavedSettings.setVector3d("FocusPosOnLogout", gAgent.calcFocusPositionTargetGlobal());
02966                 gSavedSettings.setVector3d("CameraPosOnLogout", gAgent.calcCameraPositionTargetGlobal());
02967                 gViewerWindow->setCursor(UI_CURSOR_WAIT);
02968                 gAgent.changeCameraToThirdPerson( FALSE );      // don't animate, need immediate switch
02969                 gSavedSettings.setBOOL("ShowParcelOwners", FALSE);
02970                 idle();
02971 
02972                 LLString snap_filename = gDirUtilp->getLindenUserDir();
02973                 snap_filename += gDirUtilp->getDirDelimiter();
02974                 snap_filename += SCREEN_LAST_FILENAME;
02975                 // use full pixel dimensions of viewer window (not post-scale dimensions)
02976                 gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight(), FALSE, TRUE);
02977                 mSavedFinalSnapshot = TRUE;
02978         }
02979 }
02980 
02981 void LLAppViewer::loadNameCache()
02982 {
02983         if (!gCacheName) return;
02984 
02985         std::string name_cache;
02986         name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
02987         llifstream cache_file(name_cache.c_str());
02988         if(cache_file.is_open())
02989         {
02990                 if(gCacheName->importFile(cache_file)) return;
02991         }
02992 
02993         // Try to load from the legacy format. This should go away after a
02994         // while. Phoenix 2008-01-30
02995         LLFILE* name_cache_fp = LLFile::fopen(name_cache.c_str(), "r");         // Flawfinder: ignore
02996         if (name_cache_fp)
02997         {
02998                 gCacheName->importFile(name_cache_fp);
02999                 fclose(name_cache_fp);
03000         }
03001 }
03002 
03003 void LLAppViewer::saveNameCache()
03004 {
03005         if (!gCacheName) return;
03006 
03007         std::string name_cache;
03008         name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
03009         llofstream cache_file(name_cache.c_str());
03010         if(cache_file.is_open())
03011         {
03012                 gCacheName->exportFile(cache_file);
03013         }
03014 }
03015 
03016 bool LLAppViewer::isInProductionGrid()
03017 {
03018         // *NOTE:Mani This used to compare GRID_INFO_AGNI to gGridChoice,
03019         // but it seems that loginURI trumps that.
03020         const std::string& loginURI = getLoginURIs()[0];
03021         return (loginURI == gGridInfo[GRID_INFO_AGNI].mLoginURI);
03022 }
03023 
03024 
03031 class LLFrameStatsTimer : public LLFrameTimer
03032 {
03033 public:
03034         LLFrameStatsTimer(F64 elapsed_already = 0.0)
03035                 : LLFrameTimer()
03036                 {
03037                         mStartTime -= elapsed_already;
03038                 }
03039 };
03040 
03042 // idle()
03043 //
03044 // Called every time the window is not doing anything.
03045 // Receive packets, update statistics, and schedule a redisplay.
03047 void LLAppViewer::idle()
03048 {
03049         // Update frame timers
03050         static LLTimer idle_timer;
03051 
03052         LLFrameTimer::updateFrameTime();
03053         LLEventTimer::updateClass();
03054         LLCriticalDamp::updateInterpolants();
03055         LLMortician::updateClass();
03056         F32 dt_raw = idle_timer.getElapsedTimeAndResetF32();
03057 
03058         // Cap out-of-control frame times
03059         // Too low because in menus, swapping, debugger, etc.
03060         // Too high because idle called with no objects in view, etc.
03061         const F32 MIN_FRAME_RATE = 1.f;
03062         const F32 MAX_FRAME_RATE = 200.f;
03063 
03064         F32 frame_rate_clamped = 1.f / dt_raw;
03065         frame_rate_clamped = llclamp(frame_rate_clamped, MIN_FRAME_RATE, MAX_FRAME_RATE);
03066         gFrameDTClamped = 1.f / frame_rate_clamped;
03067 
03068         // Global frame timer
03069         // Smoothly weight toward current frame
03070         gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f;
03071 
03072         F32 qas = gSavedSettings.getF32("QuitAfterSeconds");
03073         if (qas > 0.f)
03074         {
03075                 if (gRenderStartTime.getElapsedTimeF32() > qas)
03076                 {
03077                         LLAppViewer::instance()->forceQuit();
03078                 }
03079         }
03080 
03081         // Must wait until both have avatar object and mute list, so poll
03082         // here.
03083         request_initial_instant_messages();
03084 
03086         //
03087         // Special case idle if still starting up
03088         //
03089 
03090         if (LLStartUp::getStartupState() < STATE_STARTED)
03091         {
03092                 // Skip rest if idle startup returns false (essentially, no world yet)
03093                 if (!idle_startup())
03094                 {
03095                         return;
03096                 }
03097         }
03098 
03099         
03100     F32 yaw = 0.f;                              // radians
03101 
03102         if (!gDisconnected)
03103         {
03104                 LLFastTimer t(LLFastTimer::FTM_NETWORK);
03105                 // Update spaceserver timeinfo
03106             LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + (U32)(dt_raw * SEC_TO_MICROSEC));
03107     
03108     
03110             //
03111             // Update simulator agent state
03112             //
03113 
03114                 if (gSavedSettings.getBOOL("RotateRight"))
03115                 {
03116                         gAgent.moveYaw(-1.f);
03117                 }
03118 
03119             // Handle automatic walking towards points
03120             gAgentPilot.updateTarget();
03121             gAgent.autoPilot(&yaw);
03122     
03123             static LLFrameTimer agent_update_timer;
03124             static U32                          last_control_flags;
03125     
03126             //  When appropriate, update agent location to the simulator.
03127             F32 agent_update_time = agent_update_timer.getElapsedTimeF32();
03128             BOOL flags_changed = gAgent.controlFlagsDirty() || (last_control_flags != gAgent.getControlFlags());
03129     
03130             if (flags_changed || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND)))
03131             {
03132                     // Send avatar and camera info
03133                     last_control_flags = gAgent.getControlFlags();
03134                     send_agent_update(TRUE);
03135                     agent_update_timer.reset();
03136             }
03137         }
03138 
03140         //
03141         // Manage statistics
03142         //
03143         //
03144 
03145         {
03146                 // Initialize the viewer_stats_timer with an already elapsed time
03147                 // of SEND_STATS_PERIOD so that the initial stats report will
03148                 // be sent immediately.
03149                 static LLFrameStatsTimer viewer_stats_timer(SEND_STATS_PERIOD);
03150                 reset_statistics();
03151 
03152                 // Update session stats every large chunk of time
03153                 // *FIX: (???) SAMANTHA
03154                 if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected)
03155                 {
03156                         llinfos << "Transmitting sessions stats" << llendl;
03157                         send_stats();
03158                         viewer_stats_timer.reset();
03159                 }
03160 
03161                 // Print the object debugging stats
03162                 static LLFrameTimer object_debug_timer;
03163                 if (object_debug_timer.getElapsedTimeF32() > 5.f)
03164                 {
03165                         object_debug_timer.reset();
03166                         if (gObjectList.mNumDeadObjectUpdates)
03167                         {
03168                                 llinfos << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << llendl;
03169                                 gObjectList.mNumDeadObjectUpdates = 0;
03170                         }
03171                         if (gObjectList.mNumUnknownKills)
03172                         {
03173                                 llinfos << "Kills on unknown objects: " << gObjectList.mNumUnknownKills << llendl;
03174                                 gObjectList.mNumUnknownKills = 0;
03175                         }
03176                         if (gObjectList.mNumUnknownUpdates)
03177                         {
03178                                 llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl;
03179                                 gObjectList.mNumUnknownUpdates = 0;
03180                         }
03181                 }
03182                 gFrameStats.addFrameData();
03183         }
03184         
03185         if (!gDisconnected)
03186         {
03187                 LLFastTimer t(LLFastTimer::FTM_NETWORK);
03188         
03190             //
03191             // Network processing
03192             //
03193             // NOTE: Starting at this point, we may still have pointers to "dead" objects
03194             // floating throughout the various object lists.
03195             //
03196     
03197             gFrameStats.start(LLFrameStats::IDLE_NETWORK);
03198                 idleNetwork();
03199             stop_glerror();
03200                 
03201             gFrameStats.start(LLFrameStats::AGENT_MISC);
03202 
03203                 // Check for away from keyboard, kick idle agents.
03204                 idle_afk_check();
03205 
03206                 //  Update statistics for this frame
03207                 update_statistics(gFrameCount);
03208         }
03209 
03211         //
03212         // Handle the regular UI idle callbacks as well as
03213         // hover callbacks
03214         //
03215 
03216         {
03217 //              LLFastTimer t(LLFastTimer::FTM_IDLE_CB);
03218 
03219                 // Do event notifications if necessary.  Yes, we may want to move this elsewhere.
03220                 gEventNotifier.update();
03221                 
03222                 gIdleCallbacks.callFunctions();
03223         }
03224         
03225         if (gDisconnected)
03226     {
03227                 return;
03228     }
03229 
03230         gViewerWindow->handlePerFrameHover();
03231 
03233         // Agent and camera movement
03234         //
03235                 LLCoordGL current_mouse = gViewerWindow->getCurrentMouse();
03236 
03237         {
03238                 // After agent and camera moved, figure out if we need to
03239                 // deselect objects.
03240                 LLSelectMgr::getInstance()->deselectAllIfTooFar();
03241 
03242         }
03243 
03244         {
03245                 // Handle pending gesture processing
03246                 gGestureManager.update();
03247 
03248                 gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY);
03249         }
03250 
03251         {
03252                 LLFastTimer t(LLFastTimer::FTM_OBJECTLIST_UPDATE); // Actually "object update"
03253                 gFrameStats.start(LLFrameStats::OBJECT_UPDATE);
03254                 
03255         if (!(logoutRequestSent() && hasSavedFinalSnapshot()))
03256                 {
03257                         gObjectList.update(gAgent, *LLWorld::getInstance());
03258                 }
03259         }
03260         
03262         //
03263         // Deletes objects...
03264         // Has to be done after doing idleUpdates (which can kill objects)
03265         //
03266 
03267         {
03268                 LLFastTimer t(LLFastTimer::FTM_CLEANUP);
03269                 gFrameStats.start(LLFrameStats::CLEAN_DEAD);
03270                 gObjectList.cleanDeadObjects();
03271                 LLDrawable::cleanupDeadDrawables();
03272         }
03273         
03274         //
03275         // After this point, in theory we should never see a dead object
03276         // in the various object/drawable lists.
03277         //
03278 
03280         //
03281         // Update/send HUD effects
03282         //
03283         // At this point, HUD effects may clean up some references to
03284         // dead objects.
03285         //
03286 
03287         {
03288                 gFrameStats.start(LLFrameStats::UPDATE_EFFECTS);
03289                 LLSelectMgr::getInstance()->updateEffects();
03290                 LLHUDManager::getInstance()->cleanupEffects();
03291                 LLHUDManager::getInstance()->sendEffects();
03292         }
03293 
03294         stop_glerror();
03295 
03297         //
03298         // Unpack layer data that we've received
03299         //
03300 
03301         {
03302                 LLFastTimer t(LLFastTimer::FTM_NETWORK);
03303                 gVLManager.unpackData();
03304         }
03305         
03307         //
03308         // Update surfaces, and surface textures as well.
03309         //
03310 
03311         LLWorld::getInstance()->updateVisibilities();
03312         {
03313                 const F32 max_region_update_time = .001f; // 1ms
03314                 LLFastTimer t(LLFastTimer::FTM_REGION_UPDATE);
03315                 LLWorld::getInstance()->updateRegions(max_region_update_time);
03316         }
03317         
03319         //
03320         // Update weather effects
03321         //
03322         if (!gNoRender)
03323         {
03324                 LLWorld::getInstance()->updateClouds(gFrameDTClamped);
03325                 gSky.propagateHeavenlyBodies(gFrameDTClamped);                          // moves sun, moon, and planets
03326 
03327                 // Update wind vector 
03328                 LLVector3 wind_position_region;
03329                 static LLVector3 average_wind;
03330 
03331                 LLViewerRegion *regionp;
03332                 regionp = LLWorld::getInstance()->resolveRegionGlobal(wind_position_region, gAgent.getPositionGlobal());        // puts agent's local coords into wind_position 
03333                 if (regionp)
03334                 {
03335                         gWindVec = regionp->mWind.getVelocity(wind_position_region);
03336 
03337                         // Compute average wind and use to drive motion of water
03338                         
03339                         average_wind = regionp->mWind.getAverage();
03340                         F32 cloud_density = regionp->mCloudLayer.getDensityRegion(wind_position_region);
03341                         
03342                         gSky.setCloudDensityAtAgent(cloud_density);
03343                         gSky.setWind(average_wind);
03344                         //LLVOWater::setWind(average_wind);
03345                 }
03346                 else
03347                 {
03348                         gWindVec.setVec(0.0f, 0.0f, 0.0f);
03349                 }
03350         }
03351         stop_glerror();
03352         
03354         //
03355         // Sort and cull in the new renderer are moved to pipeline.cpp
03356         // Here, particles are updated and drawables are moved.
03357         //
03358         
03359         if (!gNoRender)
03360         {
03361                 LLFastTimer t(LLFastTimer::FTM_WORLD_UPDATE);
03362                 gFrameStats.start(LLFrameStats::UPDATE_MOVE);
03363                 gPipeline.updateMove();
03364 
03365                 gFrameStats.start(LLFrameStats::UPDATE_PARTICLES);
03366                 LLWorld::getInstance()->updateParticles();
03367         }
03368         stop_glerror();
03369 
03370         if (LLViewerJoystick::getInstance()->getOverrideCamera())
03371         {
03372                 LLViewerJoystick::getInstance()->moveFlycam();
03373         }
03374         else
03375         {
03376                 if (LLToolMgr::getInstance()->inBuildMode())
03377                 {
03378                         LLViewerJoystick::getInstance()->moveObjects();
03379                 }
03380 
03381                 gAgent.updateCamera();
03382         }
03383 
03384         // objects and camera should be in sync, do LOD calculations now
03385         {
03386                 LLFastTimer t(LLFastTimer::FTM_LOD_UPDATE);
03387                 gObjectList.updateApparentAngles(gAgent);
03388         }
03389 
03390         {
03391                 gFrameStats.start(LLFrameStats::AUDIO);
03392                 LLFastTimer t(LLFastTimer::FTM_AUDIO_UPDATE);
03393                 
03394                 if (gAudiop)
03395                 {
03396                     audio_update_volume(false);
03397                         audio_update_listener();
03398                         audio_update_wind(false);
03399 
03400                         // this line actually commits the changes we've made to source positions, etc.
03401                         const F32 max_audio_decode_time = 0.002f; // 2 ms decode time
03402                         gAudiop->idle(max_audio_decode_time);
03403                 }
03404         }
03405         
03406         // Handle shutdown process, for example, 
03407         // wait for floaters to close, send quit message,
03408         // forcibly quit if it has taken too long
03409         if (mQuitRequested)
03410         {
03411                 idleShutdown();
03412         }
03413 
03414         stop_glerror();
03415 }
03416 
03417 void LLAppViewer::idleShutdown()
03418 {
03419         // Wait for all modal alerts to get resolved
03420         if (LLModalDialog::activeCount() > 0)
03421         {
03422                 return;
03423         }
03424 
03425         // close IM interface
03426         if(gIMMgr)
03427         {
03428                 gIMMgr->disconnectAllSessions();
03429         }
03430         
03431         // Wait for all floaters to get resolved
03432         if (gFloaterView
03433                 && !gFloaterView->allChildrenClosed())
03434         {
03435                 return;
03436         }
03437 
03438         static bool saved_snapshot = false;
03439         if (!saved_snapshot)
03440         {
03441                 saved_snapshot = true;
03442                 saveFinalSnapshot();
03443                 return;
03444         }
03445 
03446         const F32 SHUTDOWN_UPLOAD_SAVE_TIME = 5.f;
03447 
03448         S32 pending_uploads = gAssetStorage->getNumPendingUploads();
03449         if (pending_uploads > 0
03450                 && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME
03451                 && !logoutRequestSent())
03452         {
03453                 static S32 total_uploads = 0;
03454                 // Sometimes total upload count can change during logout.
03455                 total_uploads = llmax(total_uploads, pending_uploads);
03456                 gViewerWindow->setShowProgress(TRUE);
03457                 S32 finished_uploads = total_uploads - pending_uploads;
03458                 F32 percent = 100.f * finished_uploads / total_uploads;
03459                 gViewerWindow->setProgressPercent(percent);
03460                 char buffer[MAX_STRING];                // Flawfinder: ignore
03461                 snprintf(buffer, MAX_STRING, "Saving final data...");           // Flawfinder: ignore
03462                 gViewerWindow->setProgressString(buffer);
03463                 return;
03464         }
03465 
03466         // All floaters are closed.  Tell server we want to quit.
03467         if( !logoutRequestSent() )
03468         {
03469                 sendLogoutRequest();
03470 
03471                 // Wait for a LogoutReply message
03472                 gViewerWindow->setShowProgress(TRUE);
03473                 gViewerWindow->setProgressPercent(100.f);
03474                 gViewerWindow->setProgressString("Logging out...");
03475                 return;
03476         }
03477 
03478         // Make sure that we quit if we haven't received a reply from the server.
03479         if( logoutRequestSent() 
03480                 && gLogoutTimer.getElapsedTimeF32() > gLogoutMaxTime )
03481         {
03482                 forceQuit();
03483                 return;
03484         }
03485 }
03486 
03487 void LLAppViewer::sendLogoutRequest()
03488 {
03489         if(!mLogoutRequestSent)
03490         {
03491                 LLMessageSystem* msg = gMessageSystem;
03492                 msg->newMessageFast(_PREHASH_LogoutRequest);
03493                 msg->nextBlockFast(_PREHASH_AgentData);
03494                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
03495                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
03496                 gAgent.sendReliableMessage();
03497 
03498                 gLogoutTimer.reset();
03499                 gLogoutMaxTime = LOGOUT_REQUEST_TIME;
03500                 mLogoutRequestSent = TRUE;
03501                 
03502                 gVoiceClient->leaveChannel();
03503 
03504                 //Set internal status variables and marker files
03505                 gLogoutInProgress = TRUE;
03506                 mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME);
03507                 mLogoutMarkerFile =  ll_apr_file_open(mLogoutMarkerFileName, LL_APR_W);
03508                 if (mLogoutMarkerFile)
03509                 {
03510                         llinfos << "Created logout marker file " << mLogoutMarkerFileName << llendl;
03511                 }
03512                 else
03513                 {
03514                         llwarns << "Cannot create logout marker file " << mLogoutMarkerFileName << llendl;
03515                 }
03516                 apr_file_close(mLogoutMarkerFile);
03517         }
03518 }
03519 
03520 //
03521 // Handle messages, and all message related stuff
03522 //
03523 
03524 #define TIME_THROTTLE_MESSAGES
03525 
03526 #ifdef TIME_THROTTLE_MESSAGES
03527 #define CHECK_MESSAGES_DEFAULT_MAX_TIME .020f // 50 ms = 50 fps (just for messages!)
03528 static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
03529 #endif
03530 
03531 void LLAppViewer::idleNetwork()
03532 {
03533         gObjectList.mNumNewObjects = 0;
03534         S32 total_decoded = 0;
03535 
03536         if (!gSavedSettings.getBOOL("SpeedTest"))
03537         {
03538                 LLFastTimer t(LLFastTimer::FTM_IDLE_NETWORK); // decode
03539                 
03540                 // deal with any queued name requests and replies.
03541                 gCacheName->processPending();
03542 
03543                 LLTimer check_message_timer;
03544                 //  Read all available packets from network 
03545                 stop_glerror();
03546                 const S64 frame_count = gFrameCount;  // U32->S64
03547                 F32 total_time = 0.0f;
03548                 while (gMessageSystem->checkAllMessages(frame_count, gServicePump)) 
03549                 {
03550                         if (gDoDisconnect)
03551                         {
03552                                 // We're disconnecting, don't process any more messages from the server
03553                                 // We're usually disconnecting due to either network corruption or a
03554                                 // server going down, so this is OK.
03555                                 break;
03556                         }
03557                         stop_glerror();
03558 
03559                         total_decoded++;
03560                         gPacketsIn++;
03561 
03562                         if (total_decoded > MESSAGE_MAX_PER_FRAME)
03563                         {
03564                                 break;
03565                         }
03566 
03567 #ifdef TIME_THROTTLE_MESSAGES
03568                         // Prevent slow packets from completely destroying the frame rate.
03569                         // This usually happens due to clumps of avatars taking huge amount
03570                         // of network processing time (which needs to be fixed, but this is
03571                         // a good limit anyway).
03572                         total_time = check_message_timer.getElapsedTimeF32();
03573                         if (total_time >= CheckMessagesMaxTime)
03574                                 break;
03575 #endif
03576                 }
03577                 // Handle per-frame message system processing.
03578                 gMessageSystem->processAcks();
03579 
03580 #ifdef TIME_THROTTLE_MESSAGES
03581                 if (total_time >= CheckMessagesMaxTime)
03582                 {
03583                         // Increase CheckMessagesMaxTime so that we will eventually catch up
03584                         CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames
03585                 }
03586                 else
03587                 {
03588                         // Reset CheckMessagesMaxTime to default value
03589                         CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
03590                 }
03591 #endif
03592                 
03593 
03594 
03595                 // we want to clear the control after sending out all necessary agent updates
03596                 gAgent.resetControlFlags();
03597                 stop_glerror();
03598 
03599                 
03600                 // Decode enqueued messages...
03601                 S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded;
03602 
03603                 if( remaining_possible_decodes <= 0 )
03604                 {
03605                         llinfos << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << llendl;
03606                 }
03607 
03608                 if (gPrintMessagesThisFrame)
03609                 {
03610                         llinfos << "Decoded " << total_decoded << " msgs this frame!" << llendl;
03611                         gPrintMessagesThisFrame = FALSE;
03612                 }
03613         }
03614 
03615         gObjectList.mNumNewObjectsStat.addValue(gObjectList.mNumNewObjects);
03616 
03617         // Retransmit unacknowledged packets.
03618         gXferManager->retransmitUnackedPackets();
03619         gAssetStorage->checkForTimeouts();
03620 
03621         gViewerThrottle.updateDynamicThrottle();
03622 }
03623 
03624 void LLAppViewer::disconnectViewer()
03625 {
03626         if (gDisconnected)
03627         {
03628                 return;
03629         }
03630         //
03631         // Cleanup after quitting.
03632         //      
03633         // Save snapshot for next time, if we made it through initialization
03634 
03635         llinfos << "Disconnecting viewer!" << llendl;
03636 
03637         // Dump our frame statistics
03638         gFrameStats.dump();
03639 
03640         // Remember if we were flying
03641         gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() );
03642 
03643         // Un-minimize all windows so they don't get saved minimized
03644         if (!gNoRender)
03645         {
03646                 if (gFloaterView)
03647                 {
03648                         gFloaterView->restoreAll();
03649                 }
03650         }
03651 
03652         if (LLSelectMgr::getInstance())
03653         {
03654                 LLSelectMgr::getInstance()->deselectAll();
03655         }
03656 
03657         if (!gNoRender)
03658         {
03659                 // save inventory if appropriate
03660                 gInventory.cache(gAgent.getInventoryRootID(), gAgent.getID());
03661                 if(gInventoryLibraryRoot.notNull() && gInventoryLibraryOwner.notNull())
03662                 {
03663                         gInventory.cache(gInventoryLibraryRoot, gInventoryLibraryOwner);
03664                 }
03665         }
03666 
03667         saveNameCache();
03668 
03669         // close inventory interface, close all windows
03670         LLInventoryView::cleanup();
03671 
03672         // Also writes cached agent settings to gSavedSettings
03673         gAgent.cleanup();
03674 
03675         // This is where we used to call gObjectList.destroy() and then delete gWorldp.
03676         // Now we just ask the LLWorld singleton to cleanly shut down.
03677         LLWorld::getInstance()->destroyClass();
03678 
03679         cleanup_xfer_manager();
03680         gDisconnected = TRUE;
03681 }
03682 
03683 void LLAppViewer::forceErrorLLError()
03684 {
03685         llerrs << "This is an llerror" << llendl;
03686 }
03687 
03688 void LLAppViewer::forceErrorBreakpoint()
03689 {
03690 #ifdef LL_WINDOWS
03691     DebugBreak();
03692 #endif
03693     return;
03694 }
03695 
03696 void LLAppViewer::forceErrorBadMemoryAccess()
03697 {
03698     S32* crash = NULL;
03699     *crash = 0xDEADBEEF;
03700     return;
03701 }
03702 
03703 void LLAppViewer::forceErrorInifiniteLoop()
03704 {
03705     while(true)
03706     {
03707         ;
03708     }
03709     return;
03710 }
03711  
03712 void LLAppViewer::forceErrorSoftwareException()
03713 {
03714     // *FIX: Any way to insure it won't be handled?
03715     throw; 
03716 }
03717 
03718 void LLAppViewer::startMainloopTimeout(F32 secs)
03719 {
03720         if(secs < 0.0f)
03721         {
03722                 secs = gSavedSettings.getF32("MainloopTimeoutDefault");
03723         }
03724         
03725         mMainloopTimeout->setTimeout(secs);
03726         mMainloopTimeout->start();
03727 }
03728 
03729 void LLAppViewer::stopMainloopTimeout()
03730 {
03731         mMainloopTimeout->stop();
03732 }

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