Skip to content
Snippets Groups Projects
llappviewer.cpp 110 KiB
Newer Older
/** 
 * @file llappviewer.cpp
 * @brief The LLAppViewer class definitions
 *
 * $LicenseInfo:firstyear=2007&license=viewergpl$
 * 
 * Copyright (c) 2007, Linden Research, Inc.
 * 
 * Second Life Viewer Source Code
 * The source code in this file ("Source Code") is provided by Linden Lab
 * to you under the terms of the GNU General Public License, version 2.0
 * ("GPL"), unless you have obtained a separate licensing agreement
 * ("Other License"), formally executed by you and Linden Lab.  Terms of
 * the GPL can be found in doc/GPL-license.txt in this distribution, or
 * online at http://secondlife.com/developers/opensource/gplv2
 * 
 * There are special exceptions to the terms and conditions of the GPL as
 * it is applied to this Source Code. View the full text of the exception
 * in the file doc/FLOSS-exception.txt in this software distribution, or
 * online at http://secondlife.com/developers/opensource/flossexception
 * 
 * By copying, modifying or distributing this software, you acknowledge
 * that you have read and understood your obligations described above,
 * and agree to abide by those obligations.
 * 
 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 * COMPLETENESS OR PERFORMANCE.
 * $/LicenseInfo$
 */


#include "llviewerprecompiledheaders.h"
#include "llappviewer.h"

#include "llversionviewer.h"
#include "llfeaturemanager.h"
#include "llvieweruictrlfactory.h"
#include "llalertdialog.h"
#include "llerrorcontrol.h"
#include "llviewerimagelist.h"
#include "llgroupmgr.h"
#include "llagent.h"
#include "llwindow.h"
#include "llviewerstats.h"
#include "llmd5.h"
#include "llpumpio.h"
#include "llfloateractivespeakers.h"
#include "llimpanel.h"
Josh Bell's avatar
Josh Bell committed
#include "llmimetypes.h"
#include "llstartup.h"
#include "llfocusmgr.h"
#include "llviewerjoystick.h"
Josh Bell's avatar
Josh Bell committed
#include "llares.h" 
#include "llcurl.h"
#include "llfloatersnapshot.h"
#include "llviewerwindow.h"
#include "llviewerdisplay.h"
#include "llviewermessage.h"
#include "llviewerobjectlist.h"
#include "llworldmap.h"
#include "llmutelist.h"
Josh Bell's avatar
Josh Bell committed
#include "llurlhistory.h"

#include "llweb.h"
#include "llsecondlifeurls.h"

#if LL_WINDOWS
	#include "llwindebug.h"
#endif

#if LL_WINDOWS
#	include <share.h> // For _SH_DENYWR in initMarkerFile
#else
#   include <sys/file.h> // For initMarkerFile support
#endif



#include "llnotify.h"
#include "llviewerkeyboard.h"
#include "lllfsthread.h"
#include "llworkerthread.h"
#include "lltexturecache.h"
#include "lltexturefetch.h"
#include "llimageworker.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 "lleconomy.h"
#include "llcachename.h"
#include "audioengine.h"
#include "llviewermenu.h"
#include "llselectmgr.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 "llworld.h"
#include "llhudeffecttrail.h"
#include "llvectorperfoptions.h"
#include "llurlsimstring.h"

// Included so that constants/settings might be initialized
// in save_settings_to_globals()
#include "llbutton.h"
#include "llcombobox.h"
#include "llstatusbar.h"
#include "llsurface.h"
#include "llvosky.h"
#include "llvotree.h"
#include "llvoavatar.h"
#include "llfolderview.h"
#include "lltoolbar.h"
#include "llframestats.h"
#include "llagentpilot.h"
#include "llsrv.h"
#include "llvovolume.h"
#include "llflexibleobject.h" 
#include "llvosurfacepatch.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 "llinventoryview.h"

// *FIX: Remove these once the command line params thing is figured out.
// Yuck!
static int gTempArgC = 0;
static char** gTempArgV;

// *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"
// extern EGridInfo gGridChoice;
Josh Bell's avatar
Josh Bell committed

