viewer.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "viewer.h"
00035 
00036 #include "llparcel.h"
00037 #include "llviewerparcelmgr.h"
00038 #include "llviewerjoystick.h"
00039 
00040 // System library headers
00041 #include <errno.h>
00042 #include <stdexcept>
00043 #if LL_WINDOWS
00044 #       include <share.h>
00045 #else
00046 #       include <sys/file.h>
00047 #       include <signal.h>
00048 #endif
00049 #include <sys/stat.h>
00050 #include <memory>
00051 #include <boost/tokenizer.hpp>
00052 
00053 #if LL_WINDOWS
00054 #include <fcntl.h>              //_O_APPEND
00055 #include <io.h>                 //_open_osfhandle()
00056 #include <errorrep.h>   // for AddERExcludedApplicationA()
00057 #include <process.h>    // _spawnl()
00058 #include <tchar.h>              // For TCHAR support
00059 
00060 #if LL_WINDOWS && _MSC_VER < 1400
00061 //#define LL_USE_SMARTHEAP 0
00062 #else
00063 #define LL_USE_SMARTHEAP 0
00064 #endif
00065 
00066 #if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
00067 #include "smrtheap/smrtheap.h"
00068 #endif // LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
00069 
00070 #elif LL_DARWIN || LL_LINUX || LL_SOLARIS
00071 
00072   #     include <sys/socket.h>
00073 //  #   include <sys/stat.h>            // mkdir()
00074   #     include <netinet/in.h>
00075   #     include <arpa/inet.h>   // inet_ntoa()
00076 
00077   #if LL_LINUX
00078   #     include <dlfcn.h>               // RTLD_LAZY
00079   #     include <execinfo.h>            // backtrace - glibc only
00080   #     ifndef LL_ELFBIN
00081   #define LL_ELFBIN 1
00082   #     endif // LL_ELFBIN
00083   #     if LL_ELFBIN
00084   #          include <cxxabi.h>         // for symbol demangling
00085   #          include "ELFIO.h"          // for better backtraces
00086   #     endif // LL_ELFBIN
00087   #elif LL_SOLARIS
00088   #     include <sys/types.h>
00089   #     include <unistd.h>
00090   #     include <fcntl.h>
00091   #     include <ucontext.h>
00092   #endif
00093 
00094   #if LL_DARWIN
00095     #include <Carbon/Carbon.h>
00096     // Apple sucks!  AssertMacros.h defines these COMMONLY used names.
00097     #ifdef check
00098             #undef check
00099     #endif
00100     #ifdef verify
00101             #undef verify
00102     #endif // verify
00103     #ifdef require
00104             #undef require
00105     #endif
00106   #endif
00107 #endif // !LL_WINDOWS
00108 
00109 // Support for sending crash reports from the viewer?
00110 #define LL_SEND_CRASH_REPORTS 1
00111 
00112 
00113 //
00114 // Linden library headers
00115 //
00116 
00117 #include "audioengine.h" 
00118 #include "llcommon.h" 
00119 #include "llapr.h" 
00120 #include "llcachename.h"
00121 #include "llcurl.h"
00122 #include "llcriticaldamp.h"
00123 #include "lldir.h"
00124 #include "lleconomy.h"
00125 #include "llerrorcontrol.h"
00126 #include "llhttpnode.h"
00127 #include "llflexibleobject.h"
00128 #include "llfasttimer.h"
00129 #include "llfocusmgr.h"
00130 #include "llgroupmgr.h"
00131 #include "llimage.h"
00132 #include "llimageworker.h"
00133 #include "lllfsthread.h"
00134 #include "llmemtype.h"
00135 #include "llmd5.h"
00136 #include "llsecondlifeurls.h"
00137 #include "llversionviewer.h"
00138 #include "llvfile.h"
00139 #include "llvfs.h"
00140 #include "llwindow.h"           // for shell_open
00141 #include "llworkerthread.h"
00142 #include "llvfsthread.h"
00143 #include "llxfermanager.h"
00144 #include "message.h"
00145 #include "llvoavatar.h"
00146 #include "llglslshader.h"
00147 
00148 //
00149 // Viewer headers
00150 //
00151 
00152 #include "llagent.h"
00153 #include "llagentpilot.h"
00154 #include "llbutton.h" // For constants
00155 #include "llcallbacklist.h"
00156 #include "llchatbar.h"
00157 //#include "llcombobox.h" // For constants
00158 #include "llconsole.h"
00159 #include "llcontainerview.h"
00160 #include "lldebugview.h"
00161 #include "lldrawpoolbump.h"
00162 #include "lldrawpoolterrain.h"
00163 #include "lleventnotifier.h"
00164 #include "llfasttimerview.h"
00165 #include "llfeaturemanager.h"
00166 #include "llfirstuse.h"
00167 #include "llfloateravatarlist.h"
00168 #include "llfloateractivespeakers.h"
00169 #include "llfloatertools.h"
00170 #include "llfloaterworldmap.h"
00171 #include "llfloaterhtmlhelp.h"
00172 #include "llfloatersaveavatar.h"
00173 #include "llfloatersnapshot.h"
00174 #include "llfloatereventlog.h"
00175 #include "llfolderview.h"
00176 #include "llframestats.h"
00177 #include "llgesturemgr.h"
00178 #include "llhoverview.h"
00179 #include "llhudeffecttrail.h"
00180 #include "llhudmanager.h"
00181 #include "llhttpclient.h"
00182 #include "llimview.h"
00183 #include "llimpanel.h"
00184 #include "llinventorymodel.h"
00185 #include "llinventoryview.h"
00186 #include "llkeyboard.h"
00187 #include "llkeyframemotion.h"
00188 #include "llpanellogin.h"
00189 #include "llmutelist.h"
00190 #include "llmenugl.h"
00191 #include "llnamelistctrl.h"
00192 #include "llnamebox.h"
00193 #include "llnameeditor.h"
00194 #include "llpumpio.h"
00195 #include "llnotify.h"
00196 #include "llregionnamecache.h"
00197 #include "llselectmgr.h"
00198 #include "llsky.h"
00199 #include "llsrv.h"
00200 #include "llstartup.h"
00201 #include "llstatusbar.h"
00202 #include "llsurface.h"
00203 #include "lltexlayer.h"
00204 #include "lltexturecache.h"
00205 #include "lltexturefetch.h"
00206 #include "lltoolbar.h"
00207 #include "lltoolmgr.h"
00208 #include "lltracker.h"
00209 #include "lltrustnet.h"
00210 #include "llurldispatcher.h"
00211 #include "llurlsimstring.h"
00212 #include "llurlwhitelist.h"
00213 #include "llv4math.h"           // LL_VECTORIZE
00214 #include "llviewerbuild.h"
00215 #include "llviewercamera.h"
00216 #include "llviewercontrol.h"
00217 #include "llviewerjointmesh.h"
00218 #include "llviewerimagelist.h"
00219 #include "llviewerkeyboard.h"
00220 #include "llviewermenu.h"
00221 #include "llviewermessage.h"
00222 #include "llviewernetwork.h"
00223 #include "llviewerobjectlist.h"
00224 #include "llviewerparcelmgr.h"
00225 #include "llviewerregion.h"
00226 #include "llviewerstats.h"
00227 #include "llviewerthrottle.h"
00228 #include "llvieweruictrlfactory.h"
00229 #include "llviewerwindow.h"
00230 #include "llvlmanager.h"
00231 #include "llvoavatar.h"
00232 #include "llvograss.h"
00233 #include "llvotree.h"
00234 #include "llvovolume.h"         // To set a static member.
00235 #include "llvowater.h"
00236 #include "llvolume.h"
00237 #include "llvolumemgr.h"
00238 #include "llvolumemessage.h"
00239 #include "llweb.h"
00240 #include "llworld.h"
00241 #include "llworldmap.h"
00242 #include "llworldmapview.h"
00243 #include "pipeline.h"
00244 #include "llface.h"
00245 #include "audiosettings.h"
00246 #include "res/resource.h"
00247 #include "llvoiceclient.h"
00248 
00249 #if LL_WINDOWS
00250 #include "llwindebug.h"
00251 #include "lldxhardware.h"
00252 #include "llwindowwin32.h"
00253 
00254 // for Logitech LCD keyboards / speakers
00255 #ifndef LL_LOGITECH_LCD_H
00256 #include "lllogitechlcd.h"
00257 #endif
00258 extern void CreateLCDDebugWindows();
00259 
00260 #endif // LL_WINDOWS
00261 
00262 #if LL_QUICKTIME_ENABLED
00263 #if LL_DARWIN
00264 #include <QuickTime/QuickTime.h>
00265 #else
00266 // quicktime specific includes
00267 #include "MacTypes.h"
00268 #include "QTML.h"
00269 #include "Movies.h"
00270 #include "FixMath.h"
00271 #endif
00272 #endif
00273 
00274 #if LL_GSTREAMER_ENABLED
00275 // ugh, do this instead of pulling in the gstreamer headers which indirectly
00276 // clash with expat in the monster that is viewer.cpp ... sigh.
00277 void UnloadGStreamer();
00278 #endif // LL_GSTREAMER_ENABLED
00279 
00280 #include "llmediaengine.h"
00281 
00282 #if LL_LIBXUL_ENABLED
00283 #include "llmozlib.h"
00284 #endif // LL_LIBXUL_ENABLED
00285 
00287 // Support for crash handling.
00289 
00290 void errorCallback(const std::string &error_string);
00291 S32 gCrashBehavior = CRASH_BEHAVIOR_ASK;
00292 void (*gCrashCallback)(void) = NULL;
00293 BOOL gReportedCrash = FALSE;
00294 
00295 bool gVerifySSLCert = true;
00296 
00297 BOOL gHandleKeysAsync = FALSE;
00298 
00299 // Use DirectX 9 to probe for hardware
00300 BOOL gProbeHardware = TRUE;
00301 std::string gSerialNumber;
00302 
00304 // Application constants
00306 
00307 BOOL gAgentMovementCompleted = FALSE;
00308 BOOL gHaveSavedSnapshot = FALSE;
00309 
00310 S32 gYieldMS = 0;
00311 BOOL gYieldTime = FALSE;
00312 
00313 const U32 COLLISION_LIST_DEPTH = 300;   // only looks at the first so many collisionable objects
00314 const S32 MAX_CONSOLE_LINES = 500;
00315 const S32 NUM_SESSIONS_BEFORE_SHOW_PROFILE = 5;
00316 const F32 DEFAULT_AFK_TIMEOUT = 5.f * 60.f; // time with no input before user flagged as Away From Keyboard
00317 
00318 const char *VFS_DATA_FILE_BASE                  = "data.db2.x.";
00319 const char *VFS_INDEX_FILE_BASE                 = "index.db2.x.";
00320 
00321 F32 gSimLastTime;
00322 F32 gSimFrames;
00323 
00324 //#define RENDER_CLOUD_DENSITY          // uncomment to look at cloud density
00325 
00327 // Globals
00329 
00330 //
00331 // Core Application globals
00332 //
00333 #if LL_WINDOWS
00334 llLCD   *gLcdScreen = NULL; 
00335 #endif
00336 
00337 LLString gSecondLife;
00338 LLString gWindowTitle;
00339 static char sWindowClass[] = "Dale's Unofficial Viewer";
00340 LLString gDisabledMessage;
00341 BOOL gHideLinks = FALSE;
00342 
00343 // This is whether or not we are connect to a production grid.
00344 BOOL gInProductionGrid  = FALSE;
00345 
00346 //#define APPLE_PREVIEW // Define this if you're doing a preview build on the Mac
00347 #if LL_RELEASE_FOR_DOWNLOAD
00348 // Default userserver for production builds is agni
00349 #ifndef APPLE_PREVIEW
00350 static EUserServerDomain UserServerDefaultChoice = USERSERVER_AGNI;
00351 #else
00352 static EUserServerDomain UserServerDefaultChoice = USERSERVER_ADITI;
00353 #endif
00354 #else
00355 // Default userserver for development builds is dmz
00356 static EUserServerDomain UserServerDefaultChoice = USERSERVER_DMZ;
00357 #endif
00358 
00359 #ifdef TOGGLE_HACKED_GODLIKE_VIEWER
00360 BOOL                            gHackGodmode = FALSE;
00361 #endif
00362 
00363 std::vector<std::string>        gLoginURIs;
00364 static std::string      gHelperURI;
00365 
00366 LLAgent                         gAgent;
00367 LLPipeline                      gPipeline;
00368 
00369 // Set true when the viewer has been disconnected from the server, for example,
00370 // by the user being kicked.
00371 BOOL                            gDoDisconnect = FALSE;
00372 BOOL                            gDisconnected = FALSE;
00373 
00374 // Tells us to clean up the cache directory in the case of network corruption
00375 BOOL                            gPurgeOnExit = FALSE;
00376 BOOL                            gPurgeCache = FALSE;
00377 
00378 // Allow multiple viewers in ReleaseForDownload
00379 #if LL_RELEASE_FOR_DOWNLOAD
00380 BOOL                            gMultipleViewersOK = FALSE;
00381 #else
00382 BOOL                            gMultipleViewersOK = TRUE;
00383 #endif
00384 BOOL                            gSecondInstance = FALSE;
00385 BOOL                            gDisableVoice = FALSE;
00386 
00387 LLString                        gArgs;
00388 
00389 // Setting this true will cause the app to exit cleanly at the end of the frame.
00390 BOOL                            gQuit = FALSE;
00391 // Set when user has indicated desire to quit, but may have modified documents open
00392 BOOL                            gQuitRequested = FALSE;
00393 LLString                        gLaunchFileOnQuit;
00394 BOOL                            gDoneLogout = FALSE;
00395 
00396 BOOL                            gInitializationComplete = FALSE;        // used in windows handlers to determine if OK to call idle()
00397 BOOL                            gAutoLogin = FALSE;
00398 LLString                        gOldSettingsFileName;
00399 BOOL                            gPrintMessagesThisFrame = FALSE;
00400 const char*                     DEFAULT_SETTINGS_FILE = "settings_dale.xml";
00401 const char*                     LEGACY_DEFAULT_SETTINGS_FILE = "settings_dale.ini";
00402 BOOL                            gUseWireframe = FALSE;
00403 LLUUID                          gViewerDigest;  // MD5 digest of the viewer's executable file.
00404 LLPumpIO*                       gServicePump = NULL;
00405 S32                                     gNumSessions = 0;
00406 
00407 BOOL                            gAllowIdleAFK = TRUE;
00408 F32                                     gAFKTimeout = DEFAULT_AFK_TIMEOUT;
00409 F32                                     gMouseSensitivity = 3.f;
00410 BOOL                            gInvertMouse = FALSE;
00411 BOOL                            gLogoutRequestSent = FALSE;
00412 LLTimer                         gLogoutTimer;
00413 BOOL                            gShowObjectUpdates = FALSE;
00414 
00415 const F32                       LOGOUT_REQUEST_TIME = 6.f;  // this will be cut short by the LogoutReply msg.
00416 F32                                     gLogoutMaxTime = LOGOUT_REQUEST_TIME;
00417 
00418 // Map scale in pixels per region
00419 F32                             gMapScale = 128.f;
00420 F32                             gMiniMapScale = 128.f;
00421 
00422 // Sky object, globals
00423 LLSky                           gSky;
00424 
00425 // HUD display lines in lower right
00426 BOOL                            gDisplayWindInfo = FALSE;
00427 BOOL                            gDisplayCameraPos = FALSE;
00428 BOOL                            gDisplayNearestWater = FALSE;
00429 BOOL                            gDoNearestWaterSearch = FALSE;
00430 BOOL                            gDisplayFOV = FALSE;
00431 
00432 // used to restore texture state after a mode switch
00433 LLFrameTimer    gRestoreGLTimer;
00434 BOOL                    gRestoreGL = FALSE;
00435 
00436 
00437 // VFS globals - see viewer.h
00438 LLVFS* gStaticVFS = NULL;
00439 
00440 // Threads
00441 LLTextureCache* gTextureCache = NULL;
00442 LLWorkerThread* gImageDecodeThread = NULL;
00443 LLTextureFetch* gTextureFetch = NULL;
00444 
00445 // Debugging
00446 FILE *gDebugFile = NULL;        // File pointer used by the function which writes debug data.
00447 BOOL gRandomizeFramerate = FALSE;
00448 BOOL gPeriodicSlowFrame = FALSE;
00449 std::map<S32,LLFrameTimer> gDebugTimers;
00450 
00451 //LLVector3                     gCameraVelocitySmoothed;
00452 //
00453 // Timing/Performance/statistics globals
00454 //
00455 
00456 // Frame timing
00457 U64 gFrameTime = 0;
00458 F32 gFrameTimeSeconds = 0.f;
00459 F32 gFrameIntervalSeconds = 0.f;
00460 U32     gFrameCount = 0;
00461 U32 gForegroundFrameCount = 0; // number of frames that app window was in foreground
00462 U64     gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds
00463 U64     gSpaceTime = 0; // gSpaceTime is the time, according to the spaceserver.
00464 
00465 //  Timing Globals
00466 LLTimer gRenderStartTime;
00467 LLFrameTimer gForegroundTime;
00468 F32 gQuitAfterSeconds = 0.f;
00469 BOOL gRotateRight = FALSE;
00470 
00471 // Is the Pacific time zone (aka server time zone)
00472 // current in daylight savings time?
00473 BOOL gPacificDaylightTime = FALSE;
00474 
00475 //
00476 // Simulator/SpaceServer configuration information
00477 //
00478 U32     gSecondsPerDay = 0;
00479 U32     gSecondsPerYear = 0;
00480 
00481 LLString gLastVersionChannel;
00482 
00483 //
00484 // Region/Object globals
00485 //
00486 
00487 
00488 LLVector3                       gWindVec(3.0, 3.0, 0.0);
00489 LLVector3                       gRelativeWindVec(0.0, 0.0, 0.0);
00490 
00491 //
00492 // Globals for controls...
00493 //
00494 
00495 BOOL gVelocityInterpolate = TRUE; //  (These are written once/frame with the data from gSavedSettings)
00496 BOOL gPingInterpolate = TRUE; 
00497 
00498 //
00499 // System info
00500 //
00501 
00502 LLMemoryInfo gSysMemory;
00503 LLOSInfo gSysOS;
00504 
00505 // file globals
00506 static const char USAGE[] = "\n"
00507 "usage:\tviewer [options]\n"
00508 "options:\n"
00509 " -login <first> <last> <password>     log in as a user\n"
00510 " -autologin                           log in as last saved user\n"
00511 " -loginuri <URI>                      login server and CGI script to use\n"
00512 " -helperuri <URI>                     helper web CGI prefix to use\n"
00513 " -settings <filename>                 specify the filename of a\n"
00514 "                                        configuration file\n"
00515 "                                        default is settings.xml\n"
00516 " -setdefault <variable> <value>       specify the value of a particular\n"
00517 "                                        configuration variable which can be\n"
00518 "                                        overridden by settings.xml\n"
00519 " -set <variable> <value>              specify the value of a particular\n"
00520 "                                        configuration variable that\n"
00521 "                                        overrides all other settings\n"
00522 " -user <user_server_ip>               specify userserver in dotted quad\n"
00523 #if !LL_RELEASE_FOR_DOWNLOAD
00524 " -sim <simulator_ip>                  specify the simulator ip address\n"
00525 #endif
00526 " -god                                     log in as god if you have god access\n"
00527 " -purge                               delete files in cache\n"
00528 " -safe                                reset preferences, run in safe mode\n"
00529 " -noutc                               logs in local time, not UTC\n"
00530 " -nothread                            run vfs in single thread\n"
00531 " -noinvlib                            Do not request inventory library\n"
00532 " -multiple                            allow multiple viewers\n"
00533 " -nomultiple                          block multiple viewers\n"
00534 " -novoice                             disable voice\n"
00535 " -ignorepixeldepth                    ignore pixel depth settings\n"
00536 " -cooperative [ms]                    yield some idle time to local host\n"
00537 " -skin                                ui/branding skin folder to use\n"
00538 #if LL_WINDOWS
00539 " -noprobe                             disable hardware probe\n"
00540 #endif
00541 " -noquicktime                         disable QuickTime movies, speeds startup\n"
00542 " -nopreload                           don't preload UI images or sounds, speeds startup\n"
00543 // these seem to be unused
00544 //" -noenv                               turn off environmental effects\n"
00545 //" -proxy <proxy_ip>                    specify the proxy ip address\n"
00546 "\n";
00547 
00548 
00549 // Variables used for passing data out of main
00550 BOOL gGodConnect = FALSE;
00551 BOOL gUseConsole = TRUE;
00552 BOOL gUseAudio = TRUE;
00553 BOOL gUseFMOD = TRUE;
00554 BOOL gLogMessages = FALSE;
00555 BOOL gRequestInventoryLibrary = TRUE;
00556 BOOL gAcceptTOS = FALSE;
00557 BOOL gAcceptCriticalMessage = FALSE;
00558 // this is the channel the viewer uses to check for updates/login
00559 std::string gChannelName = LL_CHANNEL;
00560 
00561 LLUUID gInventoryLibraryOwner;
00562 LLUUID gInventoryLibraryRoot;
00563 bool gPreloadImages = true;
00564 bool gPreloadSounds = true;
00565 
00566 LLString gCmdLineFirstName;
00567 LLString gCmdLineLastName;
00568 LLString gCmdLinePassword;
00569 std::map<std::string, std::string> gCommandLineSettings;
00570 std::map<std::string, std::string> gCommandLineForcedSettings;
00571 BOOL gLastExecFroze = FALSE;
00572 BOOL gIgnorePixelDepth = FALSE;
00573 
00574 
00575 LLPointer<LLImageGL> gDisconnectedImagep = NULL;
00576 
00577 
00578 /*
00579 class LLFirstInventoryLoadObserver : public LLInventoryObserver
00580 {
00581         // Called when the inventory is first loaded.
00582         // Must be allocated on the heap so that the inventory model can destroy it 
00583         // in case the app ends before the inventory finishes loading.
00584 public:
00585         virtual void changed(U32 mask);
00586         void observe(LLInventoryModel* model);
00587 protected:
00588         LLInventoryModel* mInventory;
00589 };
00590 */
00591 
00593 //
00594 // Forward declarations
00595 //
00596 
00597 //
00598 // Application initialization and cleanup
00599 //
00600 void init_marker_file();
00601 void init_crash_handler();
00602 void init_logging();
00603 void create_console();
00604 void write_system_info();
00605 int parse_args(int argc, char **argv);
00606 void saved_settings_to_globals();
00607 BOOL init_cache();
00608 void purge_cache();
00609 void cleanup_app();
00610 void disconnect_viewer(void *); // Don't use directly - use do_disconnect()
00611 
00612 //
00613 // Debugging, logging, and error reporting
00614 //
00615 void write_debug(const char *str);      // Write a string to the debug log
00616 void write_debug(const std::string& str);
00617 void close_debug();                                     // Close the debug log
00618 void catch_signals();
00619 void viewer_crash_callback();
00620 void remove_marker_file();
00621 #if !LL_WINDOWS
00622 void release_signals();
00623 #endif
00624 
00625 void bad_network_handler();
00626 
00627 #if LL_WINDOWS
00628 void disable_win_error_reporting();
00629 #endif
00630 std::string get_serial_number();
00631 bool send_url_to_other_instance(const std::string& url);
00632 BOOL another_instance_running();
00633 void main_loop();
00634 
00635 //
00636 // Callbacks
00637 //
00638 // Callbacks and other stuff that's not directly used in main
00639 //
00640 void uuid_table_request_file_callback(void **user_data, S32 result, LLExtStat ext_status);
00641 void send_stats();
00642 
00643 //
00644 // Apple specific stuff
00645 //
00646 #if LL_DARWIN
00647 void init_apple_menu(const char* product);
00648 OSErr AEGURLHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn);
00649 OSErr AEQuitHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn);
00650 OSStatus simpleDialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata);
00651 OSStatus DisplayReleaseNotes(void);
00652 #endif // LL_DARWIN
00653 
00654 void ui_audio_callback(const LLUUID& uuid)
00655 {
00656         if (gAudiop)
00657         {
00658                 F32 volume = gSavedSettings.getF32("AudioLevelUI");
00659                 gAudiop->triggerSound(uuid, gAgent.getID(), volume);
00660         }
00661 }
00662 
00663 #if LL_WINDOWS
00664 BOOL CALLBACK login_dialog_func(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lparam)
00665 {
00666         char buffer[MAX_STRING];                /* Flawfinder: ignore */
00667         switch(msg)
00668         {
00669     case WM_INITDIALOG:
00670                 {
00671                         LLString first_name = gCmdLineFirstName;
00672                         LLString last_name = gCmdLineLastName;
00673                         LLString password = gCmdLinePassword;
00674 
00675                         if (!first_name.empty())
00676                         {
00677                                 SetDlgItemTextA( hwnd, IDC_EDIT_FIRSTNAME, first_name.c_str());
00678                         }
00679                         if (!last_name.empty())
00680                         {
00681                                 SetDlgItemTextA( hwnd, IDC_EDIT_LASTNAME, last_name.c_str());
00682                         }
00683                         if (!password.empty())
00684                         {
00685                                 SetDlgItemTextA( hwnd, IDC_EDIT_PASSWORD, password.c_str());
00686                         }
00687 
00688                         first_name = gSavedSettings.getString("FirstName");
00689                         last_name = gSavedSettings.getString("LastName");
00690                         password = load_password_from_disk();
00691 
00692                         if (!first_name.empty())
00693                         {
00694                                 SetDlgItemTextA( hwnd, IDC_EDIT_FIRSTNAME, first_name.c_str());
00695                         }
00696                         if (!last_name.empty())
00697                         {
00698                                 SetDlgItemTextA( hwnd, IDC_EDIT_LASTNAME, last_name.c_str());
00699                         }
00700                         if (!password.empty())
00701                         {
00702                                 SetDlgItemTextA( hwnd, IDC_EDIT_PASSWORD, password.c_str());
00703                         }
00704 
00705                         // Focus on password if other fields are full
00706                         if (first_name.empty())
00707                         {
00708                                 SetFocus(GetDlgItem(hwnd, IDC_EDIT_FIRSTNAME)); 
00709                         }
00710                         else if (last_name.empty())
00711                         {
00712                                 SetFocus(GetDlgItem(hwnd, IDC_EDIT_LASTNAME)); 
00713                         }
00714                         else if (password.empty())
00715                         {
00716                                 SetFocus(GetDlgItem(hwnd, IDC_EDIT_PASSWORD)); 
00717                         }
00718                         else
00719                         {
00720                                 SetFocus(GetDlgItem(hwnd, IDC_EDIT_FIRSTNAME)); 
00721                         }
00722 
00723                         BOOL remember_password = gSavedSettings.getBOOL("RememberPassword");
00724                         if (remember_password)
00725                         {
00726                                 CheckDlgButton(hwnd, IDC_REMEMBER_PASSWORD, BST_CHECKED);
00727                         }
00728                         else
00729                         {
00730                                 CheckDlgButton(hwnd, IDC_REMEMBER_PASSWORD, BST_UNCHECKED);
00731                         }
00732                         return TRUE;
00733                 }
00734 
00735         case WM_COMMAND:
00736                 switch(LOWORD(wParam))
00737                 {
00738                 case IDOK:
00739                         {
00740                                 // copy login name and password into buffer
00741                                 if (GetDlgItemTextA(hwnd, IDC_EDIT_FIRSTNAME, buffer, MAX_STRING))
00742                                 {
00743                                         gCmdLineFirstName = buffer;
00744                                 }
00745                                 if (GetDlgItemTextA(hwnd, IDC_EDIT_LASTNAME, buffer, MAX_STRING))
00746                                 {
00747                                         gCmdLineLastName = buffer;
00748                                 }
00749                                 if (GetDlgItemTextA(hwnd, IDC_EDIT_PASSWORD, buffer, MAX_STRING))
00750                                 {
00751                                         gCmdLinePassword = buffer;
00752                                 }
00753                                 BOOL remember_password = (IsDlgButtonChecked(hwnd, IDC_REMEMBER_PASSWORD) == BST_CHECKED);
00754                                 gSavedSettings.setBOOL("RememberPassword", remember_password);
00755                                 EndDialog(hwnd, 0);     // return success
00756                                 return TRUE;    // handled
00757                         }
00758                 }
00759                 // If we get here, we didn't handle it
00760                 return FALSE;
00761 
00762         case WM_CLOSE:
00763         case WM_DESTROY:
00764                 EndDialog(hwnd, 666);   // assume user wants normal login screen
00765                 return TRUE;    // handled
00766 
00767         default:
00768                 return FALSE;
00769         }
00770 }
00771 #endif
00772 
00773 #if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
00774 
00775 MEM_BOOL MEM_CALLBACK second_mem_error_handler(MEM_ERROR_INFO *errorInfo);
00776 
00777 MEM_BOOL MEM_CALLBACK first_mem_error_handler(MEM_ERROR_INFO *errorInfo)
00778 {
00779     MemSetErrorHandler(second_mem_error_handler);
00780 
00781         // Really should free up reserved memory here and warn users
00782         // with dialog they have precious little time left in Second
00783         // Life!
00784 
00785         llerrs << "Memory allocation failed; aborting." << llendl;
00786         // llerrs << "Memory allocation failed; reserve memory released." << llendl;
00787 
00788         // NOTREACHED better not be, but see second_mem_error_handler
00789         // Could do that freeing up reserved memory thing here and
00790         // return 1;
00791         return 0;
00792 }
00793 
00794 MEM_BOOL MEM_CALLBACK second_mem_error_handler(MEM_ERROR_INFO *errorInfo)
00795 {
00796         // Just in case "llerrs" and "llendl" cause another out-of-memory.
00797         LLError::crashAndLoop("");
00798         // NOTREACHED better not be!
00799         return 0;
00800 }
00801 
00802 #endif // LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
00803 
00804 
00805 #if LL_WINDOWS
00806 int APIENTRY WinMain(HINSTANCE hInstance,
00807                      HINSTANCE hPrevInstance,
00808                      LPSTR     lpCmdLine,
00809                      int       nCmdShow)
00810 #else 
00811 int main( int argc, char **argv ) 
00812 #endif
00813 {
00814         LLMemType mt1(LLMemType::MTYPE_STARTUP);
00815 
00816 #if LL_SOLARIS && defined(__sparc)
00817         asm ("ta\t6");           // NOTE:  Make sure memory alignment is enforced on SPARC
00818 #endif
00819 
00820 #if LL_DARWIN
00821         // Set the working dir to <bundle>/Contents/Resources
00822         (void) chdir(gDirUtilp->getAppRODataDir().c_str());
00823 #endif
00824         
00825 #if 1
00826         // This will eventually be done in LLApp
00827         LLCommon::initClass();
00828         // This should eventually be done in LLAppViewer
00829 # if MEM_TRACK_MEM
00830         static const bool enable_threads = false;
00831 # else
00832         static const bool enable_threads = true;
00833 # endif
00834         LLVFSThread::initClass(enable_threads && true);
00835         LLLFSThread::initClass(enable_threads && true);
00836         // Image decoding
00837         gImageDecodeThread = new LLWorkerThread("ImageDecode", enable_threads && true);
00838         gTextureCache = new LLTextureCache(enable_threads && true);
00839         gTextureFetch = new LLTextureFetch(gTextureCache, enable_threads && false);
00840         LLImageWorker::initClass(gImageDecodeThread);
00841         LLImageJ2C::openDSO();
00842 #endif
00843 
00844 #if LL_WINDOWS
00845         // In Win32, we need to generate argc and argv ourselves...
00846         // Note: GetCommandLine() returns a  potentially return a LPTSTR
00847         // which can resolve to a LPWSTR (unicode string).
00848         // (That's why it's different from lpCmdLine which is a LPSTR.)
00849         // We don't currently do unicode, so call the non-unicode version
00850         // directly.
00851         LPSTR cmd_line_including_exe_name = GetCommandLineA();
00852 
00853         gIconResource = MAKEINTRESOURCE(IDI_LL_ICON);
00854 
00855         const S32       MAX_ARGS = 100;
00856         int argc = 0;
00857         char* argv[MAX_ARGS];           /* Flawfinder: ignore */
00858 
00859         char *token = NULL;
00860         if( cmd_line_including_exe_name[0] == '\"' )
00861         {
00862                 // Exe name is enclosed in quotes
00863                 token = strtok( cmd_line_including_exe_name, "\"" );
00864                 argv[argc++] = token;
00865                 token = strtok( NULL, " \t," );
00866         }
00867         else
00868         {
00869                 // Exe name is not enclosed in quotes
00870                 token = strtok( cmd_line_including_exe_name, " \t," );
00871         }
00872 
00873         while( (token != NULL) && (argc < MAX_ARGS) )
00874         {
00875                 argv[argc++] = token;
00876                 /* Get next token: */
00877                 if (*(token + strlen(token) + 1) == '\"')               /* Flawfinder: ignore*/
00878                 {
00879                         token = strtok( NULL, "\"");
00880                 }
00881                 else
00882                 {
00883                         token = strtok( NULL, " \t," );
00884                 }
00885         }
00886 #endif
00887 
00888         // HACK! We REALLY want to know what grid they were trying to connect to if they
00889         // crashed hard.
00890         // So we walk through the command line args ONLY looking for the
00891         // userserver arguments first.  And we don't do ANYTHING but set
00892         // the gUserServerName (which gets passed to the crash reporter).
00893         // We're assuming that they're trying to log into the same grid as last
00894         // time, which seems fairly reasonable.
00895         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[UserServerDefaultChoice].mName);              /* Flawfinder: ignore */
00896         S32 j;
00897         for (j = 1; j < argc; j++) 
00898         {
00899                 if (!strcmp(argv[j], "--aditi"))
00900                 {
00901                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[USERSERVER_ADITI].mName);             /* Flawfinder: ignore */
00902                 }
00903                 else if (!strcmp(argv[j], "--agni"))
00904                 {
00905                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[USERSERVER_AGNI].mName);              /* Flawfinder: ignore */
00906                 }
00907                 else if (!strcmp(argv[j], "--dmz"))
00908                 {
00909                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[USERSERVER_DMZ].mName);               /* Flawfinder: ignore */
00910                 }
00911                 else if (!strcmp(argv[j], "--siva"))
00912                 {
00913                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[USERSERVER_SIVA].mName);              /* Flawfinder: ignore */
00914                 }
00915                 else if (!strcmp(argv[j], "--shakti"))
00916                 {
00917                         sprintf(gUserServerName,"%s", gUserServerDomainName[USERSERVER_SHAKTI].mName);
00918                 }
00919                 else if (!strcmp(argv[j], "--durga"))
00920                 {
00921                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[USERSERVER_DURGA].mName);             /* Flawfinder: ignore */
00922                 }
00923                 else if (!strcmp(argv[j], "--soma"))
00924                 {
00925                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[USERSERVER_SOMA].mName);              /* Flawfinder: ignore */
00926                 }
00927                 else if (!strcmp(argv[j], "--ganga"))
00928                 {
00929                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[USERSERVER_GANGA].mName);             /* Flawfinder: ignore */
00930                 }
00931                 else if (!strcmp(argv[j], "--vaak"))
00932                 {
00933                         sprintf(gUserServerName,"%s", gUserServerDomainName[USERSERVER_VAAK].mName);
00934                 }
00935                 else if (!strcmp(argv[j], "--uma"))
00936                 {
00937                         sprintf(gUserServerName,"%s", gUserServerDomainName[USERSERVER_UMA].mName);
00938                 }
00939                 else if (!strcmp(argv[j], "-user") && (++j < argc))
00940                 {
00941                         if (!strcmp(argv[j], "-"))
00942                         {
00943                                 snprintf(gUserServerName, MAX_STRING, "%s", LOOPBACK_ADDRESS_STRING);           /* Flawfinder: ignore */
00944                         }
00945                         else
00946                         {
00947                                 snprintf(gUserServerName, MAX_STRING, "%s", argv[j]);           /* Flawfinder: ignore */
00948                         }
00949                 }
00950                 else if (!strcmp(argv[j], "-multiple"))
00951                 {
00952                         // Hack to detect -multiple so we can disable the marker file check (which will always fail)
00953                         gMultipleViewersOK = TRUE;
00954                 }
00955                 else if (!strcmp(argv[j], "-novoice"))
00956                 {
00957                         // May need to know this early also
00958                         gDisableVoice = TRUE;
00959                 }
00960         }
00961 
00962         //
00963         // Start of the application
00964         //
00965         // IMPORTANT! Do NOT put anything that will write
00966         // into the log files during normal startup until AFTER
00967         // we run the "program crashed last time" error handler below.
00968         //
00969 
00970         // Need to do this initialization before we do anything else, since anything
00971         // that touches files should really go through the lldir API
00972         gDirUtilp->initAppDirs("SecondLife");
00973 
00974         //
00975         // Set up logging defaults for the viewer
00976         //
00977         LLError::initForApplication(
00978                                 gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
00979         LLError::setFatalFunction(errorCallback);
00980 
00981 
00982 #if LL_RELEASE_FOR_DOWNLOAD && LL_SEND_CRASH_REPORTS
00983         //
00984         // Crash log if we hard crashed.
00985         // Initialize crash logging
00986         //
00987         init_crash_handler();
00988 #endif
00989         // Set up SecondLife.log
00990         init_logging();
00991         
00992         //
00993         // OK to write stuff to logs now, we've now crash reported if necessary
00994         //
00995 
00996         // Set up some defaults...
00997         gSettingsFileName = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, DEFAULT_SETTINGS_FILE);
00998         gOldSettingsFileName = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, LEGACY_DEFAULT_SETTINGS_FILE);
00999 
01001         //
01002         // Process command line arguments
01003         //
01004         S32 args_result = 0;
01005 
01006 #if LL_DARWIN
01007         {
01008                 // On the Mac, read in arguments.txt (if it exists) and process it for additional arguments.
01009                 std::string args;
01010                 if(_read_file_into_string(args, "arguments.txt"))
01011                 {
01012                         // The arguments file exists.  
01013                         // It should consist of command line arguments separated by newlines.
01014                         // Split it into individual arguments and build a fake argv[] to pass to parse_args.
01015                         std::vector<std::string> arglist;
01016                         
01017                         arglist.push_back("newview");
01018                         
01019                         llinfos << "Reading additional command line arguments from arguments.txt..." << llendl;
01020                         
01021                         typedef boost::tokenizer<boost::escaped_list_separator<char> > tokenizer;
01022                         boost::escaped_list_separator<char> sep("\\", "\r\n ", "\"'");
01023                         tokenizer tokens(args, sep);
01024                         tokenizer::iterator token_iter;
01025 
01026                         for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter)
01027                         {
01028                                 llinfos << "argument: '" << (token_iter->c_str()) << "'" << llendl;
01029                                 
01030                                 arglist.push_back(*token_iter);
01031                         }
01032 
01033                         char **fakeargv = new char*[arglist.size()];
01034                         int i;
01035                         for(i=0; i < arglist.size(); i++)
01036                                 fakeargv[i] = const_cast<char*>(arglist[i].c_str());
01037                                 
01038                         args_result = parse_args(arglist.size(), fakeargv);
01039                         delete[] fakeargv;
01040                 }
01041                 
01042                 // Get the user's preferred language string based on the Mac OS localization mechanism.
01043                 // To add a new localization:
01044                         // go to the "Resources" section of the project
01045                         // get info on "language.txt"
01046                         // in the "General" tab, click the "Add Localization" button
01047                         // create a new localization for the language you're adding
01048                         // set the contents of the new localization of the file to the string corresponding to our localization
01049                         //   (i.e. "en-us", "ja", etc.  Use the existing ones as a guide.)
01050                 CFURLRef url = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("language"), CFSTR("txt"), NULL);
01051                 char path[MAX_PATH];
01052                 if(CFURLGetFileSystemRepresentation(url, false, (UInt8 *)path, sizeof(path)))
01053                 {
01054                         std::string lang;
01055                         if(_read_file_into_string(lang, path))
01056                         {
01057                                 gCommandLineForcedSettings["SystemLanguage"] = lang;
01058                         }
01059                 }
01060                 CFRelease(url);
01061         }
01062 #endif
01063 
01064         //
01065         // Parse the command line arguments
01066         //
01067         args_result |= parse_args(argc, argv);
01068         if (args_result)
01069         {
01070                 remove_marker_file();
01071                 return args_result;
01072         }
01073 
01074         if (!strcmp(gUserServerName, gUserServerDomainName[USERSERVER_AGNI].mName))
01075         {
01076                 gInProductionGrid = TRUE;
01077         }
01078 
01079         // *TODO:translate
01080         gSecondLife = "Second Life (Dale's Unofficial Viewer)";
01081         
01082         // Read skin/branding settings if specified.
01083         if (! gDirUtilp->getSkinDir().empty() )
01084         {
01085                 std::string skin_def_file = gDirUtilp->getExpandedFilename(LL_PATH_TOP_SKIN, "skin.xml");
01086                 LLXmlTree skin_def_tree;
01087 
01088                 if (!skin_def_tree.parseFile(skin_def_file))
01089                 {
01090                         llerrs << "Failed to parse skin definition." << llendl;
01091                 }
01092 
01093                 LLXmlTreeNode* rootp = skin_def_tree.getRoot();
01094                 LLXmlTreeNode* disabled_message_node = rootp->getChildByName("disabled_message");       
01095                 if (disabled_message_node)
01096                 {
01097                         gDisabledMessage = disabled_message_node->getContents();
01098                 }
01099 
01100                 static LLStdStringHandle hide_links_string = LLXmlTree::addAttributeString("hide_links");
01101                 rootp->getFastAttributeBOOL(hide_links_string, gHideLinks);
01102 
01103                 // Legacy string.  This flag really meant we didn't want to expose references to "Second Life".
01104                 // Just set gHideLinks instead.
01105                 static LLStdStringHandle silent_string = LLXmlTree::addAttributeString("silent_update");
01106                 BOOL silent_update;
01107                 rootp->getFastAttributeBOOL(silent_string, silent_update);
01108                 gHideLinks = (gHideLinks || silent_update);
01109         }
01110 
01111 #if LL_DARWIN
01112         // Initialize apple menubar and various callbacks
01113         init_apple_menu(gSecondLife.c_str());
01114 
01115 #if __ppc__
01116         // If the CPU doesn't have Altivec (i.e. it's not at least a G4), don't go any further.
01117         // Only test PowerPC - all Intel Macs have SSE.
01118         if(!gSysCPU.hasAltivec())
01119         {
01120                 std::ostringstream msg;
01121                 msg << gSecondLife << " requires a processor with AltiVec (G4 or later).";
01122                 OSMessageBox(
01123                         msg.str().c_str(),
01124                         NULL,
01125                         OSMB_OK);
01126                 remove_marker_file();
01127                 return 1;
01128         }
01129 #endif
01130         
01131 #endif // LL_DARWIN
01132 
01133         // Display splash screen.  Must be after above check for previous
01134         // crash as this dialog is always frontmost.
01135         std::ostringstream splash_msg;
01136         // *TODO:translate
01137         splash_msg << "Loading " << gSecondLife << "...";
01138         LLSplashScreen::show();
01139         LLSplashScreen::update(splash_msg.str().c_str());
01140 
01141         LLVolumeMgr::initClass();
01142 
01143         // Initialize the feature manager
01144         // The feature manager is responsible for determining what features
01145         // are turned on/off in the app.
01146         gFeatureManagerp = new LLFeatureManager;
01147 
01148         gStartTime = totalTime();
01149 
01150 
01152         //
01153         // Process ini files
01154         //
01155 
01156         // declare all possible setting variables
01157         declare_settings();
01158 
01159 #if !LL_RELEASE_FOR_DOWNLOAD
01160 //      only write the defaults for non-release builds!
01161         gSavedSettings.saveToFile(gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,"settings_default.xml").c_str(), FALSE);
01162 #endif
01163 
01164         //
01165         // Set the name of the window
01166         //
01167 #if LL_RELEASE_FOR_DOWNLOAD
01168         gWindowTitle = gSecondLife;
01169 #elif LL_DEBUG
01170         gWindowTitle = gSecondLife + LLString(" [DEBUG] ") + gArgs;
01171 #else
01172         gWindowTitle = gSecondLife + LLString(" ") + gArgs;
01173 #endif
01174         LLString::truncate(gWindowTitle, 255);
01175 
01176         if (!gMultipleViewersOK)
01177         {
01178             //
01179             // Check for another instance of the app running
01180             //
01181 
01182                 // RN: if we received a URL, hand it off to the existing instance
01183                 // don't call another_instance_running() when doing URL handoff, as
01184                 // it relies on checking a marker file which will not work when running
01185                 // out of different directories
01186                 std::string slurl;
01187                 if (!LLStartUp::sSLURLCommand.empty())
01188                 {
01189                         slurl = LLStartUp::sSLURLCommand;
01190                 }
01191                 else if (LLURLSimString::parse())
01192                 {
01193                         slurl = LLURLSimString::getURL();
01194                 }
01195                 if (!slurl.empty())
01196                 {
01197                         if (send_url_to_other_instance(slurl))
01198                         {
01199                                 // successfully handed off URL to existing instance, exit
01200                                 return 1;
01201                         }
01202                 }
01203                 
01204                 gSecondInstance = another_instance_running();
01205                 
01206                 if (gSecondInstance)
01207                 {
01208                         std::ostringstream msg;
01209                         msg << 
01210                                 gSecondLife << " is already running.\n"
01211                                 "\n"
01212                                 "Check your task bar for a minimized copy of the program.\n"
01213                                 "If this message persists, restart your computer.",
01214                         OSMessageBox(
01215                                 msg.str().c_str(),
01216                                 NULL,
01217                                 OSMB_OK);
01218                         return 1;
01219                 }
01220 
01221                 init_marker_file();
01222 
01223 #if LL_SEND_CRASH_REPORTS
01224                 if (gLastExecFroze)
01225                 {
01226                         llinfos << "Last execution froze, requesting to send crash report." << llendl;
01227                         //
01228                         // Pop up a freeze or crash warning dialog
01229                         //
01230                         std::ostringstream msg;
01231                         msg << gSecondLife
01232                                 << " appears to have frozen or crashed on the previous run.\n"
01233                                 << "Would you like to send a crash report?";
01234                         std::string alert;
01235                         alert = gSecondLife;
01236                         alert += " Alert";
01237                         S32 choice = OSMessageBox(msg.str().c_str(),
01238                                 alert.c_str(),
01239                                 OSMB_YESNO);
01240                         if (OSBTN_YES == choice)
01241                         {
01242                                 llinfos << "Sending crash report." << llendl;
01243 
01244                                 remove_marker_file();
01245 #if LL_WINDOWS
01246                                 std::string exe_path = gDirUtilp->getAppRODataDir();
01247                                 exe_path += gDirUtilp->getDirDelimiter();
01248                                 exe_path += "win_crash_logger.exe";
01249 
01250                                 std::string arg_string = "-previous -user ";
01251                                 arg_string += gUserServerName;
01252                                 arg_string += " -name \"";
01253                                 arg_string += gSecondLife;
01254                                 arg_string += "\"";
01255                                 // Spawn crash logger.
01256                                 // NEEDS to wait until completion, otherwise log files will get smashed.
01257                                 _spawnl(_P_WAIT, exe_path.c_str(), exe_path.c_str(), arg_string.c_str(), NULL);
01258 #elif LL_DARWIN
01259                                 std::string command_str;
01260                                 command_str = "crashreporter.app/Contents/MacOS/crashreporter ";
01261                                 command_str += "-previous -user ";
01262                                 command_str += gUserServerName;
01263                                 // XXX -- We need to exit fullscreen mode for this to work.
01264                                 // XXX -- system() also doesn't wait for completion.  Hmm...
01265                                 system(command_str.c_str());            /* Flawfinder: Ignore */
01266 #elif LL_LINUX || LL_SOLARIS
01267                                 std::string cmd =gDirUtilp->getAppRODataDir();
01268                                 cmd += gDirUtilp->getDirDelimiter();
01269 #if LL_LINUX
01270                                 cmd += "linux-crash-logger.bin";
01271 #else // LL_SOLARIS
01272                                 cmd += "bin/solaris-crash-logger";
01273 #endif
01274                                 char* const cmdargv[] =
01275                                         {(char*)cmd.c_str(),
01276                                          (char*)"-previous",
01277                                          (char*)"-user",
01278                                          (char*)gUserServerName,
01279                                          (char*)"-name",
01280                                          (char*)gSecondLife.c_str(),
01281                                          NULL};
01282                                 fflush(NULL);
01283                                 pid_t pid = fork();
01284                                 if (pid == 0)
01285                                 { // child
01286                                         execv(cmd.c_str(), cmdargv);            /* Flawfinder: Ignore */
01287                                         llwarns << "execv failure when trying to start " << cmd << llendl;
01288                                         _exit(1); // avoid atexit()
01289                                 } else {
01290                                         if (pid > 0)
01291                                         {
01292                                                 // wait for child proc to die
01293                                                 int childExitStatus;
01294                                                 waitpid(pid, &childExitStatus, 0);
01295                                         } else {
01296                                                 llwarns << "fork failure." << llendl;
01297                                         }
01298                                 }
01299 #endif
01300                         }
01301                         else
01302                         {
01303                                 llinfos << "Not sending crash report." << llendl;
01304                         }
01305                 }
01306 #endif // #if LL_SEND_CRASH_REPORTS
01307         }
01308         else
01309         {
01310                 gSecondInstance = another_instance_running();
01311                 
01312                 if (gSecondInstance)
01313                 {
01314                         gDisableVoice = TRUE;
01315                 }
01316 
01317                 init_marker_file();
01318         }
01319 
01320         //
01321         // Write system information into the debug log (CPU, OS, etc.)
01322         //
01323         write_system_info();
01324 
01325 #if LL_WINDOWS
01326         //
01327         // Turn off Windows XP Error Reporting
01328         // (Don't send our data to Microsoft--at least until we are Logo approved and have a way
01329         // of getting the data back from them.)
01330         //
01331         llinfos << "Turning off Windows error reporting." << llendl;
01332         disable_win_error_reporting();
01333 #endif  // LL_WINDOWS
01334 
01335         // Build a string representing the current version number.
01336         gCurrentVersion = llformat("%s %d.%d.%d.%d.%d", gChannelName.c_str(), LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VERSION_BUILD, LL_VERSION_REVISION );
01337         
01338         //
01339         // Various introspection concerning the libs we're using
01340         //
01341         llinfos << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << llendl;
01342 
01343         //
01344         // Load the feature tables
01345         //
01346         llinfos << "Loading feature tables." << llendl;
01347         
01348         gFeatureManagerp->loadFeatureTables();
01349         gFeatureManagerp->initCPUFeatureMasks();
01350 
01351         // Merge with the command line overrides
01352         gSavedSettings.applyOverrides(gCommandLineSettings);
01353 
01354         // Need to do this before calling parseAlerts
01355         gUICtrlFactory = new LLViewerUICtrlFactory();
01356         
01357         // Pre-load alerts.xml to define the warnings settings (always loads from skins/xui/en-us/)
01358         // Do this *before* loading the settings file
01359         LLAlertDialog::parseAlerts("alerts.xml", &gSavedSettings, TRUE);
01360         
01361         // Overwrite default settings with user settings
01362         llinfos << "Loading configuration file " << gSettingsFileName << llendl;
01363         if (0 == gSavedSettings.loadFromFile(gSettingsFileName))
01364         {
01365                 llinfos << "Failed to load settings from " << gSettingsFileName << llendl;
01366                 llinfos << "Loading legacy settings from " << gOldSettingsFileName << llendl;
01367                 gSavedSettings.loadFromFileLegacy(gOldSettingsFileName);
01368         }
01369 
01370         // need to do this here - need to have initialized global settings first
01371         LLString nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" );
01372         if ( nextLoginLocation.length() )
01373         {
01374                 LLURLSimString::setString( nextLoginLocation.c_str() );
01375         };
01376 
01377         // Merge with the command line overrides
01378         gSavedSettings.applyOverrides(gCommandLineForcedSettings);
01379 
01380         gLastRunVersion = gSavedSettings.getString("LastRunVersion");
01381 
01382         fixup_settings();
01383         
01384         // Get the single value from the crash settings file, if it exists
01385         std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
01386         gCrashSettings.loadFromFile(crash_settings_filename.c_str());
01387 
01389         // OS-specific login dialogs
01391 #if LL_WINDOWS
01392         /*
01393         // Display initial login screen, comes up quickly. JC
01394         {
01395                 LLSplashScreen::hide();
01396 
01397                 INT_PTR result = DialogBox(hInstance, L"CONNECTBOX", NULL, login_dialog_func);
01398                 if (result < 0)
01399                 {
01400                         llwarns << "Connect dialog box failed, returned " << result << llendl;
01401                         return 1;
01402                 }
01403                 // success, result contains which button user clicked
01404                 llinfos << "Connect dialog box clicked " << result << llendl;
01405 
01406                 LLSplashScreen::show();
01407         }
01408         */
01409 #endif
01410 
01411         // track number of times that app has run
01412         gNumSessions = gSavedSettings.getS32("NumSessions");
01413         gNumSessions++;
01414         gSavedSettings.setS32("NumSessions", gNumSessions);
01415 
01416         gSavedSettings.setString("HelpLastVisitedURL",gSavedSettings.getString("HelpHomeURL"));
01417 
01418         if (gSavedSettings.getBOOL("VerboseLogs"))
01419         {
01420                 LLError::setPrintLocation(true);
01421         }
01422 
01423 #if !LL_RELEASE_FOR_DOWNLOAD
01424         if (gUserServerChoice == USERSERVER_NONE)
01425         {
01426                 // Development version: load last server choice by default (overridden by cmd line args)
01427                 
01428                 S32 server = gSavedSettings.getS32("ServerChoice");
01429                 if (server != 0)
01430                         gUserServerChoice = (EUserServerDomain)llclamp(server, 0, (S32)USERSERVER_COUNT - 1);
01431                 if (server == USERSERVER_OTHER)
01432                 {
01433                         LLString custom_server = gSavedSettings.getString("CustomServer");
01434                         if (custom_server.empty())
01435                         {
01436                                 snprintf(gUserServerName, MAX_STRING, "none");          /* Flawfinder: ignore */
01437                         }
01438                         else
01439                         {
01440                                 snprintf(gUserServerName, MAX_STRING, "%s", custom_server.c_str());             /* Flawfinder: ignore */
01441                         }
01442                 }
01443         }
01444 #endif
01445 
01446         if (gUserServerChoice == USERSERVER_NONE)
01447         {
01448                 gUserServerChoice = UserServerDefaultChoice;
01449         }
01450         
01451         // Load art UUID information, don't require these strings to be declared in code.
01452         LLString viewer_art_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"viewerart.xml");
01453         llinfos << "Loading art table from " << viewer_art_filename << llendl;
01454         gViewerArt.loadFromFile(viewer_art_filename.c_str(), FALSE);
01455         LLString textures_filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "textures", "textures.xml");
01456         llinfos << "Loading art table from " << textures_filename << llendl;
01457         gViewerArt.loadFromFile(textures_filename.c_str(), FALSE);
01458 
01459         LLString colors_base_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "colors_base.xml");
01460         llinfos << "Loading base colors from " << colors_base_filename << llendl;
01461         gColors.loadFromFile(colors_base_filename.c_str(), FALSE, TYPE_COL4U);
01462 
01463         // Load overrides from user colors file
01464         LLString user_colors_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "colors.xml");
01465         llinfos << "Loading user colors from " << user_colors_filename << llendl;
01466         if (gColors.loadFromFile(user_colors_filename.c_str(), FALSE, TYPE_COL4U) == 0)
01467         {
01468                 llinfos << "Failed to load user colors from " << user_colors_filename << llendl;
01469                 LLString user_legacy_colors_filename = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "colors.ini");
01470                 llinfos << "Loading legacy colors from " << user_legacy_colors_filename << llendl;
01471                 gColors.loadFromFileLegacy(user_legacy_colors_filename.c_str(), FALSE, TYPE_COL4U);
01472         }
01473 
01474         // Widget construction depends on LLUI being initialized
01475         LLUI::initClass(&gSavedSettings, 
01476                                         &gColors, 
01477                                         &gViewerArt,
01478                                         &gImageList,
01479                                         ui_audio_callback,
01480                                         &LLUI::sGLScaleFactor);
01481 
01482         gUICtrlFactory->setupPaths(); // update paths with correct language set
01483         
01485         //
01486         // Load settings files
01487         //
01488         //
01489         LLGroupMgr::parseRoleActions("role_actions.xml");
01490 
01491         LLAgent::parseTeleportMessages("teleport_strings.xml");
01492 
01493         // Move certain saved settings into global variables for speed
01494         saved_settings_to_globals();
01495 
01496         // 1.6.10: Default crash reporting to on, because this dialog doesn't
01497         // make any sense for a new user.
01498         /*
01499         if (!gSavedSettings.getBOOL("AskedAboutCrashReports"))
01500         {
01501                 // NOTE: Be sure to use gSecondLife if this becomes uncommented.
01502                 S32 retval = OSMessageBox(
01503                         "Welcome!  You have successfully installed Second Life.\n"
01504                         "\n"
01505                         "Should performance issues or crashes occur, Second Life\n"
01506                         "can automatically send technical data about your computer\n"
01507                         "to Linden Lab to diagnose and correct the problem.\n"
01508                         "This information is used solely to address technical issues\n"
01509                         "and is kept strictly confidential.\n"
01510                         "You can change this setting under Preferences / General.\n"
01511                         "Automatically send technical data if problems occur?",
01512                         "Second Life",
01513                         OSMB_YESNO);
01514                 if (OSBTN_YES == retval)
01515                 {
01516                         gAutoReportCrashes = TRUE;
01517                 }
01518                 else
01519                 {
01520                         gAutoReportCrashes = FALSE;
01521                 }
01522 
01523                 // Setting will be saved automatically at shutdown.
01524                 gSavedSettings.setBOOL("AskedAboutCrashReports", TRUE);
01525         }
01526         */
01527 
01528         // Find partition serial number (Windows) or hardware serial (Mac)
01529         gSerialNumber = get_serial_number();
01530 
01531 #if LL_WINDOWS
01532         //
01533         // Do driver verification and initialization based on DirectX
01534         // hardware polling and driver versions
01535         //
01536         if (gProbeHardware)
01537         {
01538                 BOOL vram_only = !gSavedSettings.getBOOL("ProbeHardwareOnStartup");
01539 
01540                 LLSplashScreen::update("Detecting hardware...");
01541 
01542                 llinfos << "Attempting to poll DirectX for hardware info" << llendl;
01543                 gDXHardware.setWriteDebugFunc(write_debug);
01544                 BOOL probe_ok = gDXHardware.getInfo(vram_only);
01545 
01546                 if (!probe_ok
01547                         && gSavedSettings.getWarning("AboutDirectX9"))
01548                 {
01549                         llinfos << "DirectX probe failed, alerting user." << llendl;
01550 
01551                         // Warn them that runnin without DirectX 9 will
01552                         // not allow us to tell them about driver issues
01553                         std::ostringstream msg;
01554                         msg << 
01555                                 gSecondLife << " is unable to detect DirectX 9.0b or greater.\n"
01556                                 "\n" <<
01557                                 gSecondLife << " uses DirectX to detect hardware and/or\n"
01558                                 "outdated drivers that can cause stability problems,\n"
01559                                 "poor performance and crashes.  While you can run\n" <<
01560                                 gSecondLife << " without it, we highly recommend running\n"
01561                                 "with DirectX 9.0b\n"
01562                                 "\n"
01563                                 "Do you wish to continue?\n";
01564                         S32 button = OSMessageBox(
01565                                 msg.str().c_str(),
01566                                 "Warning",
01567                                 OSMB_YESNO);
01568                         if (OSBTN_NO== button)
01569                         {
01570                                 llinfos << "User quitting after failed DirectX 9 detection" << llendl;
01571                                 LLWeb::loadURLExternal(DIRECTX_9_URL);
01572                                 return 0;
01573                         }
01574                         gSavedSettings.setWarning("AboutDirectX9", FALSE);
01575                 }
01576                 llinfos << "Done polling DirectX for hardware info" << llendl;
01577 
01578                 // Only probe once after installation
01579                 gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE);
01580 
01581                 // Disable so debugger can work
01582                 LLSplashScreen::update(splash_msg.str().c_str());
01583         }
01584 
01585         if (!LLWinDebug::setupExceptionHandler())
01586         {
01587                 llwarns << " Someone took over my exception handler (post hardware probe)!" << llendl;
01588         }
01589 
01590         gGLManager.mVRAM = gDXHardware.getVRAM();
01591         llinfos << "Detected VRAM: " << gGLManager.mVRAM << llendl;
01592 #endif
01593 
01594         // Always fetch the Ethernet MAC address, needed both for login
01595         // and password load.
01596         LLUUID::getNodeID(gMACAddress);
01597 
01598         // Prepare for out-of-memory situations, during which we will crash on
01599         // purpose and save a dump.
01600 #if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
01601         MemSetErrorHandler(first_mem_error_handler);
01602 #endif // LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
01603 
01604         gViewerStats = new LLViewerStats();
01605 
01606         //
01607         // Initialize the VFS, and gracefully handle initialization errors
01608         //
01609 
01610         if (!init_cache())
01611         {
01612                 std::ostringstream msg;
01613                 msg <<
01614                         gSecondLife << " is unable to access a file that it needs.\n"
01615                         "\n"
01616                         "This can be because you somehow have multiple copies running, "
01617                         "or your system incorrectly thinks a file is open. "
01618                         "If this message persists, restart your computer and try again. "
01619                         "If it continues to persist, you may need to completely uninstall " <<
01620                         gSecondLife << " and reinstall it.";
01621                 OSMessageBox(
01622                         msg.str().c_str(),
01623                         NULL,
01624                         OSMB_OK);
01625                 return 1;
01626         }
01627         
01628 #if LL_DARWIN
01629         // Display the release notes for the current version
01630         if(!gHideLinks && gCurrentVersion != gLastRunVersion)
01631         {
01632                 // Current version and last run version don't match exactly.  Display the release notes.
01633                 DisplayReleaseNotes();
01634         }
01635 #endif
01636 
01637         //
01638         // Initialize the window
01639         //
01640 
01641         // pop up debug console if necessary
01642 #if LL_WINDOWS
01643         if (gUseConsole && gSavedSettings.getBOOL("ShowConsoleWindow"))
01644         {
01645                 create_console();
01646         }
01647 #endif
01648 
01649         llinfos << "Initializing window..." << llendl;
01650 
01651         // store setting in a global for easy access and modification
01652         gNoRender = gSavedSettings.getBOOL("DisableRendering");
01653 
01654         // Hide the splash screen
01655         LLSplashScreen::hide();
01656 
01657         // HACK: Need a non-const char * for stupid window name (propagated deep down)
01658         char window_title_str[256];             /* Flawfinder: ignore */
01659         strncpy(window_title_str, gWindowTitle.c_str(), sizeof(window_title_str) - 1);          /* Flawfinder: ignore */
01660         window_title_str[sizeof(window_title_str) - 1] = '\0';
01661 
01662         // always start windowed
01663         gViewerWindow = new LLViewerWindow(window_title_str, sWindowClass,
01664                 gSavedSettings.getS32("WindowX"), gSavedSettings.getS32("WindowY"),
01665                 gSavedSettings.getS32("WindowWidth"), gSavedSettings.getS32("WindowHeight"),
01666                 FALSE, gIgnorePixelDepth, gSavedSettings.getS32("StereoMode"));
01667                 
01668         if (gSavedSettings.getBOOL("FullScreen"))
01669         {
01670                 gViewerWindow->toggleFullscreen(FALSE);
01671                         // request to go full screen... which will be delayed until login
01672         }
01673 
01674         // Stereo mode may turn out to be unusable. In that case, write the new mode (none)
01675         gSavedSettings.setS32("StereoMode", gViewerWindow->getWindow()->getStereoMode());
01676 
01677         if (gSavedSettings.getBOOL("WindowMaximized"))
01678         {
01679                 gViewerWindow->mWindow->maximize();
01680                 gViewerWindow->getWindow()->setNativeAspectRatio(gSavedSettings.getF32("FullScreenAspectRatio"));
01681         }
01682 
01683         LLUI::sWindow = gViewerWindow->getWindow();
01684 
01685         LLAlertDialog::parseAlerts("alerts.xml");
01686         LLNotifyBox::parseNotify("notify.xml");
01687 
01688         LLMediaEngine::initClass();
01689         
01690         //
01691         // Clean up the feature manager lookup table - settings were updated
01692         // in the LLViewerWindow constructor
01693         //
01694         gFeatureManagerp->cleanupFeatureTables();
01695 
01696         // Show watch cursor
01697         gViewerWindow->setCursor(UI_CURSOR_WAIT);
01698 
01699         
01700 #if LL_WINDOWS && LL_LCD_COMPILE
01701         // start up an LCD window on a logitech keyboard, if there is one
01702         gLcdScreen = new llLCD(hInstance);
01703         CreateLCDDebugWindows();
01704 #endif
01705 
01706         // Finish view initialization
01707         gViewerWindow->initBase();
01708 
01709         // show viewer window
01710         gViewerWindow->mWindow->show();
01711 
01712         write_debug(gGLManager.getGLInfoString());
01713         llinfos << gGLManager.getGLInfoString() << llendl;
01714 
01715         //load key settings
01716         bind_keyboard_functions();
01717 
01718         // Load Default bindings
01719         if (!gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"keys.ini").c_str()))
01720         {
01721                 llerrs << "Unable to open keys.ini" << llendl;
01722         }
01723         // Load Custom bindings (override defaults)
01724         gViewerKeyboard.loadBindings(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"custom_keys.ini").c_str());
01725 
01726         // Calculate the digest for the executable (takes < 90ms on a fast machine).
01727         FILE* app_file = LLFile::fopen( gDirUtilp->getExecutablePathAndName().c_str(), "rb" );          /* Flawfinder: ignore */
01728         if( app_file )
01729         {
01730                 LLMD5 app_md5;
01731                 app_md5.update( app_file ); // Automatically closes the file
01732                 app_md5.finalize();
01733                 app_md5.raw_digest( gViewerDigest.mData );
01734         }
01735         llinfos << "Viewer Digest: " << gViewerDigest << llendl;
01736 
01737         // If we don't have the right GL requirements, exit.
01738         // BUG: This should just be changed to a generic GL "Not good enough" flag
01739         if (!gGLManager.mHasMultitexture && !gNoRender)
01740         {
01741                 std::ostringstream msg;
01742                 msg <<
01743                         "You do not appear to have the proper hardware requirements "
01744                         "for " << gSecondLife << ". " << gSecondLife << " requires an OpenGL graphics "
01745                         "card that has multitexture support. If this is the case, "
01746                         "you may want to make sure that you have the latest drivers for "
01747                         "your graphics card, and service packs and patches for your "
01748                         "operating system.\n"
01749                         "If you continue to have problems, please go to: "
01750                         "www.secondlife.com/support ";
01751                 OSMessageBox(
01752                         msg.str().c_str(),
01753                         NULL,
01754                         OSMB_OK);
01755                 return 0;
01756         }
01757 
01758         // Save the current version to the prefs file
01759         gSavedSettings.setString("LastRunVersion", gCurrentVersion);
01760 
01761         gSimLastTime = gRenderStartTime.getElapsedTimeF32();
01762         gSimFrames   = (F32)gFrameCount;
01763 
01764         //-------------------------------------------
01765         // Run main loop until time to quit
01766         //-------------------------------------------
01767         main_loop();
01768 
01769         cleanup_app();
01770 
01771         // If we're exiting to launch an URL, do that here so the screen
01772         // is at the right resolution before we launch IE.
01773         if (!gLaunchFileOnQuit.empty())
01774         {
01775 #if LL_WINDOWS
01776                 // Indicate an application is starting.
01777                 SetCursor(LoadCursor(NULL, IDC_WAIT));
01778 #endif
01779 
01780                 // HACK: Attempt to wait until the screen res. switch is complete.
01781                 ms_sleep(1000);
01782 
01783                 LLWeb::loadURLExternal( gLaunchFileOnQuit );
01784         }
01785 
01786         llinfos << "Goodbye" << llendflush;
01787         return 0;
01788 }
01789 
01790 bool send_url_to_other_instance(const std::string& url)
01791 {
01792 #if LL_WINDOWS
01793         wchar_t window_class[256]; /* Flawfinder: ignore */   // Assume max length < 255 chars.
01794         mbstowcs(window_class, sWindowClass, 255);
01795         window_class[255] = 0;
01796         // Use the class instead of the window name.
01797         HWND other_window = FindWindow(window_class, NULL);
01798         if (other_window != NULL)
01799         {
01800                 lldebugs << "Found other window with the name '" << gWindowTitle << "'" << llendl;
01801                 COPYDATASTRUCT cds;
01802                 const S32 SLURL_MESSAGE_TYPE = 0;
01803                 cds.dwData = SLURL_MESSAGE_TYPE;
01804                 cds.cbData = url.length() + 1;
01805                 cds.lpData = (void*)url.c_str();
01806 
01807                 LRESULT msg_result = SendMessage(other_window, WM_COPYDATA, NULL, (LPARAM)&cds);
01808                 lldebugs << "SendMessage(WM_COPYDATA) to other window '" 
01809                                  << gWindowTitle << "' returned " << msg_result << llendl;
01810                 return true;
01811         }
01812 #endif
01813         return false;
01814 }
01815 
01816 BOOL another_instance_running()
01817 {
01818         // We create a marker file when the program starts and remove the file when it finishes.
01819         // If the file is currently locked, that means another process is already running.
01820 
01821         std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.exec_marker");
01822         llinfos << "Checking marker file for lock..." << llendl;
01823 
01824         // If file doesn't exist, we create it
01825         // If file does exist, try to get writing privilages
01826         FILE* fMarker = LLFile::fopen(marker_file.c_str(), "rb");               /* Flawfinder: ignore */
01827         if (fMarker != NULL)
01828         {
01829                 // File exists, try opening with write permissions
01830                 fclose(fMarker);
01831                 fMarker = LLFile::fopen(marker_file.c_str(), "wb");             /* Flawfinder: ignore */
01832                 if (fMarker == NULL)
01833                 {
01834                         llinfos << "Marker file is locked." << llendl;
01835                         return TRUE;
01836                 }
01837 #if LL_DARWIN
01838                 // Try to lock it. On Mac, this is the only way to test if it's actually locked.
01839                 if (flock(fileno(fMarker), LOCK_EX | LOCK_NB) == -1)
01840                 {
01841                         // Lock failed - somebody else has it.
01842                         fclose(fMarker);
01843                         llinfos << "Marker file is locked." << llendl;
01844                         return TRUE;
01845                 }
01846 #endif
01847                 fclose(fMarker);
01848         }
01849         llinfos << "Marker file isn't locked." << llendl;
01850         return FALSE;
01851 }
01852 
01853 
01854 void check_for_events()
01855 {
01856         LLFastTimer t2(LLFastTimer::FTM_MESSAGES);
01857 #if LL_WINDOWS
01858         if (!LLWinDebug::setupExceptionHandler())
01859         {
01860                 llwarns << " Someone took over my exception handler (post messagehandling)!" << llendl;
01861         }
01862 #endif
01863 
01864         gViewerWindow->mWindow->gatherInput();
01865 }
01866 
01867 #include "moviemaker.h"
01868 extern BOOL gbCapturing;
01869 
01870 #if !LL_SOLARIS
01871 extern MovieMaker gMovieMaker;
01872 #endif
01873 
01874 void main_loop()
01875 {
01876         // Create IO Pump to use for HTTP Requests.
01877         gServicePump = new LLPumpIO(gAPRPoolp);
01878         LLHTTPClient::setPump(*gServicePump);
01879         LLHTTPClient::setCABundle(gDirUtilp->getCAFile());
01880         
01881         // initialize voice stuff here
01882         gLocalSpeakerMgr = new LLLocalSpeakerMgr();
01883         gActiveChannelSpeakerMgr = new LLActiveSpeakerMgr();
01884 
01885         LLVoiceChannel::initClass();
01886         LLVoiceClient::init(gServicePump);
01887                                 
01888         LLMemType mt1(LLMemType::MTYPE_MAIN);
01889         LLTimer frameTimer,idleTimer;
01890         LLTimer debugTime;
01891         
01892         // Handle messages
01893         while (!gQuit)
01894         {
01895                 LLFastTimer::reset(); // Should be outside of any timer instances
01896                 {
01897                         LLFastTimer t(LLFastTimer::FTM_FRAME);
01898 
01899                         check_for_events();
01900 
01901 #if 1 && !RELEASE_FOR_DOWNLOAD
01902                         // once per second debug info
01903                         if (debugTime.getElapsedTimeF32() > 1.f)
01904                         {
01905                                 debugTime.reset();
01906                         }
01907 #endif
01908                         if (!gQuit)
01909                         {
01910                                 // Scan keyboard for movement keys.  Command keys and typing
01911                                 // are handled by windows callbacks.  Don't do this until we're
01912                                 // done initializing.  JC
01913                                 if (gViewerWindow->mWindow->getVisible() 
01914                                         && gViewerWindow->getActive()
01915                                         && !gViewerWindow->mWindow->getMinimized()
01916                                         && LLStartUp::getStartupState() == STATE_STARTED
01917                                         && !gViewerWindow->getShowProgress()
01918                                         && !gFocusMgr.focusLocked())
01919                                 {
01920                                         gKeyboard->scanKeyboard();
01921                                         LLViewerJoystick::scanJoystick();
01922                                 }
01923 
01924                                 // Update state based on messages, user input, object idle.
01925                                 {
01926                                         LLFastTimer t3(LLFastTimer::FTM_IDLE);
01927                                         idle();
01928                                         LLCurl::process();
01929                                         // this pump is necessary to make the login screen show up
01930                                         gServicePump->pump();
01931                                         gServicePump->callback();
01932                                 }
01933 
01934                                 if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
01935                                 {
01936                                         save_final_snapshot(NULL);
01937                                         disconnect_viewer(NULL);
01938                                 }
01939 
01940                                 // Render scene.
01941                                 if (!gQuit)
01942                                 {
01943                                         display();
01944 
01945                                         LLFloaterSnapshot::update(); // take snapshots
01946                                         
01947 #if !LL_SOLARIS
01948                                         if (gbCapturing)
01949                                         {
01950                                                 gMovieMaker.Snap();
01951                                         }
01952 #endif
01953 #if LL_WINDOWS && LL_LCD_COMPILE
01954                                         // update LCD Screen
01955                                         gLcdScreen->UpdateDisplay();
01956 #endif
01957                                 }
01958                         }
01959 
01960                         // Sleep and run background threads
01961                         {
01962                                 LLFastTimer t2(LLFastTimer::FTM_SLEEP);
01963                                 bool run_multiple_threads = gSavedSettings.getBOOL("RunMultipleThreads");
01964 
01965                                 // yield some time to the os based on command line option
01966                                 if(gYieldTime)
01967                                 {
01968                                         ms_sleep(gYieldMS);
01969                                 }
01970 
01971                                 // yield cooperatively when not running as foreground window
01972                                 if (   gNoRender
01973                                                 || !gViewerWindow->mWindow->getVisible()
01974                                                 || !gFocusMgr.getAppHasFocus())
01975                                 {
01976                                         // Sleep if we're not rendering, or the window is minimized.
01977                                         S32 milliseconds_to_sleep = llclamp(gSavedSettings.getS32("BackgroundYieldTime"), 0, 1000);
01978                                         // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads
01979                                         // of equal priority on Windows
01980                                         if (milliseconds_to_sleep > 0)
01981                                         {
01982                                                 ms_sleep(milliseconds_to_sleep);
01983                                                 // also pause worker threads during this wait period
01984                                                 gTextureCache->pause();
01985                                                 gImageDecodeThread->pause();
01986                                         }
01987                                 }
01988                                 
01989                                 if (gRandomizeFramerate)
01990                                 {
01991                                         ms_sleep(rand() % 200);
01992                                 }
01993 
01994                                 if (gPeriodicSlowFrame
01995                                         && (gFrameCount % 10 == 0))
01996                                 {
01997                                         llinfos << "Periodic slow frame - sleeping 500 ms" << llendl;
01998                                         ms_sleep(500);
01999                                 }
02000 
02001 
02002                                 const F64 min_frame_time = 0.0; //(.0333 - .0010); // max video frame rate = 30 fps
02003                                 const F64 min_idle_time = 0.0; //(.0010); // min idle time = 1 ms
02004                                 const F64 max_idle_time = run_multiple_threads ? min_idle_time : .005; // 5 ms
02005                                 idleTimer.reset();
02006                                 while(1)
02007                                 {
02008                                         S32 work_pending = 0;
02009                                         S32 io_pending = 0;
02010                                         work_pending += gTextureCache->update(1); // unpauses the texture cache thread
02011                                         work_pending += gImageDecodeThread->update(1); // unpauses the image thread
02012                                         work_pending += gTextureFetch->update(1); // unpauses the texture fetch thread
02013                                         io_pending += LLVFSThread::updateClass(1);
02014                                         io_pending += LLLFSThread::updateClass(1);
02015                                         if (io_pending > 1000)
02016                                         {
02017                                                 ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up
02018                                         }
02019 
02020                                         F64 frame_time = frameTimer.getElapsedTimeF64();
02021                                         F64 idle_time = idleTimer.getElapsedTimeF64();
02022                                         if (frame_time >= min_frame_time &&
02023                                                 idle_time >= min_idle_time &&
02024                                                 (!work_pending || idle_time >= max_idle_time))
02025                                         {
02026                                                 break;
02027                                         }
02028                                 }
02029                                 frameTimer.reset();
02030 
02031                                  // Prevent the worker threads from running while rendering.
02032                                 // if (LLThread::processorCount()==1) //pause() should only be required when on a single processor client...
02033                                 if (run_multiple_threads == FALSE)
02034                                 {
02035                                         gTextureCache->pause();
02036                                         gImageDecodeThread->pause();
02037                                         // gTextureFetch->pause(); // Don't pause the fetch (IO) thread
02038                                 }
02039                                 //LLVFSThread::sLocal->pause(); // Prevent the VFS thread from running while rendering.
02040                                 //LLLFSThread::sLocal->pause(); // Prevent the LFS thread from running while rendering.
02041                         }
02042                                                 
02043                 }
02044         }
02045 
02046         // Save snapshot for next time, if we made it through initialization
02047         if (STATE_STARTED == LLStartUp::getStartupState())
02048         {
02049                 save_final_snapshot(NULL);
02050         }
02051         
02052         delete gServicePump;
02053 
02054         llinfos << "Exiting main_loop" << llendflush;
02055 }
02056 
02057 
02058 void process_keystrokes_async()
02059 {
02060 #if LL_WINDOWS
02061         MSG                     msg;
02062         // look through all input messages, leaving them in the event queue
02063         while( PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE | PM_NOYIELD))
02064         {
02065                 // on first mouse message, break out
02066                 if (msg.message >= WM_MOUSEFIRST && 
02067                         msg.message <= WM_MOUSELAST ||
02068                         msg.message == WM_QUIT)
02069                 {
02070                         break;
02071                 }
02072 
02073                 // this is a message we want to handle now, so remove it from the event queue
02074                 PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE | PM_NOYIELD);
02075                 //              if (msg.message == WM_KEYDOWN)
02076                 //              {
02077                 //                      llinfos << "Process async key down " << (U32)msg.wParam << llendl;
02078                 //              }
02079                 TranslateMessage(&msg);
02080                 DispatchMessage(&msg);
02081         }
02082 
02083         // Scan keyboard for movement keys.  Command keys and typing
02084         // are handled by windows callbacks.  Don't do this until we're
02085         // done initializing.  JC
02086         if (gViewerWindow->mWindow->getVisible() 
02087                 && gViewerWindow->getActive()
02088                 && !gViewerWindow->mWindow->getMinimized()
02089                 && LLStartUp::getStartupState() == STATE_STARTED
02090                 && !gViewerWindow->getShowProgress()
02091                 && !gFocusMgr.focusLocked())
02092         {
02093                 gKeyboard->scanKeyboard();
02094         }
02095 #endif
02096 }
02097 
02099 //
02100 // Functions
02101 //
02102 
02103 FILE *gMarkerFile = NULL;
02104 
02105 void remove_marker_file()
02106 {
02107         llinfos << "remove_marker_file()" << llendl;
02108         if (gMarkerFile != NULL)
02109         {
02110                 fclose(gMarkerFile);
02111                 gMarkerFile = NULL;
02112         }
02113         if( gDirUtilp )
02114         {
02115                 LLString marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.exec_marker");
02116                 ll_apr_file_remove( marker_file );
02117         }
02118 }
02119 
02120 void init_marker_file()
02121 {
02122 #if LL_SOLARIS
02123         struct flock fl;
02124         fl.l_whence = SEEK_SET;
02125         fl.l_start = 0;
02126         fl.l_len = 1;
02127 #endif
02128         // We create a marker file when the program starts and remove the file when it finishes.
02129         // If the file is currently locked, that means another process is already running.
02130         // If the file exists and isn't locked, we crashed on the last run.
02131 
02132         std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"SecondLife.exec_marker");
02133         llinfos << "Checking marker file for lock..." << llendl;
02134 
02135         FILE* fMarker = LLFile::fopen(marker_file.c_str(), "rb");               /* Flawfinder: ignore */
02136         if (fMarker != NULL)
02137         {
02138                 // File exists, try opening with write permissions
02139                 fclose(fMarker);
02140                 fMarker = LLFile::fopen(marker_file.c_str(), "wb");             /* Flawfinder: ignore */
02141                 if (fMarker == NULL)
02142                 {
02143                         // Another instance is running. Skip the rest of these operations.
02144                         llinfos << "Marker file is locked." << llendl;
02145                         return;
02146                 }
02147 #if LL_DARWIN
02148                 // Try to lock it. On Mac, this is the only way to test if it's actually locked.
02149                 if (flock(fileno(fMarker), LOCK_EX | LOCK_NB) == -1)
02150                 {
02151                         // Lock failed - somebody else has it.
02152                         fclose(fMarker);
02153                         llinfos << "Marker file is locked." << llendl;
02154                         return;
02155                 }
02156 #endif
02157 
02158                 // No other instances; we'll lock this file now & delete on quit.
02159                 fclose(fMarker);
02160                 gLastExecFroze = TRUE;
02161                 llinfos << "Exec marker found: program froze on previous execution" << llendl;
02162         }
02163 
02164         // Create the marker file for this execution & lock it
02165 //      FILE *fp_executing_marker;
02166 #if LL_WINDOWS
02167         gMarkerFile = LLFile::_fsopen(marker_file.c_str(), "w", _SH_DENYWR);
02168 #else
02169         gMarkerFile = LLFile::fopen(marker_file.c_str(), "w");          /* Flawfinder: ignore */
02170         if (gMarkerFile)
02171         {
02172                 int fd = fileno(gMarkerFile);
02173                 // Attempt to lock
02174 #if LL_SOLARIS
02175                 fl.l_type = F_WRLCK;
02176                 if (fcntl(fd, F_SETLK, &fl) == -1)
02177 #else
02178                 if (flock(fd, LOCK_EX | LOCK_NB) == -1)
02179 #endif
02180                 {
02181                         llinfos << "Failed to lock file." << llendl;
02182                 }
02183         }
02184 #endif
02185         if (gMarkerFile)
02186         {
02187                 llinfos << "Marker file created." << llendl;
02188         }
02189         else
02190         {
02191                 llinfos << "Failed to create marker file." << llendl;
02192         }
02193 
02194 #if LL_WINDOWS
02195         // Clean up SecondLife.dmp files, to avoid confusion
02196         llinfos << "Removing SecondLife.dmp" << llendl;
02197         std::string dmp_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.dmp");
02198         LLFile::remove(dmp_filename.c_str());
02199 #endif
02200 
02201         // This is to keep the crash reporter from constantly sending stale message logs
02202         // We wipe the message file now.
02203         llinfos << "Removing message.log" << llendl;
02204         std::string message_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "message.log");
02205         LLFile::remove(message_filename.c_str());
02206 
02207         llinfos << "Exiting init_marker_file()." << llendl;
02208 }
02209 
02210 void init_crash_handler()
02211 {
02213         //
02214         // Set up error handling and logging for LL_RELEASE_FOR_DOWNLOAD
02215         //
02216 
02217         // Signal handling (or Win32 exception handling
02218         catch_signals();
02219 
02220         // Set the crash callback for the viewer
02221         gCrashCallback = viewer_crash_callback;
02222 }
02223 
02224 void init_logging()
02225 {
02226         // Remove the last ".old" log file.
02227         std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
02228                                                              "SecondLife.old");
02229         LLFile::remove(old_log_file.c_str());
02230 
02231 #if LL_LINUX || LL_SOLARIS
02232         // Remove the last stack trace, if any
02233         std::string old_stack_file =
02234                 gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
02235         LLFile::remove(old_stack_file.c_str());
02236 #endif // LL_LINUX || LL_SOLARIS
02237 
02238         // Rename current log file to ".old"
02239         std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
02240                                                              "SecondLife.log");
02241         LLFile::rename(log_file.c_str(), old_log_file.c_str());
02242 
02243         // Set the log file to SecondLife.log
02244 
02245         LLError::logToFile(log_file);
02246 }
02247 
02248 void write_system_info()
02249 {
02250         write_debug("SL Log: ");
02251         write_debug(LLError::logFileName());
02252         write_debug("\n");
02253 
02254         std::string tmp_str = gSecondLife
02255                 + llformat(" version %d.%d.%d build %d",
02256                                    LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VIEWER_BUILD);
02257         write_debug(tmp_str.c_str());
02258         write_debug("\n");
02259         write_debug(gSysCPU.getCPUString());
02260         write_debug("\n");
02261         
02262         tmp_str = llformat("RAM: %u KB\n", gSysMemory.getPhysicalMemoryKB());
02263         write_debug(tmp_str.c_str());
02264         write_debug("OS: ");
02265         write_debug(gSysOS.getOSString().c_str());
02266         write_debug("\n");
02267 
02268         // Dump some debugging info
02269         llinfos << gSecondLife << " version "
02270                 << LL_VERSION_MAJOR << "."
02271                 << LL_VERSION_MINOR << "."
02272                 << LL_VERSION_PATCH
02273                 << llendl;
02274 
02275         // Dump the local time and time zone
02276         time_t now;
02277         time(&now);
02278         char tbuffer[256];              /* Flawfinder: ignore */
02279         strftime(tbuffer, 256, "%Y-%m-%dT%H:%M:%S %Z", localtime(&now));
02280         llinfos << "Local time: " << tbuffer << llendl;
02281 
02282         // query some system information
02283         llinfos << "CPU info:\n" << gSysCPU << llendl;
02284         llinfos << "Memory info:\n" << gSysMemory << llendl;
02285         llinfos << "OS info: " << gSysOS << llendl;
02286 }
02287 
02288 #if LL_WINDOWS
02289 void disable_win_error_reporting()
02290 {
02291         const char win_xp_string[] = "Microsoft Windows XP";
02292         BOOL is_win_xp = ( gSysOS.getOSString().substr(0, strlen(win_xp_string) ) == win_xp_string );           /* Flawfinder: ignore*/
02293         if( is_win_xp )
02294         {
02295                 // Note: we need to use run-time dynamic linking, because load-time dynamic linking will fail
02296                 // on systems that don't have the library installed (all non-Windows XP systems)
02297                 HINSTANCE fault_rep_dll_handle = LoadLibrary(L"faultrep.dll");          /* Flawfinder: ignore */
02298                 if( fault_rep_dll_handle )
02299                 {
02300                         pfn_ADDEREXCLUDEDAPPLICATIONA pAddERExcludedApplicationA  = (pfn_ADDEREXCLUDEDAPPLICATIONA) GetProcAddress(fault_rep_dll_handle, "AddERExcludedApplicationA");
02301                         if( pAddERExcludedApplicationA )
02302                         {
02303 
02304                                 // Strip the path off the name
02305                                 const char* executable_name = gDirUtilp->getExecutableFilename().c_str();
02306 
02307                                 if( 0 == pAddERExcludedApplicationA( executable_name ) )
02308                                 {
02309                                         U32 error_code = GetLastError();
02310                                         llinfos << "AddERExcludedApplication() failed with error code " << error_code << llendl;
02311                                 }
02312                                 else
02313                                 {
02314                                         llinfos << "AddERExcludedApplication() success for " << executable_name << llendl;
02315                                 }
02316                         }
02317                         FreeLibrary( fault_rep_dll_handle );
02318                 }
02319         }
02320 }
02321 #endif  // LL_WINDOWS
02322 
02323 // On Windows, get the C:\ volume serial number.
02324 // On Mac, return the hardware serial number.
02325 std::string get_serial_number()
02326 {
02327         char serial_md5[MD5HEX_STR_SIZE];               /* Flawfinder: ignore */
02328         serial_md5[0] = 0;
02329 
02330 #if LL_WINDOWS
02331         DWORD serial = 0;
02332         DWORD flags = 0;
02333         BOOL success = GetVolumeInformation(
02334                         L"C:\\",
02335                         NULL,           // volume name buffer
02336                         0,                      // volume name buffer size
02337                         &serial,        // volume serial
02338                         NULL,           // max component length
02339                         &flags,         // file system flags
02340                         NULL,           // file system name buffer
02341                         0);                     // file system name buffer size
02342         if (success)
02343         {
02344                 LLMD5 md5;
02345                 md5.update( (unsigned char*)&serial, sizeof(DWORD));
02346                 md5.finalize();
02347                 md5.hex_digest(serial_md5);
02348         }
02349         else
02350         {
02351                 llwarns << "GetVolumeInformation failed" << llendl;
02352         }
02353         return serial_md5;
02354 
02355 #elif LL_DARWIN 
02356         // JC: Sample code from http://developer.apple.com/technotes/tn/tn1103.html
02357         CFStringRef serialNumber = NULL;
02358         io_service_t    platformExpert = IOServiceGetMatchingService(kIOMasterPortDefault,
02359                                                                                                                                  IOServiceMatching("IOPlatformExpertDevice"));
02360         if (platformExpert) {
02361                 serialNumber = (CFStringRef) IORegistryEntryCreateCFProperty(platformExpert,
02362                                                                                                                                          CFSTR(kIOPlatformSerialNumberKey),
02363                                                                                                                                          kCFAllocatorDefault, 0);               
02364                 IOObjectRelease(platformExpert);
02365         }
02366         
02367         if (serialNumber)
02368         {
02369                 char buffer[MAX_STRING];                /* Flawfinder: ignore */
02370                 if (CFStringGetCString(serialNumber, buffer, MAX_STRING, kCFStringEncodingASCII))
02371                 {
02372                         LLMD5 md5( (unsigned char*)buffer );
02373                         md5.hex_digest(serial_md5);
02374                 }
02375                 CFRelease(serialNumber);
02376         }
02377 
02378         return serial_md5;
02379 
02380 #elif LL_LINUX || LL_SOLARIS
02381         // TODO
02382         return serial_md5;
02383 
02384 #endif
02385 }
02386 
02387 #if LL_LINUX
02388 #define MAX_STACK_TRACE_DEPTH 40
02389 // This uses glibc's basic built-in stack-trace functions for a not very
02390 // amazing backtrace.
02391 static inline BOOL do_basic_glibc_backtrace()
02392 {
02393         void *array[MAX_STACK_TRACE_DEPTH];
02394         size_t size;
02395         char **strings;
02396         size_t i;
02397         BOOL success = FALSE;
02398 
02399         size = backtrace(array, MAX_STACK_TRACE_DEPTH);
02400         strings = backtrace_symbols(array, size);
02401 
02402         std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
02403         llinfos << "Opening stack trace file " << strace_filename << llendl;
02404         FILE* StraceFile = LLFile::fopen(strace_filename.c_str(), "w");         /* Flawfinder: ignore */
02405         if (!StraceFile)
02406         {
02407                 llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
02408                 StraceFile = stderr;
02409         }
02410 
02411         if (size)
02412         {
02413                 for (i = 0; i < size; i++)
02414                         fputs((std::string(strings[i])+"\n").c_str(),
02415                               StraceFile);
02416 
02417                 success = TRUE;
02418         }
02419         
02420         if (StraceFile != stderr)
02421                 fclose(StraceFile);
02422 
02423         free (strings);
02424         return success;
02425 }
02426 
02427 #if LL_ELFBIN
02428 // This uses glibc's basic built-in stack-trace functions together with
02429 // ELFIO's ability to parse the .symtab ELF section for better symbol
02430 // extraction without exporting symbols (which'd cause subtle, fatal bugs).
02431 static inline BOOL do_elfio_glibc_backtrace()
02432 {
02433         void *array[MAX_STACK_TRACE_DEPTH];
02434         size_t btsize;
02435         char **strings;
02436         BOOL success = FALSE;
02437 
02438         std::string appfilename = gDirUtilp->getExecutablePathAndName();
02439 
02440         std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
02441         llinfos << "Opening stack trace file " << strace_filename << llendl;
02442         FILE* StraceFile = LLFile::fopen(strace_filename.c_str(), "w");         /* Flawfinder: ignore */
02443         if (!StraceFile)
02444         {
02445                 llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
02446                 StraceFile = stderr;
02447         }
02448 
02449         // get backtrace address list and basic symbol info
02450         btsize = backtrace(array, MAX_STACK_TRACE_DEPTH);
02451         strings = backtrace_symbols(array, btsize);
02452 
02453         // create ELF reader for our app binary
02454         IELFI* pReader;
02455         const IELFISection* pSec = NULL;
02456         IELFISymbolTable* pSymTbl = 0;
02457         if (ERR_ELFIO_NO_ERROR != ELFIO::GetInstance()->CreateELFI(&pReader) ||
02458             ERR_ELFIO_NO_ERROR != pReader->Load(appfilename.c_str()) ||
02459             // find symbol table, create reader-object
02460             NULL == (pSec = pReader->GetSection( ".symtab" )) ||
02461             ERR_ELFIO_NO_ERROR != pReader->CreateSectionReader(IELFI::ELFI_SYMBOL, pSec, (void**)&pSymTbl) )
02462         {
02463                 // Failed to open our binary and read its symbol table somehow
02464                 llinfos << "Could not initialize ELF symbol reading - doing basic backtrace." << llendl;
02465                 if (StraceFile != stderr)
02466                         fclose(StraceFile);
02467                 // note that we may be leaking some of the above ELFIO
02468                 // objects now, but it's expected that we'll be dead soon
02469                 // and we want to tread delicately until we get *some* kind
02470                 // of useful backtrace.
02471                 return do_basic_glibc_backtrace();
02472         }
02473 
02474         // iterate over trace and symtab, looking for plausible symbols
02475         std::string   name;
02476         Elf32_Addr    value;
02477         Elf32_Word    ssize;
02478         unsigned char bind;
02479         unsigned char type;
02480         Elf32_Half    section;
02481         int nSymNo = pSymTbl->GetSymbolNum();
02482         size_t btpos;
02483         for (btpos = 0; btpos < btsize; ++btpos)
02484         {
02485                 fprintf(StraceFile, "%d:\t", btpos);
02486                 int symidx;
02487                 for (symidx = 0; symidx < nSymNo; ++symidx)
02488                 {
02489                         if (ERR_ELFIO_NO_ERROR ==
02490                             pSymTbl->GetSymbol(symidx, name, value, ssize,
02491                                                bind, type, section))
02492                         {
02493                                 // check if trace address within symbol range
02494                                 if (uintptr_t(array[btpos]) >= value &&
02495                                     uintptr_t(array[btpos]) < value+ssize)
02496                                 {
02497                                         char *demangled_str = NULL;
02498                                         int demangle_result = 1;
02499                                         demangled_str =
02500                                                 abi::__cxa_demangle
02501                                                 (name.c_str(), NULL, NULL,
02502                                                  &demangle_result);
02503                                         if (0 == demangle_result &&
02504                                             NULL != demangled_str) {
02505                                                 fprintf(StraceFile,
02506                                                         "ELF(%s", demangled_str);
02507                                                 free(demangled_str);
02508                                         }
02509                                         else // failed demangle; print it raw
02510                                         {
02511                                                 fprintf(StraceFile,
02512                                                         "ELF(%s", name.c_str());
02513                                         }
02514                                         // print offset from symbol start
02515                                         fprintf(StraceFile,
02516                                                 "+0x%lx) [%p]\n",
02517                                                 uintptr_t(array[btpos]) -
02518                                                 value,
02519                                                 array[btpos]);
02520                                         goto got_sym; // early escape
02521                                 }
02522                         }
02523                 }
02524                 // Fallback:
02525                 // Didn't find a suitable symbol in the binary - it's probably
02526                 // a symbol in a DSO; use glibc's idea of what it should be.
02527                 fprintf(StraceFile, "%s\n", strings[btpos]);
02528         got_sym:;
02529         }
02530         
02531         if (StraceFile != stderr)
02532                 fclose(StraceFile);
02533 
02534         pSymTbl->Release();
02535         pSec->Release();
02536         pReader->Release();
02537 
02538         free(strings);
02539 
02540         llinfos << "Finished generating stack trace." << llendl;
02541 
02542         success = TRUE;
02543         return success;
02544 }
02545 #endif // LL_ELFBIN
02546 #endif // LL_LINUX
02547 
02548 /* Report whether we're being run under the control of a debugger. */
02549 static inline bool being_debugged()
02550 {
02551         static enum {unknown, no, yes} debugged = unknown;
02552         
02553         if (debugged == unknown)
02554         {
02555 #if LL_LINUX
02556                 pid_t ppid = getppid();
02557                 char *name;
02558                 int ret;
02559 
02560                 ret = asprintf(&name, "/proc/%d/exe", ppid);
02561                 if (ret != -1)
02562                 {
02563                         char buf[1024];
02564                         ssize_t n;
02565                         
02566                         n = readlink(name, buf, sizeof(buf) - 1);
02567                         if (n != -1)
02568                         {
02569                                 char *base = strrchr(buf, '/');
02570                                 buf[n + 1] = '\0';
02571                                 if (base == NULL)
02572                                 {
02573                                         base = buf;
02574                                 } else {
02575                                         base += 1;
02576                                 }
02577                                 
02578                                 if (strcmp(base, "gdb") == 0)
02579                                 {
02580                                         debugged = yes;
02581                                 }
02582                         }
02583                         free(name);
02584                 }
02585 #endif // LL_LINUX
02586         }
02587 
02588         return debugged == yes;
02589 }
02590 
02591 #ifdef LL_SOLARIS
02592 static inline BOOL do_basic_glibc_backtrace()
02593 {
02594         BOOL success = FALSE;
02595 
02596         std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
02597         llinfos << "Opening stack trace file " << strace_filename << llendl;
02598         FILE* StraceFile = LLFile::fopen(strace_filename.c_str(), "w");
02599         if (!StraceFile)
02600         {
02601                 llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl;
02602                 StraceFile = stderr;
02603         }
02604 
02605         printstack(fileno(StraceFile));
02606 
02607         if (StraceFile != stderr)
02608                 fclose(StraceFile);
02609 
02610         return success;
02611 }
02612 #endif // LL_SOLARIS
02613 
02614 void viewer_crash_callback()
02615 {
02616         // This will drop us into the debugger.
02617         if (being_debugged())
02618         {
02619                 abort();
02620         }
02621 
02622         // Returns whether a dialog was shown.
02623         // Only do the logic in here once
02624         if (gReportedCrash)
02625         {
02626                 return;
02627         }
02628         gReportedCrash = TRUE;
02629 
02630         BOOL do_crash_report = FALSE;
02631 
02632         do_crash_report = TRUE;
02633 
02634         write_debug("Viewer exe: ");
02635         write_debug(gDirUtilp->getExecutablePathAndName().c_str());
02636         write_debug("\n");
02637         write_debug("Cur path: ");
02638         write_debug(gDirUtilp->getCurPath().c_str());
02639         write_debug("\n\n");
02640 
02641         if (gMessageSystem && gDirUtilp)
02642         {
02643                 std::string filename;
02644                 filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "stats.log");
02645                 llofstream file(filename.c_str(), llofstream::binary);
02646                 if(file.good())
02647                 {
02648                         gMessageSystem->summarizeLogs(file);
02649                 }
02650         }
02651 
02652         if (gMessageSystem)
02653         {
02654                 write_debug(gMessageSystem->getCircuitInfoString());
02655                 gMessageSystem->stopLogging();
02656         }
02657         write_debug("\n");
02658         if (gWorldp)
02659         {
02660                 write_debug(gWorldp->getInfoString());
02661         }
02662 
02663         // Close the debug file
02664         close_debug();
02665         LLError::logToFile("");
02666 
02667         // Close the SecondLife.log
02668 
02669         remove_marker_file();
02670 
02671 #if LL_WINDOWS
02672         // Windows
02673         std::string exe_path = gDirUtilp->getAppRODataDir();
02674         exe_path += gDirUtilp->getDirDelimiter();
02675         exe_path += "win_crash_logger.exe";
02676 
02677         std::string arg_string = "-user ";
02678         arg_string += gUserServerName;
02679 
02680         switch(gCrashBehavior)
02681         {
02682         case CRASH_BEHAVIOR_ASK:
02683         default:
02684                 arg_string += " -dialog ";
02685                 _spawnl(_P_NOWAIT, exe_path.c_str(), exe_path.c_str(), arg_string.c_str(), NULL);
02686                 break;
02687 
02688         case CRASH_BEHAVIOR_ALWAYS_SEND:
02689                 _spawnl(_P_NOWAIT, exe_path.c_str(), exe_path.c_str(), arg_string.c_str(), NULL);
02690                 break;
02691 
02692         case CRASH_BEHAVIOR_NEVER_SEND:
02693                 break;
02694         }
02695 
02696 #elif LL_DARWIN
02697         // Macintosh
02698         LLString command_str;
02699         command_str = "crashreporter.app/Contents/MacOS/crashreporter ";
02700         command_str += "-user ";
02701         command_str += gUserServerName;
02702         command_str += " &";    // This backgrounds the command so system() doesn't block until the crashreporter exits.
02703         system(command_str.c_str());            /* Flawfinder: ignore */
02704                 
02705         // Sometimes signals don't seem to quit the viewer.  
02706         // Make sure we exit so as to not totally confuse the user.
02707         exit(1);
02708 #elif LL_LINUX || LL_SOLARIS
02709         // Always generate the report, have the logger do the asking, and
02710         // don't wait for the logger before exiting (-> total cleanup).
02711         if (CRASH_BEHAVIOR_NEVER_SEND != gCrashBehavior)
02712         {       
02713                 // This backtrace writes into stack_trace.log
02714 #  if LL_ELFBIN
02715                 do_elfio_glibc_backtrace(); // more useful backtrace
02716 #  else
02717                 do_basic_glibc_backtrace(); // only slightly useful backtrace
02718 #  endif // LL_ELFBIN
02719                 // launch the actual crash logger
02720                 char* ask_dialog = "-dialog";
02721                 if (CRASH_BEHAVIOR_ASK != gCrashBehavior)
02722                         ask_dialog = ""; // omit '-dialog' option
02723                 std::string cmd =gDirUtilp->getAppRODataDir();
02724                 cmd += gDirUtilp->getDirDelimiter();
02725                 cmd += "linux-crash-logger.bin";
02726                 char* const cmdargv[] =
02727                         {(char*)cmd.c_str(),
02728                          ask_dialog,
02729                          (char*)"-user",
02730                          (char*)gUserServerName,
02731                          (char*)"-name",
02732                          (char*)gSecondLife.c_str(),
02733                          NULL};
02734                 fflush(NULL);
02735                 pid_t pid = fork();
02736                 if (pid == 0)
02737                 { // child
02738                         execv(cmd.c_str(), cmdargv);            /* Flawfinder: ignore */
02739                         llwarns << "execv failure when trying to start " << cmd << llendl;
02740                         _exit(1); // avoid atexit()
02741                 } else {
02742                         if (pid > 0)
02743                         {
02744                                 // DO NOT wait for child proc to die; we want
02745                                 // the logger to outlive us while we quit to
02746                                 // free up the screen/keyboard/etc.
02749                         } else {
02750                                 llwarns << "fork failure." << llendl;
02751                         }
02752                 }
02753         }
02754         // Sometimes signals don't seem to quit the viewer.  
02755         // Make sure we exit so as to not totally confuse the user.
02756         exit(1);
02757 #else
02758     #error do something with your platform.
02759 #endif // LL_DARWIN
02760 
02761         return;
02762 }
02763 
02764 
02765 
02766 BOOL init_cache()
02767 {
02768         gPurgeCache = FALSE;
02769         // Purge cache if user requested it
02770         if (gSavedSettings.getBOOL("PurgeCacheOnStartup") ||
02771                 gSavedSettings.getBOOL("PurgeCacheOnNextStartup"))
02772         {
02773                 gSavedSettings.setBOOL("PurgeCacheOnNextStartup", FALSE);
02774                 gPurgeCache = TRUE;
02775         }
02776         // Purge cache if it belongs to an old version
02777         else
02778         {
02779                 static const S32 cache_version = 5;
02780                 if (gSavedSettings.getS32("LocalCacheVersion") != cache_version)
02781                 {
02782                         gPurgeCache = TRUE;
02783                         gSavedSettings.setS32("LocalCacheVersion", cache_version);
02784                 }
02785         }
02786         
02787         // Setup and verify the cache location
02788         LLString cache_location = gSavedSettings.getString("CacheLocation");
02789         LLString new_cache_location = gSavedSettings.getString("NewCacheLocation");
02790         if (new_cache_location != cache_location)
02791         {
02792                 gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"));
02793                 purge_cache(); // purge old cache
02794                 gSavedSettings.setString("CacheLocation", new_cache_location);
02795         }
02796         
02797         if (!gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")))
02798         {
02799                 llwarns << "Unable to set cache location" << llendl;
02800                 gSavedSettings.setString("CacheLocation", "");
02801         }
02802         
02803         if (gPurgeCache)
02804         {
02805                 LLSplashScreen::update("Clearing cache...");
02806                 purge_cache();
02807         }
02808 
02809         LLSplashScreen::update("Initializing Texture Cache...");
02810         
02811         // Init the texture cache
02812         // Allocate 80% of the cache size for textures
02813         BOOL read_only = gSecondInstance ? TRUE : FALSE;
02814         const S32 MB = 1024*1024;
02815         S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB;
02816         const S64 MAX_CACHE_SIZE = 1024*MB;
02817         cache_size = llmin(cache_size, MAX_CACHE_SIZE);
02818         S64 texture_cache_size = ((cache_size * 8)/10);
02819         S64 extra = gTextureCache->initCache(LL_PATH_CACHE, texture_cache_size, read_only);
02820         texture_cache_size -= extra;
02821 
02822         LLSplashScreen::update("Initializing VFS...");
02823         
02824         // Init the VFS
02825         S64 vfs_size = cache_size - texture_cache_size;
02826         const S64 MAX_VFS_SIZE = 1024 * MB; // 1 GB
02827         vfs_size = llmin(vfs_size, MAX_VFS_SIZE);
02828         vfs_size = (vfs_size / MB) * MB; // make sure it is MB aligned
02829         U32 vfs_size_u32 = (U32)vfs_size;
02830         U32 old_vfs_size = gSavedSettings.getU32("VFSOldSize") * MB;
02831         bool resize_vfs = (vfs_size_u32 != old_vfs_size);
02832         if (resize_vfs)
02833         {
02834                 gSavedSettings.setU32("VFSOldSize", vfs_size_u32/MB);
02835         }
02836         llinfos << "VFS CACHE SIZE: " << vfs_size/(1024*1024) << " MB" << llendl;
02837         
02838         // This has to happen BEFORE starting the vfs
02839         //time_t        ltime;
02840         srand(time(NULL));              /* Flawfinder: ignore */
02841         U32 old_salt = gSavedSettings.getU32("VFSSalt");
02842         U32 new_salt;
02843         char old_vfs_data_file[LL_MAX_PATH];            /* Flawfinder: ignore */
02844         char old_vfs_index_file[LL_MAX_PATH];   /* Flawfinder: ignore */                
02845         char new_vfs_data_file[LL_MAX_PATH];            /* Flawfinder: ignore */
02846         char new_vfs_index_file[LL_MAX_PATH];   /* Flawfinder: ignore */
02847         char static_vfs_index_file[LL_MAX_PATH];        /* Flawfinder: ignore */
02848         char static_vfs_data_file[LL_MAX_PATH]; /* Flawfinder: ignore */
02849 
02850         if (gMultipleViewersOK)
02851         {
02852                 // don't mess with renaming the VFS in this case
02853                 new_salt = old_salt;
02854         }
02855         else
02856         {
02857                 do
02858                 {
02859                         new_salt = rand();
02860                 } while( new_salt == old_salt );
02861         }
02862 
02863         snprintf(old_vfs_data_file,  LL_MAX_PATH, "%s%u",               /* Flawfinder: ignore */
02864                 gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE).c_str(),
02865                 old_salt);
02866 
02867         // make sure this file exists
02868         llstat s;
02869         S32 stat_result = LLFile::stat(old_vfs_data_file, &s);
02870         if (stat_result)
02871         {
02872                 // doesn't exist, look for a data file
02873                 std::string mask;
02874                 mask = gDirUtilp->getDirDelimiter();
02875                 mask += VFS_DATA_FILE_BASE;
02876                 mask += "*";
02877 
02878                 std::string dir;
02879                 dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");
02880 
02881                 std::string found_file;
02882                 if (gDirUtilp->getNextFileInDir(dir, mask, found_file, FALSE))
02883                 {
02884                         snprintf(old_vfs_data_file, LL_MAX_PATH, "%s%s%s", dir.c_str(), gDirUtilp->getDirDelimiter().c_str(), found_file.c_str());              /* Flawfinder: ignore */
02885 
02886                         S32 start_pos;
02887                         S32 length = strlen(found_file.c_str());                /* Flawfinder: ignore*/
02888                         for (start_pos = length - 1; start_pos >= 0; start_pos--)
02889                         {
02890                                 if (found_file[start_pos] == '.')
02891                                 {
02892                                         start_pos++;
02893                                         break;
02894                                 }
02895                         }
02896                         if (start_pos > 0)
02897                         {
02898                                 sscanf(found_file.c_str() + start_pos, "%d", &old_salt);
02899                         }
02900                         llinfos << "Default vfs data file not present, found " << old_vfs_data_file << llendl;
02901                         llinfos << "Old salt: " << old_salt << llendl;
02902                 }
02903         }
02904 
02905         snprintf(old_vfs_index_file, LL_MAX_PATH, "%s%u",               /* Flawfinder: ignore */
02906                         gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_INDEX_FILE_BASE).c_str(),
02907                         old_salt);
02908 
02909         stat_result = LLFile::stat(old_vfs_index_file, &s);
02910         if (stat_result)
02911         {
02912                 // We've got a bad/missing index file, nukem!
02913                 llwarns << "Bad or missing vfx index file " << old_vfs_index_file << llendl;
02914                 llwarns << "Removing old vfs data file " << old_vfs_data_file << llendl;
02915                 LLFile::remove(old_vfs_data_file);
02916                 LLFile::remove(old_vfs_index_file);
02917                 
02918                 // Just in case, nuke any other old cache files in the directory.
02919                 std::string dir;
02920                 dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");
02921 
02922                 std::string mask;
02923                 mask = gDirUtilp->getDirDelimiter();
02924                 mask += VFS_DATA_FILE_BASE;
02925                 mask += "*";
02926 
02927                 gDirUtilp->deleteFilesInDir(dir, mask);
02928 
02929                 mask = gDirUtilp->getDirDelimiter();
02930                 mask += VFS_INDEX_FILE_BASE;
02931                 mask += "*";
02932 
02933                 gDirUtilp->deleteFilesInDir(dir, mask);
02934         }
02935 
02936         snprintf(new_vfs_data_file, LL_MAX_PATH, "%s%u",                /* Flawfinder: ignore */
02937                 gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE).c_str(),
02938                 new_salt);
02939 
02940         snprintf(new_vfs_index_file, LL_MAX_PATH, "%s%u", gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_INDEX_FILE_BASE).c_str(),           /* Flawfinder: ignore */
02941                 new_salt);
02942 
02943 
02944         strncpy(static_vfs_data_file, gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_data.db2").c_str(), LL_MAX_PATH -1);          /* Flawfinder: ignore */
02945         static_vfs_data_file[LL_MAX_PATH -1] = '\0';
02946         strncpy(static_vfs_index_file, gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_index.db2").c_str(), LL_MAX_PATH -1);                /* Flawfinder: ignore */
02947         static_vfs_index_file[LL_MAX_PATH -1] = '\0';
02948 
02949         if (resize_vfs)
02950         {
02951                 llinfos << "Removing old vfs and re-sizing" << llendl;
02952                 
02953                 LLFile::remove(old_vfs_data_file);
02954                 LLFile::remove(old_vfs_index_file);
02955         }
02956         else if (old_salt != new_salt)
02957         {
02958                 // move the vfs files to a new name before opening
02959                 llinfos << "Renaming " << old_vfs_data_file << " to " << new_vfs_data_file << llendl;
02960                 llinfos << "Renaming " << old_vfs_index_file << " to " << new_vfs_index_file << llendl;
02961                 LLFile::rename(old_vfs_data_file, new_vfs_data_file);
02962                 LLFile::rename(old_vfs_index_file, new_vfs_index_file);
02963         }
02964 
02965         // Startup the VFS...
02966         gSavedSettings.setU32("VFSSalt", new_salt);
02967 
02968         // Don't remove VFS after viewer crashes.  If user has corrupt data, they can reinstall. JC
02969         gVFS = new LLVFS(new_vfs_index_file, new_vfs_data_file, FALSE, vfs_size_u32, FALSE);
02970         if( VFSVALID_BAD_CORRUPT == gVFS->getValidState() )
02971         {
02972                 // Try again with fresh files 
02973                 // (The constructor deletes corrupt files when it finds them.)
02974                 llwarns << "VFS corrupt, deleted.  Making new VFS." << llendl;
02975                 delete gVFS;
02976                 gVFS = new LLVFS(new_vfs_index_file, new_vfs_data_file, FALSE, vfs_size_u32, FALSE);
02977         }
02978 
02979         gStaticVFS = new LLVFS(static_vfs_index_file, static_vfs_data_file, TRUE, 0, FALSE);
02980 
02981         BOOL success = gVFS->isValid() && gStaticVFS->isValid();
02982         if( !success )
02983         {
02984                 return FALSE;
02985         }
02986         else
02987         {
02988                 LLVFile::initClass();
02989                 return TRUE;
02990         }
02991 }
02992 
02993 #if LL_DARWIN
02994 
02995 OSErr AEGURLHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn)
02996 {
02997         OSErr result = noErr;
02998         DescType actualType;
02999         char buffer[1024];              /* Flawfinder: ignore */
03000         Size size;
03001         
03002         result = AEGetParamPtr (
03003                 messagein,
03004                 keyDirectObject,
03005                 typeCString,
03006                 &actualType,
03007                 (Ptr)buffer,
03008                 sizeof(buffer),
03009                 &size); 
03010         
03011         if(result == noErr)
03012         {
03013                 std::string url = buffer;
03014                 LLURLDispatcher::dispatch(url);
03015         }
03016         
03017         return(result);
03018 }
03019 
03020 OSErr AEQuitHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn)
03021 {
03022         OSErr result = noErr;
03023         
03024         app_user_quit();
03025         
03026         return(result);
03027 }
03028 
03029 OSStatus simpleDialogHandler(EventHandlerCallRef handler, EventRef event, void *userdata)
03030 {
03031         OSStatus result = eventNotHandledErr;
03032         OSStatus err;
03033         UInt32 evtClass = GetEventClass(event);
03034         UInt32 evtKind = GetEventKind(event);
03035         WindowRef window = (WindowRef)userdata;
03036         
03037         if((evtClass == kEventClassCommand) && (evtKind == kEventCommandProcess))
03038         {
03039                 HICommand cmd;
03040                 err = GetEventParameter(event, kEventParamDirectObject, typeHICommand, NULL, sizeof(cmd), NULL, &cmd);
03041                 
03042                 if(err == noErr)
03043                 {
03044                         switch(cmd.commandID)
03045                         {
03046                                 case kHICommandOK:
03047                                         QuitAppModalLoopForWindow(window);
03048                                         result = noErr;
03049                                 break;
03050                                 
03051                                 case kHICommandCancel:
03052                                         QuitAppModalLoopForWindow(window);
03053                                         result = userCanceledErr;
03054                                 break;
03055                         }
03056                 }
03057         }
03058         
03059         return(result);
03060 }
03061 
03062 OSStatus DisplayReleaseNotes(void)
03063 {
03064         OSStatus err;
03065         IBNibRef nib = NULL;
03066         WindowRef window = NULL;
03067         
03068         err = CreateNibReference(CFSTR("SecondLife"), &nib);
03069         
03070         if(err == noErr)
03071         {
03072                 CreateWindowFromNib(nib, CFSTR("Release Notes"), &window);
03073         }
03074                 
03075         if(err == noErr)
03076         {
03077                 // Get the text view control
03078                 HIViewRef textView;
03079                 ControlID id;
03080 
03081                 id.signature = 'text';
03082                 id.id = 0;
03083 
03084                 std::string releaseNotesText;
03085                 _read_file_into_string(releaseNotesText, "releasenotes.txt");
03086 
03087                 err = HIViewFindByID(HIViewGetRoot(window), id, &textView);
03088                 
03089                 if(err == noErr)
03090                 {
03091                         // Convert from the encoding used in the release notes.
03092                         CFStringRef str = CFStringCreateWithBytes(
03093                                 NULL, 
03094                                 (const UInt8*)releaseNotesText.c_str(), 
03095                                 releaseNotesText.size(), 
03096                                 kCFStringEncodingWindowsLatin1,                 // This matches the way the Windows version displays the release notes.
03097                                 FALSE);
03098                         
03099                         if(str != NULL)
03100                         {
03101                                 int size = CFStringGetLength(str);
03102 
03103                                 if(size > 0)
03104                                 {
03105                                         UniChar *chars = new UniChar[size + 1];
03106                                         CFStringGetCharacters(str, CFRangeMake(0, size), chars);
03107                                 
03108                                         err = TXNSetData(HITextViewGetTXNObject(textView), kTXNUnicodeTextData, chars, size * sizeof(UniChar), kTXNStartOffset, kTXNStartOffset);
03109                                         
03110                                         delete[] chars;
03111                                 }
03112                                 
03113                                 CFRelease(str);
03114                         }
03115                         else
03116                         {
03117                                 // Creating the string failed.  Probably an encoding problem.  Display SOMETHING...
03118                                 err = TXNSetData(HITextViewGetTXNObject(textView), kTXNTextData, releaseNotesText.c_str(), releaseNotesText.size(), kTXNStartOffset, kTXNStartOffset);
03119                         }
03120                 }
03121                 
03122                 // Set the selection to the beginning of the text and scroll it into view.
03123                 if(err == noErr)
03124                 {
03125                         err = TXNSetSelection(HITextViewGetTXNObject(textView), kTXNStartOffset, kTXNStartOffset);
03126                 }
03127                 
03128                 if(err == noErr)
03129                 {
03130                         // This function returns void.
03131                         TXNShowSelection(HITextViewGetTXNObject(textView), false);
03132                 }
03133         }
03134 
03135         if(err == noErr)
03136         {
03137                 ShowWindow(window);
03138         }
03139 
03140         if(err == noErr)
03141         {
03142                 // Set up an event handler for the window.
03143                 EventHandlerRef handler = NULL;
03144                 EventTypeSpec handlerEvents[] = 
03145                 {
03146                         { kEventClassCommand, kEventCommandProcess }
03147                 };
03148 
03149                 InstallWindowEventHandler(
03150                                 window, 
03151                                 NewEventHandlerUPP(simpleDialogHandler), 
03152                                 GetEventTypeCount (handlerEvents), 
03153                                 handlerEvents, 
03154                                 (void*)window, 
03155                                 &handler);
03156         }
03157                         
03158         if(err == noErr)
03159         {
03160                 RunAppModalLoopForWindow(window);
03161         }
03162                         
03163         if(window != NULL)
03164         {
03165                 DisposeWindow(window);
03166         }
03167         
03168         if(nib != NULL)
03169         {
03170                 DisposeNibReference(nib);
03171         }
03172 
03173         return(err);
03174 }
03175 
03176 void init_apple_menu(const char* product)
03177 {
03178         // Load up a proper menu bar.
03179         {
03180                 OSStatus err;
03181                 IBNibRef nib = NULL;
03182                 // NOTE: DO NOT translate or brand this string.  It's an internal name in the .nib file, and MUST match exactly.
03183                 err = CreateNibReference(CFSTR("SecondLife"), &nib);
03184                 
03185                 if(err == noErr)
03186                 {
03187                         // NOTE: DO NOT translate or brand this string.  It's an internal name in the .nib file, and MUST match exactly.
03188                         SetMenuBarFromNib(nib, CFSTR("MenuBar"));
03189                 }
03190 
03191                 if(nib != NULL)
03192                 {
03193                         DisposeNibReference(nib);
03194                 }
03195         }
03196         
03197         // Install a handler for 'gurl' AppleEvents.  This is how secondlife:// URLs get passed to the viewer.
03198         
03199         if(AEInstallEventHandler('GURL', 'GURL', NewAEEventHandlerUPP(AEGURLHandler),0, false) != noErr)
03200         {
03201                 // Couldn't install AppleEvent handler.  This error shouldn't be fatal.
03202                 llinfos << "Couldn't install 'GURL' AppleEvent handler.  Continuing..." << llendl;
03203         }
03204 
03205         // Install a handler for 'quit' AppleEvents.  This makes quitting the application from the dock work.
03206         if(AEInstallEventHandler(kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP(AEQuitHandler),0, false) != noErr)
03207         {
03208                 // Couldn't install AppleEvent handler.  This error shouldn't be fatal.
03209                 llinfos << "Couldn't install Quit AppleEvent handler.  Continuing..." << llendl;
03210         }
03211 }
03212 #endif
03213 
03214 void user_logout()
03215 {
03216         if (!gDoneLogout)
03217         {
03218                 LLMessageSystem* msg = gMessageSystem;
03219                 if (msg)
03220                 {
03221                                 gSavedSettings.setBOOL("LoggedIn", FALSE);
03222                 }
03223                 gDoneLogout = TRUE;
03224         }
03225 }
03226 
03227 
03228 // This routine may get called more than once during the shutdown process.
03229 // This can happen because we need to get the screenshot before the window
03230 // is destroyed.
03231 void save_final_snapshot(void*)
03232 {
03233         if (!gHaveSavedSnapshot && !gNoRender)
03234         {
03235                 gSavedSettings.setVector3d("FocusPosOnLogout", gAgent.calcFocusPositionTargetGlobal());
03236                 gSavedSettings.setVector3d("CameraPosOnLogout", gAgent.calcCameraPositionTargetGlobal());
03237                 gViewerWindow->setCursor(UI_CURSOR_WAIT);
03238                 gAgent.changeCameraToThirdPerson( FALSE );      // don't animate, need immediate switch
03239                 gSavedSettings.setBOOL("ShowParcelOwners", FALSE);
03240                 idle();
03241 
03242                 LLString snap_filename = gDirUtilp->getLindenUserDir();
03243                 snap_filename += gDirUtilp->getDirDelimiter();
03244                 snap_filename += SCREEN_LAST_FILENAME;
03245                 gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidth(), gViewerWindow->getWindowHeight(), FALSE, TRUE);
03246                 gHaveSavedSnapshot = TRUE;
03247         }
03248 }
03249 
03250 // If you pass a path+file or URL in as a 
03251 // Note: This may get called multiple times during shutdown.
03252 void app_force_quit(const char* launch_file_on_quit)
03253 {
03254         // Don't actually DO anything complicated here, because
03255         // it's called from signal handlers for the Mac on SIGTERM.
03256         // It calls this with NULL.
03257         if (launch_file_on_quit)
03258         {
03259                 gLaunchFileOnQuit.assign( (const char*)launch_file_on_quit );
03260         }
03261 
03262         gQuit = TRUE;
03263 }
03264 
03265 static void finish_quit(S32 option, void *userdata)
03266 {
03267         if (option == 0)
03268         {
03269                 app_request_quit();
03270         }
03271 }
03272 
03273 void app_user_quit()
03274 {
03275         gViewerWindow->alertXml("ConfirmQuit", finish_quit, NULL);
03276 }
03277 
03278   
03279 // Don't quit instantly.  Instead, request to be logged off.
03280 // Called from control-Q handler, Windows(tm) close-window message (WM_CLOSE), and Mac Quit AppleEvent handler.
03281 void app_request_quit()
03282 {
03283         llinfos << "app_request_quit" << llendl;
03284 
03285         LLViewerRegion* region = gAgent.getRegion();
03286         
03287         if( (LLStartUp::getStartupState() < STATE_STARTED) || !region )
03288         {
03289                 // Quit immediately
03290                 app_force_quit(NULL);
03291                 return;
03292         }
03293 
03294         if (gHUDManager)
03295         {
03296                 LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
03297                 effectp->setPositionGlobal(gAgent.getPositionGlobal());
03298                 effectp->setColor(LLColor4U(gAgent.getEffectColor()));
03299                 gHUDManager->sendEffects();
03300         }
03301 
03302         // Attempt to close all floaters that might be
03303         // editing things.
03304         if (gFloaterView)
03305         {
03306                 // application is quitting
03307                 gFloaterView->closeAllChildren(true);
03308         }
03309 
03310         send_stats();
03311 
03312         gLogoutTimer.reset();
03313         gQuitRequested = TRUE;
03314 }
03315 
03316 
03317 // User didn't really want to quit, for example, clicked "Cancel"
03318 // in a floater save dialog.
03319 void app_abort_quit()
03320 {
03321         llinfos << "app_abort_quit()" << llendl;
03322         gQuitRequested = FALSE;
03323 }
03324 
03325 void idle_shutdown()
03326 {
03327         // Wait for all modal alerts to get resolved
03328         if (LLModalDialog::activeCount() > 0)
03329         {
03330                 return;
03331         }
03332 
03333         // close IM interface
03334         if(gIMMgr)
03335         {
03336                 gIMMgr->disconnectAllSessions();
03337         }
03338         
03339         // Wait for all floaters to get resolved
03340         if (gFloaterView
03341                 && !gFloaterView->allChildrenClosed())
03342         {
03343                 return;
03344         }
03345 
03346         static bool saved_snapshot = false;
03347         if (!saved_snapshot)
03348         {
03349                 saved_snapshot = true;
03350                 save_final_snapshot(NULL);
03351                 return;
03352         }
03353 
03354         const F32 SHUTDOWN_UPLOAD_SAVE_TIME = 5.f;
03355 
03356         S32 pending_uploads = gAssetStorage->getNumPendingUploads();
03357         if (pending_uploads > 0
03358                 && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME
03359                 && !gLogoutRequestSent)
03360         {
03361                 static S32 total_uploads = 0;
03362                 // Sometimes total upload count can change during logout.
03363                 total_uploads = llmax(total_uploads, pending_uploads);
03364                 gViewerWindow->setShowProgress(TRUE);
03365                 S32 finished_uploads = total_uploads - pending_uploads;
03366                 F32 percent = 100.f * finished_uploads / total_uploads;
03367                 gViewerWindow->setProgressPercent(percent);
03368                 char buffer[MAX_STRING];                /* Flawfinder: ignore */
03369                 snprintf(buffer, MAX_STRING, "Saving final data...");           /* Flawfinder: ignore */
03370                 gViewerWindow->setProgressString(buffer);
03371                 return;
03372         }
03373 
03374         // All floaters are closed.  Tell server we want to quit.
03375         if( !gLogoutRequestSent )
03376         {
03377                 send_logout_request();
03378 
03379                 // Wait for a LogoutReply message
03380                 gViewerWindow->setShowProgress(TRUE);
03381                 gViewerWindow->setProgressPercent(100.f);
03382                 gViewerWindow->setProgressString("Logging out...");
03383                 return;
03384         }
03385 
03386         // Make sure that we quit if we haven't received a reply from the server.
03387         if( gLogoutRequestSent 
03388                 && gLogoutTimer.getElapsedTimeF32() > gLogoutMaxTime )
03389         {
03390                 app_force_quit(NULL);
03391                 return;
03392         }
03393 }
03394 
03395 
03396 U32             gTotalLandIn = 0, gTotalLandOut = 0;
03397 U32             gTotalWaterIn = 0, gTotalWaterOut = 0;
03398 
03399 F32             gAveLandCompression = 0.f, gAveWaterCompression = 0.f;
03400 F32             gBestLandCompression = 1.f, gBestWaterCompression = 1.f;
03401 F32             gWorstLandCompression = 0.f, gWorstWaterCompression = 0.f;
03402 
03403 F32             gFPSClamped = 10.f;                                             // Pretend we start at target rate.
03404 F32             gFrameDTClamped = 0.f;                                  // Time between adjacent checks to network for packets
03405 F32             gFrameDT = 0.f;
03406 
03407 //S32           gDecodedBits = 0;
03408 U32             gPacketsIn = 0;
03409 
03410 U32             gTotalWorldBytes = 0, gTotalObjectBytes = 0, gTotalTextureBytes = 0, gSimPingCount = 0;
03411 U32             gObjectBits = 0;
03412 F32             gAvgSimPing = 0.f;
03413 
03414 
03415 extern U32  gVisCompared;
03416 extern U32  gVisTested;
03417 
03418 
03419 void update_statistics(U32 frame_count)
03420 {
03421         gTotalWorldBytes += gVLManager.getTotalBytes();
03422         gTotalObjectBytes += gObjectBits / 8;
03423         gTotalTextureBytes += LLViewerImageList::sTextureBits / 8;
03424 
03425         // make sure we have a valid time delta for this frame
03426         if (gFrameIntervalSeconds > 0.f)
03427         {
03428                 if (gAgent.getCameraMode() == CAMERA_MODE_MOUSELOOK)
03429                 {
03430                         gViewerStats->incStat(LLViewerStats::ST_MOUSELOOK_SECONDS, gFrameIntervalSeconds);
03431                 }
03432                 else if (gAgent.getCameraMode() == CAMERA_MODE_CUSTOMIZE_AVATAR)
03433                 {
03434                         gViewerStats->incStat(LLViewerStats::ST_AVATAR_EDIT_SECONDS, gFrameIntervalSeconds);
03435                 }
03436                 else if (gFloaterTools && gFloaterTools->getVisible())
03437                 {
03438                         gViewerStats->incStat(LLViewerStats::ST_TOOLBOX_SECONDS, gFrameIntervalSeconds);
03439                 }
03440         }
03441         gViewerStats->setStat(LLViewerStats::ST_ENABLE_VBO, (F64)gSavedSettings.getBOOL("RenderVBOEnable"));
03442         gViewerStats->setStat(LLViewerStats::ST_LIGHTING_DETAIL, (F64)gSavedSettings.getS32("RenderLightingDetail"));
03443         gViewerStats->setStat(LLViewerStats::ST_DRAW_DIST, (F64)gSavedSettings.getF32("RenderFarClip"));
03444         gViewerStats->setStat(LLViewerStats::ST_CHAT_BUBBLES, (F64)gSavedSettings.getBOOL("UseChatBubbles"));
03445 #if 0 // 1.9.2
03446         gViewerStats->setStat(LLViewerStats::ST_SHADER_OBJECTS, (F64)gSavedSettings.getS32("VertexShaderLevelObject"));
03447         gViewerStats->setStat(LLViewerStats::ST_SHADER_AVATAR, (F64)gSavedSettings.getBOOL("VertexShaderLevelAvatar"));
03448         gViewerStats->setStat(LLViewerStats::ST_SHADER_ENVIRONMENT, (F64)gSavedSettings.getBOOL("VertexShaderLevelEnvironment"));
03449 #endif
03450         gViewerStats->setStat(LLViewerStats::ST_FRAME_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_FRAME));
03451         F64 idle_secs = gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_IDLE);
03452         F64 network_secs = gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_NETWORK);
03453         gViewerStats->setStat(LLViewerStats::ST_UPDATE_SECS, idle_secs - network_secs);
03454         gViewerStats->setStat(LLViewerStats::ST_NETWORK_SECS, network_secs);
03455         gViewerStats->setStat(LLViewerStats::ST_IMAGE_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_IMAGE_UPDATE));
03456         gViewerStats->setStat(LLViewerStats::ST_REBUILD_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_REBUILD));
03457         gViewerStats->setStat(LLViewerStats::ST_RENDER_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_RENDER_GEOMETRY));
03458                 
03459         LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost());
03460         if (cdp)
03461         {
03462                 gViewerStats->mSimPingStat.addValue(cdp->getPingDelay());
03463                 gAvgSimPing = ((gAvgSimPing * (F32)gSimPingCount) + (F32)(cdp->getPingDelay())) / ((F32)gSimPingCount + 1);
03464                 gSimPingCount++;
03465         }
03466         else
03467         {
03468                 gViewerStats->mSimPingStat.addValue(10000);
03469         }
03470 
03471         if (gFocusMgr.getAppHasFocus())
03472         {
03473                 gViewerStats->mFPSStat.addValue(1);
03474         }
03475         F32 layer_bits = (F32)(gVLManager.getLandBits() + gVLManager.getWindBits() + gVLManager.getCloudBits());
03476         gViewerStats->mLayersKBitStat.addValue(layer_bits/1024.f);
03477         gViewerStats->mObjectKBitStat.addValue(gObjectBits/1024.f);
03478         gViewerStats->mTextureKBitStat.addValue(LLViewerImageList::sTextureBits/1024.f);
03479         gViewerStats->mVFSPendingOperations.addValue(LLVFile::getVFSThread()->getPending());
03480         gViewerStats->mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f);
03481         gTransferManager.resetTransferBitsIn(LLTCT_ASSET);
03482 
03483         static S32 tex_bits_idle_count = 0;
03484         if (LLViewerImageList::sTextureBits == 0)
03485         {
03486                 if (++tex_bits_idle_count >= 30)
03487                         gDebugTimers[0].pause();
03488         }
03489         else
03490         {
03491                 tex_bits_idle_count = 0;
03492                 gDebugTimers[0].unpause();
03493         }
03494         
03495         gViewerStats->mTexturePacketsStat.addValue(LLViewerImageList::sTexturePackets);
03496 
03497         gViewerStats->mUserserverPingStat.addValue(0); // userserver doesn't exist, therefore ping time is always awesome
03498 
03499         // log when the LibXUL (aka Mozilla) widget is used and opened so we can monitor framerate changes
03500         #if LL_LIBXUL_ENABLED
03501         {
03502                 BOOL result = gViewerHtmlHelp.getFloaterOpened();
03503                 gViewerStats->setStat(LLViewerStats::ST_LIBXUL_WIDGET_USED, (F64)result);
03504         }
03505         #endif
03506 
03507         {
03508                 static F32 visible_avatar_frames = 0.f;
03509                 static F32 avg_visible_avatars = 0;
03510                 F32 visible_avatars = (F32)LLVOAvatar::sNumVisibleAvatars;
03511                 if (visible_avatars > 0.f)
03512                 {
03513                         visible_avatar_frames = 1.f;
03514                         avg_visible_avatars = (avg_visible_avatars * (F32)(visible_avatar_frames - 1.f) + visible_avatars) / visible_avatar_frames;
03515                 }
03516                 gViewerStats->setStat(LLViewerStats::ST_VISIBLE_AVATARS, (F64)avg_visible_avatars);
03517         }
03518         gWorldp->updateNetStats();
03519         gWorldp->requestCacheMisses();
03520         
03521         // Reset all of these values.
03522         gVLManager.resetBitCounts();
03523         gObjectBits = 0;
03524 //      gDecodedBits = 0;
03525 
03526         LLViewerImageList::sTextureBits = 0;
03527         LLViewerImageList::sTexturePackets = 0;
03528 
03529 #if LL_WINDOWS && LL_LCD_COMPILE
03530         bool LCDenabled = gLcdScreen->Enabled();
03531         gViewerStats->setStat(LLViewerStats::ST_LOGITECH_LCD, LCDenabled);
03532 #else
03533         gViewerStats->setStat(LLViewerStats::ST_LOGITECH_LCD, false);
03534 #endif
03535 
03536 }
03537 
03538 //
03539 // Handle messages, and all message related stuff
03540 //
03541 
03542 #define TIME_THROTTLE_MESSAGES
03543 
03544 #ifdef TIME_THROTTLE_MESSAGES
03545 #define CHECK_MESSAGES_DEFAULT_MAX_TIME .020f // 50 ms = 50 fps (just for messages!)
03546 static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
03547 #endif
03548 
03549 void idle_network()
03550 {
03551         gObjectList.mNumNewObjects = 0;
03552         S32 total_decoded = 0;
03553 
03554         if (!gSavedSettings.getBOOL("SpeedTest"))
03555         {
03556                 LLFastTimer t(LLFastTimer::FTM_IDLE_NETWORK); // decode
03557                 
03558                 // deal with any queued name requests and replies.
03559                 gCacheName->processPending();
03560 
03561                 LLTimer check_message_timer;
03562                 //  Read all available packets from network 
03563                 stop_glerror();
03564                 const S64 frame_count = gFrameCount;  // U32->S64
03565                 F32 total_time = 0.0f;
03566                 while (gMessageSystem->checkAllMessages(frame_count, gServicePump)) 
03567                 {
03568                         if (gDoDisconnect)
03569                         {
03570                                 // We're disconnecting, don't process any more messages from the server
03571                                 // We're usually disconnecting due to either network corruption or a
03572                                 // server going down, so this is OK.
03573                                 break;
03574                         }
03575                         stop_glerror();
03576 
03577                         total_decoded++;
03578                         gPacketsIn++;
03579 
03580                         if (total_decoded > MESSAGE_MAX_PER_FRAME)
03581                         {
03582                                 break;
03583                         }
03584 
03585 #ifdef TIME_THROTTLE_MESSAGES
03586                         // Prevent slow packets from completely destroying the frame rate.
03587                         // This usually happens due to clumps of avatars taking huge amount
03588                         // of network processing time (which needs to be fixed, but this is
03589                         // a good limit anyway).
03590                         total_time = check_message_timer.getElapsedTimeF32();
03591                         if (total_time >= CheckMessagesMaxTime)
03592                                 break;
03593 #endif
03594                 }
03595                 // Handle per-frame message system processing.
03596                 gMessageSystem->processAcks();
03597 
03598 #ifdef TIME_THROTTLE_MESSAGES
03599                 if (total_time >= CheckMessagesMaxTime)
03600                 {
03601                         // Increase CheckMessagesMaxTime so that we will eventually catch up
03602                         CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames
03603                 }
03604                 else
03605                 {
03606                         // Reset CheckMessagesMaxTime to default value
03607                         CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
03608                 }
03609 #endif
03610                 
03611 
03612 
03613                 // we want to clear the control after sending out all necessary agent updates
03614                 gAgent.resetControlFlags();
03615                 stop_glerror();
03616 
03617                 
03618                 // Decode enqueued messages...
03619                 S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded;
03620 
03621                 if( remaining_possible_decodes <= 0 )
03622                 {
03623                         llinfos << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << llendl;
03624                 }
03625 
03626                 if (gPrintMessagesThisFrame)
03627                 {
03628                         llinfos << "Decoded " << total_decoded << " msgs this frame!" << llendl;
03629                         gPrintMessagesThisFrame = FALSE;
03630                 }
03631         }
03632 
03633         gObjectList.mNumNewObjectsStat.addValue(gObjectList.mNumNewObjects);
03634 
03635         // Retransmit unacknowledged packets.
03636         gXferManager->retransmitUnackedPackets();
03637         gAssetStorage->checkForTimeouts();
03638 
03639         gViewerThrottle.updateDynamicThrottle();
03640 }
03641 
03642 void idle_afk_check()
03643 {
03644         // check idle timers
03645         if (gAllowIdleAFK && (gAwayTriggerTimer.getElapsedTimeF32() > gAFKTimeout))
03646         {
03647                 gAgent.setAFK();
03648         }
03649 }
03650 void request_initial_instant_messages()
03651 {
03652         static BOOL requested = FALSE;
03653         if (!requested
03654                 && gMuteListp
03655                 && gMuteListp->isLoaded()
03656                 && gAgent.getAvatarObject())
03657         {
03658                 // Auto-accepted inventory items may require the avatar object
03659                 // to build a correct name.  Likewise, inventory offers from
03660                 // muted avatars require the mute list to properly mute.
03661                 LLMessageSystem* msg = gMessageSystem;
03662                 msg->newMessageFast(_PREHASH_RetrieveInstantMessages);
03663                 msg->nextBlockFast(_PREHASH_AgentData);
03664                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
03665                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
03666                 gAgent.sendReliableMessage();
03667                 requested = TRUE;
03668         }
03669 }
03670 
03672 // idle()
03673 //
03674 // Called every time the window is not doing anything.
03675 // Receive packets, update statistics, and schedule a redisplay.
03677 
03678 void idle()
03679 {
03680         // Update frame timers
03681         static LLTimer idle_timer;
03682 
03683         LLControlBase::updateAllListeners();
03684 
03685         LLFrameTimer::updateFrameTime();
03686         LLEventTimer::updateClass();
03687         LLCriticalDamp::updateInterpolants();
03688         LLMortician::updateClass();
03689         F32 dt_raw = idle_timer.getElapsedTimeAndResetF32();
03690 
03691         // Cap out-of-control frame times
03692         // Too low because in menus, swapping, debugger, etc.
03693         // Too high because idle called with no objects in view, etc.
03694         const F32 MIN_FRAME_RATE = 1.f;
03695         const F32 MAX_FRAME_RATE = 200.f;
03696 
03697         F32 frame_rate_clamped = 1.f / dt_raw;
03698         frame_rate_clamped = llclamp(frame_rate_clamped, MIN_FRAME_RATE, MAX_FRAME_RATE);
03699         gFrameDTClamped = 1.f / frame_rate_clamped;
03700 
03701         // Global frame timer
03702         // Smoothly weight toward current frame
03703         gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f;
03704 
03705         if (gQuitAfterSeconds > 0.f)
03706         {
03707                 if (gRenderStartTime.getElapsedTimeF32() > gQuitAfterSeconds)
03708                 {
03709                         app_force_quit(NULL);
03710                 }
03711         }
03712 
03713         // Must wait until both have avatar object and mute list, so poll
03714         // here.
03715         request_initial_instant_messages();
03716 
03718         //
03719         // Special case idle if still starting up
03720         //
03721 
03722         if (LLStartUp::getStartupState() < STATE_STARTED)
03723         {
03724                 // Skip rest if idle startup returns false (essentially, no world yet)
03725                 if (!idle_startup())
03726                 {
03727                         return;
03728                 }
03729         }
03730 
03731         
03732     F32 yaw = 0.f;                              // radians
03733 
03734         if (!gDisconnected)
03735         {
03736                 LLFastTimer t(LLFastTimer::FTM_NETWORK);
03737                 
03738             // Update spaceserver timeinfo
03739             gWorldp->setSpaceTimeUSec(gWorldp->getSpaceTimeUSec() + (U32)(dt_raw * SEC_TO_MICROSEC));
03740     
03741     
03743             //
03744             // Update simulator agent state
03745             //
03746 
03747                 if (gRotateRight)
03748                 {
03749                         gAgent.moveYaw(-1.f);
03750                 }
03751 
03752             // Handle automatic walking towards points
03753             gAgentPilot.updateTarget();
03754             gAgent.autoPilot(&yaw);
03755     
03756             static LLFrameTimer agent_update_timer;
03757             static U32                          last_control_flags;
03758     
03759             //  When appropriate, update agent location to the simulator.
03760             F32 agent_update_time = agent_update_timer.getElapsedTimeF32();
03761             BOOL flags_changed = gAgent.controlFlagsDirty() || (last_control_flags != gAgent.getControlFlags());
03762     
03763             if (flags_changed || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND)))
03764             {
03765                     // Send avatar and camera info
03766                     last_control_flags = gAgent.getControlFlags();
03767                     send_agent_update(TRUE);
03768                     agent_update_timer.reset();
03769             }
03770         }
03771 
03773         //
03774         // Manage statistics
03775         //
03776         //
03777 
03778         {
03779                 static LLFrameTimer     viewer_stats_timer;
03780                 reset_statistics();
03781 
03782                 // Update session stats every large chunk of time
03783                 // *FIX: (???) SAMANTHA
03784 
03785                 if (viewer_stats_timer.getElapsedTimeF32() >= 300.f && !gDisconnected)
03786                 {
03787                         llinfos << "Transmitting sessions stats" << llendl;
03788                         send_stats();
03789                         viewer_stats_timer.reset();
03790                 }
03791 
03792                 // Print the object debugging stats
03793                 static LLFrameTimer object_debug_timer;
03794                 if (object_debug_timer.getElapsedTimeF32() > 5.f)
03795                 {
03796                         object_debug_timer.reset();
03797                         if (gObjectList.mNumDeadObjectUpdates)
03798                         {
03799                                 llinfos << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << llendl;
03800                                 gObjectList.mNumDeadObjectUpdates = 0;
03801                         }
03802                         if (gObjectList.mNumUnknownKills)
03803                         {
03804                                 llinfos << "Kills on unknown objects: " << gObjectList.mNumUnknownKills << llendl;
03805                                 gObjectList.mNumUnknownKills = 0;
03806                         }
03807                         if (gObjectList.mNumUnknownUpdates)
03808                         {
03809                                 llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl;
03810                                 gObjectList.mNumUnknownUpdates = 0;
03811                         }
03812                 }
03813                 gFrameStats.addFrameData();
03814         }
03815 
03816         // Update avatar list
03817         gFloaterAvatarList->updateAvatarList();
03818 
03819         gFloaterEventLog->updateWindow();
03820 
03821         if (!gDisconnected)
03822         {
03823                 LLFastTimer t(LLFastTimer::FTM_NETWORK);
03824         
03826             //
03827             // Network processing
03828             //
03829             // NOTE: Starting at this point, we may still have pointers to "dead" objects
03830             // floating throughout the various object lists.
03831             //
03832     
03833             gFrameStats.start(LLFrameStats::IDLE_NETWORK);
03834                 idle_network();
03835             stop_glerror();
03836                 
03837             gFrameStats.start(LLFrameStats::AGENT_MISC);
03838 
03839                 // Check for away from keyboard, kick idle agents.
03840                 idle_afk_check();
03841 
03842                 //  Update statistics for this frame
03843                 update_statistics(gFrameCount);
03844 
03845                 gViewerWindow->updateDebugText();
03846         }
03847 
03849         //
03850         // Handle the regular UI idle callbacks as well as
03851         // hover callbacks
03852         //
03853 
03854         {
03855 //              LLFastTimer t(LLFastTimer::FTM_IDLE_CB);
03856 
03857                 // Do event notifications if necessary.  Yes, we may want to move this elsewhere.
03858                 gEventNotifier.update();
03859                 
03860                 gIdleCallbacks.callFunctions();
03861         }
03862         
03863         if (gDisconnected)
03864     {
03865                 return;
03866     }
03867 
03868         gViewerWindow->handlePerFrameHover();
03869 
03871         // Agent and camera movement
03872         //
03873                 LLCoordGL current_mouse = gViewerWindow->getCurrentMouse();
03874 
03875 //              BOOL was_in_prelude = gAgent.inPrelude();
03876 
03877         {
03878                 //LLFastTimer t(LLFastTimer::FTM_TEMP1);
03879                 
03880                 // After agent and camera moved, figure out if we need to
03881                 // deselect objects.
03882                 gSelectMgr->deselectAllIfTooFar();
03883                 gSelectMgr->update(); // once per frame updat
03884         }
03885 
03886         {
03887                 LLFastTimer t(LLFastTimer::FTM_RESET_DRAWORDER);
03888                         
03890                 //
03891                 // Clear draw orders
03892                 //
03893                 // Should actually be done after render, but handlePerFrameHover actually does a "render"
03894                 // to do its selection.
03895                 //
03896 
03897                 gPipeline.resetDrawOrders();
03898         }
03899         {
03900                 // Handle pending gesture processing
03901                 gGestureManager.update();
03902 
03903                 gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY);
03904         }
03905 
03906         {
03907                 LLFastTimer t(LLFastTimer::FTM_OBJECTLIST_UPDATE); // Actually "object update"
03908                 gFrameStats.start(LLFrameStats::OBJECT_UPDATE);
03909                 
03910                 if (!(gLogoutRequestSent && gHaveSavedSnapshot))
03911                 {
03912                         gObjectList.update(gAgent, *gWorldp);
03913                 }
03914         }
03915         
03916         {
03917                 LLFastTimer t(LLFastTimer::FTM_UPDATE_SKY);     
03918                 gSky.updateSky();
03919         }
03920 
03922         //
03923         // Deletes objects...
03924         // Has to be done after doing idleUpdates (which can kill objects)
03925         //
03926 
03927         {
03928                 LLFastTimer t(LLFastTimer::FTM_CLEANUP);
03929                 gFrameStats.start(LLFrameStats::CLEAN_DEAD);
03930                 gObjectList.cleanDeadObjects();
03931                 LLDrawable::cleanupDeadDrawables();
03932         }
03933         
03934         //
03935         // After this point, in theory we should never see a dead object
03936         // in the various object/drawable lists.
03937         //
03938 
03940         //
03941         // Update/send HUD effects
03942         //
03943         // At this point, HUD effects may clean up some references to
03944         // dead objects.
03945         //
03946 
03947         {
03948                 //LLFastTimer t(LLFastTimer::FTM_TEMP3);
03949                 
03950                 gFrameStats.start(LLFrameStats::UPDATE_EFFECTS);
03951                 gSelectMgr->updateEffects();
03952                 gHUDManager->cleanupEffects();
03953                 gHUDManager->sendEffects();
03954         }
03955 
03956         stop_glerror();
03957 
03959         //
03960         // Unpack layer data that we've received
03961         //
03962 
03963         {
03964                 LLFastTimer t(LLFastTimer::FTM_NETWORK);
03965                 gVLManager.unpackData();
03966         }
03967         
03969         //
03970         // Update surfaces, and surface textures as well.
03971         //
03972 
03973         gWorldp->updateVisibilities();
03974         {
03975                 const F32 max_region_update_time = .001f; // 1ms
03976                 LLFastTimer t(LLFastTimer::FTM_REGION_UPDATE);
03977                 gWorldp->updateRegions(max_region_update_time);
03978         }
03979         
03981         //
03982         // Update weather effects
03983         //
03984 
03985         if (!gNoRender)
03986         {
03987                 gWorldp->updateClouds(gFrameDTClamped);
03988                 gSky.propagateHeavenlyBodies(gFrameDTClamped);                          // moves sun, moon, and planets
03989 
03990                 // Update wind vector 
03991                 LLVector3 wind_position_region;
03992                 static LLVector3 average_wind;
03993 
03994                 LLViewerRegion *regionp;
03995                 regionp = gWorldp->resolveRegionGlobal(wind_position_region, gAgent.getPositionGlobal());       // puts agent's local coords into wind_position 
03996                 if (regionp)
03997                 {
03998                         gWindVec = regionp->mWind.getVelocity(wind_position_region);
03999 
04000                         // Compute average wind and use to drive motion of water
04001                         
04002                         average_wind = regionp->mWind.getAverage();
04003                         F32 cloud_density = regionp->mCloudLayer.getDensityRegion(wind_position_region);
04004                         
04005                         gSky.setCloudDensityAtAgent(cloud_density);
04006                         gSky.setWind(average_wind);
04007                         //LLVOWater::setWind(average_wind);
04008                 }
04009                 else
04010                 {
04011                         gWindVec.setVec(0.0f, 0.0f, 0.0f);
04012                 }
04013         }
04014         stop_glerror();
04015         
04017         //
04018         // Update images, using the image stats generated during object update/culling
04019         //
04020         // Can put objects onto the retextured list.
04021         //
04022         gFrameStats.start(LLFrameStats::IMAGE_UPDATE);
04023 
04024         LLFastTimer t(LLFastTimer::FTM_IMAGE_UPDATE);
04025         
04026         LLViewerImage::updateClass(gCamera->getVelocityStat()->getMean(),
04027                                                                 gCamera->getAngularVelocityStat()->getMean());
04028 
04029         gBumpImageList.updateImages();  // must be called before gImageList version so that it's textures are thrown out first.
04030 
04031         const F32 max_image_decode_time = 0.005f; // 5 ms decode time
04032         gImageList.updateImages(max_image_decode_time);
04033         stop_glerror();
04034 
04036         //
04037         // Sort and cull in the new renderer are moved to pipeline.cpp
04038         // Here, particles are updated and drawables are moved.
04039         //
04040         
04041         if (!gNoRender)
04042         {
04043                 gFrameStats.start(LLFrameStats::UPDATE_MOVE);
04044                 gPipeline.updateMove();
04045 
04046                 gFrameStats.start(LLFrameStats::UPDATE_PARTICLES);
04047                 gWorldp->updateParticles();
04048         }
04049         stop_glerror();
04050 
04051         if (!LLViewerJoystick::sOverrideCamera)
04052         {
04053                 gAgent.updateCamera();
04054         }
04055         else
04056         {
04057                 LLViewerJoystick::updateCamera();
04058         }
04059 
04060         // objects and camera should be in sync, do LOD calculations now
04061         {
04062                 LLFastTimer t(LLFastTimer::FTM_LOD_UPDATE);
04063                 gObjectList.updateApparentAngles(gAgent);
04064         }
04065 
04066         {
04067                 gFrameStats.start(LLFrameStats::AUDIO);
04068                 LLFastTimer t(LLFastTimer::FTM_AUDIO_UPDATE);
04069                 
04070                 if (gAudiop)
04071                 {
04072                         audio_update_volume(false);
04073                         audio_update_listener();
04074                         audio_update_wind(false);
04075 
04076                         // this line actually commits the changes we've made to source positions, etc.
04077                         const F32 max_audio_decode_time = 0.002f; // 2 ms decode time
04078                         gAudiop->idle(max_audio_decode_time);
04079                 }
04080         }
04081         
04082         if ( gTrustNet )
04083         {
04084                 gTrustNet->processRequests();
04085         }
04086 
04087         // Handle shutdown process, for example, 
04088         // wait for floaters to close, send quit message,
04089         // forcibly quit if it has taken too long
04090         if (gQuitRequested)
04091         {
04092                 idle_shutdown();
04093         }
04094 
04095         stop_glerror();
04096 }
04097 
04098 
04099 F32 mouse_x_from_center(S32 x)
04100 {
04101         return ((F32) x / (F32) gViewerWindow->getWindowWidth() ) - 0.5f;
04102 }
04103 
04104 
04105 F32 mouse_y_from_center(S32 y)
04106 {
04107         return ((F32) y / (F32) gViewerWindow->getWindowHeight() ) - 0.5f;
04108 }
04109 
04110 
04112 
04113 void init_audio() 
04114 {
04115         if (!gAudiop) 
04116         {
04117                 llwarns << "Failed to create an appropriate Audio Engine" << llendl;
04118                 return;
04119         }
04120         LLVector3d lpos_global = gAgent.getCameraPositionGlobal();
04121         LLVector3 lpos_global_f;
04122 
04123         lpos_global_f.setVec(lpos_global);
04124                                         
04125         gAudiop->setListener(lpos_global_f,
04126                                                   LLVector3::zero,      // gCamera->getVelocity(),    // !!! BUG need to replace this with smoothed velocity!
04127                                                   gCamera->getUpAxis(),
04128                                                   gCamera->getAtAxis());
04129 
04130 // load up our initial set of sounds we'll want so they're in memory and ready to be played
04131 
04132         BOOL mute_audio = gSavedSettings.getBOOL("MuteAudio");
04133 
04134         if (!mute_audio && gPreloadSounds)
04135         {
04136                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndAlert")));
04137                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndBadKeystroke")));
04138                 //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndChatFromObject")));
04139                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndClick")));
04140                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndClickRelease")));
04141                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndHealthReductionF")));
04142                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndHealthReductionM")));
04143                 //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndIncomingChat")));
04144                 //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndIncomingIM")));
04145                 //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInvApplyToObject")));
04146                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInvalidOp")));
04147                 //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInventoryCopyToInv")));
04148                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndMoneyChangeDown")));
04149                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndMoneyChangeUp")));
04150                 //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectCopyToInv")));
04151                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectCreate")));
04152                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectDelete")));
04153                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectRezIn")));
04154                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectRezOut")));
04155                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndPieMenuAppear")));
04156                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndPieMenuHide")));
04157                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndPieMenuSliceHighlight0")));
04158                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndPieMenuSliceHighlight1")));
04159                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndPieMenuSliceHighlight2")));
04160                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndPieMenuSliceHighlight3")));
04161                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndPieMenuSliceHighlight4")));
04162                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndPieMenuSliceHighlight5")));
04163                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndPieMenuSliceHighlight6")));
04164                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndPieMenuSliceHighlight7")));
04165                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndSnapshot")));
04166                 //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartAutopilot")));
04167                 //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartFollowpilot")));
04168                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartIM")));
04169                 //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStopAutopilot")));
04170                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTeleportOut")));
04171                 //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTextureApplyToObject")));
04172                 //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTextureCopyToInv")));
04173                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTyping")));
04174                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowClose")));
04175                 gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowOpen")));
04176         }
04177 
04178         audio_update_volume(true);
04179 }
04180 
04181 void audio_update_volume(bool force_update)
04182 {
04183         F32 master_volume = gSavedSettings.getF32("AudioLevelMaster");
04184         BOOL mute_audio = gSavedSettings.getBOOL("MuteAudio");
04185         if (!gViewerWindow->getActive() && (gSavedSettings.getBOOL("MuteWhenMinimized")))
04186         {
04187                 mute_audio = TRUE;
04188         }
04189         F32 mute_volume = mute_audio ? 0.0f : 1.0f;
04190 
04191         // Sound Effects
04192         if (gAudiop) 
04193         {
04194                 gAudiop->setMasterGain ( master_volume );
04195 
04196                 gAudiop->setDopplerFactor(gSavedSettings.getF32("AudioLevelDoppler"));
04197                 gAudiop->setDistanceFactor(gSavedSettings.getF32("AudioLevelDistance")); 
04198                 gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff"));
04199 #ifdef kAUDIO_ENABLE_WIND
04200                 gAudiop->enableWind(!mute_audio);
04201 #endif
04202 
04203                 gAudiop->setMuted(mute_audio);
04204                 
04205                 if (force_update)
04206                 {
04207                         audio_update_wind(true);
04208                 }
04209         }
04210 
04211         // Streaming Music
04212         if (gAudiop) 
04213         {               
04214                 F32 music_volume = gSavedSettings.getF32("AudioLevelMusic");
04215                 music_volume = mute_volume * master_volume * (music_volume*music_volume);
04216                 gAudiop->setInternetStreamGain ( music_volume );
04217         }
04218 
04219         // Streaming Media
04220         if(LLMediaEngine::getInstance())
04221         {
04222                 F32 media_volume = gSavedSettings.getF32("AudioLevelMedia");
04223                 media_volume = mute_volume * master_volume * (media_volume*media_volume);
04224                 LLMediaEngine::getInstance()->setVolume(media_volume);
04225         }
04226 
04227         // Voice
04228         if (gVoiceClient)
04229         {
04230                 F32 voice_volume = gSavedSettings.getF32("AudioLevelVoice");
04231                 voice_volume = mute_volume * master_volume * voice_volume;
04232                 gVoiceClient->setVoiceVolume(voice_volume);
04233                 gVoiceClient->setMicGain(gSavedSettings.getF32("AudioLevelMic"));
04234 
04235                 if (!gViewerWindow->getActive() && (gSavedSettings.getBOOL("MuteWhenMinimized")))
04236                 {
04237                         gVoiceClient->setMuteMic(true);
04238                 }
04239                 else
04240                 {
04241                         gVoiceClient->setMuteMic(false);
04242                 }
04243         }
04244 }
04245 
04246 void audio_update_listener()
04247 {
04248         if (gAudiop)
04249         {
04250                 // update listener position because agent has moved     
04251                 LLVector3d lpos_global = gAgent.getCameraPositionGlobal();              
04252                 LLVector3 lpos_global_f;
04253                 lpos_global_f.setVec(lpos_global);
04254         
04255                 gAudiop->setListener(lpos_global_f,
04256                                                          // gCameraVelocitySmoothed, 
04257                                                          // LLVector3::zero,    
04258                                                          gAgent.getVelocity(),    // !!! *TODO: need to replace this with smoothed velocity!
04259                                                          gCamera->getUpAxis(),
04260                                                          gCamera->getAtAxis());
04261         }
04262 }
04263 
04264 void audio_update_wind(bool force_update)
04265 {
04266 #ifdef kAUDIO_ENABLE_WIND
04267         //
04268         //  Extract height above water to modulate filter by whether above/below water 
04269         // 
04270         LLViewerRegion* region = gAgent.getRegion();
04271         if (region)
04272         {
04273                 static F32 last_camera_water_height = -1000.f;
04274                 LLVector3 camera_pos = gAgent.getCameraPositionAgent();
04275                 F32 camera_water_height = camera_pos.mV[VZ] - region->getWaterHeight();
04276                 
04277                 //
04278                 //  Don't update rolloff factor unless water surface has been crossed
04279                 //
04280                 if (force_update || (last_camera_water_height * camera_water_height) < 0.f)
04281                 {
04282                         if (camera_water_height < 0.f)
04283                         {
04284                                 gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff") * LL_ROLLOFF_MULTIPLIER_UNDER_WATER);
04285                         }
04286                         else 
04287                         {
04288                                 gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff"));
04289                         }
04290                 }
04291                 // this line rotates the wind vector to be listener (agent) relative
04292                 // unfortunately we have to pre-translate to undo the translation that
04293                 // occurs in the transform call
04294                 gRelativeWindVec = gAgent.getFrameAgent().rotateToLocal(gWindVec - gAgent.getVelocity());
04295 
04296                 // don't use the setter setMaxWindGain() because we don't
04297                 // want to screw up the fade-in on startup by setting actual source gain
04298                 // outside the fade-in.
04299                 gAudiop->mMaxWindGain = gSavedSettings.getF32("AudioLevelAmbient");
04300                 
04301                 last_camera_water_height = camera_water_height;
04302                 gAudiop->updateWind(gRelativeWindVec, camera_water_height);
04303         }
04304 #endif
04305 }
04306 
04307 
04309 
04310 BOOL raycast_for_new_obj_pos( S32 x, S32 y, LLViewerObject** hit_obj, S32* hit_face, 
04311                                                          BOOL* b_hit_land, LLVector3* ray_start_region, LLVector3* ray_end_region, LLViewerRegion** region )
04312 {
04313         F32 max_dist_from_camera = gSavedSettings.getF32( "MaxSelectDistance" ) - 1.f;
04314 
04315         // Viewer-side pick to find the right sim to create the object on.  
04316         // First find the surface the object will be created on.
04317         gViewerWindow->hitObjectOrLandGlobalImmediate(x, y, NULL, FALSE);
04318         
04319         // Note: use the frontmost non-flora version because (a) plants usually have lots of alpha and (b) pants' Havok
04320         // representations (if any) are NOT the same as their viewer representation.
04321         *hit_obj = gObjectList.findObject( gLastHitNonFloraObjectID );
04322         *hit_face = gLastHitNonFloraObjectFace;
04323         *b_hit_land = !(*hit_obj) && !gLastHitNonFloraPosGlobal.isExactlyZero();
04324         LLVector3d land_pos_global = gLastHitNonFloraPosGlobal;
04325 
04326         // Make sure there's a surface to place the new object on.
04327         BOOL bypass_sim_raycast = FALSE;
04328         LLVector3d      surface_pos_global;
04329         if (*b_hit_land)
04330         {
04331                 surface_pos_global = land_pos_global; 
04332                 bypass_sim_raycast = TRUE;
04333         }
04334         else 
04335         if (*hit_obj)
04336         {
04337                 surface_pos_global = (*hit_obj)->getPositionGlobal();
04338         }
04339         else
04340         {
04341                 return FALSE;
04342         }
04343 
04344         // Make sure the surface isn't too far away.
04345         LLVector3d ray_start_global = gAgent.getCameraPositionGlobal();
04346         F32 dist_to_surface_sq = (F32)((surface_pos_global - ray_start_global).magVecSquared());
04347         if( dist_to_surface_sq > (max_dist_from_camera * max_dist_from_camera) )
04348         {
04349                 return FALSE;
04350         }
04351 
04352         // Find the sim where the surface lives.
04353         LLViewerRegion *regionp = gWorldp->getRegionFromPosGlobal(surface_pos_global);
04354         if (!regionp)
04355         {
04356                 llwarns << "Trying to add object outside of all known regions!" << llendl;
04357                 return FALSE;
04358         }
04359 
04360         // Find the simulator-side ray that will be used to place the object accurately
04361         LLVector3d              mouse_direction;
04362         mouse_direction.setVec( gViewerWindow->mouseDirectionGlobal( x, y ) );
04363 
04364         *region = regionp;
04365         *ray_start_region =     regionp->getPosRegionFromGlobal( ray_start_global );
04366         F32 near_clip = gCamera->getNear() + 0.01f;  // Include an epsilon to avoid rounding issues.
04367         *ray_start_region += gCamera->getAtAxis() * near_clip;
04368 
04369         if( bypass_sim_raycast )
04370         {
04371                 // Hack to work around Havok's inability to ray cast onto height fields
04372                 *ray_end_region = regionp->getPosRegionFromGlobal( surface_pos_global );  // ray end is the viewer's intersection point
04373         }
04374         else
04375         {
04376                 LLVector3d              ray_end_global = ray_start_global + (1.f + max_dist_from_camera) * mouse_direction;  // add an epsilon to the sim version of the ray to avoid rounding problems.
04377                 *ray_end_region = regionp->getPosRegionFromGlobal( ray_end_global );
04378         }
04379 
04380         return TRUE;
04381 }
04382 
04383 const LLVector3 DEFAULT_OBJECT_SCALE(0.5f, 0.5f, 0.5f);
04384 
04385 BOOL add_object( LLPCode pcode, S32 x, S32 y, U8 use_physics )
04386 {
04387         LLVector3 ray_start_region;
04388         LLVector3 ray_end_region;
04389         LLViewerRegion* regionp = NULL;
04390         BOOL b_hit_land = FALSE;
04391         S32 hit_face = -1;
04392         LLViewerObject* hit_obj = NULL;
04393         U8 state = 0;
04394         BOOL success = raycast_for_new_obj_pos( x, y, &hit_obj, &hit_face, &b_hit_land, &ray_start_region, &ray_end_region, &regionp );
04395         if( !success )
04396         {
04397                 return FALSE;
04398         }
04399 
04400         if( hit_obj && (hit_obj->isAvatar() || hit_obj->isAttachment()) )
04401         {
04402                 // Can't create objects on avatars or attachments
04403                 return FALSE;
04404         }
04405 
04406         if (NULL == regionp)
04407         {
04408                 llwarns << "regionp was NULL; aborting function." << llendl;
04409                 return FALSE;
04410         }
04411 
04412         if (regionp->getRegionFlags() & REGION_FLAGS_SANDBOX)
04413         {
04414                 LLFirstUse::useSandbox();
04415         }
04416 
04417         // Set params for new object based on its PCode.
04418         LLQuaternion    rotation;
04419         LLVector3               scale = DEFAULT_OBJECT_SCALE;
04420         U8                              material = LL_MCODE_WOOD;
04421         BOOL                    create_selected = FALSE;
04422         LLVolumeParams  volume_params;
04423         
04424         switch (pcode) 
04425         {
04426         case LL_PCODE_LEGACY_GRASS:
04427                 //  Randomize size of grass patch 
04428                 scale.setVec(10.f + ll_frand(20.f), 10.f + ll_frand(20.f),  1.f + ll_frand(2.f));
04429                 state = rand() % LLVOGrass::sMaxGrassSpecies;
04430                 break;
04431 
04432 
04433         case LL_PCODE_LEGACY_TREE:
04434         case LL_PCODE_TREE_NEW:
04435                 state = rand() % LLVOTree::sMaxTreeSpecies;
04436                 break;
04437 
04438         case LL_PCODE_SPHERE:
04439         case LL_PCODE_CONE:
04440         case LL_PCODE_CUBE:
04441         case LL_PCODE_CYLINDER:
04442         case LL_PCODE_TORUS:
04443         case LLViewerObject::LL_VO_SQUARE_TORUS:
04444         case LLViewerObject::LL_VO_TRIANGLE_TORUS:
04445         default:
04446                 create_selected = TRUE;
04447                 break;
04448         }
04449 
04450         // Play creation sound
04451         if (gAudiop)
04452         {
04453                 F32 volume = gSavedSettings.getF32("AudioLevelUI");
04454                 gAudiop->triggerSound( LLUUID(gSavedSettings.getString("UISndObjectCreate")), gAgent.getID(), volume);
04455         }
04456 
04457         gMessageSystem->newMessageFast(_PREHASH_ObjectAdd);
04458         gMessageSystem->nextBlockFast(_PREHASH_AgentData);
04459         gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
04460         gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
04461         gMessageSystem->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
04462         gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
04463         gMessageSystem->addU8Fast(_PREHASH_Material,    material);
04464 
04465         U32 flags = 0;          // not selected
04466         if (use_physics)
04467         {
04468                 flags |= FLAGS_USE_PHYSICS;
04469         }
04470         if (create_selected)
04471         {
04472                 flags |= FLAGS_CREATE_SELECTED;
04473         }
04474         gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags );
04475 
04476         LLPCode volume_pcode;   // ...PCODE_VOLUME, or the original on error
04477         switch (pcode)
04478         {
04479         case LL_PCODE_SPHERE:
04480                 rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
04481 
04482                 volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
04483                 volume_params.setBeginAndEndS( 0.f, 1.f );
04484                 volume_params.setBeginAndEndT( 0.f, 1.f );
04485                 volume_params.setRatio  ( 1, 1 );
04486                 volume_params.setShear  ( 0, 0 );
04487                 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
04488                 volume_pcode = LL_PCODE_VOLUME;
04489                 break;
04490 
04491         case LL_PCODE_TORUS:
04492                 rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
04493 
04494                 volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_CIRCLE );
04495                 volume_params.setBeginAndEndS( 0.f, 1.f );
04496                 volume_params.setBeginAndEndT( 0.f, 1.f );
04497                 volume_params.setRatio  ( 1.f, 0.25f ); // "top size"
04498                 volume_params.setShear  ( 0, 0 );
04499                 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
04500                 volume_pcode = LL_PCODE_VOLUME;
04501                 break;
04502 
04503         case LLViewerObject::LL_VO_SQUARE_TORUS:
04504                 rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
04505 
04506                 volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_CIRCLE );
04507                 volume_params.setBeginAndEndS( 0.f, 1.f );
04508                 volume_params.setBeginAndEndT( 0.f, 1.f );
04509                 volume_params.setRatio  ( 1.f, 0.25f ); // "top size"
04510                 volume_params.setShear  ( 0, 0 );
04511                 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
04512                 volume_pcode = LL_PCODE_VOLUME;
04513                 break;
04514 
04515         case LLViewerObject::LL_VO_TRIANGLE_TORUS:
04516                 rotation.setQuat(90.f * DEG_TO_RAD, LLVector3::y_axis);
04517 
04518                 volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_CIRCLE );
04519                 volume_params.setBeginAndEndS( 0.f, 1.f );
04520                 volume_params.setBeginAndEndT( 0.f, 1.f );
04521                 volume_params.setRatio  ( 1.f, 0.25f ); // "top size"
04522                 volume_params.setShear  ( 0, 0 );
04523                 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
04524                 volume_pcode = LL_PCODE_VOLUME;
04525                 break;
04526 
04527         case LL_PCODE_SPHERE_HEMI:
04528                 volume_params.setType( LL_PCODE_PROFILE_CIRCLE_HALF, LL_PCODE_PATH_CIRCLE );
04529                 //volume_params.setBeginAndEndS( 0.5f, 1.f );
04530                 volume_params.setBeginAndEndT( 0.f, 0.5f );
04531                 volume_params.setRatio  ( 1, 1 );
04532                 volume_params.setShear  ( 0, 0 );
04533                 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
04534                 volume_pcode = LL_PCODE_VOLUME;
04535                 break;
04536 
04537         case LL_PCODE_CUBE:
04538                 volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE );
04539                 volume_params.setBeginAndEndS( 0.f, 1.f );
04540                 volume_params.setBeginAndEndT( 0.f, 1.f );
04541                 volume_params.setRatio  ( 1, 1 );
04542                 volume_params.setShear  ( 0, 0 );
04543                 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
04544                 volume_pcode = LL_PCODE_VOLUME;
04545                 break;
04546 
04547         case LL_PCODE_PRISM:
04548                 volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE );
04549                 volume_params.setBeginAndEndS( 0.f, 1.f );
04550                 volume_params.setBeginAndEndT( 0.f, 1.f );
04551                 volume_params.setRatio  ( 0, 1 );
04552                 volume_params.setShear  ( -0.5f, 0 );
04553                 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
04554                 volume_pcode = LL_PCODE_VOLUME;
04555                 break;
04556 
04557         case LL_PCODE_PYRAMID:
04558                 volume_params.setType( LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE );
04559                 volume_params.setBeginAndEndS( 0.f, 1.f );
04560                 volume_params.setBeginAndEndT( 0.f, 1.f );
04561                 volume_params.setRatio  ( 0, 0 );
04562                 volume_params.setShear  ( 0, 0 );
04563                 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
04564                 volume_pcode = LL_PCODE_VOLUME;
04565                 break;
04566 
04567         case LL_PCODE_TETRAHEDRON:
04568                 volume_params.setType( LL_PCODE_PROFILE_EQUALTRI, LL_PCODE_PATH_LINE );
04569                 volume_params.setBeginAndEndS( 0.f, 1.f );
04570                 volume_params.setBeginAndEndT( 0.f, 1.f );
04571                 volume_params.setRatio  ( 0, 0 );
04572                 volume_params.setShear  ( 0, 0 );
04573                 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
04574                 volume_pcode = LL_PCODE_VOLUME;
04575                 break;
04576 
04577         case LL_PCODE_CYLINDER:
04578                 volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
04579                 volume_params.setBeginAndEndS( 0.f, 1.f );
04580                 volume_params.setBeginAndEndT( 0.f, 1.f );
04581                 volume_params.setRatio  ( 1, 1 );
04582                 volume_params.setShear  ( 0, 0 );
04583                 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
04584                 volume_pcode = LL_PCODE_VOLUME;
04585                 break;
04586 
04587         case LL_PCODE_CYLINDER_HEMI:
04588                 volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
04589                 volume_params.setBeginAndEndS( 0.25f, 0.75f );
04590                 volume_params.setBeginAndEndT( 0.f, 1.f );
04591                 volume_params.setRatio  ( 1, 1 );
04592                 volume_params.setShear  ( 0, 0 );
04593                 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
04594                 volume_pcode = LL_PCODE_VOLUME;
04595                 break;
04596 
04597         case LL_PCODE_CONE:
04598                 volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
04599                 volume_params.setBeginAndEndS( 0.f, 1.f );
04600                 volume_params.setBeginAndEndT( 0.f, 1.f );
04601                 volume_params.setRatio  ( 0, 0 );
04602                 volume_params.setShear  ( 0, 0 );
04603                 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
04604                 volume_pcode = LL_PCODE_VOLUME;
04605                 break;
04606 
04607         case LL_PCODE_CONE_HEMI:
04608                 volume_params.setType( LL_PCODE_PROFILE_CIRCLE, LL_PCODE_PATH_LINE );
04609                 volume_params.setBeginAndEndS( 0.25f, 0.75f );
04610                 volume_params.setBeginAndEndT( 0.f, 1.f );
04611                 volume_params.setRatio  ( 0, 0 );
04612                 volume_params.setShear  ( 0, 0 );
04613                 LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
04614                 volume_pcode = LL_PCODE_VOLUME;
04615                 break;
04616 
04617         default:
04618                 LLVolumeMessage::packVolumeParams(0, gMessageSystem);
04619                 volume_pcode = pcode;
04620                 break;
04621         }
04622         gMessageSystem->addU8Fast(_PREHASH_PCode, volume_pcode);
04623 
04624         gMessageSystem->addVector3Fast(_PREHASH_Scale,                  scale );
04625         gMessageSystem->addQuatFast(_PREHASH_Rotation,                  rotation );
04626         gMessageSystem->addVector3Fast(_PREHASH_RayStart,               ray_start_region );
04627         gMessageSystem->addVector3Fast(_PREHASH_RayEnd,                 ray_end_region );
04628         gMessageSystem->addU8Fast(_PREHASH_BypassRaycast,               (U8)b_hit_land );
04629         gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE );
04630         gMessageSystem->addU8Fast(_PREHASH_State, state);
04631 
04632         // Limit raycast to a single object.  
04633         // Speeds up server raycast + avoid problems with server ray hitting objects
04634         // that were clipped by the near plane or culled on the viewer.
04635         LLUUID ray_target_id;
04636         if( hit_obj )
04637         {
04638                 ray_target_id = hit_obj->getID();
04639         }
04640         else
04641         {
04642                 ray_target_id.setNull();
04643         }
04644         gMessageSystem->addUUIDFast(_PREHASH_RayTargetID,                       ray_target_id );
04645         
04646         // Pack in name value pairs
04647         gMessageSystem->sendReliable(regionp->getHost());
04648 
04649         // Spawns a message, so must be after above send
04650         if (create_selected)
04651         {
04652                 gSelectMgr->deselectAll();
04653                 gViewerWindow->getWindow()->incBusyCount();
04654         }
04655 
04656         // VEFFECT: AddObject
04657         LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)gHUDManager->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM, TRUE);
04658         effectp->setSourceObject(gAgent.getAvatarObject());
04659         effectp->setPositionGlobal(regionp->getPosGlobalFromRegion(ray_end_region));
04660         effectp->setDuration(LL_HUD_DUR_SHORT);
04661         effectp->setColor(LLColor4U(gAgent.getEffectColor()));
04662 
04663         gViewerStats->incStat(LLViewerStats::ST_CREATE_COUNT);
04664 
04665         return TRUE;
04666 }
04667 
04668 
04669 
04670 #if LL_WINDOWS
04671 void create_console()
04672 {
04673         int h_con_handle;
04674         long l_std_handle;
04675 
04676         CONSOLE_SCREEN_BUFFER_INFO coninfo;
04677         FILE *fp;
04678 
04679         // allocate a console for this app
04680         AllocConsole();
04681 
04682         // set the screen buffer to be big enough to let us scroll text
04683         GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
04684         coninfo.dwSize.Y = MAX_CONSOLE_LINES;
04685         SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
04686 
04687         // redirect unbuffered STDOUT to the console
04688         l_std_handle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
04689         h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT);
04690         fp = _fdopen( h_con_handle, "w" );
04691         *stdout = *fp;
04692         setvbuf( stdout, NULL, _IONBF, 0 );
04693 
04694         // redirect unbuffered STDIN to the console
04695         l_std_handle = (long)GetStdHandle(STD_INPUT_HANDLE);
04696         h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT);
04697         fp = _fdopen( h_con_handle, "r" );
04698         *stdin = *fp;
04699         setvbuf( stdin, NULL, _IONBF, 0 );
04700 
04701         // redirect unbuffered STDERR to the console
04702         l_std_handle = (long)GetStdHandle(STD_ERROR_HANDLE);
04703         h_con_handle = _open_osfhandle(l_std_handle, _O_TEXT);
04704         fp = _fdopen( h_con_handle, "w" );
04705         *stderr = *fp;
04706         setvbuf( stderr, NULL, _IONBF, 0 );
04707 }
04708 #endif
04709 
04710 
04711 
04712 //-------------------------------------------------------------------
04713 //-------------------------------------------------------------------
04714 // Vector Performance Options
04715 //-------------------------------------------------------------------
04716 //-------------------------------------------------------------------
04717 
04718 // Initially, we test the performance of the vectorization code, then
04719 // turn it off if it ends up being slower. JC
04720 BOOL    gVectorizePerfTest      = TRUE;
04721 BOOL    gVectorizeEnable        = FALSE;
04722 U32             gVectorizeProcessor     = 0;
04723 BOOL    gVectorizeSkin          = FALSE;
04724 
04725 void update_vector_performances(void)
04726 {
04727         char *vp;
04728         
04729         switch(gVectorizeProcessor)
04730         {
04731                 case 2: vp = "SSE2"; break;                                     // *TODO: replace the magic #s
04732                 case 1: vp = "SSE"; break;
04733                 default: vp = "COMPILER DEFAULT"; break;
04734         }
04735         llinfos << "Vectorization         : " << ( gVectorizeEnable ? "ENABLED" : "DISABLED" ) << llendl ;
04736         llinfos << "Vector Processor      : " << vp << llendl ;
04737         llinfos << "Vectorized Skinning   : " << ( gVectorizeSkin ? "ENABLED" : "DISABLED" ) << llendl ;
04738         
04739         if(gVectorizeEnable && gVectorizeSkin)
04740         {
04741                 switch(gVectorizeProcessor)
04742                 {
04743                         case 2:
04744                                 LLViewerJointMesh::sUpdateGeometryFunc = &LLViewerJointMesh::updateGeometrySSE2;
04745                                 break;
04746                         case 1:
04747                                 LLViewerJointMesh::sUpdateGeometryFunc = &LLViewerJointMesh::updateGeometrySSE;
04748                                 break;
04749                         default:
04750                                 LLViewerJointMesh::sUpdateGeometryFunc = &LLViewerJointMesh::updateGeometryVectorized;
04751                                 break;
04752                 }
04753         }
04754         else
04755         {
04756                 LLViewerJointMesh::sUpdateGeometryFunc = &LLViewerJointMesh::updateGeometryOriginal;
04757         }
04758 }
04759 
04760 
04761 class LLVectorizationEnableListener: public LLSimpleListener
04762 {
04763         bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
04764         {
04765                 gVectorizeEnable = event->getValue().asBoolean();
04766                 update_vector_performances();
04767                 return true;
04768         }
04769 };
04770 static LLVectorizationEnableListener vectorization_enable_listener;
04771 
04772 class LLVectorizeSkinListener: public LLSimpleListener
04773 {
04774         bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
04775         {
04776                 gVectorizeSkin = event->getValue().asBoolean();
04777                 update_vector_performances();
04778                 return true;
04779         }
04780 };
04781 static LLVectorizeSkinListener vectorize_skin_listener;
04782 
04783 class LLVectorProcessorListener: public LLSimpleListener
04784 {
04785         bool handleEvent(LLPointer<LLEvent> event, const LLSD& userdata)
04786         {
04787                 gVectorizeProcessor = event->getValue().asInteger();
04788                 update_vector_performances();
04789                 return true;
04790         }
04791 };
04792 static LLVectorProcessorListener vector_processor_listener;
04793 
04794 // Use these strictly for things that are constructed at startup,
04795 // or for things that are performance critical.  JC
04796 void saved_settings_to_globals()
04797 {
04798         LLBUTTON_H_PAD          = gSavedSettings.getS32("ButtonHPad");
04799         LLBUTTON_V_PAD          = gSavedSettings.getS32("ButtonVPad");
04800         BTN_HEIGHT_SMALL        = gSavedSettings.getS32("ButtonHeightSmall");
04801         BTN_HEIGHT                      = gSavedSettings.getS32("ButtonHeight");
04802 
04803         MENU_BAR_HEIGHT         = gSavedSettings.getS32("MenuBarHeight");
04804         MENU_BAR_WIDTH          = gSavedSettings.getS32("MenuBarWidth");
04805         STATUS_BAR_HEIGHT       = gSavedSettings.getS32("StatusBarHeight");
04806 
04807         LLCOMBOBOX_HEIGHT       = BTN_HEIGHT - 2;
04808         LLCOMBOBOX_WIDTH        = 128;
04809 
04810         LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
04811 
04812         LLVOSky::sNighttimeBrightness           = gSavedSettings.getF32("RenderNightBrightness");
04813         
04814         LLImageGL::sGlobalUseAnisotropic        = gSavedSettings.getBOOL("RenderAnisotropic");
04815         LLVOVolume::sLODFactor                          = gSavedSettings.getF32("RenderVolumeLODFactor");
04816         LLVOVolume::sDistanceFactor                     = 1.f-LLVOVolume::sLODFactor * 0.1f;
04817         LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor");
04818         LLVOTree::sTreeFactor                           = gSavedSettings.getF32("RenderTreeLODFactor");
04819         LLVOAvatar::sLODFactor                          = gSavedSettings.getF32("RenderAvatarLODFactor");
04820         LLVOAvatar::sMaxVisible                         = gSavedSettings.getS32("RenderAvatarMaxVisible");
04821         LLVOAvatar::sVisibleInFirstPerson       = gSavedSettings.getBOOL("FirstPersonAvatarVisible");
04822         // clamp auto-open time to some minimum usable value
04823         LLFolderView::sAutoOpenTime                     = llmax(0.25f, gSavedSettings.getF32("FolderAutoOpenDelay"));
04824         LLToolBar::sInventoryAutoOpenTime       = gSavedSettings.getF32("InventoryAutoOpenDelay");
04825         LLSelectMgr::sRectSelectInclusive       = gSavedSettings.getBOOL("RectangleSelectInclusive");
04826         LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections");
04827         LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius");
04828 
04829         gFrameStats.setTrackStats(gSavedSettings.getBOOL("StatsSessionTrackFrameStats"));
04830         gAgentPilot.mNumRuns            = gSavedSettings.getS32("StatsNumRuns");
04831         gAgentPilot.mQuitAfterRuns      = gSavedSettings.getBOOL("StatsQuitAfterRuns");
04832         gAgent.mHideGroupTitle          = gSavedSettings.getBOOL("RenderHideGroupTitle");
04833 
04834         gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc");
04835         gAllowIdleAFK = gSavedSettings.getBOOL("AllowIdleAFK");
04836         gAFKTimeout = gSavedSettings.getF32("AFKTimeout");
04837         gMouseSensitivity = gSavedSettings.getF32("MouseSensitivity");
04838         gInvertMouse = gSavedSettings.getBOOL("InvertMouse");
04839         gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates");
04840         gMapScale = gSavedSettings.getF32("MapScale");
04841         gMiniMapScale = gSavedSettings.getF32("MiniMapScale");
04842         gHandleKeysAsync = gSavedSettings.getBOOL("AsyncKeyboard");
04843         LLHoverView::sShowHoverTips = gSavedSettings.getBOOL("ShowHoverTips");
04844 
04845 #if LL_VECTORIZE
04846         if (gSysCPU.hasAltivec())
04847         {
04848                 gSavedSettings.setBOOL("VectorizeEnable", TRUE );
04849                 gSavedSettings.setU32("VectorizeProcessor", 0 );
04850         }
04851         else
04852         if (gSysCPU.hasSSE2())
04853         {
04854                 gSavedSettings.setBOOL("VectorizeEnable", TRUE );
04855                 gSavedSettings.setU32("VectorizeProcessor", 2 );
04856         }
04857         else
04858         if (gSysCPU.hasSSE())
04859         {
04860                 gSavedSettings.setBOOL("VectorizeEnable", TRUE );
04861                 gSavedSettings.setU32("VectorizeProcessor", 1 );
04862         }
04863         else
04864         {
04865                 // Don't bother testing or running if CPU doesn't support it. JC
04866                 gSavedSettings.setBOOL("VectorizePerfTest", FALSE );
04867                 gSavedSettings.setBOOL("VectorizeEnable", FALSE );
04868                 gSavedSettings.setU32("VectorizeProcessor", 0 );
04869                 gSavedSettings.setBOOL("VectorizeSkin", FALSE);
04870         }
04871 #else
04872         // This build target doesn't support SSE, don't test/run.
04873         gSavedSettings.setBOOL("VectorizePerfTest", FALSE );
04874         gSavedSettings.setBOOL("VectorizeEnable", FALSE );
04875         gSavedSettings.setU32("VectorizeProcessor", 0 );
04876         gSavedSettings.setBOOL("VectorizeSkin", FALSE);
04877 #endif
04878 
04879         gVectorizePerfTest = gSavedSettings.getBOOL("VectorizePerfTest");
04880         gVectorizeEnable = gSavedSettings.getBOOL("VectorizeEnable");
04881         gVectorizeProcessor = gSavedSettings.getU32("VectorizeProcessor");
04882         gVectorizeSkin = gSavedSettings.getBOOL("VectorizeSkin");
04883         update_vector_performances();
04884 
04885         // Into a global in case we corrupt the list on crash.
04886         gCrashBehavior = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING);
04887 
04888         // propagate push to talk preference to current status
04889         gSavedSettings.setBOOL("PTTCurrentlyEnabled", gSavedSettings.getBOOL("EnablePushToTalk"));
04890 
04891         settings_setup_listeners();
04892         
04893         // these are currently static in this file, so they can't move to settings_setup_listeners
04894         gSavedSettings.getControl("VectorizeEnable")->addListener(&vectorization_enable_listener);
04895         gSavedSettings.getControl("VectorizeProcessor")->addListener(&vector_processor_listener);
04896         gSavedSettings.getControl("VectorizeSkin")->addListener(&vectorize_skin_listener);
04897 
04898         // gAgent.init() also loads from saved settings.
04899 }
04900 
04901 void cleanup_saved_settings()
04902 {
04903         gSavedSettings.setBOOL("MouseSun", FALSE);
04904 
04905         gSavedSettings.setBOOL("FlyBtnState", FALSE);
04906 
04907         gSavedSettings.setBOOL("FirstPersonBtnState", FALSE);
04908         gSavedSettings.setBOOL("ThirdPersonBtnState", TRUE);
04909         gSavedSettings.setBOOL("BuildBtnState", FALSE);
04910 
04911         gSavedSettings.setBOOL("UseEnergy", TRUE);                              // force toggle to turn off, since sends message to simulator
04912 
04913         gSavedSettings.setBOOL("DebugWindowProc", gDebugWindowProc);
04914                 
04915         gSavedSettings.setBOOL("AllowIdleAFK", gAllowIdleAFK);
04916         gSavedSettings.setBOOL("ShowObjectUpdates", gShowObjectUpdates);
04917         
04918         if (!gNoRender)
04919         {
04920                 if (gDebugView)
04921                 {
04922                         gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible());
04923                         gSavedSettings.setBOOL("ShowDebugStats", gDebugView->mStatViewp->getVisible());
04924                 }
04925         }
04926 
04927         // save window position if not fullscreen
04928         // as we don't track it in callbacks
04929         BOOL fullscreen = gViewerWindow->mWindow->getFullscreen();
04930         BOOL maximized = gViewerWindow->mWindow->getMaximized();
04931         if (!fullscreen && !maximized)
04932         {
04933                 LLCoordScreen window_pos;
04934 
04935                 if (gViewerWindow->mWindow->getPosition(&window_pos))
04936                 {
04937                         gSavedSettings.setS32("WindowX", window_pos.mX);
04938                         gSavedSettings.setS32("WindowY", window_pos.mY);
04939                 }
04940         }
04941 
04942         gSavedSettings.setF32("MapScale", gMapScale );
04943         gSavedSettings.setF32("MiniMapScale", gMiniMapScale );
04944         gSavedSettings.setBOOL("AsyncKeyboard", gHandleKeysAsync);
04945         gSavedSettings.setBOOL("ShowHoverTips", LLHoverView::sShowHoverTips);
04946 
04947         // Some things are cached in LLAgent.
04948         if (gAgent.mInitialized)
04949         {
04950                 gSavedSettings.setF32("RenderFarClip", gAgent.mDrawDistance);
04951         }
04952 
04953         gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, gCrashBehavior);
04954 }
04955 
04956 
04957 void callback_cache_name(const LLUUID& id, const char* firstname, const char* lastname, BOOL is_group, void* data)
04958 {
04959         LLNameListCtrl::refreshAll(id, firstname, lastname, is_group);
04960         LLNameBox::refreshAll(id, firstname, lastname, is_group);
04961         LLNameEditor::refreshAll(id, firstname, lastname, is_group);
04962         
04963         // TODO: Actually be intelligent about the refresh.
04964         // For now, just brute force refresh the dialogs.
04965         dialog_refresh_all();
04966 }
04967 
04968 
04969 void write_debug(const std::string& str)
04970 {
04971         write_debug(str.c_str());
04972 }
04973 
04974 void write_debug(const char *str)
04975 {
04976         if (!gDebugFile)
04977         {
04978                 std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log");
04979                 llinfos << "Opening debug file " << debug_filename << llendl;
04980                 gDebugFile = LLFile::fopen(debug_filename.c_str(), "w");                /* Flawfinder: ignore */
04981         if (!gDebugFile)
04982         {
04983                     llinfos << "Opening debug file " << debug_filename << " failed. Using stderr." << llendl;
04984             gDebugFile = stderr;
04985         }
04986         }
04987         fputs(str, gDebugFile);
04988         fflush(gDebugFile);
04989 }
04990 
04991 void close_debug()
04992 {
04993         if (gDebugFile)
04994         {
04995                 fclose(gDebugFile);
04996         }
04997         gDebugFile = NULL;
04998 }
04999 
05000 void print_agent_nvpairs(void*)
05001 {
05002         LLViewerObject *objectp;
05003 
05004         llinfos << "Agent Name Value Pairs" << llendl;
05005 
05006         objectp = gObjectList.findObject(gAgentID);
05007         if (objectp)
05008         {
05009                 objectp->printNameValuePairs();
05010         }
05011         else
05012         {
05013                 llinfos << "Can't find agent object" << llendl;
05014         }
05015 
05016         llinfos << "Camera at " << gAgent.getCameraPositionGlobal() << llendl;
05017 }
05018 
05019 
05020 void reset_statistics()
05021 {
05022         gPipeline.resetFrameStats();    // Reset per-frame statistics.
05023         if (LLSurface::sTextureUpdateTime)
05024         {
05025                 LLSurface::sTexelsUpdatedPerSecStat.addValue(0.001f*(LLSurface::sTexelsUpdated / LLSurface::sTextureUpdateTime));
05026                 LLSurface::sTexelsUpdated = 0;
05027                 LLSurface::sTextureUpdateTime = 0.f;
05028         }
05029 }
05030 
05031 
05032 void output_statistics(void*)
05033 {
05034         llinfos << "Number of orphans: " << gObjectList.getOrphanCount() << llendl;
05035         llinfos << "Number of dead objects: " << gObjectList.mNumDeadObjects << llendl;
05036         llinfos << "Num images: " << gImageList.getNumImages() << llendl;
05037         llinfos << "Texture usage: " << LLImageGL::sGlobalTextureMemory << llendl;
05038         llinfos << "Texture working set: " << LLImageGL::sBoundTextureMemory << llendl;
05039         llinfos << "Raw usage: " << LLImageRaw::sGlobalRawMemory << llendl;
05040         llinfos << "Formatted usage: " << LLImageFormatted::sGlobalFormattedMemory << llendl;
05041         llinfos << "Zombie Viewer Objects: " << LLViewerObject::getNumZombieObjects() << llendl;
05042         llinfos << "Number of lights: " << gPipeline.getLightCount() << llendl;
05043 
05044         llinfos << "Memory Usage:" << llendl;
05045         llinfos << "--------------------------------" << llendl;
05046         llinfos << "Pipeline:" << llendl;
05047         llinfos << llendl;
05048 
05049 #if LL_SMARTHEAP
05050         llinfos << "--------------------------------" << llendl;
05051         {
05052                 llinfos << "sizeof(LLVOVolume) = " << sizeof(LLVOVolume) << llendl;
05053 
05054                 U32 total_pool_size = 0;
05055                 U32 total_used_size = 0;
05056                 MEM_POOL_INFO pool_info;
05057                 MEM_POOL_STATUS pool_status;
05058                 U32 pool_num = 0;
05059                 for(pool_status = MemPoolFirst( &pool_info, 1 ); 
05060                         pool_status != MEM_POOL_END; 
05061                         pool_status = MemPoolNext( &pool_info, 1 ) )
05062                 {
05063                         llinfos << "Pool #" << pool_num << llendl;
05064                         if( MEM_POOL_OK != pool_status )
05065                         {
05066                                 llwarns << "Pool not ok" << llendl;
05067                                 continue;
05068                         }
05069 
05070                         llinfos << "Pool blockSizeFS " << pool_info.blockSizeFS
05071                                 << " pageSize " << pool_info.pageSize
05072                                 << llendl;
05073 
05074                         U32 pool_count = MemPoolCount(pool_info.pool);
05075                         llinfos << "Blocks " << pool_count << llendl;
05076 
05077                         U32 pool_size = MemPoolSize( pool_info.pool );
05078                         if( pool_size == MEM_ERROR_RET )
05079                         {
05080                                 llinfos << "MemPoolSize() failed (" << pool_num << ")" << llendl;
05081                         }
05082                         else
05083                         {
05084                                 llinfos << "MemPool Size " << pool_size / 1024 << "K" << llendl;
05085                         }
05086 
05087                         total_pool_size += pool_size;
05088 
05089                         if( !MemPoolLock( pool_info.pool ) )
05090                         {
05091                                 llinfos << "MemPoolLock failed (" << pool_num << ") " << llendl;
05092                                 continue;
05093                         }
05094 
05095                         U32 used_size = 0; 
05096                         MEM_POOL_ENTRY entry;
05097                         entry.entry = NULL;
05098                         while( MemPoolWalk( pool_info.pool, &entry ) == MEM_POOL_OK )
05099                         {
05100                                 if( entry.isInUse )
05101                                 {
05102                                         used_size += entry.size;
05103                                 }
05104                         }
05105 
05106                         MemPoolUnlock( pool_info.pool );
05107 
05108                         llinfos << "MemPool Used " << used_size/1024 << "K" << llendl;
05109                         total_used_size += used_size;
05110                         pool_num++;
05111                 }
05112                 
05113                 llinfos << "Total Pool Size " << total_pool_size/1024 << "K" << llendl;
05114                 llinfos << "Total Used Size " << total_used_size/1024 << "K" << llendl;
05115 
05116         }
05117 #endif
05118 
05119         llinfos << "--------------------------------" << llendl;
05120         llinfos << "Avatar Memory (partly overlaps with above stats):" << llendl;
05121         gTexStaticImageList.dumpByteCount();
05122         LLVOAvatar::dumpScratchTextureByteCount();
05123         LLTexLayerSetBuffer::dumpTotalByteCount();
05124         LLVOAvatar::dumpTotalLocalTextureByteCount();
05125         LLTexLayerParamAlpha::dumpCacheByteCount();
05126         LLVOAvatar::dumpBakedStatus();
05127 
05128         llinfos << llendl;
05129 
05130         llinfos << "Object counts:" << llendl;
05131         S32 i;
05132         S32 obj_counts[256];
05133 //      S32 app_angles[256];
05134         for (i = 0; i < 256; i++)
05135         {
05136                 obj_counts[i] = 0;
05137         }
05138         for (i = 0; i < gObjectList.getNumObjects(); i++)
05139         {
05140                 LLViewerObject *objectp = gObjectList.getObject(i);
05141                 if (objectp)
05142                 {
05143                         obj_counts[objectp->getPCode()]++;
05144                 }
05145         }
05146         for (i = 0; i < 256; i++)
05147         {
05148                 if (obj_counts[i])
05149                 {
05150                         llinfos << LLPrimitive::pCodeToString(i) << ":" << obj_counts[i] << llendl;
05151                 }
05152         }
05153 
05154         /*
05155         llinfos << "Object size distribution" << llendl;
05156         llinfos << "------------------------" << llendl;
05157         for (i = 0; i < 256; i++)
05158         {
05159                 obj_counts[i] = 0;
05160                 //app_angles[i] = 0;
05161         }
05162         for (i = 0; i < gObjectList.getNumObjects(); i++)
05163         {
05164                 LLViewerObject *objectp = gObjectList.getObject(i);
05165                 S32 size = llmin(255, (S32)objectp->getRadius()/2);
05166                 obj_counts[size]++;
05167         }
05168         for (i = 0; i < 256; i++)
05169         {
05170                 if (obj_counts[i])
05171                 {
05172                         llinfos << i*2 << ":" << (i+1)*2 << " - " << obj_counts[i] << llendl;
05173                 }
05174         }
05175         */
05176 
05177         /*
05178 
05179         llinfos << llendl;
05180         llinfos << "Lighting statistics" << llendl;
05181         llinfos << "-------------------" << llendl;
05182         S32 light_bins[256];
05183         S32 light_counts[256];
05184         for (i = 0; i < 256; i++)
05185         {
05186                 light_bins[i] = 0;
05187                 light_counts[i] = 0;
05188         }
05189         for (i = 0; i < gPipeline.mLightSet.count(); i++)
05190         {
05191                 LLDrawable *drawablep = gPipeline.mLightSet[i];
05192                 F32 light_range = drawablep->getMetric() * LIGHT_RANGE_FACTOR;
05193                 S32 light_bin = light_range / 4;
05194                 S32 count_bin = llmin(drawablep->mLightSet.getLength() / 25, 255);
05195 
05196                 if (count_bin > 20)
05197                 {
05198                         llinfos << drawablep->getVObj()->getPCodeString() << ":" << count_bin*25 << llendl;
05199                         drawablep->getVObj()->dump();
05200                 }
05201                 //llinfos << i << ": " << light_range << llendl;
05202                 light_bins[light_bin]++;
05203                 light_counts[count_bin]++;
05204         }
05205         for (i = 0; i < 256; i++)
05206         {
05207                 if (light_bins[i])
05208                 {
05209                         llinfos << i*4 << ":" << (i+1)*4 << " - " << light_bins[i] << llendl;
05210                 }
05211         }
05212         llinfos << llendl;
05213         llinfos << "LightSet counts" << llendl;
05214         for (i = 0; i < 256; i++)
05215         {
05216                 if (light_counts[i])
05217                 {
05218                         llinfos << i*25 << ":" << (i+1)*25 << " - " << light_counts[i] << llendl;
05219                 }
05220         }
05221         */
05222 }
05223 
05224 class ViewerStatsResponder : public LLHTTPClient::Responder
05225 {
05226 public:
05227     ViewerStatsResponder() { }
05228 
05229     void error(U32 statusNum, const std::string& reason)
05230     {
05231                 llinfos << "ViewerStatsResponder::error " << statusNum << " "
05232                                 << reason << llendl;
05233     }
05234 
05235     void result(const LLSD& content)
05236     {
05237                 llinfos << "ViewerStatsResponder::result" << llendl;
05238         }
05239 };
05240 
05241 /*
05242  * The sim-side LLSD is in newsim/llagentinfo.cpp:forwardViewerStats.
05243  *
05244  * There's also a compatibility shim for the old fixed-format sim
05245  * stats in newsim/llagentinfo.cpp:processViewerStats.
05246  *
05247  * If you move stats around here, make the corresponding changes in
05248  * those locations, too.
05249  */
05250 void send_stats()
05251 {
05252         // IW 9/23/02 I elected not to move this into LLViewerStats
05253         // because it depends on too many viewer.cpp globals.
05254         // Someday we may want to merge all our stats into a central place
05255         // but that day is not today.
05256 
05257         // Only send stats if the agent is connected to a region.
05258         if (!gAgent.getRegion() || gNoRender)
05259         {
05260                 return;
05261         }
05262 
05263         LLSD body;
05264         std::string url = gAgent.getRegion()->getCapability("ViewerStats");
05265 
05266         if (url.empty()) {
05267                 llwarns << "Could not get ViewerStats capability" << llendl;
05268                 return;
05269         }
05270         
05271         body["session_id"] = gAgentSessionID;
05272         
05273         LLSD &agent = body["agent"];
05274         
05275         time_t ltime;
05276         time(&ltime);
05277         F32 run_time = F32(LLFrameTimer::getElapsedSeconds());
05278 
05279         agent["start_time"] = ltime - run_time;
05280         agent["run_time"] = run_time;
05281         // send fps only for time app spends in foreground
05282         agent["fps"] = (F32)gForegroundFrameCount / gForegroundTime.getElapsedTimeF32();
05283         agent["version"] = gCurrentVersion;
05284         agent["language"] = gSavedSettings.getString("Language");
05285         
05286         agent["sim_fps"] = ((F32) gFrameCount - gSimFrames) /
05287                 (F32) (gRenderStartTime.getElapsedTimeF32() - gSimLastTime);
05288 
05289         gSimLastTime = gRenderStartTime.getElapsedTimeF32();
05290         gSimFrames   = (F32) gFrameCount;
05291 
05292         agent["agents_in_view"] = LLVOAvatar::sNumVisibleAvatars;
05293         agent["ping"] = gAvgSimPing;
05294         agent["meters_traveled"] = gAgent.getDistanceTraveled();
05295         agent["regions_visited"] = gAgent.getRegionsVisited();
05296         agent["mem_use"] = getCurrentRSS() / 1024.0;
05297 
05298         LLSD &system = body["system"];
05299         
05300         system["ram"] = (S32) gSysMemory.getPhysicalMemoryKB();
05301         system["os"] = gSysOS.getOSString();
05302         system["cpu"] = gSysCPU.getCPUString();
05303 
05304         std::string gpu_desc = llformat(
05305                 "%-6s Class %d ",
05306                 gGLManager.mGLVendorShort.substr(0,6).c_str(),
05307                 gFeatureManagerp->getGPUClass())
05308                 + gFeatureManagerp->getGPUString();
05309 
05310         system["gpu"] = gpu_desc;
05311         system["gpu_class"] = gFeatureManagerp->getGPUClass();
05312         system["gpu_vendor"] = gGLManager.mGLVendorShort;
05313         system["gpu_version"] = gGLManager.mDriverVersionVendorString;
05314 
05315         LLSD &download = body["downloads"];
05316 
05317         download["world_kbytes"] = gTotalWorldBytes / 1024.0;
05318         download["object_kbytes"] = gTotalObjectBytes / 1024.0;
05319         download["texture_kbytes"] = gTotalTextureBytes / 1024.0;
05320 
05321         LLSD &in = body["stats"]["net"]["in"];
05322 
05323         in["kbytes"] = gMessageSystem->mTotalBytesIn / 1024.0;
05324         in["packets"] = (S32) gMessageSystem->mPacketsIn;
05325         in["compressed_packets"] = (S32) gMessageSystem->mCompressedPacketsIn;
05326         in["savings"] = (gMessageSystem->mUncompressedBytesIn -
05327                                          gMessageSystem->mCompressedBytesIn) / 1024.0;
05328         
05329         LLSD &out = body["stats"]["net"]["out"];
05330         
05331         out["kbytes"] = gMessageSystem->mTotalBytesOut / 1024.0;
05332         out["packets"] = (S32) gMessageSystem->mPacketsOut;
05333         out["compressed_packets"] = (S32) gMessageSystem->mCompressedPacketsOut;
05334         out["savings"] = (gMessageSystem->mUncompressedBytesOut -
05335                                           gMessageSystem->mCompressedBytesOut) / 1024.0;
05336 
05337         LLSD &fail = body["stats"]["failures"];
05338 
05339         fail["send_packet"] = (S32) gMessageSystem->mSendPacketFailureCount;
05340         fail["dropped"] = (S32) gMessageSystem->mDroppedPackets;
05341         fail["resent"] = (S32) gMessageSystem->mResentPackets;
05342         fail["failed_resends"] = (S32) gMessageSystem->mFailedResendPackets;
05343         fail["off_circuit"] = (S32) gMessageSystem->mOffCircuitPackets;
05344         fail["invalid"] = (S32) gMessageSystem->mInvalidOnCircuitPackets;
05345 
05346         gViewerStats->addToMessage(body);
05347 
05348         LLHTTPClient::post(url, body, new ViewerStatsResponder());
05349 }
05350 
05351 #if !LL_WINDOWS
05352 // catch the first signal and send logout messages logout
05353 void signal_handlers(S32 s)
05354 {
05355         release_signals();
05356 
05357         // Check for graceful exit conditions
05358         if(SIGTERM == s)
05359         {
05360                 // Raise the flag telling the system to shut down
05361                 app_force_quit(NULL);
05362                 return;
05363         }
05364 
05365 # if LL_LINUX || LL_SOLARIS
05366         // Really useful to know what KIND of crash we got.
05367         // Might want this on OSX too!
05368         llwarns << "*** Caught signal " << s << llendl;
05369 # endif
05370 
05371         if (gCrashCallback)
05372         {
05373                 gCrashCallback();
05374         }
05375 }
05376 #endif
05377 
05378 // Assign signal handler to be called in case we crash.
05379 void catch_signals()
05380 {
05381 #if LL_WINDOWS
05382         // Win32 signal handling uses a Microsoft API instead of signal handlers
05383         LLWinDebug::setupExceptionHandler();
05384         return;
05385 #else
05386         // This happens before log file output is properly set up, so this would go to the system log.
05387 //      llinfos << "Assigning signal handlers!" << llendl;
05388 
05389         // Handle the signals that default to causing a core image to be created, as per the man page on signal(2).
05390         signal(SIGILL, signal_handlers);
05391         signal(SIGTRAP, signal_handlers);
05392         if (being_debugged())
05393         {
05394                 // If we're being run under the control of a debugger, give
05395                 // ourselves a way to bail into the debugger.
05396                 signal(SIGABRT, SIG_DFL);
05397         } else {
05398                 signal(SIGABRT, signal_handlers);
05399         }
05400         signal(SIGFPE, signal_handlers);
05401         signal(SIGBUS, signal_handlers);
05402         signal(SIGSEGV, signal_handlers);
05403         signal(SIGSYS, signal_handlers);
05404 
05405         // SIGEMT is an 'emulator trap' which is not defined on linux.
05406 #if !LL_LINUX && !LL_SOLARIS
05407         signal(SIGEMT, signal_handlers);
05408 #endif
05409 
05410         // This one is treated specially in the signal handler.
05411         signal(SIGTERM, signal_handlers);
05412 
05413 #endif // LL_WINDOWS
05414 }
05415 
05416 #if !LL_WINDOWS
05417 void release_signals()
05418 {
05419         signal(SIGTERM, SIG_DFL);
05420         signal(SIGABRT, SIG_DFL);
05421         signal(SIGILL, SIG_DFL);
05422         signal(SIGFPE, SIG_DFL);
05423         signal(SIGSEGV, SIG_DFL);
05424 
05425 #ifdef SIGBUS
05426         signal(SIGBUS, SIG_DFL);
05427 #endif
05428 
05429 #ifdef SIGSYS
05430         signal(SIGSYS, SIG_DFL);
05431 #endif
05432 }
05433 #endif // !LL_WINDOWS
05434 
05435 void purge_cache()
05436 {
05437         llinfos << "Purging Texture Cache..." << llendl;
05438         gTextureCache->purgeCache(LL_PATH_CACHE);
05439         llinfos << "Purging Cache..." << llendl;
05440         std::string mask = gDirUtilp->getDirDelimiter() + "*.*";
05441         gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"").c_str(),mask);
05442 }
05443 
05444 int parse_args(int argc, char **argv)
05445 {
05446         // Sometimes IP addresses passed in on the command line have leading
05447         // or trailing white space.  Use LLString to clean that up.
05448         LLString ip_string;
05449         S32 j;
05450 
05451         for (j = 1; j < argc; j++) 
05452         {
05453                 gArgs += argv[j];
05454                 gArgs += " ";
05455 
05456                 if ((!strcmp(argv[j], "-port")) && (++j < argc)) 
05457                 {
05458                         sscanf(argv[j], "%u", &(gAgent.mViewerPort));
05459                 }
05460                 else if ((!strcmp(argv[j], "-drop")) && (++j < argc)) 
05461                 {
05462                         sscanf(argv[j], "%f", &gPacketDropPercentage);
05463                 }
05464                 else if ((!strcmp(argv[j], "-inbw")) && (++j < argc))
05465                 {
05466                         sscanf(argv[j], "%f", &gInBandwidth);
05467                 }
05468                 else if ((!strcmp(argv[j], "-outbw")) && (++j < argc))
05469                 {
05470                         sscanf(argv[j], "%f", &gOutBandwidth);
05471                 }
05472                 else if (!strcmp(argv[j], "--aditi"))
05473                 {
05474                         gUserServerChoice = USERSERVER_ADITI;
05475                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[gUserServerChoice].mName);            /* Flawfinder: ignore */
05476                 }
05477                 else if (!strcmp(argv[j], "--agni"))
05478                 {
05479                         gUserServerChoice = USERSERVER_AGNI;
05480                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[gUserServerChoice].mName);            /* Flawfinder: ignore */
05481                 }
05482                 else if (!strcmp(argv[j], "--dmz"))
05483                 {
05484                         gUserServerChoice = USERSERVER_DMZ;
05485                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[gUserServerChoice].mName);            /* Flawfinder: ignore */
05486                 }
05487                 else if (!strcmp(argv[j], "--siva"))
05488                 {
05489                         gUserServerChoice = USERSERVER_SIVA;
05490                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[gUserServerChoice].mName);            /* Flawfinder: ignore */
05491                 }
05492                 else if (!strcmp(argv[j], "--shakti"))
05493                 {
05494                         gUserServerChoice = USERSERVER_SHAKTI;
05495                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[gUserServerChoice].mName);            /* Flawfinder: ignore */
05496                 }
05497                 else if (!strcmp(argv[j], "--durga"))
05498                 {
05499                         gUserServerChoice = USERSERVER_DURGA;
05500                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[gUserServerChoice].mName);            /* Flawfinder: ignore */
05501                 }
05502                 else if (!strcmp(argv[j], "--soma"))
05503                 {
05504                         gUserServerChoice = USERSERVER_SOMA;
05505                         snprintf(gUserServerName, MAX_STRING, "%s", gUserServerDomainName[gUserServerChoice].mName);            /* Flawfinder: ignore */
05506                 }
05507                 else if (!strcmp(argv[j], "--ganga"))
05508                 {
05509                         gUserServerChoice = USERSERVER_GANGA;
05510                         sprintf(gUserServerName,"%s", gUserServerDomainName[gUserServerChoice].mName);
05511                 }
05512                 else if (!strcmp(argv[j], "--vaak"))
05513                 {
05514                         gUserServerChoice = USERSERVER_VAAK;
05515                         sprintf(gUserServerName,"%s", gUserServerDomainName[gUserServerChoice].mName);
05516                 }
05517                 else if (!strcmp(argv[j], "--uma"))
05518                 {
05519                         gUserServerChoice = USERSERVER_UMA;
05520                         sprintf(gUserServerName,"%s", gUserServerDomainName[gUserServerChoice].mName);
05521                 }
05522                 else if (!strcmp(argv[j], "-user") && (++j < argc)) 
05523                 {
05524                         if (!strcmp(argv[j], "-"))
05525                         {
05526                                 gUserServerChoice = USERSERVER_LOCAL;
05527                                 snprintf(gUserServerName, MAX_STRING, "%s", LOOPBACK_ADDRESS_STRING);           /* Flawfinder: ignore */
05528                         }
05529                         else
05530                         {
05531                                 gUserServerChoice = USERSERVER_OTHER;
05532                                 ip_string.assign( argv[j] );
05533                                 LLString::trim(ip_string);
05534                                 snprintf(gUserServerName, MAX_STRING, "%s", ip_string.c_str());         /* Flawfinder: ignore */
05535                         }
05536                 }
05537                 else if (!strcmp(argv[j], "-loginuri") && (++j < argc))
05538                 {
05539                         gLoginURIs.push_back(utf8str_trim(argv[j]));
05540                 }
05541                 else if (!strcmp(argv[j], "-helperuri") && (++j < argc))
05542                 {
05543                         gHelperURI = argv[j];
05544                         gHelperURI = utf8str_trim(gHelperURI);
05545                 }
05546                 else if (!strcmp(argv[j], "-debugviews"))
05547                 {
05548                         LLView::sDebugRects = TRUE;
05549                 }
05550                 else if (!strcmp(argv[j], "-skin") && (++j < argc))
05551                 {
05552                         std::string folder(argv[j]);
05553                         gDirUtilp->setSkinFolder(folder);
05554                 }
05555                 else if (!strcmp(argv[j], "-autologin") || !strcmp(argv[j], "--autologin")) // keep --autologin for compatibility
05556                 {
05557                         gAutoLogin = TRUE;
05558                 }
05559                 else if (!strcmp(argv[j], "-quitafter") && (++j < argc))
05560                 {
05561                         gQuitAfterSeconds = (F32)atof(argv[j]);
05562                 }
05563                 else if (!strcmp(argv[j], "-rotate"))
05564                 {
05565                         gRotateRight = TRUE;
05566                 }
05567 //              else if (!strcmp(argv[j], "-noenv")) 
05568 //              {
05569                         //turn OFF environmental effects for slow machines/video cards
05570 //                      gRequestParaboloidMap = FALSE;
05571 //              }
05572                 else if (!strcmp(argv[j], "-noaudio"))
05573                 {
05574                         gUseAudio = FALSE;
05575                 }
05576                 else if (!strcmp(argv[j], "-nosound"))  // tends to be popular cmdline on Linux.
05577                 {
05578                         gUseAudio = FALSE;
05579                 }
05580                 else if (!strcmp(argv[j], "-nofmod"))
05581                 {
05582                         gUseFMOD = FALSE;
05583                 }
05584                 else if (!strcmp(argv[j], "-noprobe"))
05585                 {
05586                         gProbeHardware = FALSE;
05587                 }
05588                 else if (!strcmp(argv[j], "-noquicktime"))
05589                 {
05590                         // Developers can log in faster if they don't load all the
05591                         // quicktime dlls.
05592                         gUseQuickTime = false;
05593                 }
05594                 else if (!strcmp(argv[j], "-nopreload"))
05595                 {
05596                         // Developers can log in faster if they don't decode sounds
05597                         // or images on startup, ~5 seconds faster.
05598                         gPreloadSounds = false;
05599                         gPreloadImages = false;
05600                 }
05601                 else if (!strcmp(argv[j], "-purge"))
05602                 {
05603                         purge_cache();
05604                 }
05605                 else if(!strcmp(argv[j], "-noinvlib"))
05606                 {
05607                         gRequestInventoryLibrary = FALSE;
05608                 }
05609                 else if (!strcmp(argv[j], "-log"))
05610                 {
05611                         gLogMessages = TRUE;
05612                         continue;
05613                 }
05614                 else if (!strcmp(argv[j], "-logfile") && (++j < argc)) 
05615                 {
05616                         // *NOTE: This buffer size is hard coded into scanf() below.
05617                         char logfile[256];      /* Flawfinder: ignore */
05618                         sscanf(argv[j], "%255s", logfile);      /* Flawfinder: ignore */
05619                         llinfos << "Setting log file to " << logfile << llendl;
05620                         LLFile::remove(logfile);
05621                         LLError::logToFile(logfile);
05622                 }
05623                 else if (!strcmp(argv[j], "-settings") && (++j < argc)) 
05624                 {
05625                         gSettingsFileName = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, argv[j]);
05626                 }
05627                 else if (!strcmp(argv[j], "-setdefault") && (j + 2 < argc)) 
05628                 {
05629                         std::string control_name;
05630                         std::string control_value;
05631                         
05632                         j++;
05633                         if (argv[j]) control_name = std::string(argv[j]);
05634 
05635                         j++;
05636                         if (argv[j]) control_value = std::string(argv[j]);
05637                         
05638                         // grab control name and value
05639                         if (!control_name.empty())
05640                         {
05641                                 gCommandLineSettings[control_name] = control_value;
05642                         }
05643                 }
05644                 else if (!strcmp(argv[j], "-set") && (j + 2 < argc)) 
05645                 {
05646                         std::string control_name;
05647                         std::string control_value;
05648                         
05649                         j++;
05650                         if (argv[j]) control_name = std::string(argv[j]);
05651 
05652                         j++;
05653                         if (argv[j]) control_value = std::string(argv[j]);
05654                         
05655                         // grab control name and value
05656                         if (!control_name.empty())
05657                         {
05658                                 gCommandLineForcedSettings[control_name] = control_value;
05659                         }
05660                 }
05661                 else if (!strcmp(argv[j], "-login"))
05662                 {
05663                         if (j + 3 < argc)
05664                         {
05665                                 j++;
05666                                 gCmdLineFirstName = argv[j];
05667                                 j++;
05668                                 gCmdLineLastName = argv[j];
05669                                 j++;
05670                                 gCmdLinePassword = argv[j];
05671                         }
05672                         else
05673                         {
05674                                 // only works if -login is last parameter on command line
05675                                 llerrs << "Not enough parameters to -login. Did you mean -loginuri?" << llendl;
05676                         }
05677                 }
05678                 else if (!strcmp(argv[j], "-god"))
05679                 {
05680                         gGodConnect = TRUE;
05681                 }
05682                 else if (!strcmp(argv[j], "-noconsole"))
05683                 {
05684                         gUseConsole = FALSE;
05685                 }
05686                 else if (!strcmp(argv[j], "-safe"))
05687                 {
05688                         llinfos << "Setting viewer feature table to run in safe mode, resetting prefs" << llendl;
05689                         gFeatureManagerp->setSafe(TRUE);
05690                 }
05691                 else if (!strcmp(argv[j], "-multiple"))
05692                 {
05693                         gMultipleViewersOK = TRUE;
05694                 }
05695                 else if (!strcmp(argv[j], "-nomultiple"))
05696                 {
05697                         gMultipleViewersOK = FALSE;
05698                 }
05699                 else if (!strcmp(argv[j], "-novoice"))
05700                 {
05701                         gDisableVoice = TRUE;
05702                 }
05703                 else if (!strcmp(argv[j], "-nothread"))
05704                 {
05705                         LLVFile::ALLOW_ASYNC = FALSE;
05706                         llinfos << "Running VFS in nothread mode" << llendl;
05707                 }
05708                 // some programs don't respect the command line options in protocol handlers (I'm looking at you, Opera)
05709                 // so this allows us to parse the URL straight off the command line without a "-url" paramater
05710                 else if (LLURLDispatcher::isSLURL(argv[j])
05711                                  || !strcmp(argv[j], "-url") && (++j < argc)) 
05712                 {
05713                         std::string slurl = argv[j];
05714                         if (LLURLDispatcher::isSLURLCommand(slurl))
05715                         {
05716                                 LLStartUp::sSLURLCommand = slurl;
05717                         }
05718                         else
05719                         {
05720                                 LLURLSimString::setString(slurl);
05721                         }
05722                         // *NOTE: After setting the url, bail. What can happen is
05723                         // that someone can use IE (or potentially other browsers)
05724                         // and do the rough equivalent of command injection and
05725                         // steal passwords. Phoenix. SL-55321
05726                         gArgs += argv[j];
05727                         return 0;
05728                 }
05729                 else if (!strcmp(argv[j], "-ignorepixeldepth"))
05730                 {
05731                         gIgnorePixelDepth = TRUE;
05732                 }
05733                 else if (!strcmp(argv[j], "-cooperative"))
05734                 {
05735                         S32 ms_to_yield = 0;
05736                         if(++j < argc)
05737                         {
05738                                 S32 rv = sscanf(argv[j], "%d", &ms_to_yield);
05739                                 if(0 == rv)
05740                                 {
05741                                         --j;
05742                                 }
05743                         }
05744                         else
05745                         {
05746                                 --j;
05747                         }
05748                         gYieldMS = ms_to_yield;
05749                         gYieldTime = TRUE;
05750                 }
05751                 else if (!strncmp(argv[j], "-lang", 5))
05752                 {
05753                         j++;
05754                         if (argv[j])
05755                                 gSavedSettings.setString("Language", std::string(argv[j]));
05756                 }
05757                 else if (!strcmp(argv[j], "-no-verify-ssl-cert"))
05758                 {
05759                         gVerifySSLCert = false;
05760                 }
05761                 else if ( (!strcmp(argv[j], "--channel") || !strcmp(argv[j], "-channel"))  && (++j < argc)) 
05762                 {
05763                         gChannelName = argv[j];
05764                 }
05765 #if LL_DARWIN
05766                 else if (!strncmp(argv[j], "-psn_", 5))
05767                 {
05768                         // this is the Finder passing the process session number
05769                         // we ignore this
05770                 }
05771 #endif
05772                 else
05773                 {
05774 
05775                         // DBC - Mac OS X passes some stuff by default on the command line (e.g. psn).
05776                         // Second Life URLs are passed this way as well?
05777                         llwarns << "Possible unknown keyword " << argv[j] << llendl;
05778 
05779                         // print usage information
05780                         llinfos << USAGE << llendl;
05781                         // return 1;
05782                 }
05783         }
05784         return 0;
05785 }
05786 
05787 //============================================================================
05788 
05789 void load_name_cache()
05790 {
05791         if (!gCacheName) return;
05792 
05793         std::string name_cache;
05794         name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
05795         FILE* name_cache_fp = LLFile::fopen(name_cache.c_str(), "r");           /* Flawfinder: ignore*/
05796         if (name_cache_fp)
05797         {
05798                 gCacheName->importFile(name_cache_fp);
05799                 fclose(name_cache_fp);
05800         }
05801 }
05802 
05803 void save_name_cache()
05804 {
05805         if (!gCacheName) return;
05806 
05807         std::string name_cache;
05808         name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
05809         FILE* name_cache_fp = LLFile::fopen(name_cache.c_str(), "w");           /* Flawfinder: ignore*/
05810         if (name_cache_fp)
05811         {
05812                 gCacheName->exportFile(name_cache_fp);
05813                 fclose(name_cache_fp);
05814         }
05815 }
05816 
05817 void load_region_name_cache()
05818 {
05819         if (!gCacheName) return;
05820 
05821         // Load static cache, then user specific one
05822         gRegionNameCache->importFile(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "region_names.xml"), true);
05823         gRegionNameCache->importFile(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "region_names.xml"), false);
05824 }
05825 
05826 void save_region_name_cache()
05827 {
05828         if (!gCacheName) return;
05829 
05830         std::string name_cache;
05831         name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "region_names.xml");
05832         gRegionNameCache->exportFile(name_cache);
05833 }
05834 
05835 
05836 void login_alert_done(S32 option, void* user_data)
05837 {
05838         LLPanelLogin::giveFocus();
05839 }
05840 
05841 void disconnect_viewer(void *)
05842 {
05843         if (gDisconnected)
05844         {
05845                 return;
05846         }
05847         //
05848         // Cleanup after quitting.
05849         //      
05850         // Save snapshot for next time, if we made it through initialization
05851 
05852         llinfos << "Disconnecting viewer!" << llendl;
05853 
05854         // Dump our frame statistics
05855         gFrameStats.dump();
05856 
05857 
05858         // Signal handlers may need resources that we're destroying here, so don't use them.
05859 #if !LL_WINDOWS
05860         release_signals();
05861 #endif
05862 
05863         // Remember if we were flying
05864         gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() );
05865 
05866         // Un-minimize all windows so they don't get saved minimized
05867         if (!gNoRender)
05868         {
05869                 if (gFloaterView)
05870                 {
05871                         gFloaterView->restoreAll();
05872                 }
05873         }
05874 
05875         if (gSelectMgr)
05876         {
05877                 gSelectMgr->deselectAll();
05878         }
05879 
05880         if (!gNoRender)
05881         {
05882                 // save inventory if appropriate
05883                 gInventory.cache(gAgent.getInventoryRootID(), gAgent.getID());
05884                 if(gInventoryLibraryRoot.notNull() && gInventoryLibraryOwner.notNull())
05885                 {
05886                         gInventory.cache(gInventoryLibraryRoot, gInventoryLibraryOwner);
05887                 }
05888         }
05889 
05890         save_name_cache();
05891         save_region_name_cache();
05892 
05893         // close inventory interface, close all windows
05894         LLInventoryView::cleanup();
05895 
05896         // Log out of userserver
05897         user_logout();
05898 
05899         // Delete stuff that would result in net connections
05900 
05901         // Also writes cached agent settings to gSavedSettings
05902         gAgent.cleanup();
05903 
05904         gObjectList.destroy();
05905         delete gWorldp;
05906         gWorldp = NULL;
05907 
05908         cleanup_xfer_manager();
05909         gDisconnected = TRUE;
05910 }
05911 
05912 // helper function for cleanup_app
05913 void remove_cache_files(const char* file_mask)
05914 {
05915         char mask[LL_MAX_PATH];         /* Flawfinder: ignore */
05916         snprintf(mask, LL_MAX_PATH, "%s%s", gDirUtilp->getDirDelimiter().c_str(), file_mask);           /* Flawfinder: ignore */
05917         gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "").c_str(), mask);
05918 }
05919 
05920 
05921 
05922 
05923 void finish_early_exit(S32 option, void* userdata)
05924 {
05925         app_force_quit(NULL);
05926 }
05927 
05928 void app_early_exit(const LLString& mesg)
05929 {
05930         llwarns << "app_early_exit: " << mesg << llendl;
05931         gDoDisconnect = TRUE;
05932 //      LLStringBase<char>::format_map_t args;
05933 //      args["[MESSAGE]"] = mesg;
05934 //      gViewerWindow->alertXml("AppEarlyExit", args, finish_early_exit);
05935         LLAlertDialog::showCritical(mesg, finish_early_exit, NULL);
05936 }
05937 
05938 // Used for drones, etc
05939 void app_force_exit(S32 arg)
05940 {
05941         remove_marker_file();
05942         exit(arg);
05943 }
05944 
05945 // Callback from a dialog indicating user was logged out.  
05946 void finish_disconnect(S32 option, void* userdata)
05947 {
05948         if (1 == option)
05949         {
05950                 app_force_quit(NULL);
05951         }
05952 }
05953 
05954 // Callback from an early disconnect dialog, force an exit
05955 void finish_forced_disconnect(S32 /* option */, void* /* userdata */)
05956 {
05957         app_force_quit(NULL);
05958 }
05959 
05960 void send_logout_request()
05961 {
05962         if(!gLogoutRequestSent)
05963         {
05964                 LLMessageSystem* msg = gMessageSystem;
05965                 msg->newMessageFast(_PREHASH_LogoutRequest);
05966                 msg->nextBlockFast(_PREHASH_AgentData);
05967                 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
05968                 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
05969                 gAgent.sendReliableMessage();
05970 
05971                 gLogoutTimer.reset();
05972                 gLogoutMaxTime = LOGOUT_REQUEST_TIME;
05973                 gLogoutRequestSent = TRUE;
05974                 
05975                 gVoiceClient->leaveChannel();
05976         }
05977 }
05978 
05979 void do_disconnect(const LLString& mesg)
05980 {
05981         if (gDoDisconnect)
05982     {
05983                 // Already popped up one of these dialogs, don't
05984                 // do this again.
05985                 return;
05986     }
05987 
05988         // Translate the message if possible
05989         LLString big_reason = LLAgent::sTeleportErrorMessages[mesg];
05990         if ( big_reason.size() == 0 )
05991         {
05992                 big_reason = mesg;
05993         }
05994 
05995         LLStringBase<char>::format_map_t args;
05996         gDoDisconnect = TRUE;
05997 
05998         if (LLStartUp::getStartupState() < STATE_STARTED)
05999         {
06000                 // Tell users what happened
06001                 args["[ERROR_MESSAGE]"] = big_reason;
06002                 gViewerWindow->alertXml("ErrorMessage", args, finish_forced_disconnect);
06003         }
06004         else
06005         {
06006                 args["[MESSAGE]"] = big_reason;
06007                 gViewerWindow->alertXml("YouHaveBeenLoggedOut", args, finish_disconnect );
06008         }
06009 }
06010 
06011 const LLUUID& agent_get_id()
06012 {
06013         return gAgent.getID();
06014 }
06015 
06016 const LLUUID& agent_get_session_id()
06017 {
06018         return gAgent.getSessionID();
06019 }
06020 
06021 void agent_send_reliable_message()
06022 {
06023         gAgent.sendReliableMessage();
06024 }
06025 
06026 void bad_network_handler()
06027 {
06028         // Dump the packet
06029         gMessageSystem->dumpPacketToLog();
06030 
06031         // Flush all of our caches on exit in the case of disconnect due to
06032         // invalid packets.
06033 
06034         gPurgeOnExit = TRUE;
06035 
06036 #if LL_WINDOWS
06037         LLWinDebug::handleException(NULL);
06038 #else
06039         // Call the crash callback
06040         if (gCrashCallback)
06041         {
06042                 gCrashCallback();
06043         }
06044 #endif
06045 
06046         std::ostringstream message;
06047         message <<
06048                 "The viewer has detected mangled network data indicative\n"
06049                 "of a bad upstream network connection or an incomplete\n"
06050                 "local installation of " << gSecondLife << ". \n"
06051                 " \n"
06052                 "Try uninstalling and reinstalling to see if this resolves \n"
06053                 "the issue. \n"
06054                 " \n"
06055                 "If the problem continues, see the Tech Support FAQ at: \n"
06056                 "www.secondlife.com/support";
06057         do_disconnect(message.str());
06058 }
06059 
06060 
06061 // dump current avatar to .cal file
06062 void save_avatar(void*)
06063 {
06064         LLFloaterSaveAvatar::show();
06065 }
06066 
06067 void cleanup_app()
06068 {
06069         //flag all elements as needing to be destroyed immediately
06070         // to ensure shutdown order
06071         LLMortician::setZealous(TRUE);
06072 
06073         LLVoiceClient::terminate();
06074         
06075         disconnect_viewer(NULL);
06076 
06077         llinfos << "Viewer disconnected" << llendflush;
06078 
06079         gDisconnectedImagep = NULL;
06080         release_start_screen(); // just in case
06081 
06082         LLError::logToFixedBuffer(NULL);
06083 
06084         llinfos << "Cleaning Up" << llendflush;
06085 
06086         LLKeyframeDataCache::clear();
06087         
06088         // Must clean up texture references before viewer window is destroyed.
06089         LLHUDObject::cleanupHUDObjects();
06090         llinfos << "HUD Objects cleaned up" << llendflush;
06091 
06092         // End TransferManager before deleting systems it depends on (Audio, VFS, AssetStorage)
06093 #if 0 // this seems to get us stuck in an infinite loop...
06094         gTransferManager.cleanup();
06095 #endif
06096         
06097         // Clean up map data storage
06098         delete gWorldMap;
06099         gWorldMap = NULL;
06100 
06101         delete gHUDManager;
06102         gHUDManager = NULL;
06103 
06104         delete gToolMgr;
06105         gToolMgr = NULL;
06106 
06107         delete gAssetStorage;
06108         gAssetStorage = NULL;
06109 
06110         LLPolyMesh::freeAllMeshes();
06111 
06112         delete gCacheName;
06113         gCacheName = NULL;
06114 
06115         delete gGlobalEconomy;
06116         gGlobalEconomy = NULL;
06117 
06118         delete gLocalSpeakerMgr;
06119         gLocalSpeakerMgr = NULL;
06120 
06121         LLNotifyBox::cleanup();
06122 
06123         llinfos << "Global stuff deleted" << llendflush;
06124 
06125 #if !LL_RELEASE_FOR_DOWNLOAD
06126         if (gAudiop)
06127         {
06128                 gAudiop->shutdown();
06129         }
06130 #else
06131         // This hack exists because fmod likes to occasionally hang forever
06132         // when shutting down for no apparent reason.
06133         llwarns << "Hack, skipping audio engine cleanup" << llendflush;
06134 #endif
06135 
06136 
06137         // moved to main application shutdown for now because it's non-trivial and only needs to be done once
06138         // (even though it goes against the media framework design)
06139 
06140         LLMediaEngine::cleanupClass();
06141         
06142 #if LL_QUICKTIME_ENABLED
06143         if (gQuickTimeInitialized)
06144         {
06145                 // clean up media stuff
06146                 llinfos << "Cleaning up QuickTime" << llendl;
06147                 ExitMovies ();
06148                 #if LL_WINDOWS
06149                         // Only necessary/available on Windows.
06150                         TerminateQTML ();
06151                 #endif
06152         }
06153         llinfos << "Quicktime cleaned up" << llendflush;
06154 #endif
06155 
06156 #if LL_GSTREAMER_ENABLED
06157         llinfos << "Cleaning up GStreamer" << llendl;
06158         UnloadGStreamer();
06159         llinfos << "GStreamer cleaned up" << llendflush;        
06160 #endif
06161 
06162         llinfos << "Cleaning up feature manager" << llendflush;
06163         delete gFeatureManagerp;
06164         gFeatureManagerp = NULL;
06165 
06166         // Patch up settings for next time
06167         // Must do this before we delete the viewer window,
06168         // such that we can suck rectangle information out of
06169         // it.
06170         cleanup_saved_settings();
06171         llinfos << "Settings patched up" << llendflush;
06172 
06173         delete gAudiop;
06174         gAudiop = NULL;
06175 
06176         // delete some of the files left around in the cache.
06177         remove_cache_files("*.wav");
06178         remove_cache_files("*.tmp");
06179         remove_cache_files("*.lso");
06180         remove_cache_files("*.out");
06181         remove_cache_files("*.dsf");
06182         remove_cache_files("*.bodypart");
06183         remove_cache_files("*.clothing");
06184 
06185         llinfos << "Cache files removed" << llendflush;
06186 
06187 
06188         cleanup_menus();
06189 
06190         // Wait for any pending VFS IO
06191         while (1)
06192         {
06193                 S32 pending = LLVFSThread::updateClass(0);
06194                 pending += LLLFSThread::updateClass(0);
06195                 if (!pending)
06196                 {
06197                         break;
06198                 }
06199                 llinfos << "Waiting for pending IO to finish: " << pending << llendflush;
06200                 ms_sleep(100);
06201         }
06202         llinfos << "Shutting down." << llendflush;
06203         
06204         // Destroy Windows(R) window, and make sure we're not fullscreen
06205         // This may generate window reshape and activation events.
06206         // Therefore must do this before destroying the message system.
06207         delete gViewerWindow;
06208         gViewerWindow = NULL;
06209         llinfos << "ViewerWindow deleted" << llendflush;
06210 
06211         // viewer UI relies on keyboard so keep it aound until viewer UI isa gone
06212         delete gKeyboard;
06213         gKeyboard = NULL;
06214 
06215         // Clean up selection managers after UI is destroyed, as UI
06216         // may be observing them.
06217         LLSelectMgr::cleanupGlobals();
06218 
06219         LLViewerObject::cleanupVOClasses();
06220                 
06221         LLTracker::cleanupInstance();
06222         
06223 #if LL_LIBXUL_ENABLED
06224         // this must be done after floater cleanup (delete gViewerWindow) since 
06225         // floaters  potentially need the manager to destroy their contents.
06226         LLMozLib::getInstance()->reset();
06227 #endif
06228 
06229 #if LL_WINDOWS
06230         gDXHardware.cleanup();
06231 #endif // LL_WINDOWS
06232 
06233 #if LL_WINDOWS && LL_LCD_COMPILE
06234         // shut down the LCD window on a logitech keyboard, if there is one
06235         delete gLcdScreen;
06236 #endif
06237 
06238         if (!gVolumeMgr->cleanup())
06239         {
06240                 llwarns << "Remaining references in the volume manager!" << llendflush;
06241         }
06242 
06243         LLViewerParcelMgr::cleanupGlobals();
06244 
06245         delete gViewerStats;
06246         gViewerStats = NULL;
06247 
06248         end_messaging_system();
06249 
06250         LLFollowCamMgr::cleanupClass();
06251         LLVolumeMgr::cleanupClass();
06252         LLWorldMapView::cleanupClass();
06253         LLUI::cleanupClass();
06254         
06255         //
06256         // Shut down the VFS's AFTER the decode manager cleans up (since it cleans up vfiles).
06257         // Also after viewerwindow is deleted, since it may have image pointers (which have vfiles)
06258         // Also after shutting down the messaging system since it has VFS dependencies
06259         //
06260         LLVFile::cleanupClass();
06261         llinfos << "VFS cleaned up" << llendflush;
06262 
06263         // Store the time of our current logoff
06264         gSavedPerAccountSettings.setU32("LastLogoff", time_corrected());
06265 
06266         // Must do this after all panels have been deleted because panels that have persistent rects
06267         // save their rects on delete.
06268         gSavedSettings.saveToFile(gSettingsFileName, TRUE);
06269         if (!gPerAccountSettingsFileName.empty())
06270         {
06271                 gSavedPerAccountSettings.saveToFile(gPerAccountSettingsFileName, TRUE);
06272         }
06273         llinfos << "Saved settings" << llendflush;
06274 
06275         std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
06276         // save all settings, even if equals defaults
06277         gCrashSettings.saveToFile(crash_settings_filename.c_str(), FALSE);
06278 
06279         delete gUICtrlFactory;
06280         gUICtrlFactory = NULL;
06281 
06282         gSavedSettings.cleanup();
06283         gViewerArt.cleanup();
06284         gColors.cleanup();
06285         gCrashSettings.cleanup();
06286 
06287         if (gMuteListp)
06288         {
06289                 // save mute list
06290                 gMuteListp->cache(gAgent.getID());
06291 
06292                 delete gMuteListp;
06293                 gMuteListp = NULL;
06294         }
06295 
06296         if (gPurgeOnExit)
06297         {
06298                 llinfos << "Purging all cache files on exit" << llendflush;
06299                 char mask[LL_MAX_PATH];         /* Flawfinder: ignore */
06300                 snprintf(mask, LL_MAX_PATH, "%s*.*", gDirUtilp->getDirDelimiter().c_str());             /* Flawfinder: ignore */
06301                 gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"").c_str(),mask);
06302         }
06303 
06304         remove_marker_file(); // Any crashes from here on we'll just have to ignore
06305         
06306         close_debug();
06307 
06308         // Let threads finish
06309         LLTimer idleTimer;
06310         idleTimer.reset();
06311         const F64 max_idle_time = 5.f; // 5 seconds
06312         while(1)
06313         {
06314                 S32 pending = 0;
06315                 pending += gTextureCache->update(1); // unpauses the worker thread
06316                 pending += gImageDecodeThread->update(1); // unpauses the image thread
06317                 pending += gTextureFetch->update(1); // unpauses the texture fetch thread
06318                 pending += LLVFSThread::updateClass(0);
06319                 pending += LLLFSThread::updateClass(0);
06320                 F64 idle_time = idleTimer.getElapsedTimeF64();
06321                 if (!pending || idle_time >= max_idle_time)
06322                 {
06323                         llwarns << "Quitting with pending background tasks." << llendl;
06324                         break;
06325                 }
06326         }
06327         
06328         // Delete workers first
06329         // shotdown all worker threads before deleting them in case of co-dependencies
06330         gTextureCache->shutdown();
06331         gTextureFetch->shutdown();
06332         gImageDecodeThread->shutdown();
06333         delete gTextureCache;
06334         delete gTextureFetch;
06335         delete gImageDecodeThread;
06336 
06337         gImageList.shutdown(); // shutdown again in case a callback added something
06338         
06339         // This should eventually be done in LLAppViewer
06340         LLImageJ2C::closeDSO();
06341         LLImageFormatted::cleanupClass();
06342         LLVFSThread::cleanupClass();
06343         LLLFSThread::cleanupClass();
06344 
06345         llinfos << "VFS Thread finished" << llendflush;
06346 
06347 #ifndef LL_RELEASE_FOR_DOWNLOAD
06348         llinfos << "Auditing VFS" << llendl;
06349         gVFS->audit();
06350 #endif
06351 
06352         // For safety, the LLVFS has to be deleted *after* LLVFSThread. This should be cleaned up.
06353         // (LLVFS doesn't know about LLVFSThread so can't kill pending requests) -Steve
06354         delete gStaticVFS;
06355         gStaticVFS = NULL;
06356         delete gVFS;
06357         gVFS = NULL;
06358         
06359         LLCurl::cleanup();
06360 
06361         // This will eventually be done in LLApp
06362         LLCommon::cleanupClass();
06363 
06364         end_messaging_system();
06365 }
06366 
06367 // Clear URIs when picking a new server
06368 void resetURIs()
06369 {
06370         gLoginURIs.clear();
06371         gHelperURI.clear();
06372 }
06373 
06374 const std::vector<std::string>& getLoginURIs()
06375 {
06376         if (gLoginURIs.empty())
06377         {
06378                 // not specified on the command line, use value from table
06379                 gLoginURIs = LLSRV::rewriteURI(gUserServerDomainName[gUserServerChoice].mLoginURI);
06380         }
06381         return gLoginURIs;
06382 }
06383 
06384 const std::string& getHelperURI()
06385 {
06386         if (gHelperURI.empty())
06387         {
06388                 // not specified on the command line, use value from table
06389                 gHelperURI = gUserServerDomainName[gUserServerChoice].mHelperURI;
06390         }
06391         return gHelperURI;
06392 }
06393 
06394 void errorCallback(const std::string &error_string)
06395 {
06396 #ifndef LL_RELEASE_FOR_DOWNLOAD
06397         OSMessageBox(error_string.c_str(), "Fatal Error", OSMB_OK);
06398 #endif
06399         LLError::crashAndLoop(error_string);
06400 }
06401 // JC - Please don't put code here.  Find the right file, perhaps
06402 // llviewermessage.cpp, and put it there.  Thanks!

Generated on Thu Jul 1 06:10:03 2010 for Second Life Viewer by  doxygen 1.4.7