llappviewer.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:127k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llappviewer.cpp
  3.  * @brief The LLAppViewer class definitions
  4.  *
  5.  * $LicenseInfo:firstyear=2007&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2007-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "llviewerprecompiledheaders.h"
  33. #include "llappviewer.h"
  34. // Viewer includes
  35. #include "llversioninfo.h"
  36. #include "llfeaturemanager.h"
  37. #include "lluictrlfactory.h"
  38. #include "lltexteditor.h"
  39. #include "llerrorcontrol.h"
  40. #include "lleventtimer.h"
  41. #include "llviewertexturelist.h"
  42. #include "llgroupmgr.h"
  43. #include "llagent.h"
  44. #include "llagentwearables.h"
  45. #include "llwindow.h"
  46. #include "llviewerstats.h"
  47. #include "llmd5.h"
  48. #include "llpumpio.h"
  49. #include "llmimetypes.h"
  50. #include "llslurl.h"
  51. #include "llstartup.h"
  52. #include "llfocusmgr.h"
  53. #include "llviewerjoystick.h"
  54. #include "llallocator.h"
  55. #include "llares.h" 
  56. #include "llcurl.h"
  57. #include "lltexturestats.h"
  58. #include "lltexturestats.h"
  59. #include "llviewerwindow.h"
  60. #include "llviewerdisplay.h"
  61. #include "llviewermedia.h"
  62. #include "llviewerparcelmedia.h"
  63. #include "llviewermediafocus.h"
  64. #include "llviewermessage.h"
  65. #include "llviewerobjectlist.h"
  66. #include "llworldmap.h"
  67. #include "llmutelist.h"
  68. #include "llviewerhelp.h"
  69. #include "lluicolortable.h"
  70. #include "llurldispatcher.h"
  71. #include "llurlhistory.h"
  72. //#include "llfirstuse.h"
  73. #include "llrender.h"
  74. #include "llteleporthistory.h"
  75. #include "lllocationhistory.h"
  76. #include "llfasttimerview.h"
  77. #include "llvoicechannel.h"
  78. #include "llsidetray.h"
  79. #include "llweb.h"
  80. #include "llsecondlifeurls.h"
  81. // Linden library includes
  82. #include "llimagej2c.h"
  83. #include "llmemory.h"
  84. #include "llprimitive.h"
  85. #include "llurlaction.h"
  86. #include "llvfile.h"
  87. #include "llvfsthread.h"
  88. #include "llvolumemgr.h"
  89. #include "llxfermanager.h"
  90. #include "llnotificationmanager.h"
  91. #include "llnotifications.h"
  92. #include "llnotificationsutil.h"
  93. // Third party library includes
  94. #include <boost/bind.hpp>
  95. #if LL_WINDOWS
  96. #include "llwindebug.h"
  97. # include <share.h> // For _SH_DENYWR in initMarkerFile
  98. #else
  99. #   include <sys/file.h> // For initMarkerFile support
  100. #endif
  101. #include "llapr.h"
  102. #include "apr_dso.h"
  103. #include <boost/lexical_cast.hpp>
  104. #include "llviewerkeyboard.h"
  105. #include "lllfsthread.h"
  106. #include "llworkerthread.h"
  107. #include "lltexturecache.h"
  108. #include "lltexturefetch.h"
  109. #include "llimageworker.h"
  110. #include "llevents.h"
  111. // The files below handle dependencies from cleanup.
  112. #include "llkeyframemotion.h"
  113. #include "llworldmap.h"
  114. #include "llhudmanager.h"
  115. #include "lltoolmgr.h"
  116. #include "llassetstorage.h"
  117. #include "llpolymesh.h"
  118. #include "llcachename.h"
  119. #include "llaudioengine.h"
  120. #include "llstreamingaudio.h"
  121. #include "llviewermenu.h"
  122. #include "llselectmgr.h"
  123. #include "lltrans.h"
  124. #include "lltransutil.h"
  125. #include "lltracker.h"
  126. #include "llviewerparcelmgr.h"
  127. #include "llworldmapview.h"
  128. #include "llpostprocess.h"
  129. #include "llwlparammanager.h"
  130. #include "llwaterparammanager.h"
  131. #include "lldebugview.h"
  132. #include "llconsole.h"
  133. #include "llcontainerview.h"
  134. #include "lltooltip.h"
  135. #include "llsdserialize.h"
  136. #include "llworld.h"
  137. #include "llhudeffecttrail.h"
  138. #include "llvectorperfoptions.h"
  139. #include "llurlsimstring.h"
  140. #include "llwatchdog.h"
  141. // Included so that constants/settings might be initialized
  142. // in save_settings_to_globals()
  143. #include "llbutton.h"
  144. #include "llcombobox.h"
  145. #include "llstatusbar.h"
  146. #include "llsurface.h"
  147. #include "llvosky.h"
  148. #include "llvotree.h"
  149. #include "llvoavatar.h"
  150. #include "llfolderview.h"
  151. #include "llagentpilot.h"
  152. #include "llvovolume.h"
  153. #include "llflexibleobject.h" 
  154. #include "llvosurfacepatch.h"
  155. #include "llviewerfloaterreg.h"
  156. #include "llcommandlineparser.h"
  157. #include "llfloatermemleak.h"
  158. #include "llfloaterreg.h"
  159. #include "llfloatersnapshot.h"
  160. #include "llfloaterinventory.h"
  161. // includes for idle() idleShutdown()
  162. #include "llviewercontrol.h"
  163. #include "lleventnotifier.h"
  164. #include "llcallbacklist.h"
  165. #include "pipeline.h"
  166. #include "llgesturemgr.h"
  167. #include "llsky.h"
  168. #include "llvlmanager.h"
  169. #include "llviewercamera.h"
  170. #include "lldrawpoolbump.h"
  171. #include "llvieweraudio.h"
  172. #include "llimview.h"
  173. #include "llviewerthrottle.h"
  174. #include "llparcel.h"
  175. #include "llavatariconctrl.h"
  176. // *FIX: These extern globals should be cleaned up.
  177. // The globals either represent state/config/resource-storage of either 
  178. // this app, or another 'component' of the viewer. App globals should be 
  179. // moved into the app class, where as the other globals should be 
  180. // moved out of here.
  181. // If a global symbol reference seems valid, it will be included
  182. // via header files above.
  183. //----------------------------------------------------------------------------
  184. // llviewernetwork.h
  185. #include "llviewernetwork.h"
  186. // define a self-registering event API object
  187. #include "llappviewerlistener.h"
  188. #if (LL_LINUX || LL_SOLARIS) && LL_GTK
  189. #include "glib.h"
  190. #endif // (LL_LINUX || LL_SOLARIS) && LL_GTK
  191. #if LL_MSVC
  192. // disable boost::lexical_cast warning
  193. #pragma warning (disable:4702)
  194. #endif
  195. static LLAppViewerListener sAppViewerListener(LLAppViewer::instance);
  196. ////// Windows-specific includes to the bottom - nasty defines in these pollute the preprocessor
  197. //
  198. //----------------------------------------------------------------------------
  199. // viewer.cpp - these are only used in viewer, should be easily moved.
  200. #if LL_DARWIN
  201. extern void init_apple_menu(const char* product);
  202. #endif // LL_DARWIN
  203. extern BOOL gRandomizeFramerate;
  204. extern BOOL gPeriodicSlowFrame;
  205. extern BOOL gDebugGL;
  206. ////////////////////////////////////////////////////////////
  207. // All from the last globals push...
  208. const F32 DEFAULT_AFK_TIMEOUT = 5.f * 60.f; // time with no input before user flagged as Away From Keyboard
  209. F32 gSimLastTime; // Used in LLAppViewer::init and send_stats()
  210. F32 gSimFrames;
  211. BOOL gShowObjectUpdates = FALSE;
  212. BOOL gUseQuickTime = TRUE;
  213. eLastExecEvent gLastExecEvent = LAST_EXEC_NORMAL;
  214. LLSD gDebugInfo;
  215. U32 gFrameCount = 0;
  216. U32 gForegroundFrameCount = 0; // number of frames that app window was in foreground
  217. LLPumpIO* gServicePump = NULL;
  218. U64 gFrameTime = 0;
  219. F32 gFrameTimeSeconds = 0.f;
  220. F32 gFrameIntervalSeconds = 0.f;
  221. F32 gFPSClamped = 10.f; // Pretend we start at target rate.
  222. F32 gFrameDTClamped = 0.f; // Time between adjacent checks to network for packets
  223. U64 gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds
  224. U32 gFrameStalls = 0;
  225. const F64 FRAME_STALL_THRESHOLD = 1.0;
  226. LLTimer gRenderStartTime;
  227. LLFrameTimer gForegroundTime;
  228. LLTimer gLogoutTimer;
  229. static const F32 LOGOUT_REQUEST_TIME = 6.f;  // this will be cut short by the LogoutReply msg.
  230. F32 gLogoutMaxTime = LOGOUT_REQUEST_TIME;
  231. BOOL gDisconnected = FALSE;
  232. // used to restore texture state after a mode switch
  233. LLFrameTimer gRestoreGLTimer;
  234. BOOL gRestoreGL = FALSE;
  235. BOOL gUseWireframe = FALSE;
  236. // VFS globals - see llappviewer.h
  237. LLVFS* gStaticVFS = NULL;
  238. LLMemoryInfo gSysMemory;
  239. U64 gMemoryAllocated = 0; // updated in display_stats() in llviewerdisplay.cpp
  240. std::string gLastVersionChannel;
  241. LLVector3 gWindVec(3.0, 3.0, 0.0);
  242. LLVector3 gRelativeWindVec(0.0, 0.0, 0.0);
  243. U32 gPacketsIn = 0;
  244. BOOL gPrintMessagesThisFrame = FALSE;
  245. BOOL gRandomizeFramerate = FALSE;
  246. BOOL gPeriodicSlowFrame = FALSE;
  247. BOOL gCrashOnStartup = FALSE;
  248. BOOL gLLErrorActivated = FALSE;
  249. BOOL gLogoutInProgress = FALSE;
  250. ////////////////////////////////////////////////////////////
  251. // Internal globals... that should be removed.
  252. static std::string gArgs;
  253. const std::string MARKER_FILE_NAME("SecondLife.exec_marker");
  254. const std::string ERROR_MARKER_FILE_NAME("SecondLife.error_marker");
  255. const std::string LLERROR_MARKER_FILE_NAME("SecondLife.llerror_marker");
  256. const std::string LOGOUT_MARKER_FILE_NAME("SecondLife.logout_marker");
  257. static BOOL gDoDisconnect = FALSE;
  258. static std::string gLaunchFileOnQuit;
  259. // Used on Win32 for other apps to identify our window (eg, win_setup)
  260. const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
  261. //----------------------------------------------------------------------------
  262. // List of entries from strings.xml to always replace
  263. static std::set<std::string> default_trans_args;
  264. void init_default_trans_args()
  265. {
  266. default_trans_args.insert("SECOND_LIFE"); // World
  267. default_trans_args.insert("APP_NAME");
  268. default_trans_args.insert("CAPITALIZED_APP_NAME");
  269. default_trans_args.insert("SECOND_LIFE_GRID");
  270. default_trans_args.insert("SUPPORT_SITE");
  271. }
  272. //----------------------------------------------------------------------------
  273. // File scope definitons
  274. const char *VFS_DATA_FILE_BASE = "data.db2.x.";
  275. const char *VFS_INDEX_FILE_BASE = "index.db2.x.";
  276. static std::string gWindowTitle;
  277. std::string gLoginPage;
  278. std::vector<std::string> gLoginURIs;
  279. static std::string gHelperURI;
  280. LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ;
  281. void idle_afk_check()
  282. {
  283. // check idle timers
  284. if (gSavedSettings.getS32("AFKTimeout") && (gAwayTriggerTimer.getElapsedTimeF32() > gSavedSettings.getS32("AFKTimeout")))
  285. {
  286. gAgent.setAFK();
  287. }
  288. }
  289. // A callback set in LLAppViewer::init()
  290. static void ui_audio_callback(const LLUUID& uuid)
  291. {
  292. if (gAudiop)
  293. {
  294. gAudiop->triggerSound(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI);
  295. }
  296. }
  297. void request_initial_instant_messages()
  298. {
  299. static BOOL requested = FALSE;
  300. if (!requested
  301. && gMessageSystem
  302. && LLMuteList::getInstance()->isLoaded()
  303. && gAgent.getAvatarObject())
  304. {
  305. // Auto-accepted inventory items may require the avatar object
  306. // to build a correct name.  Likewise, inventory offers from
  307. // muted avatars require the mute list to properly mute.
  308. LLMessageSystem* msg = gMessageSystem;
  309. msg->newMessageFast(_PREHASH_RetrieveInstantMessages);
  310. msg->nextBlockFast(_PREHASH_AgentData);
  311. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
  312. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  313. gAgent.sendReliableMessage();
  314. requested = TRUE;
  315. }
  316. }
  317. // A settings system callback for CrashSubmitBehavior
  318. bool handleCrashSubmitBehaviorChanged(const LLSD& newvalue)
  319. {
  320. S32 cb = newvalue.asInteger();
  321. const S32 NEVER_SUBMIT_REPORT = 2;
  322. if(cb == NEVER_SUBMIT_REPORT)
  323. {
  324. //  LLWatchdog::getInstance()->cleanup(); // SJB: cleaning up a running watchdog thread is unsafe
  325. LLAppViewer::instance()->destroyMainloopTimeout();
  326. }
  327. else if(gSavedSettings.getBOOL("WatchdogEnabled") == TRUE)
  328. {
  329. // Don't re-enable the watchdog when we change the setting; this may get called before it's started
  330. //  LLWatchdog::getInstance()->init();
  331. }
  332. return true;
  333. }
  334. // Use these strictly for things that are constructed at startup,
  335. // or for things that are performance critical.  JC
  336. static void settings_to_globals()
  337. {
  338. LLBUTTON_H_PAD = gSavedSettings.getS32("ButtonHPad");
  339. BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall");
  340. BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight");
  341. MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight");
  342. MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth");
  343. LLCOMBOBOX_HEIGHT = BTN_HEIGHT - 2;
  344. LLCOMBOBOX_WIDTH = 128;
  345. LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
  346. LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic");
  347. LLVOVolume::sLODFactor = gSavedSettings.getF32("RenderVolumeLODFactor");
  348. LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f;
  349. LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor");
  350. LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor");
  351. LLVOAvatar::sLODFactor = gSavedSettings.getF32("RenderAvatarLODFactor");
  352. LLVOAvatar::sMaxVisible = gSavedSettings.getS32("RenderAvatarMaxVisible");
  353. LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible");
  354. // clamp auto-open time to some minimum usable value
  355. LLFolderView::sAutoOpenTime = llmax(0.25f, gSavedSettings.getF32("FolderAutoOpenDelay"));
  356. LLSelectMgr::sRectSelectInclusive = gSavedSettings.getBOOL("RectangleSelectInclusive");
  357. LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections");
  358. LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius");
  359. gAgentPilot.mNumRuns = gSavedSettings.getS32("StatsNumRuns");
  360. gAgentPilot.mQuitAfterRuns = gSavedSettings.getBOOL("StatsQuitAfterRuns");
  361. gAgent.setHideGroupTitle(gSavedSettings.getBOOL("RenderHideGroupTitle"));
  362. gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc");
  363. gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates");
  364. LLWorldMapView::sMapScale = gSavedSettings.getF32("MapScale");
  365. LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap");
  366. }
  367. static void settings_modify()
  368. {
  369. LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderUseFBO");
  370. LLVOAvatar::sUseImpostors = gSavedSettings.getBOOL("RenderUseImpostors");
  371. LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor");
  372. LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4]
  373. gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession;
  374. gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
  375. gAuditTexture = gSavedSettings.getBOOL("AuditTexture");
  376. #if LL_VECTORIZE
  377. if (gSysCPU.hasAltivec())
  378. {
  379. gSavedSettings.setBOOL("VectorizeEnable", TRUE );
  380. gSavedSettings.setU32("VectorizeProcessor", 0 );
  381. }
  382. else
  383. if (gSysCPU.hasSSE2())
  384. {
  385. gSavedSettings.setBOOL("VectorizeEnable", TRUE );
  386. gSavedSettings.setU32("VectorizeProcessor", 2 );
  387. }
  388. else
  389. if (gSysCPU.hasSSE())
  390. {
  391. gSavedSettings.setBOOL("VectorizeEnable", TRUE );
  392. gSavedSettings.setU32("VectorizeProcessor", 1 );
  393. }
  394. else
  395. {
  396. // Don't bother testing or running if CPU doesn't support it. JC
  397. gSavedSettings.setBOOL("VectorizePerfTest", FALSE );
  398. gSavedSettings.setBOOL("VectorizeEnable", FALSE );
  399. gSavedSettings.setU32("VectorizeProcessor", 0 );
  400. gSavedSettings.setBOOL("VectorizeSkin", FALSE);
  401. }
  402. #else
  403. // This build target doesn't support SSE, don't test/run.
  404. gSavedSettings.setBOOL("VectorizePerfTest", FALSE );
  405. gSavedSettings.setBOOL("VectorizeEnable", FALSE );
  406. gSavedSettings.setU32("VectorizeProcessor", 0 );
  407. gSavedSettings.setBOOL("VectorizeSkin", FALSE);
  408. #endif
  409. }
  410. class LLFastTimerLogThread : public LLThread
  411. {
  412. public:
  413. std::string mFile;
  414. LLFastTimerLogThread() : LLThread("fast timer log")
  415. {
  416. if(LLFastTimer::sLog)
  417. {
  418. mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance.slp");
  419. }
  420. if(LLFastTimer::sMetricLog)
  421. {
  422. mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric.slp");
  423. }
  424. }
  425. void run()
  426. {
  427. std::ofstream os(mFile.c_str());
  428. while (!LLAppViewer::instance()->isQuitting())
  429. {
  430. LLFastTimer::writeLog(os);
  431. os.flush();
  432. ms_sleep(32);
  433. }
  434. os.close();
  435. }
  436. };
  437. void LLAppViewer::initGridChoice()
  438. {
  439. // Load up the initial grid choice from:
  440. // - hard coded defaults...
  441. // - command line settings...
  442. // - if dev build, persisted settings...
  443. // Set the "grid choice", this is specified by command line.
  444. std::string grid_choice = gSavedSettings.getString("CmdLineGridChoice");
  445. LLViewerLogin::getInstance()->setGridChoice(grid_choice);
  446. // Load last server choice by default 
  447. // ignored if the command line grid choice has been set
  448. if(grid_choice.empty())
  449. {
  450. S32 server = gSavedSettings.getS32("ServerChoice");
  451. server = llclamp(server, 0, (S32)GRID_INFO_COUNT - 1);
  452. if(server == GRID_INFO_OTHER)
  453. {
  454. std::string custom_server = gSavedSettings.getString("CustomServer");
  455. LLViewerLogin::getInstance()->setGridChoice(custom_server);
  456. }
  457. else if(server != (S32)GRID_INFO_NONE)
  458. {
  459. LLViewerLogin::getInstance()->setGridChoice((EGridInfo)server);
  460. }
  461. }
  462. }
  463. //virtual
  464. bool LLAppViewer::initSLURLHandler()
  465. {
  466. // does nothing unless subclassed
  467. return false;
  468. }
  469. //virtual
  470. bool LLAppViewer::sendURLToOtherInstance(const std::string& url)
  471. {
  472. // does nothing unless subclassed
  473. return false;
  474. }
  475. //----------------------------------------------------------------------------
  476. // LLAppViewer definition
  477. // Static members.
  478. // The single viewer app.
  479. LLAppViewer* LLAppViewer::sInstance = NULL;
  480. const std::string LLAppViewer::sGlobalSettingsName = "Global"; 
  481. LLTextureCache* LLAppViewer::sTextureCache = NULL; 
  482. LLImageDecodeThread* LLAppViewer::sImageDecodeThread = NULL; 
  483. LLTextureFetch* LLAppViewer::sTextureFetch = NULL; 
  484. LLAppViewer::LLAppViewer() : 
  485. mMarkerFile(),
  486. mLogoutMarkerFile(NULL),
  487. mReportedCrash(false),
  488. mNumSessions(0),
  489. mPurgeCache(false),
  490. mPurgeOnExit(false),
  491. mSecondInstance(false),
  492. mSavedFinalSnapshot(false),
  493. mForceGraphicsDetail(false),
  494. mQuitRequested(false),
  495. mLogoutRequestSent(false),
  496. mYieldTime(-1),
  497. mMainloopTimeout(NULL),
  498. mAgentRegionLastAlive(false),
  499. mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", FALSE)),
  500. mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)),
  501. mFastTimerLogThread(NULL)
  502. {
  503. if(NULL != sInstance)
  504. {
  505. llerrs << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << llendl;
  506. }
  507. setupErrorHandling();
  508. sInstance = this;
  509. }
  510. LLAppViewer::~LLAppViewer()
  511. {
  512. destroyMainloopTimeout();
  513. // If we got to this destructor somehow, the app didn't hang.
  514. removeMarkerFile();
  515. }
  516. bool LLAppViewer::init()
  517. {
  518. //
  519. // Start of the application
  520. //
  521. // IMPORTANT! Do NOT put anything that will write
  522. // into the log files during normal startup until AFTER
  523. // we run the "program crashed last time" error handler below.
  524. //
  525. LLFastTimer::reset();
  526. // Need to do this initialization before we do anything else, since anything
  527. // that touches files should really go through the lldir API
  528. gDirUtilp->initAppDirs("SecondLife");
  529. // set skin search path to default, will be overridden later
  530. // this allows simple skinned file lookups to work
  531. gDirUtilp->setSkinFolder("default");
  532. initLogging();
  533. //
  534. // OK to write stuff to logs now, we've now crash reported if necessary
  535. //
  536. init_default_trans_args();
  537. if (!initConfiguration())
  538. return false;
  539. // Although initLogging() is the right place to mess with
  540. // setFatalFunction(), we can't query gSavedSettings until after
  541. // initConfiguration().
  542. S32 rc(gSavedSettings.getS32("QAModeTermCode"));
  543. if (rc >= 0)
  544. {
  545. // QAModeTermCode set, terminate with that rc on LL_ERRS. Use _exit()
  546. // rather than exit() because normal cleanup depends too much on
  547. // successful startup!
  548. LLError::setFatalFunction(boost::bind(_exit, rc));
  549. }
  550.     mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
  551.     // *NOTE:Mani - LLCurl::initClass is not thread safe. 
  552.     // Called before threads are created.
  553.     LLCurl::initClass();
  554.     initThreads();
  555.     writeSystemInfo();
  556. // Build a string representing the current version number.
  557.     gCurrentVersion = llformat("%s %s", 
  558.    gSavedSettings.getString("VersionChannelName").c_str(),
  559.    LLVersionInfo::getVersion().c_str());
  560. //////////////////////////////////////////////////////////////////////////////
  561. //////////////////////////////////////////////////////////////////////////////
  562. //////////////////////////////////////////////////////////////////////////////
  563. //////////////////////////////////////////////////////////////////////////////
  564. // *FIX: The following code isn't grouped into functions yet.
  565. // Statistics / debug timer initialization
  566. init_statistics();
  567. //
  568. // Various introspection concerning the libs we're using - particularly
  569.         // the libs involved in getting to a full login screen.
  570. //
  571. LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL;
  572. LL_INFOS("InitInfo") << "libcurl version is: " << LLCurl::getVersionString() << LL_ENDL;
  573. // Get the single value from the crash settings file, if it exists
  574. std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
  575. gCrashSettings.loadFromFile(crash_settings_filename);
  576. if(gSavedSettings.getBOOL("IgnoreAllNotifications"))
  577. {
  578. gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ALWAYS_SEND);
  579. gCrashSettings.saveToFile(crash_settings_filename, FALSE);
  580. }
  581. /////////////////////////////////////////////////
  582. // OS-specific login dialogs
  583. /////////////////////////////////////////////////
  584. //test_cached_control();
  585. // track number of times that app has run
  586. mNumSessions = gSavedSettings.getS32("NumSessions");
  587. mNumSessions++;
  588. gSavedSettings.setS32("NumSessions", mNumSessions);
  589. if (gSavedSettings.getBOOL("VerboseLogs"))
  590. {
  591. LLError::setPrintLocation(true);
  592. }
  593. // Widget construction depends on LLUI being initialized
  594. LLUI::settings_map_t settings_map;
  595. settings_map["config"] = &gSavedSettings;
  596. settings_map["ignores"] = &gWarningSettings;
  597. settings_map["floater"] = &gSavedSettings; // *TODO: New settings file
  598. settings_map["account"] = &gSavedPerAccountSettings;
  599. LLUI::initClass(settings_map,
  600. LLUIImageList::getInstance(),
  601. ui_audio_callback,
  602. &LLUI::sGLScaleFactor);
  603. // Setup paths and LLTrans after LLUI::initClass has been called
  604. LLUI::setupPaths();
  605. LLTransUtil::parseStrings("strings.xml", default_trans_args);
  606. LLTransUtil::parseLanguageStrings("language_settings.xml");
  607. // LLKeyboard relies on LLUI to know what some accelerator keys are called.
  608. LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString );
  609. LLWeb::initClass();   // do this after LLUI
  610. // Provide the text fields with callbacks for opening Urls
  611. LLUrlAction::setOpenURLCallback(&LLWeb::loadURL);
  612. LLUrlAction::setOpenURLInternalCallback(&LLWeb::loadURLInternal);
  613. LLUrlAction::setOpenURLExternalCallback(&LLWeb::loadURLExternal);
  614. LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor);
  615. // Let code in llui access the viewer help floater
  616. LLUI::sHelpImpl = LLViewerHelp::getInstance();
  617. // Load translations for tooltips
  618. LLFloater::initClass();
  619. /////////////////////////////////////////////////
  620. LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated
  621. LLViewerFloaterReg::registerFloaters();
  622. /////////////////////////////////////////////////
  623. //
  624. // Load settings files
  625. //
  626. //
  627. LLGroupMgr::parseRoleActions("role_actions.xml");
  628. LLAgent::parseTeleportMessages("teleport_strings.xml");
  629. LLViewerJointMesh::updateVectorize();
  630. // load MIME type -> media impl mappings
  631. std::string mime_types_name;
  632. #if LL_DARWIN
  633. mime_types_name = "mime_types_mac.xml";
  634. #elif LL_LINUX
  635. mime_types_name = "mime_types_linux.xml";
  636. #else
  637. mime_types_name = "mime_types.xml";
  638. #endif
  639. LLMIMETypes::parseMIMETypes( mime_types_name ); 
  640. // Copy settings to globals. *TODO: Remove or move to appropriage class initializers
  641. settings_to_globals();
  642. // Setup settings listeners
  643. settings_setup_listeners();
  644. // Modify settings based on system configuration and compile options
  645. settings_modify();
  646. // Find partition serial number (Windows) or hardware serial (Mac)
  647. mSerialNumber = generateSerialNumber();
  648. // do any necessary set-up for accepting incoming SLURLs from apps
  649. initSLURLHandler();
  650. if(false == initHardwareTest())
  651. {
  652. // Early out from user choice.
  653. return false;
  654. }
  655. // Always fetch the Ethernet MAC address, needed both for login
  656. // and password load.
  657. LLUUID::getNodeID(gMACAddress);
  658. // Prepare for out-of-memory situations, during which we will crash on
  659. // purpose and save a dump.
  660. #if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
  661. MemSetErrorHandler(first_mem_error_handler);
  662. #endif // LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
  663. // *Note: this is where gViewerStats used to be created.
  664. //
  665. // Initialize the VFS, and gracefully handle initialization errors
  666. //
  667. if (!initCache())
  668. {
  669. std::ostringstream msg;
  670. msg << LLTrans::getString("MBUnableToAccessFile");
  671. OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
  672. return 1;
  673. }
  674. //
  675. // Initialize the window
  676. //
  677. gGLActive = TRUE;
  678. initWindow();
  679. // call all self-registered classes
  680. LLInitClassList::instance().fireCallbacks();
  681. LLFolderViewItem::initClass(); // SJB: Needs to happen after initWindow(), not sure why but related to fonts
  682. gGLManager.getGLInfo(gDebugInfo);
  683. gGLManager.printGLInfoString();
  684. //load key settings
  685. bind_keyboard_functions();
  686. // Load Default bindings
  687. if (!gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"keys.ini")))
  688. {
  689. LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL;
  690. }
  691. // Load Custom bindings (override defaults)
  692. gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"custom_keys.ini"));
  693. // If we don't have the right GL requirements, exit.
  694. if (!gGLManager.mHasRequirements && !gNoRender)
  695. {
  696. // can't use an alert here since we're exiting and
  697. // all hell breaks lose.
  698. OSMessageBox(
  699. LLNotifications::instance().getGlobalString("UnsupportedGLRequirements"),
  700. LLStringUtil::null,
  701. OSMB_OK);
  702. return 0;
  703. }
  704. // alert the user if they are using unsupported hardware
  705. if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware"))
  706. {
  707. bool unsupported = false;
  708. LLSD args;
  709. std::string minSpecs;
  710. // get cpu data from xml
  711. std::stringstream minCPUString(LLNotifications::instance().getGlobalString("UnsupportedCPUAmount"));
  712. S32 minCPU = 0;
  713. minCPUString >> minCPU;
  714. // get RAM data from XML
  715. std::stringstream minRAMString(LLNotifications::instance().getGlobalString("UnsupportedRAMAmount"));
  716. U64 minRAM = 0;
  717. minRAMString >> minRAM;
  718. minRAM = minRAM * 1024 * 1024;
  719. if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN)
  720. {
  721. minSpecs += LLNotifications::instance().getGlobalString("UnsupportedGPU");
  722. minSpecs += "n";
  723. unsupported = true;
  724. }
  725. if(gSysCPU.getMhz() < minCPU)
  726. {
  727. minSpecs += LLNotifications::instance().getGlobalString("UnsupportedCPU");
  728. minSpecs += "n";
  729. unsupported = true;
  730. }
  731. if(gSysMemory.getPhysicalMemoryClamped() < minRAM)
  732. {
  733. minSpecs += LLNotifications::instance().getGlobalString("UnsupportedRAM");
  734. minSpecs += "n";
  735. unsupported = true;
  736. }
  737. if (LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_UNKNOWN)
  738. {
  739. LLNotificationsUtil::add("UnknownGPU");
  740. if(unsupported)
  741. {
  742. if(!gSavedSettings.controlExists("WarnUnsupportedHardware") 
  743. || gSavedSettings.getBOOL("WarnUnsupportedHardware"))
  744. {
  745. args["MINSPECS"] = minSpecs;
  746. LLNotificationsUtil::add("UnsupportedHardware", args );
  747. }
  748. }
  749. }
  750. // save the graphics card
  751. gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString();
  752. // Save the current version to the prefs file
  753. gSavedSettings.setString("LastRunVersion", gCurrentVersion);
  754. gSimLastTime = gRenderStartTime.getElapsedTimeF32();
  755. gSimFrames = (F32)gFrameCount;
  756. LLViewerJoystick::getInstance()->init(false);
  757. gGLActive = FALSE;
  758. if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getS32("QAModeEventHostPort") > 0)
  759. {
  760. loadEventHostModule(gSavedSettings.getS32("QAModeEventHostPort"));
  761. }
  762. LLViewerMedia::initClass();
  763. return true;
  764. }
  765. static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages");
  766. static LLFastTimer::DeclareTimer FTM_SLEEP("Sleep");
  767. static LLFastTimer::DeclareTimer FTM_TEXTURE_CACHE("Texture Cache");
  768. static LLFastTimer::DeclareTimer FTM_DECODE("Image Decode");
  769. static LLFastTimer::DeclareTimer FTM_VFS("VFS Thread");
  770. static LLFastTimer::DeclareTimer FTM_LFS("LFS Thread");
  771. static LLFastTimer::DeclareTimer FTM_PAUSE_THREADS("Pause Threads");
  772. static LLFastTimer::DeclareTimer FTM_IDLE("Idle");
  773. static LLFastTimer::DeclareTimer FTM_PUMP("Pump");
  774. bool LLAppViewer::mainLoop()
  775. {
  776. LLMemType mt1(LLMemType::MTYPE_MAIN);
  777. mMainloopTimeout = new LLWatchdogTimeout();
  778. //-------------------------------------------
  779. // Run main loop until time to quit
  780. //-------------------------------------------
  781. // Create IO Pump to use for HTTP Requests.
  782. gServicePump = new LLPumpIO(gAPRPoolp);
  783. LLHTTPClient::setPump(*gServicePump);
  784. LLCurl::setCAFile(gDirUtilp->getCAFile());
  785. LLCurl::setSSLVerify(! gSavedSettings.getBOOL("NoVerifySSLCert"));
  786. // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
  787. LLVoiceChannel::initClass();
  788. LLVoiceClient::init(gServicePump);
  789. LLTimer frameTimer,idleTimer;
  790. LLTimer debugTime;
  791. LLViewerJoystick* joystick(LLViewerJoystick::getInstance());
  792. joystick->setNeedsReset(true);
  793.     LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
  794.     // As we do not (yet) send data on the mainloop LLEventPump that varies
  795.     // with each frame, no need to instantiate a new LLSD event object each
  796.     // time. Obviously, if that changes, just instantiate the LLSD at the
  797.     // point of posting.
  798.     LLSD newFrame;
  799. // Handle messages
  800. while (!LLApp::isExiting())
  801. {
  802. LLFastTimer::nextFrame(); // Should be outside of any timer instances
  803. try
  804. {
  805. pingMainloopTimeout("Main:MiscNativeWindowEvents");
  806. if (gViewerWindow)
  807. {
  808. LLFastTimer t2(FTM_MESSAGES);
  809. gViewerWindow->mWindow->processMiscNativeEvents();
  810. }
  811. pingMainloopTimeout("Main:GatherInput");
  812. if (gViewerWindow)
  813. {
  814. LLFastTimer t2(FTM_MESSAGES);
  815. if (!restoreErrorTrap())
  816. {
  817. llwarns << " Someone took over my signal/exception handler (post messagehandling)!" << llendl;
  818. }
  819. gViewerWindow->mWindow->gatherInput();
  820. }
  821. #if 1 && !LL_RELEASE_FOR_DOWNLOAD
  822. // once per second debug info
  823. if (debugTime.getElapsedTimeF32() > 1.f)
  824. {
  825. debugTime.reset();
  826. }
  827. #endif
  828. //memory leaking simulation
  829. LLFloaterMemLeak* mem_leak_instance =
  830. LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
  831. if(mem_leak_instance)
  832. {
  833. mem_leak_instance->idle() ;
  834. }
  835.             // canonical per-frame event
  836.             mainloop.post(newFrame);
  837. if (!LLApp::isExiting())
  838. {
  839. pingMainloopTimeout("Main:JoystickKeyboard");
  840. // Scan keyboard for movement keys.  Command keys and typing
  841. // are handled by windows callbacks.  Don't do this until we're
  842. // done initializing.  JC
  843. if (gViewerWindow->mWindow->getVisible() 
  844. && gViewerWindow->getActive()
  845. && !gViewerWindow->mWindow->getMinimized()
  846. && LLStartUp::getStartupState() == STATE_STARTED
  847. && !gViewerWindow->getShowProgress()
  848. && !gFocusMgr.focusLocked())
  849. {
  850. LLMemType mjk(LLMemType::MTYPE_JOY_KEY);
  851. joystick->scanJoystick();
  852. gKeyboard->scanKeyboard();
  853. }
  854. // Update state based on messages, user input, object idle.
  855. {
  856. pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
  857. LLFastTimer t3(FTM_IDLE);
  858. idle();
  859. if (gAres != NULL && gAres->isInitialized())
  860. {
  861. LLMemType mt_ip(LLMemType::MTYPE_IDLE_PUMP);
  862. pingMainloopTimeout("Main:ServicePump");
  863. LLFastTimer t4(FTM_PUMP);
  864. gAres->process();
  865. // this pump is necessary to make the login screen show up
  866. gServicePump->pump();
  867. gServicePump->callback();
  868. }
  869. resumeMainloopTimeout();
  870. }
  871.  
  872. if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
  873. {
  874. pauseMainloopTimeout();
  875. saveFinalSnapshot();
  876. disconnectViewer();
  877. resumeMainloopTimeout();
  878. }
  879. // Render scene.
  880. if (!LLApp::isExiting())
  881. {
  882. pingMainloopTimeout("Main:Display");
  883. gGLActive = TRUE;
  884. display();
  885. pingMainloopTimeout("Main:Snapshot");
  886. LLFloaterSnapshot::update(); // take snapshots
  887. gGLActive = FALSE;
  888. }
  889. }
  890. pingMainloopTimeout("Main:Sleep");
  891. pauseMainloopTimeout();
  892. // Sleep and run background threads
  893. {
  894. LLMemType mt_sleep(LLMemType::MTYPE_SLEEP);
  895. LLFastTimer t2(FTM_SLEEP);
  896. bool run_multiple_threads = gSavedSettings.getBOOL("RunMultipleThreads");
  897. // yield some time to the os based on command line option
  898. if(mYieldTime >= 0)
  899. {
  900. ms_sleep(mYieldTime);
  901. }
  902. // yield cooperatively when not running as foreground window
  903. if (   gNoRender
  904.    || (gViewerWindow && !gViewerWindow->mWindow->getVisible())
  905. || !gFocusMgr.getAppHasFocus())
  906. {
  907. // Sleep if we're not rendering, or the window is minimized.
  908. S32 milliseconds_to_sleep = llclamp(gSavedSettings.getS32("BackgroundYieldTime"), 0, 1000);
  909. // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads
  910. // of equal priority on Windows
  911. if (milliseconds_to_sleep > 0)
  912. {
  913. ms_sleep(milliseconds_to_sleep);
  914. // also pause worker threads during this wait period
  915. LLAppViewer::getTextureCache()->pause();
  916. LLAppViewer::getImageDecodeThread()->pause();
  917. }
  918. }
  919. if (mRandomizeFramerate)
  920. {
  921. ms_sleep(rand() % 200);
  922. }
  923. if (mPeriodicSlowFrame
  924. && (gFrameCount % 10 == 0))
  925. {
  926. llinfos << "Periodic slow frame - sleeping 500 ms" << llendl;
  927. ms_sleep(500);
  928. }
  929. const F64 min_frame_time = 0.0; //(.0333 - .0010); // max video frame rate = 30 fps
  930. const F64 min_idle_time = 0.0; //(.0010); // min idle time = 1 ms
  931. const F64 max_idle_time = run_multiple_threads ? min_idle_time : llmin(.005*10.0*gFrameTimeSeconds, 0.005); // 5 ms a second
  932. idleTimer.reset();
  933. while(1)
  934. {
  935. S32 work_pending = 0;
  936. S32 io_pending = 0;
  937. {
  938. LLFastTimer ftm(FTM_TEXTURE_CACHE);
  939.   work_pending += LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
  940. }
  941. {
  942. LLFastTimer ftm(FTM_DECODE);
  943.   work_pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
  944. }
  945. {
  946. LLFastTimer ftm(FTM_DECODE);
  947.   work_pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
  948. }
  949. {
  950. LLFastTimer ftm(FTM_VFS);
  951.   io_pending += LLVFSThread::updateClass(1);
  952. }
  953. {
  954. LLFastTimer ftm(FTM_LFS);
  955.   io_pending += LLLFSThread::updateClass(1);
  956. }
  957. if (io_pending > 1000)
  958. {
  959. ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up
  960. }
  961. F64 frame_time = frameTimer.getElapsedTimeF64();
  962. F64 idle_time = idleTimer.getElapsedTimeF64();
  963. if (frame_time >= min_frame_time &&
  964. idle_time >= min_idle_time &&
  965. (!work_pending || idle_time >= max_idle_time))
  966. {
  967. break;
  968. }
  969. }
  970. if ((LLStartUp::getStartupState() >= STATE_CLEANUP) &&
  971. (frameTimer.getElapsedTimeF64() > FRAME_STALL_THRESHOLD))
  972. {
  973. gFrameStalls++;
  974. }
  975. frameTimer.reset();
  976.  // Prevent the worker threads from running while rendering.
  977. // if (LLThread::processorCount()==1) //pause() should only be required when on a single processor client...
  978. if (run_multiple_threads == FALSE)
  979. {
  980. LLFastTimer ftm(FTM_PAUSE_THREADS);
  981.  
  982. LLAppViewer::getTextureCache()->pause();
  983. LLAppViewer::getImageDecodeThread()->pause();
  984. // LLAppViewer::getTextureFetch()->pause(); // Don't pause the fetch (IO) thread
  985. }
  986. //LLVFSThread::sLocal->pause(); // Prevent the VFS thread from running while rendering.
  987. //LLLFSThread::sLocal->pause(); // Prevent the LFS thread from running while rendering.
  988. resumeMainloopTimeout();
  989. pingMainloopTimeout("Main:End");
  990. }
  991. }
  992. catch(std::bad_alloc)
  993. {
  994. //stop memory leaking simulation
  995. LLFloaterMemLeak* mem_leak_instance =
  996. LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
  997. if(mem_leak_instance)
  998. {
  999. mem_leak_instance->stop() ;
  1000. llwarns << "Bad memory allocation in LLAppViewer::mainLoop()!" << llendl ;
  1001. }
  1002. else
  1003. {
  1004. //output possible call stacks to log file.
  1005. LLError::LLCallStacks::print() ;
  1006. llerrs << "Bad memory allocation in LLAppViewer::mainLoop()!" << llendl ;
  1007. }
  1008. }
  1009. }
  1010. // Save snapshot for next time, if we made it through initialization
  1011. if (STATE_STARTED == LLStartUp::getStartupState())
  1012. {
  1013. try
  1014. {
  1015. saveFinalSnapshot();
  1016. }
  1017. catch(std::bad_alloc)
  1018. {
  1019. llwarns << "Bad memory allocation when saveFinalSnapshot() is called!" << llendl ;
  1020. //stop memory leaking simulation
  1021. LLFloaterMemLeak* mem_leak_instance =
  1022. LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
  1023. if(mem_leak_instance)
  1024. {
  1025. mem_leak_instance->stop() ;
  1026. }
  1027. }
  1028. }
  1029. delete gServicePump;
  1030. destroyMainloopTimeout();
  1031. llinfos << "Exiting main_loop" << llendflush;
  1032. return true;
  1033. }
  1034. bool LLAppViewer::cleanup()
  1035. {
  1036. // workaround for DEV-35406 crash on shutdown
  1037. LLEventPumps::instance().reset();
  1038. // *TODO - generalize this and move DSO wrangling to a helper class -brad
  1039. std::set<struct apr_dso_handle_t *>::const_iterator i;
  1040. for(i = mPlugins.begin(); i != mPlugins.end(); ++i)
  1041. {
  1042. int (*ll_plugin_stop_func)(void) = NULL;
  1043. apr_status_t rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_stop_func, *i, "ll_plugin_stop");
  1044. ll_plugin_stop_func();
  1045. rv = apr_dso_unload(*i);
  1046. }
  1047. mPlugins.clear();
  1048. //----------------------------------------------
  1049. //this test code will be removed after the test
  1050. //test manual call stack tracer
  1051. if(gSavedSettings.getBOOL("QAMode"))
  1052. {
  1053. LLError::LLCallStacks::print() ;
  1054. }
  1055. //end of the test code
  1056. //----------------------------------------------
  1057. //flag all elements as needing to be destroyed immediately
  1058. // to ensure shutdown order
  1059. LLMortician::setZealous(TRUE);
  1060. LLVoiceClient::terminate();
  1061. disconnectViewer();
  1062. llinfos << "Viewer disconnected" << llendflush;
  1063. display_cleanup(); 
  1064. release_start_screen(); // just in case
  1065. LLError::logToFixedBuffer(NULL);
  1066. llinfos << "Cleaning Up" << llendflush;
  1067. // Must clean up texture references before viewer window is destroyed.
  1068. LLHUDManager::getInstance()->updateEffects();
  1069. LLHUDObject::updateAll();
  1070. LLHUDManager::getInstance()->cleanupEffects();
  1071. LLHUDObject::cleanupHUDObjects();
  1072. llinfos << "HUD Objects cleaned up" << llendflush;
  1073. LLKeyframeDataCache::clear();
  1074.   // End TransferManager before deleting systems it depends on (Audio, VFS, AssetStorage)
  1075. #if 0 // this seems to get us stuck in an infinite loop...
  1076. gTransferManager.cleanup();
  1077. #endif
  1078. // Note: this is where gWorldMap used to be deleted.
  1079. // Note: this is where gHUDManager used to be deleted.
  1080. LLHUDManager::getInstance()->shutdownClass();
  1081. delete gAssetStorage;
  1082. gAssetStorage = NULL;
  1083. LLPolyMesh::freeAllMeshes();
  1084. delete gCacheName;
  1085. gCacheName = NULL;
  1086. // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted.
  1087. LLWorldMap::getInstance()->reset(); // release any images
  1088. llinfos << "Global stuff deleted" << llendflush;
  1089. if (gAudiop)
  1090. {
  1091. // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem.
  1092. LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl();
  1093. delete sai;
  1094. gAudiop->setStreamingAudioImpl(NULL);
  1095. // shut down the audio subsystem
  1096. bool want_longname = false;
  1097. if (gAudiop->getDriverName(want_longname) == "FMOD")
  1098. {
  1099. // This hack exists because fmod likes to occasionally
  1100. // crash or hang forever when shutting down, for no
  1101. // apparent reason.
  1102. llwarns << "Hack, skipping FMOD audio engine cleanup" << llendflush;
  1103. }
  1104. else
  1105. {
  1106. gAudiop->shutdown();
  1107. }
  1108. delete gAudiop;
  1109. gAudiop = NULL;
  1110. }
  1111. // Note: this is where LLFeatureManager::getInstance()-> used to be deleted.
  1112. // Patch up settings for next time
  1113. // Must do this before we delete the viewer window,
  1114. // such that we can suck rectangle information out of
  1115. // it.
  1116. cleanupSavedSettings();
  1117. llinfos << "Settings patched up" << llendflush;
  1118. // delete some of the files left around in the cache.
  1119. removeCacheFiles("*.wav");
  1120. removeCacheFiles("*.tmp");
  1121. removeCacheFiles("*.lso");
  1122. removeCacheFiles("*.out");
  1123. removeCacheFiles("*.dsf");
  1124. removeCacheFiles("*.bodypart");
  1125. removeCacheFiles("*.clothing");
  1126. llinfos << "Cache files removed" << llendflush;
  1127. // Wait for any pending VFS IO
  1128. while (1)
  1129. {
  1130. S32 pending = LLVFSThread::updateClass(0);
  1131. pending += LLLFSThread::updateClass(0);
  1132. if (!pending)
  1133. {
  1134. break;
  1135. }
  1136. llinfos << "Waiting for pending IO to finish: " << pending << llendflush;
  1137. ms_sleep(100);
  1138. }
  1139. llinfos << "Shutting down Views" << llendflush;
  1140. // Destroy the UI
  1141. if( gViewerWindow)
  1142. gViewerWindow->shutdownViews();
  1143. llinfos << "Cleaning up Inventory" << llendflush;
  1144. // Cleanup Inventory after the UI since it will delete any remaining observers
  1145. // (Deleted observers should have already removed themselves)
  1146. gInventory.cleanupInventory();
  1147. llinfos << "Cleaning up Selections" << llendflush;
  1148. // Clean up selection managers after UI is destroyed, as UI may be observing them.
  1149. // Clean up before GL is shut down because we might be holding on to objects with texture references
  1150. LLSelectMgr::cleanupGlobals();
  1151. llinfos << "Shutting down OpenGL" << llendflush;
  1152. // Shut down OpenGL
  1153. if( gViewerWindow)
  1154. {
  1155. gViewerWindow->shutdownGL();
  1156. // Destroy window, and make sure we're not fullscreen
  1157. // This may generate window reshape and activation events.
  1158. // Therefore must do this before destroying the message system.
  1159. delete gViewerWindow;
  1160. gViewerWindow = NULL;
  1161. llinfos << "ViewerWindow deleted" << llendflush;
  1162. }
  1163. llinfos << "Cleaning up Keyboard & Joystick" << llendflush;
  1164. // viewer UI relies on keyboard so keep it aound until viewer UI isa gone
  1165. delete gKeyboard;
  1166. gKeyboard = NULL;
  1167. // Turn off Space Navigator and similar devices
  1168. LLViewerJoystick::getInstance()->terminate();
  1169. llinfos << "Cleaning up Objects" << llendflush;
  1170. LLViewerObject::cleanupVOClasses();
  1171. LLWaterParamManager::cleanupClass();
  1172. LLWLParamManager::cleanupClass();
  1173. LLPostProcess::cleanupClass();
  1174. LLTracker::cleanupInstance();
  1175. // *FIX: This is handled in LLAppViewerWin32::cleanup().
  1176. // I'm keeping the comment to remember its order in cleanup,
  1177. // in case of unforseen dependency.
  1178. //#if LL_WINDOWS
  1179. // gDXHardware.cleanup();
  1180. //#endif // LL_WINDOWS
  1181. LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager();
  1182. if (!volume_manager->cleanup())
  1183. {
  1184. llwarns << "Remaining references in the volume manager!" << llendflush;
  1185. }
  1186. LLPrimitive::cleanupVolumeManager();
  1187. llinfos << "Additional Cleanup..." << llendflush;
  1188. LLViewerParcelMgr::cleanupGlobals();
  1189. // *Note: this is where gViewerStats used to be deleted.
  1190.   //end_messaging_system();
  1191. LLFollowCamMgr::cleanupClass();
  1192. //LLVolumeMgr::cleanupClass();
  1193. LLPrimitive::cleanupVolumeManager();
  1194. LLWorldMapView::cleanupClass();
  1195. LLFolderViewItem::cleanupClass();
  1196. LLUI::cleanupClass();
  1197. //
  1198. // Shut down the VFS's AFTER the decode manager cleans up (since it cleans up vfiles).
  1199. // Also after viewerwindow is deleted, since it may have image pointers (which have vfiles)
  1200. // Also after shutting down the messaging system since it has VFS dependencies
  1201. //
  1202. llinfos << "Cleaning up VFS" << llendflush;
  1203. LLVFile::cleanupClass();
  1204. llinfos << "Saving Data" << llendflush;
  1205. // Quitting with "Remember Password" turned off should always stomp your
  1206. // saved password, whether or not you successfully logged in.  JC
  1207. if (!gSavedSettings.getBOOL("RememberPassword"))
  1208. {
  1209. LLStartUp::deletePasswordFromDisk();
  1210. }
  1211. // Store the time of our current logoff
  1212. gSavedPerAccountSettings.setU32("LastLogoff", time_corrected());
  1213. // Must do this after all panels have been deleted because panels that have persistent rects
  1214. // save their rects on delete.
  1215. gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);
  1216. LLUIColorTable::instance().saveUserSettings();
  1217. // PerAccountSettingsFile should be empty if no user has been logged on.
  1218. // *FIX:Mani This should get really saved in a "logoff" mode. 
  1219. if (gSavedSettings.getString("PerAccountSettingsFile").empty())
  1220. {
  1221. llinfos << "Not saving per-account settings; don't know the account name yet." << llendl;
  1222. }
  1223. else
  1224. {
  1225. gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);
  1226. llinfos << "Saved settings" << llendflush;
  1227. }
  1228. std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
  1229. // save all settings, even if equals defaults
  1230. gCrashSettings.saveToFile(crash_settings_filename, FALSE);
  1231. std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings"));
  1232. gWarningSettings.saveToFile(warnings_settings_filename, TRUE);
  1233. // Save URL history file
  1234. LLURLHistory::saveFile("url_history.xml");
  1235. // save mute list. gMuteList used to also be deleted here too.
  1236. LLMuteList::getInstance()->cache(gAgent.getID());
  1237. if (mPurgeOnExit)
  1238. {
  1239. llinfos << "Purging all cache files on exit" << llendflush;
  1240. std::string mask = gDirUtilp->getDirDelimiter() + "*.*";
  1241. gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);
  1242. }
  1243. removeMarkerFile(); // Any crashes from here on we'll just have to ignore
  1244. writeDebugInfo();
  1245. LLLocationHistory::getInstance()->save();
  1246. LLAvatarIconIDCache::getInstance()->save();
  1247. llinfos << "Shutting down Threads" << llendflush;
  1248. // Let threads finish
  1249. LLTimer idleTimer;
  1250. idleTimer.reset();
  1251. const F64 max_idle_time = 5.f; // 5 seconds
  1252. while(1)
  1253. {
  1254. S32 pending = 0;
  1255. pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread
  1256. pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
  1257. pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
  1258. pending += LLVFSThread::updateClass(0);
  1259. pending += LLLFSThread::updateClass(0);
  1260. F64 idle_time = idleTimer.getElapsedTimeF64();
  1261. if (!pending || idle_time >= max_idle_time)
  1262. {
  1263. llwarns << "Quitting with pending background tasks." << llendl;
  1264. break;
  1265. }
  1266. }
  1267. // Delete workers first
  1268. // shotdown all worker threads before deleting them in case of co-dependencies
  1269. sTextureCache->shutdown();
  1270. sTextureFetch->shutdown();
  1271. sImageDecodeThread->shutdown();
  1272. delete sTextureCache;
  1273.     sTextureCache = NULL;
  1274. delete sTextureFetch;
  1275.     sTextureFetch = NULL;
  1276. delete sImageDecodeThread;
  1277.     sImageDecodeThread = NULL;
  1278. delete mFastTimerLogThread;
  1279. mFastTimerLogThread = NULL;
  1280. if (LLFastTimerView::sAnalyzePerformance)
  1281. {
  1282. llinfos << "Analyzing performance" << llendl;
  1283. if(LLFastTimer::sLog)
  1284. {
  1285. LLFastTimerView::doAnalysis(
  1286. gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance_baseline.slp"),
  1287. gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance.slp"),
  1288. gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance_report.csv"));
  1289. }
  1290. if(LLFastTimer::sMetricLog)
  1291. {
  1292. LLFastTimerView::doAnalysis(
  1293. gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric_baseline.slp"),
  1294. gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric.slp"),
  1295. gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric_report.csv"));
  1296. }
  1297. }
  1298. LLMetricPerformanceTester::cleanClass() ;
  1299. llinfos << "Cleaning up Media and Textures" << llendflush;
  1300. //Note:
  1301. //LLViewerMedia::cleanupClass() has to be put before gTextureList.shutdown()
  1302. //because some new image might be generated during cleaning up media. --bao
  1303. LLViewerMedia::cleanupClass();
  1304. LLViewerParcelMedia::cleanupClass();
  1305. gTextureList.shutdown(); // shutdown again in case a callback added something
  1306. LLUIImageList::getInstance()->cleanUp();
  1307. // This should eventually be done in LLAppViewer
  1308. LLImage::cleanupClass();
  1309. LLVFSThread::cleanupClass();
  1310. LLLFSThread::cleanupClass();
  1311. #ifndef LL_RELEASE_FOR_DOWNLOAD
  1312. llinfos << "Auditing VFS" << llendl;
  1313. gVFS->audit();
  1314. #endif
  1315. llinfos << "Misc Cleanup" << llendflush;
  1316. // For safety, the LLVFS has to be deleted *after* LLVFSThread. This should be cleaned up.
  1317. // (LLVFS doesn't know about LLVFSThread so can't kill pending requests) -Steve
  1318. delete gStaticVFS;
  1319. gStaticVFS = NULL;
  1320. delete gVFS;
  1321. gVFS = NULL;
  1322. gSavedSettings.cleanup();
  1323. LLUIColorTable::instance().clear();
  1324. gCrashSettings.cleanup();
  1325. LLWatchdog::getInstance()->cleanup();
  1326. llinfos << "Shutting down message system" << llendflush;
  1327. end_messaging_system();
  1328. // *NOTE:Mani - The following call is not thread safe. 
  1329. LLCurl::cleanupClass();
  1330. // If we're exiting to launch an URL, do that here so the screen
  1331. // is at the right resolution before we launch IE.
  1332. if (!gLaunchFileOnQuit.empty())
  1333. {
  1334. llinfos << "Launch file on quit." << llendflush;
  1335. #if LL_WINDOWS
  1336. // Indicate an application is starting.
  1337. SetCursor(LoadCursor(NULL, IDC_WAIT));
  1338. #endif
  1339. // HACK: Attempt to wait until the screen res. switch is complete.
  1340. ms_sleep(1000);
  1341. LLWeb::loadURLExternal( gLaunchFileOnQuit );
  1342. llinfos << "File launched." << llendflush;
  1343. }
  1344. ll_close_fail_log();
  1345.     llinfos << "Goodbye!" << llendflush;
  1346. // return 0;
  1347. return true;
  1348. }
  1349. // A callback for llerrs to call during the watchdog error.
  1350. void watchdog_llerrs_callback(const std::string &error_string)
  1351. {
  1352. gLLErrorActivated = true;
  1353. #ifdef LL_WINDOWS
  1354. RaiseException(0,0,0,0);
  1355. #else
  1356. raise(SIGQUIT);
  1357. #endif
  1358. }
  1359. // A callback for the watchdog to call.
  1360. void watchdog_killer_callback()
  1361. {
  1362. LLError::setFatalFunction(watchdog_llerrs_callback);
  1363. llerrs << "Watchdog killer event" << llendl;
  1364. }
  1365. bool LLAppViewer::initThreads()
  1366. {
  1367. #if MEM_TRACK_MEM
  1368. static const bool enable_threads = false;
  1369. #else
  1370. static const bool enable_threads = true;
  1371. #endif
  1372. const S32 NEVER_SUBMIT_REPORT = 2;
  1373. bool use_watchdog = gSavedSettings.getBOOL("WatchdogEnabled");
  1374. bool send_reports = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING) != NEVER_SUBMIT_REPORT;
  1375. if(use_watchdog && send_reports)
  1376. {
  1377. LLWatchdog::getInstance()->init(watchdog_killer_callback);
  1378. }
  1379. LLVFSThread::initClass(enable_threads && false);
  1380. LLLFSThread::initClass(enable_threads && false);
  1381. // Image decoding
  1382. LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true);
  1383. LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true);
  1384. LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), sImageDecodeThread, enable_threads && true);
  1385. LLImage::initClass();
  1386. if (LLFastTimer::sLog || LLFastTimer::sMetricLog)
  1387. {
  1388. LLFastTimer::sLogLock = new LLMutex(NULL);
  1389. mFastTimerLogThread = new LLFastTimerLogThread();
  1390. mFastTimerLogThread->start();
  1391. }
  1392. // *FIX: no error handling here!
  1393. return true;
  1394. }
  1395. void errorCallback(const std::string &error_string)
  1396. {
  1397. #ifndef LL_RELEASE_FOR_DOWNLOAD
  1398. OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_OK);
  1399. #endif
  1400. //Set the ErrorActivated global so we know to create a marker file
  1401. gLLErrorActivated = true;
  1402. LLError::crashAndLoop(error_string);
  1403. }
  1404. bool LLAppViewer::initLogging()
  1405. {
  1406. //
  1407. // Set up logging defaults for the viewer
  1408. //
  1409. LLError::initForApplication(
  1410. gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
  1411. LLError::setFatalFunction(errorCallback);
  1412. // Remove the last ".old" log file.
  1413. std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
  1414.      "SecondLife.old");
  1415. LLFile::remove(old_log_file);
  1416. // Rename current log file to ".old"
  1417. std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
  1418.      "SecondLife.log");
  1419. LLFile::rename(log_file, old_log_file);
  1420. // Set the log file to SecondLife.log
  1421. LLError::logToFile(log_file);
  1422. // *FIX:Mani no error handling here!
  1423. return true;
  1424. }
  1425. bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
  1426.     bool set_defaults)
  1427. {
  1428. // Find and vet the location key.
  1429. if(!mSettingsLocationList.has(location_key))
  1430. {
  1431. llerrs << "Requested unknown location: " << location_key << llendl;
  1432. return false;
  1433. }
  1434. LLSD location = mSettingsLocationList.get(location_key);
  1435. if(!location.has("PathIndex"))
  1436. {
  1437. llerrs << "Settings location is missing PathIndex value. Settings cannot be loaded." << llendl;
  1438. return false;
  1439. }
  1440. ELLPath path_index = (ELLPath)(location.get("PathIndex").asInteger());
  1441. if(path_index <= LL_PATH_NONE || path_index >= LL_PATH_LAST)
  1442. {
  1443. llerrs << "Out of range path index in app_settings/settings_files.xml" << llendl;
  1444. return false;
  1445. }
  1446. // Iterate through the locations list of files.
  1447. LLSD files = location.get("Files");
  1448. for(LLSD::map_iterator itr = files.beginMap(); itr != files.endMap(); ++itr)
  1449. {
  1450. std::string settings_group = (*itr).first;
  1451. llinfos << "Attempting to load settings for the group " << settings_group 
  1452.     << " - from location " << location_key << llendl;
  1453. if(!LLControlGroup::getInstance(settings_group))
  1454. {
  1455. llwarns << "No matching settings group for name " << settings_group << llendl;
  1456. continue;
  1457. }
  1458. LLSD file = (*itr).second;
  1459. std::string full_settings_path;
  1460. if(file.has("NameFromSetting"))
  1461. {
  1462. std::string custom_name_setting = file.get("NameFromSetting");
  1463. // *NOTE: Regardless of the group currently being lodaed,
  1464. // this setting is always read from the Global settings.
  1465. if(LLControlGroup::getInstance(sGlobalSettingsName)->controlExists(custom_name_setting))
  1466. {
  1467. std::string file_name = 
  1468. LLControlGroup::getInstance(sGlobalSettingsName)->getString(custom_name_setting);
  1469. full_settings_path = file_name;
  1470. }
  1471. }
  1472. if(full_settings_path.empty())
  1473. {
  1474. std::string file_name = file.get("Name");
  1475. full_settings_path = gDirUtilp->getExpandedFilename(path_index, file_name);
  1476. }
  1477. int requirement = 0;
  1478. if(file.has("Requirement"))
  1479. {
  1480. requirement = file.get("Requirement").asInteger();
  1481. }
  1482. if(!LLControlGroup::getInstance(settings_group)->loadFromFile(full_settings_path, set_defaults))
  1483. {
  1484. if(requirement == 1)
  1485. {
  1486. llwarns << "Error: Cannot load required settings file from: " 
  1487. << full_settings_path << llendl;
  1488. return false;
  1489. }
  1490. else
  1491. {
  1492. llwarns << "Cannot load " << full_settings_path << " - No settings found." << llendl;
  1493. }
  1494. }
  1495. else
  1496. {
  1497. llinfos << "Loaded settings file " << full_settings_path << llendl;
  1498. }
  1499. }
  1500. return true;
  1501. }
  1502. std::string LLAppViewer::getSettingsFilename(const std::string& location_key,
  1503.  const std::string& file)
  1504. {
  1505. if(mSettingsLocationList.has(location_key))
  1506. {
  1507. LLSD location = mSettingsLocationList.get(location_key);
  1508. if(location.has("Files"))
  1509. {
  1510. LLSD files = location.get("Files");
  1511. if(files.has(file) && files[file].has("Name"))
  1512. {
  1513. return files.get(file).get("Name").asString();
  1514. }
  1515. }
  1516. }
  1517. return std::string();
  1518. }
  1519. void LLAppViewer::loadColorSettings()
  1520. {
  1521. LLUIColorTable::instance().loadFromSettings();
  1522. }
  1523. bool LLAppViewer::initConfiguration()
  1524. {
  1525. //Load settings files list
  1526. std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml");
  1527. LLControlGroup settings_control("SettingsFiles");
  1528. llinfos << "Loading settings file list " << settings_file_list << llendl;
  1529. if (0 == settings_control.loadFromFile(settings_file_list))
  1530. {
  1531.         llerrs << "Cannot load default configuration file " << settings_file_list << llendl;
  1532. }
  1533. mSettingsLocationList = settings_control.getLLSD("Locations");
  1534. // The settings and command line parsing have a fragile
  1535. // order-of-operation:
  1536. // - load defaults from app_settings
  1537. // - set procedural settings values
  1538. // - read command line settings
  1539. // - selectively apply settings needed to load user settings.
  1540.     // - load overrides from user_settings 
  1541. // - apply command line settings (to override the overrides)
  1542. // - load per account settings (happens in llstartup
  1543. // - load defaults
  1544. bool set_defaults = true;
  1545. if(!loadSettingsFromDirectory("Default", set_defaults))
  1546. {
  1547. std::ostringstream msg;
  1548. msg << "Unable to load default settings file. The installation may be corrupted.";
  1549. OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
  1550. return false;
  1551. }
  1552. LLUI::setupPaths(); // setup paths for LLTrans based on settings files only
  1553. LLTransUtil::parseStrings("strings.xml", default_trans_args);
  1554. LLTransUtil::parseLanguageStrings("language_settings.xml");
  1555. // - set procedural settings
  1556. // Note: can't use LL_PATH_PER_SL_ACCOUNT for any of these since we haven't logged in yet
  1557. gSavedSettings.setString("ClientSettingsFile", 
  1558.         gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global")));
  1559. gSavedSettings.setString("VersionChannelName", LLVersionInfo::getChannel());
  1560. #ifndef LL_RELEASE_FOR_DOWNLOAD
  1561. // provide developer build only overrides for these control variables that are not
  1562. // persisted to settings.xml
  1563. LLControlVariable* c = gSavedSettings.getControl("ShowConsoleWindow");
  1564. if (c)
  1565. {
  1566. c->setValue(true, false);
  1567. }
  1568. c = gSavedSettings.getControl("AllowMultipleViewers");
  1569. if (c)
  1570. {
  1571. c->setValue(true, false);
  1572. }
  1573. #endif
  1574. //*FIX:Mani - Set default to disabling watchdog mainloop 
  1575. // timeout for mac and linux. There is no call stack info 
  1576. // on these platform to help debug.
  1577. #ifndef LL_RELEASE_FOR_DOWNLOAD
  1578. gSavedSettings.setBOOL("WatchdogEnabled", FALSE);
  1579. gSavedSettings.setBOOL("QAMode", TRUE );
  1580. #endif
  1581. #ifndef LL_WINDOWS
  1582. gSavedSettings.setBOOL("WatchdogEnabled", FALSE);
  1583. #endif
  1584. gCrashSettings.getControl(CRASH_BEHAVIOR_SETTING)->getSignal()->connect(boost::bind(&handleCrashSubmitBehaviorChanged, _2));
  1585. // These are warnings that appear on the first experience of that condition.
  1586. // They are already set in the settings_default.xml file, but still need to be added to LLFirstUse
  1587. // for disable/reset ability
  1588. // LLFirstUse::addConfigVariable("FirstBalanceIncrease");
  1589. // LLFirstUse::addConfigVariable("FirstBalanceDecrease");
  1590. // LLFirstUse::addConfigVariable("FirstSit");
  1591. // LLFirstUse::addConfigVariable("FirstMap");
  1592. // LLFirstUse::addConfigVariable("FirstGoTo");
  1593. // LLFirstUse::addConfigVariable("FirstBuild");
  1594. // LLFirstUse::addConfigVariable("FirstLeftClickNoHit");
  1595. // LLFirstUse::addConfigVariable("FirstTeleport");
  1596. // LLFirstUse::addConfigVariable("FirstOverrideKeys");
  1597. // LLFirstUse::addConfigVariable("FirstAttach");
  1598. // LLFirstUse::addConfigVariable("FirstAppearance");
  1599. // LLFirstUse::addConfigVariable("FirstInventory");
  1600. // LLFirstUse::addConfigVariable("FirstSandbox");
  1601. // LLFirstUse::addConfigVariable("FirstFlexible");
  1602. // LLFirstUse::addConfigVariable("FirstDebugMenus");
  1603. // LLFirstUse::addConfigVariable("FirstSculptedPrim");
  1604. // LLFirstUse::addConfigVariable("FirstVoice");
  1605. // LLFirstUse::addConfigVariable("FirstMedia");
  1606. // - read command line settings.
  1607. LLControlGroupCLP clp;
  1608. std::string cmd_line_config = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,
  1609.   "cmd_line.xml");
  1610. clp.configure(cmd_line_config, &gSavedSettings);
  1611. if(!initParseCommandLine(clp))
  1612. {
  1613. llwarns << "Error parsing command line options. Command Line options ignored."  << llendl;
  1614. llinfos << "Command line usage:n" << clp << llendl;
  1615. std::ostringstream msg;
  1616. msg << LLTrans::getString("MBCmdLineError") << clp.getErrorMessage();
  1617. OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
  1618. return false;
  1619. }
  1620. // - selectively apply settings 
  1621. // If the user has specified a alternate settings file name.
  1622. // Load it now before loading the user_settings/settings.xml
  1623. if(clp.hasOption("settings"))
  1624. {
  1625. std::string user_settings_filename = 
  1626. gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, 
  1627.    clp.getOption("settings")[0]);
  1628. gSavedSettings.setString("ClientSettingsFile", user_settings_filename);
  1629. llinfos << "Using command line specified settings filename: " 
  1630. << user_settings_filename << llendl;
  1631. }
  1632. // - load overrides from user_settings 
  1633. loadSettingsFromDirectory("User");
  1634. // - apply command line settings 
  1635. clp.notify(); 
  1636. // Handle initialization from settings.
  1637. // Start up the debugging console before handling other options.
  1638. if (gSavedSettings.getBOOL("ShowConsoleWindow"))
  1639. {
  1640. initConsole();
  1641. }
  1642. if(clp.hasOption("help"))
  1643. {
  1644. std::ostringstream msg;
  1645. msg << LLTrans::getString("MBCmdLineUsg") << "n" << clp;
  1646. llinfos << msg.str() << llendl;
  1647. OSMessageBox(
  1648. msg.str().c_str(),
  1649. LLStringUtil::null,
  1650. OSMB_OK);
  1651. return false;
  1652. }
  1653.     if(clp.hasOption("set"))
  1654.     {
  1655.         const LLCommandLineParser::token_vector_t& set_values = clp.getOption("set");
  1656.         if(0x1 & set_values.size())
  1657.         {
  1658.             llwarns << "Invalid '--set' parameter count." << llendl;
  1659.         }
  1660.         else
  1661.         {
  1662.             LLCommandLineParser::token_vector_t::const_iterator itr = set_values.begin();
  1663.             for(; itr != set_values.end(); ++itr)
  1664.             {
  1665.                 const std::string& name = *itr;
  1666.                 const std::string& value = *(++itr);
  1667. LLControlVariable* c = LLControlGroup::getInstance(sGlobalSettingsName)->getControl(name);
  1668.                 if(c)
  1669.                 {
  1670.                     c->setValue(value, false);
  1671.                 }
  1672.                 else
  1673.                 {
  1674.                     llwarns << "'--set' specified with unknown setting: '"
  1675.                         << name << "'." << llendl;
  1676.                 }
  1677.             }
  1678.         }
  1679.     }
  1680.     initGridChoice();
  1681. // If we have specified crash on startup, set the global so we'll trigger the crash at the right time
  1682. if(clp.hasOption("crashonstartup"))
  1683. {
  1684. gCrashOnStartup = TRUE;
  1685. }
  1686. if (clp.hasOption("logperformance"))
  1687. {
  1688. LLFastTimer::sLog = TRUE;
  1689. }
  1690. if(clp.hasOption("logmetrics"))
  1691. {
  1692. LLFastTimer::sMetricLog = TRUE ;
  1693. }
  1694. if (clp.hasOption("graphicslevel"))
  1695. {
  1696. const LLCommandLineParser::token_vector_t& value = clp.getOption("graphicslevel");
  1697.         if(value.size() != 1)
  1698.         {
  1699. llwarns << "Usage: -graphicslevel <0-3>" << llendl;
  1700.         }
  1701.         else
  1702.         {
  1703. std::string detail = value.front();
  1704. mForceGraphicsDetail = TRUE;
  1705. switch (detail.c_str()[0])
  1706. {
  1707. case '0': 
  1708. gSavedSettings.setU32("RenderQualityPerformance", 0);
  1709. break;
  1710. case '1': 
  1711. gSavedSettings.setU32("RenderQualityPerformance", 1);
  1712. break;
  1713. case '2': 
  1714. gSavedSettings.setU32("RenderQualityPerformance", 2);
  1715. break;
  1716. case '3': 
  1717. gSavedSettings.setU32("RenderQualityPerformance", 3);
  1718. break;
  1719. default:
  1720. mForceGraphicsDetail = FALSE;
  1721. llwarns << "Usage: -graphicslevel <0-3>" << llendl;
  1722. break;
  1723. }
  1724.         }
  1725. }
  1726. if (clp.hasOption("analyzeperformance"))
  1727. {
  1728. LLFastTimerView::sAnalyzePerformance = TRUE;
  1729. }
  1730. if (clp.hasOption("replaysession"))
  1731. {
  1732. LLAgentPilot::sReplaySession = TRUE;
  1733. }
  1734. if (clp.hasOption("nonotifications"))
  1735. {
  1736. gSavedSettings.setBOOL("IgnoreAllNotifications", TRUE);
  1737. }
  1738. if (clp.hasOption("debugsession"))
  1739. {
  1740. gDebugSession = TRUE;
  1741. gDebugGL = TRUE;
  1742. ll_init_fail_log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "test_failures.log"));
  1743. }
  1744. // Handle slurl use. NOTE: Don't let SL-55321 reappear.
  1745.     // *FIX: This init code should be made more robust to prevent 
  1746.     // the issue SL-55321 from returning. One thought is to allow 
  1747.     // only select options to be set from command line when a slurl 
  1748.     // is specified. More work on the settings system is needed to 
  1749.     // achieve this. For now...
  1750.     // *NOTE:Mani The command line parser parses tokens and is 
  1751.     // setup to bail after parsing the '--url' option or the 
  1752.     // first option specified without a '--option' flag (or
  1753.     // any other option that uses the 'last_option' setting - 
  1754.     // see LLControlGroupCLP::configure())
  1755.     // What can happen is that someone can use IE (or potentially 
  1756.     // other browsers) and do the rough equivalent of command 
  1757.     // injection and steal passwords. Phoenix. SL-55321
  1758.     if(clp.hasOption("url"))
  1759.     {
  1760.         std::string slurl = clp.getOption("url")[0];
  1761.         if (LLSLURL::isSLURLCommand(slurl))
  1762.         {
  1763.         LLStartUp::sSLURLCommand = slurl;
  1764.         }
  1765.         else
  1766.         {
  1767.         LLURLSimString::setString(slurl);
  1768.         }
  1769.     }
  1770.     else if(clp.hasOption("slurl"))
  1771.     {
  1772.         std::string slurl = clp.getOption("slurl")[0];
  1773.         if(LLSLURL::isSLURL(slurl))
  1774.         {
  1775.             if (LLSLURL::isSLURLCommand(slurl))
  1776.             {
  1777.             LLStartUp::sSLURLCommand = slurl;
  1778.             }
  1779.             else
  1780.             {
  1781.             LLURLSimString::setString(slurl);
  1782.             }
  1783.         }
  1784.     }
  1785.     const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent");
  1786.     if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString())
  1787.     {   
  1788. // hack to force the skin to default.
  1789.         //gDirUtilp->setSkinFolder(skinfolder->getValue().asString());
  1790. gDirUtilp->setSkinFolder("default");
  1791.     }
  1792.     mYieldTime = gSavedSettings.getS32("YieldTime");
  1793. // Read skin/branding settings if specified.
  1794. //if (! gDirUtilp->getSkinDir().empty() )
  1795. //{
  1796. // std::string skin_def_file = gDirUtilp->findSkinnedFilename("skin.xml");
  1797. // LLXmlTree skin_def_tree;
  1798. // if (!skin_def_tree.parseFile(skin_def_file))
  1799. // {
  1800. // llerrs << "Failed to parse skin definition." << llendl;
  1801. // }
  1802. //}
  1803. #if LL_DARWIN
  1804. // Initialize apple menubar and various callbacks
  1805. init_apple_menu(LLTrans::getString("APP_NAME").c_str());
  1806. #if __ppc__
  1807. // If the CPU doesn't have Altivec (i.e. it's not at least a G4), don't go any further.
  1808. // Only test PowerPC - all Intel Macs have SSE.
  1809. if(!gSysCPU.hasAltivec())
  1810. {
  1811. std::ostringstream msg;
  1812. msg << LLTrans::getString("MBRequiresAltiVec");
  1813. OSMessageBox(
  1814. msg.str(),
  1815. LLStringUtil::null,
  1816. OSMB_OK);
  1817. removeMarkerFile();
  1818. return false;
  1819. }
  1820. #endif
  1821. #endif // LL_DARWIN
  1822. // Display splash screen.  Must be after above check for previous
  1823. // crash as this dialog is always frontmost.
  1824. std::ostringstream splash_msg;
  1825. splash_msg << "Loading " << LLTrans::getString("SECOND_LIFE") << "...";
  1826. LLSplashScreen::show();
  1827. LLSplashScreen::update(splash_msg.str());
  1828. //LLVolumeMgr::initClass();
  1829. LLVolumeMgr* volume_manager = new LLVolumeMgr();
  1830. volume_manager->useMutex(); // LLApp and LLMutex magic must be manually enabled
  1831. LLPrimitive::setVolumeManager(volume_manager);
  1832. // Note: this is where we used to initialize gFeatureManagerp.
  1833. gStartTime = totalTime();
  1834. //
  1835. // Set the name of the window
  1836. //
  1837. gWindowTitle = LLTrans::getString("APP_NAME");
  1838. #if LL_DEBUG
  1839. gWindowTitle += std::string(" [DEBUG] ") + gArgs;
  1840. #else
  1841. gWindowTitle += std::string(" ") + gArgs;
  1842. #endif
  1843. LLStringUtil::truncate(gWindowTitle, 255);
  1844. //RN: if we received a URL, hand it off to the existing instance.
  1845. // don't call anotherInstanceRunning() when doing URL handoff, as
  1846. // it relies on checking a marker file which will not work when running
  1847. // out of different directories
  1848. std::string slurl;
  1849. if (!LLStartUp::sSLURLCommand.empty())
  1850. {
  1851. slurl = LLStartUp::sSLURLCommand;
  1852. }
  1853. else if (LLURLSimString::parse())
  1854. {
  1855. slurl = LLURLSimString::getURL();
  1856. }
  1857. if (!slurl.empty())
  1858. {
  1859. if (sendURLToOtherInstance(slurl))
  1860. {
  1861. // successfully handed off URL to existing instance, exit
  1862. return false;
  1863. }
  1864. }
  1865. if (!gSavedSettings.getBOOL("AllowMultipleViewers"))
  1866. {
  1867.     //
  1868.     // Check for another instance of the app running
  1869.     //
  1870. mSecondInstance = anotherInstanceRunning();
  1871. if (mSecondInstance)
  1872. {
  1873. std::ostringstream msg;
  1874. msg << LLTrans::getString("MBAlreadyRunning");
  1875. OSMessageBox(
  1876. msg.str(),
  1877. LLStringUtil::null,
  1878. OSMB_OK);
  1879. return false;
  1880. }
  1881. initMarkerFile();
  1882.         
  1883.         checkForCrash();
  1884.     }
  1885. else
  1886. {
  1887. mSecondInstance = anotherInstanceRunning();
  1888. if (mSecondInstance)
  1889. {
  1890. // This is the second instance of SL. Turn off voice support,
  1891. // but make sure the setting is *not* persisted.
  1892. LLControlVariable* disable_voice = gSavedSettings.getControl("CmdLineDisableVoice");
  1893. if(disable_voice)
  1894. {
  1895. const BOOL DO_NOT_PERSIST = FALSE;
  1896. disable_voice->setValue(LLSD(TRUE), DO_NOT_PERSIST);
  1897. }
  1898. }
  1899. initMarkerFile();
  1900.         
  1901.         if(!mSecondInstance)
  1902.         {
  1903.             checkForCrash();
  1904.         }
  1905. }
  1906.     // need to do this here - need to have initialized global settings first
  1907. std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" );
  1908. if ( nextLoginLocation.length() )
  1909. {
  1910. LLURLSimString::setString( nextLoginLocation );
  1911. };
  1912. gLastRunVersion = gSavedSettings.getString("LastRunVersion");
  1913. loadColorSettings();
  1914. return true; // Config was successful.
  1915. }
  1916. void LLAppViewer::checkForCrash(void)
  1917. {
  1918.     
  1919. #if LL_SEND_CRASH_REPORTS
  1920. //*NOTE:Mani The current state of the crash handler has the MacOSX
  1921. // sending all crash reports as freezes, in order to let 
  1922. // the MacOSX CrashRepoter generate stacks before spawning the 
  1923. // SL crash logger.
  1924. // The Linux and Windows clients generate their own stacks and
  1925. // spawn the SL crash logger immediately. This may change in the future. 
  1926. #if LL_DARWIN
  1927. if(gLastExecEvent != LAST_EXEC_NORMAL)
  1928. #else
  1929. if (gLastExecEvent == LAST_EXEC_FROZE)
  1930. #endif
  1931.     {
  1932.         llinfos << "Last execution froze, requesting to send crash report." << llendl;
  1933.         //
  1934.         // Pop up a freeze or crash warning dialog
  1935.         //
  1936.         S32 choice;
  1937.         if(gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING) == CRASH_BEHAVIOR_ASK)
  1938.         {
  1939.             std::ostringstream msg;
  1940. msg << LLTrans::getString("MBFrozenCrashed");
  1941. std::string alert = LLTrans::getString("APP_NAME") + " " + LLTrans::getString("MBAlert");
  1942.             choice = OSMessageBox(msg.str(),
  1943.                                   alert,
  1944.                                   OSMB_YESNO);
  1945.         } 
  1946.         else if(gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING) == CRASH_BEHAVIOR_NEVER_SEND)
  1947.         {
  1948.             choice = OSBTN_NO;
  1949.         }
  1950.         else
  1951.         {
  1952.             choice = OSBTN_YES;
  1953.         }
  1954.         if (OSBTN_YES == choice)
  1955.         {
  1956.             llinfos << "Sending crash report." << llendl;
  1957.             
  1958.             bool report_freeze = true;
  1959.             handleCrashReporting(report_freeze);
  1960.         }
  1961.         else
  1962.         {
  1963.             llinfos << "Not sending crash report." << llendl;
  1964.         }
  1965.     }
  1966. #endif // LL_SEND_CRASH_REPORTS    
  1967.     
  1968. }
  1969. bool LLAppViewer::initWindow()
  1970. {
  1971. LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL;
  1972. // store setting in a global for easy access and modification
  1973. gNoRender = gSavedSettings.getBOOL("DisableRendering");
  1974. // always start windowed
  1975. BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth");
  1976. gViewerWindow = new LLViewerWindow(gWindowTitle, 
  1977. VIEWER_WINDOW_CLASSNAME,
  1978. gSavedSettings.getS32("WindowX"), gSavedSettings.getS32("WindowY"),
  1979. gSavedSettings.getS32("WindowWidth"), gSavedSettings.getS32("WindowHeight"),
  1980. FALSE, ignorePixelDepth);
  1981. LLNotificationsUI::LLNotificationManager::getInstance();
  1982. if (gSavedSettings.getBOOL("WindowFullScreen"))
  1983. {
  1984. // request to go full screen... which will be delayed until login
  1985. gViewerWindow->toggleFullscreen(FALSE);
  1986. }
  1987. if (gSavedSettings.getBOOL("WindowMaximized"))
  1988. {
  1989. gViewerWindow->mWindow->maximize();
  1990. gViewerWindow->getWindow()->setNativeAspectRatio(gSavedSettings.getF32("FullScreenAspectRatio"));
  1991. }
  1992. if (!gNoRender)
  1993. {
  1994. //
  1995. // Initialize GL stuff
  1996. //
  1997. if (mForceGraphicsDetail)
  1998. {
  1999. LLFeatureManager::getInstance()->setGraphicsLevel(gSavedSettings.getU32("RenderQualityPerformance"), false);
  2000. }
  2001. // Set this flag in case we crash while initializing GL
  2002. gSavedSettings.setBOOL("RenderInitError", TRUE);
  2003. gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
  2004. gPipeline.init();
  2005. stop_glerror();
  2006. gViewerWindow->initGLDefaults();
  2007. gSavedSettings.setBOOL("RenderInitError", FALSE);
  2008. gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
  2009. }
  2010. //If we have a startup crash, it's usually near GL initialization, so simulate that.
  2011. if(gCrashOnStartup)
  2012. {
  2013. LLAppViewer::instance()->forceErrorLLError();
  2014. }
  2015. LLUI::sWindow = gViewerWindow->getWindow();
  2016. // Show watch cursor
  2017. gViewerWindow->setCursor(UI_CURSOR_WAIT);
  2018. // Finish view initialization
  2019. gViewerWindow->initBase();
  2020. // show viewer window
  2021. //gViewerWindow->mWindow->show();
  2022. return true;
  2023. }
  2024. void LLAppViewer::writeDebugInfo()
  2025. {
  2026. std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log");
  2027. llinfos << "Opening debug file " << debug_filename << llendl;
  2028. llofstream out_file(debug_filename);
  2029. LLSDSerialize::toPrettyXML(gDebugInfo, out_file);
  2030. out_file.close();
  2031. }
  2032. void LLAppViewer::cleanupSavedSettings()
  2033. {
  2034. gSavedSettings.setBOOL("MouseSun", FALSE);
  2035. gSavedSettings.setBOOL("UseEnergy", TRUE); // force toggle to turn off, since sends message to simulator
  2036. gSavedSettings.setBOOL("DebugWindowProc", gDebugWindowProc);
  2037. gSavedSettings.setBOOL("ShowObjectUpdates", gShowObjectUpdates);
  2038. if (!gNoRender)
  2039. {
  2040. if (gDebugView)
  2041. {
  2042. gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible());
  2043. }
  2044. }
  2045. // save window position if not fullscreen
  2046. // as we don't track it in callbacks
  2047. BOOL fullscreen = gViewerWindow->mWindow->getFullscreen();
  2048. BOOL maximized = gViewerWindow->mWindow->getMaximized();
  2049. if (!fullscreen && !maximized)
  2050. {
  2051. LLCoordScreen window_pos;
  2052. if (gViewerWindow->mWindow->getPosition(&window_pos))
  2053. {
  2054. gSavedSettings.setS32("WindowX", window_pos.mX);
  2055. gSavedSettings.setS32("WindowY", window_pos.mY);
  2056. }
  2057. }
  2058. gSavedSettings.setF32("MapScale", LLWorldMapView::sMapScale );
  2059. // Some things are cached in LLAgent.
  2060. if (gAgent.mInitialized)
  2061. {
  2062. gSavedSettings.setF32("RenderFarClip", gAgent.mDrawDistance);
  2063. }
  2064. }
  2065. void LLAppViewer::removeCacheFiles(const std::string& file_mask)
  2066. {
  2067. std::string mask = gDirUtilp->getDirDelimiter() + file_mask;
  2068. gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), mask);
  2069. }
  2070. void LLAppViewer::writeSystemInfo()
  2071. {
  2072. gDebugInfo["SLLog"] = LLError::logFileName();
  2073. gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName");
  2074. gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
  2075. gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
  2076. gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch();
  2077. gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild();
  2078. gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
  2079. gDebugInfo["CPUInfo"]["CPUString"] = gSysCPU.getCPUString();
  2080. gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily();
  2081. gDebugInfo["CPUInfo"]["CPUMhz"] = gSysCPU.getMhz();
  2082. gDebugInfo["CPUInfo"]["CPUAltivec"] = gSysCPU.hasAltivec();
  2083. gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE();
  2084. gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2();
  2085. gDebugInfo["RAMInfo"]["Physical"] = (LLSD::Integer)(gSysMemory.getPhysicalMemoryKB());
  2086. gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer)(gMemoryAllocated>>10); // MB -> KB
  2087. gDebugInfo["OSInfo"] = getOSInfo().getOSStringSimple();
  2088. // The user is not logged on yet, but record the current grid choice login url
  2089. // which may have been the intended grid. This can b
  2090. gDebugInfo["GridName"] = LLViewerLogin::getInstance()->getGridLabel();
  2091. // *FIX:Mani - move this ddown in llappviewerwin32
  2092. #ifdef LL_WINDOWS
  2093. DWORD thread_id = GetCurrentThreadId();
  2094. gDebugInfo["MainloopThreadID"] = (S32)thread_id;
  2095. #endif
  2096. // "CrashNotHandled" is set here, while things are running well,
  2097. // in case of a freeze. If there is a freeze, the crash logger will be launched
  2098. // and can read this value from the debug_info.log.
  2099. // If the crash is handled by LLAppViewer::handleViewerCrash, ie not a freeze,
  2100. // then the value of "CrashNotHandled" will be set to true.
  2101. gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)true;
  2102. // Dump some debugging info
  2103. LL_INFOS("SystemInfo") << LLTrans::getString("APP_NAME")
  2104. << " version " << LLVersionInfo::getShortVersion() << LL_ENDL;
  2105. // Dump the local time and time zone
  2106. time_t now;
  2107. time(&now);
  2108. char tbuffer[256]; /* Flawfinder: ignore */
  2109. strftime(tbuffer, 256, "%Y-%m-%dT%H:%M:%S %Z", localtime(&now));
  2110. LL_INFOS("SystemInfo") << "Local time: " << tbuffer << LL_ENDL;
  2111. // query some system information
  2112. LL_INFOS("SystemInfo") << "CPU info:n" << gSysCPU << LL_ENDL;
  2113. LL_INFOS("SystemInfo") << "Memory info:n" << gSysMemory << LL_ENDL;
  2114. LL_INFOS("SystemInfo") << "OS: " << getOSInfo().getOSStringSimple() << LL_ENDL;
  2115. LL_INFOS("SystemInfo") << "OS info: " << getOSInfo() << LL_ENDL;
  2116. writeDebugInfo(); // Save out debug_info.log early, in case of crash.
  2117. }
  2118. void LLAppViewer::handleSyncViewerCrash()
  2119. {
  2120. LLAppViewer* pApp = LLAppViewer::instance();
  2121. // Call to pure virtual, handled by platform specific llappviewer instance.
  2122. pApp->handleSyncCrashTrace(); 
  2123. }
  2124. void LLAppViewer::handleViewerCrash()
  2125. {
  2126. llinfos << "Handle viewer crash entry." << llendl;
  2127. //print out recorded call stacks if there are any.
  2128. LLError::LLCallStacks::print();
  2129. LLAppViewer* pApp = LLAppViewer::instance();
  2130. if (pApp->beingDebugged())
  2131. {
  2132. // This will drop us into the debugger.
  2133. abort();
  2134. }
  2135. // Returns whether a dialog was shown.
  2136. // Only do the logic in here once
  2137. if (pApp->mReportedCrash)
  2138. {
  2139. return;
  2140. }
  2141. pApp->mReportedCrash = TRUE;
  2142. // Make sure the watchdog gets turned off...
  2143. //  pApp->destroyMainloopTimeout(); // SJB: Bah. This causes the crash handler to hang, not sure why.
  2144. //We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version
  2145. //to check against no matter what
  2146. gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName");
  2147. gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
  2148. gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
  2149. gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch();
  2150. gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild();
  2151. LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
  2152. if ( parcel && parcel->getMusicURL()[0])
  2153. {
  2154. gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL();
  2155. }
  2156. if ( parcel && parcel->getMediaURL()[0])
  2157. {
  2158. gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL();
  2159. }
  2160. gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile");
  2161. gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
  2162. gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName();
  2163. gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath();
  2164. gDebugInfo["SessionLength"] = F32(LLFrameTimer::getElapsedSeconds());
  2165. gDebugInfo["StartupState"] = LLStartUp::getStartupStateString();
  2166. gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer) LLMemory::getCurrentRSS() >> 10;
  2167. gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin();
  2168. gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall");
  2169. if(gLogoutInProgress)
  2170. {
  2171. gDebugInfo["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH;
  2172. }
  2173. else
  2174. {
  2175. gDebugInfo["LastExecEvent"] = gLLErrorActivated ? LAST_EXEC_LLERROR_CRASH : LAST_EXEC_OTHER_CRASH;
  2176. }
  2177. if(gAgent.getRegion())
  2178. {
  2179. gDebugInfo["CurrentSimHost"] = gAgent.getRegionHost().getHostName();
  2180. gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName();
  2181. const LLVector3& loc = gAgent.getPositionAgent();
  2182. gDebugInfo["CurrentLocationX"] = loc.mV[0];
  2183. gDebugInfo["CurrentLocationY"] = loc.mV[1];
  2184. gDebugInfo["CurrentLocationZ"] = loc.mV[2];
  2185. }
  2186. if(LLAppViewer::instance()->mMainloopTimeout)
  2187. {
  2188. gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState();
  2189. }
  2190. // The crash is being handled here so set this value to false.
  2191. // Otherwise the crash logger will think this crash was a freeze.
  2192. gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)false;
  2193.     
  2194. //Write out the crash status file
  2195. //Use marker file style setup, as that's the simplest, especially since
  2196. //we're already in a crash situation
  2197. if (gDirUtilp)
  2198. {
  2199. std::string crash_file_name;
  2200. if(gLLErrorActivated) crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LLERROR_MARKER_FILE_NAME);
  2201. else crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,ERROR_MARKER_FILE_NAME);
  2202. llinfos << "Creating crash marker file " << crash_file_name << llendl;
  2203. LLAPRFile crash_file ;
  2204. crash_file.open(crash_file_name, LL_APR_W);
  2205. if (crash_file.getFileHandle())
  2206. {
  2207. LL_INFOS("MarkerFile") << "Created crash marker file " << crash_file_name << LL_ENDL;
  2208. }
  2209. else
  2210. {
  2211. LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_file_name << LL_ENDL;
  2212. }
  2213. }
  2214. if (gMessageSystem && gDirUtilp)
  2215. {
  2216. std::string filename;
  2217. filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "stats.log");
  2218. llofstream file(filename, llofstream::binary);
  2219. if(file.good())
  2220. {
  2221. llinfos << "Handle viewer crash generating stats log." << llendl;
  2222. gMessageSystem->summarizeLogs(file);
  2223. file.close();
  2224. }
  2225. }
  2226. if (gMessageSystem)
  2227. {
  2228. gMessageSystem->getCircuitInfo(gDebugInfo["CircuitInfo"]);
  2229. gMessageSystem->stopLogging();
  2230. }
  2231. if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo);
  2232. // Close the debug file
  2233. pApp->writeDebugInfo();
  2234. LLError::logToFile("");
  2235. // On Mac, we send the report on the next run, since we need macs crash report
  2236. // for a stack trace, so we have to let it the app fail.
  2237. #if !LL_DARWIN
  2238. // Remove the marker file, since otherwise we'll spawn a process that'll keep it locked
  2239. if(gDebugInfo["LastExecEvent"].asInteger() == LAST_EXEC_LOGOUT_CRASH)
  2240. {
  2241. pApp->removeMarkerFile(true);
  2242. }
  2243. else
  2244. {
  2245. pApp->removeMarkerFile(false);
  2246. }
  2247. // Call to pure virtual, handled by platform specific llappviewer instance.
  2248. pApp->handleCrashReporting(); 
  2249. #endif //!LL_DARWIN
  2250.     
  2251. return;
  2252. }
  2253. bool LLAppViewer::anotherInstanceRunning()
  2254. {
  2255. // We create a marker file when the program starts and remove the file when it finishes.
  2256. // If the file is currently locked, that means another process is already running.
  2257. std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, MARKER_FILE_NAME);
  2258. LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;
  2259. //Freeze case checks
  2260. if (LLAPRFile::isExist(marker_file, NULL, LL_APR_RB))
  2261. {
  2262. // File exists, try opening with write permissions
  2263. LLAPRFile outfile ;
  2264. outfile.open(marker_file, LL_APR_WB);
  2265. apr_file_t* fMarker = outfile.getFileHandle() ; 
  2266. if (!fMarker)
  2267. {
  2268. // Another instance is running. Skip the rest of these operations.
  2269. LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
  2270. return true;
  2271. }
  2272. if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) //flock(fileno(fMarker), LOCK_EX | LOCK_NB) == -1)
  2273. {
  2274. LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
  2275. return true;
  2276. }
  2277. // No other instances; we'll lock this file now & delete on quit.
  2278. }
  2279. LL_DEBUGS("MarkerFile") << "Marker file isn't locked." << LL_ENDL;
  2280. return false;
  2281. }
  2282. void LLAppViewer::initMarkerFile()
  2283. {
  2284. //First, check for the existence of other files.
  2285. //There are marker files for two different types of crashes
  2286. mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME);
  2287. LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;
  2288. //We've got 4 things to test for here
  2289. // - Other Process Running (SecondLife.exec_marker present, locked)
  2290. // - Freeze (SecondLife.exec_marker present, not locked)
  2291. // - LLError Crash (SecondLife.llerror_marker present)
  2292. // - Other Crash (SecondLife.error_marker present)
  2293. // These checks should also remove these files for the last 2 cases if they currently exist
  2294. //LLError/Error checks. Only one of these should ever happen at a time.
  2295. std::string logout_marker_file =  gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME);
  2296. std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);
  2297. std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
  2298. if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB) && !anotherInstanceRunning())
  2299. {
  2300. gLastExecEvent = LAST_EXEC_FROZE;
  2301. LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL;
  2302. }    
  2303.     
  2304. if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB))
  2305. {
  2306. LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << LL_ENDL;
  2307. gLastExecEvent = LAST_EXEC_LOGOUT_FROZE;
  2308. }
  2309. if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB))
  2310. {
  2311. llinfos << "Last exec LLError crashed, setting LastExecEvent to " << LAST_EXEC_LLERROR_CRASH << llendl;
  2312. if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
  2313. else gLastExecEvent = LAST_EXEC_LLERROR_CRASH;
  2314. }
  2315. if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB))
  2316. {
  2317. LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << LAST_EXEC_OTHER_CRASH << LL_ENDL;
  2318. if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
  2319. else gLastExecEvent = LAST_EXEC_OTHER_CRASH;
  2320. }
  2321. LLAPRFile::remove(logout_marker_file);
  2322. LLAPRFile::remove(llerror_marker_file);
  2323. LLAPRFile::remove(error_marker_file);
  2324. // No new markers if another instance is running.
  2325. if(anotherInstanceRunning()) 
  2326. {
  2327. return;
  2328. }
  2329. // Create the marker file for this execution & lock it
  2330. apr_status_t s;
  2331. s = mMarkerFile.open(mMarkerFileName, LL_APR_W, TRUE);
  2332. if (s == APR_SUCCESS && mMarkerFile.getFileHandle())
  2333. {
  2334. LL_DEBUGS("MarkerFile") << "Marker file created." << LL_ENDL;
  2335. }
  2336. else
  2337. {
  2338. LL_INFOS("MarkerFile") << "Failed to create marker file." << LL_ENDL;
  2339. return;
  2340. }
  2341. if (apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) 
  2342. {
  2343. mMarkerFile.close() ;
  2344. LL_INFOS("MarkerFile") << "Marker file cannot be locked." << LL_ENDL;
  2345. return;
  2346. }
  2347. LL_DEBUGS("MarkerFile") << "Marker file locked." << LL_ENDL;
  2348. }
  2349. void LLAppViewer::removeMarkerFile(bool leave_logout_marker)
  2350. {
  2351. LL_DEBUGS("MarkerFile") << "removeMarkerFile()" << LL_ENDL;
  2352. if (mMarkerFile.getFileHandle())
  2353. {
  2354. mMarkerFile.close() ;
  2355. LLAPRFile::remove( mMarkerFileName );
  2356. }
  2357. if (mLogoutMarkerFile != NULL && !leave_logout_marker)
  2358. {
  2359. LLAPRFile::remove( mLogoutMarkerFileName );
  2360. mLogoutMarkerFile = NULL;
  2361. }
  2362. }
  2363. void LLAppViewer::forceQuit()
  2364. LLApp::setQuitting(); 
  2365. }
  2366. void LLAppViewer::requestQuit()
  2367. {
  2368. llinfos << "requestQuit" << llendl;
  2369. LLViewerRegion* region = gAgent.getRegion();
  2370. if( (LLStartUp::getStartupState() < STATE_STARTED) || !region )
  2371. {
  2372. // Quit immediately
  2373. forceQuit();
  2374. return;
  2375. }
  2376. LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
  2377. effectp->setPositionGlobal(gAgent.getPositionGlobal());
  2378. effectp->setColor(LLColor4U(gAgent.getEffectColor()));
  2379. LLHUDManager::getInstance()->sendEffects();
  2380. effectp->markDead() ;//remove it.
  2381. // Attempt to close all floaters that might be
  2382. // editing things.
  2383. if (gFloaterView)
  2384. {
  2385. // application is quitting
  2386. gFloaterView->closeAllChildren(true);
  2387. }
  2388. LLSideTray::getInstance()->notifyChildren(LLSD().with("request","quit"));
  2389. send_stats();
  2390. gLogoutTimer.reset();
  2391. mQuitRequested = true;
  2392. }
  2393. static bool finish_quit(const LLSD& notification, const LLSD& response)
  2394. {
  2395. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  2396. if (option == 0)
  2397. {
  2398. LLAppViewer::instance()->requestQuit();
  2399. }
  2400. return false;
  2401. }
  2402. static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_quit);
  2403. void LLAppViewer::userQuit()
  2404. {
  2405. if (gDisconnected)
  2406. {
  2407. requestQuit();
  2408. }
  2409. else
  2410. {
  2411. LLNotificationsUtil::add("ConfirmQuit");
  2412. }
  2413. }
  2414. static bool finish_early_exit(const LLSD& notification, const LLSD& response)
  2415. {
  2416. LLAppViewer::instance()->forceQuit();
  2417. return false;
  2418. }
  2419. void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions)
  2420. {
  2421.     llwarns << "app_early_exit: " << name << llendl;
  2422. gDoDisconnect = TRUE;
  2423. LLNotificationsUtil::add(name, substitutions, LLSD(), finish_early_exit);
  2424. }
  2425. void LLAppViewer::forceExit(S32 arg)
  2426. {
  2427.     removeMarkerFile();
  2428.     
  2429.     // *FIX:Mani - This kind of exit hardly seems appropriate.
  2430.     exit(arg);
  2431. }
  2432. void LLAppViewer::abortQuit()
  2433. {
  2434.     llinfos << "abortQuit()" << llendl;
  2435. mQuitRequested = false;
  2436. }
  2437. void LLAppViewer::migrateCacheDirectory()
  2438. {
  2439. #if LL_WINDOWS || LL_DARWIN
  2440. // NOTE: (Nyx) as of 1.21, cache for mac is moving to /library/caches/SecondLife from
  2441. // /library/application support/SecondLife/cache This should clear/delete the old dir.
  2442. // As of 1.23 the Windows cache moved from
  2443. //   C:Documents and SettingsJamesApplication SupportSecondLifecache
  2444. // to
  2445. //   C:Documents and SettingsJamesLocal SettingsApplication SupportSecondLife
  2446. //
  2447. // The Windows Vista equivalent is from
  2448. //   C:UsersJamesAppDataRoamingSecondLifecache
  2449. // to
  2450. //   C:UsersJamesAppDataLocalSecondLife
  2451. //
  2452. // Note the absence of cache on the second path.  James.
  2453. // Only do this once per fresh install of this version.
  2454. if (gSavedSettings.getBOOL("MigrateCacheDirectory"))
  2455. {
  2456. gSavedSettings.setBOOL("MigrateCacheDirectory", FALSE);
  2457. std::string delimiter = gDirUtilp->getDirDelimiter();
  2458. std::string old_cache_dir = gDirUtilp->getOSUserAppDir() + delimiter + "cache";
  2459. std::string new_cache_dir = gDirUtilp->getCacheDir(true);
  2460. if (gDirUtilp->fileExists(old_cache_dir))
  2461. {
  2462. llinfos << "Migrating cache from " << old_cache_dir << " to " << new_cache_dir << llendl;
  2463. // Migrate inventory cache to avoid pain to inventory database after mass update
  2464. S32 file_count = 0;
  2465. std::string file_name;
  2466. std::string mask = delimiter + "*.*";
  2467. while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name, false))
  2468. {
  2469. if (file_name == "." || file_name == "..") continue;
  2470. std::string source_path = old_cache_dir + delimiter + file_name;
  2471. std::string dest_path = new_cache_dir + delimiter + file_name;
  2472. if (!LLFile::rename(source_path, dest_path))
  2473. {
  2474. file_count++;
  2475. }
  2476. }
  2477. llinfos << "Moved " << file_count << " files" << llendl;
  2478. // Nuke the old cache
  2479. gDirUtilp->setCacheDir(old_cache_dir);
  2480. purgeCache();
  2481. gDirUtilp->setCacheDir(new_cache_dir);
  2482. #if LL_DARWIN
  2483. // Clean up Mac files not deleted by removing *.*
  2484. std::string ds_store = old_cache_dir + "/.DS_Store";
  2485. if (gDirUtilp->fileExists(ds_store))
  2486. {
  2487. LLFile::remove(ds_store);
  2488. }
  2489. #endif
  2490. if (LLFile::rmdir(old_cache_dir) != 0)
  2491. {
  2492. llwarns << "could not delete old cache directory " << old_cache_dir << llendl;
  2493. }
  2494. }
  2495. }
  2496. #endif // LL_WINDOWS || LL_DARWIN
  2497. }
  2498. bool LLAppViewer::initCache()
  2499. {
  2500. mPurgeCache = false;
  2501. // Purge cache if user requested it
  2502. if (gSavedSettings.getBOOL("PurgeCacheOnStartup") ||
  2503. gSavedSettings.getBOOL("PurgeCacheOnNextStartup"))
  2504. {
  2505. gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false);
  2506. mPurgeCache = true;
  2507. }
  2508. // Purge cache if it belongs to an old version
  2509. else
  2510. {
  2511. static const S32 cache_version = 6;
  2512. if (gSavedSettings.getS32("LocalCacheVersion") != cache_version)
  2513. {
  2514. mPurgeCache = true;
  2515. gSavedSettings.setS32("LocalCacheVersion", cache_version);
  2516. }
  2517. }
  2518. // We have moved the location of the cache directory over time.
  2519. migrateCacheDirectory();
  2520. // Setup and verify the cache location
  2521. std::string cache_location = gSavedSettings.getString("CacheLocation");
  2522. std::string new_cache_location = gSavedSettings.getString("NewCacheLocation");
  2523. if (new_cache_location != cache_location)
  2524. {
  2525. gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"));
  2526. purgeCache(); // purge old cache
  2527. gSavedSettings.setString("CacheLocation", new_cache_location);
  2528. gSavedSettings.setString("CacheLocationTopFolder", gDirUtilp->getBaseFileName(new_cache_location));
  2529. }
  2530. if (!gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")))
  2531. {
  2532. LL_WARNS("AppCache") << "Unable to set cache location" << LL_ENDL;
  2533. gSavedSettings.setString("CacheLocation", "");
  2534. gSavedSettings.setString("CacheLocationTopFolder", "");
  2535. }
  2536. if (mPurgeCache)
  2537. {
  2538. LLSplashScreen::update("Clearing cache...");
  2539. purgeCache();
  2540. }
  2541. LLSplashScreen::update("Initializing Texture Cache...");
  2542. // Init the texture cache
  2543. // Allocate 80% of the cache size for textures
  2544. BOOL read_only = mSecondInstance ? TRUE : FALSE;
  2545. const S32 MB = 1024*1024;
  2546. S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB;
  2547. const S64 MAX_CACHE_SIZE = 1024*MB;
  2548. cache_size = llmin(cache_size, MAX_CACHE_SIZE);
  2549. S64 texture_cache_size = ((cache_size * 8)/10);
  2550. S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, read_only);
  2551. texture_cache_size -= extra;
  2552. LLSplashScreen::update("Initializing VFS...");
  2553. // Init the VFS
  2554. S64 vfs_size = cache_size - texture_cache_size;
  2555. const S64 MAX_VFS_SIZE = 1024 * MB; // 1 GB
  2556. vfs_size = llmin(vfs_size, MAX_VFS_SIZE);
  2557. vfs_size = (vfs_size / MB) * MB; // make sure it is MB aligned
  2558. U32 vfs_size_u32 = (U32)vfs_size;
  2559. U32 old_vfs_size = gSavedSettings.getU32("VFSOldSize") * MB;
  2560. bool resize_vfs = (vfs_size_u32 != old_vfs_size);
  2561. if (resize_vfs)
  2562. {
  2563. gSavedSettings.setU32("VFSOldSize", vfs_size_u32/MB);
  2564. }
  2565. LL_INFOS("AppCache") << "VFS CACHE SIZE: " << vfs_size/(1024*1024) << " MB" << LL_ENDL;
  2566. // This has to happen BEFORE starting the vfs
  2567. //time_t ltime;
  2568. srand(time(NULL)); // Flawfinder: ignore
  2569. U32 old_salt = gSavedSettings.getU32("VFSSalt");
  2570. U32 new_salt;
  2571. std::string old_vfs_data_file;
  2572. std::string old_vfs_index_file;
  2573. std::string new_vfs_data_file;
  2574. std::string new_vfs_index_file;
  2575. std::string static_vfs_index_file;
  2576. std::string static_vfs_data_file;
  2577. if (gSavedSettings.getBOOL("AllowMultipleViewers"))
  2578. {
  2579. // don't mess with renaming the VFS in this case
  2580. new_salt = old_salt;
  2581. }
  2582. else
  2583. {
  2584. do
  2585. {
  2586. new_salt = rand();
  2587. } while( new_salt == old_salt );
  2588. }
  2589. old_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE) + llformat("%u",old_salt);
  2590. // make sure this file exists
  2591. llstat s;
  2592. S32 stat_result = LLFile::stat(old_vfs_data_file, &s);
  2593. if (stat_result)
  2594. {
  2595. // doesn't exist, look for a data file
  2596. std::string mask;
  2597. mask = gDirUtilp->getDirDelimiter();
  2598. mask += VFS_DATA_FILE_BASE;
  2599. mask += "*";
  2600. std::string dir;
  2601. dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");
  2602. std::string found_file;
  2603. if (gDirUtilp->getNextFileInDir(dir, mask, found_file, false))
  2604. {
  2605. old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file;
  2606. S32 start_pos = found_file.find_last_of('.');
  2607. if (start_pos > 0)
  2608. {
  2609. sscanf(found_file.substr(start_pos+1).c_str(), "%d", &old_salt);
  2610. }
  2611. LL_DEBUGS("AppCache") << "Default vfs data file not present, found: " << old_vfs_data_file << " Old salt: " << old_salt << llendl;
  2612. }
  2613. }
  2614. old_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_INDEX_FILE_BASE) + llformat("%u",old_salt);
  2615. stat_result = LLFile::stat(old_vfs_index_file, &s);
  2616. if (stat_result)
  2617. {
  2618. // We've got a bad/missing index file, nukem!
  2619. LL_WARNS("AppCache") << "Bad or missing vfx index file " << old_vfs_index_file << LL_ENDL;
  2620. LL_WARNS("AppCache") << "Removing old vfs data file " << old_vfs_data_file << LL_ENDL;
  2621. LLFile::remove(old_vfs_data_file);
  2622. LLFile::remove(old_vfs_index_file);
  2623. // Just in case, nuke any other old cache files in the directory.
  2624. std::string dir;
  2625. dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");
  2626. std::string mask;
  2627. mask = gDirUtilp->getDirDelimiter();
  2628. mask += VFS_DATA_FILE_BASE;
  2629. mask += "*";
  2630. gDirUtilp->deleteFilesInDir(dir, mask);
  2631. mask = gDirUtilp->getDirDelimiter();
  2632. mask += VFS_INDEX_FILE_BASE;
  2633. mask += "*";
  2634. gDirUtilp->deleteFilesInDir(dir, mask);
  2635. }
  2636. new_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE) + llformat("%u",new_salt);
  2637. new_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_INDEX_FILE_BASE) + llformat("%u",new_salt);
  2638. static_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_data.db2");
  2639. static_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_index.db2");
  2640. if (resize_vfs)
  2641. {
  2642. LL_DEBUGS("AppCache") << "Removing old vfs and re-sizing" << LL_ENDL;
  2643. LLFile::remove(old_vfs_data_file);
  2644. LLFile::remove(old_vfs_index_file);
  2645. }
  2646. else if (old_salt != new_salt)
  2647. {
  2648. // move the vfs files to a new name before opening
  2649. LL_DEBUGS("AppCache") << "Renaming " << old_vfs_data_file << " to " << new_vfs_data_file << LL_ENDL;
  2650. LL_DEBUGS("AppCache") << "Renaming " << old_vfs_index_file << " to " << new_vfs_index_file << LL_ENDL;
  2651. LLFile::rename(old_vfs_data_file, new_vfs_data_file);
  2652. LLFile::rename(old_vfs_index_file, new_vfs_index_file);
  2653. }
  2654. // Startup the VFS...
  2655. gSavedSettings.setU32("VFSSalt", new_salt);
  2656. // Don't remove VFS after viewer crashes.  If user has corrupt data, they can reinstall. JC
  2657. gVFS = LLVFS::createLLVFS(new_vfs_index_file, new_vfs_data_file, false, vfs_size_u32, false);
  2658. if( !gVFS )
  2659. {
  2660. return false;
  2661. }
  2662. gStaticVFS = LLVFS::createLLVFS(static_vfs_index_file, static_vfs_data_file, true, 0, false);
  2663. if( !gStaticVFS )
  2664. {
  2665. return false;
  2666. }
  2667. BOOL success = gVFS->isValid() && gStaticVFS->isValid();
  2668. if( !success )
  2669. {
  2670. return false;
  2671. }
  2672. else
  2673. {
  2674. LLVFile::initClass();
  2675. return true;
  2676. }
  2677. }
  2678. void LLAppViewer::purgeCache()
  2679. {
  2680. LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << llendl;
  2681. LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE);
  2682. std::string mask = gDirUtilp->getDirDelimiter() + "*.*";
  2683. gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);
  2684. }
  2685. std::string LLAppViewer::getSecondLifeTitle() const
  2686. {
  2687. return LLTrans::getString("APP_NAME");
  2688. }
  2689. std::string LLAppViewer::getWindowTitle() const 
  2690. {
  2691. return gWindowTitle;
  2692. }
  2693. // Callback from a dialog indicating user was logged out.  
  2694. bool finish_disconnect(const LLSD& notification, const LLSD& response)
  2695. {
  2696. S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
  2697. if (1 == option)
  2698. {
  2699.         LLAppViewer::instance()->forceQuit();
  2700. }
  2701. return false;
  2702. }
  2703. // Callback from an early disconnect dialog, force an exit
  2704. bool finish_forced_disconnect(const LLSD& notification, const LLSD& response)
  2705. {
  2706. LLAppViewer::instance()->forceQuit();
  2707. return false;
  2708. }
  2709. void LLAppViewer::forceDisconnect(const std::string& mesg)
  2710. {
  2711. if (gDoDisconnect)
  2712.     {
  2713. // Already popped up one of these dialogs, don't
  2714. // do this again.
  2715. return;
  2716.     }
  2717. // *TODO: Translate the message if possible
  2718. std::string big_reason = LLAgent::sTeleportErrorMessages[mesg];
  2719. if ( big_reason.size() == 0 )
  2720. {
  2721. big_reason = mesg;
  2722. }
  2723. LLSD args;
  2724. gDoDisconnect = TRUE;
  2725. if (LLStartUp::getStartupState() < STATE_STARTED)
  2726. {
  2727. // Tell users what happened
  2728. args["ERROR_MESSAGE"] = big_reason;
  2729. LLNotificationsUtil::add("ErrorMessage", args, LLSD(), &finish_forced_disconnect);
  2730. }
  2731. else
  2732. {
  2733. args["MESSAGE"] = big_reason;
  2734. LLNotificationsUtil::add("YouHaveBeenLoggedOut", args, LLSD(), &finish_disconnect );
  2735. }
  2736. }
  2737. void LLAppViewer::badNetworkHandler()
  2738. {
  2739. // Dump the packet
  2740. gMessageSystem->dumpPacketToLog();
  2741. // Flush all of our caches on exit in the case of disconnect due to
  2742. // invalid packets.
  2743. mPurgeOnExit = TRUE;
  2744. #if LL_WINDOWS
  2745. // Generates the minidump.
  2746. LLWinDebug::generateCrashStacks(NULL);
  2747. #endif
  2748. LLAppViewer::handleSyncViewerCrash();
  2749. LLAppViewer::handleViewerCrash();
  2750. std::ostringstream message;
  2751. message <<
  2752. "The viewer has detected mangled network data indicativen"
  2753. "of a bad upstream network connection or an incompleten"
  2754. "local installation of " << LLAppViewer::instance()->getSecondLifeTitle() << ". n"
  2755. " n"
  2756. "Try uninstalling and reinstalling to see if this resolves n"
  2757. "the issue. n"
  2758. " n"
  2759. "If the problem continues, see the Tech Support FAQ at: n"
  2760. "www.secondlife.com/support";
  2761. forceDisconnect(message.str());
  2762. }
  2763. // This routine may get called more than once during the shutdown process.
  2764. // This can happen because we need to get the screenshot before the window
  2765. // is destroyed.
  2766. void LLAppViewer::saveFinalSnapshot()
  2767. {
  2768. if (!mSavedFinalSnapshot && !gNoRender)
  2769. {
  2770. gSavedSettings.setVector3d("FocusPosOnLogout", gAgent.calcFocusPositionTargetGlobal());
  2771. gSavedSettings.setVector3d("CameraPosOnLogout", gAgent.calcCameraPositionTargetGlobal());
  2772. gViewerWindow->setCursor(UI_CURSOR_WAIT);
  2773. gAgent.changeCameraToThirdPerson( FALSE ); // don't animate, need immediate switch
  2774. gSavedSettings.setBOOL("ShowParcelOwners", FALSE);
  2775. idle();
  2776. std::string snap_filename = gDirUtilp->getLindenUserDir();
  2777. snap_filename += gDirUtilp->getDirDelimiter();
  2778. snap_filename += SCREEN_LAST_FILENAME;
  2779. // use full pixel dimensions of viewer window (not post-scale dimensions)
  2780. gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, TRUE);
  2781. mSavedFinalSnapshot = TRUE;
  2782. }
  2783. }
  2784. void LLAppViewer::loadNameCache()
  2785. {
  2786. if (!gCacheName) return;
  2787. std::string name_cache;
  2788. name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
  2789. llifstream cache_file(name_cache);
  2790. if(cache_file.is_open())
  2791. {
  2792. if(gCacheName->importFile(cache_file)) return;
  2793. }
  2794. // Try to load from the legacy format. This should go away after a
  2795. // while. Phoenix 2008-01-30
  2796. LLFILE* name_cache_fp = LLFile::fopen(name_cache, "r"); // Flawfinder: ignore
  2797. if (name_cache_fp)
  2798. {
  2799. gCacheName->importFile(name_cache_fp);
  2800. fclose(name_cache_fp);
  2801. }
  2802. }
  2803. void LLAppViewer::saveNameCache()
  2804. {
  2805. if (!gCacheName) return;
  2806. std::string name_cache;
  2807. name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
  2808. llofstream cache_file(name_cache);
  2809. if(cache_file.is_open())
  2810. {
  2811. gCacheName->exportFile(cache_file);
  2812. }
  2813. }
  2814. /*! @brief This class is an LLFrameTimer that can be created with
  2815. an elapsed time that starts counting up from the given value
  2816. rather than 0.0.
  2817. Otherwise it behaves the same way as LLFrameTimer.
  2818. */
  2819. class LLFrameStatsTimer : public LLFrameTimer
  2820. {
  2821. public:
  2822. LLFrameStatsTimer(F64 elapsed_already = 0.0)
  2823. : LLFrameTimer()
  2824. {
  2825. mStartTime -= elapsed_already;
  2826. }
  2827. };
  2828. static LLFastTimer::DeclareTimer FTM_AUDIO_UPDATE("Update Audio");
  2829. static LLFastTimer::DeclareTimer FTM_CLEANUP("Cleanup");
  2830. static LLFastTimer::DeclareTimer FTM_IDLE_CB("Idle Callbacks");
  2831. static LLFastTimer::DeclareTimer FTM_LOD_UPDATE("Update LOD");
  2832. static LLFastTimer::DeclareTimer FTM_OBJECTLIST_UPDATE("Update Objectlist");
  2833. static LLFastTimer::DeclareTimer FTM_REGION_UPDATE("Update Region");
  2834. static LLFastTimer::DeclareTimer FTM_WORLD_UPDATE("Update World");
  2835. static LLFastTimer::DeclareTimer FTM_NETWORK("Network");
  2836. ///////////////////////////////////////////////////////
  2837. // idle()
  2838. //
  2839. // Called every time the window is not doing anything.
  2840. // Receive packets, update statistics, and schedule a redisplay.
  2841. ///////////////////////////////////////////////////////
  2842. void LLAppViewer::idle()
  2843. {
  2844. LLMemType mt_idle(LLMemType::MTYPE_IDLE);
  2845. pingMainloopTimeout("Main:Idle");
  2846. // Update frame timers
  2847. static LLTimer idle_timer;
  2848. LLFrameTimer::updateFrameTime();
  2849. LLFrameTimer::updateFrameCount();
  2850. LLEventTimer::updateClass();
  2851. LLCriticalDamp::updateInterpolants();
  2852. LLMortician::updateClass();
  2853. F32 dt_raw = idle_timer.getElapsedTimeAndResetF32();
  2854. // Cap out-of-control frame times
  2855. // Too low because in menus, swapping, debugger, etc.
  2856. // Too high because idle called with no objects in view, etc.
  2857. const F32 MIN_FRAME_RATE = 1.f;
  2858. const F32 MAX_FRAME_RATE = 200.f;
  2859. F32 frame_rate_clamped = 1.f / dt_raw;
  2860. frame_rate_clamped = llclamp(frame_rate_clamped, MIN_FRAME_RATE, MAX_FRAME_RATE);
  2861. gFrameDTClamped = 1.f / frame_rate_clamped;
  2862. // Global frame timer
  2863. // Smoothly weight toward current frame
  2864. gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f;
  2865. F32 qas = gSavedSettings.getF32("QuitAfterSeconds");
  2866. if (qas > 0.f)
  2867. {
  2868. if (gRenderStartTime.getElapsedTimeF32() > qas)
  2869. {
  2870. LLAppViewer::instance()->forceQuit();
  2871. }
  2872. }
  2873. // Must wait until both have avatar object and mute list, so poll
  2874. // here.
  2875. request_initial_instant_messages();
  2876. ///////////////////////////////////
  2877. //
  2878. // Special case idle if still starting up
  2879. //
  2880. if (LLStartUp::getStartupState() < STATE_STARTED)
  2881. {
  2882. // Skip rest if idle startup returns false (essentially, no world yet)
  2883. gGLActive = TRUE;
  2884. if (!idle_startup())
  2885. {
  2886. gGLActive = FALSE;
  2887. return;
  2888. }
  2889. gGLActive = FALSE;
  2890. }
  2891.     F32 yaw = 0.f; // radians
  2892. if (!gDisconnected)
  2893. {
  2894. LLFastTimer t(FTM_NETWORK);
  2895. // Update spaceserver timeinfo
  2896.     LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + (U32)(dt_raw * SEC_TO_MICROSEC));
  2897.     
  2898.     
  2899.     //////////////////////////////////////
  2900.     //
  2901.     // Update simulator agent state
  2902.     //
  2903. if (gSavedSettings.getBOOL("RotateRight"))
  2904. {
  2905. gAgent.moveYaw(-1.f);
  2906. }
  2907.     // Handle automatic walking towards points
  2908.     gAgentPilot.updateTarget();
  2909.     gAgent.autoPilot(&yaw);
  2910.     
  2911.     static LLFrameTimer agent_update_timer;
  2912.     static U32  last_control_flags;
  2913.     
  2914.     // When appropriate, update agent location to the simulator.
  2915.     F32 agent_update_time = agent_update_timer.getElapsedTimeF32();
  2916.     BOOL flags_changed = gAgent.controlFlagsDirty() || (last_control_flags != gAgent.getControlFlags());
  2917.     
  2918.     if (flags_changed || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND)))
  2919.     {
  2920.     // Send avatar and camera info
  2921.     last_control_flags = gAgent.getControlFlags();
  2922.     send_agent_update(TRUE);
  2923.     agent_update_timer.reset();
  2924.     }
  2925. }
  2926. //////////////////////////////////////
  2927. //
  2928. // Manage statistics
  2929. //
  2930. //
  2931. {
  2932. // Initialize the viewer_stats_timer with an already elapsed time
  2933. // of SEND_STATS_PERIOD so that the initial stats report will
  2934. // be sent immediately.
  2935. static LLFrameStatsTimer viewer_stats_timer(SEND_STATS_PERIOD);
  2936. reset_statistics();
  2937. // Update session stats every large chunk of time
  2938. // *FIX: (???) SAMANTHA
  2939. if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected)
  2940. {
  2941. llinfos << "Transmitting sessions stats" << llendl;
  2942. send_stats();
  2943. viewer_stats_timer.reset();
  2944. }
  2945. // Print the object debugging stats
  2946. static LLFrameTimer object_debug_timer;
  2947. if (object_debug_timer.getElapsedTimeF32() > 5.f)
  2948. {
  2949. object_debug_timer.reset();
  2950. if (gObjectList.mNumDeadObjectUpdates)
  2951. {
  2952. llinfos << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << llendl;
  2953. gObjectList.mNumDeadObjectUpdates = 0;
  2954. }
  2955. if (gObjectList.mNumUnknownKills)
  2956. {
  2957. llinfos << "Kills on unknown objects: " << gObjectList.mNumUnknownKills << llendl;
  2958. gObjectList.mNumUnknownKills = 0;
  2959. }
  2960. if (gObjectList.mNumUnknownUpdates)
  2961. {
  2962. llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl;
  2963. gObjectList.mNumUnknownUpdates = 0;
  2964. }
  2965. }
  2966. }
  2967. if (!gDisconnected)
  2968. {
  2969. LLFastTimer t(FTM_NETWORK);
  2970.     ////////////////////////////////////////////////
  2971.     //
  2972.     // Network processing
  2973.     //
  2974.     // NOTE: Starting at this point, we may still have pointers to "dead" objects
  2975.     // floating throughout the various object lists.
  2976.     //
  2977.     
  2978. idleNetwork();
  2979.              
  2980. // Check for away from keyboard, kick idle agents.
  2981. idle_afk_check();
  2982. //  Update statistics for this frame
  2983. update_statistics(gFrameCount);
  2984. }
  2985. ////////////////////////////////////////
  2986. //
  2987. // Handle the regular UI idle callbacks as well as
  2988. // hover callbacks
  2989. //
  2990. {
  2991. //  LLFastTimer t(FTM_IDLE_CB);
  2992. // Do event notifications if necessary.  Yes, we may want to move this elsewhere.
  2993. gEventNotifier.update();
  2994. gIdleCallbacks.callFunctions();
  2995. gInventory.idleNotifyObservers();
  2996. }
  2997. if (gDisconnected)
  2998.     {
  2999. return;
  3000.     }
  3001. gViewerWindow->updateUI();
  3002. ///////////////////////////////////////
  3003. // Agent and camera movement
  3004. //
  3005. LLCoordGL current_mouse = gViewerWindow->getCurrentMouse();
  3006. {
  3007. // After agent and camera moved, figure out if we need to
  3008. // deselect objects.
  3009. LLSelectMgr::getInstance()->deselectAllIfTooFar();
  3010. }
  3011. {
  3012. // Handle pending gesture processing
  3013. LLGestureManager::instance().update();
  3014. gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY);
  3015. }
  3016. {
  3017. LLFastTimer t(FTM_OBJECTLIST_UPDATE); // Actually "object update"
  3018.         if (!(logoutRequestSent() && hasSavedFinalSnapshot()))
  3019. {
  3020. gObjectList.update(gAgent, *LLWorld::getInstance());
  3021. }
  3022. }
  3023. //////////////////////////////////////
  3024. //
  3025. // Deletes objects...
  3026. // Has to be done after doing idleUpdates (which can kill objects)
  3027. //
  3028. {
  3029. LLFastTimer t(FTM_CLEANUP);
  3030. gObjectList.cleanDeadObjects();
  3031. LLDrawable::cleanupDeadDrawables();
  3032. }
  3033. //
  3034. // After this point, in theory we should never see a dead object
  3035. // in the various object/drawable lists.
  3036. //
  3037. //////////////////////////////////////
  3038. //
  3039. // Update/send HUD effects
  3040. //
  3041. // At this point, HUD effects may clean up some references to
  3042. // dead objects.
  3043. //
  3044. {
  3045. LLSelectMgr::getInstance()->updateEffects();
  3046. LLHUDManager::getInstance()->cleanupEffects();
  3047. LLHUDManager::getInstance()->sendEffects();
  3048. }
  3049. ////////////////////////////////////////
  3050. //
  3051. // Unpack layer data that we've received
  3052. //
  3053. {
  3054. LLFastTimer t(FTM_NETWORK);
  3055. gVLManager.unpackData();
  3056. }
  3057. /////////////////////////
  3058. //
  3059. // Update surfaces, and surface textures as well.
  3060. //
  3061. LLWorld::getInstance()->updateVisibilities();
  3062. {
  3063. const F32 max_region_update_time = .001f; // 1ms
  3064. LLFastTimer t(FTM_REGION_UPDATE);
  3065. LLWorld::getInstance()->updateRegions(max_region_update_time);
  3066. }
  3067. /////////////////////////
  3068. //
  3069. // Update weather effects
  3070. //
  3071. if (!gNoRender)
  3072. {
  3073. LLWorld::getInstance()->updateClouds(gFrameDTClamped);
  3074. gSky.propagateHeavenlyBodies(gFrameDTClamped); // moves sun, moon, and planets
  3075. // Update wind vector 
  3076. LLVector3 wind_position_region;
  3077. static LLVector3 average_wind;
  3078. LLViewerRegion *regionp;
  3079. regionp = LLWorld::getInstance()->resolveRegionGlobal(wind_position_region, gAgent.getPositionGlobal()); // puts agent's local coords into wind_position
  3080. if (regionp)
  3081. {
  3082. gWindVec = regionp->mWind.getVelocity(wind_position_region);
  3083. // Compute average wind and use to drive motion of water
  3084. average_wind = regionp->mWind.getAverage();
  3085. F32 cloud_density = regionp->mCloudLayer.getDensityRegion(wind_position_region);
  3086. gSky.setCloudDensityAtAgent(cloud_density);
  3087. gSky.setWind(average_wind);
  3088. //LLVOWater::setWind(average_wind);
  3089. }
  3090. else
  3091. {
  3092. gWindVec.setVec(0.0f, 0.0f, 0.0f);
  3093. }
  3094. }
  3095. //////////////////////////////////////
  3096. //
  3097. // Sort and cull in the new renderer are moved to pipeline.cpp
  3098. // Here, particles are updated and drawables are moved.
  3099. //
  3100. if (!gNoRender)
  3101. {
  3102. LLFastTimer t(FTM_WORLD_UPDATE);
  3103. gPipeline.updateMove();
  3104. LLWorld::getInstance()->updateParticles();
  3105. }
  3106. if (LLViewerJoystick::getInstance()->getOverrideCamera())
  3107. {
  3108. LLViewerJoystick::getInstance()->moveFlycam();
  3109. }
  3110. else
  3111. {
  3112. if (LLToolMgr::getInstance()->inBuildMode())
  3113. {
  3114. LLViewerJoystick::getInstance()->moveObjects();
  3115. }
  3116. gAgent.updateCamera();
  3117. }
  3118. // update media focus
  3119. LLViewerMediaFocus::getInstance()->update();
  3120. // objects and camera should be in sync, do LOD calculations now
  3121. {
  3122. LLFastTimer t(FTM_LOD_UPDATE);
  3123. gObjectList.updateApparentAngles(gAgent);
  3124. }
  3125. {
  3126. LLFastTimer t(FTM_AUDIO_UPDATE);
  3127. if (gAudiop)
  3128. {
  3129.     audio_update_volume(false);
  3130. audio_update_listener();
  3131. audio_update_wind(false);
  3132. // this line actually commits the changes we've made to source positions, etc.
  3133. const F32 max_audio_decode_time = 0.002f; // 2 ms decode time
  3134. gAudiop->idle(max_audio_decode_time);
  3135. }
  3136. }
  3137. // Handle shutdown process, for example, 
  3138. // wait for floaters to close, send quit message,
  3139. // forcibly quit if it has taken too long
  3140. if (mQuitRequested)
  3141. {
  3142. gGLActive = TRUE;
  3143. idleShutdown();
  3144. }
  3145. }
  3146. void LLAppViewer::idleShutdown()
  3147. {
  3148. // Wait for all modal alerts to get resolved
  3149. if (LLModalDialog::activeCount() > 0)
  3150. {
  3151. return;
  3152. }
  3153. // close IM interface
  3154. if(gIMMgr)
  3155. {
  3156. gIMMgr->disconnectAllSessions();
  3157. }
  3158. // Wait for all floaters to get resolved
  3159. if (gFloaterView
  3160. && !gFloaterView->allChildrenClosed())
  3161. {
  3162. return;
  3163. }
  3164. if (LLSideTray::getInstance()->notifyChildren(LLSD().with("request","wait_quit")))
  3165. {
  3166. return;
  3167. }
  3168. // ProductEngine: Try moving this code to where we shut down sTextureCache in cleanup()
  3169. // *TODO: ugly
  3170. static bool saved_teleport_history = false;
  3171. if (!saved_teleport_history)
  3172. {
  3173. saved_teleport_history = true;
  3174. LLTeleportHistory::getInstance()->dump();
  3175. LLLocationHistory::getInstance()->save(); // *TODO: find a better place for doing this
  3176. return;
  3177. }
  3178. static bool saved_snapshot = false;
  3179. if (!saved_snapshot)
  3180. {
  3181. saved_snapshot = true;
  3182. saveFinalSnapshot();
  3183. return;
  3184. }
  3185. const F32 SHUTDOWN_UPLOAD_SAVE_TIME = 5.f;
  3186. S32 pending_uploads = gAssetStorage->getNumPendingUploads();
  3187. if (pending_uploads > 0
  3188. && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME
  3189. && !logoutRequestSent())
  3190. {
  3191. static S32 total_uploads = 0;
  3192. // Sometimes total upload count can change during logout.
  3193. total_uploads = llmax(total_uploads, pending_uploads);
  3194. gViewerWindow->setShowProgress(TRUE);
  3195. S32 finished_uploads = total_uploads - pending_uploads;
  3196. F32 percent = 100.f * finished_uploads / total_uploads;
  3197. gViewerWindow->setProgressPercent(percent);
  3198. gViewerWindow->setProgressString("Saving your settings...");
  3199. return;
  3200. }
  3201. // All floaters are closed.  Tell server we want to quit.
  3202. if( !logoutRequestSent() )
  3203. {
  3204. sendLogoutRequest();
  3205. // Wait for a LogoutReply message
  3206. gViewerWindow->setShowProgress(TRUE);
  3207. gViewerWindow->setProgressPercent(100.f);
  3208. gViewerWindow->setProgressString("Logging out...");
  3209. return;
  3210. }
  3211. // Make sure that we quit if we haven't received a reply from the server.
  3212. if( logoutRequestSent() 
  3213. && gLogoutTimer.getElapsedTimeF32() > gLogoutMaxTime )
  3214. {
  3215. forceQuit();
  3216. return;
  3217. }
  3218. }
  3219. void LLAppViewer::sendLogoutRequest()
  3220. {
  3221. if(!mLogoutRequestSent)
  3222. {
  3223. LLMessageSystem* msg = gMessageSystem;
  3224. msg->newMessageFast(_PREHASH_LogoutRequest);
  3225. msg->nextBlockFast(_PREHASH_AgentData);
  3226. msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
  3227. msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
  3228. gAgent.sendReliableMessage();
  3229. gLogoutTimer.reset();
  3230. gLogoutMaxTime = LOGOUT_REQUEST_TIME;
  3231. mLogoutRequestSent = TRUE;
  3232. gVoiceClient->leaveChannel();
  3233. //Set internal status variables and marker files
  3234. gLogoutInProgress = TRUE;
  3235. mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME);
  3236. LLAPRFile outfile ;
  3237. outfile.open(mLogoutMarkerFileName, LL_APR_W);
  3238. mLogoutMarkerFile =  outfile.getFileHandle() ;
  3239. if (mLogoutMarkerFile)
  3240. {
  3241. llinfos << "Created logout marker file " << mLogoutMarkerFileName << llendl;
  3242.      apr_file_close(mLogoutMarkerFile);
  3243. }
  3244. else
  3245. {
  3246. llwarns << "Cannot create logout marker file " << mLogoutMarkerFileName << llendl;
  3247. }
  3248. }
  3249. }
  3250. //
  3251. // Handle messages, and all message related stuff
  3252. //
  3253. #define TIME_THROTTLE_MESSAGES
  3254. #ifdef TIME_THROTTLE_MESSAGES
  3255. #define CHECK_MESSAGES_DEFAULT_MAX_TIME .020f // 50 ms = 50 fps (just for messages!)
  3256. static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
  3257. #endif
  3258. static LLFastTimer::DeclareTimer FTM_IDLE_NETWORK("Network");
  3259. void LLAppViewer::idleNetwork()
  3260. {
  3261. LLMemType mt_in(LLMemType::MTYPE_IDLE_NETWORK);
  3262. pingMainloopTimeout("idleNetwork");
  3263. LLError::LLCallStacks::clear() ;
  3264. llpushcallstacks ;
  3265. gObjectList.mNumNewObjects = 0;
  3266. S32 total_decoded = 0;
  3267. if (!gSavedSettings.getBOOL("SpeedTest"))
  3268. {
  3269. LLFastTimer t(FTM_IDLE_NETWORK); // decode
  3270. // deal with any queued name requests and replies.
  3271. gCacheName->processPending();
  3272. llpushcallstacks ;
  3273. LLTimer check_message_timer;
  3274. //  Read all available packets from network 
  3275. const S64 frame_count = gFrameCount;  // U32->S64
  3276. F32 total_time = 0.0f;
  3277. while (gMessageSystem->checkAllMessages(frame_count, gServicePump)) 
  3278. {
  3279. if (gDoDisconnect)
  3280. {
  3281. // We're disconnecting, don't process any more messages from the server
  3282. // We're usually disconnecting due to either network corruption or a
  3283. // server going down, so this is OK.
  3284. break;
  3285. }
  3286. total_decoded++;
  3287. gPacketsIn++;
  3288. if (total_decoded > MESSAGE_MAX_PER_FRAME)
  3289. {
  3290. break;
  3291. }
  3292. #ifdef TIME_THROTTLE_MESSAGES
  3293. // Prevent slow packets from completely destroying the frame rate.
  3294. // This usually happens due to clumps of avatars taking huge amount
  3295. // of network processing time (which needs to be fixed, but this is
  3296. // a good limit anyway).
  3297. total_time = check_message_timer.getElapsedTimeF32();
  3298. if (total_time >= CheckMessagesMaxTime)
  3299. break;
  3300. #endif
  3301. }
  3302. // Handle per-frame message system processing.
  3303. gMessageSystem->processAcks();
  3304. #ifdef TIME_THROTTLE_MESSAGES
  3305. if (total_time >= CheckMessagesMaxTime)
  3306. {
  3307. // Increase CheckMessagesMaxTime so that we will eventually catch up
  3308. CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames
  3309. }
  3310. else
  3311. {
  3312. // Reset CheckMessagesMaxTime to default value
  3313. CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
  3314. }
  3315. #endif
  3316. // we want to clear the control after sending out all necessary agent updates
  3317. gAgent.resetControlFlags();
  3318. // Decode enqueued messages...
  3319. S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded;
  3320. if( remaining_possible_decodes <= 0 )
  3321. {
  3322. llinfos << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << llendl;
  3323. }
  3324. if (gPrintMessagesThisFrame)
  3325. {
  3326. llinfos << "Decoded " << total_decoded << " msgs this frame!" << llendl;
  3327. gPrintMessagesThisFrame = FALSE;
  3328. }
  3329. }
  3330. llpushcallstacks ;
  3331. LLViewerStats::getInstance()->mNumNewObjectsStat.addValue(gObjectList.mNumNewObjects);
  3332. // Retransmit unacknowledged packets.
  3333. gXferManager->retransmitUnackedPackets();
  3334. gAssetStorage->checkForTimeouts();
  3335. llpushcallstacks ;
  3336. gViewerThrottle.updateDynamicThrottle();
  3337. llpushcallstacks ;
  3338. // Check that the circuit between the viewer and the agent's current
  3339. // region is still alive
  3340. LLViewerRegion *agent_region = gAgent.getRegion();
  3341. if (agent_region && (LLStartUp::getStartupState()==STATE_STARTED))
  3342. {
  3343. LLUUID this_region_id = agent_region->getRegionID();
  3344. bool this_region_alive = agent_region->isAlive();
  3345. if ((mAgentRegionLastAlive && !this_region_alive) // newly dead
  3346.     && (mAgentRegionLastID == this_region_id)) // same region
  3347. {
  3348. forceDisconnect(LLTrans::getString("AgentLostConnection"));
  3349. }
  3350. mAgentRegionLastID = this_region_id;
  3351. mAgentRegionLastAlive = this_region_alive;
  3352. }
  3353. llpushcallstacks ;
  3354. }
  3355. void LLAppViewer::disconnectViewer()
  3356. {
  3357. if (gDisconnected)
  3358. {
  3359. return;
  3360. }
  3361. //
  3362. // Cleanup after quitting.
  3363. //
  3364. // Save snapshot for next time, if we made it through initialization
  3365. llinfos << "Disconnecting viewer!" << llendl;
  3366. // Dump our frame statistics
  3367. // Remember if we were flying
  3368. gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() );
  3369. // Un-minimize all windows so they don't get saved minimized
  3370. if (!gNoRender)
  3371. {
  3372. if (gFloaterView)
  3373. {
  3374. gFloaterView->restoreAll();
  3375. }
  3376. }
  3377. if (LLSelectMgr::getInstance())
  3378. {
  3379. LLSelectMgr::getInstance()->deselectAll();
  3380. }
  3381. // save inventory if appropriate
  3382. gInventory.cache(gInventory.getRootFolderID(), gAgent.getID());
  3383. if (gInventory.getLibraryRootFolderID().notNull()
  3384. && gInventory.getLibraryOwnerID().notNull())
  3385. {
  3386. gInventory.cache(
  3387. gInventory.getLibraryRootFolderID(),
  3388. gInventory.getLibraryOwnerID());
  3389. }
  3390. saveNameCache();
  3391. // close inventory interface, close all windows
  3392. LLFloaterInventory::cleanup();
  3393. gAgentWearables.cleanup();
  3394. // Also writes cached agent settings to gSavedSettings
  3395. gAgent.cleanup();
  3396. // This is where we used to call gObjectList.destroy() and then delete gWorldp.
  3397. // Now we just ask the LLWorld singleton to cleanly shut down.
  3398. LLWorld::getInstance()->destroyClass();
  3399. // call all self-registered classes
  3400. LLDestroyClassList::instance().fireCallbacks();
  3401. cleanup_xfer_manager();
  3402. gDisconnected = TRUE;
  3403. }
  3404. void LLAppViewer::forceErrorLLError()
  3405. {
  3406.     llerrs << "This is an llerror" << llendl;
  3407. }
  3408. void LLAppViewer::forceErrorBreakpoint()
  3409. {
  3410. #ifdef LL_WINDOWS
  3411.     DebugBreak();
  3412. #endif
  3413.     return;
  3414. }
  3415. void LLAppViewer::forceErrorBadMemoryAccess()
  3416. {
  3417.     S32* crash = NULL;
  3418.     *crash = 0xDEADBEEF;
  3419.     return;
  3420. }
  3421. void LLAppViewer::forceErrorInfiniteLoop()
  3422. {
  3423.     while(true)
  3424.     {
  3425.         ;
  3426.     }
  3427.     return;
  3428. }
  3429.  
  3430. void LLAppViewer::forceErrorSoftwareException()
  3431. {
  3432.     // *FIX: Any way to insure it won't be handled?
  3433.     throw; 
  3434. }
  3435. void LLAppViewer::forceErrorDriverCrash()
  3436. {
  3437. glDeleteTextures(1, NULL);
  3438. }
  3439. void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs)
  3440. {
  3441. if(!mMainloopTimeout)
  3442. {
  3443. mMainloopTimeout = new LLWatchdogTimeout();
  3444. resumeMainloopTimeout(state, secs);
  3445. }
  3446. }
  3447. void LLAppViewer::destroyMainloopTimeout()
  3448. {
  3449. if(mMainloopTimeout)
  3450. {
  3451. delete mMainloopTimeout;
  3452. mMainloopTimeout = NULL;
  3453. }
  3454. }
  3455. void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs)
  3456. {
  3457. if(mMainloopTimeout)
  3458. {
  3459. if(secs < 0.0f)
  3460. {
  3461. secs = gSavedSettings.getF32("MainloopTimeoutDefault");
  3462. }
  3463. mMainloopTimeout->setTimeout(secs);
  3464. mMainloopTimeout->start(state);
  3465. }
  3466. }
  3467. void LLAppViewer::pauseMainloopTimeout()
  3468. {
  3469. if(mMainloopTimeout)
  3470. {
  3471. mMainloopTimeout->stop();
  3472. }
  3473. }
  3474. void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs)
  3475. {
  3476. // if(!restoreErrorTrap())
  3477. // {
  3478. // llwarns << "!!!!!!!!!!!!! Its an error trap!!!!" << state << llendl;
  3479. // }
  3480. if(mMainloopTimeout)
  3481. {
  3482. if(secs < 0.0f)
  3483. {
  3484. secs = gSavedSettings.getF32("MainloopTimeoutDefault");
  3485. }
  3486. mMainloopTimeout->setTimeout(secs);
  3487. mMainloopTimeout->ping(state);
  3488. }
  3489. }
  3490. void LLAppViewer::handleLoginComplete()
  3491. {
  3492. initMainloopTimeout("Mainloop Init");
  3493. // Store some data to DebugInfo in case of a freeze.
  3494. gDebugInfo["ClientInfo"]["Name"] = gSavedSettings.getString("VersionChannelName");
  3495. gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
  3496. gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
  3497. gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch();
  3498. gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild();
  3499. LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
  3500. if ( parcel && parcel->getMusicURL()[0])
  3501. {
  3502. gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL();
  3503. }
  3504. if ( parcel && parcel->getMediaURL()[0])
  3505. {
  3506. gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL();
  3507. }
  3508. gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile");
  3509. gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
  3510. gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName();
  3511. gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath();
  3512. if(gAgent.getRegion())
  3513. {
  3514. gDebugInfo["CurrentSimHost"] = gAgent.getRegionHost().getHostName();
  3515. gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName();
  3516. }
  3517. if(LLAppViewer::instance()->mMainloopTimeout)
  3518. {
  3519. gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState();
  3520. }
  3521. mOnLoginCompleted();
  3522. writeDebugInfo();
  3523. }
  3524. // *TODO - generalize this and move DSO wrangling to a helper class -brad
  3525. void LLAppViewer::loadEventHostModule(S32 listen_port)
  3526. {
  3527. std::string dso_name =
  3528. #if LL_WINDOWS
  3529.     "lleventhost.dll";
  3530. #elif LL_DARWIN
  3531.     "liblleventhost.dylib";
  3532. #else
  3533.     "liblleventhost.so";
  3534. #endif
  3535. std::string dso_path = gDirUtilp->findFile(dso_name,
  3536. gDirUtilp->getAppRODataDir(),
  3537. gDirUtilp->getExecutableDir());
  3538. if(dso_path == "")
  3539. {
  3540. llerrs << "QAModeEventHost requested but module "" << dso_name << "" not found!" << llendl;
  3541. return;
  3542. }
  3543. apr_dso_handle_t * eventhost_dso_handle = NULL;
  3544. apr_pool_t * eventhost_dso_memory_pool = NULL;
  3545. //attempt to load the shared library
  3546. apr_pool_create(&eventhost_dso_memory_pool, NULL);
  3547. apr_status_t rv = apr_dso_load(&eventhost_dso_handle,
  3548. dso_path.c_str(),
  3549. eventhost_dso_memory_pool);
  3550. ll_apr_assert_status(rv);
  3551. llassert_always(eventhost_dso_handle != NULL);
  3552. int (*ll_plugin_start_func)(LLSD const &) = NULL;
  3553. rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_start_func, eventhost_dso_handle, "ll_plugin_start");
  3554. ll_apr_assert_status(rv);
  3555. llassert_always(ll_plugin_start_func != NULL);
  3556. LLSD args;
  3557. args["listen_port"] = listen_port;
  3558. int status = ll_plugin_start_func(args);
  3559. if(status != 0)
  3560. {
  3561. llerrs << "problem loading eventhost plugin, status: " << status << llendl;
  3562. }
  3563. mPlugins.insert(eventhost_dso_handle);
  3564. }
  3565. void LLAppViewer::launchUpdater()
  3566. {
  3567. LLSD query_map = LLSD::emptyMap();
  3568. // *TODO place os string in a global constant
  3569. #if LL_WINDOWS  
  3570. query_map["os"] = "win";
  3571. #elif LL_DARWIN
  3572. query_map["os"] = "mac";
  3573. #elif LL_LINUX
  3574. query_map["os"] = "lnx";
  3575. #elif LL_SOLARIS
  3576. query_map["os"] = "sol";
  3577. #endif
  3578. // *TODO change userserver to be grid on both viewer and sim, since
  3579. // userserver no longer exists.
  3580. query_map["userserver"] = LLViewerLogin::getInstance()->getGridLabel();
  3581. query_map["channel"] = gSavedSettings.getString("VersionChannelName");
  3582. // *TODO constantize this guy
  3583. // *NOTE: This URL is also used in win_setup/lldownloader.cpp
  3584. LLURI update_url = LLURI::buildHTTP("secondlife.com", 80, "update.php", query_map);
  3585. if(LLAppViewer::sUpdaterInfo)
  3586. {
  3587. delete LLAppViewer::sUpdaterInfo;
  3588. }
  3589. LLAppViewer::sUpdaterInfo = new LLAppViewer::LLUpdaterInfo() ;
  3590. // if a sim name was passed in via command line parameter (typically through a SLURL)
  3591. if ( LLURLSimString::sInstance.mSimString.length() )
  3592. {
  3593. // record the location to start at next time
  3594. gSavedSettings.setString( "NextLoginLocation", LLURLSimString::sInstance.mSimString ); 
  3595. };
  3596. #if LL_WINDOWS
  3597. LLAppViewer::sUpdaterInfo->mUpdateExePath = gDirUtilp->getTempFilename();
  3598. if (LLAppViewer::sUpdaterInfo->mUpdateExePath.empty())
  3599. {
  3600. delete LLAppViewer::sUpdaterInfo ;
  3601. LLAppViewer::sUpdaterInfo = NULL ;
  3602. // We're hosed, bail
  3603. LL_WARNS("AppInit") << "LLDir::getTempFilename() failed" << LL_ENDL;
  3604. return;
  3605. }
  3606. LLAppViewer::sUpdaterInfo->mUpdateExePath += ".exe";
  3607. std::string updater_source = gDirUtilp->getAppRODataDir();
  3608. updater_source += gDirUtilp->getDirDelimiter();
  3609. updater_source += "updater.exe";
  3610. LL_DEBUGS("AppInit") << "Calling CopyFile source: " << updater_source
  3611. << " dest: " << LLAppViewer::sUpdaterInfo->mUpdateExePath
  3612. << LL_ENDL;
  3613. if (!CopyFileA(updater_source.c_str(), LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), FALSE))
  3614. {
  3615. delete LLAppViewer::sUpdaterInfo ;
  3616. LLAppViewer::sUpdaterInfo = NULL ;
  3617. LL_WARNS("AppInit") << "Unable to copy the updater!" << LL_ENDL;
  3618. return;
  3619. }
  3620. LLAppViewer::sUpdaterInfo->mParams << "-url "" << update_url.asString() << """;
  3621. LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << " " << LLAppViewer::sUpdaterInfo->mParams.str() << LL_ENDL;
  3622. //Explicitly remove the marker file, otherwise we pass the lock onto the child process and things get weird.
  3623. LLAppViewer::instance()->removeMarkerFile(); // In case updater fails
  3624. // *NOTE:Mani The updater is spawned as the last thing before the WinMain exit.
  3625. // see LLAppViewerWin32.cpp
  3626. #elif LL_DARWIN
  3627. LLAppViewer::sUpdaterInfo->mUpdateExePath = "'";
  3628. LLAppViewer::sUpdaterInfo->mUpdateExePath += gDirUtilp->getAppRODataDir();
  3629. LLAppViewer::sUpdaterInfo->mUpdateExePath += "/mac-updater.app/Contents/MacOS/mac-updater' -url "";
  3630. LLAppViewer::sUpdaterInfo->mUpdateExePath += update_url.asString();
  3631. LLAppViewer::sUpdaterInfo->mUpdateExePath += "" -name "";
  3632. LLAppViewer::sUpdaterInfo->mUpdateExePath += LLAppViewer::instance()->getSecondLifeTitle();
  3633. LLAppViewer::sUpdaterInfo->mUpdateExePath += "" &";
  3634. LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL;
  3635. // Run the auto-updater.
  3636. system(LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str()); /* Flawfinder: ignore */
  3637. #elif (LL_LINUX || LL_SOLARIS) && LL_GTK
  3638. // we tell the updater where to find the xml containing string
  3639. // translations which it can use for its own UI
  3640. std::string xml_strings_file = "strings.xml";
  3641. std::vector<std::string> xui_path_vec = LLUI::getXUIPaths();
  3642. std::string xml_search_paths;
  3643. std::vector<std::string>::const_iterator iter;
  3644. // build comma-delimited list of xml paths to pass to updater
  3645. for (iter = xui_path_vec.begin(); iter != xui_path_vec.end(); )
  3646. {
  3647. std::string this_skin_dir = gDirUtilp->getDefaultSkinDir()
  3648. + gDirUtilp->getDirDelimiter()
  3649. + (*iter);
  3650. llinfos << "Got a XUI path: " << this_skin_dir << llendl;
  3651. xml_search_paths.append(this_skin_dir);
  3652. ++iter;
  3653. if (iter != xui_path_vec.end())
  3654. xml_search_paths.append(","); // comma-delimit
  3655. }
  3656. // build the overall command-line to run the updater correctly
  3657. LLAppViewer::sUpdaterInfo->mUpdateExePath = 
  3658. gDirUtilp->getExecutableDir() + "/" + "linux-updater.bin" + 
  3659. " --url "" + update_url.asString() + """ +
  3660. " --name "" + LLAppViewer::instance()->getSecondLifeTitle() + """ +
  3661. " --dest "" + gDirUtilp->getAppRODataDir() + """ +
  3662. " --stringsdir "" + xml_search_paths + """ +
  3663. " --stringsfile "" + xml_strings_file + """;
  3664. LL_INFOS("AppInit") << "Calling updater: " 
  3665.     << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL;
  3666. // *TODO: we could use the gdk equivalent to ensure the updater
  3667. // gets started on the same screen.
  3668. GError *error = NULL;
  3669. if (!g_spawn_command_line_async(LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), &error))
  3670. {
  3671. llerrs << "Failed to launch updater: "
  3672.        << error->message
  3673.        << llendl;
  3674. }
  3675. if (error) {
  3676. g_error_free(error);
  3677. }
  3678. #else
  3679. OSMessageBox(LLTrans::getString("MBNoAutoUpdate"), LLStringUtil::null, OSMB_OK);
  3680. #endif
  3681. // *REMOVE:Mani - Saving for reference...
  3682. // LLAppViewer::instance()->forceQuit();
  3683. }
  3684. //virtual
  3685. void LLAppViewer::setMasterSystemAudioMute(bool mute)
  3686. {
  3687. gSavedSettings.setBOOL("MuteAudio", mute);
  3688. }
  3689. //virtual
  3690. bool LLAppViewer::getMasterSystemAudioMute()
  3691. {
  3692. return gSavedSettings.getBOOL("MuteAudio");
  3693. }