////// Windows-specific includes to the bottom - nasty defines in these pollute the preprocessor
//
#if LL_WINDOWS && LL_LCD_COMPILE
	#include "lllcd.h"
#endif

//----------------------------------------------------------------------------
// viewer.cpp - these are only used in viewer, should be easily moved.
extern void disable_win_error_reporting();

//#define APPLE_PREVIEW // Define this if you're doing a preview build on the Mac
#if LL_RELEASE_FOR_DOWNLOAD
// Default userserver for production builds is agni
#ifndef APPLE_PREVIEW
static EGridInfo GridDefaultChoice = GRID_INFO_AGNI;
#else
static EGridInfo GridDefaultChoice = GRID_INFO_ADITI;
#endif
#else
// Default userserver for development builds is none
static EGridInfo GridDefaultChoice = GRID_INFO_NONE;
#endif

#if LL_WINDOWS
extern void create_console();
#endif


#if LL_DARWIN
#include <Carbon/Carbon.h>
extern void init_apple_menu(const char* product);
extern OSErr AEGURLHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn);
extern OSErr AEQuitHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn);
extern OSStatus simpleDialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata);
extern OSStatus DisplayReleaseNotes(void);
#include <boost/tokenizer.hpp>
#endif // LL_DARWIN


extern BOOL gRandomizeFramerate;
extern BOOL gPeriodicSlowFrame;

////////////////////////////////////////////////////////////
// All from the last globals push...
bool gVerifySSLCert = true;
BOOL gProbeHardware = TRUE; // Use DirectX 9 to probe for hardware

S32 gYieldMS = 0; // set in parse_args, used in mainLoop
BOOL gYieldTime = FALSE;

const F32 DEFAULT_AFK_TIMEOUT = 5.f * 60.f; // time with no input before user flagged as Away From Keyboard

F32 gSimLastTime; // Used in LLAppViewer::init and send_stats()
F32 gSimFrames;

LLString gDisabledMessage; // Set in LLAppViewer::initConfiguration used in idle_startup

BOOL gHideLinks = FALSE; // Set in LLAppViewer::initConfiguration, used externally

BOOL				gAllowIdleAFK = TRUE;
F32					gAFKTimeout = DEFAULT_AFK_TIMEOUT;
BOOL gLogMessages = FALSE;
std::string gChannelName = LL_CHANNEL;
BOOL gUseAudio = TRUE;
Josh Bell's avatar
Josh Bell committed
BOOL gUseQuickTime = TRUE;
LLString gCmdLineFirstName;
LLString gCmdLineLastName;
LLString gCmdLinePassword;

BOOL				gAutoLogin = FALSE;

const char*			DEFAULT_SETTINGS_FILE = "settings.xml";
BOOL gRequestInventoryLibrary = TRUE;
BOOL gGodConnect = FALSE;
BOOL gAcceptTOS = FALSE;
BOOL gAcceptCriticalMessage = FALSE;

LLUUID				gViewerDigest;	// MD5 digest of the viewer's executable file.
eLastExecEvent gLastExecEvent = LAST_EXEC_NORMAL;
U32	gFrameCount = 0;
U32 gForegroundFrameCount = 0; // number of frames that app window was in foreground
LLPumpIO*			gServicePump = NULL;

BOOL gPacificDaylightTime = FALSE;

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

LLTimer gRenderStartTime;
LLFrameTimer gForegroundTime;
LLTimer				gLogoutTimer;
static const F32			LOGOUT_REQUEST_TIME = 6.f;  // this will be cut short by the LogoutReply msg.
F32					gLogoutMaxTime = LOGOUT_REQUEST_TIME;

LLUUID gInventoryLibraryOwner;
LLUUID gInventoryLibraryRoot;

BOOL				gDisableVoice = FALSE;
BOOL				gDisconnected = FALSE;

// Map scale in pixels per region
F32 				gMapScale = 128.f;
F32 				gMiniMapScale = 128.f;

// used to restore texture state after a mode switch
LLFrameTimer	gRestoreGLTimer;
BOOL			gRestoreGL = FALSE;
BOOL				gUseWireframe = FALSE;

