/indra/newview/llappviewer.cpp
C++ | 2191 lines | 1448 code | 399 blank | 344 comment | 149 complexity | 2d022bdd69b86b347004945c8eb65f14 MD5 | raw file
Possible License(s): LGPL-2.1
- /**
- * @file llappviewer.cpp
- * @brief The LLAppViewer class definitions
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
- #include "llviewerprecompiledheaders.h"
- #include "llappviewer.h"
- // Viewer includes
- #include "llversioninfo.h"
- #include "llversionviewer.h"
- #include "llfeaturemanager.h"
- #include "lluictrlfactory.h"
- #include "lltexteditor.h"
- #include "llerrorcontrol.h"
- #include "lleventtimer.h"
- #include "llviewertexturelist.h"
- #include "llgroupmgr.h"
- #include "llagent.h"
- #include "llagentcamera.h"
- #include "llagentlanguage.h"
- #include "llagentwearables.h"
- #include "llwindow.h"
- #include "llviewerstats.h"
- #include "llviewerstatsrecorder.h"
- #include "llmarketplacefunctions.h"
- #include "llmarketplacenotifications.h"
- #include "llmd5.h"
- #include "llmeshrepository.h"
- #include "llpumpio.h"
- #include "llmimetypes.h"
- #include "llslurl.h"
- #include "llstartup.h"
- #include "llfocusmgr.h"
- #include "llviewerjoystick.h"
- #include "llallocator.h"
- #include "llares.h"
- #include "llcurl.h"
- #include "llcalc.h"
- #include "lltexturestats.h"
- #include "lltexturestats.h"
- #include "llviewerwindow.h"
- #include "llviewerdisplay.h"
- #include "llviewermedia.h"
- #include "llviewerparcelmedia.h"
- #include "llviewermediafocus.h"
- #include "llviewermessage.h"
- #include "llviewerobjectlist.h"
- #include "llworldmap.h"
- #include "llmutelist.h"
- #include "llviewerhelp.h"
- #include "lluicolortable.h"
- #include "llurldispatcher.h"
- #include "llurlhistory.h"
- //#include "llfirstuse.h"
- #include "llrender.h"
- #include "llteleporthistory.h"
- #include "lltoast.h"
- #include "lllocationhistory.h"
- #include "llfasttimerview.h"
- #include "llvector4a.h"
- #include "llviewermenufile.h"
- #include "llvoicechannel.h"
- #include "llvoavatarself.h"
- #include "llurlmatch.h"
- #include "lltextutil.h"
- #include "lllogininstance.h"
- #include "llprogressview.h"
- #include "llvocache.h"
- #include "llweb.h"
- #include "llsecondlifeurls.h"
- #include "llupdaterservice.h"
- #include "llcallfloater.h"
- // Linden library includes
- #include "llavatarnamecache.h"
- #include "lldiriterator.h"
- #include "llimagej2c.h"
- #include "llmemory.h"
- #include "llprimitive.h"
- #include "llurlaction.h"
- #include "llurlentry.h"
- #include "llvfile.h"
- #include "llvfsthread.h"
- #include "llvolumemgr.h"
- #include "llxfermanager.h"
- #include "llnotificationmanager.h"
- #include "llnotifications.h"
- #include "llnotificationsutil.h"
- // Third party library includes
- #include <boost/bind.hpp>
- #include <boost/foreach.hpp>
- #if LL_WINDOWS
- # include <share.h> // For _SH_DENYWR in initMarkerFile
- #else
- # include <sys/file.h> // For initMarkerFile support
- #endif
- #include "llapr.h"
- #include "apr_dso.h"
- #include <boost/lexical_cast.hpp>
- #include "llviewerkeyboard.h"
- #include "lllfsthread.h"
- #include "llworkerthread.h"
- #include "lltexturecache.h"
- #include "lltexturefetch.h"
- #include "llimageworker.h"
- #include "llevents.h"
- // The files below handle dependencies from cleanup.
- #include "llkeyframemotion.h"
- #include "llworldmap.h"
- #include "llhudmanager.h"
- #include "lltoolmgr.h"
- #include "llassetstorage.h"
- #include "llpolymesh.h"
- #include "llproxy.h"
- #include "llaudioengine.h"
- #include "llstreamingaudio.h"
- #include "llviewermenu.h"
- #include "llselectmgr.h"
- #include "lltrans.h"
- #include "lltransutil.h"
- #include "lltracker.h"
- #include "llviewerparcelmgr.h"
- #include "llworldmapview.h"
- #include "llpostprocess.h"
- #include "llwlparammanager.h"
- #include "llwaterparammanager.h"
- #include "lldebugview.h"
- #include "llconsole.h"
- #include "llcontainerview.h"
- #include "lltooltip.h"
- #include "llsdserialize.h"
- #include "llworld.h"
- #include "llhudeffecttrail.h"
- #include "llvectorperfoptions.h"
- #include "llslurl.h"
- #include "llwatchdog.h"
- // Included so that constants/settings might be initialized
- // in save_settings_to_globals()
- #include "llbutton.h"
- #include "llstatusbar.h"
- #include "llsurface.h"
- #include "llvosky.h"
- #include "llvotree.h"
- #include "llvoavatar.h"
- #include "llfolderview.h"
- #include "llagentpilot.h"
- #include "llvovolume.h"
- #include "llflexibleobject.h"
- #include "llvosurfacepatch.h"
- #include "llviewerfloaterreg.h"
- #include "llcommandlineparser.h"
- #include "llfloatermemleak.h"
- #include "llfloaterreg.h"
- #include "llfloatersnapshot.h"
- #include "llfloaterinventory.h"
- // includes for idle() idleShutdown()
- #include "llviewercontrol.h"
- #include "lleventnotifier.h"
- #include "llcallbacklist.h"
- #include "pipeline.h"
- #include "llgesturemgr.h"
- #include "llsky.h"
- #include "llvlmanager.h"
- #include "llviewercamera.h"
- #include "lldrawpoolbump.h"
- #include "llvieweraudio.h"
- #include "llimview.h"
- #include "llviewerthrottle.h"
- #include "llparcel.h"
- #include "llavatariconctrl.h"
- #include "llgroupiconctrl.h"
- #include "llviewerassetstats.h"
- // Include for security api initialization
- #include "llsecapi.h"
- #include "llmachineid.h"
- #include "llmainlooprepeater.h"
- // *FIX: These extern globals should be cleaned up.
- // The globals either represent state/config/resource-storage of either
- // this app, or another 'component' of the viewer. App globals should be
- // moved into the app class, where as the other globals should be
- // moved out of here.
- // If a global symbol reference seems valid, it will be included
- // via header files above.
- //----------------------------------------------------------------------------
- // llviewernetwork.h
- #include "llviewernetwork.h"
- // define a self-registering event API object
- #include "llappviewerlistener.h"
- #if (LL_LINUX || LL_SOLARIS) && LL_GTK
- #include "glib.h"
- #endif // (LL_LINUX || LL_SOLARIS) && LL_GTK
- #if LL_MSVC
- // disable boost::lexical_cast warning
- #pragma warning (disable:4702)
- #endif
- static LLAppViewerListener sAppViewerListener(LLAppViewer::instance);
- ////// Windows-specific includes to the bottom - nasty defines in these pollute the preprocessor
- //
- //----------------------------------------------------------------------------
- // viewer.cpp - these are only used in viewer, should be easily moved.
- #if LL_DARWIN
- extern void init_apple_menu(const char* product);
- #endif // LL_DARWIN
- extern BOOL gRandomizeFramerate;
- extern BOOL gPeriodicSlowFrame;
- extern BOOL gDebugGL;
- ////////////////////////////////////////////////////////////
- // All from the last globals push...
- F32 gSimLastTime; // Used in LLAppViewer::init and send_stats()
- F32 gSimFrames;
- BOOL gShowObjectUpdates = FALSE;
- BOOL gUseQuickTime = TRUE;
- eLastExecEvent gLastExecEvent = LAST_EXEC_NORMAL;
- LLSD gDebugInfo;
- U32 gFrameCount = 0;
- U32 gForegroundFrameCount = 0; // number of frames that app window was in foreground
- LLPumpIO* gServicePump = NULL;
- U64 gFrameTime = 0;
- F32 gFrameTimeSeconds = 0.f;
- F32 gFrameIntervalSeconds = 0.f;
- F32 gFPSClamped = 10.f; // Pretend we start at target rate.
- F32 gFrameDTClamped = 0.f; // Time between adjacent checks to network for packets
- U64 gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds
- U32 gFrameStalls = 0;
- const F64 FRAME_STALL_THRESHOLD = 1.0;
- LLTimer gRenderStartTime;
- LLFrameTimer gForegroundTime;
- LLFrameTimer gLoggedInTime;
- LLTimer gLogoutTimer;
- static const F32 LOGOUT_REQUEST_TIME = 6.f; // this will be cut short by the LogoutReply msg.
- F32 gLogoutMaxTime = LOGOUT_REQUEST_TIME;
- BOOL gDisconnected = FALSE;
- // used to restore texture state after a mode switch
- LLFrameTimer gRestoreGLTimer;
- BOOL gRestoreGL = FALSE;
- BOOL gUseWireframe = FALSE;
- // VFS globals - see llappviewer.h
- LLVFS* gStaticVFS = NULL;
- LLMemoryInfo gSysMemory;
- U64 gMemoryAllocated = 0; // updated in display_stats() in llviewerdisplay.cpp
- std::string gLastVersionChannel;
- LLVector3 gWindVec(3.0, 3.0, 0.0);
- LLVector3 gRelativeWindVec(0.0, 0.0, 0.0);
- U32 gPacketsIn = 0;
- BOOL gPrintMessagesThisFrame = FALSE;
- BOOL gRandomizeFramerate = FALSE;
- BOOL gPeriodicSlowFrame = FALSE;
- BOOL gCrashOnStartup = FALSE;
- BOOL gLLErrorActivated = FALSE;
- BOOL gLogoutInProgress = FALSE;
- ////////////////////////////////////////////////////////////
- // Internal globals... that should be removed.
- static std::string gArgs;
- const std::string MARKER_FILE_NAME("SecondLife.exec_marker");
- const std::string ERROR_MARKER_FILE_NAME("SecondLife.error_marker");
- const std::string LLERROR_MARKER_FILE_NAME("SecondLife.llerror_marker");
- const std::string LOGOUT_MARKER_FILE_NAME("SecondLife.logout_marker");
- static BOOL gDoDisconnect = FALSE;
- static std::string gLaunchFileOnQuit;
- // Used on Win32 for other apps to identify our window (eg, win_setup)
- const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
- //-- LLDeferredTaskList ------------------------------------------------------
- /**
- * A list of deferred tasks.
- *
- * We sometimes need to defer execution of some code until the viewer gets idle,
- * e.g. removing an inventory item from within notifyObservers() may not work out.
- *
- * Tasks added to this list will be executed in the next LLAppViewer::idle() iteration.
- * All tasks are executed only once.
- */
- class LLDeferredTaskList: public LLSingleton<LLDeferredTaskList>
- {
- LOG_CLASS(LLDeferredTaskList);
- friend class LLAppViewer;
- typedef boost::signals2::signal<void()> signal_t;
- void addTask(const signal_t::slot_type& cb)
- {
- mSignal.connect(cb);
- }
- void run()
- {
- if (!mSignal.empty())
- {
- mSignal();
- mSignal.disconnect_all_slots();
- }
- }
- signal_t mSignal;
- };
- //----------------------------------------------------------------------------
- // List of entries from strings.xml to always replace
- static std::set<std::string> default_trans_args;
- void init_default_trans_args()
- {
- default_trans_args.insert("SECOND_LIFE"); // World
- default_trans_args.insert("APP_NAME");
- default_trans_args.insert("CAPITALIZED_APP_NAME");
- default_trans_args.insert("SECOND_LIFE_GRID");
- default_trans_args.insert("SUPPORT_SITE");
- }
- //----------------------------------------------------------------------------
- // File scope definitons
- const char *VFS_DATA_FILE_BASE = "data.db2.x.";
- const char *VFS_INDEX_FILE_BASE = "index.db2.x.";
- struct SettingsFile : public LLInitParam::Block<SettingsFile>
- {
- Mandatory<std::string> name;
- Optional<std::string> file_name;
- Optional<bool> required,
- persistent;
- Optional<std::string> file_name_setting;
- SettingsFile()
- : name("name"),
- file_name("file_name"),
- required("required", false),
- persistent("persistent", true),
- file_name_setting("file_name_setting")
- {}
- };
- struct SettingsGroup : public LLInitParam::Block<SettingsGroup>
- {
- Mandatory<std::string> name;
- Mandatory<S32> path_index;
- Multiple<SettingsFile> files;
- SettingsGroup()
- : name("name"),
- path_index("path_index"),
- files("file")
- {}
- };
- struct SettingsFiles : public LLInitParam::Block<SettingsFiles>
- {
- Multiple<SettingsGroup> groups;
- SettingsFiles()
- : groups("group")
- {}
- };
- static std::string gWindowTitle;
- LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ;
- //----------------------------------------------------------------------------
- // Metrics logging control constants
- //----------------------------------------------------------------------------
- static const F32 METRICS_INTERVAL_DEFAULT = 600.0;
- static const F32 METRICS_INTERVAL_QA = 30.0;
- static F32 app_metrics_interval = METRICS_INTERVAL_DEFAULT;
- static bool app_metrics_qa_mode = false;
- void idle_afk_check()
- {
- // check idle timers
- F32 current_idle = gAwayTriggerTimer.getElapsedTimeF32();
- F32 afk_timeout = gSavedSettings.getS32("AFKTimeout");
- if (afk_timeout && (current_idle > afk_timeout) && ! gAgent.getAFK())
- {
- LL_INFOS("IdleAway") << "Idle more than " << afk_timeout << " seconds: automatically changing to Away status" << LL_ENDL;
- gAgent.setAFK();
- }
- }
- // A callback set in LLAppViewer::init()
- static void ui_audio_callback(const LLUUID& uuid)
- {
- if (gAudiop)
- {
- gAudiop->triggerSound(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI);
- }
- }
- bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base)
- {
- if(!match || !base || base->getPlainText())
- return false;
- LLUUID match_id = match->getID();
- LLIconCtrl* icon;
- if(gAgent.isInGroup(match_id, TRUE))
- {
- LLGroupIconCtrl::Params icon_params;
- icon_params.group_id = match_id;
- icon_params.rect = LLRect(0, 16, 16, 0);
- icon_params.visible = true;
- icon = LLUICtrlFactory::instance().create<LLGroupIconCtrl>(icon_params);
- }
- else
- {
- LLAvatarIconCtrl::Params icon_params;
- icon_params.avatar_id = match_id;
- icon_params.rect = LLRect(0, 16, 16, 0);
- icon_params.visible = true;
- icon = LLUICtrlFactory::instance().create<LLAvatarIconCtrl>(icon_params);
- }
- LLInlineViewSegment::Params params;
- params.force_newline = false;
- params.view = icon;
- params.left_pad = 4;
- params.right_pad = 4;
- params.top_pad = -2;
- params.bottom_pad = 2;
- base->appendWidget(params," ",false);
-
- return true;
- }
- void request_initial_instant_messages()
- {
- static BOOL requested = FALSE;
- if (!requested
- && gMessageSystem
- && LLMuteList::getInstance()->isLoaded()
- && isAgentAvatarValid())
- {
- // Auto-accepted inventory items may require the avatar object
- // to build a correct name. Likewise, inventory offers from
- // muted avatars require the mute list to properly mute.
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_RetrieveInstantMessages);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gAgent.sendReliableMessage();
- requested = TRUE;
- }
- }
- // Use these strictly for things that are constructed at startup,
- // or for things that are performance critical. JC
- static void settings_to_globals()
- {
- LLBUTTON_H_PAD = gSavedSettings.getS32("ButtonHPad");
- BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall");
- BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight");
- MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight");
- MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth");
- LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
-
- LLRender::sGLCoreProfile = gSavedSettings.getBOOL("RenderGLCoreProfile");
- LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic");
- LLVOVolume::sLODFactor = gSavedSettings.getF32("RenderVolumeLODFactor");
- LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f;
- LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor");
- LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor");
- LLVOAvatar::sLODFactor = gSavedSettings.getF32("RenderAvatarLODFactor");
- LLVOAvatar::sPhysicsLODFactor = gSavedSettings.getF32("RenderAvatarPhysicsLODFactor");
- LLVOAvatar::sMaxVisible = (U32)gSavedSettings.getS32("RenderAvatarMaxVisible");
- LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible");
- // clamp auto-open time to some minimum usable value
- LLFolderView::sAutoOpenTime = llmax(0.25f, gSavedSettings.getF32("FolderAutoOpenDelay"));
- LLSelectMgr::sRectSelectInclusive = gSavedSettings.getBOOL("RectangleSelectInclusive");
- LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections");
- LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius");
- gAgentPilot.setNumRuns(gSavedSettings.getS32("StatsNumRuns"));
- gAgentPilot.setQuitAfterRuns(gSavedSettings.getBOOL("StatsQuitAfterRuns"));
- gAgent.setHideGroupTitle(gSavedSettings.getBOOL("RenderHideGroupTitle"));
- gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc");
- gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates");
- LLWorldMapView::sMapScale = gSavedSettings.getF32("MapScale");
- }
- static void settings_modify()
- {
- LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderDeferred");
- LLPipeline::sRenderDeferred = gSavedSettings.getBOOL("RenderDeferred");
- LLVOAvatar::sUseImpostors = gSavedSettings.getBOOL("RenderUseImpostors");
- LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor");
- LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4]
- gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession;
- gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
- gAuditTexture = gSavedSettings.getBOOL("AuditTexture");
- }
- class LLFastTimerLogThread : public LLThread
- {
- public:
- std::string mFile;
- LLFastTimerLogThread(std::string& test_name) : LLThread("fast timer log")
- {
- std::string file_name = test_name + std::string(".slp");
- mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name);
- }
- void run()
- {
- std::ofstream os(mFile.c_str());
-
- while (!LLAppViewer::instance()->isQuitting())
- {
- LLFastTimer::writeLog(os);
- os.flush();
- ms_sleep(32);
- }
- os.close();
- }
- };
- //virtual
- bool LLAppViewer::initSLURLHandler()
- {
- // does nothing unless subclassed
- return false;
- }
- //virtual
- bool LLAppViewer::sendURLToOtherInstance(const std::string& url)
- {
- // does nothing unless subclassed
- return false;
- }
- //----------------------------------------------------------------------------
- // LLAppViewer definition
- // Static members.
- // The single viewer app.
- LLAppViewer* LLAppViewer::sInstance = NULL;
- LLTextureCache* LLAppViewer::sTextureCache = NULL;
- LLImageDecodeThread* LLAppViewer::sImageDecodeThread = NULL;
- LLTextureFetch* LLAppViewer::sTextureFetch = NULL;
- LLAppViewer::LLAppViewer() :
- mMarkerFile(),
- mLogoutMarkerFile(NULL),
- mReportedCrash(false),
- mNumSessions(0),
- mPurgeCache(false),
- mPurgeOnExit(false),
- mSecondInstance(false),
- mSavedFinalSnapshot(false),
- mForceGraphicsDetail(false),
- mQuitRequested(false),
- mLogoutRequestSent(false),
- mYieldTime(-1),
- mMainloopTimeout(NULL),
- mAgentRegionLastAlive(false),
- mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", FALSE)),
- mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)),
- mFastTimerLogThread(NULL),
- mUpdater(new LLUpdaterService()),
- mSettingsLocationList(NULL)
- {
- if(NULL != sInstance)
- {
- llerrs << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << llendl;
- }
- setupErrorHandling();
- sInstance = this;
- gLoggedInTime.stop();
-
- LLLoginInstance::instance().setUpdaterService(mUpdater.get());
- }
- LLAppViewer::~LLAppViewer()
- {
- delete mSettingsLocationList;
- LLLoginInstance::instance().setUpdaterService(0);
-
- destroyMainloopTimeout();
- // If we got to this destructor somehow, the app didn't hang.
- removeMarkerFile();
- }
- bool LLAppViewer::init()
- {
- //
- // Start of the application
- //
- // IMPORTANT! Do NOT put anything that will write
- // into the log files during normal startup until AFTER
- // we run the "program crashed last time" error handler below.
- //
- LLFastTimer::reset();
- // initialize SSE options
- LLVector4a::initClass();
- // Need to do this initialization before we do anything else, since anything
- // that touches files should really go through the lldir API
- gDirUtilp->initAppDirs("SecondLife");
- // set skin search path to default, will be overridden later
- // this allows simple skinned file lookups to work
- gDirUtilp->setSkinFolder("default");
- initLogging();
-
- //
- // OK to write stuff to logs now, we've now crash reported if necessary
- //
-
- init_default_trans_args();
-
- if (!initConfiguration())
- return false;
- LL_INFOS("InitInfo") << "Configuration initialized." << LL_ENDL ;
- //set the max heap size.
- initMaxHeapSize() ;
- LLPrivateMemoryPoolManager::initClass((BOOL)gSavedSettings.getBOOL("MemoryPrivatePoolEnabled"), (U32)gSavedSettings.getU32("MemoryPrivatePoolSize")) ;
- // write Google Breakpad minidump files to our log directory
- std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
- logdir += gDirUtilp->getDirDelimiter();
- setMiniDumpDir(logdir);
- // Although initLogging() is the right place to mess with
- // setFatalFunction(), we can't query gSavedSettings until after
- // initConfiguration().
- S32 rc(gSavedSettings.getS32("QAModeTermCode"));
- if (rc >= 0)
- {
- // QAModeTermCode set, terminate with that rc on LL_ERRS. Use _exit()
- // rather than exit() because normal cleanup depends too much on
- // successful startup!
- LLError::setFatalFunction(boost::bind(_exit, rc));
- }
- mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
- #if LL_RECORD_VIEWER_STATS
- LLViewerStatsRecorder::initClass();
- #endif
- // *NOTE:Mani - LLCurl::initClass is not thread safe.
- // Called before threads are created.
- LLCurl::initClass(gSavedSettings.getF32("CurlRequestTimeOut"),
- gSavedSettings.getS32("CurlMaximumNumberOfHandles"),
- gSavedSettings.getBOOL("CurlUseMultipleThreads"));
- LL_INFOS("InitInfo") << "LLCurl initialized." << LL_ENDL ;
- LLMachineID::init();
-
- {
- // Viewer metrics initialization
- static LLCachedControl<bool> metrics_submode(gSavedSettings,
- "QAModeMetrics",
- false,
- "Enables QA features (logging, faster cycling) for metrics collector");
- if (metrics_submode)
- {
- app_metrics_qa_mode = true;
- app_metrics_interval = METRICS_INTERVAL_QA;
- }
- LLViewerAssetStatsFF::init();
- }
- initThreads();
- LL_INFOS("InitInfo") << "Threads initialized." << LL_ENDL ;
- // Initialize settings early so that the defaults for ignorable dialogs are
- // picked up and then correctly re-saved after launching the updater (STORM-1268).
- LLUI::settings_map_t settings_map;
- settings_map["config"] = &gSavedSettings;
- settings_map["ignores"] = &gWarningSettings;
- settings_map["floater"] = &gSavedSettings; // *TODO: New settings file
- settings_map["account"] = &gSavedPerAccountSettings;
- LLUI::initClass(settings_map,
- LLUIImageList::getInstance(),
- ui_audio_callback,
- &LLUI::sGLScaleFactor);
- LL_INFOS("InitInfo") << "UI initialized." << LL_ENDL ;
- // Setup paths and LLTrans after LLUI::initClass has been called.
- LLUI::setupPaths();
- LLTransUtil::parseStrings("strings.xml", default_trans_args);
- LLTransUtil::parseLanguageStrings("language_settings.xml");
- // Setup notifications after LLUI::setupPaths() has been called.
- LLNotifications::instance();
- LL_INFOS("InitInfo") << "Notifications initialized." << LL_ENDL ;
- writeSystemInfo();
- // Initialize updater service (now that we have an io pump)
- initUpdater();
- if(isQuitting())
- {
- // Early out here because updater set the quitting flag.
- return true;
- }
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- // *FIX: The following code isn't grouped into functions yet.
- // Statistics / debug timer initialization
- init_statistics();
-
- //
- // Various introspection concerning the libs we're using - particularly
- // the libs involved in getting to a full login screen.
- //
- LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL;
- LL_INFOS("InitInfo") << "libcurl version is: " << LLCurl::getVersionString() << LL_ENDL;
- /////////////////////////////////////////////////
- // OS-specific login dialogs
- /////////////////////////////////////////////////
- //test_cached_control();
- // track number of times that app has run
- mNumSessions = gSavedSettings.getS32("NumSessions");
- mNumSessions++;
- gSavedSettings.setS32("NumSessions", mNumSessions);
- if (gSavedSettings.getBOOL("VerboseLogs"))
- {
- LLError::setPrintLocation(true);
- }
- // LLKeyboard relies on LLUI to know what some accelerator keys are called.
- LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString );
- LLWeb::initClass(); // do this after LLUI
-
- // Provide the text fields with callbacks for opening Urls
- LLUrlAction::setOpenURLCallback(boost::bind(&LLWeb::loadURL, _1, LLStringUtil::null, LLStringUtil::null));
- LLUrlAction::setOpenURLInternalCallback(boost::bind(&LLWeb::loadURLInternal, _1, LLStringUtil::null, LLStringUtil::null));
- LLUrlAction::setOpenURLExternalCallback(boost::bind(&LLWeb::loadURLExternal, _1, true, LLStringUtil::null));
- LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor);
- // Let code in llui access the viewer help floater
- LLUI::sHelpImpl = LLViewerHelp::getInstance();
- LL_INFOS("InitInfo") << "UI initialization is done." << LL_ENDL ;
- // Load translations for tooltips
- LLFloater::initClass();
- /////////////////////////////////////////////////
-
- LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated
-
- LLViewerFloaterReg::registerFloaters();
-
- /////////////////////////////////////////////////
- //
- // Load settings files
- //
- //
- LLGroupMgr::parseRoleActions("role_actions.xml");
- LLAgent::parseTeleportMessages("teleport_strings.xml");
- // load MIME type -> media impl mappings
- std::string mime_types_name;
- #if LL_DARWIN
- mime_types_name = "mime_types_mac.xml";
- #elif LL_LINUX
- mime_types_name = "mime_types_linux.xml";
- #else
- mime_types_name = "mime_types.xml";
- #endif
- LLMIMETypes::parseMIMETypes( mime_types_name );
- // Copy settings to globals. *TODO: Remove or move to appropriage class initializers
- settings_to_globals();
- // Setup settings listeners
- settings_setup_listeners();
- // Modify settings based on system configuration and compile options
- settings_modify();
- // Find partition serial number (Windows) or hardware serial (Mac)
- mSerialNumber = generateSerialNumber();
- // do any necessary set-up for accepting incoming SLURLs from apps
- initSLURLHandler();
- if(false == initHardwareTest())
- {
- // Early out from user choice.
- return false;
- }
- LL_INFOS("InitInfo") << "Hardware test initialization done." << LL_ENDL ;
- // Prepare for out-of-memory situations, during which we will crash on
- // purpose and save a dump.
- #if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
- MemSetErrorHandler(first_mem_error_handler);
- #endif // LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
- // *Note: this is where gViewerStats used to be created.
- //
- // Initialize the VFS, and gracefully handle initialization errors
- //
- if (!initCache())
- {
- std::ostringstream msg;
- msg << LLTrans::getString("MBUnableToAccessFile");
- OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
- return 1;
- }
- LL_INFOS("InitInfo") << "Cache initialization is done." << LL_ENDL ;
- // Initialize the repeater service.
- LLMainLoopRepeater::instance().start();
- //
- // Initialize the window
- //
- gGLActive = TRUE;
- initWindow();
- LL_INFOS("InitInfo") << "Window is initialized." << LL_ENDL ;
- // initWindow also initializes the Feature List, so now we can initialize this global.
- LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap");
- // call all self-registered classes
- LLInitClassList::instance().fireCallbacks();
- LLFolderViewItem::initClass(); // SJB: Needs to happen after initWindow(), not sure why but related to fonts
-
- gGLManager.getGLInfo(gDebugInfo);
- gGLManager.printGLInfoString();
- // Load Default bindings
- std::string key_bindings_file = gDirUtilp->findFile("keys.xml",
- gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
- gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
- if (!gViewerKeyboard.loadBindingsXML(key_bindings_file))
- {
- std::string key_bindings_file = gDirUtilp->findFile("keys.ini",
- gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
- gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
- if (!gViewerKeyboard.loadBindings(key_bindings_file))
- {
- LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL;
- }
- }
- // If we don't have the right GL requirements, exit.
- if (!gGLManager.mHasRequirements)
- {
- // can't use an alert here since we're exiting and
- // all hell breaks lose.
- OSMessageBox(
- LLNotifications::instance().getGlobalString("UnsupportedGLRequirements"),
- LLStringUtil::null,
- OSMB_OK);
- return 0;
- }
- // Without SSE2 support we will crash almost immediately, warn here.
- if (!gSysCPU.hasSSE2())
- {
- // can't use an alert here since we're exiting and
- // all hell breaks lose.
- OSMessageBox(
- LLNotifications::instance().getGlobalString("UnsupportedCPUSSE2"),
- LLStringUtil::null,
- OSMB_OK);
- return 0;
- }
- // alert the user if they are using unsupported hardware
- if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware"))
- {
- bool unsupported = false;
- LLSD args;
- std::string minSpecs;
-
- // get cpu data from xml
- std::stringstream minCPUString(LLNotifications::instance().getGlobalString("UnsupportedCPUAmount"));
- S32 minCPU = 0;
- minCPUString >> minCPU;
- // get RAM data from XML
- std::stringstream minRAMString(LLNotifications::instance().getGlobalString("UnsupportedRAMAmount"));
- U64 minRAM = 0;
- minRAMString >> minRAM;
- minRAM = minRAM * 1024 * 1024;
- if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN)
- {
- minSpecs += LLNotifications::instance().getGlobalString("UnsupportedGPU");
- minSpecs += "\n";
- unsupported = true;
- }
- if(gSysCPU.getMHz() < minCPU)
- {
- minSpecs += LLNotifications::instance().getGlobalString("UnsupportedCPU");
- minSpecs += "\n";
- unsupported = true;
- }
- if(gSysMemory.getPhysicalMemoryClamped() < minRAM)
- {
- minSpecs += LLNotifications::instance().getGlobalString("UnsupportedRAM");
- minSpecs += "\n";
- unsupported = true;
- }
- if (LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_UNKNOWN)
- {
- LLNotificationsUtil::add("UnknownGPU");
- }
-
- if(unsupported)
- {
- if(!gSavedSettings.controlExists("WarnUnsupportedHardware")
- || gSavedSettings.getBOOL("WarnUnsupportedHardware"))
- {
- args["MINSPECS"] = minSpecs;
- LLNotificationsUtil::add("UnsupportedHardware", args );
- }
- }
- }
- // save the graphics card
- gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString();
- // Save the current version to the prefs file
- gSavedSettings.setString("LastRunVersion",
- LLVersionInfo::getChannelAndVersion());
- gSimLastTime = gRenderStartTime.getElapsedTimeF32();
- gSimFrames = (F32)gFrameCount;
- LLViewerJoystick::getInstance()->init(false);
- try {
- initializeSecHandler();
- }
- catch (LLProtectedDataException ex)
- {
- LLNotificationsUtil::add("CorruptedProtectedDataStore");
- }
- LLHTTPClient::setCertVerifyCallback(secapiSSLCertVerifyCallback);
- gGLActive = FALSE;
- if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getS32("QAModeEventHostPort") > 0)
- {
- loadEventHostModule(gSavedSettings.getS32("QAModeEventHostPort"));
- }
-
- LLViewerMedia::initClass();
- LL_INFOS("InitInfo") << "Viewer media initialized." << LL_ENDL ;
- LLTextUtil::TextHelpers::iconCallbackCreationFunction = create_text_segment_icon_from_url_match;
- //EXT-7013 - On windows for some locale (Japanese) standard
- //datetime formatting functions didn't support some parameters such as "weekday".
- //Names for days and months localized in xml are also useful for Polish locale(STORM-107).
- std::string language = gSavedSettings.getString("Language");
- if(language == "ja" || language == "pl")
- {
- LLStringOps::setupWeekDaysNames(LLTrans::getString("dateTimeWeekdaysNames"));
- LLStringOps::setupWeekDaysShortNames(LLTrans::getString("dateTimeWeekdaysShortNames"));
- LLStringOps::setupMonthNames(LLTrans::getString("dateTimeMonthNames"));
- LLStringOps::setupMonthShortNames(LLTrans::getString("dateTimeMonthShortNames"));
- LLStringOps::setupDayFormat(LLTrans::getString("dateTimeDayFormat"));
- LLStringOps::sAM = LLTrans::getString("dateTimeAM");
- LLStringOps::sPM = LLTrans::getString("dateTimePM");
- }
- LLAgentLanguage::init();
- return true;
- }
- void LLAppViewer::initMaxHeapSize()
- {
- //set the max heap size.
- //here is some info regarding to the max heap size:
- //------------------------------------------------------------------------------------------
- // OS | setting | SL address bits | max manageable memory space | max heap size
- // Win 32 | default | 32-bit | 2GB | < 1.7GB
- // Win 32 | /3G | 32-bit | 3GB | < 1.7GB or 2.7GB
- //Linux 32 | default | 32-bit | 3GB | < 2.7GB
- //Linux 32 |HUGEMEM | 32-bit | 4GB | < 3.7GB
- //64-bit OS |default | 32-bit | 4GB | < 3.7GB
- //64-bit OS |default | 64-bit | N/A (> 4GB) | N/A (> 4GB)
- //------------------------------------------------------------------------------------------
- //currently SL is built under 32-bit setting, we set its max heap size no more than 1.6 GB.
- //F32 max_heap_size_gb = llmin(1.6f, (F32)gSavedSettings.getF32("MaxHeapSize")) ;
- F32 max_heap_size_gb = gSavedSettings.getF32("MaxHeapSize") ;
- BOOL enable_mem_failure_prevention = (BOOL)gSavedSettings.getBOOL("MemoryFailurePreventionEnabled") ;
- LLMemory::initMaxHeapSizeGB(max_heap_size_gb, enable_mem_failure_prevention) ;
- }
- void LLAppViewer::checkMemory()
- {
- const static F32 MEMORY_CHECK_INTERVAL = 1.0f ; //second
- //const static F32 MAX_QUIT_WAIT_TIME = 30.0f ; //seconds
- //static F32 force_quit_timer = MAX_QUIT_WAIT_TIME + MEMORY_CHECK_INTERVAL ;
- if(!gGLManager.mDebugGPU)
- {
- return ;
- }
- if(MEMORY_CHECK_INTERVAL > mMemCheckTimer.getElapsedTimeF32())
- {
- return ;
- }
- mMemCheckTimer.reset() ;
- //update the availability of memory
- LLMemory::updateMemoryInfo() ;
- bool is_low = LLMemory::isMemoryPoolLow() ;
- LLPipeline::throttleNewMemoryAllocation(is_low) ;
-
- if(is_low)
- {
- LLMemory::logMemoryInfo() ;
- }
- }
- static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages");
- static LLFastTimer::DeclareTimer FTM_SLEEP("Sleep");
- static LLFastTimer::DeclareTimer FTM_TEXTURE_CACHE("Texture Cache");
- static LLFastTimer::DeclareTimer FTM_DECODE("Image Decode");
- static LLFastTimer::DeclareTimer FTM_VFS("VFS Thread");
- static LLFastTimer::DeclareTimer FTM_LFS("LFS Thread");
- static LLFastTimer::DeclareTimer FTM_PAUSE_THREADS("Pause Threads");
- static LLFastTimer::DeclareTimer FTM_IDLE("Idle");
- static LLFastTimer::DeclareTimer FTM_PUMP("Pump");
- static LLFastTimer::DeclareTimer FTM_PUMP_ARES("Ares");
- static LLFastTimer::DeclareTimer FTM_PUMP_SERVICE("Service");
- static LLFastTimer::DeclareTimer FTM_SERVICE_CALLBACK("Callback");
- static LLFastTimer::DeclareTimer FTM_AGENT_AUTOPILOT("Autopilot");
- static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE("Update");
- bool LLAppViewer::mainLoop()
- {
- LLMemType mt1(LLMemType::MTYPE_MAIN);
- mMainloopTimeout = new LLWatchdogTimeout();
-
- //-------------------------------------------
- // Run main loop until time to quit
- //-------------------------------------------
- // Create IO Pump to use for HTTP Requests.
- gServicePump = new LLPumpIO(gAPRPoolp);
- LLHTTPClient::setPump(*gServicePump);
- LLCurl::setCAFile(gDirUtilp->getCAFile());
- // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
- LLVoiceChannel::initClass();
- LLVoiceClient::getInstance()->init(gServicePump);
- LLVoiceChannel::setCurrentVoiceChannelChangedCallback(boost::bind(&LLCallFloater::sOnCurrentChannelChanged, _1), true);
- LLTimer frameTimer,idleTimer;
- LLTimer debugTime;
- LLViewerJoystick* joystick(LLViewerJoystick::getInstance());
- joystick->setNeedsReset(true);
- LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
- // As we do not (yet) send data on the mainloop LLEventPump that varies
- // with each frame, no need to instantiate a new LLSD event object each
- // time. Obviously, if that changes, just instantiate the LLSD at the
- // point of posting.
- LLSD newFrame;
- //LLPrivateMemoryPoolTester::getInstance()->run(false) ;
- //LLPrivateMemoryPoolTester::getInstance()->run(true) ;
- //LLPrivateMemoryPoolTester::destroy() ;
- // Handle messages
- while (!LLApp::isExiting())
- {
- LLFastTimer::nextFrame(); // Should be outside of any timer instances
- //clear call stack records
- llclearcallstacks;
- //check memory availability information
- checkMemory() ;
-
- try
- {
- pingMainloopTimeout("Main:MiscNativeWindowEvents");
- if (gViewerWindow)
- {
- LLFastTimer t2(FTM_MESSAGES);
- gViewerWindow->getWindow()->processMiscNativeEvents();
- }
-
- pingMainloopTimeout("Main:GatherInput");
-
- if (gViewerWindow)
- {
- LLFastTimer t2(FTM_MESSAGES);
- if (!restoreErrorTrap())
- {
- llwarns << " Someone took over my signal/exception handler (post messagehandling)!" << llendl;
- }
- gViewerWindow->getWindow()->gatherInput();
- }
- #if 1 && !LL_RELEASE_FOR_DOWNLOAD
- // once per second debug info
- if (debugTime.getElapsedTimeF32() > 1.f)
- {
- debugTime.reset();
- }
-
- #endif
- //memory leaking simulation
- LLFloaterMemLeak* mem_leak_instance =
- LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
- if(mem_leak_instance)
- {
- mem_leak_instance->idle() ;
- }
- // canonical per-frame event
- mainloop.post(newFrame);
- if (!LLApp::isExiting())
- {
- pingMainloopTimeout("Main:JoystickKeyboard");
-
- // Scan keyboard for movement keys. Command keys and typing
- // are handled by windows callbacks. Don't do this until we're
- // done initializing. JC
- if ((gHeadlessClient || gViewerWindow->getWindow()->getVisible())
- && gViewerWindow->getActive()
- && !gViewerWindow->getWindow()->getMinimized()
- && LLStartUp::getStartupState() == STATE_STARTED
- && (gHeadlessClient || !gViewerWindow->getShowProgress())
- && !gFocusMgr.focusLocked())
- {
- LLMemType mjk(LLMemType::MTYPE_JOY_KEY);
- joystick->scanJoystick();
- gKeyboard->scanKeyboard();
- }
- // Update state based on messages, user input, object idle.
- {
- pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
-
- LLFastTimer t3(FTM_IDLE);
- idle();
- if (gAres != NULL && gAres->isInitialized())
- {
- LLMemType mt_ip(LLMemType::MTYPE_IDLE_PUMP);
- pingMainloopTimeout("Main:ServicePump");
- LLFastTimer t4(FTM_PUMP);
- {
- LLFastTimer t(FTM_PUMP_ARES);
- gAres->process();
- }
- {
- LLFastTimer t(FTM_PUMP_SERVICE);
- // this pump is necessary to make the login screen show up
- gServicePump->pump();
- {
- LLFastTimer t(FTM_SERVICE_CALLBACK);
- gServicePump->callback();
- }
- }
- }
-
- resumeMainloopTimeout();
- }
-
- if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
- {
- pauseMainloopTimeout();
- saveFinalSnapshot();
- disconnectViewer();
- resumeMainloopTimeout();
- }
- // Render scene.
- // *TODO: Should we run display() even during gHeadlessClient? DK 2011-02-18
- if (!LLApp::isExiting() && !gHeadlessClient)
- {
- pingMainloopTimeout("Main:Display");
- gGLActive = TRUE;
- display();
- pingMainloopTimeout("Main:Snapshot");
- LLFloaterSnapshot::update(); // take snapshots
- gGLActive = FALSE;
- }
- }
- pingMainloopTimeout("Main:Sleep");
-
- pauseMainloopTimeout();
- // Sleep and run background threads
- {
- LLMemType mt_sleep(LLMemType::MTYPE_SLEEP);
- LLFastTimer t2(FTM_SLEEP);
-
- // yield some time to the os based on command line option
- if(mYieldTime >= 0)
- {
- ms_sleep(mYieldTime);
- }
- // yield cooperatively when not running as foreground window
- if ( (gViewerWindow && !gViewerWindow->getWindow()->getVisible())
- || !gFocusMgr.getAppHasFocus())
- {
- // Sleep if we're not rendering, or the window is minimized.
- S32 milliseconds_to_sleep = llclamp(gSavedSettings.getS32("BackgroundYieldTime"), 0, 1000);
- // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads
- // of equal priority on Windows
- if (milliseconds_to_sleep > 0)
- {
- ms_sleep(milliseconds_to_sleep);
- // also pause worker threads during this wait period
- LLAppViewer::getTextureCache()->pause();
- LLAppViewer::getImageDecodeThread()->pause();
- }
- }
-
- if (mRandomizeFramerate)
- {
- ms_sleep(rand() % 200);
- }
- if (mPeriodicSlowFrame
- && (gFrameCount % 10 == 0))
- {
- llinfos << "Periodic slow frame - sleeping 500 ms" << llendl;
- ms_sleep(500);
- }
- static const F64 FRAME_SLOW_THRESHOLD = 0.5; //2 frames per seconds
- const F64 max_idle_time = llmin(.005*10.0*gFrameTimeSeconds, 0.005); // 5 ms a second
- idleTimer.reset();
- bool is_slow = (frameTimer.getElapsedTimeF64() > FRAME_SLOW_THRESHOLD) ;
- S32 total_work_pending = 0;
- S32 total_io_pending = 0;
- while(!is_slow)//do not unpause threads if the frame rates are very low.
- {
- S32 work_pending = 0;
- S32 io_pending = 0;
- F32 max_time = llmin(gFrameIntervalSeconds*10.f, 1.f);
- {
- LLFastTimer ftm(FTM_TEXTURE_CACHE);
- work_pending += LLAppViewer::getTextureCache()->update(max_time); // unpauses the texture cache thread
- }
- {
- LLFastTimer ftm(FTM_DECODE);
- work_pending += LLAppViewer::getImageDecodeThread()->update(max_time); // unpauses the image thread
- }
- {
- LLFastTimer ftm(FTM_DECODE);
- work_pending += LLAppViewer::getTextureFetch()->update(max_time); // unpauses the texture fetch thread
- }
- {
- LLFastTimer ftm(FTM_VFS);
- io_pending += LLVFSThread::updateClass(1);
- }
- {
- LLFastTimer ftm(FTM_LFS);
- io_pending += LLLFSThread::updateClass(1);
- }
- if (io_pending > 1000)
- {
- ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up
- }
- total_work_pending += work_pending ;
- total_io_pending += io_pending ;
-
- if (!work_pending || idleTimer.getElapsedTimeF64() >= max_idle_time)
- {
- break;
- }
- }
- gMeshRepo.update() ;
-
- if(!LLCurl::getCurlThread()->update(1))
- {
- LLCurl::getCurlThread()->pause() ; //nothing in the curl thread.
- }
- if(!total_work_pending) //pause texture fetching threads if nothing to process.
- {
- LLAppViewer::getTextureCache()->pause();
- LLAppViewer::getImageDecodeThread()->pause();
- LLAppViewer::getTextureFetch()->pause();
- }
- if(!total_io_pending) //pause file threads if nothing to process.
- {
- LLVFSThread::sLocal->pause();
- LLLFSThread::sLocal->pause();
- }
- if ((LLStartUp::getStartupState() >= STATE_CLEANUP) &&
- (frameTimer.getElapsedTimeF64() > FRAME_STALL_THRESHOLD))
- {
- gFrameStalls++;
- }
- frameTimer.reset();
- resumeMainloopTimeout();
-
- pingMainloopTimeout("Main:End");
- }
- }
- catch(std::bad_alloc)
- {
- LLMemory::logMemoryInfo(TRUE) ;
- //stop memory leaking simulation
- LLFloaterMemLeak* mem_leak_instance =
- LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
- if(mem_leak_instance)
- {
- mem_leak_instance->stop() ;
- llwarns << "Bad memory allocation in LLAppViewer::mainLoop()!" << llendl ;
- }
- else
- {
- //output possible call stacks to log file.
- LLError::LLCallStacks::print() ;
- llerrs << "Bad memory allocation in LLAppViewer::mainLoop()!" << llendl ;
- }
- }
- }
- // Save snapshot for next time, if we made it through initialization
- if (STATE_STARTED == LLStartUp::getStartupState())
- {
- try
- {
- saveFinalSnapshot();
- }
- catch(std::bad_alloc)
- {
- llwarns << "Bad memory allocation when saveFinalSnapshot() is called!" << llendl ;
- //stop memory leaking simulation
- LLFloaterMemLeak* mem_leak_instance =
- LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
- if(mem_leak_instance)
- {
- mem_leak_instance->stop() ;
- }
- }
- }
-
- delete gServicePump;
- destroyMainloopTimeout();
- llinfos << "Exiting main_loop" << llendflush;
- return true;
- }
- void LLAppViewer::flushVFSIO()
- {
- while (1)
- {
- S32 pending = LLVFSThread::updateClass(0);
- pending += LLLFSThread::updateClass(0);
- if (!pending)
- {
- break;
- }
- llinfos << "Waiting for pending IO to finish: " << pending << llendflush;
- ms_sleep(100);
- }
- }
- bool LLAppViewer::cleanup()
- {
- // workaround for DEV-35406 crash on shutdown
- LLEventPumps::instance().reset();
- if (LLFastTimerView::sAnalyzePerformance)
- {
- llinfos << "Analyzing performance" << llendl;
- std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp";
- std::string current_name = LLFastTimer::sLogName + ".slp";
- std::string report_name = LLFastTimer::sLogName + "_report.csv";
- LLFastTimerView::doAnalysis(
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name),
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name),
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name));
- }
- LLMetricPerformanceTesterBasic::cleanClass();
- // remove any old breakpad minidump files from the log directory
- if (! isError())
- {
- std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
- logdir += gDirUtilp->getDirDelimiter();
- gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp");
- }
- // *TODO - generalize this and move DSO wrangling to a helper class -brad
- std::set<struct apr_dso_handle_t *>::const_iterator i;
- for(i = mPlugins.begin(); i != mPlugins.end(); ++i)
- {
- int (*ll_plugin_stop_func)(void) = NULL;
- apr_status_t rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_stop_func, *i, "ll_plugin_stop");
- ll_plugin_stop_func();
- rv = apr_dso_unload(*i);
- }
- mPlugins.clear();
- //flag all elements as needing to be destroyed immediately
- // to ensure shutdown order
- LLMortician::setZealous(TRUE);
- LLVoiceClient::getInstance()->terminate();
-
- disconnectViewer();
- llinfos << "Viewer disconnected" << llendflush;
- display_cleanup();
- release_start_screen(); // just in case
- LLError::logToFixedBuffer(NULL);
- llinfos << "Cleaning Up" << llendflush;
- // shut down mesh streamer
- gMeshRepo.shutdown();
- // Must clean up texture references before viewer window is destroyed.
- if(LLHUDManager::instanceExists())
- {
- LLHUDManager::getInstance()->updateEffects();
- LLHUDObject::updateAll();
- LLHUDManager::getInstance()->cleanupEffects();
- LLHUDObject::cleanupHUDObjects();
- llinfos << "HUD Objects cleaned up" << llendflush;
- }
- LLKeyframeDataCache::clear();
-
- // End TransferManager before deleting systems it depends on (Audio, VFS, AssetStorage)
- #if 0 // this seems to get us stuck in an infinite loop...
- gTransferManager.cleanup();
- #endif
-
- // Note: this is where gWorldMap used to be deleted.
- // Note: this is where gHUDManager used to be deleted.
- if(LLHUDManager::instanceExists())
- {
- LLHUDManager::getInstance()->shutdownClass();
- }
- delete gAssetStorage;
- gAssetStorage = NULL;
- LLPolyMesh::freeAllMeshes();
- LLStartUp::cleanupNameCache();
- // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted.
- LLWorldMap::getInstance()->reset(); // release any images
- LLCalc::cleanUp();
- llinfos << "Global stuff deleted" << llendflush;
- if (gAudiop)
- {
- // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem.
- LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl();
- delete sai;
- gAudiop->setStreamingAudioImpl(NULL);
- // shut down the audio subsystem
- bool want_longname = false;
- if (gAudiop->getDriverName(want_longname) == "FMOD")
- {
- // This hack exists because fmod likes to occasionally
- // crash or hang forever when shutting down, for no
- // apparent reason.
- llwarns << "Hack, skipping FMOD audio engine cleanup" << llendflush;
- }
- else
- {
- gAudiop->shutdown();
- }
- delete gAudiop;
- gAudiop = NULL;
- }
- // Note: this is where LLFeatureManager::getInstance()-> used to be deleted.
- // Patch up settings for next time
- // Must do this before we delete the viewer window,
- // such that we can suck rectangle information out of
- // it.
- cleanupSavedSettings();
- llinfos << "Settings patched up" << llendflush;
- // delete some of the files left around in the cache.
- removeCacheFiles("*.wav");
- removeCacheFiles("*.tmp");
- removeCacheFiles("*.lso");
- removeCacheFiles("*.out");
- removeCacheFiles("*.dsf");
- removeCacheFiles("*.bodypart");
- removeCacheFiles("*.clothing");
- llinfos << "Cache files removed" << llendflush;
- // Wait for any pending VFS IO
- flushVFSIO();
- llinfos << "Shutting down Views" << llendflush;
- // Destroy the UI
- if( gViewerWindow)
- gViewerWindow->shutdownViews();
- llinfos << "Cleaning up Inventory" << llendflush;
-
- // Cleanup Inventory after the UI since it will delete any remaining observers
- // (Deleted observers should have already removed themselves)
- gInventory.cleanupInventory();
- llinfos << "Cleaning up Selections" << llendflush;
-
- // Clean up selection managers after UI is destroyed, as UI may be observing them.
- // Clean up before GL is shut down because we might be holding on to objects with texture references
- LLSelectMgr::cleanupGlobals();
-
- llinfos << "Shutting down OpenGL" << llendflush;
- // Shut down OpenGL
- if( gViewerWindow)
- {
- gViewerWindow->shutdownGL();
-
- // Destroy window, and make sure we're not fullscreen
- // This may generate window reshape and activation events.
- // Therefore must do this before destroying the message system.
- delete gViewerWindow;
- gViewerWindow = NULL;
- llinfos << "ViewerWindow deleted" << llendflush;
- }
- llinfos << "Cleaning up Keyboard & Joystick" << llendflush;
-
- // viewer UI relies on keyboard so keep it aound until viewer UI isa gone
- delete gKeyboard;
- gKeyboard = NULL;
- // Turn off Space Navigator and similar devices
- LLViewerJoystick::getInstance()->terminate();
-
- llinfos << "Cleaning up Objects" << llendflush;
-
- LLViewerObject::cleanupVOClasses();
-
- LLPostProcess::cleanupClass();
- LLTracker::cleanupInstance();
-
- // *FIX: This is handled in LLAppViewerWin32::cleanup().
- // I'm keeping the comment to remember its order in cleanup,
- // in case of unforseen dependency.
- //#if LL_WINDOWS
- // gDXHardware.cleanup();
- //#endif // LL_WINDOWS
- LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager();
- if (!volume_manager->cleanup())
- {
- llwarns << "Remaining references in the volume manager!" << llendflush;
- }
- LLPrimitive::cleanupVolumeManager();
- llinfos << "Additional Cleanup..." << llendflush;
-
- LLViewerParcelMgr::cleanupGlobals();
- // *Note: this is where gViewerStats used to be deleted.
- //end_messaging_system();
- LLFollowCamMgr::cleanupClass();
- //LLVolumeMgr::cleanupClass();
- LLPrimitive::cleanupVolumeManager();
- LLWorldMapView::cleanupClass();
- LLFolderViewItem::cleanupClass();
- LLUI::cleanupClass();
-
- //
- // Shut down the VFS's AFTER the decode manager cleans up (since it cleans up vfiles).
- // Also after viewerwindow is deleted, since it may have image pointers (which have vfiles)
- // Also after shutting down the messaging system since it has VFS dependencies
- //
- llinfos << "Cleaning up VFS" << llendflush;
- LLVFile::cleanupClass();
- llinfos << "Saving Data" << llendflush;
-
- // Store the time of our current logoff
- gSavedPerAccountSettings.setU32("LastLogoff", time_corrected());
- // Must do this after all panels have been deleted because panels that have persistent rects
- // save their rects on delete.
- gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);
-
- LLUIColorTable::instance().saveUserSettings();
- // PerAccountSettingsFile should be empty if no user has been logged on.
- // *FIX:Mani This should get really saved in a "logoff" mode.
- if (gSavedSettings.getString("PerAccountSettingsFile").empty())
- {
- llinfos << "Not saving per-account settings; don't know the account name yet." << llendl;
- }
- else
- {
- gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);
- llinfos << "Saved settings" << llendflush;
- }
- std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings"));
- gWarningSettings.saveToFile(warnings_settings_filename, TRUE);
- // Save URL history file
- LLURLHistory::saveFile("url_history.xml");
- // save mute list. gMuteList used to also be deleted here too.
- LLMuteList::getInstance()->cache(gAgent.getID());
- if (mPurgeOnExit)
- {
- llinfos << "Purging all cache files on exit" << llendflush;
- std::string mask = gDirUtilp->getDirDelimiter() + "*.*";
- gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);
- }
- removeMarkerFile(); // Any crashes from here on we'll just have to ignore
-
- writeDebugInfo();
- LLLocationHistory::getInstance()->save();
- LLAvatarIconIDCache::getInstance()->save();
-
- LLViewerMedia::saveCookieFile();
- // Stop the plugin read thread if it's running.
- LLPluginProcessParent::setUseReadThread(false);
- llinfos << "Shutting down Threads" << llendflush;
- // Let threads finish
- LLTimer idleTimer;
- idleTimer.reset();
- const F64 max_idle_time = 5.f; // 5 seconds
- while(1)
- {
- S32 pending = 0;
- pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread
- pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
- pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
- pending += LLVFSThread::updateClass(0);
- pending += LLLFSThread::updateClass(0);
- pending += LLCurl::getCurlThread()->update(1) ;
- F64 idle_time = idleTimer.getElapsedTimeF64();
- if(!pending)
- {
- break ; //done
- }
- else if(idle_time >= max_idle_time)
- {
- llwarns << "Quitting with pending background tasks." << llendl;
- break;
- }
- }
- LLCurl::getCurlThread()->pause() ;
- // Delete workers first
- // shotdown all worker threads before deleting them in case of co-dependencies
- sTextureFetch->shutdown();
- sTextureCache->shutdown();
- sImageDecodeThread->shutdown();
-
- sTextureFetch->shutDownTextureCacheThread() ;
- sTextureFetch->shutDownImageDecodeThread() ;
- LLFilePickerThread::cleanupClass();
- delete sTextureCache;
- sTextureCache = NULL;
- delete sTextureFetch;
- sTextureFetch = NULL;
- delete sImageDecodeThread;
- sImageDecodeThread = NULL;
- delete mFastTimerLogThread;
- mFastTimerLogThread = NULL;
-
- if (LLFastTimerView::sAnalyzePerformance)
- {
- llinfos << "Analyzing performance" << llendl;
-
- std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp";
- std::string current_name = LLFastTimer::sLogName + ".slp";
- std::string report_name = LLFastTimer::sLogName + "_report.csv";
- LLFastTimerView::doAnalysis(
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name),
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name),
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name));
- }
- LLMetricPerformanceTesterBasic::cleanClass() ;
- #if LL_RECORD_VIEWER_STATS
- LLViewerStatsRecorder::cleanupClass();
- #endif
- llinfos << "Cleaning up Media and Textures" << llendflush;
- //Note:
- //LLViewerMedia::cleanupClass() has to be put before gTextureList.shutdown()
- //because some new image might be generated during cleaning up media. --bao
- LLViewerMedia::cleanupClass();
- LLViewerParcelMedia::cleanupClass();
- gTextureList.shutdown(); // shutdown again in case a callback added something
- LLUIImageList::getInstance()->cleanUp();
-
- // This should eventually be done in LLAppViewer
- LLImage::cleanupClass();
- LLVFSThread::cleanupClass();
- LLLFSThread::cleanupClass();
- #ifndef LL_RELEASE_FOR_DOWNLOAD
- llinfos << "Auditing VFS" << llendl;
- if(gVFS)
- {
- gVFS->audit();
- }
- #endif
- llinfos << "Misc Cleanup" << llendflush;
-
- // For safety, the LLVFS has to be deleted *after* LLVFSThread. This should be cleaned up.
- // (LLVFS doesn't know about LLVFSThread so can't kill pending requests) -Steve
- delete gStaticVFS;
- gStaticVFS = NULL;
- delete gVFS;
- gVFS = NULL;
-
- gSavedSettings.cleanup();
- LLUIColorTable::instance().clear();
- LLWatchdog::getInstance()->cleanup();
- LLViewerAssetStatsFF::cleanup();
-
- llinfos << "Shutting down message system" << llendflush;
- end_messaging_system();
- // *NOTE:Mani - The following call is not thread safe.
- LLCurl::cleanupClass();
- // If we're exiting to launch an URL, do that here so the screen
- // is at the right resolution before we launch IE.
- if (!gLaunchFileOnQuit.empty())
- {
- llinfos << "Launch file on quit." << llendflush;
- #if LL_WINDOWS
- // Indicate an application is starting.
- SetCursor(LoadCursor(NULL, IDC_WAIT));
- #endif
- // HACK: Attempt to wait until the screen res. switch is complete.
- ms_sleep(1000);
- LLWeb::loadURLExternal( gLaunchFileOnQuit, false );
- llinfos << "File launched." << llendflush;
- }
- llinfos << "Cleaning up LLProxy." << llendl;
- LLProxy::cleanupClass();
- LLMainLoopRepeater::instance().stop();
- //release all private memory pools.
- LLPrivateMemoryPoolManager::destroyClass() ;
- ll_close_fail_log();
- MEM_TRACK_RELEASE
- llinfos << "Goodbye!" << llendflush;
- // return 0;
- return true;
- }
- // A callback for llerrs to call during the watchdog error.
- void watchdog_llerrs_callback(const std::string &error_string)
- {
- gLLErrorActivated = true;
- #ifdef LL_WINDOWS
- RaiseException(0,0,0,0);
- #else
- raise(SIGQUIT);
- #endif
- }
- // A callback for the watchdog to call.
- void watchdog_killer_callback()
- {
- LLError::setFatalFunction(watchdog_llerrs_callback);
- llerrs << "Watchdog killer event" << llendl;
- }
- bool LLAppViewer::initThreads()
- {
- #if MEM_TRACK_MEM
- static const bool enable_threads = false;
- #else
- static const bool enable_threads = true;
- #endif
- LLImage::initClass();
- LLVFSThread::initClass(enable_threads && false);
- LLLFSThread::initClass(enable_threads && false);
- // Image decoding
- LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true);
- LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true);
- LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(),
- sImageDecodeThread,
- enable_threads && true,
- app_metrics_qa_mode);
- if (LLFastTimer::sLog || LLFastTimer::sMetricLog)
- {
- LLFastTimer::sLogLock = new LLMutex(NULL);
- mFastTimerLogThread = new LLFastTimerLogThread(LLFastTimer::sLogName);
- mFastTimerLogThread->start();
- }
- // Mesh streaming and caching
- gMeshRepo.init();
- LLFilePickerThread::initClass();
- // *FIX: no error handling here!
- return true;
- }
- void errorCallback(const std::string &error_string)
- {
- #ifndef LL_RELEASE_FOR_DOWNLOAD
- OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_OK);
- #endif
- //Set the ErrorActivated global so we know to create a marker file
- gLLErrorActivated = true;
-
- LLError::crashAndLoop(error_string);
- }
- bool LLAppViewer::initLogging()
- {
- //
- // Set up logging defaults for the viewer
- //
- LLError::initForApplication(
- gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
- LLError::setFatalFunction(errorCallback);
- // Remove the last ".old" log file.
- std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
- "SecondLife.old");
- LLFile::remove(old_log_file);
- // Rename current log file to ".old"
- std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
- "SecondLife.log");
- LLFile::rename(log_file, old_log_file);
- // Set the log file to SecondLife.log
- LLError::logToFile(log_file);
- // *FIX:Mani no error handling here!
- return true;
- }
- bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
- bool set_defaults)
- {
- if (!mSettingsLocationList)
- {
- llerrs << "Invalid settings location list" << llendl;
- }
- BOOST_FOREACH(const SettingsGroup& group, mSettingsLocationList->groups)
- {
- // skip settings groups that aren't the one we requested
- if (group.name() != location_key) continue;
- ELLPath path_index = (ELLPath)group.path_index();
- if(path_index <= LL_PATH_NONE || path_index >= LL_PATH_LAST)
- {
- llerrs << "Out of range path index in app_settings/settings_files.xml" << llendl;
- return false;
- }
- BOOST_FOREACH(const SettingsFile& file, group.files)
- {
- llinfos << "Attempting to load settings for the group " << file.name()
- << " - from location " << location_key << llendl;
- LLControlGroup* settings_group = LLControlGroup::getInstance(file.name);
- if(!settings_group)
- {
- llwarns << "No matching settings group for name " << file.name() << llendl;
- continue;
- }
- std::string full_settings_path;
- if (file.file_name_setting.isProvided()
- && gSavedSettings.controlExists(file.file_name_setting))
- {
- // try to find filename stored in file_name_setting control
- full_settings_path = gSavedSettings.getString(file.file_name_setting);
- if (full_settings_path.empty())
- {
- continue;
- }
- else if (!gDirUtilp->fileExists(full_settings_path))
- {
- // search in default path
- full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, full_settings_path);
- }
- }
- else
- {
- // by default, use specified file name
- full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, file.file_name());
- }
- if(settings_group->loadFromFile(full_settings_path, set_defaults, file.persistent))
- { // success!
- llinfos << "Loaded settings file " << full_settings_path << llendl;
- }
- else
- { // failed to load
- if(file.required)
- {
- llerrs << "Error: Cannot load required settings file from: " << full_settings_path << llendl;
- return false;
- }
- else
- {
- // only complain if we actually have a filename at this point
- if (!full_settings_path.empty())
- {
- llinfos << "Cannot load " << full_settings_path << " - No settings found." << llendl;
- }
- }
- }
- }
- }
- return true;
- }
- std::string LLAppViewer::getSettingsFilename(const std::string& location_key,
- const std::string& file)
- {
- BOOST_FOREACH(const SettingsGroup& group, mSettingsLocationList->groups)
- {
- if (group.name() == location_key)
- {
- BOOST_FOREACH(const SettingsFile& settings_file, group.files)
- {
- if (settings_file.name() == file)
- {
- return settings_file.file_name;
- }
- }
- }
- }
- return std::string();
- }
- void LLAppViewer::loadColorSettings()
- {
- LLUIColorTable::instance().loadFromSettings();
- }
- bool LLAppViewer::initConfiguration()
- {
- //Load settings files list
- std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml");
- //LLControlGroup settings_control("SettingsFiles");
- //llinfos << "Loading settings file list " << settings_file_list << llendl;
- //if (0 == settings_control.loadFromFile(settings_file_list))
- //{
- // llerrs << "Cannot load default configuration file " << settings_file_list << llendl;
- //}
- LLXMLNodePtr root;
- BOOL success = LLXMLNode::parseFile(settings_file_list, root, NULL);
- if (!success)
- {
- llerrs << "Cannot load default configuration file " << settings_file_list << llendl;
- }
- mSettingsLocationList = new SettingsFiles();
- LLXUIParser parser;
- parser.readXUI(root, *mSettingsLocationList, settings_file_list);
- if (!mSettingsLocationList->validateBlock())
- {
- llerrs << "Invalid settings file list " << settings_file_list << llendl;
- }
-
- // The settings and command line parsing have a fragile
- // order-of-operation:
- // - load defaults from app_settings
- // - set procedural settings values
- // - read command line settings
- // - selectively apply settings needed to load user settings.
- // - load overrides from user_settings
- // - apply command line settings (to override the overrides)
- // - load per account settings (happens in llstartup
-
- // - load defaults
- bool set_defaults = true;
- if(!loadSettingsFromDirectory("Default", set_defaults))
- {
- std::ostringstream msg;
- msg << "Unable to load default settings file. The installation may be corrupted.";
- OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
- return false;
- }
-
- LLUI::setupPaths(); // setup paths for LLTrans based on settings files only
- LLTransUtil::parseStrings("strings.xml", default_trans_args);
- LLTransUtil::parseLanguageStrings("language_settings.xml");
- // - set procedural settings
- // Note: can't use LL_PATH_PER_SL_ACCOUNT for any of these since we haven't logged in yet
- gSavedSettings.setString("ClientSettingsFile",
- gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global")));
- gSavedSettings.setString("VersionChannelName", LLVersionInfo::getChannel());
- #ifndef LL_RELEASE_FOR_DOWNLOAD
- // provide developer build only overrides for these control variables that are not
- // persisted to settings.xml
- LLControlVariable* c = gSavedSettings.getControl("ShowConsoleWindow");
- if (c)
- {
- c->setValue(true, false);
- }
- c = gSavedSettings.getCont