F32					gMouseSensitivity = 3.f;
BOOL				gInvertMouse = FALSE;

// VFS globals - see llappviewer.h
LLVFS* gStaticVFS = NULL;

LLMemoryInfo gSysMemory;

bool gPreloadImages = true;
bool gPreloadSounds = true;

LLString gLastVersionChannel;

LLVector3			gWindVec(3.0, 3.0, 0.0);
LLVector3			gRelativeWindVec(0.0, 0.0, 0.0);

U32		gPacketsIn = 0;

BOOL				gPrintMessagesThisFrame = FALSE;

BOOL gUseConsole = TRUE;

BOOL gRandomizeFramerate = FALSE;
BOOL gPeriodicSlowFrame = FALSE;

BOOL gQAMode = FALSE;
BOOL gLLErrorActivated = FALSE;
////////////////////////////////////////////////////////////
// Internal globals... that should be removed.
static F32 gQuitAfterSeconds = 0.f;
static BOOL gRotateRight = FALSE;
static BOOL gIgnorePixelDepth = FALSE;

// Allow multiple viewers in ReleaseForDownload
#if LL_RELEASE_FOR_DOWNLOAD
static BOOL gMultipleViewersOK = FALSE;
#else
static BOOL gMultipleViewersOK = TRUE;
#endif

static std::map<std::string, std::string> gCommandLineSettings;
static std::map<std::string, std::string> gCommandLineForcedSettings;

static LLString gOldSettingsFileName;
static const char* LEGACY_DEFAULT_SETTINGS_FILE = "settings.ini";
const char* MARKER_FILE_NAME = "SecondLife.exec_marker";
const char* ERROR_MARKER_FILE_NAME = "SecondLife.error_marker";
const char* LLERROR_MARKER_FILE_NAME = "SecondLife.llerror_marker";
static BOOL gDoDisconnect = FALSE;
static LLString gLaunchFileOnQuit;

//----------------------------------------------------------------------------
// File scope definitons
const char *VFS_DATA_FILE_BASE = "data.db2.x.";
const char *VFS_INDEX_FILE_BASE = "index.db2.x.";

static LLString gSecondLife;
static LLString gWindowTitle;
#ifdef LL_WINDOWS
	static char sWindowClass[] = "Second Life";
#endif

Josh Bell's avatar
Josh Bell committed
std::string gLoginPage;
std::vector<std::string> gLoginURIs;
static std::string gHelperURI;

static const char USAGE[] = "\n"
"usage:\tviewer [options]\n"
"options:\n"
" -login <first> <last> <password>     log in as a user\n"
" -autologin                           log in as last saved user\n"
" -loginpage <URL>                     login authentication page to use\n"
" -loginuri <URI>                      login server and CGI script to use\n"
" -helperuri <URI>                     helper web CGI prefix to use\n"
" -settings <filename>                 specify the filename of a\n"
"                                        configuration file\n"
"                                        default is settings.xml\n"
" -setdefault <variable> <value>       specify the value of a particular\n"
"                                        configuration variable which can be\n"
"                                        overridden by settings.xml\n"
" -set <variable> <value>              specify the value of a particular\n"
"                                        configuration variable that\n"
"                                        overrides all other settings\n"
#if !LL_RELEASE_FOR_DOWNLOAD
" -sim <simulator_ip>                  specify the simulator ip address\n"
#endif
" -god		                           log in as god if you have god access\n"
" -purge                               delete files in cache\n"
" -safe                                reset preferences, run in safe mode\n"
" -noutc                               logs in local time, not UTC\n"
" -nothread                            run vfs in single thread\n"
" -noinvlib                            Do not request inventory library\n"
" -multiple                            allow multiple viewers\n"
" -nomultiple                          block multiple viewers\n"
" -novoice                             disable voice\n"
" -ignorepixeldepth                    ignore pixel depth settings\n"
" -cooperative [ms]                    yield some idle time to local host\n"
" -skin                                ui/branding skin folder to use\n"
#if LL_WINDOWS
" -noprobe                             disable hardware probe\n"
#endif
" -noquicktime                         disable QuickTime movies, speeds startup\n"
" -nopreload                           don't preload UI images or sounds, speeds startup\n"
// these seem to be unused
//" -noenv                               turn off environmental effects\n"
//" -proxy <proxy_ip>                    specify the proxy ip address\n"
"\n";

	if (gAllowIdleAFK && (gAwayTriggerTimer.getElapsedTimeF32() > gAFKTimeout))
	{
		gAgent.setAFK();
	}
}

// A callback set in LLAppViewer::init()
static void ui_audio_callback(const LLUUID& uuid)
{
	if (gAudiop)
	{
Jon Wolk's avatar
Jon Wolk committed
		F32 volume = gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI");
		gAudiop->triggerSound(uuid, gAgent.getID(), volume);
	}
}

void request_initial_instant_messages()
{
	static BOOL requested = FALSE;
	if (!requested
		&& gMuteListp
		&& gMuteListp->isLoaded()
		&& gAgent.getAvatarObject())
	{
		// 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 saved_settings_to_globals()
{
	LLBUTTON_H_PAD		= gSavedSettings.getS32("ButtonHPad");
	LLBUTTON_V_PAD		= gSavedSettings.getS32("ButtonVPad");
	BTN_HEIGHT_SMALL	= gSavedSettings.getS32("ButtonHeightSmall");
	BTN_HEIGHT			= gSavedSettings.getS32("ButtonHeight");

	MENU_BAR_HEIGHT		= gSavedSettings.getS32("MenuBarHeight");
	MENU_BAR_WIDTH		= gSavedSettings.getS32("MenuBarWidth");
	STATUS_BAR_HEIGHT	= gSavedSettings.getS32("StatusBarHeight");

	LLCOMBOBOX_HEIGHT	= BTN_HEIGHT - 2;
	LLCOMBOBOX_WIDTH	= 128;

	LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
	
	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::sMaxVisible				= 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"));
	LLToolBar::sInventoryAutoOpenTime	= gSavedSettings.getF32("InventoryAutoOpenDelay");
	LLSelectMgr::sRectSelectInclusive	= gSavedSettings.getBOOL("RectangleSelectInclusive");
	LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections");
	LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius");

	gFrameStats.setTrackStats(gSavedSettings.getBOOL("StatsSessionTrackFrameStats"));
	gAgentPilot.mNumRuns		= gSavedSettings.getS32("StatsNumRuns");
	gAgentPilot.mQuitAfterRuns	= gSavedSettings.getBOOL("StatsQuitAfterRuns");
	gAgent.mHideGroupTitle		= gSavedSettings.getBOOL("RenderHideGroupTitle");

	gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc");
	gAllowIdleAFK = gSavedSettings.getBOOL("AllowIdleAFK");
	gAFKTimeout = gSavedSettings.getF32("AFKTimeout");
	gMouseSensitivity = gSavedSettings.getF32("MouseSensitivity");
	gInvertMouse = gSavedSettings.getBOOL("InvertMouse");
	gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates");
	gMapScale = gSavedSettings.getF32("MapScale");
	gMiniMapScale = gSavedSettings.getF32("MiniMapScale");
	gHandleKeysAsync = gSavedSettings.getBOOL("AsyncKeyboard");
	LLHoverView::sShowHoverTips = gSavedSettings.getBOOL("ShowHoverTips");

	LLRenderTarget::sUseFBO				= gSavedSettings.getBOOL("RenderUseFBO");
	LLVOAvatar::sUseImpostors			= gSavedSettings.getBOOL("RenderUseImpostors");
	LLVOSurfacePatch::sLODFactor		= gSavedSettings.getF32("RenderTerrainLODFactor");
	LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //sqaure lod factor to get exponential range of [1,4]

#if LL_VECTORIZE
	if (gSysCPU.hasAltivec())
	{
		gSavedSettings.setBOOL("VectorizeEnable", TRUE );
		gSavedSettings.setU32("VectorizeProcessor", 0 );
	}
	else
	if (gSysCPU.hasSSE2())
	{
		gSavedSettings.setBOOL("VectorizeEnable", TRUE );
		gSavedSettings.setU32("VectorizeProcessor", 2 );
	}
	else
	if (gSysCPU.hasSSE())
	{
		gSavedSettings.setBOOL("VectorizeEnable", TRUE );
		gSavedSettings.setU32("VectorizeProcessor", 1 );
	}
	else
	{
		// Don't bother testing or running if CPU doesn't support it. JC
		gSavedSettings.setBOOL("VectorizePerfTest", FALSE );
		gSavedSettings.setBOOL("VectorizeEnable", FALSE );
		gSavedSettings.setU32("VectorizeProcessor", 0 );
		gSavedSettings.setBOOL("VectorizeSkin", FALSE);
	}
#else
	// This build target doesn't support SSE, don't test/run.
	gSavedSettings.setBOOL("VectorizePerfTest", FALSE );
	gSavedSettings.setBOOL("VectorizeEnable", FALSE );
	gSavedSettings.setU32("VectorizeProcessor", 0 );
	gSavedSettings.setBOOL("VectorizeSkin", FALSE);
#endif

	// propagate push to talk preference to current status
	gSavedSettings.setBOOL("PTTCurrentlyEnabled", gSavedSettings.getBOOL("EnablePushToTalk"));

	settings_setup_listeners();

	// gAgent.init() also loads from saved settings.
int parse_args(int argc, char **argv)
	// Sometimes IP addresses passed in on the command line have leading
	// or trailing white space.  Use LLString to clean that up.
	LLString ip_string;
	S32 j;

	for (j = 1; j < argc; j++) 
	{
		// Used to show first chunk of each argument passed in the 
		// window title.
		gArgs += argv[j];
		gArgs += " ";
		LLString argument = argv[j];
		if ((!strcmp(argv[j], "-port")) && (++j < argc)) 
		{
			sscanf(argv[j], "%u", &(gAgent.mViewerPort));
		}
		else if ((!strcmp(argv[j], "-drop")) && (++j < argc)) 
		{
			sscanf(argv[j], "%f", &gPacketDropPercentage);
		}
		else if ((!strcmp(argv[j], "-inbw")) && (++j < argc))
		{
			sscanf(argv[j], "%f", &gInBandwidth);
		}
		else if ((!strcmp(argv[j], "-outbw")) && (++j < argc))
		{
			sscanf(argv[j], "%f", &gOutBandwidth);
		}
		else if (!strcmp(argv[j], "--aditi"))
		{
			gGridChoice = GRID_INFO_ADITI;
			snprintf(gGridName, MAX_STRING, "%s", gGridInfo[gGridChoice].mName);		// Flawfinder: ignore
		}
		else if (!strcmp(argv[j], "--agni"))
		{
			gGridChoice = GRID_INFO_AGNI;
			snprintf(gGridName, MAX_STRING, "%s", gGridInfo[gGridChoice].mName);		// Flawfinder: ignore
		}
		else if (!strcmp(argv[j], "--aruna"))
		{
			gGridChoice = GRID_INFO_ARUNA;
			sprintf(gGridName,"%s", gGridInfo[gGridChoice].mName);
		}
		else if (!strcmp(argv[j], "--durga"))
		{
			gGridChoice = GRID_INFO_DURGA;
			snprintf(gGridName, MAX_STRING, "%s", gGridInfo[gGridChoice].mName);		// Flawfinder: ignore
		}
		else if (!strcmp(argv[j], "--ganga"))
		{
			gGridChoice = GRID_INFO_GANGA;
			sprintf(gGridName,"%s", gGridInfo[gGridChoice].mName);
		}
		else if (!strcmp(argv[j], "--mitra"))
		{
			gGridChoice = GRID_INFO_MITRA;
			sprintf(gGridName,"%s", gGridInfo[gGridChoice].mName);
		}
		else if (!strcmp(argv[j], "--mohini"))
		{
			gGridChoice = GRID_INFO_MOHINI;
			sprintf(gGridName,"%s", gGridInfo[gGridChoice].mName);
		}
		else if (!strcmp(argv[j], "--nandi"))
		{
			gGridChoice = GRID_INFO_NANDI;
			sprintf(gGridName,"%s", gGridInfo[gGridChoice].mName);
		}
		else if (!strcmp(argv[j], "--radha"))
		{
			gGridChoice = GRID_INFO_RADHA;
			sprintf(gGridName,"%s", gGridInfo[gGridChoice].mName);
		}
		else if (!strcmp(argv[j], "--ravi"))
		{
			gGridChoice = GRID_INFO_RAVI;
			sprintf(gGridName,"%s", gGridInfo[gGridChoice].mName);
		}
		else if (!strcmp(argv[j], "--siva"))
		{
			gGridChoice = GRID_INFO_SIVA;
			snprintf(gGridName, MAX_STRING, "%s", gGridInfo[gGridChoice].mName);		// Flawfinder: ignore
		}
		else if (!strcmp(argv[j], "--shakti"))
		{
			gGridChoice = GRID_INFO_SHAKTI;
			snprintf(gGridName, MAX_STRING, "%s", gGridInfo[gGridChoice].mName);		// Flawfinder: ignore
		}
		else if (!strcmp(argv[j], "--soma"))
		{
			gGridChoice = GRID_INFO_SOMA;
			snprintf(gGridName, MAX_STRING, "%s", gGridInfo[gGridChoice].mName);		// Flawfinder: ignore
		}
		else if (!strcmp(argv[j], "--uma"))
		{
			gGridChoice = GRID_INFO_UMA;
			sprintf(gGridName,"%s", gGridInfo[gGridChoice].mName);
		}
		else if (!strcmp(argv[j], "--vaak"))
		{
			gGridChoice = GRID_INFO_VAAK;
			sprintf(gGridName,"%s", gGridInfo[gGridChoice].mName);
		}
		else if (!strcmp(argv[j], "--yami"))
		{
			gGridChoice = GRID_INFO_YAMI;
			sprintf(gGridName,"%s", gGridInfo[gGridChoice].mName);
		}
		else if (!strcmp(argv[j], "-loginpage") && (++j < argc))
		{
			LLAppViewer::instance()->setLoginPage(utf8str_trim(argv[j]));
		}
		else if (!strcmp(argv[j], "-loginuri") && (++j < argc))
		{
            LLAppViewer::instance()->addLoginURI(utf8str_trim(argv[j]));
		}
		else if (!strcmp(argv[j], "-helperuri") && (++j < argc))
		{
            LLAppViewer::instance()->setHelperURI(utf8str_trim(argv[j]));
		}
		else if (!strcmp(argv[j], "-debugviews"))
		{
			LLView::sDebugRects = TRUE;
		}
		else if (!strcmp(argv[j], "-skin") && (++j < argc))
		{
			std::string folder(argv[j]);
			gDirUtilp->setSkinFolder(folder);
		}
		else if (!strcmp(argv[j], "-autologin") || !strcmp(argv[j], "--autologin")) // keep --autologin for compatibility
		{
			gAutoLogin = TRUE;
		}
		else if (!strcmp(argv[j], "-quitafter") && (++j < argc))
		{
			gQuitAfterSeconds = (F32)atof(argv[j]);
		}
		else if (!strcmp(argv[j], "-rotate"))
		{
			gRotateRight = TRUE;
		}
//		else if (!strcmp(argv[j], "-noenv")) 
//		{
			//turn OFF environmental effects for slow machines/video cards
//			gRequestParaboloidMap = FALSE;
//		}
		else if (!strcmp(argv[j], "-noaudio"))
		{
			gUseAudio = FALSE;
		}
		else if (!strcmp(argv[j], "-nosound"))  // tends to be popular cmdline on Linux.
		{
			gUseAudio = FALSE;
		}
		else if (!strcmp(argv[j], "-noprobe"))
		{
			gProbeHardware = FALSE;
		}
		else if (!strcmp(argv[j], "-noquicktime"))
		{
			// Developers can log in faster if they don't load all the
			// quicktime dlls.
			gUseQuickTime = false;
		}
		else if (!strcmp(argv[j], "-nopreload"))
		{
			// Developers can log in faster if they don't decode sounds
			// or images on startup, ~5 seconds faster.
			gPreloadSounds = false;
			gPreloadImages = false;
		}
		else if (!strcmp(argv[j], "-purge"))
		{
			LLAppViewer::instance()->purgeCache();
		}
		else if(!strcmp(argv[j], "-noinvlib"))
		{
			gRequestInventoryLibrary = FALSE;
		}
		else if (!strcmp(argv[j], "-log"))
		{
			gLogMessages = TRUE;
			continue;
		}
		else if (!strcmp(argv[j], "-logfile") && (++j < argc)) 
		{
			// *NOTE: This buffer size is hard coded into scanf() below.
			char logfile[256];	// Flawfinder: ignore
			sscanf(argv[j], "%255s", logfile);	// Flawfinder: ignore
			llinfos << "Setting log file to " << logfile << llendl;
			LLFile::remove(logfile);
			LLError::logToFile(logfile);
		}
		else if (!strcmp(argv[j], "-settings") && (++j < argc)) 
		{
			gSettingsFileName = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, argv[j]);
		}
		else if (!strcmp(argv[j], "-setdefault") && (j + 2 < argc)) 
		{
			std::string control_name;
			std::string control_value;
			
			j++;
			if (argv[j]) control_name = std::string(argv[j]);
			j++;
			if (argv[j]) control_value = std::string(argv[j]);
			
			// grab control name and value
			if (!control_name.empty())
			{
				gCommandLineSettings[control_name] = control_value;
			}
		}
		else if (!strcmp(argv[j], "-set") && (j + 2 < argc)) 
			std::string control_name;
			std::string control_value;
			
			j++;
			if (argv[j]) control_name = std::string(argv[j]);

			j++;
			if (argv[j]) control_value = std::string(argv[j]);
			
			// grab control name and value
			if (!control_name.empty())
				gCommandLineForcedSettings[control_name] = control_value;
			}
		}
		else if (!strcmp(argv[j], "-login"))
		{
			if (j + 3 < argc)
			{
				j++;
				gCmdLineFirstName = argv[j];
				j++;
				gCmdLineLastName = argv[j];
				j++;
				gCmdLinePassword = argv[j];
				// only works if -login is last parameter on command line
				llerrs << "Not enough parameters to -login. Did you mean -loginuri?" << llendl;
		else if (!strcmp(argv[j], "-god"))
		{
			gGodConnect = TRUE;
		}
		else if (!strcmp(argv[j], "-noconsole"))
		{
			gUseConsole = FALSE;
		}
		else if (!strcmp(argv[j], "-safe"))
		{
			llinfos << "Setting viewer feature table to run in safe mode, resetting prefs" << llendl;
			gFeatureManagerp->setSafe(TRUE);
		}
		else if (!strcmp(argv[j], "-multiple"))
		{
			gMultipleViewersOK = TRUE;
		}
		else if (!strcmp(argv[j], "-nomultiple"))
		{
			gMultipleViewersOK = FALSE;
		}
		else if (!strcmp(argv[j], "-novoice"))
		{
			gDisableVoice = TRUE;
		}
		else if (!strcmp(argv[j], "-nothread"))
		{
			LLVFile::ALLOW_ASYNC = FALSE;
			llinfos << "Running VFS in nothread mode" << llendl;
		}
		// some programs don't respect the command line options in protocol handlers (I'm looking at you, Opera)
		// so this allows us to parse the URL straight off the command line without a "-url" paramater
		else if (LLURLDispatcher::isSLURL(argv[j])
				 || !strcmp(argv[j], "-url") && (++j < argc)) 
		{
			std::string slurl = argv[j];
			if (LLURLDispatcher::isSLURLCommand(slurl))
			{
				LLStartUp::sSLURLCommand = slurl;
			}
			else
			{
				LLURLSimString::setString(slurl);
			}
			// *NOTE: After setting the url, bail. What can happen is
			// that someone can use IE (or potentially other browsers)
			// and do the rough equivalent of command injection and
			// steal passwords. Phoenix. SL-55321
			return 0;
		}
		else if (!strcmp(argv[j], "-ignorepixeldepth"))
		{
			gIgnorePixelDepth = TRUE;
		}
		else if (!strcmp(argv[j], "-cooperative"))
		{
			S32 ms_to_yield = 0;
			if(++j < argc)
			{
				S32 rv = sscanf(argv[j], "%d", &ms_to_yield);
				if(0 == rv)
				{
					--j;
				}
			}
			else
			{
				--j;
			}
			gYieldMS = ms_to_yield;
			gYieldTime = TRUE;
		}
		else if (!strcmp(argv[j], "-no-verify-ssl-cert"))
		{
			gVerifySSLCert = false;
		}
		else if ( (!strcmp(argv[j], "--channel") || !strcmp(argv[j], "-channel"))  && (++j < argc)) 
		{
			gChannelName = argv[j];
		}
#if LL_DARWIN
		else if (!strncmp(argv[j], "-psn_", 5))
		{
			// this is the Finder passing the process session number
			// we ignore this
		}
		else if(!strncmp(argv[j], "-qa", 3))
		{
			gQAMode = TRUE;
		}
		else
		{
			// DBC - Mac OS X passes some stuff by default on the command line (e.g. psn).
			// Second Life URLs are passed this way as well?
			llwarns << "Possible unknown keyword " << argv[j] << llendl;

			// print usage information
			llinfos << USAGE << llendl;
			// return 1;
		}
}

bool send_url_to_other_instance(const std::string& url)
{
#if LL_WINDOWS
	wchar_t window_class[256]; /* Flawfinder: ignore */   // Assume max length < 255 chars.
	mbstowcs(window_class, sWindowClass, 255);
	window_class[255] = 0;
	// Use the class instead of the window name.
	HWND other_window = FindWindow(window_class, NULL);
	if (other_window != NULL)
	{
		lldebugs << "Found other window with the name '" << gWindowTitle << "'" << llendl;
		COPYDATASTRUCT cds;
		const S32 SLURL_MESSAGE_TYPE = 0;
		cds.dwData = SLURL_MESSAGE_TYPE;
		cds.cbData = url.length() + 1;
		cds.lpData = (void*)url.c_str();

		LRESULT msg_result = SendMessage(other_window, WM_COPYDATA, NULL, (LPARAM)&cds);
		lldebugs << "SendMessage(WM_COPYDATA) to other window '" 
				 << gWindowTitle << "' returned " << msg_result << llendl;
		return true;
	}
#endif
	return false;
}

//----------------------------------------------------------------------------
// LLAppViewer definition

// Static members.
// The single viewer app.
LLAppViewer* LLAppViewer::sInstance = NULL;

LLTextureCache* LLAppViewer::sTextureCache = NULL; 
LLWorkerThread* LLAppViewer::sImageDecodeThread = NULL; 
LLTextureFetch* LLAppViewer::sTextureFetch = NULL; 

LLAppViewer::LLAppViewer() : 
	mMarkerFile(NULL),
	mCrashBehavior(CRASH_BEHAVIOR_ASK),
	mReportedCrash(false),
	mNumSessions(0),
	mPurgeCache(false),
    mPurgeOnExit(false),
    mSecondInstance(false),
    mQuitRequested(false),
    mLogoutRequestSent(false)
{
	if(NULL != sInstance)
	{
		llerrs << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << llendl;
	}

	sInstance = this;
}

LLAppViewer::~LLAppViewer()
{
	// If we got to this destructor somehow, the app didn't hang.
	removeMarkerFile();
}

bool LLAppViewer::tempStoreCommandOptions(int argc, char** argv)
{
	gTempArgC = argc;
	gTempArgV = argv;
	return true;
}

bool LLAppViewer::init()
{
    // *NOTE:Mani - LLCurl::initClass is not thread safe. 
    // Called before threads are created.
    LLCurl::initClass();

    initThreads();

	initEarlyConfiguration();

	//
	// 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.
	//

	// 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");


	initLogging();
	
	//
	// OK to write stuff to logs now, we've now crash reported if necessary
	//

	// Set up some defaults...
	gSettingsFileName = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, DEFAULT_SETTINGS_FILE);
	gOldSettingsFileName = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, LEGACY_DEFAULT_SETTINGS_FILE);